summaryrefslogtreecommitdiff
path: root/packages/linux/opensimpad/mmc-spi.patch
diff options
context:
space:
mode:
authorDenys Dmytriyenko <denis@denix.org>2009-03-17 14:32:59 -0400
committerDenys Dmytriyenko <denis@denix.org>2009-03-17 14:32:59 -0400
commit709c4d66e0b107ca606941b988bad717c0b45d9b (patch)
tree37ee08b1eb308f3b2b6426d5793545c38396b838 /packages/linux/opensimpad/mmc-spi.patch
parentfa6cd5a3b993f16c27de4ff82b42684516d433ba (diff)
rename packages/ to recipes/ per earlier agreement
See links below for more details: http://thread.gmane.org/gmane.comp.handhelds.openembedded/21326 http://thread.gmane.org/gmane.comp.handhelds.openembedded/21816 Signed-off-by: Denys Dmytriyenko <denis@denix.org> Acked-by: Mike Westerhof <mwester@dls.net> Acked-by: Philip Balister <philip@balister.org> Acked-by: Khem Raj <raj.khem@gmail.com> Acked-by: Marcin Juszkiewicz <hrw@openembedded.org> Acked-by: Koen Kooi <koen@openembedded.org> Acked-by: Frans Meulenbroeks <fransmeulenbroeks@gmail.com>
Diffstat (limited to 'packages/linux/opensimpad/mmc-spi.patch')
-rw-r--r--packages/linux/opensimpad/mmc-spi.patch885
1 files changed, 0 insertions, 885 deletions
diff --git a/packages/linux/opensimpad/mmc-spi.patch b/packages/linux/opensimpad/mmc-spi.patch
deleted file mode 100644
index 1841b45fbd..0000000000
--- a/packages/linux/opensimpad/mmc-spi.patch
+++ /dev/null
@@ -1,885 +0,0 @@
-
-#
-# Patch managed by http://www.holgerschurig.de/patcher.html
-#
-
---- /dev/null
-+++ linux-2.4.27/drivers/block/mmc.c
-@@ -0,0 +1,857 @@
-+/*
-+ * Copyright (c) Clément Ballabriga, 2005 - GPL
-+ * Copyright (c) Guylhem Aznar, 2005 - GPL
-+ *
-+ * Please check http://externe.net/zaurus/simpad-bluetooth reference design first.
-+ *
-+ * Based on Madsuk/Rohde work on a MMC driver for the WRT54G.
-+ *
-+ * This is an ugly hack of a driver. I am surprised if it ever works!
-+ * So please use a real driver or contribute one to the 2.4/2.6 mmc framework
-+ */
-+
-+#include <linux/stddef.h>
-+#include <linux/delay.h>
-+#include <linux/timer.h>
-+#include <linux/module.h>
-+#include <linux/mm.h>
-+#include <linux/init.h>
-+#include <linux/fs.h>
-+#include <linux/blkpg.h>
-+#include <linux/hdreg.h>
-+#include <linux/major.h>
-+
-+#include <asm/hardware.h>
-+#include <asm/uaccess.h>
-+#include <asm/io.h>
-+
-+/*
-+ * *******************************************************************
-+ *
-+ * This is the only configurable part.
-+ *
-+ * *******************************************************************
-+ *
-+ */
-+
-+// #define DEBUG 1
-+
-+#define DEVICE_NAME "mmc"
-+#define DEVICE_NR(device) (MINOR(device))
-+#define DEVICE_ON(device)
-+#define DEVICE_OFF(device)
-+#define MAJOR_NR 121
-+
-+/* Let that include where it is or compilation fails on INIT_REQUEST/CURRENT */
-+
-+#include <linux/blk.h>
-+
-+MODULE_AUTHOR("Guylhem Aznar <mmc-driver @externe.net>");
-+MODULE_DESCRIPTION("Driver for MMC/SD-Cards in SPI mode by GPIO");
-+MODULE_SUPPORTED_DEVICE("Simpad");
-+MODULE_LICENSE("GPL");
-+
-+/* Registers should be architecture independant - but it's not ! */
-+
-+#define MAP_START 0x90040000
-+#define MAP_SIZE 0x00001000
-+
-+#define MY_GPLR 0
-+#define MY_GPDR 1
-+#define MY_GPSR 2
-+#define MY_GPCR 3
-+#define MY_GRER 4
-+#define MY_GFER 5
-+#define MY_GEDR 6
-+#define MY_GAFR 7
-+
-+/*
-+ * If you are using different GPIOs in your hardware hack, you must
-+ * first make sure they are unused for other functions and then
-+ * configure them here.
-+ *
-+ * On the simpad I use spare pins from the UART1 (internal serial port):
-+ * - DCD (in) : GPIO 23 : DO
-+ * - DTR (out) : GPIO 07 : CS
-+ * - RI (in) : GPIO 19 : CLK
-+ * - DSR (in) : GPIO 06 : DI
-+ *
-+ * Don't worry about in/out original function - the GPIOs will be
-+ * reprogrammed.
-+ */
-+
-+#define GPIO_SD_DO 23
-+#define GPIO_SD_CS 7
-+#define GPIO_SD_CLK 19
-+#define GPIO_SD_DI 6
-+
-+/*
-+ * *******************************************************************
-+ *
-+ * Do not change anything below !
-+ *
-+ * *******************************************************************
-+ *
-+ */
-+
-+
-+/* GPIO states */
-+#define LOW 0
-+#define HIGH 1
-+
-+#define INPUT 0
-+#define OUTPUT 1
-+
-+#define PRESENT 1
-+#define ABSENT 0
-+
-+typedef unsigned int uint32;
-+typedef unsigned long u32_t;
-+typedef unsigned short u16_t;
-+typedef unsigned char u8_t;
-+
-+/* we have only one device */
-+static int hd_sizes[1 << 6];
-+static int hd_blocksizes[1 << 6];
-+static int hd_hardsectsizes[1 << 6];
-+static int hd_maxsect[1 << 6];
-+static struct hd_struct hd[1 << 6];
-+
-+static struct timer_list mmc_timer;
-+
-+/* start with no card */
-+static int mmc_media_detect = 0;
-+static int mmc_media_changed = 1;
-+
-+extern struct gendisk hd_gendisk;
-+
-+/* Use only one global device */
-+typedef struct gpio_s gpio_t;
-+struct gpio_s {
-+ volatile u32_t *base;
-+};
-+
-+static gpio_t gp = {
-+ (void *) io_p2v(MAP_START)
-+};
-+
-+/*
-+ * *******************************************************************
-+ *
-+ * Begin GPIO hardware access functions.
-+ *
-+ * *******************************************************************
-+ *
-+ */
-+
-+gpio_t *gpio_open(void)
-+{
-+ static gpio_t tmp;
-+ tmp.base = (void *) io_p2v(MAP_START);
-+ return (&tmp);
-+}
-+
-+void gpio_setdir(gpio_t * g, int num, int dir)
-+{
-+ if (dir == 1) {
-+ g->base[MY_GPDR] |= (1 << num);
-+ } else {
-+ g->base[MY_GPDR] &= ~(1 << num);
-+
-+ }
-+}
-+
-+void gpio_setalt(gpio_t * g, int num, int alt)
-+{
-+ if (alt == 1) {
-+ g->base[MY_GAFR] |= (1 << num);
-+ } else {
-+ g->base[MY_GAFR] &= ~(1 << num);
-+ }
-+}
-+
-+int gpio_getdir(gpio_t * g, int num)
-+{
-+ return ((g->base[MY_GPDR] & (1 << num)) ? 1 : 0);
-+}
-+
-+int gpio_getalt(gpio_t * g, int num)
-+{
-+ return ((g->base[MY_GAFR] & (1 << num)) ? 1 : 0);
-+}
-+
-+static int gpio_read(gpio_t * g, int num)
-+{
-+ int what;
-+
-+ what=(g->base[MY_GPLR] & (1 << num)) ? 1 : 0;
-+
-+#ifdef DEBUG
-+ if (num == GPIO_SD_DO) {
-+ printk ("GPIO_SD_DO read: %u\n", what);
-+ }
-+#endif
-+ return (what);
-+}
-+
-+static int gpio_write(gpio_t * g, int num, int val)
-+{
-+#ifdef DEBUG
-+ int check;
-+#endif
-+
-+ if (val == 1) {
-+ g->base[MY_GPSR] = 1 << num;
-+ } else {
-+ g->base[MY_GPCR] = 1 << num;
-+ }
-+#ifdef DEBUG
-+ check=gpio_read(g,num);
-+ if (check != val)
-+ {
-+ printk ("Error while write to %d: found %d after writing %d\n",num, check, val);
-+ return (1);
-+ }
-+ else return(0);
-+#endif
-+
-+}
-+
-+/*
-+ * *******************************************************************
-+ *
-+ * Begin SPI hardware access functions.
-+ *
-+ * *******************************************************************
-+ *
-+ */
-+static int mmc_spi_media_detect(void)
-+{
-+// FIXME: add card detection/test by SPI
-+
-+ return 1;
-+}
-+
-+static int mmc_spi_hardware_init(void)
-+{
-+ /*unsigned char gpio_outen;*/
-+
-+ printk("mmc: GPIO init\n");
-+
-+ /* Now global
-+ * gp = gpio_open(); */
-+
-+ /* Cut existing functions */
-+ gpio_setalt(&gp, GPIO_SD_CLK, 0);
-+ gpio_setalt(&gp, GPIO_SD_DI, 0);
-+ gpio_setalt(&gp, GPIO_SD_DO, 0);
-+ gpio_setalt(&gp, GPIO_SD_CS, 0);
-+
-+ /* Remap directions */
-+ gpio_setdir(&gp, GPIO_SD_CLK, OUTPUT);
-+ gpio_setdir(&gp, GPIO_SD_DI, OUTPUT);
-+ gpio_setdir(&gp, GPIO_SD_DO, INPUT);
-+ gpio_setdir(&gp, GPIO_SD_CS, OUTPUT);
-+
-+ printk("mmc: initialising MMC\n");
-+
-+ /* Start */
-+ gpio_write(&gp, GPIO_SD_CLK, LOW);
-+ gpio_write(&gp, GPIO_SD_DI, LOW);
-+ gpio_write(&gp, GPIO_SD_CS, LOW);
-+ return 0;
-+}
-+
-+/* return what has been read, write the parameter */
-+
-+static unsigned char mmc_spi_readwrite(unsigned char data_out)
-+{
-+ int i;
-+ unsigned char result = 0/*, tmp_data = 0*/;
-+
-+ for (i = 0; i < 8; i++) {
-+ if (data_out & (0x01 << (7 - i)))
-+ gpio_write(&gp, GPIO_SD_DI, HIGH);
-+ else
-+ gpio_write(&gp, GPIO_SD_DI, LOW);
-+
-+ gpio_write(&gp, GPIO_SD_CLK, HIGH);
-+
-+ result <<= 1;
-+
-+ if (gpio_read(&gp, GPIO_SD_DO) == 1)
-+ result |= 1;
-+
-+ gpio_write(&gp, GPIO_SD_CLK, LOW);
-+ }
-+
-+ return (result);
-+}
-+
-+static int mmc_spi_card_init(void)
-+{
-+ unsigned char result = 0;
-+ short i, j;
-+ unsigned long flags;
-+
-+ save_flags(flags);
-+ cli();
-+
-+ printk("GPIO_SD_CS dir: %u alt: %u\n", gpio_getdir(&gp, GPIO_SD_CS), gpio_getalt(&gp, GPIO_SD_CS));
-+ printk("GPIO_SD_DI dir: %u alt: %u\n", gpio_getdir(&gp, GPIO_SD_DI), gpio_getalt(&gp, GPIO_SD_DI));
-+ printk("GPIO_SD_DO dir: %u alt: %u\n", gpio_getdir(&gp, GPIO_SD_DO), gpio_getalt(&gp, GPIO_SD_DO));
-+ printk("GPIO_SD_CS dir: %u alt: %u\n", gpio_getdir(&gp, GPIO_SD_CLK), gpio_getalt(&gp, GPIO_SD_CLK));
-+
-+ printk("mmc: card init 1/2\n");
-+ gpio_write(&gp, GPIO_SD_CS, HIGH);
-+ for (i = 0; i < 20; i++)
-+ mmc_spi_readwrite(0xff);
-+
-+ gpio_write(&gp, GPIO_SD_CS, LOW);
-+
-+ mmc_spi_readwrite(0x40);
-+ for (i = 0; i < 4; i++)
-+ mmc_spi_readwrite(0x00);
-+ mmc_spi_readwrite(0x95);
-+ for (i = 0; i < 8; i++) {
-+ result = mmc_spi_readwrite(0xff);
-+ if (result == 0x01)
-+ break;
-+ }
-+ gpio_write(&gp, GPIO_SD_CS, HIGH);
-+ mmc_spi_readwrite(0xff);
-+ if (result != 0x01) {
-+ printk("mmc: card init %d error\n", result);
-+ restore_flags(flags);
-+ return (1);
-+ }
-+
-+ printk("mmc: card init 2/2\n");
-+ for (j = 0; j < 10000; j++) {
-+ gpio_write(&gp, GPIO_SD_CS, LOW);
-+
-+ mmc_spi_readwrite(0x41);
-+ for (i = 0; i < 4; i++)
-+ mmc_spi_readwrite(0x00);
-+ mmc_spi_readwrite(0xff);
-+ for (i = 0; i < 8; i++) {
-+ result = mmc_spi_readwrite(0xff);
-+ if (result == 0x00)
-+ break;
-+ }
-+ gpio_write(&gp, GPIO_SD_CS, HIGH);
-+ mmc_spi_readwrite(0xff);
-+ if (result == 0x00) {
-+ restore_flags(flags);
-+ printk("mmc: card init 3/3\n");
-+ return (0);
-+ }
-+ }
-+ restore_flags(flags);
-+
-+ return (2);
-+}
-+
-+
-+static int mmc_spi_card_config(void)
-+{
-+ unsigned char result = 0;
-+ short i;
-+ unsigned char csd[32];
-+ unsigned int c_size;
-+ unsigned int c_size_mult;
-+ unsigned int mult;
-+ unsigned int read_bl_len;
-+ unsigned int blocknr = 0;
-+ unsigned int block_len = 0;
-+ unsigned int size = 0;
-+
-+ gpio_write(&gp, GPIO_SD_CS, LOW);
-+ for (i = 0; i < 4; i++)
-+ mmc_spi_readwrite(0xff);
-+ mmc_spi_readwrite(0x49);
-+ for (i = 0; i < 4; i++)
-+ mmc_spi_readwrite(0x00);
-+ mmc_spi_readwrite(0xff);
-+ for (i = 0; i < 8; i++) {
-+ result = mmc_spi_readwrite(0xff);
-+ if (result == 0x00)
-+ break;
-+ }
-+ if (result != 0x00) {
-+ gpio_write(&gp, GPIO_SD_CS, HIGH);
-+ mmc_spi_readwrite(0xff);
-+ return (1);
-+ }
-+ for (i = 0; i < 8; i++) {
-+ result = mmc_spi_readwrite(0xff);
-+ if (result == 0xfe)
-+ break;
-+ }
-+ if (result != 0xfe) {
-+ gpio_write(&gp, GPIO_SD_CS, HIGH);
-+ mmc_spi_readwrite(0xff);
-+ return (2);
-+ }
-+ for (i = 0; i < 16; i++) {
-+ result = mmc_spi_readwrite(0xff);
-+ csd[i] = result;
-+ }
-+ for (i = 0; i < 2; i++) {
-+ result = mmc_spi_readwrite(0xff);
-+ }
-+ gpio_write(&gp, GPIO_SD_CS, HIGH);
-+ mmc_spi_readwrite(0xff);
-+ if (result == 0x00)
-+ return (3);
-+
-+ c_size = csd[8] + csd[7] * 256 + (csd[6] & 0x03) * 256 * 256;
-+ c_size >>= 6;
-+ c_size_mult = csd[10] + (csd[9] & 0x03) * 256;
-+ c_size_mult >>= 7;
-+ read_bl_len = csd[5] & 0x0f;
-+ mult = 1;
-+ mult <<= c_size_mult + 2;
-+ blocknr = (c_size + 1) * mult;
-+ block_len = 1;
-+ block_len <<= read_bl_len;
-+ size = block_len * blocknr;
-+ size >>= 10;
-+
-+ for (i = 0; i < (1 << 6); i++) {
-+ hd_blocksizes[i] = 1024;
-+ hd_hardsectsizes[i] = block_len;
-+ hd_maxsect[i] = 256;
-+ }
-+ hd_sizes[0] = size;
-+ hd[0].nr_sects = blocknr;
-+
-+
-+ printk("Size = %d, hardsectsize = %d, sectors = %d\n",
-+ size, block_len, blocknr);
-+
-+ return 0;
-+}
-+
-+
-+/*
-+ * *******************************************************************
-+ *
-+ * End of SPI hardware access functions.
-+ *
-+ * *******************************************************************
-+ */
-+
-+
-+static int mmc_write_block(unsigned int dest_addr, unsigned char *data)
-+{
-+ unsigned int address;
-+ unsigned char result = 0;
-+ unsigned char ab0, ab1, ab2, ab3;
-+ int i;
-+
-+ address = dest_addr;
-+
-+ ab3 = 0xff & (address >> 24);
-+ ab2 = 0xff & (address >> 16);
-+ ab1 = 0xff & (address >> 8);
-+ ab0 = 0xff & address;
-+ gpio_write(&gp, GPIO_SD_CS, LOW);
-+ for (i = 0; i < 4; i++)
-+ mmc_spi_readwrite(0xff);
-+ mmc_spi_readwrite(0x58);
-+ mmc_spi_readwrite(ab3); /* msb */
-+ mmc_spi_readwrite(ab2);
-+ mmc_spi_readwrite(ab1);
-+ mmc_spi_readwrite(ab0); /* lsb */
-+ mmc_spi_readwrite(0xff);
-+ for (i = 0; i < 8; i++) {
-+ result = mmc_spi_readwrite(0xff);
-+ if (result == 0x00)
-+ break;
-+ }
-+ if (result != 0x00) {
-+ gpio_write(&gp, GPIO_SD_CS, HIGH);
-+ mmc_spi_readwrite(0xff);
-+ return (1);
-+ }
-+
-+ mmc_spi_readwrite(0xfe);
-+ for (i = 0; i < 512; i++)
-+ mmc_spi_readwrite(data[i]);
-+ for (i = 0; i < 2; i++)
-+ mmc_spi_readwrite(0xff);
-+
-+ for (i = 0; i < 1000000; i++) {
-+ result = mmc_spi_readwrite(0xff);
-+ if (result == 0xff)
-+ break;
-+ }
-+ if (result != 0xff) {
-+ gpio_write(&gp, GPIO_SD_CS, HIGH);
-+ mmc_spi_readwrite(0xff);
-+ return (3);
-+ }
-+ gpio_write(&gp, GPIO_SD_CS, HIGH);
-+ mmc_spi_readwrite(0xff);
-+ return (0);
-+}
-+
-+static int mmc_read_block(unsigned char *data, unsigned int src_addr)
-+{
-+ unsigned int address;
-+ unsigned char result = 0;
-+ unsigned char ab0, ab1, ab2, ab3;
-+ int i;
-+
-+ address = src_addr;
-+
-+ ab3 = 0xff & (address >> 24);
-+ ab2 = 0xff & (address >> 16);
-+ ab1 = 0xff & (address >> 8);
-+ ab0 = 0xff & address;
-+
-+ gpio_write(&gp, GPIO_SD_CS, LOW);
-+ for (i = 0; i < 4; i++)
-+ mmc_spi_readwrite(0xff);
-+ mmc_spi_readwrite(0x51);
-+ mmc_spi_readwrite(ab3); /* msb */
-+ mmc_spi_readwrite(ab2);
-+ mmc_spi_readwrite(ab1);
-+ mmc_spi_readwrite(ab0); /* lsb */
-+
-+ mmc_spi_readwrite(0xff);
-+ for (i = 0; i < 8; i++) {
-+ result = mmc_spi_readwrite(0xff);
-+ if (result == 0x00)
-+ break;
-+ }
-+ if (result != 0x00) {
-+ gpio_write(&gp, GPIO_SD_CS, HIGH);
-+ mmc_spi_readwrite(0xff);
-+ return (1);
-+ }
-+ for (i = 0; i < 100000; i++) {
-+ result = mmc_spi_readwrite(0xff);
-+ if (result == 0xfe)
-+ break;
-+ }
-+ if (result != 0xfe) {
-+ gpio_write(&gp, GPIO_SD_CS, HIGH);
-+ mmc_spi_readwrite(0xff);
-+ return (2);
-+ }
-+ for (i = 0; i < 512; i++) {
-+ result = mmc_spi_readwrite(0xff);
-+ data[i] = result;
-+ }
-+ for (i = 0; i < 2; i++) {
-+ result = mmc_spi_readwrite(0xff);
-+ }
-+ gpio_write(&gp, GPIO_SD_CS, HIGH);
-+ mmc_spi_readwrite(0xff);
-+
-+ return (0);
-+}
-+
-+static void mmc_request(request_queue_t * q)
-+{
-+ unsigned int mmc_address;
-+ unsigned char *buffer_address;
-+ int nr_sectors;
-+ int i;
-+ int cmd;
-+ int result, code;
-+
-+ (void) q;
-+ while (1) {
-+ code = 1; // Default is success
-+ INIT_REQUEST;
-+ mmc_address =
-+ (CURRENT->sector +
-+ hd[MINOR(CURRENT->rq_dev)].start_sect) * hd_hardsectsizes[0];
-+ buffer_address = CURRENT->buffer;
-+ nr_sectors = CURRENT->current_nr_sectors;
-+ cmd = CURRENT->cmd;
-+ if (((CURRENT->sector + CURRENT->current_nr_sectors +
-+ hd[MINOR(CURRENT->rq_dev)].start_sect) > hd[0].nr_sects)
-+ || (mmc_media_detect == 0)) {
-+ code = 0;
-+ } else if (cmd == READ) {
-+ spin_unlock_irq(&io_request_lock);
-+ for (i = 0; i < nr_sectors; i++) {
-+ result = mmc_read_block(buffer_address, mmc_address);
-+ if (result != 0) {
-+ printk("mmc: error %d in mmc_read_block\n", result);
-+ code = 0;
-+ break;
-+ } else {
-+ mmc_address += hd_hardsectsizes[0];
-+ buffer_address += hd_hardsectsizes[0];
-+ }
-+ }
-+ spin_lock_irq(&io_request_lock);
-+ } else if (cmd == WRITE) {
-+ spin_unlock_irq(&io_request_lock);
-+ for (i = 0; i < nr_sectors; i++) {
-+ result = mmc_write_block(mmc_address, buffer_address);
-+ if (result != 0) {
-+ printk("mmc: error %d in mmc_write_block\n", result);
-+ code = 0;
-+ break;
-+ } else {
-+ mmc_address += hd_hardsectsizes[0];
-+ buffer_address += hd_hardsectsizes[0];
-+ }
-+ }
-+ spin_lock_irq(&io_request_lock);
-+ } else {
-+ code = 0;
-+ }
-+ end_request(code);
-+ }
-+}
-+
-+
-+static int mmc_open(struct inode *inode, struct file *filp)
-+{
-+ /*int device;*/
-+ (void) filp;
-+ mmc_media_detect = mmc_spi_media_detect();
-+
-+ if (mmc_media_detect == 0)
-+ return -ENODEV;
-+
-+#if defined(MODULE)
-+ MOD_INC_USE_COUNT;
-+#endif
-+ return 0;
-+}
-+
-+static int mmc_release(struct inode *inode, struct file *filp)
-+{
-+ (void) filp;
-+ fsync_dev(inode->i_rdev);
-+ invalidate_buffers(inode->i_rdev);
-+
-+#if defined(MODULE)
-+ MOD_DEC_USE_COUNT;
-+#endif
-+ return 0;
-+}
-+
-+static int mmc_revalidate(kdev_t dev)
-+{
-+ int target, max_p, start, i;
-+
-+ mmc_media_detect = mmc_spi_media_detect();
-+
-+ if (mmc_media_detect == 0)
-+ return -ENODEV;
-+
-+ target = DEVICE_NR(dev);
-+
-+ max_p = hd_gendisk.max_p;
-+ start = target << 6;
-+ for (i = max_p - 1; i >= 0; i--) {
-+ int minor = start + i;
-+ invalidate_device(MKDEV(MAJOR_NR, minor), 1);
-+ hd_gendisk.part[minor].start_sect = 0;
-+ hd_gendisk.part[minor].nr_sects = 0;
-+ }
-+
-+ grok_partitions(&hd_gendisk, target, 1 << 6, hd_sizes[0] * 2);
-+
-+ return 0;
-+}
-+
-+static int mmc_ioctl(struct inode *inode, struct file *filp,
-+ unsigned int cmd, unsigned long arg)
-+{
-+ if (!inode || !inode->i_rdev)
-+ return -EINVAL;
-+
-+ switch (cmd) {
-+ case BLKGETSIZE:
-+ return put_user(hd[MINOR(inode->i_rdev)].nr_sects,
-+ (unsigned long *) arg);
-+ case BLKGETSIZE64:
-+ return put_user((u64) hd[MINOR(inode->i_rdev)].
-+ nr_sects, (u64 *) arg);
-+ case BLKRRPART:
-+ if (!capable(CAP_SYS_ADMIN))
-+ return -EACCES;
-+
-+ return mmc_revalidate(inode->i_rdev);
-+ case HDIO_GETGEO:
-+ {
-+ struct hd_geometry *loc, g;
-+ loc = (struct hd_geometry *) arg;
-+ if (!loc)
-+ return -EINVAL;
-+ g.heads = 4;
-+ g.sectors = 16;
-+ g.cylinders = hd[0].nr_sects / (4 * 16);
-+ g.start = hd[MINOR(inode->i_rdev)].start_sect;
-+ return copy_to_user(loc, &g, sizeof(g)) ? -EFAULT : 0;
-+ }
-+ default:
-+ return blk_ioctl(inode->i_rdev, cmd, arg);
-+ }
-+}
-+
-+
-+/*
-+static int mmc_check_media_change(kdev_t dev)
-+{
-+ (void) dev;
-+ if (mmc_media_changed == 1) {
-+ mmc_media_changed = 0;
-+ return 1;
-+ } else
-+ return 0;
-+}
-+*/
-+
-+static struct block_device_operations mmc_bdops = {
-+ open:mmc_open,
-+ release:mmc_release,
-+ ioctl:mmc_ioctl,
-+/* FIXME: add media change support
-+ * check_media_change: mmc_check_media_change,
-+ * revalidate: mmc_revalidate,
-+ */
-+};
-+
-+static struct gendisk hd_gendisk = {
-+ major:MAJOR_NR,
-+ major_name:DEVICE_NAME,
-+ minor_shift:6,
-+ max_p:1 << 6,
-+ part:hd,
-+ sizes:hd_sizes,
-+ fops:&mmc_bdops,
-+};
-+
-+static int mmc_init(void)
-+{
-+ int result;
-+
-+ result = mmc_spi_hardware_init();
-+
-+ if (result != 0) {
-+ printk("mmc: error %d in mmc_spi_hardware_init\n", result);
-+ return -1;
-+ }
-+
-+ result = mmc_spi_card_init();
-+ if (result != 0) {
-+ // Give it an extra shot
-+ result = mmc_spi_card_init();
-+ if (result != 0) {
-+ printk("mmc: error %d in mmc_card_init\n", result);
-+ return -1;
-+ }
-+ }
-+
-+ memset(hd_sizes, 0, sizeof(hd_sizes));
-+ result = mmc_spi_card_config();
-+ if (result != 0) {
-+ printk("mmc: error %d in mmc_card_config\n", result);
-+ return -1;
-+ }
-+
-+
-+ blk_size[MAJOR_NR] = hd_sizes;
-+
-+ memset(hd, 0, sizeof(hd));
-+ hd[0].nr_sects = hd_sizes[0] * 2;
-+
-+ blksize_size[MAJOR_NR] = hd_blocksizes;
-+ hardsect_size[MAJOR_NR] = hd_hardsectsizes;
-+ max_sectors[MAJOR_NR] = hd_maxsect;
-+
-+ hd_gendisk.nr_real = 1;
-+
-+ register_disk(&hd_gendisk, MKDEV(MAJOR_NR, 0), 1 << 6,
-+ &mmc_bdops, hd_sizes[0] * 2);
-+
-+ return 0;
-+}
-+
-+static void mmc_exit(void)
-+{
-+ blk_size[MAJOR_NR] = NULL;
-+ blksize_size[MAJOR_NR] = NULL;
-+ hardsect_size[MAJOR_NR] = NULL;
-+ max_sectors[MAJOR_NR] = NULL;
-+ hd[0].nr_sects = 0;
-+}
-+
-+static void mmc_check_media(void)
-+{
-+ int old_state, new_state;
-+ int result;
-+
-+ old_state = mmc_media_detect;
-+ new_state = mmc_spi_media_detect();
-+
-+ if (old_state != new_state) {
-+ mmc_media_changed = 1;
-+ if (new_state == PRESENT) {
-+ result = mmc_init();
-+ if (result != 0)
-+ printk("mmc: error %d in mmc_init\n", result);
-+ } else {
-+ mmc_exit();
-+ }
-+ }
-+
-+ /* del_timer(&mmc_timer);
-+ mmc_timer.expires = jiffies + 10*HZ;
-+ add_timer(&mmc_timer); */
-+}
-+
-+static int __init mmc_driver_init(void)
-+{
-+ int result;
-+
-+ result = devfs_register_blkdev(MAJOR_NR, DEVICE_NAME, &mmc_bdops);
-+ if (result < 0) {
-+ printk(KERN_WARNING "mmc: can't get major %d\n", MAJOR_NR);
-+ return result;
-+ }
-+
-+ blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), mmc_request);
-+
-+ mmc_check_media();
-+
-+ /*init_timer(&mmc_timer);
-+ mmc_timer.expires = jiffies + HZ;
-+ mmc_timer.function = (void *)mmc_check_media;
-+ add_timer(&mmc_timer); */
-+
-+
-+ read_ahead[MAJOR_NR] = 8;
-+ add_gendisk(&hd_gendisk);
-+
-+
-+ return 0;
-+}
-+
-+static void __exit mmc_driver_exit(void)
-+{
-+ int i;
-+ del_timer(&mmc_timer);
-+
-+ for (i = 0; i < (1 << 6); i++)
-+ fsync_dev(MKDEV(MAJOR_NR, i));
-+
-+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-+ del_gendisk(&hd_gendisk);
-+ devfs_unregister_blkdev(MAJOR_NR, DEVICE_NAME);
-+ mmc_exit();
-+}
-+
-+module_init(mmc_driver_init);
-+module_exit(mmc_driver_exit);
---- linux-2.4.27/drivers/block/Config.in~mmc-spi
-+++ linux-2.4.27/drivers/block/Config.in
-@@ -4,6 +4,7 @@
- mainmenu_option next_comment
- comment 'Block devices'
-
-+tristate 'MMC SPI driver' CONFIG_BLK_DEV_MMC
- tristate 'Normal floppy disk support' CONFIG_BLK_DEV_FD
- if [ "$CONFIG_AMIGA" = "y" ]; then
- tristate 'Amiga floppy support' CONFIG_AMIGA_FLOPPY
---- linux-2.4.27/drivers/block/Makefile~mmc-spi
-+++ linux-2.4.27/drivers/block/Makefile
-@@ -15,6 +15,7 @@
- obj-y := ll_rw_blk.o blkpg.o genhd.o elevator.o
-
- obj-$(CONFIG_MAC_FLOPPY) += swim3.o
-+obj-$(CONFIG_BLK_DEV_MMC) += mmc.o
- obj-$(CONFIG_BLK_DEV_FD) += floppy.o
- obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o
- obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o