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