mirror of https://github.com/hak5/openwrt-owl.git
parent
a123c4daaf
commit
8def1507df
|
@ -1,46 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2007 OpenWrt.org
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
include $(INCLUDE_DIR)/kernel.mk
|
||||
|
||||
PKG_NAME:=broadcom-mmc
|
||||
PKG_VERSION:=0.1
|
||||
PKG_RELEASE:=1
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
MAKEFLAGS_KMOD:= -C "$(LINUX_DIR)" \
|
||||
CROSS_COMPILE="$(TARGET_CROSS)" \
|
||||
ARCH="$(LINUX_KARCH)" \
|
||||
PATH="$(TARGET_PATH)" \
|
||||
SUBDIRS="$(PKG_BUILD_DIR)"
|
||||
|
||||
define KernelPackage/broadcom-mmc
|
||||
SUBMENU:=Other modules
|
||||
DEPENDS:=@TARGET_brcm_2_4
|
||||
TITLE:=Kernel driver for the Linksys WRT54G MM/SD-Card Mod
|
||||
URL:=http://kiel.kool.dk/
|
||||
FILES:=$(PKG_BUILD_DIR)/mmc.$(LINUX_KMOD_SUFFIX)
|
||||
AUTOLOAD:=$(call AutoLoad,80,mmc)
|
||||
endef
|
||||
|
||||
define KernelPackage/broadcom-mmc/description
|
||||
Kernel driver for the Linksys WRT54G MM/SD-Card Mod
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
$(CP) ./src/* $(PKG_BUILD_DIR)/
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
$(MAKE) $(MAKEFLAGS_KMOD) \
|
||||
modules
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,broadcom-mmc))
|
|
@ -1,7 +0,0 @@
|
|||
obj-m := mmc.o
|
||||
|
||||
ifeq ($(MAKING_MODULES),1)
|
||||
|
||||
-include $(TOPDIR)/Rules.make
|
||||
endif
|
||||
|
|
@ -1,676 +0,0 @@
|
|||
#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/uaccess.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define DEVICE_NAME "mmc"
|
||||
#define DEVICE_NR(device) (MINOR(device))
|
||||
#define DEVICE_ON(device)
|
||||
#define DEVICE_OFF(device)
|
||||
#define MAJOR_NR 121
|
||||
|
||||
#include <linux/blk.h>
|
||||
|
||||
MODULE_AUTHOR("Madsuk/Rohde");
|
||||
MODULE_DESCRIPTION("Driver MMC/SD-Cards");
|
||||
MODULE_SUPPORTED_DEVICE("WRT54G");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define SD_DI 0x20
|
||||
#define SD_DO 0x10
|
||||
#define SD_CLK 0x08
|
||||
#define SD_CS 0x80
|
||||
|
||||
/* 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;
|
||||
static int mmc_media_detect = 0;
|
||||
static int mmc_media_changed = 1;
|
||||
|
||||
typedef unsigned int uint32;
|
||||
|
||||
static unsigned char port_state = 0x00;
|
||||
static volatile uint32 *gpioaddr_input = (uint32 *)0xb8000060;
|
||||
static volatile uint32 *gpioaddr_output = (uint32 *)0xb8000064;
|
||||
static volatile uint32 *gpioaddr_enable = (uint32 *)0xb8000068;
|
||||
static volatile uint32 *gpioaddr_control = (uint32 *)0xb800006c;
|
||||
|
||||
static void mmc_spi_cs_low(void)
|
||||
{
|
||||
port_state &= ~(SD_CS);
|
||||
*gpioaddr_output = port_state;
|
||||
}
|
||||
|
||||
static void mmc_spi_cs_high(void)
|
||||
{
|
||||
port_state |= SD_CS;
|
||||
*gpioaddr_output = port_state;
|
||||
}
|
||||
|
||||
static unsigned char mmc_spi_io(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)))
|
||||
port_state |= SD_DI;
|
||||
else
|
||||
port_state &= ~SD_DI;
|
||||
|
||||
*gpioaddr_output = port_state;
|
||||
port_state |= SD_CLK;
|
||||
*gpioaddr_output = port_state;
|
||||
|
||||
tmp_data = *gpioaddr_input;
|
||||
|
||||
port_state &= ~SD_CLK;
|
||||
*gpioaddr_output = port_state;
|
||||
|
||||
result <<= 1;
|
||||
|
||||
if(tmp_data & SD_DO)
|
||||
result |= 1;
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
static int mmc_write_block(unsigned int dest_addr, unsigned char *data)
|
||||
{
|
||||
unsigned int address;
|
||||
unsigned char r = 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;
|
||||
mmc_spi_cs_low();
|
||||
for (i = 0; i < 4; i++) mmc_spi_io(0xff);
|
||||
mmc_spi_io(0x58);
|
||||
mmc_spi_io(ab3); /* msb */
|
||||
mmc_spi_io(ab2);
|
||||
mmc_spi_io(ab1);
|
||||
mmc_spi_io(ab0); /* lsb */
|
||||
mmc_spi_io(0xff);
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
r = mmc_spi_io(0xff);
|
||||
if (r == 0x00) break;
|
||||
}
|
||||
if (r != 0x00)
|
||||
{
|
||||
mmc_spi_cs_high();
|
||||
mmc_spi_io(0xff);
|
||||
return(1);
|
||||
}
|
||||
|
||||
mmc_spi_io(0xfe);
|
||||
for (i = 0; i < 512; i++) mmc_spi_io(data[i]);
|
||||
for (i = 0; i < 2; i++) mmc_spi_io(0xff);
|
||||
|
||||
for (i = 0; i < 1000000; i++)
|
||||
{
|
||||
r = mmc_spi_io(0xff);
|
||||
if (r == 0xff) break;
|
||||
}
|
||||
if (r != 0xff)
|
||||
{
|
||||
mmc_spi_cs_high();
|
||||
mmc_spi_io(0xff);
|
||||
return(3);
|
||||
}
|
||||
mmc_spi_cs_high();
|
||||
mmc_spi_io(0xff);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int mmc_read_block(unsigned char *data, unsigned int src_addr)
|
||||
{
|
||||
unsigned int address;
|
||||
unsigned char r = 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;
|
||||
|
||||
mmc_spi_cs_low();
|
||||
for (i = 0; i < 4; i++) mmc_spi_io(0xff);
|
||||
mmc_spi_io(0x51);
|
||||
mmc_spi_io(ab3); /* msb */
|
||||
mmc_spi_io(ab2);
|
||||
mmc_spi_io(ab1);
|
||||
mmc_spi_io(ab0); /* lsb */
|
||||
|
||||
mmc_spi_io(0xff);
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
r = mmc_spi_io(0xff);
|
||||
if (r == 0x00) break;
|
||||
}
|
||||
if (r != 0x00)
|
||||
{
|
||||
mmc_spi_cs_high();
|
||||
mmc_spi_io(0xff);
|
||||
return(1);
|
||||
}
|
||||
for (i = 0; i < 100000; i++)
|
||||
{
|
||||
r = mmc_spi_io(0xff);
|
||||
if (r == 0xfe) break;
|
||||
}
|
||||
if (r != 0xfe)
|
||||
{
|
||||
mmc_spi_cs_high();
|
||||
mmc_spi_io(0xff);
|
||||
return(2);
|
||||
}
|
||||
for (i = 0; i < 512; i++)
|
||||
{
|
||||
r = mmc_spi_io(0xff);
|
||||
data[i] = r;
|
||||
}
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
r = mmc_spi_io(0xff);
|
||||
}
|
||||
mmc_spi_cs_high();
|
||||
mmc_spi_io(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 rc, 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++)
|
||||
{
|
||||
rc = mmc_read_block(buffer_address, mmc_address);
|
||||
if (rc != 0)
|
||||
{
|
||||
printk("mmc: error in mmc_read_block (%d)\n", rc);
|
||||
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++)
|
||||
{
|
||||
rc = mmc_write_block(mmc_address, buffer_address);
|
||||
if (rc != 0)
|
||||
{
|
||||
printk("mmc: error in mmc_write_block (%d)\n", rc);
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
extern struct gendisk hd_gendisk;
|
||||
static int mmc_revalidate(kdev_t dev)
|
||||
{
|
||||
int target, max_p, start, i;
|
||||
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_card_init(void)
|
||||
{
|
||||
unsigned char r = 0;
|
||||
short i, j;
|
||||
unsigned long flags;
|
||||
|
||||
save_flags(flags);
|
||||
cli();
|
||||
|
||||
printk("mmc Card init\n");
|
||||
mmc_spi_cs_high();
|
||||
for (i = 0; i < 20; i++) mmc_spi_io(0xff);
|
||||
|
||||
mmc_spi_cs_low();
|
||||
|
||||
mmc_spi_io(0x40);
|
||||
for (i = 0; i < 4; i++) mmc_spi_io(0x00);
|
||||
mmc_spi_io(0x95);
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
r = mmc_spi_io(0xff);
|
||||
if (r == 0x01) break;
|
||||
}
|
||||
mmc_spi_cs_high();
|
||||
mmc_spi_io(0xff);
|
||||
if (r != 0x01)
|
||||
{
|
||||
restore_flags(flags);
|
||||
return(1);
|
||||
}
|
||||
|
||||
printk("mmc Card init *1*\n");
|
||||
for (j = 0; j < 10000; j++)
|
||||
{
|
||||
mmc_spi_cs_low();
|
||||
|
||||
mmc_spi_io(0x41);
|
||||
for (i = 0; i < 4; i++) mmc_spi_io(0x00);
|
||||
mmc_spi_io(0xff);
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
r = mmc_spi_io(0xff);
|
||||
if (r == 0x00) break;
|
||||
}
|
||||
mmc_spi_cs_high();
|
||||
mmc_spi_io(0xff);
|
||||
if (r == 0x00)
|
||||
{
|
||||
restore_flags(flags);
|
||||
printk("mmc Card init *2*\n");
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
restore_flags(flags);
|
||||
|
||||
return(2);
|
||||
}
|
||||
|
||||
static int mmc_card_config(void)
|
||||
{
|
||||
unsigned char r = 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;
|
||||
|
||||
mmc_spi_cs_low();
|
||||
for (i = 0; i < 4; i++) mmc_spi_io(0xff);
|
||||
mmc_spi_io(0x49);
|
||||
for (i = 0; i < 4; i++) mmc_spi_io(0x00);
|
||||
mmc_spi_io(0xff);
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
r = mmc_spi_io(0xff);
|
||||
if (r == 0x00) break;
|
||||
}
|
||||
if (r != 0x00)
|
||||
{
|
||||
mmc_spi_cs_high();
|
||||
mmc_spi_io(0xff);
|
||||
return(1);
|
||||
}
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
r = mmc_spi_io(0xff);
|
||||
if (r == 0xfe) break;
|
||||
}
|
||||
if (r != 0xfe)
|
||||
{
|
||||
mmc_spi_cs_high();
|
||||
mmc_spi_io(0xff);
|
||||
return(2);
|
||||
}
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
r = mmc_spi_io(0xff);
|
||||
csd[i] = r;
|
||||
}
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
r = mmc_spi_io(0xff);
|
||||
}
|
||||
mmc_spi_cs_high();
|
||||
mmc_spi_io(0xff);
|
||||
if (r == 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;
|
||||
}
|
||||
|
||||
static int mmc_hardware_init(void)
|
||||
{
|
||||
unsigned char gpio_outen;
|
||||
|
||||
// Set inputs/outputs here
|
||||
printk("mmc Hardware init\n");
|
||||
gpio_outen = *gpioaddr_enable;
|
||||
|
||||
gpio_outen = (gpio_outen | SD_DI | SD_CLK | SD_CS) & ~SD_DO;
|
||||
*gpioaddr_enable = gpio_outen;
|
||||
|
||||
port_state = *gpioaddr_input;
|
||||
|
||||
// Clock low
|
||||
port_state &= ~(SD_CLK | SD_DI | SD_CS);
|
||||
*gpioaddr_output = port_state;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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,
|
||||
#if 0
|
||||
check_media_change: mmc_check_media_change,
|
||||
revalidate: mmc_revalidate,
|
||||
#endif
|
||||
};
|
||||
|
||||
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 rc;
|
||||
|
||||
rc = mmc_hardware_init();
|
||||
|
||||
if ( rc != 0)
|
||||
{
|
||||
printk("mmc: error in mmc_hardware_init (%d)\n", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = mmc_card_init();
|
||||
if ( rc != 0)
|
||||
{
|
||||
// Give it an extra shot
|
||||
rc = mmc_card_init();
|
||||
if ( rc != 0)
|
||||
{
|
||||
printk("mmc: error in mmc_card_init (%d)\n", rc);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
memset(hd_sizes, 0, sizeof(hd_sizes));
|
||||
rc = mmc_card_config();
|
||||
if ( rc != 0)
|
||||
{
|
||||
printk("mmc: error in mmc_card_config (%d)\n", rc);
|
||||
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;
|
||||
int rc;
|
||||
|
||||
old_state = mmc_media_detect;
|
||||
|
||||
// TODO: Add card detection here
|
||||
mmc_media_detect = 1;
|
||||
if (old_state != mmc_media_detect)
|
||||
{
|
||||
mmc_media_changed = 1;
|
||||
if (mmc_media_detect == 1)
|
||||
{
|
||||
rc = mmc_init();
|
||||
if (rc != 0) printk("mmc: error in mmc_init (%d)\n", rc);
|
||||
}
|
||||
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 rc;
|
||||
|
||||
rc = devfs_register_blkdev(MAJOR_NR, DEVICE_NAME, &mmc_bdops);
|
||||
if (rc < 0)
|
||||
{
|
||||
printk(KERN_WARNING "mmc: can't get major %d\n", MAJOR_NR);
|
||||
return rc;
|
||||
}
|
||||
|
||||
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), mmc_request);
|
||||
|
||||
read_ahead[MAJOR_NR] = 8;
|
||||
add_gendisk(&hd_gendisk);
|
||||
|
||||
mmc_check_media();
|
||||
|
||||
/*init_timer(&mmc_timer);
|
||||
mmc_timer.expires = jiffies + HZ;
|
||||
mmc_timer.function = (void *)mmc_check_media;
|
||||
add_timer(&mmc_timer);*/
|
||||
|
||||
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);
|
Loading…
Reference in New Issue