new driver: multimedia card (mmc) framework, patch against 2.4.19

From: James Hicks (Jamey.Hicks@hp.com)
Date: Fri Aug 09 2002 - 15:24:15 EST


This patch implements the core framework for Multimedia Cards (MMC). It
has been tested with iPAQ H3800 handhelds with MMC storage cards.

At the moment, access to the information required to write a driver for SD
or SDIO requires signing and NDA that precludes the release of an open
source driver, so only MMC is supported at this time.
 
Jamey Hicks
jamey.hicks@hp.com

diff -ruwN -X dontdiff linux-2.4.19/Documentation/Configure.help linux-2.4.19-mmc1/Documentation/Configure.help
--- linux-2.4.19/Documentation/Configure.help Fri Aug 2 20:39:42 2002
+++ linux-2.4.19-mmc1/Documentation/Configure.help Fri Aug 9 14:45:17 2002
@@ -14257,6 +14257,25 @@
   The module will be called bluetooth.o. If you want to compile it as
   a module, say M here and read <file:Documentation/modules.txt>.
 
+MMC/SD Card support
+CONFIG_MMC
+ Say Y or M here if you want to enable support for Multimedia or
+ Secure Digital Cards. You will need an MMC/SD socket and drivers
+ for your socket. At the moment, access to the information required
+ to write a driver for SD or SDIO requires signing and NDA that
+ precludes the release of an open source driver, so only MMC is
+ supported at this time. If you want to compile it as a module, say
+ M here and read <file:Documentation/modules.txt>.
+
+MMC debugging
+CONFIG_MMC_DEBUG
+ Say Y here if you want to enable debug output from the MMC drivers.
+
+MMC debugging verbosity
+CONFIG_MMC_DEBUG_VERBOSE
+ Enter a number from 0 (quiet) to 3 (noisy) here to control the
+ verbosity of MMC debug output.
+
 Minix fs support
 CONFIG_MINIX_FS
   Minix is a simple operating system used in many classes about OS's.
diff -ruwN -X dontdiff linux-2.4.19/MAINTAINERS linux-2.4.19-mmc1/MAINTAINERS
--- linux-2.4.19/MAINTAINERS Fri Aug 2 20:39:42 2002
+++ linux-2.4.19-mmc1/MAINTAINERS Fri Aug 9 12:50:27 2002
@@ -1013,6 +1013,14 @@
 L: linux-kernel@vger.kernel.org
 S: Maintained
 
+MULTIMEDIA CARD (MMC) SUBSYSTEM
+P: Andrew Christian
+P: Jamey Hicks
+P: George France
+L: MMC-Developer's <mmc-dev@handhelds.org>
+W: http://www.handhelds.org/pub/linux/mmc/
+S: Maintained
+
 MODULE SUPPORT [GENERAL], KMOD
 P: Keith Owens
 M: kaos@ocs.com.au
diff -ruwN -X dontdiff linux-2.4.19/arch/alpha/config.in linux-2.4.19-mmc1/arch/alpha/config.in
--- linux-2.4.19/arch/alpha/config.in Fri Aug 2 20:39:42 2002
+++ linux-2.4.19-mmc1/arch/alpha/config.in Fri Aug 9 12:37:54 2002
@@ -404,6 +404,7 @@
 source drivers/input/Config.in
 
 source net/bluetooth/Config.in
+source drivers/mmc/Config.in
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
diff -ruwN -X dontdiff linux-2.4.19/arch/arm/config.in linux-2.4.19-mmc1/arch/arm/config.in
--- linux-2.4.19/arch/arm/config.in Fri Aug 2 20:39:42 2002
+++ linux-2.4.19-mmc1/arch/arm/config.in Fri Aug 9 12:37:45 2002
@@ -630,6 +630,7 @@
 source drivers/usb/Config.in
 
 source net/bluetooth/Config.in
+source drivers/mmc/Config.in
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
diff -ruwN -X dontdiff linux-2.4.19/arch/cris/config.in linux-2.4.19-mmc1/arch/cris/config.in
--- linux-2.4.19/arch/cris/config.in Mon Feb 25 14:37:52 2002
+++ linux-2.4.19-mmc1/arch/cris/config.in Fri Aug 9 12:38:23 2002
@@ -244,6 +244,7 @@
 endmenu
 
 source drivers/usb/Config.in
+source drivers/mmc/Config.in
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
diff -ruwN -X dontdiff linux-2.4.19/arch/i386/config.in linux-2.4.19-mmc1/arch/i386/config.in
--- linux-2.4.19/arch/i386/config.in Fri Aug 2 20:39:42 2002
+++ linux-2.4.19-mmc1/arch/i386/config.in Fri Aug 9 12:37:32 2002
@@ -411,6 +411,7 @@
 source drivers/usb/Config.in
 
 source net/bluetooth/Config.in
+source drivers/mmc/Config.in
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
diff -ruwN -X dontdiff linux-2.4.19/arch/ia64/config.in linux-2.4.19-mmc1/arch/ia64/config.in
--- linux-2.4.19/arch/ia64/config.in Fri Aug 2 20:39:42 2002
+++ linux-2.4.19-mmc1/arch/ia64/config.in Fri Aug 9 12:38:35 2002
@@ -257,6 +257,7 @@
   endmenu
 fi
 
+source drivers/mmc/Config.in
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
diff -ruwN -X dontdiff linux-2.4.19/arch/m68k/config.in linux-2.4.19-mmc1/arch/m68k/config.in
--- linux-2.4.19/arch/m68k/config.in Fri Aug 2 20:39:43 2002
+++ linux-2.4.19-mmc1/arch/m68k/config.in Fri Aug 9 12:38:47 2002
@@ -554,6 +554,8 @@
    endmenu
 fi
 
+source drivers/mmc/Config.in
+
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
diff -ruwN -X dontdiff linux-2.4.19/arch/mips/config.in linux-2.4.19-mmc1/arch/mips/config.in
--- linux-2.4.19/arch/mips/config.in Fri Aug 2 20:39:43 2002
+++ linux-2.4.19-mmc1/arch/mips/config.in Fri Aug 9 12:39:00 2002
@@ -621,6 +621,8 @@
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
+source drivers/mmc/Config.in
+
 bool 'Are you using a crosscompiler' CONFIG_CROSSCOMPILE
 if [ "$CONFIG_SERIAL" = "y" -o "$CONFIG_AU1000_UART" = "y" ]; then
   bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
diff -ruwN -X dontdiff linux-2.4.19/arch/mips64/config.in linux-2.4.19-mmc1/arch/mips64/config.in
--- linux-2.4.19/arch/mips64/config.in Fri Aug 2 20:39:43 2002
+++ linux-2.4.19-mmc1/arch/mips64/config.in Fri Aug 9 12:57:31 2002
@@ -322,6 +322,7 @@
 source drivers/usb/Config.in
 
 source net/bluetooth/Config.in
+source drivers/mmc/Config.in
 
 source drivers/input/Config.in
 
diff -ruwN -X dontdiff linux-2.4.19/arch/parisc/config.in linux-2.4.19-mmc1/arch/parisc/config.in
--- linux-2.4.19/arch/parisc/config.in Tue Apr 17 20:19:25 2001
+++ linux-2.4.19-mmc1/arch/parisc/config.in Fri Aug 9 12:57:40 2002
@@ -201,6 +201,8 @@
 fi
 # endmenu
 
+source drivers/mmc/Config.in
+
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
diff -ruwN -X dontdiff linux-2.4.19/arch/ppc/config.in linux-2.4.19-mmc1/arch/ppc/config.in
--- linux-2.4.19/arch/ppc/config.in Fri Aug 2 20:39:43 2002
+++ linux-2.4.19-mmc1/arch/ppc/config.in Fri Aug 9 12:57:48 2002
@@ -394,6 +394,7 @@
 source drivers/usb/Config.in
 
 source net/bluetooth/Config.in
+source drivers/mmc/Config.in
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
diff -ruwN -X dontdiff linux-2.4.19/arch/ppc64/config.in linux-2.4.19-mmc1/arch/ppc64/config.in
--- linux-2.4.19/arch/ppc64/config.in Fri Aug 2 20:39:43 2002
+++ linux-2.4.19-mmc1/arch/ppc64/config.in Fri Aug 9 12:57:57 2002
@@ -225,6 +225,7 @@
 endmenu
 
 source drivers/usb/Config.in
+source drivers/mmc/Config.in
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
diff -ruwN -X dontdiff linux-2.4.19/arch/s390/config.in linux-2.4.19-mmc1/arch/s390/config.in
--- linux-2.4.19/arch/s390/config.in Fri Aug 2 20:39:43 2002
+++ linux-2.4.19-mmc1/arch/s390/config.in Fri Aug 9 12:58:03 2002
@@ -64,6 +64,7 @@
 fi
 
 source fs/Config.in
+source drivers/mmc/Config.in
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
diff -ruwN -X dontdiff linux-2.4.19/arch/s390x/config.in linux-2.4.19-mmc1/arch/s390x/config.in
--- linux-2.4.19/arch/s390x/config.in Fri Aug 2 20:39:43 2002
+++ linux-2.4.19-mmc1/arch/s390x/config.in Fri Aug 9 12:58:11 2002
@@ -66,6 +66,7 @@
 fi
 
 source fs/Config.in
+source drivers/mmc/Config.in
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
diff -ruwN -X dontdiff linux-2.4.19/arch/sh/config.in linux-2.4.19-mmc1/arch/sh/config.in
--- linux-2.4.19/arch/sh/config.in Mon Feb 25 14:37:56 2002
+++ linux-2.4.19-mmc1/arch/sh/config.in Fri Aug 9 12:58:20 2002
@@ -377,6 +377,8 @@
 fi
 endmenu
 
+source drivers/mmc/Config.in
+
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
diff -ruwN -X dontdiff linux-2.4.19/arch/sparc/config.in linux-2.4.19-mmc1/arch/sparc/config.in
--- linux-2.4.19/arch/sparc/config.in Fri Aug 2 20:39:43 2002
+++ linux-2.4.19-mmc1/arch/sparc/config.in Fri Aug 9 12:58:32 2002
@@ -266,6 +266,8 @@
 tristate 'Software watchdog' CONFIG_SOFT_WATCHDOG
 endmenu
 
+source drivers/mmc/Config.in
+
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
diff -ruwN -X dontdiff linux-2.4.19/arch/sparc64/config.in linux-2.4.19-mmc1/arch/sparc64/config.in
--- linux-2.4.19/arch/sparc64/config.in Fri Aug 2 20:39:43 2002
+++ linux-2.4.19-mmc1/arch/sparc64/config.in Fri Aug 9 12:58:42 2002
@@ -291,6 +291,8 @@
 tristate 'Software watchdog' CONFIG_SOFT_WATCHDOG
 endmenu
 
+source drivers/mmc/Config.in
+
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
diff -ruwN -X dontdiff linux-2.4.19/drivers/Makefile linux-2.4.19-mmc1/drivers/Makefile
--- linux-2.4.19/drivers/Makefile Fri Aug 2 20:39:43 2002
+++ linux-2.4.19-mmc1/drivers/Makefile Fri Aug 9 12:37:12 2002
@@ -46,5 +46,6 @@
 subdir-$(CONFIG_ACPI) += acpi
 
 subdir-$(CONFIG_BLUEZ) += bluetooth
+subdir-$(CONFIG_MMC) += mmc
 
 include $(TOPDIR)/Rules.make
