diff options
author | Frederic Bompart <frederic@unknown.openembedded.org> | 2005-11-11 14:51:32 +0000 |
---|---|---|
committer | OpenEmbedded Project <openembedded-devel@lists.openembedded.org> | 2005-11-11 14:51:32 +0000 |
commit | 5fb88e711e1f6614c358d6a331e81881ba11d1bc (patch) | |
tree | a5be76558dfac886e2ddfc1b505e3c4c77b2f172 /packages/linux/opensimpad/mmc-spi.patch | |
parent | ddfdc42ce0e9c07226c1a6390b03e5df4e731902 (diff) |
opensimpad: MMC support + better support for SinusPad and 128M SIMpad
- There's now a config options to build the kernel for 128Mb SIMpad
(as there was one for the SinusPad)
- The .bb files automatically turn on these options depending on the
total memory available.
- The MMC driver was made by Clement Ballabriga <clement@asso.ups-tlse.fr>
and Guylhem Aznar <simpad@externe.net>.
Adding an MMC card (internal or external) to the SIMpad is described
on these pages:
http://externe.net/zaurus/simpad-bluetooth/
http://www.iral.com/~albertr/linux/simpad/mmc/
Diffstat (limited to 'packages/linux/opensimpad/mmc-spi.patch')
-rw-r--r-- | packages/linux/opensimpad/mmc-spi.patch | 885 |
1 files changed, 885 insertions, 0 deletions
diff --git a/packages/linux/opensimpad/mmc-spi.patch b/packages/linux/opensimpad/mmc-spi.patch new file mode 100644 index 0000000000..1841b45fbd --- /dev/null +++ b/packages/linux/opensimpad/mmc-spi.patch @@ -0,0 +1,885 @@ + +# +# 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 |