]> pilppa.org Git - familiar-h63xx-build.git/blob - org.handhelds.familiar/packages/linux/opensimpad/mmc-spi.patch
OE tree imported from monotone branch org.openembedded.oz354fam083 at revision 8b12e3...
[familiar-h63xx-build.git] / org.handhelds.familiar / packages / linux / opensimpad / mmc-spi.patch
1
2 #
3 # Patch managed by http://www.holgerschurig.de/patcher.html
4 #
5
6 --- /dev/null
7 +++ linux-2.4.27/drivers/block/mmc.c
8 @@ -0,0 +1,857 @@
9 +/*
10 + * Copyright (c) ClĂ©ment Ballabriga, 2005 - GPL
11 + * Copyright (c) Guylhem Aznar, 2005 - GPL
12 + *
13 + * Please check http://externe.net/zaurus/simpad-bluetooth reference design first.
14 + *
15 + * Based on Madsuk/Rohde work on a MMC driver for the WRT54G.
16 + *
17 + * This is an ugly hack of a driver. I am surprised if it ever works!
18 + * So please use a real driver or contribute one to the 2.4/2.6 mmc framework
19 + */
20 +
21 +#include <linux/stddef.h>
22 +#include <linux/delay.h>
23 +#include <linux/timer.h>
24 +#include <linux/module.h>
25 +#include <linux/mm.h>
26 +#include <linux/init.h>
27 +#include <linux/fs.h>
28 +#include <linux/blkpg.h>
29 +#include <linux/hdreg.h>
30 +#include <linux/major.h>
31 +
32 +#include <asm/hardware.h>
33 +#include <asm/uaccess.h>
34 +#include <asm/io.h>
35 +
36 +/*
37 + * *******************************************************************
38 + *
39 + *                This is the only configurable part.
40 + *
41 + * *******************************************************************
42 + *
43 + */
44 +
45 +// #define DEBUG 1
46 +
47 +#define DEVICE_NAME "mmc"
48 +#define DEVICE_NR(device) (MINOR(device))
49 +#define DEVICE_ON(device)
50 +#define DEVICE_OFF(device)
51 +#define MAJOR_NR 121
52 +
53 +/* Let that include where it is or compilation fails on INIT_REQUEST/CURRENT */
54 +
55 +#include <linux/blk.h>
56 +
57 +MODULE_AUTHOR("Guylhem Aznar <mmc-driver @externe.net>");
58 +MODULE_DESCRIPTION("Driver for MMC/SD-Cards in SPI mode by GPIO");
59 +MODULE_SUPPORTED_DEVICE("Simpad");
60 +MODULE_LICENSE("GPL");
61 +
62 +/* Registers should be architecture independant - but it's not ! */
63 +
64 +#define MAP_START 0x90040000
65 +#define MAP_SIZE  0x00001000
66 +
67 +#define MY_GPLR 0
68 +#define MY_GPDR 1
69 +#define MY_GPSR 2
70 +#define MY_GPCR 3
71 +#define MY_GRER 4
72 +#define MY_GFER 5
73 +#define MY_GEDR 6
74 +#define MY_GAFR 7
75 +
76 +/*
77 + * If you are using different GPIOs in your hardware hack, you must
78 + * first make sure they are unused for other functions and then
79 + * configure them here.
80 + *
81 + * On the simpad I use spare pins from the UART1 (internal serial port):
82 + * - DCD (in)  : GPIO 23 : DO
83 + * - DTR (out) : GPIO 07 : CS 
84 + * - RI  (in)  : GPIO 19 : CLK
85 + * - DSR (in)  : GPIO 06 : DI
86 + *
87 + * Don't worry about in/out original function - the GPIOs will be
88 + * reprogrammed.
89 + */
90 +
91 +#define GPIO_SD_DO  23
92 +#define GPIO_SD_CS  7
93 +#define GPIO_SD_CLK 19
94 +#define GPIO_SD_DI  6
95 +
96 +/*
97 + * *******************************************************************
98 + *
99 + *               Do not change anything below !
100 + *
101 + * *******************************************************************
102 + *
103 + */
104 +
105 +
106 +/* GPIO states */
107 +#define LOW 0
108 +#define HIGH 1
109 +
110 +#define INPUT 0
111 +#define OUTPUT 1
112 +
113 +#define PRESENT 1
114 +#define ABSENT 0
115 +
116 +typedef unsigned int uint32;
117 +typedef unsigned long u32_t;
118 +typedef unsigned short u16_t;
119 +typedef unsigned char u8_t;
120 +
121 +/* we have only one device */
122 +static int hd_sizes[1 << 6];
123 +static int hd_blocksizes[1 << 6];
124 +static int hd_hardsectsizes[1 << 6];
125 +static int hd_maxsect[1 << 6];
126 +static struct hd_struct hd[1 << 6];
127 +
128 +static struct timer_list mmc_timer;
129 +
130 +/* start with no card */
131 +static int mmc_media_detect = 0;
132 +static int mmc_media_changed = 1;
133 +
134 +extern struct gendisk hd_gendisk;
135 +
136 +/* Use only one global device */
137 +typedef struct gpio_s gpio_t;
138 +struct gpio_s {
139 +    volatile u32_t *base;
140 +};
141 +
142 +static gpio_t gp = {
143 +       (void *) io_p2v(MAP_START)
144 +};
145 +
146 +/*
147 + * *******************************************************************
148 + *
149 + *             Begin GPIO hardware access functions.
150 + *
151 + * *******************************************************************
152 + *
153 + */
154 +
155 +gpio_t *gpio_open(void)
156 +{
157 +    static gpio_t tmp;
158 +    tmp.base = (void *) io_p2v(MAP_START);
159 +    return (&tmp);
160 +}
161 +
162 +void gpio_setdir(gpio_t * g, int num, int dir)
163 +{
164 +    if (dir == 1) {
165 +       g->base[MY_GPDR] |= (1 << num);
166 +    } else {
167 +       g->base[MY_GPDR] &= ~(1 << num);
168 +
169 +    }
170 +}
171 +
172 +void gpio_setalt(gpio_t * g, int num, int alt)
173 +{
174 +    if (alt == 1) {
175 +       g->base[MY_GAFR] |= (1 << num);
176 +    } else {
177 +       g->base[MY_GAFR] &= ~(1 << num);
178 +    }
179 +}
180 +
181 +int gpio_getdir(gpio_t * g, int num)
182 +{
183 +    return ((g->base[MY_GPDR] & (1 << num)) ? 1 : 0);
184 +}
185 +
186 +int gpio_getalt(gpio_t * g, int num)
187 +{
188 +    return ((g->base[MY_GAFR] & (1 << num)) ? 1 : 0);
189 +}
190 +
191 +static int gpio_read(gpio_t * g, int num)
192 +{
193 +       int what;
194 +    
195 +       what=(g->base[MY_GPLR] & (1 << num)) ? 1 : 0;
196 +       
197 +#ifdef DEBUG
198 +    if (num == GPIO_SD_DO) {
199 +           printk ("GPIO_SD_DO read: %u\n", what);
200 +    }
201 +#endif
202 +    return (what);
203 +}
204 +
205 +static int gpio_write(gpio_t * g, int num, int val)
206 +{
207 +#ifdef DEBUG
208 +       int check;
209 +#endif
210 +       
211 +    if (val == 1) {
212 +       g->base[MY_GPSR] = 1 << num;
213 +    } else {
214 +       g->base[MY_GPCR] = 1 << num;
215 +    }
216 +#ifdef DEBUG
217 +    check=gpio_read(g,num);
218 +    if (check != val)
219 +    {
220 +         printk ("Error while write to %d: found %d after writing %d\n",num, check, val);
221 +       return (1);
222 +    }
223 +    else return(0);
224 +#endif
225 +
226 +}
227 +
228 +/*
229 + * *******************************************************************
230 + *
231 + *             Begin SPI hardware access functions.
232 + *
233 + * *******************************************************************
234 + *
235 + */
236 +static int mmc_spi_media_detect(void)
237 +{
238 +// FIXME: add card detection/test by SPI
239 +
240 +    return 1;
241 +}
242 +
243 +static int mmc_spi_hardware_init(void)
244 +{
245 +    /*unsigned char gpio_outen;*/
246 +
247 +    printk("mmc: GPIO init\n");
248 +
249 +    /* Now global
250 +     * gp = gpio_open(); */
251 +
252 +    /* Cut existing functions */
253 +    gpio_setalt(&gp, GPIO_SD_CLK, 0);
254 +    gpio_setalt(&gp, GPIO_SD_DI, 0);
255 +    gpio_setalt(&gp, GPIO_SD_DO, 0);
256 +    gpio_setalt(&gp, GPIO_SD_CS, 0);
257 +
258 +    /* Remap directions */
259 +    gpio_setdir(&gp, GPIO_SD_CLK, OUTPUT);
260 +    gpio_setdir(&gp, GPIO_SD_DI, OUTPUT);
261 +    gpio_setdir(&gp, GPIO_SD_DO, INPUT);
262 +    gpio_setdir(&gp, GPIO_SD_CS, OUTPUT);
263 +
264 +    printk("mmc: initialising MMC\n");
265 +
266 +    /* Start */
267 +    gpio_write(&gp, GPIO_SD_CLK, LOW);
268 +    gpio_write(&gp, GPIO_SD_DI, LOW);
269 +    gpio_write(&gp, GPIO_SD_CS, LOW);
270 +    return 0;
271 +}
272 +
273 +/* return what has been read, write the parameter */
274 +
275 +static unsigned char mmc_spi_readwrite(unsigned char data_out)
276 +{
277 +    int i;
278 +    unsigned char result = 0/*, tmp_data = 0*/;
279 +
280 +    for (i = 0; i < 8; i++) {
281 +       if (data_out & (0x01 << (7 - i)))
282 +           gpio_write(&gp, GPIO_SD_DI, HIGH);
283 +       else
284 +           gpio_write(&gp, GPIO_SD_DI, LOW);
285 +
286 +       gpio_write(&gp, GPIO_SD_CLK, HIGH);
287 +
288 +       result <<= 1;
289 +
290 +       if (gpio_read(&gp, GPIO_SD_DO) == 1)
291 +           result |= 1;
292 +
293 +       gpio_write(&gp, GPIO_SD_CLK, LOW);
294 +    }
295 +
296 +    return (result);
297 +}
298 +
299 +static int mmc_spi_card_init(void)
300 +{
301 +    unsigned char result = 0;
302 +    short i, j;
303 +    unsigned long flags;
304 +
305 +    save_flags(flags);
306 +    cli();
307 +
308 +    printk("GPIO_SD_CS dir: %u alt: %u\n", gpio_getdir(&gp, GPIO_SD_CS), gpio_getalt(&gp, GPIO_SD_CS));
309 +    printk("GPIO_SD_DI dir: %u alt: %u\n", gpio_getdir(&gp, GPIO_SD_DI), gpio_getalt(&gp, GPIO_SD_DI));
310 +    printk("GPIO_SD_DO dir: %u alt: %u\n", gpio_getdir(&gp, GPIO_SD_DO), gpio_getalt(&gp, GPIO_SD_DO));
311 +    printk("GPIO_SD_CS dir: %u alt: %u\n", gpio_getdir(&gp, GPIO_SD_CLK), gpio_getalt(&gp, GPIO_SD_CLK));
312 +    
313 +    printk("mmc: card init 1/2\n");
314 +    gpio_write(&gp, GPIO_SD_CS, HIGH);
315 +    for (i = 0; i < 20; i++)
316 +       mmc_spi_readwrite(0xff);
317 +
318 +    gpio_write(&gp, GPIO_SD_CS, LOW);
319 +
320 +    mmc_spi_readwrite(0x40);
321 +    for (i = 0; i < 4; i++)
322 +       mmc_spi_readwrite(0x00);
323 +    mmc_spi_readwrite(0x95);
324 +    for (i = 0; i < 8; i++) {
325 +       result = mmc_spi_readwrite(0xff);
326 +       if (result == 0x01)
327 +           break;
328 +    }
329 +    gpio_write(&gp, GPIO_SD_CS, HIGH);
330 +    mmc_spi_readwrite(0xff);
331 +    if (result != 0x01) {
332 +        printk("mmc: card init %d error\n", result);
333 +       restore_flags(flags);
334 +       return (1);
335 +    }
336 +
337 +    printk("mmc: card init 2/2\n");
338 +    for (j = 0; j < 10000; j++) {
339 +       gpio_write(&gp, GPIO_SD_CS, LOW);
340 +
341 +       mmc_spi_readwrite(0x41);
342 +       for (i = 0; i < 4; i++)
343 +           mmc_spi_readwrite(0x00);
344 +       mmc_spi_readwrite(0xff);
345 +       for (i = 0; i < 8; i++) {
346 +           result = mmc_spi_readwrite(0xff);
347 +           if (result == 0x00)
348 +               break;
349 +       }
350 +       gpio_write(&gp, GPIO_SD_CS, HIGH);
351 +       mmc_spi_readwrite(0xff);
352 +       if (result == 0x00) {
353 +           restore_flags(flags);
354 +           printk("mmc: card init 3/3\n");
355 +           return (0);
356 +       }
357 +    }
358 +    restore_flags(flags);
359 +
360 +    return (2);
361 +}
362 +
363 +
364 +static int mmc_spi_card_config(void)
365 +{
366 +    unsigned char result = 0;
367 +    short i;
368 +    unsigned char csd[32];
369 +    unsigned int c_size;
370 +    unsigned int c_size_mult;
371 +    unsigned int mult;
372 +    unsigned int read_bl_len;
373 +    unsigned int blocknr = 0;
374 +    unsigned int block_len = 0;
375 +    unsigned int size = 0;
376 +
377 +    gpio_write(&gp, GPIO_SD_CS, LOW);
378 +    for (i = 0; i < 4; i++)
379 +       mmc_spi_readwrite(0xff);
380 +    mmc_spi_readwrite(0x49);
381 +    for (i = 0; i < 4; i++)
382 +       mmc_spi_readwrite(0x00);
383 +    mmc_spi_readwrite(0xff);
384 +    for (i = 0; i < 8; i++) {
385 +       result = mmc_spi_readwrite(0xff);
386 +       if (result == 0x00)
387 +           break;
388 +    }
389 +    if (result != 0x00) {
390 +       gpio_write(&gp, GPIO_SD_CS, HIGH);
391 +       mmc_spi_readwrite(0xff);
392 +       return (1);
393 +    }
394 +    for (i = 0; i < 8; i++) {
395 +       result = mmc_spi_readwrite(0xff);
396 +       if (result == 0xfe)
397 +           break;
398 +    }
399 +    if (result != 0xfe) {
400 +       gpio_write(&gp, GPIO_SD_CS, HIGH);
401 +       mmc_spi_readwrite(0xff);
402 +       return (2);
403 +    }
404 +    for (i = 0; i < 16; i++) {
405 +       result = mmc_spi_readwrite(0xff);
406 +       csd[i] = result;
407 +    }
408 +    for (i = 0; i < 2; i++) {
409 +       result = mmc_spi_readwrite(0xff);
410 +    }
411 +    gpio_write(&gp, GPIO_SD_CS, HIGH);
412 +    mmc_spi_readwrite(0xff);
413 +    if (result == 0x00)
414 +       return (3);
415 +
416 +    c_size = csd[8] + csd[7] * 256 + (csd[6] & 0x03) * 256 * 256;
417 +    c_size >>= 6;
418 +    c_size_mult = csd[10] + (csd[9] & 0x03) * 256;
419 +    c_size_mult >>= 7;
420 +    read_bl_len = csd[5] & 0x0f;
421 +    mult = 1;
422 +    mult <<= c_size_mult + 2;
423 +    blocknr = (c_size + 1) * mult;
424 +    block_len = 1;
425 +    block_len <<= read_bl_len;
426 +    size = block_len * blocknr;
427 +    size >>= 10;
428 +
429 +    for (i = 0; i < (1 << 6); i++) {
430 +       hd_blocksizes[i] = 1024;
431 +       hd_hardsectsizes[i] = block_len;
432 +       hd_maxsect[i] = 256;
433 +    }
434 +    hd_sizes[0] = size;
435 +    hd[0].nr_sects = blocknr;
436 +
437 +
438 +    printk("Size = %d, hardsectsize = %d, sectors = %d\n",
439 +          size, block_len, blocknr);
440 +
441 +    return 0;
442 +}
443 +
444 +
445 +/*
446 + * *******************************************************************
447 + *
448 + *             End of SPI hardware access functions.
449 + *
450 + * *******************************************************************
451 + */
452 +
453 +
454 +static int mmc_write_block(unsigned int dest_addr, unsigned char *data)
455 +{
456 +    unsigned int address;
457 +    unsigned char result = 0;
458 +    unsigned char ab0, ab1, ab2, ab3;
459 +    int i;
460 +
461 +    address = dest_addr;
462 +
463 +    ab3 = 0xff & (address >> 24);
464 +    ab2 = 0xff & (address >> 16);
465 +    ab1 = 0xff & (address >> 8);
466 +    ab0 = 0xff & address;
467 +    gpio_write(&gp, GPIO_SD_CS, LOW);
468 +    for (i = 0; i < 4; i++)
469 +       mmc_spi_readwrite(0xff);
470 +    mmc_spi_readwrite(0x58);
471 +    mmc_spi_readwrite(ab3);            /* msb */
472 +    mmc_spi_readwrite(ab2);
473 +    mmc_spi_readwrite(ab1);
474 +    mmc_spi_readwrite(ab0);            /* lsb */
475 +    mmc_spi_readwrite(0xff);
476 +    for (i = 0; i < 8; i++) {
477 +       result = mmc_spi_readwrite(0xff);
478 +       if (result == 0x00)
479 +           break;
480 +    }
481 +    if (result != 0x00) {
482 +       gpio_write(&gp, GPIO_SD_CS, HIGH);
483 +       mmc_spi_readwrite(0xff);
484 +       return (1);
485 +    }
486 +
487 +    mmc_spi_readwrite(0xfe);
488 +    for (i = 0; i < 512; i++)
489 +       mmc_spi_readwrite(data[i]);
490 +    for (i = 0; i < 2; i++)
491 +       mmc_spi_readwrite(0xff);
492 +
493 +    for (i = 0; i < 1000000; i++) {
494 +       result = mmc_spi_readwrite(0xff);
495 +       if (result == 0xff)
496 +           break;
497 +    }
498 +    if (result != 0xff) {
499 +       gpio_write(&gp, GPIO_SD_CS, HIGH);
500 +       mmc_spi_readwrite(0xff);
501 +       return (3);
502 +    }
503 +    gpio_write(&gp, GPIO_SD_CS, HIGH);
504 +    mmc_spi_readwrite(0xff);
505 +    return (0);
506 +}
507 +
508 +static int mmc_read_block(unsigned char *data, unsigned int src_addr)
509 +{
510 +    unsigned int address;
511 +    unsigned char result = 0;
512 +    unsigned char ab0, ab1, ab2, ab3;
513 +    int i;
514 +
515 +    address = src_addr;
516 +
517 +    ab3 = 0xff & (address >> 24);
518 +    ab2 = 0xff & (address >> 16);
519 +    ab1 = 0xff & (address >> 8);
520 +    ab0 = 0xff & address;
521 +
522 +    gpio_write(&gp, GPIO_SD_CS, LOW);
523 +    for (i = 0; i < 4; i++)
524 +       mmc_spi_readwrite(0xff);
525 +    mmc_spi_readwrite(0x51);
526 +    mmc_spi_readwrite(ab3);            /* msb */
527 +    mmc_spi_readwrite(ab2);
528 +    mmc_spi_readwrite(ab1);
529 +    mmc_spi_readwrite(ab0);            /* lsb */
530 +
531 +    mmc_spi_readwrite(0xff);
532 +    for (i = 0; i < 8; i++) {
533 +       result = mmc_spi_readwrite(0xff);
534 +       if (result == 0x00)
535 +           break;
536 +    }
537 +    if (result != 0x00) {
538 +       gpio_write(&gp, GPIO_SD_CS, HIGH);
539 +       mmc_spi_readwrite(0xff);
540 +       return (1);
541 +    }
542 +    for (i = 0; i < 100000; i++) {
543 +       result = mmc_spi_readwrite(0xff);
544 +       if (result == 0xfe)
545 +           break;
546 +    }
547 +    if (result != 0xfe) {
548 +       gpio_write(&gp, GPIO_SD_CS, HIGH);
549 +       mmc_spi_readwrite(0xff);
550 +       return (2);
551 +    }
552 +    for (i = 0; i < 512; i++) {
553 +       result = mmc_spi_readwrite(0xff);
554 +       data[i] = result;
555 +    }
556 +    for (i = 0; i < 2; i++) {
557 +       result = mmc_spi_readwrite(0xff);
558 +    }
559 +    gpio_write(&gp, GPIO_SD_CS, HIGH);
560 +    mmc_spi_readwrite(0xff);
561 +
562 +    return (0);
563 +}
564 +
565 +static void mmc_request(request_queue_t * q)
566 +{
567 +    unsigned int mmc_address;
568 +    unsigned char *buffer_address;
569 +    int nr_sectors;
570 +    int i;
571 +    int cmd;
572 +    int result, code;
573 +
574 +    (void) q;
575 +    while (1) {
576 +       code = 1;               // Default is success
577 +       INIT_REQUEST;
578 +       mmc_address =
579 +           (CURRENT->sector +
580 +            hd[MINOR(CURRENT->rq_dev)].start_sect) * hd_hardsectsizes[0];
581 +       buffer_address = CURRENT->buffer;
582 +       nr_sectors = CURRENT->current_nr_sectors;
583 +       cmd = CURRENT->cmd;
584 +       if (((CURRENT->sector + CURRENT->current_nr_sectors +
585 +             hd[MINOR(CURRENT->rq_dev)].start_sect) > hd[0].nr_sects)
586 +           || (mmc_media_detect == 0)) {
587 +           code = 0;
588 +       } else if (cmd == READ) {
589 +           spin_unlock_irq(&io_request_lock);
590 +           for (i = 0; i < nr_sectors; i++) {
591 +               result = mmc_read_block(buffer_address, mmc_address);
592 +               if (result != 0) {
593 +                   printk("mmc: error %d in mmc_read_block\n", result);
594 +                   code = 0;
595 +                   break;
596 +               } else {
597 +                   mmc_address += hd_hardsectsizes[0];
598 +                   buffer_address += hd_hardsectsizes[0];
599 +               }
600 +           }
601 +           spin_lock_irq(&io_request_lock);
602 +       } else if (cmd == WRITE) {
603 +           spin_unlock_irq(&io_request_lock);
604 +           for (i = 0; i < nr_sectors; i++) {
605 +               result = mmc_write_block(mmc_address, buffer_address);
606 +               if (result != 0) {
607 +                   printk("mmc: error %d in mmc_write_block\n", result);
608 +                   code = 0;
609 +                   break;
610 +               } else {
611 +                   mmc_address += hd_hardsectsizes[0];
612 +                   buffer_address += hd_hardsectsizes[0];
613 +               }
614 +           }
615 +           spin_lock_irq(&io_request_lock);
616 +       } else {
617 +           code = 0;
618 +       }
619 +       end_request(code);
620 +    }
621 +}
622 +
623 +
624 +static int mmc_open(struct inode *inode, struct file *filp)
625 +{
626 +    /*int device;*/
627 +    (void) filp;
628 +    mmc_media_detect = mmc_spi_media_detect();
629 +
630 +    if (mmc_media_detect == 0)
631 +       return -ENODEV;
632 +
633 +#if defined(MODULE)
634 +    MOD_INC_USE_COUNT;
635 +#endif
636 +    return 0;
637 +}
638 +
639 +static int mmc_release(struct inode *inode, struct file *filp)
640 +{
641 +    (void) filp;
642 +    fsync_dev(inode->i_rdev);
643 +    invalidate_buffers(inode->i_rdev);
644 +
645 +#if defined(MODULE)
646 +    MOD_DEC_USE_COUNT;
647 +#endif
648 +    return 0;
649 +}
650 +
651 +static int mmc_revalidate(kdev_t dev)
652 +{
653 +    int target, max_p, start, i;
654 +
655 +    mmc_media_detect = mmc_spi_media_detect();
656 +
657 +    if (mmc_media_detect == 0)
658 +       return -ENODEV;
659 +
660 +    target = DEVICE_NR(dev);
661 +
662 +    max_p = hd_gendisk.max_p;
663 +    start = target << 6;
664 +    for (i = max_p - 1; i >= 0; i--) {
665 +       int minor = start + i;
666 +       invalidate_device(MKDEV(MAJOR_NR, minor), 1);
667 +       hd_gendisk.part[minor].start_sect = 0;
668 +       hd_gendisk.part[minor].nr_sects = 0;
669 +    }
670 +
671 +    grok_partitions(&hd_gendisk, target, 1 << 6, hd_sizes[0] * 2);
672 +
673 +    return 0;
674 +}
675 +
676 +static int mmc_ioctl(struct inode *inode, struct file *filp,
677 +                    unsigned int cmd, unsigned long arg)
678 +{
679 +    if (!inode || !inode->i_rdev)
680 +       return -EINVAL;
681 +
682 +    switch (cmd) {
683 +    case BLKGETSIZE:
684 +       return put_user(hd[MINOR(inode->i_rdev)].nr_sects,
685 +                       (unsigned long *) arg);
686 +    case BLKGETSIZE64:
687 +       return put_user((u64) hd[MINOR(inode->i_rdev)].
688 +                       nr_sects, (u64 *) arg);
689 +    case BLKRRPART:
690 +       if (!capable(CAP_SYS_ADMIN))
691 +           return -EACCES;
692 +
693 +       return mmc_revalidate(inode->i_rdev);
694 +    case HDIO_GETGEO:
695 +       {
696 +           struct hd_geometry *loc, g;
697 +           loc = (struct hd_geometry *) arg;
698 +           if (!loc)
699 +               return -EINVAL;
700 +           g.heads = 4;
701 +           g.sectors = 16;
702 +           g.cylinders = hd[0].nr_sects / (4 * 16);
703 +           g.start = hd[MINOR(inode->i_rdev)].start_sect;
704 +           return copy_to_user(loc, &g, sizeof(g)) ? -EFAULT : 0;
705 +       }
706 +    default:
707 +       return blk_ioctl(inode->i_rdev, cmd, arg);
708 +    }
709 +}
710 +
711 +
712 +/*
713 +static int mmc_check_media_change(kdev_t dev)
714 +{
715 +    (void) dev;
716 +    if (mmc_media_changed == 1) {
717 +       mmc_media_changed = 0;
718 +       return 1;
719 +    } else
720 +       return 0;
721 +}
722 +*/
723 +
724 +static struct block_device_operations mmc_bdops = {
725 +  open:mmc_open,
726 +  release:mmc_release,
727 +  ioctl:mmc_ioctl,
728 +/* FIXME: add media change support
729 + *     check_media_change: mmc_check_media_change,
730 + *     revalidate: mmc_revalidate,
731 + */
732 +};
733 +
734 +static struct gendisk hd_gendisk = {
735 +  major:MAJOR_NR,
736 +  major_name:DEVICE_NAME,
737 +  minor_shift:6,
738 +  max_p:1 << 6,
739 +  part:hd,
740 +  sizes:hd_sizes,
741 +  fops:&mmc_bdops,
742 +};
743 +
744 +static int mmc_init(void)
745 +{
746 +    int result;
747 +
748 +    result = mmc_spi_hardware_init();
749 +
750 +    if (result != 0) {
751 +       printk("mmc: error %d in mmc_spi_hardware_init\n", result);
752 +       return -1;
753 +    }
754 +
755 +    result = mmc_spi_card_init();
756 +    if (result != 0) {
757 +       // Give it an extra shot
758 +       result = mmc_spi_card_init();
759 +       if (result != 0) {
760 +           printk("mmc: error %d in mmc_card_init\n", result);
761 +           return -1;
762 +       }
763 +    }
764 +
765 +    memset(hd_sizes, 0, sizeof(hd_sizes));
766 +    result = mmc_spi_card_config();
767 +    if (result != 0) {
768 +       printk("mmc: error %d in mmc_card_config\n", result);
769 +       return -1;
770 +    }
771 +
772 +
773 +    blk_size[MAJOR_NR] = hd_sizes;
774 +
775 +    memset(hd, 0, sizeof(hd));
776 +    hd[0].nr_sects = hd_sizes[0] * 2;
777 +
778 +    blksize_size[MAJOR_NR] = hd_blocksizes;
779 +    hardsect_size[MAJOR_NR] = hd_hardsectsizes;
780 +    max_sectors[MAJOR_NR] = hd_maxsect;
781 +
782 +    hd_gendisk.nr_real = 1;
783 +
784 +    register_disk(&hd_gendisk, MKDEV(MAJOR_NR, 0), 1 << 6,
785 +                 &mmc_bdops, hd_sizes[0] * 2);
786 +
787 +    return 0;
788 +}
789 +
790 +static void mmc_exit(void)
791 +{
792 +    blk_size[MAJOR_NR] = NULL;
793 +    blksize_size[MAJOR_NR] = NULL;
794 +    hardsect_size[MAJOR_NR] = NULL;
795 +    max_sectors[MAJOR_NR] = NULL;
796 +    hd[0].nr_sects = 0;
797 +}
798 +
799 +static void mmc_check_media(void)
800 +{
801 +    int old_state, new_state;
802 +    int result;
803 +
804 +    old_state = mmc_media_detect;
805 +    new_state = mmc_spi_media_detect();
806 +
807 +    if (old_state != new_state) {
808 +       mmc_media_changed = 1;
809 +       if (new_state == PRESENT) {
810 +           result = mmc_init();
811 +           if (result != 0)
812 +               printk("mmc: error %d in mmc_init\n", result);
813 +       } else {
814 +           mmc_exit();
815 +       }
816 +    }
817 +
818 +    /* del_timer(&mmc_timer);
819 +       mmc_timer.expires = jiffies + 10*HZ;
820 +       add_timer(&mmc_timer); */
821 +}
822 +
823 +static int __init mmc_driver_init(void)
824 +{
825 +    int result;
826 +
827 +    result = devfs_register_blkdev(MAJOR_NR, DEVICE_NAME, &mmc_bdops);
828 +    if (result < 0) {
829 +       printk(KERN_WARNING "mmc: can't get major %d\n", MAJOR_NR);
830 +       return result;
831 +    }
832 +
833 +    blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), mmc_request);
834 +
835 +    mmc_check_media();
836 +
837 +    /*init_timer(&mmc_timer);
838 +       mmc_timer.expires = jiffies + HZ;
839 +       mmc_timer.function = (void *)mmc_check_media;
840 +       add_timer(&mmc_timer); */
841 +
842 +
843 +    read_ahead[MAJOR_NR] = 8;
844 +    add_gendisk(&hd_gendisk);
845 +
846 +
847 +    return 0;
848 +}
849 +
850 +static void __exit mmc_driver_exit(void)
851 +{
852 +    int i;
853 +    del_timer(&mmc_timer);
854 +
855 +    for (i = 0; i < (1 << 6); i++)
856 +       fsync_dev(MKDEV(MAJOR_NR, i));
857 +
858 +    blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
859 +    del_gendisk(&hd_gendisk);
860 +    devfs_unregister_blkdev(MAJOR_NR, DEVICE_NAME);
861 +    mmc_exit();
862 +}
863 +
864 +module_init(mmc_driver_init);
865 +module_exit(mmc_driver_exit);
866 --- linux-2.4.27/drivers/block/Config.in~mmc-spi
867 +++ linux-2.4.27/drivers/block/Config.in
868 @@ -4,6 +4,7 @@
869  mainmenu_option next_comment
870  comment 'Block devices'
871  
872 +tristate 'MMC SPI driver' CONFIG_BLK_DEV_MMC
873  tristate 'Normal floppy disk support' CONFIG_BLK_DEV_FD
874  if [ "$CONFIG_AMIGA" = "y" ]; then
875     tristate 'Amiga floppy support' CONFIG_AMIGA_FLOPPY
876 --- linux-2.4.27/drivers/block/Makefile~mmc-spi
877 +++ linux-2.4.27/drivers/block/Makefile
878 @@ -15,6 +15,7 @@
879  obj-y  := ll_rw_blk.o blkpg.o genhd.o elevator.o
880  
881  obj-$(CONFIG_MAC_FLOPPY)       += swim3.o
882 +obj-$(CONFIG_BLK_DEV_MMC)      += mmc.o
883  obj-$(CONFIG_BLK_DEV_FD)       += floppy.o
884  obj-$(CONFIG_AMIGA_FLOPPY)     += amiflop.o
885  obj-$(CONFIG_ATARI_FLOPPY)     += ataflop.o