blob: a7ec947a3ebb1d262ac11ff0ccae218422e8b72e [file] [log] [blame]
Thomas Gleixner957ec1382019-06-04 10:11:00 +02001// SPDX-License-Identifier: GPL-2.0-only
Adrian McMenamin47a72682009-03-04 00:31:04 +00002/* 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
Adrian McMenamin47a72682009-03-04 00:31:04 +00007 */
8#include <linux/init.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +09009#include <linux/slab.h>
Adrian McMenamin47a72682009-03-04 00:31:04 +000010#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;
Bernard Zhao06262582020-09-22 04:28:02 -070043 u32 removable;
Adrian McMenamin47a72682009-03-04 00:31:04 +000044 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
Adrian McMenamin47a72682009-03-04 00:31:04 +0000361 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
Adrian McMenamin47a72682009-03-04 00:31:04 +0000432 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;
Artem Bityutskiy3c3c10b2012-01-30 14:58:32 +0200537 mtd_cur->_write = vmu_flash_write;
538 mtd_cur->_read = vmu_flash_read;
539 mtd_cur->_sync = vmu_flash_sync;
Adrian McMenamin47a72682009-03-04 00:31:04 +0000540 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
Jamie Ilesee0e87b2011-05-23 10:23:40 +0100556 error = mtd_device_register(mtd_cur, NULL, 0);
Adrian McMenamin47a72682009-03-04 00:31:04 +0000557 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 */
Bill Pemberton06f25512012-11-19 13:23:07 -0500597static int vmu_connect(struct maple_device *mdev)
Adrian McMenamin47a72682009-03-04 00:31:04 +0000598{
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
Akinobu Mita782e5712009-11-20 14:56:07 +0900606 * function_data element has details of the memory card
607 */
608 c = hweight_long(test_flash_data);
Adrian McMenamin47a72682009-03-04 00:31:04 +0000609
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) {
Roel Kluin895fb492009-11-11 21:47:06 +0100614 error = -ENOMEM;
Adrian McMenamin47a72682009-03-04 00:31:04 +0000615 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;
Bernard Zhao06262582020-09-22 04:28:02 -0700622 card->removable = basic_flash_data >> 7 & 1;
Adrian McMenamin47a72682009-03-04 00:31:04 +0000623
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 */
Kees Cook6da2ec52018-06-12 13:55:00 -0700630 card->parts = kmalloc_array(card->partitions, sizeof(struct vmupart),
631 GFP_KERNEL);
Adrian McMenamin47a72682009-03-04 00:31:04 +0000632 if (!card->parts) {
633 error = -ENOMEM;
634 goto fail_partitions;
635 }
636
Kees Cook6da2ec52018-06-12 13:55:00 -0700637 card->mtd = kmalloc_array(card->partitions, sizeof(struct mtd_info),
638 GFP_KERNEL);
Adrian McMenamin47a72682009-03-04 00:31:04 +0000639 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
Bill Pemberton810b7e02012-11-19 13:26:04 -0500691static void vmu_disconnect(struct maple_device *mdev)
Adrian McMenamin47a72682009-03-04 00:31:04 +0000692{
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;
Jamie Ilesee0e87b2011-05-23 10:23:40 +0100702 mtd_device_unregister(&((card->mtd)[x]));
Adrian McMenamin47a72682009-03-04 00:31:04 +0000703 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
Bill Pemberton06f25512012-11-19 13:23:07 -0500773static int probe_maple_vmu(struct device *dev)
Adrian McMenamin47a72682009-03-04 00:31:04 +0000774{
Adrian McMenamin47a72682009-03-04 00:31:04 +0000775 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
Liu Shixin6aec3452020-09-19 18:08:54 +0800782 return vmu_connect(mdev);
Adrian McMenamin47a72682009-03-04 00:31:04 +0000783}
784
Bill Pemberton810b7e02012-11-19 13:26:04 -0500785static int remove_maple_vmu(struct device *dev)
Adrian McMenamin47a72682009-03-04 00:31:04 +0000786{
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,
Bill Pemberton5153b882012-11-19 13:21:24 -0500798 .remove = remove_maple_vmu,
Adrian McMenamin47a72682009-03-04 00:31:04 +0000799 },
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");