cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vmu-flash.c (19788B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* vmu-flash.c
      3 * Driver for SEGA Dreamcast Visual Memory Unit
      4 *
      5 * Copyright (c) Adrian McMenamin 2002 - 2009
      6 * Copyright (c) Paul Mundt 2001
      7 */
      8#include <linux/init.h>
      9#include <linux/slab.h>
     10#include <linux/sched.h>
     11#include <linux/delay.h>
     12#include <linux/maple.h>
     13#include <linux/mtd/mtd.h>
     14#include <linux/mtd/map.h>
     15
     16struct vmu_cache {
     17	unsigned char *buffer;		/* Cache */
     18	unsigned int block;		/* Which block was cached */
     19	unsigned long jiffies_atc;	/* When was it cached? */
     20	int valid;
     21};
     22
     23struct mdev_part {
     24	struct maple_device *mdev;
     25	int partition;
     26};
     27
     28struct vmupart {
     29	u16 user_blocks;
     30	u16 root_block;
     31	u16 numblocks;
     32	char *name;
     33	struct vmu_cache *pcache;
     34};
     35
     36struct memcard {
     37	u16 tempA;
     38	u16 tempB;
     39	u32 partitions;
     40	u32 blocklen;
     41	u32 writecnt;
     42	u32 readcnt;
     43	u32 removable;
     44	int partition;
     45	int read;
     46	unsigned char *blockread;
     47	struct vmupart *parts;
     48	struct mtd_info *mtd;
     49};
     50
     51struct vmu_block {
     52	unsigned int num; /* block number */
     53	unsigned int ofs; /* block offset */
     54};
     55
     56static struct vmu_block *ofs_to_block(unsigned long src_ofs,
     57	struct mtd_info *mtd, int partition)
     58{
     59	struct vmu_block *vblock;
     60	struct maple_device *mdev;
     61	struct memcard *card;
     62	struct mdev_part *mpart;
     63	int num;
     64
     65	mpart = mtd->priv;
     66	mdev = mpart->mdev;
     67	card = maple_get_drvdata(mdev);
     68
     69	if (src_ofs >= card->parts[partition].numblocks * card->blocklen)
     70		goto failed;
     71
     72	num = src_ofs / card->blocklen;
     73	if (num > card->parts[partition].numblocks)
     74		goto failed;
     75
     76	vblock = kmalloc(sizeof(struct vmu_block), GFP_KERNEL);
     77	if (!vblock)
     78		goto failed;
     79
     80	vblock->num = num;
     81	vblock->ofs = src_ofs % card->blocklen;
     82	return vblock;
     83
     84failed:
     85	return NULL;
     86}
     87
     88/* Maple bus callback function for reads */
     89static void vmu_blockread(struct mapleq *mq)
     90{
     91	struct maple_device *mdev;
     92	struct memcard *card;
     93
     94	mdev = mq->dev;
     95	card = maple_get_drvdata(mdev);
     96	/* copy the read in data */
     97
     98	if (unlikely(!card->blockread))
     99		return;
    100
    101	memcpy(card->blockread, mq->recvbuf->buf + 12,
    102		card->blocklen/card->readcnt);
    103
    104}
    105
    106/* Interface with maple bus to read blocks
    107 * caching the results so that other parts
    108 * of the driver can access block reads */
    109static int maple_vmu_read_block(unsigned int num, unsigned char *buf,
    110	struct mtd_info *mtd)
    111{
    112	struct memcard *card;
    113	struct mdev_part *mpart;
    114	struct maple_device *mdev;
    115	int partition, error = 0, x, wait;
    116	unsigned char *blockread = NULL;
    117	struct vmu_cache *pcache;
    118	__be32 sendbuf;
    119
    120	mpart = mtd->priv;
    121	mdev = mpart->mdev;
    122	partition = mpart->partition;
    123	card = maple_get_drvdata(mdev);
    124	pcache = card->parts[partition].pcache;
    125	pcache->valid = 0;
    126
    127	/* prepare the cache for this block */
    128	if (!pcache->buffer) {
    129		pcache->buffer = kmalloc(card->blocklen, GFP_KERNEL);
    130		if (!pcache->buffer) {
    131			dev_err(&mdev->dev, "VMU at (%d, %d) - read fails due"
    132				" to lack of memory\n", mdev->port,
    133				mdev->unit);
    134			error = -ENOMEM;
    135			goto outB;
    136		}
    137	}
    138
    139	/*
    140	* Reads may be phased - again the hardware spec
    141	* supports this - though may not be any devices in
    142	* the wild that implement it, but we will here
    143	*/
    144	for (x = 0; x < card->readcnt; x++) {
    145		sendbuf = cpu_to_be32(partition << 24 | x << 16 | num);
    146
    147		if (atomic_read(&mdev->busy) == 1) {
    148			wait_event_interruptible_timeout(mdev->maple_wait,
    149				atomic_read(&mdev->busy) == 0, HZ);
    150			if (atomic_read(&mdev->busy) == 1) {
    151				dev_notice(&mdev->dev, "VMU at (%d, %d)"
    152					" is busy\n", mdev->port, mdev->unit);
    153				error = -EAGAIN;
    154				goto outB;
    155			}
    156		}
    157
    158		atomic_set(&mdev->busy, 1);
    159		blockread = kmalloc(card->blocklen/card->readcnt, GFP_KERNEL);
    160		if (!blockread) {
    161			error = -ENOMEM;
    162			atomic_set(&mdev->busy, 0);
    163			goto outB;
    164		}
    165		card->blockread = blockread;
    166
    167		maple_getcond_callback(mdev, vmu_blockread, 0,
    168			MAPLE_FUNC_MEMCARD);
    169		error = maple_add_packet(mdev, MAPLE_FUNC_MEMCARD,
    170				MAPLE_COMMAND_BREAD, 2, &sendbuf);
    171		/* Very long timeouts seem to be needed when box is stressed */
    172		wait = wait_event_interruptible_timeout(mdev->maple_wait,
    173			(atomic_read(&mdev->busy) == 0 ||
    174			atomic_read(&mdev->busy) == 2), HZ * 3);
    175		/*
    176		* MTD layer does not handle hotplugging well
    177		* so have to return errors when VMU is unplugged
    178		* in the middle of a read (busy == 2)
    179		*/
    180		if (error || atomic_read(&mdev->busy) == 2) {
    181			if (atomic_read(&mdev->busy) == 2)
    182				error = -ENXIO;
    183			atomic_set(&mdev->busy, 0);
    184			card->blockread = NULL;
    185			goto outA;
    186		}
    187		if (wait == 0 || wait == -ERESTARTSYS) {
    188			card->blockread = NULL;
    189			atomic_set(&mdev->busy, 0);
    190			error = -EIO;
    191			list_del_init(&(mdev->mq->list));
    192			kfree(mdev->mq->sendbuf);
    193			mdev->mq->sendbuf = NULL;
    194			if (wait == -ERESTARTSYS) {
    195				dev_warn(&mdev->dev, "VMU read on (%d, %d)"
    196					" interrupted on block 0x%X\n",
    197					mdev->port, mdev->unit, num);
    198			} else
    199				dev_notice(&mdev->dev, "VMU read on (%d, %d)"
    200					" timed out on block 0x%X\n",
    201					mdev->port, mdev->unit, num);
    202			goto outA;
    203		}
    204
    205		memcpy(buf + (card->blocklen/card->readcnt) * x, blockread,
    206			card->blocklen/card->readcnt);
    207
    208		memcpy(pcache->buffer + (card->blocklen/card->readcnt) * x,
    209			card->blockread, card->blocklen/card->readcnt);
    210		card->blockread = NULL;
    211		pcache->block = num;
    212		pcache->jiffies_atc = jiffies;
    213		pcache->valid = 1;
    214		kfree(blockread);
    215	}
    216
    217	return error;
    218
    219outA:
    220	kfree(blockread);
    221outB:
    222	return error;
    223}
    224
    225/* communicate with maple bus for phased writing */
    226static int maple_vmu_write_block(unsigned int num, const unsigned char *buf,
    227	struct mtd_info *mtd)
    228{
    229	struct memcard *card;
    230	struct mdev_part *mpart;
    231	struct maple_device *mdev;
    232	int partition, error, locking, x, phaselen, wait;
    233	__be32 *sendbuf;
    234
    235	mpart = mtd->priv;
    236	mdev = mpart->mdev;
    237	partition = mpart->partition;
    238	card = maple_get_drvdata(mdev);
    239
    240	phaselen = card->blocklen/card->writecnt;
    241
    242	sendbuf = kmalloc(phaselen + 4, GFP_KERNEL);
    243	if (!sendbuf) {
    244		error = -ENOMEM;
    245		goto fail_nosendbuf;
    246	}
    247	for (x = 0; x < card->writecnt; x++) {
    248		sendbuf[0] = cpu_to_be32(partition << 24 | x << 16 | num);
    249		memcpy(&sendbuf[1], buf + phaselen * x, phaselen);
    250		/* wait until the device is not busy doing something else
    251		* or 1 second - which ever is longer */
    252		if (atomic_read(&mdev->busy) == 1) {
    253			wait_event_interruptible_timeout(mdev->maple_wait,
    254				atomic_read(&mdev->busy) == 0, HZ);
    255			if (atomic_read(&mdev->busy) == 1) {
    256				error = -EBUSY;
    257				dev_notice(&mdev->dev, "VMU write at (%d, %d)"
    258					"failed - device is busy\n",
    259					mdev->port, mdev->unit);
    260				goto fail_nolock;
    261			}
    262		}
    263		atomic_set(&mdev->busy, 1);
    264
    265		locking = maple_add_packet(mdev, MAPLE_FUNC_MEMCARD,
    266			MAPLE_COMMAND_BWRITE, phaselen / 4 + 2, sendbuf);
    267		wait = wait_event_interruptible_timeout(mdev->maple_wait,
    268			atomic_read(&mdev->busy) == 0, HZ/10);
    269		if (locking) {
    270			error = -EIO;
    271			atomic_set(&mdev->busy, 0);
    272			goto fail_nolock;
    273		}
    274		if (atomic_read(&mdev->busy) == 2) {
    275			atomic_set(&mdev->busy, 0);
    276		} else if (wait == 0 || wait == -ERESTARTSYS) {
    277			error = -EIO;
    278			dev_warn(&mdev->dev, "Write at (%d, %d) of block"
    279				" 0x%X at phase %d failed: could not"
    280				" communicate with VMU", mdev->port,
    281				mdev->unit, num, x);
    282			atomic_set(&mdev->busy, 0);
    283			kfree(mdev->mq->sendbuf);
    284			mdev->mq->sendbuf = NULL;
    285			list_del_init(&(mdev->mq->list));
    286			goto fail_nolock;
    287		}
    288	}
    289	kfree(sendbuf);
    290
    291	return card->blocklen;
    292
    293fail_nolock:
    294	kfree(sendbuf);
    295fail_nosendbuf:
    296	dev_err(&mdev->dev, "VMU (%d, %d): write failed\n", mdev->port,
    297		mdev->unit);
    298	return error;
    299}
    300
    301/* mtd function to simulate reading byte by byte */
    302static unsigned char vmu_flash_read_char(unsigned long ofs, int *retval,
    303	struct mtd_info *mtd)
    304{
    305	struct vmu_block *vblock;
    306	struct memcard *card;
    307	struct mdev_part *mpart;
    308	struct maple_device *mdev;
    309	unsigned char *buf, ret;
    310	int partition, error;
    311
    312	mpart = mtd->priv;
    313	mdev = mpart->mdev;
    314	partition = mpart->partition;
    315	card = maple_get_drvdata(mdev);
    316	*retval =  0;
    317
    318	buf = kmalloc(card->blocklen, GFP_KERNEL);
    319	if (!buf) {
    320		*retval = 1;
    321		ret = -ENOMEM;
    322		goto finish;
    323	}
    324
    325	vblock = ofs_to_block(ofs, mtd, partition);
    326	if (!vblock) {
    327		*retval = 3;
    328		ret = -ENOMEM;
    329		goto out_buf;
    330	}
    331
    332	error = maple_vmu_read_block(vblock->num, buf, mtd);
    333	if (error) {
    334		ret = error;
    335		*retval = 2;
    336		goto out_vblock;
    337	}
    338
    339	ret = buf[vblock->ofs];
    340
    341out_vblock:
    342	kfree(vblock);
    343out_buf:
    344	kfree(buf);
    345finish:
    346	return ret;
    347}
    348
    349/* mtd higher order function to read flash */
    350static int vmu_flash_read(struct mtd_info *mtd, loff_t from, size_t len,
    351	size_t *retlen,  u_char *buf)
    352{
    353	struct maple_device *mdev;
    354	struct memcard *card;
    355	struct mdev_part *mpart;
    356	struct vmu_cache *pcache;
    357	struct vmu_block *vblock;
    358	int index = 0, retval, partition, leftover, numblocks;
    359	unsigned char cx;
    360
    361	mpart = mtd->priv;
    362	mdev = mpart->mdev;
    363	partition = mpart->partition;
    364	card = maple_get_drvdata(mdev);
    365
    366	numblocks = card->parts[partition].numblocks;
    367	if (from + len > numblocks * card->blocklen)
    368		len = numblocks * card->blocklen - from;
    369	if (len == 0)
    370		return -EIO;
    371	/* Have we cached this bit already? */
    372	pcache = card->parts[partition].pcache;
    373	do {
    374		vblock =  ofs_to_block(from + index, mtd, partition);
    375		if (!vblock)
    376			return -ENOMEM;
    377		/* Have we cached this and is the cache valid and timely? */
    378		if (pcache->valid &&
    379			time_before(jiffies, pcache->jiffies_atc + HZ) &&
    380			(pcache->block == vblock->num)) {
    381			/* we have cached it, so do necessary copying */
    382			leftover = card->blocklen - vblock->ofs;
    383			if (vblock->ofs + len - index < card->blocklen) {
    384				/* only a bit of this block to copy */
    385				memcpy(buf + index,
    386					pcache->buffer + vblock->ofs,
    387					len - index);
    388				index = len;
    389			} else {
    390				/* otherwise copy remainder of whole block */
    391				memcpy(buf + index, pcache->buffer +
    392					vblock->ofs, leftover);
    393				index += leftover;
    394			}
    395		} else {
    396			/*
    397			* Not cached so read one byte -
    398			* but cache the rest of the block
    399			*/
    400			cx = vmu_flash_read_char(from + index, &retval, mtd);
    401			if (retval) {
    402				*retlen = index;
    403				kfree(vblock);
    404				return cx;
    405			}
    406			memset(buf + index, cx, 1);
    407			index++;
    408		}
    409		kfree(vblock);
    410	} while (len > index);
    411	*retlen = index;
    412
    413	return 0;
    414}
    415
    416static int vmu_flash_write(struct mtd_info *mtd, loff_t to, size_t len,
    417	size_t *retlen, const u_char *buf)
    418{
    419	struct maple_device *mdev;
    420	struct memcard *card;
    421	struct mdev_part *mpart;
    422	int index = 0, partition, error = 0, numblocks;
    423	struct vmu_cache *pcache;
    424	struct vmu_block *vblock;
    425	unsigned char *buffer;
    426
    427	mpart = mtd->priv;
    428	mdev = mpart->mdev;
    429	partition = mpart->partition;
    430	card = maple_get_drvdata(mdev);
    431
    432	numblocks = card->parts[partition].numblocks;
    433	if (to + len > numblocks * card->blocklen)
    434		len = numblocks * card->blocklen - to;
    435	if (len == 0) {
    436		error = -EIO;
    437		goto failed;
    438	}
    439
    440	vblock = ofs_to_block(to, mtd, partition);
    441	if (!vblock) {
    442		error = -ENOMEM;
    443		goto failed;
    444	}
    445
    446	buffer = kmalloc(card->blocklen, GFP_KERNEL);
    447	if (!buffer) {
    448		error = -ENOMEM;
    449		goto fail_buffer;
    450	}
    451
    452	do {
    453		/* Read in the block we are to write to */
    454		error = maple_vmu_read_block(vblock->num, buffer, mtd);
    455		if (error)
    456			goto fail_io;
    457
    458		do {
    459			buffer[vblock->ofs] = buf[index];
    460			vblock->ofs++;
    461			index++;
    462			if (index >= len)
    463				break;
    464		} while (vblock->ofs < card->blocklen);
    465
    466		/* write out new buffer */
    467		error = maple_vmu_write_block(vblock->num, buffer, mtd);
    468		/* invalidate the cache */
    469		pcache = card->parts[partition].pcache;
    470		pcache->valid = 0;
    471
    472		if (error != card->blocklen)
    473			goto fail_io;
    474
    475		vblock->num++;
    476		vblock->ofs = 0;
    477	} while (len > index);
    478
    479	kfree(buffer);
    480	*retlen = index;
    481	kfree(vblock);
    482	return 0;
    483
    484fail_io:
    485	kfree(buffer);
    486fail_buffer:
    487	kfree(vblock);
    488failed:
    489	dev_err(&mdev->dev, "VMU write failing with error %d\n", error);
    490	return error;
    491}
    492
    493static void vmu_flash_sync(struct mtd_info *mtd)
    494{
    495	/* Do nothing here */
    496}
    497
    498/* Maple bus callback function to recursively query hardware details */
    499static void vmu_queryblocks(struct mapleq *mq)
    500{
    501	struct maple_device *mdev;
    502	unsigned short *res;
    503	struct memcard *card;
    504	__be32 partnum;
    505	struct vmu_cache *pcache;
    506	struct mdev_part *mpart;
    507	struct mtd_info *mtd_cur;
    508	struct vmupart *part_cur;
    509	int error;
    510
    511	mdev = mq->dev;
    512	card = maple_get_drvdata(mdev);
    513	res = (unsigned short *) (mq->recvbuf->buf);
    514	card->tempA = res[12];
    515	card->tempB = res[6];
    516
    517	dev_info(&mdev->dev, "VMU device at partition %d has %d user "
    518		"blocks with a root block at %d\n", card->partition,
    519		card->tempA, card->tempB);
    520
    521	part_cur = &card->parts[card->partition];
    522	part_cur->user_blocks = card->tempA;
    523	part_cur->root_block = card->tempB;
    524	part_cur->numblocks = card->tempB + 1;
    525	part_cur->name = kmalloc(12, GFP_KERNEL);
    526	if (!part_cur->name)
    527		goto fail_name;
    528
    529	sprintf(part_cur->name, "vmu%d.%d.%d",
    530		mdev->port, mdev->unit, card->partition);
    531	mtd_cur = &card->mtd[card->partition];
    532	mtd_cur->name = part_cur->name;
    533	mtd_cur->type = 8;
    534	mtd_cur->flags = MTD_WRITEABLE|MTD_NO_ERASE;
    535	mtd_cur->size = part_cur->numblocks * card->blocklen;
    536	mtd_cur->erasesize = card->blocklen;
    537	mtd_cur->_write = vmu_flash_write;
    538	mtd_cur->_read = vmu_flash_read;
    539	mtd_cur->_sync = vmu_flash_sync;
    540	mtd_cur->writesize = card->blocklen;
    541
    542	mpart = kmalloc(sizeof(struct mdev_part), GFP_KERNEL);
    543	if (!mpart)
    544		goto fail_mpart;
    545
    546	mpart->mdev = mdev;
    547	mpart->partition = card->partition;
    548	mtd_cur->priv = mpart;
    549	mtd_cur->owner = THIS_MODULE;
    550
    551	pcache = kzalloc(sizeof(struct vmu_cache), GFP_KERNEL);
    552	if (!pcache)
    553		goto fail_cache_create;
    554	part_cur->pcache = pcache;
    555
    556	error = mtd_device_register(mtd_cur, NULL, 0);
    557	if (error)
    558		goto fail_mtd_register;
    559
    560	maple_getcond_callback(mdev, NULL, 0,
    561		MAPLE_FUNC_MEMCARD);
    562
    563	/*
    564	* Set up a recursive call to the (probably theoretical)
    565	* second or more partition
    566	*/
    567	if (++card->partition < card->partitions) {
    568		partnum = cpu_to_be32(card->partition << 24);
    569		maple_getcond_callback(mdev, vmu_queryblocks, 0,
    570			MAPLE_FUNC_MEMCARD);
    571		maple_add_packet(mdev, MAPLE_FUNC_MEMCARD,
    572			MAPLE_COMMAND_GETMINFO, 2, &partnum);
    573	}
    574	return;
    575
    576fail_mtd_register:
    577	dev_err(&mdev->dev, "Could not register maple device at (%d, %d)"
    578		"error is 0x%X\n", mdev->port, mdev->unit, error);
    579	for (error = 0; error <= card->partition; error++) {
    580		kfree(((card->parts)[error]).pcache);
    581		((card->parts)[error]).pcache = NULL;
    582	}
    583fail_cache_create:
    584fail_mpart:
    585	for (error = 0; error <= card->partition; error++) {
    586		kfree(((card->mtd)[error]).priv);
    587		((card->mtd)[error]).priv = NULL;
    588	}
    589	maple_getcond_callback(mdev, NULL, 0,
    590		MAPLE_FUNC_MEMCARD);
    591	kfree(part_cur->name);
    592fail_name:
    593	return;
    594}
    595
    596/* Handles very basic info about the flash, queries for details */
    597static int vmu_connect(struct maple_device *mdev)
    598{
    599	unsigned long test_flash_data, basic_flash_data;
    600	int c, error;
    601	struct memcard *card;
    602	u32 partnum = 0;
    603
    604	test_flash_data = be32_to_cpu(mdev->devinfo.function);
    605	/* Need to count how many bits are set - to find out which
    606	 * function_data element has details of the memory card
    607	 */
    608	c = hweight_long(test_flash_data);
    609
    610	basic_flash_data = be32_to_cpu(mdev->devinfo.function_data[c - 1]);
    611
    612	card = kmalloc(sizeof(struct memcard), GFP_KERNEL);
    613	if (!card) {
    614		error = -ENOMEM;
    615		goto fail_nomem;
    616	}
    617
    618	card->partitions = (basic_flash_data >> 24 & 0xFF) + 1;
    619	card->blocklen = ((basic_flash_data >> 16 & 0xFF) + 1) << 5;
    620	card->writecnt = basic_flash_data >> 12 & 0xF;
    621	card->readcnt = basic_flash_data >> 8 & 0xF;
    622	card->removable = basic_flash_data >> 7 & 1;
    623
    624	card->partition = 0;
    625
    626	/*
    627	* Not sure there are actually any multi-partition devices in the
    628	* real world, but the hardware supports them, so, so will we
    629	*/
    630	card->parts = kmalloc_array(card->partitions, sizeof(struct vmupart),
    631				    GFP_KERNEL);
    632	if (!card->parts) {
    633		error = -ENOMEM;
    634		goto fail_partitions;
    635	}
    636
    637	card->mtd = kmalloc_array(card->partitions, sizeof(struct mtd_info),
    638				  GFP_KERNEL);
    639	if (!card->mtd) {
    640		error = -ENOMEM;
    641		goto fail_mtd_info;
    642	}
    643
    644	maple_set_drvdata(mdev, card);
    645
    646	/*
    647	* We want to trap meminfo not get cond
    648	* so set interval to zero, but rely on maple bus
    649	* driver to pass back the results of the meminfo
    650	*/
    651	maple_getcond_callback(mdev, vmu_queryblocks, 0,
    652		MAPLE_FUNC_MEMCARD);
    653
    654	/* Make sure we are clear to go */
    655	if (atomic_read(&mdev->busy) == 1) {
    656		wait_event_interruptible_timeout(mdev->maple_wait,
    657			atomic_read(&mdev->busy) == 0, HZ);
    658		if (atomic_read(&mdev->busy) == 1) {
    659			dev_notice(&mdev->dev, "VMU at (%d, %d) is busy\n",
    660				mdev->port, mdev->unit);
    661			error = -EAGAIN;
    662			goto fail_device_busy;
    663		}
    664	}
    665
    666	atomic_set(&mdev->busy, 1);
    667
    668	/*
    669	* Set up the minfo call: vmu_queryblocks will handle
    670	* the information passed back
    671	*/
    672	error = maple_add_packet(mdev, MAPLE_FUNC_MEMCARD,
    673		MAPLE_COMMAND_GETMINFO, 2, &partnum);
    674	if (error) {
    675		dev_err(&mdev->dev, "Could not lock VMU at (%d, %d)"
    676			" error is 0x%X\n", mdev->port, mdev->unit, error);
    677		goto fail_mtd_info;
    678	}
    679	return 0;
    680
    681fail_device_busy:
    682	kfree(card->mtd);
    683fail_mtd_info:
    684	kfree(card->parts);
    685fail_partitions:
    686	kfree(card);
    687fail_nomem:
    688	return error;
    689}
    690
    691static void vmu_disconnect(struct maple_device *mdev)
    692{
    693	struct memcard *card;
    694	struct mdev_part *mpart;
    695	int x;
    696
    697	mdev->callback = NULL;
    698	card = maple_get_drvdata(mdev);
    699	for (x = 0; x < card->partitions; x++) {
    700		mpart = ((card->mtd)[x]).priv;
    701		mpart->mdev = NULL;
    702		mtd_device_unregister(&((card->mtd)[x]));
    703		kfree(((card->parts)[x]).name);
    704	}
    705	kfree(card->parts);
    706	kfree(card->mtd);
    707	kfree(card);
    708}
    709
    710/* Callback to handle eccentricities of both mtd subsystem
    711 * and general flakyness of Dreamcast VMUs
    712 */
    713static int vmu_can_unload(struct maple_device *mdev)
    714{
    715	struct memcard *card;
    716	int x;
    717	struct mtd_info *mtd;
    718
    719	card = maple_get_drvdata(mdev);
    720	for (x = 0; x < card->partitions; x++) {
    721		mtd = &((card->mtd)[x]);
    722		if (mtd->usecount > 0)
    723			return 0;
    724	}
    725	return 1;
    726}
    727
    728#define ERRSTR "VMU at (%d, %d) file error -"
    729
    730static void vmu_file_error(struct maple_device *mdev, void *recvbuf)
    731{
    732	enum maple_file_errors error = ((int *)recvbuf)[1];
    733
    734	switch (error) {
    735
    736	case MAPLE_FILEERR_INVALID_PARTITION:
    737		dev_notice(&mdev->dev, ERRSTR " invalid partition number\n",
    738			mdev->port, mdev->unit);
    739		break;
    740
    741	case MAPLE_FILEERR_PHASE_ERROR:
    742		dev_notice(&mdev->dev, ERRSTR " phase error\n",
    743			mdev->port, mdev->unit);
    744		break;
    745
    746	case MAPLE_FILEERR_INVALID_BLOCK:
    747		dev_notice(&mdev->dev, ERRSTR " invalid block number\n",
    748			mdev->port, mdev->unit);
    749		break;
    750
    751	case MAPLE_FILEERR_WRITE_ERROR:
    752		dev_notice(&mdev->dev, ERRSTR " write error\n",
    753			mdev->port, mdev->unit);
    754		break;
    755
    756	case MAPLE_FILEERR_INVALID_WRITE_LENGTH:
    757		dev_notice(&mdev->dev, ERRSTR " invalid write length\n",
    758			mdev->port, mdev->unit);
    759		break;
    760
    761	case MAPLE_FILEERR_BAD_CRC:
    762		dev_notice(&mdev->dev, ERRSTR " bad CRC\n",
    763			mdev->port, mdev->unit);
    764		break;
    765
    766	default:
    767		dev_notice(&mdev->dev, ERRSTR " 0x%X\n",
    768			mdev->port, mdev->unit, error);
    769	}
    770}
    771
    772
    773static int probe_maple_vmu(struct device *dev)
    774{
    775	struct maple_device *mdev = to_maple_dev(dev);
    776	struct maple_driver *mdrv = to_maple_driver(dev->driver);
    777
    778	mdev->can_unload = vmu_can_unload;
    779	mdev->fileerr_handler = vmu_file_error;
    780	mdev->driver = mdrv;
    781
    782	return vmu_connect(mdev);
    783}
    784
    785static int remove_maple_vmu(struct device *dev)
    786{
    787	struct maple_device *mdev = to_maple_dev(dev);
    788
    789	vmu_disconnect(mdev);
    790	return 0;
    791}
    792
    793static struct maple_driver vmu_flash_driver = {
    794	.function =	MAPLE_FUNC_MEMCARD,
    795	.drv = {
    796		.name =		"Dreamcast_visual_memory",
    797		.probe =	probe_maple_vmu,
    798		.remove =	remove_maple_vmu,
    799	},
    800};
    801
    802static int __init vmu_flash_map_init(void)
    803{
    804	return maple_driver_register(&vmu_flash_driver);
    805}
    806
    807static void __exit vmu_flash_map_exit(void)
    808{
    809	maple_driver_unregister(&vmu_flash_driver);
    810}
    811
    812module_init(vmu_flash_map_init);
    813module_exit(vmu_flash_map_exit);
    814
    815MODULE_LICENSE("GPL");
    816MODULE_AUTHOR("Adrian McMenamin");
    817MODULE_DESCRIPTION("Flash mapping for Sega Dreamcast visual memory");