diff -ruwN -X dontdiff linux-2.4.19/drivers/mmc/Config.in linux-2.4.19-mmc1/drivers/mmc/Config.in
--- linux-2.4.19/drivers/mmc/Config.in Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-mmc1/drivers/mmc/Config.in Tue Jun 18 08:38:40 2002
@@ -0,0 +1,15 @@
+#
+# MMC subsystem configuration
+#
+mainmenu_option next_comment
+comment 'MMC/SD Card support'
+
+tristate 'MMC support' CONFIG_MMC
+if [ "$CONFIG_MMC" = "y" -o "$CONFIG_MMC" = "m" ]; then
+ bool ' MMC debugging' CONFIG_MMC_DEBUG
+ if [ "$CONFIG_MMC_DEBUG" = "y" ]; then
+ int ' MMC debugging verbosity (0=quiet, 3=noisy)' CONFIG_MMC_DEBUG_VERBOSE 0
+ fi
+fi
+
+endmenu
diff -ruwN -X dontdiff linux-2.4.19/drivers/mmc/Makefile linux-2.4.19-mmc1/drivers/mmc/Makefile
--- linux-2.4.19/drivers/mmc/Makefile Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-mmc1/drivers/mmc/Makefile Tue Jun 18 08:38:40 2002
@@ -0,0 +1,20 @@
+#
+# Makefile for the kernel mmc device drivers.
+#
+
+O_TARGET := mmc.o
+
+export-objs := mmc_core.o
+
+obj-$(CONFIG_MMC) += mmc_base.o
+
+# Declare multi-part drivers.
+list-multi := mmc_base.o
+mmc_base-objs := mmc_protocol.o mmc_core.o mmc_media.o
+
+include $(TOPDIR)/Rules.make
+
+# Link rules for multi-part drivers.
+
+mmc_base.o: $(mmc_base-objs)
+ $(LD) -r -o $@ $(mmc_base-objs)
diff -ruwN -X dontdiff linux-2.4.19/drivers/mmc/mmc_core.c linux-2.4.19-mmc1/drivers/mmc/mmc_core.c
--- linux-2.4.19/drivers/mmc/mmc_core.c Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-mmc1/drivers/mmc/mmc_core.c Fri Aug 9 16:18:37 2002
@@ -0,0 +1,839 @@
+/*
+ * Core MMC driver functions
+ *
+ * Copyright (c) 2002 Hewlett-Packard Company
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
+ *
+ * Author: Andrew Christian
+ * 6 May 2002 */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/version.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/sysctl.h>
+#include <linux/pm.h>
+
+#include "mmc_core.h"
+
+#define STATE_CMD_ACTIVE (1<<0)
+#define STATE_CMD_DONE (1<<1)
+#define STATE_INSERT (1<<2)
+#define STATE_EJECT (1<<3)
+
+static struct mmc_dev g_mmc_dev;
+static struct proc_dir_entry *proc_mmc_dir;
+
+int g_mmc_debug = CONFIG_MMC_DEBUG_VERBOSE;
+EXPORT_SYMBOL(g_mmc_debug);
+
+/**************************************************************************
+ * Debugging functions
+ **************************************************************************/
+
+static char * mmc_result_strings[] = {
+ "NO_RESPONSE",
+ "NO_ERROR",
+ "ERROR_OUT_OF_RANGE",
+ "ERROR_ADDRESS",
+ "ERROR_BLOCK_LEN",
+ "ERROR_ERASE_SEQ",
+ "ERROR_ERASE_PARAM",
+ "ERROR_WP_VIOLATION",
+ "ERROR_CARD_IS_LOCKED",
+ "ERROR_LOCK_UNLOCK_FAILED",
+ "ERROR_COM_CRC",
+ "ERROR_ILLEGAL_COMMAND",
+ "ERROR_CARD_ECC_FAILED",
+ "ERROR_CC",
+ "ERROR_GENERAL",
+ "ERROR_UNDERRUN",
+ "ERROR_OVERRUN",
+ "ERROR_CID_CSD_OVERWRITE",
+ "ERROR_STATE_MISMATCH",
+ "ERROR_HEADER_MISMATCH",
+ "ERROR_TIMEOUT",
+ "ERROR_CRC",
+ "ERROR_DRIVER_FAILURE",
+};
+
+char * mmc_result_to_string( int i )
+{
+ return mmc_result_strings[i+1];
+}
+
+static char * card_state_strings[] = {
+ "empty",
+ "idle",
+ "ready",
+ "ident",
+ "stby",
+ "tran",
+ "data",
+ "rcv",
+ "prg",
+ "dis",
+};
+
+static inline char * card_state_to_string( int i )
+{
+ return card_state_strings[i+1];
+}
+
+/**************************************************************************
+ * Utility functions
+ **************************************************************************/
+
+#define PARSE_U32(_buf,_index) \
+ (((u32)_buf[_index]) << 24) | (((u32)_buf[_index+1]) << 16) | \
+ (((u32)_buf[_index+2]) << 8) | ((u32)_buf[_index+3]);
+
+#define PARSE_U16(_buf,_index) \
+ (((u16)_buf[_index]) << 8) | ((u16)_buf[_index+1]);
+
+int mmc_unpack_csd( struct mmc_request *request, struct mmc_csd *csd )
+{
+ u8 *buf = request->response;
+
+ if ( request->result ) return request->result;
+
+ csd->csd_structure = (buf[1] & 0xc0) >> 6;
+ csd->spec_vers = (buf[1] & 0x3c) >> 2;
+ csd->taac = buf[2];
+ csd->nsac = buf[3];
+ csd->tran_speed = buf[4];
+ csd->ccc = (((u16)buf[5]) << 4) | ((buf[6] & 0xf0) >> 4);
+ csd->read_bl_len = buf[6] & 0x0f;
+ csd->read_bl_partial = (buf[7] & 0x80) ? 1 : 0;
+ csd->write_blk_misalign = (buf[7] & 0x40) ? 1 : 0;
+ csd->read_blk_misalign = (buf[7] & 0x20) ? 1 : 0;
+ csd->dsr_imp = (buf[7] & 0x10) ? 1 : 0;
+ csd->c_size = ((((u16)buf[7]) & 0x03) << 10) | (((u16)buf[8]) << 2) | (((u16)buf[9]) & 0xc0) >> 6;
+ csd->vdd_r_curr_min = (buf[9] & 0x38) >> 3;
+ csd->vdd_r_curr_max = buf[9] & 0x07;
+ csd->vdd_w_curr_min = (buf[10] & 0xe0) >> 5;
+ csd->vdd_w_curr_max = (buf[10] & 0x1c) >> 2;
+ csd->c_size_mult = ((buf[10] & 0x03) << 1) | ((buf[11] & 0x80) >> 7);
+ switch ( csd->csd_structure ) {
+ case CSD_STRUCT_VER_1_0:
+ case CSD_STRUCT_VER_1_1:
+ csd->erase.v22.sector_size = (buf[11] & 0x7c) >> 2;
+ csd->erase.v22.erase_grp_size = ((buf[11] & 0x03) << 3) | ((buf[12] & 0xe0) >> 5);
+ break;
+ case CSD_STRUCT_VER_1_2:
+ default:
+ csd->erase.v31.erase_grp_size = (buf[11] & 0x7c) >> 2;
+ csd->erase.v31.erase_grp_mult = ((buf[11] & 0x03) << 3) | ((buf[12] & 0xe0) >> 5);
+ break;
+ }
+ csd->wp_grp_size = buf[12] & 0x1f;
+ csd->wp_grp_enable = (buf[13] & 0x80) ? 1 : 0;
+ csd->default_ecc = (buf[13] & 0x60) >> 5;
+ csd->r2w_factor = (buf[13] & 0x1c) >> 2;
+ csd->write_bl_len = ((buf[13] & 0x03) << 2) | ((buf[14] & 0xc0) >> 6);
+ csd->write_bl_partial = (buf[14] & 0x20) ? 1 : 0;
+ csd->file_format_grp = (buf[15] & 0x80) ? 1 : 0;
+ csd->copy = (buf[15] & 0x40) ? 1 : 0;
+ csd->perm_write_protect = (buf[15] & 0x20) ? 1 : 0;
+ csd->tmp_write_protect = (buf[15] & 0x10) ? 1 : 0;
+ csd->file_format = (buf[15] & 0x0c) >> 2;
+ csd->ecc = buf[15] & 0x03;
+
+ DEBUG(2," csd_structure=%d spec_vers=%d taac=%02x nsac=%02x tran_speed=%02x\n"
+ " ccc=%04x read_bl_len=%d read_bl_partial=%d write_blk_misalign=%d\n"
+ " read_blk_misalign=%d dsr_imp=%d c_size=%d vdd_r_curr_min=%d\n"
+ " vdd_r_curr_max=%d vdd_w_curr_min=%d vdd_w_curr_max=%d c_size_mult=%d\n"
+ " wp_grp_size=%d wp_grp_enable=%d default_ecc=%d r2w_factor=%d\n"
+ " write_bl_len=%d write_bl_partial=%d file_format_grp=%d copy=%d\n"
+ " perm_write_protect=%d tmp_write_protect=%d file_format=%d ecc=%d\n",
+ csd->csd_structure, csd->spec_vers,
+ csd->taac, csd->nsac, csd->tran_speed,
+ csd->ccc, csd->read_bl_len,
+ csd->read_bl_partial, csd->write_blk_misalign,
+ csd->read_blk_misalign, csd->dsr_imp,
+ csd->c_size, csd->vdd_r_curr_min,
+ csd->vdd_r_curr_max, csd->vdd_w_curr_min,
+ csd->vdd_w_curr_max, csd->c_size_mult,
+ csd->wp_grp_size, csd->wp_grp_enable,
+ csd->default_ecc, csd->r2w_factor,
+ csd->write_bl_len, csd->write_bl_partial,
+ csd->file_format_grp, csd->copy,
+ csd->perm_write_protect, csd->tmp_write_protect,
+ csd->file_format, csd->ecc);
+ switch (csd->csd_structure) {
+ case CSD_STRUCT_VER_1_0:
+ case CSD_STRUCT_VER_1_1:
+ DEBUG(2," V22 sector_size=%d erase_grp_size=%d\n",
+ csd->erase.v22.sector_size,
+ csd->erase.v22.erase_grp_size);
+ break;
+ case CSD_STRUCT_VER_1_2:
+ default:
+ DEBUG(2," V31 erase_grp_size=%d erase_grp_mult=%d\n",
+ csd->erase.v31.erase_grp_size,
+ csd->erase.v31.erase_grp_mult);
+ break;
+
+ }
+
+ if ( buf[0] != 0x3f ) return MMC_ERROR_HEADER_MISMATCH;
+
+ return 0;
+}
+
+int mmc_unpack_r1( struct mmc_request *request, struct mmc_response_r1 *r1, enum card_state state )
+{
+ u8 *buf = request->response;
+
+ if ( request->result ) return request->result;
+
+ r1->cmd = buf[0];
+ r1->status = PARSE_U32(buf,1);
+
+ DEBUG(2," cmd=%d status=%08x\n", r1->cmd, r1->status);
+
+ if (R1_STATUS(r1->status)) {
+ if ( r1->status & R1_OUT_OF_RANGE ) return MMC_ERROR_OUT_OF_RANGE;
+ if ( r1->status & R1_ADDRESS_ERROR ) return MMC_ERROR_ADDRESS;
+ if ( r1->status & R1_BLOCK_LEN_ERROR ) return MMC_ERROR_BLOCK_LEN;
+ if ( r1->status & R1_ERASE_SEQ_ERROR ) return MMC_ERROR_ERASE_SEQ;
+ if ( r1->status & R1_ERASE_PARAM ) return MMC_ERROR_ERASE_PARAM;
+ if ( r1->status & R1_WP_VIOLATION ) return MMC_ERROR_WP_VIOLATION;
+ if ( r1->status & R1_CARD_IS_LOCKED ) return MMC_ERROR_CARD_IS_LOCKED;
+ if ( r1->status & R1_LOCK_UNLOCK_FAILED ) return MMC_ERROR_LOCK_UNLOCK_FAILED;
+ if ( r1->status & R1_COM_CRC_ERROR ) return MMC_ERROR_COM_CRC;
+ if ( r1->status & R1_ILLEGAL_COMMAND ) return MMC_ERROR_ILLEGAL_COMMAND;
+ if ( r1->status & R1_CARD_ECC_FAILED ) return MMC_ERROR_CARD_ECC_FAILED;
+ if ( r1->status & R1_CC_ERROR ) return MMC_ERROR_CC;
+ if ( r1->status & R1_ERROR ) return MMC_ERROR_GENERAL;
+ if ( r1->status & R1_UNDERRUN ) return MMC_ERROR_UNDERRUN;
+ if ( r1->status & R1_OVERRUN ) return MMC_ERROR_OVERRUN;
+ if ( r1->status & R1_CID_CSD_OVERWRITE ) return MMC_ERROR_CID_CSD_OVERWRITE;
+ }
+
+ if ( buf[0] != request->cmd ) return MMC_ERROR_HEADER_MISMATCH;
+
+ /* This should be last - it's the least dangerous error */
+ if ( R1_CURRENT_STATE(r1->status) != state ) return MMC_ERROR_STATE_MISMATCH;
+
+ return 0;
+}
+
+int mmc_unpack_cid( struct mmc_request *request, struct mmc_cid *cid )
+{
+ u8 *buf = request->response;
+ int i;
+
+ if ( request->result ) return request->result;
+
+ cid->mid = buf[1];
+ cid->oid = PARSE_U16(buf,2);
+ for ( i = 0 ; i < 6 ; i++ )
+ cid->pnm[i] = buf[4+i];
+ cid->pnm[6] = 0;
+ cid->prv = buf[10];
+ cid->psn = PARSE_U32(buf,11);
+ cid->mdt = buf[15];
+
+ DEBUG(2," mid=%d oid=%d pnm=%s prv=%d.%d psn=%08x mdt=%d/%d\n",
+ cid->mid, cid->oid, cid->pnm,
+ (cid->prv>>4), (cid->prv&0xf),
+ cid->psn, (cid->mdt>>4), (cid->mdt&0xf)+1997);
+
+ if ( buf[0] != 0x3f ) return MMC_ERROR_HEADER_MISMATCH;
+ return 0;
+}
+
+int mmc_unpack_r3( struct mmc_request *request, struct mmc_response_r3 *r3 )
+{
+ u8 *buf = request->response;
+
+ if ( request->result ) return request->result;
+
+ r3->ocr = PARSE_U32(buf,1);
+ DEBUG(2," ocr=%08x\n", r3->ocr);
+
+ if ( buf[0] != 0x3f ) return MMC_ERROR_HEADER_MISMATCH;
+ return 0;
+}
+
+/**************************************************************************/
+
+#define KBPS 1
+#define MBPS 1000
+
+static u32 ts_exp[] = { 100*KBPS, 1*MBPS, 10*MBPS, 100*MBPS, 0, 0, 0, 0 };
+static u32 ts_mul[] = { 0, 1000, 1200, 1300, 1500, 2000, 2500, 3000,
+ 3500, 4000, 4500, 5000, 5500, 6000, 7000, 8000 };
+
+u32 mmc_tran_speed( u8 ts )
+{
+ u32 rate = ts_exp[(ts & 0x7)] * ts_mul[(ts & 0x78) >> 3];
+
+ if ( rate <= 0 ) {
+ DEBUG(0, ": error - unrecognized speed 0x%02x\n", ts);
+ return 1;
+ }
+
+ return rate;
+}
+
+/**************************************************************************/
+
+void mmc_send_cmd( struct mmc_dev *dev, int cmd, u32 arg,
+ u16 nob, u16 block_len, enum mmc_rsp_t rtype )
+{
+ dev->request.cmd = cmd;
+ dev->request.arg = arg;
+ dev->request.rtype = rtype;
+ dev->request.nob = nob;
+ dev->request.block_len = block_len;
+ dev->request.buffer = NULL;
+ if ( nob && dev->io_request )
+ dev->request.buffer = dev->io_request->buffer;
+
+ dev->state |= STATE_CMD_ACTIVE;
+ dev->sdrive->send_cmd(&dev->request);
+}
+
+void mmc_finish_io_request( struct mmc_dev *dev, int result )
+{
+ struct mmc_io_request *t = dev->io_request;
+ struct mmc_slot *slot = dev->slot + t->id;
+
+ dev->io_request = NULL; // Remove the old request (the media driver may requeue)
+ if ( slot->media_driver )
+ slot->media_driver->io_request_done( t, result );
+}
+
+
+/* Only call this when there is no pending request - it unloads the media driver */
+int mmc_check_eject( struct mmc_dev *dev )
+{
+ unsigned long flags;
+ int state;
+ int i;
+
+ DEBUG(2," dev state=%x\n", dev->state);
+
+ local_irq_save(flags);
+ state = dev->state;
+ dev->state = state & ~STATE_EJECT;
+ local_irq_restore(flags);
+
+ if ( !(state & STATE_EJECT) )
+ return 0;
+
+ for ( i = 0 ; i < dev->num_slots ; i++ ) {
+ struct mmc_slot *slot = dev->slot + i;
+
+ if ( slot->flags & MMC_SLOT_FLAG_EJECT ) {
+ slot->state = CARD_STATE_EMPTY;
+ if ( slot->media_driver ) {
+ slot->media_driver->unload( slot );
+ slot->media_driver = NULL;
+ }
+ slot->flags &= ~MMC_SLOT_FLAG_EJECT;
+ run_sbin_mmc_hotplug(dev,i,0);
+ }
+ }
+ return 1;
+}
+
+int mmc_check_insert( struct mmc_dev *dev )
+{
+ unsigned long flags;
+ int state;
+ int i;
+ int card_count = 0;
+
+ DEBUG(2," dev state=%x\n", dev->state);
+
+ local_irq_save(flags);
+ state = dev->state;
+ dev->state = state & ~STATE_INSERT;
+ local_irq_restore(flags);
+
+ if ( !(state & STATE_INSERT) )
+ return 0;
+
+ for ( i = 0 ; i < dev->num_slots ; i++ ) {
+ struct mmc_slot *slot = dev->slot + i;
+
+ if ( slot->flags & MMC_SLOT_FLAG_INSERT ) {
+ if (!dev->sdrive->is_empty(i)) {
+ slot->state = CARD_STATE_IDLE;
+ card_count++;
+ }
+ slot->flags &= ~MMC_SLOT_FLAG_INSERT;
+ }
+ }
+ return card_count;
+}
+
+/******************************************************************
+ *
+ * Hotplug callback card insertion/removal
+ *
+ ******************************************************************/
+
+#ifdef CONFIG_HOTPLUG
+
+extern char hotplug_path[];
+extern int call_usermodehelper(char *path, char **argv, char **envp);
+
+static void run_sbin_hotplug(struct mmc_dev *dev, int id, int insert)
+{
+ int i;
+ char *argv[3], *envp[8];
+ char media[64], slotnum[16];
+
+ if (!hotplug_path[0])
+ return;
+
+ DEBUG(0,": hotplug_path=%s id=%d insert=%d\n", hotplug_path, id, insert);
+
+ i = 0;
+ argv[i++] = hotplug_path;
+ argv[i++] = "mmc";
+ argv[i] = 0;
+
+ /* minimal command environment */
+ i = 0;
+ envp[i++] = "HOME=/";
+ envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+
+ /* other stuff we want to pass to /sbin/hotplug */
+ sprintf(slotnum, "SLOT=%d", id );
+ if ( dev->slot[id].media_driver && dev->slot[id].media_driver->name )
+ sprintf(media, "MEDIA=%s", dev->slot[id].media_driver->name );
+ else
+ sprintf(media, "MEDIA=unknown");
+
+ envp[i++] = slotnum;
+ envp[i++] = media;
+
+ if (insert)
+ envp[i++] = "ACTION=add";
+ else
+ envp[i++] = "ACTION=remove";
+ envp[i] = 0;
+
+ call_usermodehelper (argv [0], argv, envp);
+}
+
+static void mmc_hotplug_task_handler( void *nr )
+{
+ int insert = ((int) nr) & 0x01;
+ int id = ((int) nr) >> 1;
+ DEBUG(2," id=%d insert=%d\n", id, insert );
+ run_sbin_hotplug(&g_mmc_dev, id, insert );
+}
+
+static struct tq_struct mmc_hotplug_task = {
+ routine: mmc_hotplug_task_handler
+};
+
+void run_sbin_mmc_hotplug(struct mmc_dev *dev, int id, int insert )
+{
+ mmc_hotplug_task.data = (void *) ((id << 1) | insert);
+ schedule_task( &mmc_hotplug_task );
+}
+
+#else
+void run_sbin_mmc_hotplug(struct sleeve_dev *sdev, int insert) { }
+#endif /* CONFIG_HOTPLUG */
+
+
+/******************************************************************
+ * Common processing tasklet
+ * Everything gets serialized through this
+ ******************************************************************/
+
+static void mmc_tasklet_action(unsigned long data)
+{
+ struct mmc_dev *dev = (struct mmc_dev *)data;
+ unsigned long flags;
+ int state;
+
+ DEBUG(2,": dev=%p flags=%02x\n", dev, dev->state);
+
+ /* Grab the current working state */
+ local_irq_save(flags);
+ state = dev->state;
+ if ( state & STATE_CMD_DONE )
+ dev->state = state & ~(STATE_CMD_DONE | STATE_CMD_ACTIVE);
+ local_irq_restore(flags);
+
+ /* If there is an active command, don't do anything */
+ if ( (state & STATE_CMD_ACTIVE) && !(state & STATE_CMD_DONE) )
+ return;
+
+ if ( dev->protocol )
+ dev->protocol(dev,state);
+}
+
+/******************************************************************
+ * Callbacks from low-level driver
+ * These run at interrupt time
+ ******************************************************************/
+
+void mmc_cmd_complete(struct mmc_request *request)
+{
+ DEBUG(2,": request=%p retval=%d\n", request, request->result);
+ g_mmc_dev.state |= STATE_CMD_DONE;
+ if ( !g_mmc_dev.suspended )
+ tasklet_schedule(&g_mmc_dev.task);
+}
+
+void mmc_insert(int slot)
+{
+ DEBUG(2,": %d\n", slot);
+ g_mmc_dev.state |= STATE_INSERT;
+ g_mmc_dev.slot[slot].flags |= MMC_SLOT_FLAG_INSERT;
+ if ( !g_mmc_dev.suspended )
+ tasklet_schedule(&g_mmc_dev.task);
+}
+
+void mmc_eject(int slot)
+{
+ DEBUG(2,": %d\n", slot);
+ g_mmc_dev.state |= STATE_EJECT;
+ g_mmc_dev.slot[slot].flags |= MMC_SLOT_FLAG_EJECT;
+ if ( !g_mmc_dev.suspended )
+ tasklet_schedule(&g_mmc_dev.task);
+}
+
+EXPORT_SYMBOL(mmc_cmd_complete);
+EXPORT_SYMBOL(mmc_insert);
+EXPORT_SYMBOL(mmc_eject);
+
+/******************************************************************
+ * Called from the media handler
+ ******************************************************************/
+
+void mmc_handle_io_request( struct mmc_io_request *t )
+{
+ DEBUG(2," id=%d cmd=%d sector=%ld nr_sectors=%ld block_len=%ld buf=%p\n",
+ t->id, t->cmd, t->sector, t->nr_sectors, t->block_len, t->buffer);
+
+ if ( g_mmc_dev.io_request ) {
+ DEBUG(0,": error! io_request in progress\n");
+ return;
+ }
+
+ g_mmc_dev.io_request = t;
+ tasklet_schedule(&g_mmc_dev.task);
+}
+
+EXPORT_SYMBOL(mmc_handle_io_request);
+
+/******************************************************************
+ * Media handlers
+ * Allow different drivers to register a media handler
+ ******************************************************************/
+
+static LIST_HEAD(mmc_media_drivers);
+
+int mmc_match_media_driver( struct mmc_slot *slot )
+{
+ struct list_head *item;
+
+ DEBUG(2,": slot=%p\n", slot);
+
+ for ( item = mmc_media_drivers.next ; item != &mmc_media_drivers ; item = item->next ) {
+ struct mmc_media_driver *drv = list_entry(item, struct mmc_media_driver, node );
+ if ( drv->probe(slot) ) {
+ slot->media_driver = drv;
+ drv->load(slot);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int mmc_register_media_driver( struct mmc_media_driver *drv )
+{
+ list_add_tail( &drv->node, &mmc_media_drivers );
+ return 0;
+}
+
+void mmc_unregister_media_driver( struct mmc_media_driver *drv )
+{
+ list_del(&drv->node);
+}
+
+EXPORT_SYMBOL(mmc_register_media_driver);
+EXPORT_SYMBOL(mmc_unregister_media_driver);
+
+/******************************************************************/
+
+int mmc_register_slot_driver( struct mmc_slot_driver *sdrive, int num_slots )
+{
+ int i;
+ int retval;
+
+ DEBUG(2," max=%d ocr=0x%08x\n", num_slots, sdrive->ocr);
+
+ if ( num_slots > MMC_MAX_SLOTS ) {
+ printk(KERN_CRIT __FUNCTION__ ": illegal num of slots %d\n", num_slots );
+ return -ENOMEM;
+ }
+
+ if ( g_mmc_dev.sdrive ) {
+ printk(KERN_ALERT __FUNCTION__ ": slot in use\n");
+ return -EBUSY;
+ }
+
+ g_mmc_dev.sdrive = sdrive;
+ g_mmc_dev.num_slots = num_slots;
+
+ for ( i = 0 ; i < num_slots ; i++ ) {
+ struct mmc_slot *slot = &g_mmc_dev.slot[i];
+ memset(slot,0,sizeof(struct mmc_slot));
+ slot->id = i;
+ slot->state = CARD_STATE_EMPTY;
+ }
+ retval = sdrive->init();
+ if ( retval )
+ return retval;
+
+ /* Generate insert events for cards */
+ for ( i = 0 ; i < num_slots ; i++ )
+ if ( !sdrive->is_empty(i) )
+ mmc_insert(i);
+ return 0;
+}
+
+void mmc_unregister_slot_driver( struct mmc_slot_driver *sdrive )
+{
+ int i;
+ DEBUG(2,"\n");
+
+ for ( i = 0 ; i < g_mmc_dev.num_slots ; i++ )
+ mmc_eject(i);
+
+ if ( sdrive == g_mmc_dev.sdrive ) {
+ g_mmc_dev.sdrive->cleanup();
+ g_mmc_dev.sdrive = NULL;
+ }
+}
+
+EXPORT_SYMBOL(mmc_register_slot_driver);
+EXPORT_SYMBOL(mmc_unregister_slot_driver);
+
+/******************************************************************/
+
+static struct pm_dev *mmc_pm_dev;
+
+static int mmc_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
+{
+ int i;
+ DEBUG(0,": pm callback %d\n", req );
+
+ switch (req) {
+ case PM_SUSPEND: /* Enter D1-D3 */
+ g_mmc_dev.suspended = 1;
+ break;
+ case PM_RESUME: /* Enter D0 */
+ if ( g_mmc_dev.suspended ) {
+ g_mmc_dev.suspended = 0;
+ g_mmc_dev.state = 0; // Clear the old state
+ for ( i = 0 ; i < g_mmc_dev.num_slots ; i++ ) {
+ mmc_eject(i);
+ if ( !g_mmc_dev.sdrive->is_empty(i) )
+ mmc_insert(i);
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+/******************************************************************
+ * TODO: These would be better handled by driverfs
+ * For the moment, we'll just eject and insert everything
+ ******************************************************************/
+
+int mmc_do_eject(ctl_table *ctl, int write, struct file * filp, void *buffer, size_t *lenp)
+{
+ mmc_eject(0);
+ return 0;
+}
+
+int mmc_do_insert(ctl_table *ctl, int write, struct file * filp, void *buffer, size_t *lenp)
+{
+ mmc_insert(0);
+ return 0;
+}
+
+
+static struct ctl_table mmc_sysctl_table[] =
+{
+ { 1, "debug", &g_mmc_debug, sizeof(int), 0666, NULL, &proc_dointvec },
+ { 2, "eject", NULL, 0, 0600, NULL, &mmc_do_eject },
+ { 3, "insert", NULL, 0, 0600, NULL, &mmc_do_insert },
+ {0}
+};
+
+static struct ctl_table mmc_dir_table[] =
+{
+ {BUS_MMC, "mmc", NULL, 0, 0555, mmc_sysctl_table},
+ {0}
+};
+
+static struct ctl_table bus_dir_table[] =
+{
+ {CTL_BUS, "bus", NULL, 0, 0555, mmc_dir_table},
+ {0}
+};
+
+static struct ctl_table_header *mmc_sysctl_header;
+
+static int mmc_proc_read_device(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ struct mmc_dev *dev = (struct mmc_dev *)data;
+ char *p = page;
+ int len = 0;
+ int i;
+
+ if (!dev || !dev->sdrive)
+ return 0;
+
+ for ( i = 0 ; i < dev->num_slots ; i++ ) {
+ struct mmc_slot *slot = &dev->slot[i];
+
+ p += sprintf(p, "Slot #%d\n", i);
+ p += sprintf(p, " State %s (%d)\n", card_state_to_string(slot->state), slot->state);
+
+ if ( slot->state != CARD_STATE_EMPTY ) {
+ p += sprintf(p, " Media %s\n", (slot->media_driver ? slot->media_driver->name : "unknown"));
+ p += sprintf(p, " CID mid=%d\n", slot->cid.mid);
+ p += sprintf(p, " oid=%d\n", slot->cid.oid);
+ p += sprintf(p, " pnm=%s\n", slot->cid.pnm);
+ p += sprintf(p, " prv=%d.%d\n", slot->cid.prv>>4, slot->cid.prv&0xf);
+ p += sprintf(p, " psn=0x%08x\n", slot->cid.psn);
+ p += sprintf(p, " mdt=%d/%d\n", slot->cid.mdt>>4, (slot->cid.mdt&0xf)+1997);
+
+ p += sprintf(p, " CSD csd_structure=%d\n", slot->csd.csd_structure);
+ p += sprintf(p, " spec_vers=%d\n", slot->csd.spec_vers);
+ p += sprintf(p, " taac=0x%02x\n", slot->csd.taac);
+ p += sprintf(p, " nsac=0x%02x\n", slot->csd.nsac);
+ p += sprintf(p, " tran_speed=0x%02x\n", slot->csd.tran_speed);
+ p += sprintf(p, " ccc=0x%04x\n", slot->csd.ccc);
+ p += sprintf(p, " read_bl_len=%d\n", slot->csd.read_bl_len);
+ p += sprintf(p, " read_bl_partial=%d\n", slot->csd.read_bl_partial);
+ p += sprintf(p, " write_blk_misalign=%d\n", slot->csd.write_blk_misalign);
+ p += sprintf(p, " read_blk_misalign=%d\n", slot->csd.read_blk_misalign);
+ p += sprintf(p, " dsr_imp=%d\n", slot->csd.dsr_imp);
+ p += sprintf(p, " c_size=%d\n", slot->csd.c_size);
+ p += sprintf(p, " vdd_r_curr_min=%d\n", slot->csd.vdd_r_curr_min);
+ p += sprintf(p, " vdd_r_curr_max=%d\n", slot->csd.vdd_r_curr_max);
+ p += sprintf(p, " vdd_w_curr_min=%d\n", slot->csd.vdd_w_curr_min);
+ p += sprintf(p, " vdd_w_curr_max=%d\n", slot->csd.vdd_w_curr_max);
+ p += sprintf(p, " c_size_mult=%d\n", slot->csd.c_size_mult);
+ p += sprintf(p, " wp_grp_size=%d\n", slot->csd.wp_grp_size);
+ p += sprintf(p, " wp_grp_enable=%d\n", slot->csd.wp_grp_enable);
+ p += sprintf(p, " default_ecc=%d\n", slot->csd.default_ecc);
+ p += sprintf(p, " r2w_factor=%d\n", slot->csd.r2w_factor);
+ p += sprintf(p, " write_bl_len=%d\n", slot->csd.write_bl_len);
+ p += sprintf(p, " write_bl_partial=%d\n", slot->csd.write_bl_partial);
+ p += sprintf(p, " file_format_grp=%d\n", slot->csd.file_format_grp);
+ p += sprintf(p, " copy=%d\n", slot->csd.copy);
+ p += sprintf(p, " perm_write_protect=%d\n", slot->csd.perm_write_protect);
+ p += sprintf(p, " tmp_write_protect=%d\n", slot->csd.tmp_write_protect);
+ p += sprintf(p, " file_format=%d\n", slot->csd.file_format);
+ p += sprintf(p, " ecc=%d\n", slot->csd.ecc);
+ switch (slot->csd.csd_structure) {
+ case CSD_STRUCT_VER_1_0:
+ case CSD_STRUCT_VER_1_1:
+ p += sprintf(p, " sector_size=%d\n", slot->csd.erase.v22.sector_size);
+ p += sprintf(p, " erase_grp_size=%d\n", slot->csd.erase.v22.erase_grp_size);
+ break;
+ case CSD_STRUCT_VER_1_2:
+ default:
+ p += sprintf(p, " erase_grp_size=%d\n", slot->csd.erase.v31.erase_grp_size);
+ p += sprintf(p, " erase_grp_mult=%d\n", slot->csd.erase.v31.erase_grp_mult);
+ break;
+ }
+ }
+ }
+
+ len = (p - page) - off;
+ *start = page + off;
+ return len;
+}
+
+/******************************************************************/
+
+void mmc_protocol_single_card( struct mmc_dev *dev, int state_flags );
+extern struct mmc_media_module media_module;
+
+static int __init mmc_init(void)
+{
+ DEBUG(1,"\n");
+
+ mmc_sysctl_header = register_sysctl_table(bus_dir_table, 0 );
+
+ tasklet_init(&g_mmc_dev.task,mmc_tasklet_action,(unsigned long)&g_mmc_dev);
+ g_mmc_dev.protocol = mmc_protocol_single_card;
+
+ proc_mmc_dir = proc_mkdir("mmc", proc_bus);
+ if ( proc_mmc_dir )
+ create_proc_read_entry("device", 0, proc_mmc_dir, mmc_proc_read_device, &g_mmc_dev);
+
+ mmc_pm_dev = pm_register(PM_UNKNOWN_DEV, PM_SYS_UNKNOWN, mmc_pm_callback);
+
+ media_module.init();
+ return 0;
+}
+
+static void __exit mmc_exit(void)
+{
+ DEBUG(1,"\n");
+
+ media_module.cleanup();
+
+ unregister_sysctl_table(mmc_sysctl_header);
+
+ tasklet_kill(&g_mmc_dev.task);
+
+ if ( proc_mmc_dir ) {
+ remove_proc_entry("device", proc_mmc_dir);
+ remove_proc_entry("mmc", proc_bus);
+ }
+
+ pm_unregister(mmc_pm_dev);
+}
+
+module_init(mmc_init);
+module_exit(mmc_exit);
+
+MODULE_AUTHOR("Andy Christian")
+MODULE_LICENSE("MIT")
+MODULE_DESCRIPTION("Core support for MultiMedia Cards")
diff -ruwN -X dontdiff linux-2.4.19/drivers/mmc/mmc_core.h linux-2.4.19-mmc1/drivers/mmc/mmc_core.h
--- linux-2.4.19/drivers/mmc/mmc_core.h Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-mmc1/drivers/mmc/mmc_core.h Fri Aug 9 16:07:14 2002
@@ -0,0 +1,79 @@
+/*
+ * Header for MultiMediaCard (MMC)
+ *
+ * Copyright (c) 2002 Hewlett-Packard Company
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
+ *
+ * Based strongly on code by:
+ *
+ * Author: Yong-iL Joh <tolkien@mizi.com>
+ * Date : $Date: 2002/06/18 19:06:06 $
+ *
+ * Author: Andrew Christian
+ * 15 May 2002
+ */
+
+#ifndef MMC_MMC_CORE_H
+#define MMC_MMC_CORE_H
+
+#include <linux/mmc/mmc_ll.h>
+#include "mmc_media.h"
+
+#define ID_TO_RCA(x) ((x)+1)
+
+struct mmc_dev {
+ struct mmc_slot_driver *sdrive;
+ struct mmc_slot slot[MMC_MAX_SLOTS];
+ struct mmc_request request; // Active request to the low-level driver
+ struct mmc_io_request *io_request; // Active transfer request from the high-level media io
+ struct tasklet_struct task;
+ int num_slots; // Copied from the slot driver; used when slot driver shuts down
+
+ /* State maintenance */
+ int state;
+ int suspended;
+ void (*protocol)(struct mmc_dev *, int);
+};
+
+char * mmc_result_to_string( int );
+int mmc_unpack_csd( struct mmc_request *request, struct mmc_csd *csd );
+int mmc_unpack_r1( struct mmc_request *request, struct mmc_response_r1 *r1, enum card_state state );
+int mmc_unpack_cid( struct mmc_request *request, struct mmc_cid *cid );
+int mmc_unpack_r3( struct mmc_request *request, struct mmc_response_r3 *r3 );
+
+void mmc_send_cmd( struct mmc_dev *dev, int cmd, u32 arg,
+ u16 nob, u16 block_len, enum mmc_rsp_t rtype );
+void mmc_finish_io_request( struct mmc_dev *dev, int result );
+int mmc_check_eject( struct mmc_dev *dev );
+int mmc_check_insert( struct mmc_dev *dev );
+u32 mmc_tran_speed( u8 ts );
+int mmc_match_media_driver( struct mmc_slot *slot );
+void run_sbin_mmc_hotplug(struct mmc_dev *dev, int id, int insert);
+
+static inline void mmc_simple_cmd( struct mmc_dev *dev, int cmd, u32 arg, enum mmc_rsp_t rtype )
+{
+ mmc_send_cmd( dev, cmd, arg, 0, 0, rtype );
+}
+
+#endif /* MMC_MMC_CORE_H */
+
diff -ruwN -X dontdiff linux-2.4.19/drivers/mmc/mmc_media.c linux-2.4.19-mmc1/drivers/mmc/mmc_media.c
--- linux-2.4.19/drivers/mmc/mmc_media.c Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-mmc1/drivers/mmc/mmc_media.c Fri Aug 9 16:07:24 2002
@@ -0,0 +1,511 @@
+/*
+ * Block driver for media (i.e., flash cards)
+ *
+ * Copyright 2002 Hewlett-Packard Company
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
+ *
+ * Author: Andrew Christian
+ * 28 May 2002
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h> /* printk() */
+#include <linux/fs.h> /* everything... */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/fcntl.h> /* O_ACCMODE */
+#include <linux/hdreg.h> /* HDIO_GETGEO */
+#include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include "mmc_media.h"
+
+#define MAJOR_NR mmc_major /* force definitions on in blk.h */
+static int mmc_major; /* must be declared before including blk.h */
+
+#define MMC_SHIFT 3 /* max 8 partitions per card */
+
+#define DEVICE_NR(device) (MINOR(device)>>MMC_SHIFT)
+#define DEVICE_NAME "mmc" /* name for messaging */
+#define DEVICE_INTR mmc_intrptr /* pointer to the bottom half */
+#define DEVICE_NO_RANDOM /* no entropy to contribute */
+#define DEVICE_REQUEST mmc_media_request
+#define DEVICE_OFF(d) /* do-nothing */
+
+#include <linux/blk.h>
+#include <linux/blkpg.h>
+
+static int rahead = 8;
+static int maxsectors = 4;
+
+MODULE_PARM(maxsectors,"i");
+MODULE_PARM_DESC(maxsectors,"Maximum number of sectors for a single request");
+MODULE_PARM(rahead,"i");
+MODULE_PARM_DESC(rahead,"Default sector read ahead");
+
+#define MMC_NDISK (MMC_MAX_SLOTS << MMC_SHIFT)
+
+/*
+ Don't bother messing with blksize_size....it gets changed by various filesystems.
+ You're better off dealing with arbitrary blksize's
+*/
+static int mmc_blk[MMC_NDISK]; /* Used for hardsect_size - should be 512 bytes */
+static int mmc_max[MMC_NDISK]; /* Used for max_sectors[] - limit size of individual request */
+
+static int mmc_sizes[MMC_NDISK]; /* Used in gendisk - gives whole size of partition */
+static struct hd_struct mmc_partitions[MMC_NDISK]; /* Used in gendisk - gives particular partition information */
+
+static char mmc_gendisk_flags;
+static devfs_handle_t mmc_devfs_handle;
+
+// There is one mmc_media_dev per inserted card
+struct mmc_media_dev {
+ int usage;
+ struct mmc_slot *slot;
+ spinlock_t lock;
+ int changed;
+ long nr_sects; // In total number of sectors
+
+ int read_block_len; // Valid read block length
+ int write_block_len; // Valid write block length
+};
+
+static struct mmc_media_dev g_media_dev[MMC_MAX_SLOTS];
+static struct mmc_io_request g_io_request;
+static int g_busy;
+
+static struct gendisk mmc_gendisk = {
+ major: 0, /* major number dynamically assigned */
+ major_name: DEVICE_NAME,
+ minor_shift: MMC_SHIFT, /* shift to get device number */
+ max_p: 1 << MMC_SHIFT, /* Number of partiions */
+ /* The remainder will be filled in dynamically */
+};
+
+/*************************************************************************/
+/* TODO: O_EXCL, O_NDELAY, invalidate_buffers */
+static int mmc_media_open( struct inode *inode, struct file *filp )
+{
+ struct mmc_media_dev *dev;
+ int num = DEVICE_NR(inode->i_rdev);
+
+ DEBUG(1,": num=%d\n", num);
+
+ if ( num >= MMC_MAX_SLOTS)
+ return -ENODEV;
+
+ dev = &g_media_dev[num];
+ if ( !dev->slot )
+ return -ENODEV;
+
+ spin_lock(&dev->lock);
+ if (!dev->usage)
+ check_disk_change(inode->i_rdev);
+ dev->usage++;
+ MOD_INC_USE_COUNT;
+ spin_unlock(&dev->lock);
+ return 0;
+}
+
+static int mmc_media_release( struct inode *inode, struct file *filep )
+{
+ struct mmc_media_dev *dev = &g_media_dev[DEVICE_NR(inode->i_rdev)];
+
+ DEBUG(1,": num=%d\n", DEVICE_NR(inode->i_rdev));
+
+ spin_lock(&dev->lock);
+ dev->usage--;
+ /* Is this worth doing? */
+ if (!dev->usage) {
+ fsync_dev(inode->i_rdev);
+ invalidate_buffers(inode->i_rdev);
+ }
+ MOD_DEC_USE_COUNT;
+ spin_unlock(&dev->lock);
+ return 0;
+}
+
+static int mmc_media_revalidate(kdev_t i_rdev)
+{
+ int index, max_p, start, i;
+ struct mmc_media_dev *dev;
+
+ index = DEVICE_NR(i_rdev);
+ DEBUG(2,": index=%d\n", index);
+
+ max_p = mmc_gendisk.max_p;
+ start = index << MMC_SHIFT;
+ dev = &g_media_dev[index];
+
+ for ( i = max_p - 1 ; i >= 0 ; i-- ) {
+ int item = start + i;
+ invalidate_device(MKDEV(mmc_major,item),1);
+ mmc_gendisk.part[item].start_sect = 0;
+ mmc_gendisk.part[item].nr_sects = 0;
+ /* TODO: Fix the blocksize? */
+ }
+
+ register_disk(&mmc_gendisk, i_rdev, 1 << MMC_SHIFT, mmc_gendisk.fops, dev->nr_sects);
+ return 0;
+}
+
+static int mmc_media_ioctl (struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ int num = DEVICE_NR(inode->i_rdev);
+ int size;
+ struct hd_geometry geo;
+
+ DEBUG(1," ioctl 0x%x 0x%lx\n", cmd, arg);
+
+ switch(cmd) {
+ case BLKGETSIZE:
+ /* Return the device size, expressed in sectors */
+ /* Not really necessary, but this is faster than walking the gendisk list */
+ if (!access_ok(VERIFY_WRITE, arg, sizeof(long)))
+ return -EFAULT;
+ return put_user(mmc_partitions[MINOR(inode->i_rdev)].nr_sects, (long *)arg);
+
+ case BLKRRPART: /* re-read partition table */
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ return mmc_media_revalidate(inode->i_rdev);
+
+ case HDIO_GETGEO:
+ if (!access_ok(VERIFY_WRITE, arg, sizeof(geo)))
+ return -EFAULT;
+ /* Grab the size from the 0 partition for this minor */
+ /* TODO: is this the right thing? Or should we do it by partition??? */
+ size = mmc_sizes[num << MMC_SHIFT] / mmc_blk[num << MMC_SHIFT];
+ geo.cylinders = (size & ~0x3f) >> 6;
+ geo.heads = 4;
+ geo.sectors = 16;
+ geo.start = mmc_partitions[MINOR(inode->i_rdev)].start_sect;
+ if (copy_to_user((void *) arg, &geo, sizeof(geo)))
+ return -EFAULT;
+ return 0;
+
+ default:
+ return blk_ioctl(inode->i_rdev, cmd, arg);
+ }
+
+ return -ENOTTY; /* should never get here */
+}
+
+static int mmc_media_check_change(kdev_t i_rdev)
+{
+ int index, retval;
+ struct mmc_media_dev *dev;
+ unsigned long flags;
+
+ index = DEVICE_NR(i_rdev);
+ DEBUG(2," device=%d\n", index);
+ if (index >= MMC_MAX_SLOTS)
+ return 0;
+
+ dev = &g_media_dev[index];
+
+ spin_lock_irqsave(&dev->lock, flags);
+ retval = (dev->changed ? 1 : 0);
+ dev->changed = 0;
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ return retval;
+}
+
+static struct mmc_media_dev * mmc_media_locate_device(const struct request *req)
+{
+ int num = DEVICE_NR(req->rq_dev);
+ if ( num >= MMC_MAX_SLOTS) {
+ static int count = 0;
+ if (count++ < 5) /* print the message at most five times */
+ printk(KERN_WARNING "mmc: request for unknown device\n");
+ return NULL;
+ }
+ return &g_media_dev[num];
+}
+
+static int mmc_media_transfer( struct mmc_media_dev *dev, const struct request *req )
+{
+ int minor = MINOR(req->rq_dev);
+ unsigned long flags;
+
+ DEBUG(2,": minor=%d\n", minor);
+
+ if ( req->sector + req->current_nr_sectors > mmc_partitions[minor].nr_sects ) {
+ static int count = 0;
+ if (count++ < 5)
+ printk(KERN_WARNING __FUNCTION__ ": request past end of partition\n");
+ return 0;
+ }
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ g_io_request.id = DEVICE_NR(req->rq_dev);
+ g_io_request.cmd = req->cmd;
+ g_io_request.sector = mmc_partitions[minor].start_sect + req->sector;
+ g_io_request.nr_sectors = req->current_nr_sectors;
+ g_io_request.block_len = mmc_blk[minor];
+ g_io_request.buffer = req->buffer;
+
+ DEBUG(2,": id=%d cmd=%d sector=%ld nr_sectors=%ld block_len=%ld buf=%p\n",
+ g_io_request.id, g_io_request.cmd, g_io_request.sector, g_io_request.nr_sectors,
+ g_io_request.block_len, g_io_request.buffer );
+
+ mmc_handle_io_request(&g_io_request);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return 1;
+}
+
+static void mmc_media_request( request_queue_t *q )
+{
+ struct mmc_media_dev *dev;
+
+ if ( g_busy )
+ return;
+
+ while(1) {
+ INIT_REQUEST; /* returns when queue is empty */
+ dev = mmc_media_locate_device(CURRENT);
+ if ( !dev ) {
+ end_request(0);
+ continue;
+ }
+
+ DEBUG(2," (%p): cmd %i sec %li (nr. %li)\n", CURRENT,
+ CURRENT->cmd, CURRENT->sector, CURRENT->current_nr_sectors);
+
+ if ( mmc_media_transfer(dev,CURRENT) ) {
+ g_busy = 1;
+ return;
+ }
+ end_request(0); /* There was a problem with the request */
+ }
+}
+
+static void mmc_media_transfer_done( struct mmc_io_request *trans, int result )
+{
+ unsigned long flags;
+ DEBUG(3,": result=%d\n", result);
+ spin_lock_irqsave(&io_request_lock, flags);
+ end_request(result);
+ g_busy = 0;
+ if (!QUEUE_EMPTY)
+ mmc_media_request(NULL); // Start the next transfer
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+
+static struct block_device_operations mmc_bdops = {
+ open: mmc_media_open,
+ release: mmc_media_release,
+ ioctl: mmc_media_ioctl,
+ check_media_change: mmc_media_check_change,
+ revalidate: mmc_media_revalidate
+};
+
+/******************************************************************/
+/* TODO:
+ We have a race condition if two slots need to be revalidated at the same
+ time. Perhaps we should walk the list of devices and look for change
+ flags?
+*/
+
+static void mmc_media_load_task_handler( void *nr )
+{
+ int slot_id = (int) nr;
+ DEBUG(2," slot_id=%d\n", slot_id );
+ mmc_media_revalidate(MKDEV(mmc_major,(slot_id<<MMC_SHIFT)));
+}
+
+static struct tq_struct mmc_media_load_task = {
+ routine: mmc_media_load_task_handler
+};
+
+static void mmc_media_load( struct mmc_slot *slot )
+{
+ unsigned long flags;
+ struct mmc_media_dev *dev = &g_media_dev[slot->id];
+ int i;
+
+ long nr_sects;
+ int write_block_len;
+ int read_block_len;
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ nr_sects = (1 + slot->csd.c_size) * (1 << (slot->csd.c_size_mult + 2));
+ write_block_len = 1 << slot->csd.write_bl_len;
+ read_block_len = 1 << slot->csd.read_bl_len;
+
+ MOD_INC_USE_COUNT;
+ DEBUG(1, " slot=%p nr_sect=%ld write_block_length=%d read_block_len=%d\n",
+ slot, nr_sects, write_block_len, read_block_len );
+
+ dev->slot = slot;
+ dev->nr_sects = nr_sects;
+ dev->read_block_len = read_block_len;
+ dev->write_block_len = write_block_len;
+ dev->changed = 1;
+ mmc_gendisk.nr_real++;
+
+ /* Fix up the block size to match read_block_len */
+ /* TODO: can we really do this? Right now we're affecting blksize_size and hardsect_size */
+ for ( i = 0 ; i < (1 << MMC_SHIFT) ; i++ )
+ mmc_blk[(slot->id << MMC_SHIFT) + i] = read_block_len;
+
+ mmc_media_load_task.data = (void *) slot->id;
+ schedule_task( &mmc_media_load_task );
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+/* TODO: This is a problem area. We've lost our card, so we'd like
+ to flush all outstanding buffers and requests, remove the partitions from
+ the file system, and generally shut everything down.
+*/
+
+static void mmc_media_unload( struct mmc_slot *slot )
+{
+ unsigned long flags;
+ struct mmc_media_dev *dev = &g_media_dev[slot->id];
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+// for ( i = 0 ; i < MMC_SHIFT ; i++ )
+// fsync_dev(MKDEV(mmc_major,slot->id,i));
+
+ MOD_DEC_USE_COUNT;
+ DEBUG(1," slot=%p id=%d\n", slot, slot->id);
+
+ dev->slot = NULL;
+ dev->nr_sects = 0;
+ dev->changed = 1;
+ mmc_gendisk.nr_real--;
+
+ mmc_media_load_task.data = (void *) slot->id;
+ schedule_task( &mmc_media_load_task );
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+/*
+ Called once the device has a valid CSD structure
+ In the future this should determine what type of card we have
+ For the moment, everything is a memory card
+*/
+
+static int mmc_media_probe( struct mmc_slot *slot )
+{
+ return 1;
+}
+
+static struct mmc_media_driver mmc_driver = {
+ name: "flash",
+ load: mmc_media_load,
+ unload: mmc_media_unload,
+ probe: mmc_media_probe,
+ io_request_done: mmc_media_transfer_done,
+};
+
+/******************************************************************/
+
+static int __init mmc_media_init( void )
+{
+ int i, result;
+ DEBUG(0,"\n");
+
+ mmc_devfs_handle = devfs_mk_dir(NULL, DEVICE_NAME, NULL);
+ if (!mmc_devfs_handle) return -EBUSY;
+
+ result = devfs_register_blkdev(mmc_major, DEVICE_NAME, &mmc_bdops);
+ if (result < 0) {
+ printk(KERN_WARNING "Unable to get major %d for MMC media\n", mmc_major);
+ return result;
+ }
+
+ if ( !mmc_major ) mmc_major = result;
+
+ /* Set up global block arrays */
+ read_ahead[mmc_major] = rahead;
+ for(i=0 ; i < MMC_NDISK; i++)
+ mmc_blk[i] = 512;
+ hardsect_size[mmc_major] = mmc_blk;
+ for(i=0; i < MMC_NDISK; i++)
+ mmc_max[i] = maxsectors;
+ max_sectors[mmc_major] = mmc_max;
+
+ /* Start with zero-sized partitions : we'll fix this later */
+ memset(mmc_sizes, 0, sizeof(int) * MMC_NDISK);
+ blk_size[mmc_major] = mmc_sizes;
+
+ /* Fix up the gendisk structure */
+ mmc_gendisk.part = mmc_partitions;
+ mmc_gendisk.sizes = mmc_sizes;
+ mmc_gendisk.nr_real = 0;
+ mmc_gendisk.de_arr = &mmc_devfs_handle;
+ mmc_gendisk.flags = &mmc_gendisk_flags;
+ mmc_gendisk.fops = &mmc_bdops;
+
+ /* Add ourselves to the global list */
+ mmc_gendisk.major = mmc_major;
+ add_gendisk(&mmc_gendisk);
+
+ blk_init_queue(BLK_DEFAULT_QUEUE(mmc_major), DEVICE_REQUEST);
+ return mmc_register_media_driver(&mmc_driver);
+}
+
+static void __exit mmc_media_cleanup( void )
+{
+ int i;
+ DEBUG(0,"\n");
+
+ flush_scheduled_tasks();
+ unregister_blkdev(mmc_major, DEVICE_NAME);
+
+ for ( i = 0 ; i < MMC_NDISK; i++ )
+ fsync_dev(MKDEV(mmc_major,i));
+
+ mmc_unregister_media_driver(&mmc_driver);
+
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(mmc_major));
+
+ blk_size[mmc_major] = NULL;
+ hardsect_size[mmc_major] = NULL;
+ max_sectors[mmc_major] = NULL;
+
+ del_gendisk(&mmc_gendisk);
+
+ devfs_unregister(mmc_devfs_handle);
+}
+
+struct mmc_media_module media_module = {
+ init: mmc_media_init,
+ cleanup: mmc_media_cleanup
+};
diff -ruwN -X dontdiff linux-2.4.19/drivers/mmc/mmc_media.h linux-2.4.19-mmc1/drivers/mmc/mmc_media.h
--- linux-2.4.19/drivers/mmc/mmc_media.h Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-mmc1/drivers/mmc/mmc_media.h Fri Aug 9 16:07:33 2002
@@ -0,0 +1,96 @@
+/*
+ * Header for MultiMediaCard (MMC)
+ *
+ * Copyright (c) 2002 Hewlett-Packard Company
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
+ *
+ * Based strongly on code by:
+ *
+ * Author: Yong-iL Joh <tolkien@mizi.com>
+ * Date : $Date: 2002/06/18 12:38:40 $
+ *
+ * Author: Andrew Christian
+ * 15 May 2002
+ */
+
+#ifndef MMC_MMC_MEDIA_H
+#define MMC_MMC_MEDIA_H
+
+#include <linux/interrupt.h>
+#include <linux/list.h>
+
+#include <linux/mmc/mmc_protocol.h>
+
+/* Set an upper bound for how many cards we'll support */
+/* This is used only for static array initialization */
+#define MMC_MAX_SLOTS 2
+
+#define MMC_SLOT_FLAG_INSERT (1<<0)
+#define MMC_SLOT_FLAG_EJECT (1<<1)
+
+struct mmc_media_driver;
+
+struct mmc_slot {
+ int id; /* Card index */
+ /* Card specific information */
+ struct mmc_cid cid;
+ struct mmc_csd csd;
+
+ enum card_state state; /* empty, ident, ready, whatever */
+ int flags; /* Ejected, inserted */
+
+ /* Assigned media driver */
+ struct mmc_media_driver *media_driver;
+};
+
+struct mmc_io_request {
+ int id; /* Card index */
+ int cmd; /* READ or WRITE */
+ unsigned long sector; /* Start address */
+ unsigned long nr_sectors; /* Length of read */
+ unsigned long block_len; /* Size of sector (sanity check) */
+ char *buffer; /* Data buffer */
+};
+
+/* Media driver (e.g., Flash card, I/O card...) */
+struct mmc_media_driver {
+ struct list_head node;
+ char *name;
+ void (*load)(struct mmc_slot *);
+ void (*unload)(struct mmc_slot *);
+ int (*probe)(struct mmc_slot *);
+ void (*io_request_done)(struct mmc_io_request *, int result);
+};
+
+struct mmc_media_module {
+ int (*init)(void);
+ void (*cleanup)(void);
+};
+
+/* Calls made by the media driver */
+extern int mmc_register_media_driver( struct mmc_media_driver * );
+extern void mmc_unregister_media_driver( struct mmc_media_driver * );
+extern void mmc_handle_io_request( struct mmc_io_request * );
+
+#endif /* MMC_MMC_MEDIA_H */
+
diff -ruwN -X dontdiff linux-2.4.19/drivers/mmc/mmc_protocol.c linux-2.4.19-mmc1/drivers/mmc/mmc_protocol.c
--- linux-2.4.19/drivers/mmc/mmc_protocol.c Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-mmc1/drivers/mmc/mmc_protocol.c Fri Aug 9 16:07:45 2002
@@ -0,0 +1,440 @@
+/*
+ * MMC State machine functions
+ *
+ * Copyright (c) 2002 Hewlett-Packard Company
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
+ *
+ * This part of the code is separated from mmc_core.o so we can
+ * plug in different state machines (e.g., SPI, SD)
+ *
+ * This code assumes that you have exactly one card slot, no more.
+ *
+ * Author: Andrew Christian
+ * 6 May 2002
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/version.h>
+#include <linux/proc_fs.h>
+
+#include "mmc_core.h"
+
+static void * mmc_cim_default_state( struct mmc_dev *dev, int first );
+
+/******************************************************************
+ *
+ * Useful utility functions
+ *
+ ******************************************************************/
+
+static int mmc_has_valid_request( struct mmc_dev *dev )
+{
+ struct mmc_io_request *request = dev->io_request;
+ struct mmc_slot *slot;
+
+ DEBUG(2," (%p)\n", request);
+
+ if ( !request ) return 0;
+
+ slot = dev->slot + request->id;
+
+ if ( !slot->media_driver ) {
+ DEBUG(0,": card doesn't have media driver\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+static void mmc_configure_card( struct mmc_dev *dev, int slot )
+{
+ u32 rate;
+ DEBUG(2,": slot=%d\n", slot);
+
+ /* Fix the clock rate */
+ rate = mmc_tran_speed(dev->slot[slot].csd.tran_speed);
+ if ( rate < MMC_CLOCK_SLOW )
+ rate = MMC_CLOCK_SLOW;
+ if ( rate > MMC_CLOCK_FAST )
+ rate = MMC_CLOCK_FAST;
+
+ dev->sdrive->set_clock(rate);
+
+ /* Match the drive media */
+ mmc_match_media_driver(&dev->slot[slot]);
+ run_sbin_mmc_hotplug(dev, slot, 1);
+}
+
+/* The blocks requested by the kernel may or may not
+ match what we can do. Unfortunately, filesystems play
+ fast and loose with block sizes, so we're stuck with this */
+
+static void mmc_fix_request_block_size( struct mmc_dev *dev )
+{
+ struct mmc_io_request *t = dev->io_request;
+ struct mmc_slot *slot = dev->slot + t->id;
+ u16 block_len;
+
+ DEBUG(1, ": io_request id=%d cmd=%d sector=%ld nr_sectors=%ld block_len=%ld buf=%p\n",
+ t->id, t->cmd, t->sector, t->nr_sectors, t->block_len, t->buffer);
+
+ switch( t->cmd ) {
+ case READ:
+ block_len = 1 << slot->csd.read_bl_len;
+ break;
+ case WRITE:
+ block_len = 1 << slot->csd.write_bl_len;
+ break;
+ default:
+ DEBUG(0,": unrecognized command %d\n", t->cmd);
+ return;
+ }
+
+ if ( block_len < t->block_len ) {
+ int scale = t->block_len / block_len;
+ DEBUG(1,": scaling by %d from block_len=%d to %ld\n",
+ scale, block_len, t->block_len);
+ t->block_len = block_len;
+ t->sector *= scale;
+ t->nr_sectors *= scale;
+ }
+}
+
+
+/******************************************************************
+ * State machine routines to read and write data
+ *
+ * SET_BLOCKLEN only needs to be done once for each card.
+ * SET_BLOCK_COUNT is only valid in MMC 3.1; most cards don't support this,
+ * so we don't use it.
+ *
+ * In the 2.x cards we have a choice between STREAMING mode and
+ * SINGLE mode. There's an obvious performance possibility in
+ * using streaming mode, but at this time we're just using the SINGLE
+ * mode.
+ ******************************************************************/
+
+static void * mmc_cim_read_write_block( struct mmc_dev *dev, int first )
+{
+ struct mmc_io_request *t = dev->io_request;
+ struct mmc_response_r1 r1;
+ struct mmc_slot *slot = dev->slot + t->id;
+ int retval = 0;
+ int i;
+
+ DEBUG(2," first=%d\n",first);
+
+ if ( first ) {
+ mmc_fix_request_block_size( dev );
+
+ switch ( slot->state ) {
+ case CARD_STATE_STBY:
+ mmc_simple_cmd(dev, MMC_SELECT_CARD, ID_TO_RCA(slot->id) << 16, RESPONSE_R1B );
+ break;
+ case CARD_STATE_TRAN:
+ mmc_simple_cmd(dev, MMC_SET_BLOCKLEN, t->block_len, RESPONSE_R1 );
+ break;
+ default:
+ DEBUG(0,": invalid card state %d\n", slot->state);
+ goto read_block_error;
+ break;
+ }
+ return NULL;
+ }
+
+ switch (dev->request.cmd) {
+ case MMC_SELECT_CARD:
+ if ( (retval = mmc_unpack_r1( &dev->request, &r1, slot->state )) )
+ goto read_block_error;
+
+ for ( i = 0 ; i < dev->num_slots ; i++ )
+ dev->slot[i].state = ( i == t->id ? CARD_STATE_TRAN : CARD_STATE_STBY );
+
+ mmc_simple_cmd(dev, MMC_SET_BLOCKLEN, t->block_len, RESPONSE_R1 );
+ break;
+
+ case MMC_SET_BLOCKLEN:
+ if ( (retval = mmc_unpack_r1( &dev->request, &r1, slot->state )) )
+ goto read_block_error;
+
+ mmc_send_cmd(dev, (t->cmd == READ ? MMC_READ_SINGLE_BLOCK : MMC_WRITE_BLOCK),
+ t->sector * t->block_len, 1, t->block_len, RESPONSE_R1 );
+ break;
+
+ case MMC_READ_SINGLE_BLOCK:
+ case MMC_WRITE_BLOCK:
+ if ( (retval = mmc_unpack_r1( &dev->request, &r1, slot->state )) )
+ goto read_block_error;
+
+ t->nr_sectors--;
+ t->sector++;
+ t->buffer += t->block_len;
+
+ if ( t->nr_sectors ) {
+ mmc_send_cmd(dev, (t->cmd == READ ? MMC_READ_SINGLE_BLOCK : MMC_WRITE_BLOCK),
+ t->sector * t->block_len, 1, t->block_len, RESPONSE_R1 );
+ }
+ else {
+ mmc_finish_io_request( dev, 1 );
+ if ( mmc_has_valid_request(dev) )
+ return mmc_cim_read_write_block;
+ return mmc_cim_default_state;
+ }
+ break;
+
+ default:
+ goto read_block_error;
+ break;
+ }
+ return NULL;
+
+read_block_error:
+ DEBUG(0,": failure during cmd %d, error %d (%s)\n",
+ dev->request.cmd, retval, mmc_result_to_string(retval));
+ mmc_finish_io_request( dev, 0 ); // Failure
+ return mmc_cim_default_state;
+}
+
+/* Update the card's status information in preparation to running a read/write cycle */
+
+static void * mmc_cim_get_status( struct mmc_dev *dev, int first )
+{
+ struct mmc_slot *slot = dev->slot + dev->io_request->id;
+ struct mmc_response_r1 r1;
+ int retval = MMC_NO_ERROR;
+
+ DEBUG(2," first=%d\n",first);
+
+ if ( first ) {
+ mmc_simple_cmd(dev, MMC_SEND_STATUS, ID_TO_RCA(slot->id) << 16, RESPONSE_R1 );
+ return NULL;
+ }
+
+ switch (dev->request.cmd) {
+ case MMC_SEND_STATUS:
+ retval = mmc_unpack_r1(&dev->request,&r1,slot->state);
+ if ( !retval || retval == MMC_ERROR_STATE_MISMATCH ) {
+ slot->state = R1_CURRENT_STATE(r1.status);
+ return mmc_cim_read_write_block;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ DEBUG(0, ": failure during cmd %d, error=%d (%s)\n", dev->request.cmd,
+ retval, mmc_result_to_string(retval));
+ mmc_finish_io_request(dev,0);
+ return mmc_cim_default_state;
+}
+
+static void * mmc_cim_handle_request( struct mmc_dev *dev, int first )
+{
+ DEBUG(2," first=%d\n",first);
+
+ if ( !first && !mmc_has_valid_request(dev)) {
+ DEBUG(0, ": invalid request\n");
+ mmc_finish_io_request(dev,0);
+ return mmc_cim_default_state;
+ }
+
+ if ( first )
+ return mmc_cim_get_status;
+
+ return mmc_cim_read_write_block;
+}
+
+/******************************************************************
+ *
+ * State machine routines to initialize card(s)
+ *
+ ******************************************************************/
+
+/*
+ CIM_SINGLE_CARD_ACQ (frequency at 400 kHz)
+ --- Must enter from GO_IDLE_STATE ---
+
+ 1. SEND_OP_COND (Full Range) [CMD1] {optional}
+ 2. SEND_OP_COND (Set Range ) [CMD1]
+ If busy, delay and repeat step 2
+ 3. ALL_SEND_CID [CMD2]
+ If timeout, set an error (no cards found)
+ 4. SET_RELATIVE_ADDR [CMD3]
+ 5. SEND_CSD [CMD9]
+ 6. SET_DSR [CMD4] Only call this if (csd.dsr_imp).
+ 7. Set clock frequency (check available in csd.tran_speed)
+ */
+
+static void * mmc_cim_single_card_acq( struct mmc_dev *dev, int first )
+{
+ struct mmc_response_r3 r3;
+ struct mmc_response_r1 r1;
+ struct mmc_slot *slot = dev->slot; /* Must be slot 0 */
+ int retval;
+
+ DEBUG(2,"\n");
+
+ if ( first ) {
+ mmc_simple_cmd(dev, MMC_GO_IDLE_STATE, 0, RESPONSE_NONE);
+ return NULL;
+ }
+
+ switch (dev->request.cmd) {
+ case MMC_GO_IDLE_STATE: /* No response to parse */
+ if ( (dev->sdrive->flags & MMC_SDFLAG_VOLTAGE ))
+ DEBUG(0,": error - current driver doesn't do OCR\n");
+ mmc_simple_cmd(dev, MMC_SEND_OP_COND, dev->sdrive->ocr, RESPONSE_R3);
+ break;
+
+ case MMC_SEND_OP_COND:
+ retval = mmc_unpack_r3(&dev->request, &r3);
+ if ( retval ) {
+ DEBUG(0,": failed SEND_OP_COND error=%d (%s) - could be SD card\n",
+ retval, mmc_result_to_string(retval));
+ return mmc_cim_default_state;
+ }
+
+ DEBUG(2,": read ocr value = 0x%08x\n", r3.ocr);
+ if (!(r3.ocr & MMC_CARD_BUSY)) {
+ mmc_simple_cmd(dev, MMC_SEND_OP_COND, dev->sdrive->ocr, RESPONSE_R3);
+ }
+ else {
+ slot->state = CARD_STATE_READY;
+ mmc_simple_cmd(dev, MMC_ALL_SEND_CID, 0, RESPONSE_R2_CID);
+ }
+ break;
+
+ case MMC_ALL_SEND_CID:
+ retval = mmc_unpack_cid( &dev->request, &slot->cid );
+ if ( retval ) {
+ DEBUG(0,": unable to ALL_SEND_CID error=%d (%s)\n",
+ retval, mmc_result_to_string(retval));
+ return mmc_cim_default_state;
+ }
+ slot->state = CARD_STATE_IDENT;
+ mmc_simple_cmd(dev, MMC_SET_RELATIVE_ADDR, ID_TO_RCA(slot->id) << 16, RESPONSE_R1);
+ break;
+
+ case MMC_SET_RELATIVE_ADDR:
+ retval = mmc_unpack_r1(&dev->request,&r1,slot->state);
+ if ( retval ) {
+ DEBUG(0, ": unable to SET_RELATIVE_ADDR error=%d (%s)\n",
+ retval, mmc_result_to_string(retval));
+ return mmc_cim_default_state;
+ }
+ slot->state = CARD_STATE_STBY;
+ mmc_simple_cmd(dev, MMC_SEND_CSD, ID_TO_RCA(slot->id) << 16, RESPONSE_R2_CSD);
+ break;
+
+ case MMC_SEND_CSD:
+ retval = mmc_unpack_csd(&dev->request, &slot->csd);
+ if ( retval ) {
+ DEBUG(0, ": unable to SEND_CSD error=%d (%s)\n",
+ retval, mmc_result_to_string(retval));
+ return mmc_cim_default_state;
+ }
+ if ( slot->csd.dsr_imp ) {
+ DEBUG(0, ": driver doesn't support setting DSR\n");
+ // mmc_simple_cmd(dev, MMC_SET_DSR, 0, RESPONSE_NONE);
+ }
+ mmc_configure_card( dev, 0 );
+ return mmc_cim_default_state;
+
+ default:
+ DEBUG(0, ": error! Illegal last cmd %d\n", dev->request.cmd);
+ return mmc_cim_default_state;
+ }
+ return NULL;
+}
+
+/*
+ CIM_INIT_STACK (frequency at 400 kHz)
+
+ 1. GO_IDLE_STATE (CMD0)
+ 2. Do CIM_SINGLE_CARD_ACQ
+*/
+
+static void * mmc_cim_init_stack( struct mmc_dev *dev, int first )
+{
+ DEBUG(2,"\n");
+
+ if ( first ) {
+ mmc_simple_cmd(dev, MMC_CIM_RESET, 0, RESPONSE_NONE);
+ return NULL;
+ }
+
+ switch (dev->request.cmd) {
+ case MMC_CIM_RESET:
+ if ( dev->slot[0].state == CARD_STATE_EMPTY )
+ return mmc_cim_default_state;
+
+ dev->slot[0].state = CARD_STATE_IDLE;
+ return mmc_cim_single_card_acq;
+
+ default:
+ DEBUG(0,": invalid state %d\n", dev->request.cmd);
+ break;
+ }
+
+ return NULL;
+}
+
+/******************************************************************
+ * Default state - start here
+ ******************************************************************/
+
+static void * mmc_cim_default_state( struct mmc_dev *dev, int first )
+{
+ DEBUG(2,"\n");
+
+ mmc_check_eject(dev);
+
+ if (mmc_check_insert(dev))
+ return mmc_cim_init_stack;
+ else if (mmc_has_valid_request(dev))
+ return mmc_cim_handle_request;
+
+ return NULL;
+}
+
+
+/******************************************************************
+ * State function handler
+ ******************************************************************/
+
+typedef void *(*state_func_t)(struct mmc_dev *, int);
+static state_func_t g_single_card = &mmc_cim_default_state;
+
+void mmc_protocol_single_card( struct mmc_dev *dev, int state_flags )
+{
+ state_func_t sf;
+
+ sf = g_single_card(dev,0);
+ while ( sf ) {
+ g_single_card = sf;
+ sf = g_single_card(dev,1);
+ }
+}
diff -ruwN -X dontdiff linux-2.4.19/drivers/mmc/mmc_protocol.h linux-2.4.19-mmc1/drivers/mmc/mmc_protocol.h
--- linux-2.4.19/drivers/mmc/mmc_protocol.h Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-mmc1/drivers/mmc/mmc_protocol.h Fri Aug 9 16:07:50 2002
@@ -0,0 +1,266 @@
+/*
+ * Header for MultiMediaCard (MMC)
+ *
+ * Copyright (c) 2002 Hewlett-Packard Company
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
+ *
+ * Based strongly on code by:
+ *
+ * Author: Yong-iL Joh <tolkien@mizi.com>
+ * Date : $Date: 2002/06/13 21:06:08 $
+ *
+ * Author: Andrew Christian
+ * 15 May 2002
+ */
+
+#ifndef MMC_MMC_PROTOCOL_H
+#define MMC_MMC_PROTOCOL_H
+
+#include <linux/types.h>
+
+/* Standard MMC clock speeds */
+#define MMC_CLOCK_SLOW 400000 /* 400 kHz for initial setup */
+#define MMC_CLOCK_FAST 20000000 /* 20 MHz for maximum for normal operation */
+
+/* Extra MMC commands for state control */
+/* Use negative numbers to disambiguate */
+#define MMC_CIM_RESET -1
+
+/* Standard MMC commands (3.1) type argument response */
+ /* class 1 */
+#define MMC_GO_IDLE_STATE 0 /* bc */
+#define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */
+#define MMC_ALL_SEND_CID 2 /* bcr R2 */
+#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */
+#define MMC_SET_DSR 4 /* bc [31:16] RCA */
+#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */
+#define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */
+#define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */
+#define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */
+#define MMC_STOP_TRANSMISSION 12 /* ac R1b */
+#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */
+#define MMC_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */
+
+ /* class 2 */
+#define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */
+#define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */
+#define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */
+
+ /* class 3 */
+#define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */
+
+ /* class 4 */
+#define MMC_SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */
+#define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */
+#define MMC_WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */
+#define MMC_PROGRAM_CID 26 /* adtc R1 */
+#define MMC_PROGRAM_CSD 27 /* adtc R1 */
+
+ /* class 6 */
+#define MMC_SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */
+#define MMC_CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */
+#define MMC_SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */
+
+ /* class 5 */
+#define MMC_ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */
+#define MMC_ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */
+#define MMC_ERASE 37 /* ac R1b */
+
+ /* class 9 */
+#define MMC_FAST_IO 39 /* ac <Complex> R4 */
+#define MMC_GO_IRQ_STATE 40 /* bcr R5 */
+
+ /* class 7 */
+#define MMC_LOCK_UNLOCK 42 /* adtc R1b */
+
+ /* class 8 */
+#define MMC_APP_CMD 55 /* ac [31:16] RCA R1 */
+#define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1b */
+
+/* Don't change the order of these; they are used in dispatch tables */
+enum mmc_rsp_t {
+ RESPONSE_NONE = 0,
+ RESPONSE_R1 = 1,
+ RESPONSE_R1B = 2,
+ RESPONSE_R2_CID = 3,
+ RESPONSE_R2_CSD = 4,
+ RESPONSE_R3 = 5,
+ RESPONSE_R4 = 6,
+ RESPONSE_R5 = 7
+};
+
+
+/*
+ MMC status in R1
+ Type
+ e : error bit
+ s : status bit
+ r : detected and set for the actual command response
+ x : detected and set during command execution. the host must poll
+ the card by sending status command in order to read these bits.
+ Clear condition
+ a : according to the card state
+ b : always related to the previous command. Reception of
+ a valid command will clear it (with a delay of one command)
+ c : clear by read
+ */
+
+#define R1_OUT_OF_RANGE (1 << 31) /* er, c */
+#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */
+#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */
+#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */
+#define R1_ERASE_PARAM (1 << 27) /* ex, c */
+#define R1_WP_VIOLATION (1 << 26) /* erx, c */
+#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */
+#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */
+#define R1_COM_CRC_ERROR (1 << 23) /* er, b */
+#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */
+#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */
+#define R1_CC_ERROR (1 << 20) /* erx, c */
+#define R1_ERROR (1 << 19) /* erx, c */
+#define R1_UNDERRUN (1 << 18) /* ex, c */
+#define R1_OVERRUN (1 << 17) /* ex, c */
+#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */
+#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */
+#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */
+#define R1_ERASE_RESET (1 << 13) /* sr, c */
+#define R1_STATUS(x) (x & 0xFFFFE000)
+#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */
+#define R1_READY_FOR_DATA (1 << 8) /* sx, a */
+#define R1_APP_CMD (1 << 7) /* sr, c */
+
+enum card_state {
+ CARD_STATE_EMPTY = -1,
+ CARD_STATE_IDLE = 0,
+ CARD_STATE_READY = 1,
+ CARD_STATE_IDENT = 2,
+ CARD_STATE_STBY = 3,
+ CARD_STATE_TRAN = 4,
+ CARD_STATE_DATA = 5,
+ CARD_STATE_RCV = 6,
+ CARD_STATE_PRG = 7,
+ CARD_STATE_DIS = 8,
+};
+
+/* These are unpacked versions of the actual responses */
+
+struct mmc_response_r1 {
+ u8 cmd;
+ u32 status;
+};
+
+struct mmc_cid {
+ u8 mid;
+ u16 oid;
+ u8 pnm[7]; // Product name (we null-terminate)
+ u8 prv;
+ u32 psn;
+ u8 mdt;
+};
+
+struct mmc_csd {
+ u8 csd_structure;
+ u8 spec_vers;
+ u8 taac;
+ u8 nsac;
+ u8 tran_speed;
+ u16 ccc;
+ u8 read_bl_len;
+ u8 read_bl_partial;
+ u8 write_blk_misalign;
+ u8 read_blk_misalign;
+ u8 dsr_imp;
+ u16 c_size;
+ u8 vdd_r_curr_min;
+ u8 vdd_r_curr_max;
+ u8 vdd_w_curr_min;
+ u8 vdd_w_curr_max;
+ u8 c_size_mult;
+ union {
+ struct { /* MMC system specification version 3.1 */
+ u8 erase_grp_size;
+ u8 erase_grp_mult;
+ } v31;
+ struct { /* MMC system specification version 2.2 */
+ u8 sector_size;
+ u8 erase_grp_size;
+ } v22;
+ } erase;
+ u8 wp_grp_size;
+ u8 wp_grp_enable;
+ u8 default_ecc;
+ u8 r2w_factor;
+ u8 write_bl_len;
+ u8 write_bl_partial;
+ u8 file_format_grp;
+ u8 copy;
+ u8 perm_write_protect;
+ u8 tmp_write_protect;
+ u8 file_format;
+ u8 ecc;
+};
+
+struct mmc_response_r3 {
+ u32 ocr;
+};
+
+#define MMC_VDD_145_150 0x00000001 /* VDD voltage 1.45 - 1.50 */
+#define MMC_VDD_150_155 0x00000002 /* VDD voltage 1.50 - 1.55 */
+#define MMC_VDD_155_160 0x00000004 /* VDD voltage 1.55 - 1.60 */
+#define MMC_VDD_160_165 0x00000008 /* VDD voltage 1.60 - 1.65 */
+#define MMC_VDD_165_170 0x00000010 /* VDD voltage 1.65 - 1.70 */
+#define MMC_VDD_17_18 0x00000020 /* VDD voltage 1.7 - 1.8 */
+#define MMC_VDD_18_19 0x00000040 /* VDD voltage 1.8 - 1.9 */
+#define MMC_VDD_19_20 0x00000080 /* VDD voltage 1.9 - 2.0 */
+#define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */
+#define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */
+#define MMC_VDD_22_23 0x00000400 /* VDD voltage 2.2 ~ 2.3 */
+#define MMC_VDD_23_24 0x00000800 /* VDD voltage 2.3 ~ 2.4 */
+#define MMC_VDD_24_25 0x00001000 /* VDD voltage 2.4 ~ 2.5 */
+#define MMC_VDD_25_26 0x00002000 /* VDD voltage 2.5 ~ 2.6 */
+#define MMC_VDD_26_27 0x00004000 /* VDD voltage 2.6 ~ 2.7 */
+#define MMC_VDD_27_28 0x00008000 /* VDD voltage 2.7 ~ 2.8 */
+#define MMC_VDD_28_29 0x00010000 /* VDD voltage 2.8 ~ 2.9 */
+#define MMC_VDD_29_30 0x00020000 /* VDD voltage 2.9 ~ 3.0 */
+#define MMC_VDD_30_31 0x00040000 /* VDD voltage 3.0 ~ 3.1 */
+#define MMC_VDD_31_32 0x00080000 /* VDD voltage 3.1 ~ 3.2 */
+#define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */
+#define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */
+#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */
+#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */
+#define MMC_CARD_BUSY 0x80000000 /* Card Power up status bit */
+
+
+/* CSD field definitions */
+
+#define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */
+#define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */
+#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 */
+
+#define CSD_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.2 */
+#define CSD_SPEC_VER_1 1 /* Implements system specification 1.4 */
+#define CSD_SPEC_VER_2 2 /* Implements system specification 2.0 - 2.2 */
+#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 */
+
+#endif /* MMC_MMC_PROTOCOL_H */
+
diff -ruwN -X dontdiff linux-2.4.19/include/linux/mmc/mmc_ll.h linux-2.4.19-mmc1/include/linux/mmc/mmc_ll.h
--- linux-2.4.19/include/linux/mmc/mmc_ll.h Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-mmc1/include/linux/mmc/mmc_ll.h Fri Aug 9 16:08:01 2002
@@ -0,0 +1,117 @@
+/*
+ * Header for MultiMediaCard (MMC)
+ *
+ * Copyright (c) 2002 Hewlett-Packard Company
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
+ *
+ * Based strongly on code by:
+ *
+ * Author: Yong-iL Joh <tolkien@mizi.com>
+ * Date : $Date: 2002/06/18 19:07:20 $
+ *
+ * Author: Andrew Christian
+ * 15 May 2002
+ */
+
+#ifndef MMC_MMC_LL_H
+#define MMC_MMC_LL_H
+
+#include <linux/types.h>
+#include <linux/mmc/mmc_protocol.h>
+
+#ifdef __KERNEL__
+
+/* Error codes */
+enum mmc_result_t {
+ MMC_NO_RESPONSE = -1,
+ MMC_NO_ERROR = 0,
+ MMC_ERROR_OUT_OF_RANGE,
+ MMC_ERROR_ADDRESS,
+ MMC_ERROR_BLOCK_LEN,
+ MMC_ERROR_ERASE_SEQ,
+ MMC_ERROR_ERASE_PARAM,
+ MMC_ERROR_WP_VIOLATION,
+ MMC_ERROR_CARD_IS_LOCKED,
+ MMC_ERROR_LOCK_UNLOCK_FAILED,
+ MMC_ERROR_COM_CRC,
+ MMC_ERROR_ILLEGAL_COMMAND,
+ MMC_ERROR_CARD_ECC_FAILED,
+ MMC_ERROR_CC,
+ MMC_ERROR_GENERAL,
+ MMC_ERROR_UNDERRUN,
+ MMC_ERROR_OVERRUN,
+ MMC_ERROR_CID_CSD_OVERWRITE,
+ MMC_ERROR_STATE_MISMATCH,
+ MMC_ERROR_HEADER_MISMATCH,
+ MMC_ERROR_TIMEOUT,
+ MMC_ERROR_CRC,
+ MMC_ERROR_DRIVER_FAILURE,
+};
+
+struct mmc_request {
+ int index; /* Slot index - used for CS lines */
+ int cmd; /* Command to send */
+ u32 arg; /* Argument to send */
+ enum mmc_rsp_t rtype; /* Response type expected */
+
+ /* Data transfer (these may be modified at the low level) */
+ u16 nob; /* Number of blocks to transfer*/
+ u16 block_len; /* Block length */
+ u8 *buffer; /* Data buffer */
+
+ /* Results */
+ u8 response[18]; /* Buffer to store response - CRC is optional */
+ enum mmc_result_t result;
+};
+
+#define MMC_SDFLAG_SPI_MODE (1<<0) /* Can use SPI mode */
+#define MMC_SDFLAG_MMC_MODE (1<<1) /* Can use MMC mode */
+#define MMC_SDFLAG_SD_MODE (1<<2) /* Can use SD mode */
+#define MMC_SDFLAG_VOLTAGE (1<<3) /* Can change voltage range */
+
+struct module;
+
+struct mmc_slot_driver {
+ struct module *owner;
+ char *name;
+ u32 ocr; /* Valid voltage ranges */
+ u32 flags; /* Slot driver flags */
+
+ int (*init)(void);
+ void (*cleanup)(void);
+ int (*is_empty)(int);
+ int (*set_clock)(u32 rate);
+ void (*send_cmd)(struct mmc_request *);
+};
+
+/* Calls made by the hardware-specific slot driver code */
+extern int mmc_register_slot_driver( struct mmc_slot_driver *, int );
+extern void mmc_unregister_slot_driver( struct mmc_slot_driver * );
+extern void mmc_cmd_complete( struct mmc_request * );
+extern void mmc_insert( int );
+extern void mmc_eject( int );
+
+#endif /* #ifdef __KERNEL__ */
+
+#endif /* MMC_MMC_LL_H */
+
diff -ruwN -X dontdiff linux-2.4.19/include/linux/mmc/mmc_protocol.h linux-2.4.19-mmc1/include/linux/mmc/mmc_protocol.h
--- linux-2.4.19/include/linux/mmc/mmc_protocol.h Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-mmc1/include/linux/mmc/mmc_protocol.h Fri Aug 9 16:08:07 2002
@@ -0,0 +1,285 @@
+/*
+ * Header for MultiMediaCard (MMC)
+ *
+ * Copyright (c) 2002 Hewlett-Packard Company
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
+ *
+ * Based strongly on code by:
+ *
+ * Author: Yong-iL Joh <tolkien@mizi.com>
+ * Date : $Date: 2002/06/18 12:37:30 $
+ *
+ * Author: Andrew Christian
+ * 15 May 2002
+ */
+
+#ifndef MMC_MMC_PROTOCOL_H
+#define MMC_MMC_PROTOCOL_H
+
+#include <linux/types.h>
+
+/* Standard MMC clock speeds */
+#define MMC_CLOCK_SLOW 400000 /* 400 kHz for initial setup */
+#define MMC_CLOCK_FAST 20000000 /* 20 MHz for maximum for normal operation */
+
+/* Extra MMC commands for state control */
+/* Use negative numbers to disambiguate */
+#define MMC_CIM_RESET -1
+
+/* Standard MMC commands (3.1) type argument response */
+ /* class 1 */
+#define MMC_GO_IDLE_STATE 0 /* bc */
+#define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */
+#define MMC_ALL_SEND_CID 2 /* bcr R2 */
+#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */
+#define MMC_SET_DSR 4 /* bc [31:16] RCA */
+#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */
+#define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */
+#define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */
+#define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */
+#define MMC_STOP_TRANSMISSION 12 /* ac R1b */
+#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */
+#define MMC_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */
+
+ /* class 2 */
+#define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */
+#define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */
+#define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */
+
+ /* class 3 */
+#define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */
+
+ /* class 4 */
+#define MMC_SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */
+#define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */
+#define MMC_WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */
+#define MMC_PROGRAM_CID 26 /* adtc R1 */
+#define MMC_PROGRAM_CSD 27 /* adtc R1 */
+
+ /* class 6 */
+#define MMC_SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */
+#define MMC_CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */
+#define MMC_SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */
+
+ /* class 5 */
+#define MMC_ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */
+#define MMC_ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */
+#define MMC_ERASE 37 /* ac R1b */
+
+ /* class 9 */
+#define MMC_FAST_IO 39 /* ac <Complex> R4 */
+#define MMC_GO_IRQ_STATE 40 /* bcr R5 */
+
+ /* class 7 */
+#define MMC_LOCK_UNLOCK 42 /* adtc R1b */
+
+ /* class 8 */
+#define MMC_APP_CMD 55 /* ac [31:16] RCA R1 */
+#define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1b */
+
+/* Don't change the order of these; they are used in dispatch tables */
+enum mmc_rsp_t {
+ RESPONSE_NONE = 0,
+ RESPONSE_R1 = 1,
+ RESPONSE_R1B = 2,
+ RESPONSE_R2_CID = 3,
+ RESPONSE_R2_CSD = 4,
+ RESPONSE_R3 = 5,
+ RESPONSE_R4 = 6,
+ RESPONSE_R5 = 7
+};
+
+
+/*
+ MMC status in R1
+ Type
+ e : error bit
+ s : status bit
+ r : detected and set for the actual command response
+ x : detected and set during command execution. the host must poll
+ the card by sending status command in order to read these bits.
+ Clear condition
+ a : according to the card state
+ b : always related to the previous command. Reception of
+ a valid command will clear it (with a delay of one command)
+ c : clear by read
+ */
+
+#define R1_OUT_OF_RANGE (1 << 31) /* er, c */
+#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */
+#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */
+#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */
+#define R1_ERASE_PARAM (1 << 27) /* ex, c */
+#define R1_WP_VIOLATION (1 << 26) /* erx, c */
+#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */
+#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */
+#define R1_COM_CRC_ERROR (1 << 23) /* er, b */
+#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */
+#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */
+#define R1_CC_ERROR (1 << 20) /* erx, c */
+#define R1_ERROR (1 << 19) /* erx, c */
+#define R1_UNDERRUN (1 << 18) /* ex, c */
+#define R1_OVERRUN (1 << 17) /* ex, c */
+#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */
+#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */
+#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */
+#define R1_ERASE_RESET (1 << 13) /* sr, c */
+#define R1_STATUS(x) (x & 0xFFFFE000)
+#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */
+#define R1_READY_FOR_DATA (1 << 8) /* sx, a */
+#define R1_APP_CMD (1 << 7) /* sr, c */
+
+enum card_state {
+ CARD_STATE_EMPTY = -1,
+ CARD_STATE_IDLE = 0,
+ CARD_STATE_READY = 1,
+ CARD_STATE_IDENT = 2,
+ CARD_STATE_STBY = 3,
+ CARD_STATE_TRAN = 4,
+ CARD_STATE_DATA = 5,
+ CARD_STATE_RCV = 6,
+ CARD_STATE_PRG = 7,
+ CARD_STATE_DIS = 8,
+};
+
+/* These are unpacked versions of the actual responses */
+
+struct mmc_response_r1 {
+ u8 cmd;
+ u32 status;
+};
+
+struct mmc_cid {
+ u8 mid;
+ u16 oid;
+ u8 pnm[7]; // Product name (we null-terminate)
+ u8 prv;
+ u32 psn;
+ u8 mdt;
+};
+
+struct mmc_csd {
+ u8 csd_structure;
+ u8 spec_vers;
+ u8 taac;
+ u8 nsac;
+ u8 tran_speed;
+ u16 ccc;
+ u8 read_bl_len;
+ u8 read_bl_partial;
+ u8 write_blk_misalign;
+ u8 read_blk_misalign;
+ u8 dsr_imp;
+ u16 c_size;
+ u8 vdd_r_curr_min;
+ u8 vdd_r_curr_max;
+ u8 vdd_w_curr_min;
+ u8 vdd_w_curr_max;
+ u8 c_size_mult;
+ union {
+ struct { /* MMC system specification version 3.1 */
+ u8 erase_grp_size;
+ u8 erase_grp_mult;
+ } v31;
+ struct { /* MMC system specification version 2.2 */
+ u8 sector_size;
+ u8 erase_grp_size;
+ } v22;
+ } erase;
+ u8 wp_grp_size;
+ u8 wp_grp_enable;
+ u8 default_ecc;
+ u8 r2w_factor;
+ u8 write_bl_len;
+ u8 write_bl_partial;
+ u8 file_format_grp;
+ u8 copy;
+ u8 perm_write_protect;
+ u8 tmp_write_protect;
+ u8 file_format;
+ u8 ecc;
+};
+
+struct mmc_response_r3 {
+ u32 ocr;
+};
+
+#define MMC_VDD_145_150 0x00000001 /* VDD voltage 1.45 - 1.50 */
+#define MMC_VDD_150_155 0x00000002 /* VDD voltage 1.50 - 1.55 */
+#define MMC_VDD_155_160 0x00000004 /* VDD voltage 1.55 - 1.60 */
+#define MMC_VDD_160_165 0x00000008 /* VDD voltage 1.60 - 1.65 */
+#define MMC_VDD_165_170 0x00000010 /* VDD voltage 1.65 - 1.70 */
+#define MMC_VDD_17_18 0x00000020 /* VDD voltage 1.7 - 1.8 */
+#define MMC_VDD_18_19 0x00000040 /* VDD voltage 1.8 - 1.9 */
+#define MMC_VDD_19_20 0x00000080 /* VDD voltage 1.9 - 2.0 */
+#define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */
+#define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */
+#define MMC_VDD_22_23 0x00000400 /* VDD voltage 2.2 ~ 2.3 */
+#define MMC_VDD_23_24 0x00000800 /* VDD voltage 2.3 ~ 2.4 */
+#define MMC_VDD_24_25 0x00001000 /* VDD voltage 2.4 ~ 2.5 */
+#define MMC_VDD_25_26 0x00002000 /* VDD voltage 2.5 ~ 2.6 */
+#define MMC_VDD_26_27 0x00004000 /* VDD voltage 2.6 ~ 2.7 */
+#define MMC_VDD_27_28 0x00008000 /* VDD voltage 2.7 ~ 2.8 */
+#define MMC_VDD_28_29 0x00010000 /* VDD voltage 2.8 ~ 2.9 */
+#define MMC_VDD_29_30 0x00020000 /* VDD voltage 2.9 ~ 3.0 */
+#define MMC_VDD_30_31 0x00040000 /* VDD voltage 3.0 ~ 3.1 */
+#define MMC_VDD_31_32 0x00080000 /* VDD voltage 3.1 ~ 3.2 */
+#define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */
+#define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */
+#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */
+#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */
+#define MMC_CARD_BUSY 0x80000000 /* Card Power up status bit */
+
+
+/* CSD field definitions */
+
+#define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */
+#define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */
+#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 */
+
+#define CSD_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.2 */
+#define CSD_SPEC_VER_1 1 /* Implements system specification 1.4 */
+#define CSD_SPEC_VER_2 2 /* Implements system specification 2.0 - 2.2 */
+#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 */
+
+
+
+#ifdef CONFIG_MMC_DEBUG
+#ifndef CONFIG_MMC_DEBUG_VERBOSE
+#define CONFIG_MMC_DEBUG_VERBOSE 3
+#endif
+extern int g_mmc_debug;
+#define DEBUG(n, args...) \
+ if (n <= g_mmc_debug) { \
+ printk(KERN_INFO __FUNCTION__ args); \
+ }
+#define START_DEBUG(n) do { if (n <= g_mmc_debug)
+#define END_DEBUG } while (0)
+#else
+#define DEBUG(n, args...)
+#define START_DEBUG(n)
+#define END_DEBUG
+#endif /* CONFIG_MMC_DEBUG */
+
+#endif /* MMC_MMC_PROTOCOL_H */
+
diff -ruwN -X dontdiff linux-2.4.19/include/linux/sysctl.h linux-2.4.19-mmc1/include/linux/sysctl.h
--- linux-2.4.19/include/linux/sysctl.h Fri Aug 2 20:39:46 2002
+++ linux-2.4.19-mmc1/include/linux/sysctl.h Fri Aug 9 15:54:57 2002
@@ -69,7 +69,8 @@
 /* CTL_BUS names: */
 enum
 {
- BUS_ISA=1 /* ISA */
+ BUS_ISA=1, /* ISA */
+ BUS_MMC=2 /* MultiMedia Card */
 };
 
 /* CTL_KERN names: */
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Thu Aug 15 2002 - 22:00:20 EST