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