147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin/* vmu-flash.c 247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * Driver for SEGA Dreamcast Visual Memory Unit 347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * 447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * Copyright (c) Adrian McMenamin 2002 - 2009 547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * Copyright (c) Paul Mundt 2001 647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * 747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * Licensed under version 2 of the 847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * GNU General Public Licence 947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin */ 1047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin#include <linux/init.h> 115a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 1247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin#include <linux/sched.h> 1347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin#include <linux/delay.h> 1447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin#include <linux/maple.h> 1547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin#include <linux/mtd/mtd.h> 1647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin#include <linux/mtd/map.h> 1747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 1847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminstruct vmu_cache { 1947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin unsigned char *buffer; /* Cache */ 2047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin unsigned int block; /* Which block was cached */ 2147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin unsigned long jiffies_atc; /* When was it cached? */ 2247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin int valid; 2347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin}; 2447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 2547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminstruct mdev_part { 2647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct maple_device *mdev; 2747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin int partition; 2847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin}; 2947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 3047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminstruct vmupart { 3147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin u16 user_blocks; 3247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin u16 root_block; 3347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin u16 numblocks; 3447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin char *name; 3547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct vmu_cache *pcache; 3647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin}; 3747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 3847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminstruct memcard { 3947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin u16 tempA; 4047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin u16 tempB; 4147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin u32 partitions; 4247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin u32 blocklen; 4347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin u32 writecnt; 4447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin u32 readcnt; 4547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin u32 removeable; 4647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin int partition; 4747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin int read; 4847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin unsigned char *blockread; 4947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct vmupart *parts; 5047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct mtd_info *mtd; 5147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin}; 5247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 5347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminstruct vmu_block { 5447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin unsigned int num; /* block number */ 5547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin unsigned int ofs; /* block offset */ 5647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin}; 5747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 5847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminstatic struct vmu_block *ofs_to_block(unsigned long src_ofs, 5947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct mtd_info *mtd, int partition) 6047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin{ 6147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct vmu_block *vblock; 6247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct maple_device *mdev; 6347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct memcard *card; 6447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct mdev_part *mpart; 6547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin int num; 6647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 6747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mpart = mtd->priv; 6847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev = mpart->mdev; 6947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card = maple_get_drvdata(mdev); 7047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 7147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (src_ofs >= card->parts[partition].numblocks * card->blocklen) 7247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto failed; 7347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 7447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin num = src_ofs / card->blocklen; 7547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (num > card->parts[partition].numblocks) 7647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto failed; 7747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 7847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin vblock = kmalloc(sizeof(struct vmu_block), GFP_KERNEL); 7947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (!vblock) 8047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto failed; 8147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 8247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin vblock->num = num; 8347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin vblock->ofs = src_ofs % card->blocklen; 8447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin return vblock; 8547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 8647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminfailed: 8747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin return NULL; 8847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin} 8947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 9047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin/* Maple bus callback function for reads */ 9147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminstatic void vmu_blockread(struct mapleq *mq) 9247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin{ 9347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct maple_device *mdev; 9447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct memcard *card; 9547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 9647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev = mq->dev; 9747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card = maple_get_drvdata(mdev); 9847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin /* copy the read in data */ 9947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 10047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (unlikely(!card->blockread)) 10147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin return; 10247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 10347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin memcpy(card->blockread, mq->recvbuf->buf + 12, 10447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card->blocklen/card->readcnt); 10547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 10647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin} 10747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 10847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin/* Interface with maple bus to read blocks 10947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * caching the results so that other parts 11047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * of the driver can access block reads */ 11147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminstatic int maple_vmu_read_block(unsigned int num, unsigned char *buf, 11247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct mtd_info *mtd) 11347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin{ 11447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct memcard *card; 11547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct mdev_part *mpart; 11647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct maple_device *mdev; 11747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin int partition, error = 0, x, wait; 11847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin unsigned char *blockread = NULL; 11947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct vmu_cache *pcache; 12047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin __be32 sendbuf; 12147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 12247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mpart = mtd->priv; 12347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev = mpart->mdev; 12447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin partition = mpart->partition; 12547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card = maple_get_drvdata(mdev); 12647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin pcache = card->parts[partition].pcache; 12747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin pcache->valid = 0; 12847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 12947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin /* prepare the cache for this block */ 13047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (!pcache->buffer) { 13147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin pcache->buffer = kmalloc(card->blocklen, GFP_KERNEL); 13247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (!pcache->buffer) { 13347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin dev_err(&mdev->dev, "VMU at (%d, %d) - read fails due" 13447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin " to lack of memory\n", mdev->port, 13547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev->unit); 13647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin error = -ENOMEM; 13747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto outB; 13847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 13947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 14047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 14147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin /* 14247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * Reads may be phased - again the hardware spec 14347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * supports this - though may not be any devices in 14447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * the wild that implement it, but we will here 14547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin */ 14647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin for (x = 0; x < card->readcnt; x++) { 14747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin sendbuf = cpu_to_be32(partition << 24 | x << 16 | num); 14847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 14947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (atomic_read(&mdev->busy) == 1) { 15047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin wait_event_interruptible_timeout(mdev->maple_wait, 15147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin atomic_read(&mdev->busy) == 0, HZ); 15247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (atomic_read(&mdev->busy) == 1) { 15347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin dev_notice(&mdev->dev, "VMU at (%d, %d)" 15447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin " is busy\n", mdev->port, mdev->unit); 15547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin error = -EAGAIN; 15647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto outB; 15747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 15847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 15947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 16047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin atomic_set(&mdev->busy, 1); 16147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin blockread = kmalloc(card->blocklen/card->readcnt, GFP_KERNEL); 16247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (!blockread) { 16347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin error = -ENOMEM; 16447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin atomic_set(&mdev->busy, 0); 16547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto outB; 16647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 16747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card->blockread = blockread; 16847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 16947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin maple_getcond_callback(mdev, vmu_blockread, 0, 17047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin MAPLE_FUNC_MEMCARD); 17147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin error = maple_add_packet(mdev, MAPLE_FUNC_MEMCARD, 17247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin MAPLE_COMMAND_BREAD, 2, &sendbuf); 17347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin /* Very long timeouts seem to be needed when box is stressed */ 17447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin wait = wait_event_interruptible_timeout(mdev->maple_wait, 17547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin (atomic_read(&mdev->busy) == 0 || 17647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin atomic_read(&mdev->busy) == 2), HZ * 3); 17747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin /* 17847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * MTD layer does not handle hotplugging well 17947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * so have to return errors when VMU is unplugged 18047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * in the middle of a read (busy == 2) 18147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin */ 18247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (error || atomic_read(&mdev->busy) == 2) { 18347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (atomic_read(&mdev->busy) == 2) 18447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin error = -ENXIO; 18547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin atomic_set(&mdev->busy, 0); 18647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card->blockread = NULL; 18747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto outA; 18847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 18947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (wait == 0 || wait == -ERESTARTSYS) { 19047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card->blockread = NULL; 19147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin atomic_set(&mdev->busy, 0); 19247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin error = -EIO; 19347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin list_del_init(&(mdev->mq->list)); 19447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin kfree(mdev->mq->sendbuf); 19547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev->mq->sendbuf = NULL; 19647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (wait == -ERESTARTSYS) { 19747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin dev_warn(&mdev->dev, "VMU read on (%d, %d)" 19847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin " interrupted on block 0x%X\n", 19947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev->port, mdev->unit, num); 20047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } else 20147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin dev_notice(&mdev->dev, "VMU read on (%d, %d)" 20247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin " timed out on block 0x%X\n", 20347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev->port, mdev->unit, num); 20447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto outA; 20547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 20647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 20747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin memcpy(buf + (card->blocklen/card->readcnt) * x, blockread, 20847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card->blocklen/card->readcnt); 20947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 21047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin memcpy(pcache->buffer + (card->blocklen/card->readcnt) * x, 21147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card->blockread, card->blocklen/card->readcnt); 21247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card->blockread = NULL; 21347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin pcache->block = num; 21447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin pcache->jiffies_atc = jiffies; 21547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin pcache->valid = 1; 21647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin kfree(blockread); 21747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 21847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 21947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin return error; 22047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 22147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminoutA: 22247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin kfree(blockread); 22347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminoutB: 22447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin return error; 22547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin} 22647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 22747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin/* communicate with maple bus for phased writing */ 22847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminstatic int maple_vmu_write_block(unsigned int num, const unsigned char *buf, 22947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct mtd_info *mtd) 23047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin{ 23147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct memcard *card; 23247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct mdev_part *mpart; 23347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct maple_device *mdev; 23447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin int partition, error, locking, x, phaselen, wait; 23547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin __be32 *sendbuf; 23647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 23747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mpart = mtd->priv; 23847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev = mpart->mdev; 23947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin partition = mpart->partition; 24047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card = maple_get_drvdata(mdev); 24147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 24247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin phaselen = card->blocklen/card->writecnt; 24347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 24447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin sendbuf = kmalloc(phaselen + 4, GFP_KERNEL); 24547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (!sendbuf) { 24647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin error = -ENOMEM; 24747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto fail_nosendbuf; 24847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 24947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin for (x = 0; x < card->writecnt; x++) { 25047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin sendbuf[0] = cpu_to_be32(partition << 24 | x << 16 | num); 25147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin memcpy(&sendbuf[1], buf + phaselen * x, phaselen); 25247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin /* wait until the device is not busy doing something else 25347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * or 1 second - which ever is longer */ 25447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (atomic_read(&mdev->busy) == 1) { 25547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin wait_event_interruptible_timeout(mdev->maple_wait, 25647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin atomic_read(&mdev->busy) == 0, HZ); 25747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (atomic_read(&mdev->busy) == 1) { 25847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin error = -EBUSY; 25947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin dev_notice(&mdev->dev, "VMU write at (%d, %d)" 26047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin "failed - device is busy\n", 26147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev->port, mdev->unit); 26247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto fail_nolock; 26347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 26447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 26547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin atomic_set(&mdev->busy, 1); 26647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 26747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin locking = maple_add_packet(mdev, MAPLE_FUNC_MEMCARD, 26847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin MAPLE_COMMAND_BWRITE, phaselen / 4 + 2, sendbuf); 26947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin wait = wait_event_interruptible_timeout(mdev->maple_wait, 27047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin atomic_read(&mdev->busy) == 0, HZ/10); 27147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (locking) { 27247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin error = -EIO; 27347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin atomic_set(&mdev->busy, 0); 27447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto fail_nolock; 27547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 27647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (atomic_read(&mdev->busy) == 2) { 27747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin atomic_set(&mdev->busy, 0); 27847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } else if (wait == 0 || wait == -ERESTARTSYS) { 27947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin error = -EIO; 28047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin dev_warn(&mdev->dev, "Write at (%d, %d) of block" 28147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin " 0x%X at phase %d failed: could not" 28247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin " communicate with VMU", mdev->port, 28347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev->unit, num, x); 28447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin atomic_set(&mdev->busy, 0); 28547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin kfree(mdev->mq->sendbuf); 28647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev->mq->sendbuf = NULL; 28747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin list_del_init(&(mdev->mq->list)); 28847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto fail_nolock; 28947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 29047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 29147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin kfree(sendbuf); 29247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 29347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin return card->blocklen; 29447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 29547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminfail_nolock: 29647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin kfree(sendbuf); 29747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminfail_nosendbuf: 29847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin dev_err(&mdev->dev, "VMU (%d, %d): write failed\n", mdev->port, 29947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev->unit); 30047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin return error; 30147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin} 30247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 30347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin/* mtd function to simulate reading byte by byte */ 30447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminstatic unsigned char vmu_flash_read_char(unsigned long ofs, int *retval, 30547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct mtd_info *mtd) 30647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin{ 30747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct vmu_block *vblock; 30847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct memcard *card; 30947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct mdev_part *mpart; 31047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct maple_device *mdev; 31147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin unsigned char *buf, ret; 31247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin int partition, error; 31347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 31447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mpart = mtd->priv; 31547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev = mpart->mdev; 31647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin partition = mpart->partition; 31747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card = maple_get_drvdata(mdev); 31847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin *retval = 0; 31947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 32047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin buf = kmalloc(card->blocklen, GFP_KERNEL); 32147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (!buf) { 32247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin *retval = 1; 32347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin ret = -ENOMEM; 32447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto finish; 32547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 32647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 32747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin vblock = ofs_to_block(ofs, mtd, partition); 32847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (!vblock) { 32947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin *retval = 3; 33047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin ret = -ENOMEM; 33147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto out_buf; 33247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 33347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 33447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin error = maple_vmu_read_block(vblock->num, buf, mtd); 33547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (error) { 33647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin ret = error; 33747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin *retval = 2; 33847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto out_vblock; 33947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 34047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 34147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin ret = buf[vblock->ofs]; 34247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 34347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminout_vblock: 34447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin kfree(vblock); 34547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminout_buf: 34647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin kfree(buf); 34747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminfinish: 34847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin return ret; 34947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin} 35047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 35147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin/* mtd higher order function to read flash */ 35247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminstatic int vmu_flash_read(struct mtd_info *mtd, loff_t from, size_t len, 35347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin size_t *retlen, u_char *buf) 35447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin{ 35547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct maple_device *mdev; 35647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct memcard *card; 35747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct mdev_part *mpart; 35847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct vmu_cache *pcache; 35947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct vmu_block *vblock; 36047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin int index = 0, retval, partition, leftover, numblocks; 36147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin unsigned char cx; 36247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 36347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mpart = mtd->priv; 36447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev = mpart->mdev; 36547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin partition = mpart->partition; 36647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card = maple_get_drvdata(mdev); 36747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 36847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin numblocks = card->parts[partition].numblocks; 36947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (from + len > numblocks * card->blocklen) 37047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin len = numblocks * card->blocklen - from; 37147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (len == 0) 37247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin return -EIO; 37347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin /* Have we cached this bit already? */ 37447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin pcache = card->parts[partition].pcache; 37547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin do { 37647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin vblock = ofs_to_block(from + index, mtd, partition); 37747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (!vblock) 37847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin return -ENOMEM; 37947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin /* Have we cached this and is the cache valid and timely? */ 38047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (pcache->valid && 38147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin time_before(jiffies, pcache->jiffies_atc + HZ) && 38247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin (pcache->block == vblock->num)) { 38347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin /* we have cached it, so do necessary copying */ 38447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin leftover = card->blocklen - vblock->ofs; 38547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (vblock->ofs + len - index < card->blocklen) { 38647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin /* only a bit of this block to copy */ 38747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin memcpy(buf + index, 38847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin pcache->buffer + vblock->ofs, 38947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin len - index); 39047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin index = len; 39147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } else { 39247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin /* otherwise copy remainder of whole block */ 39347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin memcpy(buf + index, pcache->buffer + 39447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin vblock->ofs, leftover); 39547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin index += leftover; 39647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 39747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } else { 39847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin /* 39947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * Not cached so read one byte - 40047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * but cache the rest of the block 40147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin */ 40247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin cx = vmu_flash_read_char(from + index, &retval, mtd); 40347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (retval) { 40447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin *retlen = index; 40547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin kfree(vblock); 40647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin return cx; 40747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 40847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin memset(buf + index, cx, 1); 40947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin index++; 41047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 41147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin kfree(vblock); 41247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } while (len > index); 41347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin *retlen = index; 41447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 41547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin return 0; 41647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin} 41747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 41847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminstatic int vmu_flash_write(struct mtd_info *mtd, loff_t to, size_t len, 41947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin size_t *retlen, const u_char *buf) 42047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin{ 42147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct maple_device *mdev; 42247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct memcard *card; 42347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct mdev_part *mpart; 42447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin int index = 0, partition, error = 0, numblocks; 42547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct vmu_cache *pcache; 42647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct vmu_block *vblock; 42747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin unsigned char *buffer; 42847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 42947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mpart = mtd->priv; 43047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev = mpart->mdev; 43147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin partition = mpart->partition; 43247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card = maple_get_drvdata(mdev); 43347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 43447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin numblocks = card->parts[partition].numblocks; 43547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (to + len > numblocks * card->blocklen) 43647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin len = numblocks * card->blocklen - to; 43747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (len == 0) { 43847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin error = -EIO; 43947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto failed; 44047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 44147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 44247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin vblock = ofs_to_block(to, mtd, partition); 44347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (!vblock) { 44447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin error = -ENOMEM; 44547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto failed; 44647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 44747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 44847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin buffer = kmalloc(card->blocklen, GFP_KERNEL); 44947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (!buffer) { 45047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin error = -ENOMEM; 45147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto fail_buffer; 45247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 45347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 45447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin do { 45547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin /* Read in the block we are to write to */ 45647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin error = maple_vmu_read_block(vblock->num, buffer, mtd); 45747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (error) 45847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto fail_io; 45947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 46047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin do { 46147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin buffer[vblock->ofs] = buf[index]; 46247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin vblock->ofs++; 46347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin index++; 46447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (index >= len) 46547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin break; 46647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } while (vblock->ofs < card->blocklen); 46747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 46847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin /* write out new buffer */ 46947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin error = maple_vmu_write_block(vblock->num, buffer, mtd); 47047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin /* invalidate the cache */ 47147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin pcache = card->parts[partition].pcache; 47247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin pcache->valid = 0; 47347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 47447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (error != card->blocklen) 47547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto fail_io; 47647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 47747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin vblock->num++; 47847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin vblock->ofs = 0; 47947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } while (len > index); 48047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 48147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin kfree(buffer); 48247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin *retlen = index; 48347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin kfree(vblock); 48447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin return 0; 48547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 48647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminfail_io: 48747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin kfree(buffer); 48847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminfail_buffer: 48947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin kfree(vblock); 49047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminfailed: 49147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin dev_err(&mdev->dev, "VMU write failing with error %d\n", error); 49247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin return error; 49347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin} 49447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 49547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminstatic void vmu_flash_sync(struct mtd_info *mtd) 49647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin{ 49747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin /* Do nothing here */ 49847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin} 49947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 50047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin/* Maple bus callback function to recursively query hardware details */ 50147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminstatic void vmu_queryblocks(struct mapleq *mq) 50247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin{ 50347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct maple_device *mdev; 50447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin unsigned short *res; 50547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct memcard *card; 50647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin __be32 partnum; 50747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct vmu_cache *pcache; 50847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct mdev_part *mpart; 50947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct mtd_info *mtd_cur; 51047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct vmupart *part_cur; 51147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin int error; 51247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 51347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev = mq->dev; 51447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card = maple_get_drvdata(mdev); 51547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin res = (unsigned short *) (mq->recvbuf->buf); 51647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card->tempA = res[12]; 51747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card->tempB = res[6]; 51847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 51947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin dev_info(&mdev->dev, "VMU device at partition %d has %d user " 52047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin "blocks with a root block at %d\n", card->partition, 52147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card->tempA, card->tempB); 52247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 52347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin part_cur = &card->parts[card->partition]; 52447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin part_cur->user_blocks = card->tempA; 52547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin part_cur->root_block = card->tempB; 52647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin part_cur->numblocks = card->tempB + 1; 52747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin part_cur->name = kmalloc(12, GFP_KERNEL); 52847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (!part_cur->name) 52947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto fail_name; 53047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 53147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin sprintf(part_cur->name, "vmu%d.%d.%d", 53247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev->port, mdev->unit, card->partition); 53347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mtd_cur = &card->mtd[card->partition]; 53447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mtd_cur->name = part_cur->name; 53547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mtd_cur->type = 8; 53647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mtd_cur->flags = MTD_WRITEABLE|MTD_NO_ERASE; 53747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mtd_cur->size = part_cur->numblocks * card->blocklen; 53847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mtd_cur->erasesize = card->blocklen; 5393c3c10bba1e4ccb75b41442e45c1a072f6cded19Artem Bityutskiy mtd_cur->_write = vmu_flash_write; 5403c3c10bba1e4ccb75b41442e45c1a072f6cded19Artem Bityutskiy mtd_cur->_read = vmu_flash_read; 5413c3c10bba1e4ccb75b41442e45c1a072f6cded19Artem Bityutskiy mtd_cur->_sync = vmu_flash_sync; 54247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mtd_cur->writesize = card->blocklen; 54347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 54447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mpart = kmalloc(sizeof(struct mdev_part), GFP_KERNEL); 54547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (!mpart) 54647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto fail_mpart; 54747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 54847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mpart->mdev = mdev; 54947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mpart->partition = card->partition; 55047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mtd_cur->priv = mpart; 55147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mtd_cur->owner = THIS_MODULE; 55247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 55347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin pcache = kzalloc(sizeof(struct vmu_cache), GFP_KERNEL); 55447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (!pcache) 55547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto fail_cache_create; 55647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin part_cur->pcache = pcache; 55747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 558ee0e87b174bb41f0310cf089262bf5dd8f95a212Jamie Iles error = mtd_device_register(mtd_cur, NULL, 0); 55947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (error) 56047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto fail_mtd_register; 56147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 56247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin maple_getcond_callback(mdev, NULL, 0, 56347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin MAPLE_FUNC_MEMCARD); 56447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 56547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin /* 56647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * Set up a recursive call to the (probably theoretical) 56747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * second or more partition 56847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin */ 56947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (++card->partition < card->partitions) { 57047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin partnum = cpu_to_be32(card->partition << 24); 57147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin maple_getcond_callback(mdev, vmu_queryblocks, 0, 57247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin MAPLE_FUNC_MEMCARD); 57347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin maple_add_packet(mdev, MAPLE_FUNC_MEMCARD, 57447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin MAPLE_COMMAND_GETMINFO, 2, &partnum); 57547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 57647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin return; 57747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 57847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminfail_mtd_register: 57947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin dev_err(&mdev->dev, "Could not register maple device at (%d, %d)" 58047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin "error is 0x%X\n", mdev->port, mdev->unit, error); 58147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin for (error = 0; error <= card->partition; error++) { 58247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin kfree(((card->parts)[error]).pcache); 58347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin ((card->parts)[error]).pcache = NULL; 58447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 58547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminfail_cache_create: 58647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminfail_mpart: 58747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin for (error = 0; error <= card->partition; error++) { 58847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin kfree(((card->mtd)[error]).priv); 58947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin ((card->mtd)[error]).priv = NULL; 59047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 59147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin maple_getcond_callback(mdev, NULL, 0, 59247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin MAPLE_FUNC_MEMCARD); 59347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin kfree(part_cur->name); 59447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminfail_name: 59547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin return; 59647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin} 59747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 59847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin/* Handles very basic info about the flash, queries for details */ 59906f25510692385ed4dadd23f7d3d064d1ab11c2dBill Pembertonstatic int vmu_connect(struct maple_device *mdev) 60047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin{ 60147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin unsigned long test_flash_data, basic_flash_data; 60247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin int c, error; 60347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct memcard *card; 60447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin u32 partnum = 0; 60547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 60647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin test_flash_data = be32_to_cpu(mdev->devinfo.function); 60747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin /* Need to count how many bits are set - to find out which 608782e5711d61b2cda45dea447badba3ab07c236f0Akinobu Mita * function_data element has details of the memory card 609782e5711d61b2cda45dea447badba3ab07c236f0Akinobu Mita */ 610782e5711d61b2cda45dea447badba3ab07c236f0Akinobu Mita c = hweight_long(test_flash_data); 61147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 61247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin basic_flash_data = be32_to_cpu(mdev->devinfo.function_data[c - 1]); 61347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 61447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card = kmalloc(sizeof(struct memcard), GFP_KERNEL); 61547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (!card) { 616895fb49459227edbb4a4e5a2b5e9d12c34640f84Roel Kluin error = -ENOMEM; 61747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto fail_nomem; 61847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 61947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 62047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card->partitions = (basic_flash_data >> 24 & 0xFF) + 1; 62147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card->blocklen = ((basic_flash_data >> 16 & 0xFF) + 1) << 5; 62247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card->writecnt = basic_flash_data >> 12 & 0xF; 62347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card->readcnt = basic_flash_data >> 8 & 0xF; 62447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card->removeable = basic_flash_data >> 7 & 1; 62547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 62647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card->partition = 0; 62747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 62847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin /* 62947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * Not sure there are actually any multi-partition devices in the 63047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * real world, but the hardware supports them, so, so will we 63147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin */ 63247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card->parts = kmalloc(sizeof(struct vmupart) * card->partitions, 63347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin GFP_KERNEL); 63447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (!card->parts) { 63547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin error = -ENOMEM; 63647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto fail_partitions; 63747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 63847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 63947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card->mtd = kmalloc(sizeof(struct mtd_info) * card->partitions, 64047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin GFP_KERNEL); 64147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (!card->mtd) { 64247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin error = -ENOMEM; 64347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto fail_mtd_info; 64447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 64547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 64647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin maple_set_drvdata(mdev, card); 64747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 64847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin /* 64947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * We want to trap meminfo not get cond 65047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * so set interval to zero, but rely on maple bus 65147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * driver to pass back the results of the meminfo 65247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin */ 65347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin maple_getcond_callback(mdev, vmu_queryblocks, 0, 65447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin MAPLE_FUNC_MEMCARD); 65547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 65647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin /* Make sure we are clear to go */ 65747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (atomic_read(&mdev->busy) == 1) { 65847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin wait_event_interruptible_timeout(mdev->maple_wait, 65947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin atomic_read(&mdev->busy) == 0, HZ); 66047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (atomic_read(&mdev->busy) == 1) { 66147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin dev_notice(&mdev->dev, "VMU at (%d, %d) is busy\n", 66247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev->port, mdev->unit); 66347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin error = -EAGAIN; 66447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto fail_device_busy; 66547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 66647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 66747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 66847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin atomic_set(&mdev->busy, 1); 66947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 67047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin /* 67147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * Set up the minfo call: vmu_queryblocks will handle 67247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * the information passed back 67347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin */ 67447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin error = maple_add_packet(mdev, MAPLE_FUNC_MEMCARD, 67547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin MAPLE_COMMAND_GETMINFO, 2, &partnum); 67647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (error) { 67747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin dev_err(&mdev->dev, "Could not lock VMU at (%d, %d)" 67847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin " error is 0x%X\n", mdev->port, mdev->unit, error); 67947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin goto fail_mtd_info; 68047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 68147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin return 0; 68247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 68347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminfail_device_busy: 68447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin kfree(card->mtd); 68547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminfail_mtd_info: 68647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin kfree(card->parts); 68747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminfail_partitions: 68847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin kfree(card); 68947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminfail_nomem: 69047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin return error; 69147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin} 69247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 693810b7e060c14110d8f580daaf77fab3a7d950483Bill Pembertonstatic void vmu_disconnect(struct maple_device *mdev) 69447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin{ 69547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct memcard *card; 69647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct mdev_part *mpart; 69747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin int x; 69847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 69947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev->callback = NULL; 70047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card = maple_get_drvdata(mdev); 70147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin for (x = 0; x < card->partitions; x++) { 70247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mpart = ((card->mtd)[x]).priv; 70347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mpart->mdev = NULL; 704ee0e87b174bb41f0310cf089262bf5dd8f95a212Jamie Iles mtd_device_unregister(&((card->mtd)[x])); 70547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin kfree(((card->parts)[x]).name); 70647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 70747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin kfree(card->parts); 70847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin kfree(card->mtd); 70947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin kfree(card); 71047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin} 71147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 71247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin/* Callback to handle eccentricities of both mtd subsystem 71347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin * and general flakyness of Dreamcast VMUs 71447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin */ 71547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminstatic int vmu_can_unload(struct maple_device *mdev) 71647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin{ 71747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct memcard *card; 71847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin int x; 71947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct mtd_info *mtd; 72047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 72147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin card = maple_get_drvdata(mdev); 72247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin for (x = 0; x < card->partitions; x++) { 72347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mtd = &((card->mtd)[x]); 72447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (mtd->usecount > 0) 72547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin return 0; 72647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 72747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin return 1; 72847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin} 72947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 73047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin#define ERRSTR "VMU at (%d, %d) file error -" 73147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 73247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminstatic void vmu_file_error(struct maple_device *mdev, void *recvbuf) 73347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin{ 73447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin enum maple_file_errors error = ((int *)recvbuf)[1]; 73547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 73647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin switch (error) { 73747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 73847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin case MAPLE_FILEERR_INVALID_PARTITION: 73947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin dev_notice(&mdev->dev, ERRSTR " invalid partition number\n", 74047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev->port, mdev->unit); 74147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin break; 74247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 74347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin case MAPLE_FILEERR_PHASE_ERROR: 74447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin dev_notice(&mdev->dev, ERRSTR " phase error\n", 74547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev->port, mdev->unit); 74647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin break; 74747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 74847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin case MAPLE_FILEERR_INVALID_BLOCK: 74947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin dev_notice(&mdev->dev, ERRSTR " invalid block number\n", 75047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev->port, mdev->unit); 75147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin break; 75247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 75347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin case MAPLE_FILEERR_WRITE_ERROR: 75447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin dev_notice(&mdev->dev, ERRSTR " write error\n", 75547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev->port, mdev->unit); 75647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin break; 75747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 75847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin case MAPLE_FILEERR_INVALID_WRITE_LENGTH: 75947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin dev_notice(&mdev->dev, ERRSTR " invalid write length\n", 76047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev->port, mdev->unit); 76147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin break; 76247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 76347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin case MAPLE_FILEERR_BAD_CRC: 76447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin dev_notice(&mdev->dev, ERRSTR " bad CRC\n", 76547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev->port, mdev->unit); 76647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin break; 76747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 76847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin default: 76947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin dev_notice(&mdev->dev, ERRSTR " 0x%X\n", 77047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev->port, mdev->unit, error); 77147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin } 77247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin} 77347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 77447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 77506f25510692385ed4dadd23f7d3d064d1ab11c2dBill Pembertonstatic int probe_maple_vmu(struct device *dev) 77647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin{ 77747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin int error; 77847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct maple_device *mdev = to_maple_dev(dev); 77947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct maple_driver *mdrv = to_maple_driver(dev->driver); 78047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 78147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev->can_unload = vmu_can_unload; 78247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev->fileerr_handler = vmu_file_error; 78347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin mdev->driver = mdrv; 78447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 78547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin error = vmu_connect(mdev); 78647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin if (error) 78747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin return error; 78847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 78947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin return 0; 79047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin} 79147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 792810b7e060c14110d8f580daaf77fab3a7d950483Bill Pembertonstatic int remove_maple_vmu(struct device *dev) 79347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin{ 79447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin struct maple_device *mdev = to_maple_dev(dev); 79547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 79647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin vmu_disconnect(mdev); 79747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin return 0; 79847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin} 79947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 80047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminstatic struct maple_driver vmu_flash_driver = { 80147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin .function = MAPLE_FUNC_MEMCARD, 80247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin .drv = { 80347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin .name = "Dreamcast_visual_memory", 80447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin .probe = probe_maple_vmu, 8055153b88cac39b0a14662f0e15439b826bacfe213Bill Pemberton .remove = remove_maple_vmu, 80647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin }, 80747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin}; 80847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 80947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminstatic int __init vmu_flash_map_init(void) 81047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin{ 81147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin return maple_driver_register(&vmu_flash_driver); 81247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin} 81347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 81447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminstatic void __exit vmu_flash_map_exit(void) 81547a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin{ 81647a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin maple_driver_unregister(&vmu_flash_driver); 81747a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin} 81847a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 81947a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminmodule_init(vmu_flash_map_init); 82047a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminmodule_exit(vmu_flash_map_exit); 82147a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenamin 82247a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminMODULE_LICENSE("GPL"); 82347a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminMODULE_AUTHOR("Adrian McMenamin"); 82447a72688fae7298e1ad5fdc9bff7e04b6a549620Adrian McMenaminMODULE_DESCRIPTION("Flash mapping for Sega Dreamcast visual memory"); 825