shame on me, I forget to added the new patches
authorHenning Heinold <heinold@inf.fu-berlin.de>
Fri, 6 Jul 2007 20:42:53 +0000 (20:42 +0000)
committerHenning Heinold <heinold@inf.fu-berlin.de>
Fri, 6 Jul 2007 20:42:53 +0000 (20:42 +0000)
here now they are

packages/linux/linux/simpad/linux-2.6.21-SIMpad-GPIO-MMC-mod.patch [new file with mode: 0644]
packages/linux/linux/simpad/linux-2.6.21-SIMpad-battery-old-way-but-also-with-sysfs.patch [new file with mode: 0644]
packages/linux/linux/simpad/linux-2.6.21-SIMpad-net-shared-irq.patch [new file with mode: 0644]
packages/linux/linux/simpad/linux-2.6.21-SIMpad-pcmcia.patch [new file with mode: 0644]
packages/linux/linux/simpad/linux-2.6.21-SIMpad-serial-gpio_keys-and-cs3-ro.patch [new file with mode: 0644]
packages/linux/linux/simpad/linux-2.6.21-SIMpad-ucb1x00-ts-supend-and-accuracy.patch [new file with mode: 0644]
packages/linux/linux/simpad/linux-2.6.21-SIMpad-usb-gadget.patch [new file with mode: 0644]

diff --git a/packages/linux/linux/simpad/linux-2.6.21-SIMpad-GPIO-MMC-mod.patch b/packages/linux/linux/simpad/linux-2.6.21-SIMpad-GPIO-MMC-mod.patch
new file mode 100644 (file)
index 0000000..22f220d
--- /dev/null
@@ -0,0 +1,1650 @@
+diff -uNr linux-2.6.21.vanilla/drivers/mmc/Kconfig linux-2.6.21/drivers/mmc/Kconfig
+--- linux-2.6.21.vanilla/drivers/mmc/Kconfig   2007-05-30 18:00:30.000000000 +0200
++++ linux-2.6.21/drivers/mmc/Kconfig   2007-05-30 18:26:18.000000000 +0200
+@@ -4,6 +4,12 @@
+ menu "MMC/SD Card support"
++config MMC_SPI_BLOCK
++      tristate "MMC support for SIMpad over GPIO"
++      help
++        Say Y here to enable MMC block device over GPIO
++        if you have done the MMC-Mod. For Module say M.
++
+ config MMC
+       tristate "MMC support"
+       help
+diff -uNr linux-2.6.21.vanilla/drivers/mmc/Makefile linux-2.6.21/drivers/mmc/Makefile
+--- linux-2.6.21.vanilla/drivers/mmc/Makefile  2007-05-30 18:00:30.000000000 +0200
++++ linux-2.6.21/drivers/mmc/Makefile  2007-05-30 18:26:18.000000000 +0200
+@@ -2,6 +2,8 @@
+ # Makefile for the kernel mmc device drivers.
+ #
++obj-$(CONFIG_MMC_SPI_BLOCK)   += mmc_spi_block.o
++
+ #
+ # Core
+ #
+diff -uNr linux-2.6.21.vanilla/drivers/mmc/mmc_spi_block.c linux-2.6.21/drivers/mmc/mmc_spi_block.c
+--- linux-2.6.21.vanilla/drivers/mmc/mmc_spi_block.c   1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.21/drivers/mmc/mmc_spi_block.c   2007-05-30 18:30:58.000000000 +0200
+@@ -0,0 +1,1618 @@
++/*
++ * Copyright (c) Cl�ent Ballabriga, 2005 - GPL
++ * Copyright (c) Guylhem Aznar, 2005 - GPL
++ *
++ * Please check http://externe.net/zaurus/simpad-bluetooth reference design first.
++ *
++ * Based on Madsuk/Rohde work on a MMC driver for the WRT54G.
++ *
++ * This is an ugly hack of a driver. I am surprised if it ever works!
++ * So please use a real driver or contribute one to the 2.4/2.6 mmc framework
++ *
++ * mrdata: ported to 2.6
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++
++#include <linux/sched.h>
++#include <linux/kernel.h>
++#include <linux/fs.h>
++#include <linux/errno.h>
++#include <linux/hdreg.h>
++#include <linux/kdev_t.h>
++#include <linux/blkdev.h>
++#include <linux/spinlock.h>
++#include <linux/time.h>
++#include <linux/delay.h>
++#include <linux/timer.h>
++
++#include <linux/platform_device.h>
++
++#include <asm/hardware.h>
++#include <asm/arch/simpad.h>
++#include <asm/arch/gpio.h>
++
++static int major = 121;
++
++#define DEVICE_NAME "mmc_spi"
++
++static int hd_sizes[1<<6];
++static int hd_blocksizes[1<<6];
++static int hd_hardsectsizes[1<<6];
++static int hd_maxsect[1<<6];
++static struct hd_struct hd[1<<6];
++
++static struct gendisk *mmc_disk;
++
++static struct platform_device *mmc_dev; /* the one and only instance */
++
++static spinlock_t mmc_spi_lock;
++
++/*
++ * *******************************************************************
++ *
++ *                This is the only configurable part.
++ *
++ * *******************************************************************
++ *
++ */
++
++// #define DEBUG 1
++// #define DEBUG_HD 1
++// #define CHECK_MEDIA_CHANGE  // for developement ONLY, not working yet
++
++/* Let that include where it is or compilation fails on INIT_REQUEST/CURRENT */
++
++
++/*
++ * If you are using different GPIOs in your hardware hack, you must
++ * first make sure they are unused for other functions and then
++ * configure them here.
++ *
++ * On the simpad I use spare pins from the UART1 (internal serial port -> DECT 20-polig):
++ * 
++ *   Funktion  PIN  ##  Original direction  GPIO  ##  SPI function                New direction  SD/MMC   
++ * - DCD       PIN  08  (in)                GPIO  23  DO  - new name: DI -> MISO  (in)           PIN  7  Data Out
++ * - DTR       PIN  11  (out)               GPIO  07  CS                          (out)          PIN  1  Chip Select
++ * - RI        PIN  14  (in)                GPIO  19  CLK                         (out)          PIN  5  Clock
++ * - DSR       PIN  16  (in)                GPIO  06  DI  - new name: DO -> MOSI  (out)          PIN  2  Data In
++ * 
++ *
++ * SPI: MISO = Master In / Slave OUT   MOSI = Master Out / Slave In
++ *
++ * Don't worry about in/out original function - the GPIOs will be
++ * reprogrammed.
++ */
++
++#define GPIO_SD_DI   23
++#define GPIO_SD_CS   7
++#define GPIO_SD_CLK  19
++#define GPIO_SD_DO   6
++
++// #define FAST_GPIO_SD_DI            GPIO_GPIO23
++// #define FAST_GPIO_SD_CS            GPIO_GPIO7
++// #define FAST_GPIO_SD_CLK           GPIO_GPIO19
++// #define FAST_GPIO_SD_DO            GPIO_GPIO6
++
++#define FAST_GPIO_SD_DI   GPIO_UART1_DCD
++#define FAST_GPIO_SD_CS   GPIO_UART1_DTR
++#define FAST_GPIO_SD_CLK  GPIO_UART1_RI
++#define FAST_GPIO_SD_DO   GPIO_UART1_DSR
++
++/*
++ * *******************************************************************
++ *
++ *               Do not change anything below !
++ *
++ * *******************************************************************
++ *
++ */
++
++/* GPIO states */
++#define LOW 0
++#define HIGH 1
++
++#define INPUT 0
++#define OUTPUT 1
++
++#define PRESENT 1
++#define ABSENT 0
++
++typedef unsigned int   uint32;
++typedef unsigned long  u32_t;
++typedef unsigned short u16_t;
++typedef unsigned char  u8_t;
++
++static struct timer_list mmc_timer;
++
++// static struct timeval s_zeit, e_zeit;
++
++/* start with no card */
++static int mmc_media_detect = 0;
++static int mmc_media_changed = 1;
++
++
++/////////////////////
++// prototypes
++static int mmc_open(struct inode *inode, struct file *filp);
++static int mmc_release(struct inode *inode, struct file *filp);
++static int mmc_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
++static void mmc_request(request_queue_t *q);
++
++
++/*
++ * *******************************************************************
++ *
++ *             Begin GPIO hardware access functions.
++ *
++ * *******************************************************************
++ *
++ */
++
++#define gpio_read(a)          ((GPLR & a) ? 1 : 0)
++#define gpio_write_high(a)    GPSR = a
++#define gpio_write_low(a)     GPCR = a
++
++/* set MMC_Chip_Select to HIGH (MMC/SD-Card inaktiv) */
++#define MMC_Disable() gpio_write_high( FAST_GPIO_SD_CS)
++
++/* set MMC_Chip_Select to LOW (MMC/SD-Card aktiv) */
++#define MMC_Enable() gpio_write_low( FAST_GPIO_SD_CS)
++
++/*
++ * *******************************************************************
++ *
++ *             Begin SPI hardware access functions.
++ *
++ * *******************************************************************
++ *
++ */
++static int mmc_spi_media_detect(void)
++{
++// FIXME: add card detection/test by SPI
++
++    return 1;
++}
++
++static int mmc_spi_hardware_init(void)
++{
++      printk("\nmmc: GPIO init\n");
++
++      /* cut existing functions */
++      gpio_set_alternative_function(GPIO_SD_CLK, 0);
++      gpio_set_alternative_function(GPIO_SD_DI, 0);
++      gpio_set_alternative_function(GPIO_SD_DO, 0);
++      gpio_set_alternative_function(GPIO_SD_CS, 0);
++
++      /* remap directions and set state of spi pins */
++      gpio_direction_output(GPIO_SD_CLK, 0);
++      gpio_direction_input(GPIO_SD_DI);       
++      gpio_direction_output(GPIO_SD_DO, 0);
++      gpio_direction_output(GPIO_SD_CS, 0);
++
++      printk("mmc: initialising MMC\n");
++
++      /* Start */
++      MMC_Disable();
++      gpio_write_low( FAST_GPIO_SD_CLK);
++      gpio_write_high( FAST_GPIO_SD_DO);
++      return 0;
++}
++
++/* return what has been read, write the parameter */
++/* Clockrate round about 1,2 MHz                  */
++
++static unsigned char mmc_spi_readwrite(unsigned char data_out)
++{
++    unsigned char i;
++    unsigned char result = 0;
++
++    for(i = 0x80 ; i != 0 ; i >>= 1)
++    {
++        if (data_out & i)
++        {
++            gpio_write_high( FAST_GPIO_SD_DO);
++        }
++        else
++        {
++            gpio_write_low( FAST_GPIO_SD_DO);
++        }
++
++        gpio_write_high( FAST_GPIO_SD_CLK);
++      
++        if (gpio_read( FAST_GPIO_SD_DI) == 1)
++        {
++            result |= i;
++        }
++
++        gpio_write_low( FAST_GPIO_SD_CLK);
++      
++    }
++
++    gpio_write_high( FAST_GPIO_SD_DO);
++
++    return (result);
++}
++
++/* return what has been read, write the parameter */
++/* Clockrate round 200 kHz                        */
++ 
++static unsigned char mmc_spi_readwrite_slow(unsigned char data_out)
++{
++    unsigned char i;
++    unsigned char result = 0;
++
++    for(i = 0x80 ; i != 0 ; i >>= 1)
++    { 
++        if (data_out & i)
++        {
++            gpio_write_high( FAST_GPIO_SD_DO);
++        }
++        else
++        {
++            gpio_write_low( FAST_GPIO_SD_DO);
++        }
++
++        udelay(10);
++
++        gpio_write_high( FAST_GPIO_SD_CLK);
++
++        udelay(10);
++
++        if (gpio_read( FAST_GPIO_SD_DI) == 1)
++        {
++            result |= i;
++        }
++
++        udelay(10);
++      
++        gpio_write_low( FAST_GPIO_SD_CLK);
++
++        udelay(10);
++      
++    }
++
++    gpio_write_high( FAST_GPIO_SD_DO);
++
++    udelay(10);
++
++    // printk("Send Byte = 0x%2X   Receive Byte = 0x%2X \n", data_out, result);
++
++    return (result);
++}
++
++/* return what has been read */
++
++static unsigned char mmc_spi_read_only(void)
++{
++    unsigned char i;
++    unsigned char result = 0;
++
++    for(i = 0x80 ; i != 0 ; i >>= 1)
++    {
++
++        gpio_write_high( FAST_GPIO_SD_CLK);
++      
++        if (gpio_read( FAST_GPIO_SD_DI) == 1)
++        {
++            result |= i;
++        }
++
++        gpio_write_low( FAST_GPIO_SD_CLK);
++      
++    }
++
++    return (result);
++}
++
++/* write the parameter */
++/* Clockrate round about 3,6 MHz                  */
++
++static unsigned char mmc_spi_write_only(unsigned char data_out)
++{
++    unsigned char i;
++    unsigned char result = 0;
++
++    for(i = 0x80 ; i != 0 ; i >>= 1)
++    {
++    
++        if (data_out & i)
++        {
++            gpio_write_high( FAST_GPIO_SD_DO);
++        }
++        else
++        {
++            gpio_write_low( FAST_GPIO_SD_DO);
++        }
++
++        gpio_write_high( FAST_GPIO_SD_CLK);
++      
++        gpio_write_low( FAST_GPIO_SD_CLK);
++      
++    }
++
++    gpio_write_high( FAST_GPIO_SD_DO);
++
++    return (result);
++}
++
++
++/**
++ * this function was contributed by: rcichielo from openwrt forums
++ *
++ * Comments added by Marc DENTY on 2007-03-20
++ *
++ * Sequence to read a card's "CID" bytes (name, serial number etc)
++ *
++ * Send: 4ah,00h,00h,00h,00h,00h  - CMD10, no args, null CRC
++ * Read: xx                       - NCR Time
++ * Read: xx                       - Command Response (Should be 00h)
++ * Read: until FEh is received    - Wait for Data token
++ * Read: yy  * 16                 - Get 16 bytes from CID
++ * Read: zz                       - Read CRC lo byte
++ * Read: zz                       - Read CRC hi byte
++ *
++ * Useful locations in the returned data packet:
++ *
++ * 03h-08h Manufacturers's name in ascii
++ * 0ah-0dh Card's 32 bit serial number 
++ */
++/**
++ * Comments added by Cyril CATTIAUX on 2007-03-21
++ *
++ * CID format specification (from Sandisk SD Product Manual v1.9)
++ *
++ * cid[00   ] Manufacturer ID (unsigned byte)
++ * cid[01-02] OEM/Application ID (ASCII)
++ * cid[03-07] Product Name (ASCII)
++ * cid[08   ] Product Revistion (BCD coded number)
++ * cid[09-12] Serial Number (32-bit unsigned int)
++ * cid[13-14] Reserved(bit 12->15) - Manufacture Date(bit 0->11)
++ * cid[15   ] CRC7(bit 1->7) - Not used, allways 1 (bit 0)
++*/
++static int mmc_read_cid(unsigned char *cid)
++{
++      unsigned char result = 0;
++        int i;
++
++        MMC_Enable();
++      
++      /* wait */
++      for (i = 0; i < 4; i++)
++      {
++              result=mmc_spi_readwrite(0xff);
++      }
++
++      /* issue CID (card identification data) read request */
++      mmc_spi_readwrite(0xff);
++      mmc_spi_readwrite(0x40 | 10);
++      mmc_spi_readwrite(0x00);
++      mmc_spi_readwrite(0x00);
++      mmc_spi_readwrite(0x00);
++      mmc_spi_readwrite(0x00);
++      mmc_spi_readwrite(0x95);
++      
++      for (i = 0; i < 8; i++)
++      {
++              result=mmc_spi_readwrite(0xff);
++
++              if(result == 0x00)
++                      break;
++      }
++
++      if (result != 0x00) {
++              MMC_Disable();
++              mmc_spi_readwrite(0xff);
++              return(1);
++      }
++
++      for (i = 0; i < 8; i++) {
++              result = mmc_spi_readwrite(0xff);
++              if (result == 0xfe) break;
++      }
++
++      if (result != 0xfe) {
++              MMC_Disable();
++              mmc_spi_readwrite(0xff);
++              return(2);
++      }
++
++      for (i = 0; i < 16; i++) {
++              result = mmc_spi_readwrite(0xff);
++              cid[i] = result;
++      }
++      
++      mmc_spi_readwrite(0xff);
++      mmc_spi_readwrite(0xff);
++      
++      MMC_Disable();
++      mmc_spi_readwrite(0xff);
++
++      return 0;
++}
++
++
++/**
++ * Comments added by Cyril CATTIAUX on 2007-03-21
++ *
++ * CID format specification (from Sandisk SD Product Manual v1.9)
++ *
++ * cid[00   ] Manufacturer ID (unsigned byte)
++ * cid[01-02] OEM/Application ID (ASCII)
++ * cid[03-07] Product Name (ASCII)
++ * cid[08   ] Product Revision (BCD coded 2 digit number)
++ * cid[09-12] Serial Number (32-bit unsigned int)
++ * cid[13-14] Manufacture Date(bit 0->11) (BCD coded 3 digit number YYM offset from 2000) - Reserved(bit 12->15)
++ * cid[15   ] Not used, allways 1 (bit 0) - CRC7(bit 1->7)
++*/
++static void mmc_show_cid_info(void)
++{
++      int i, result;
++      unsigned short tmps;
++      unsigned char  cid[16];
++      
++      char           manufacturer_id;
++      char           oem_id[3];
++      char           product_name[6];
++      unsigned char  product_revision_h, product_revision_l;
++      unsigned int   product_sn;
++      unsigned short product_date_y;
++      unsigned char  product_date_m;
++
++      result = mmc_read_cid(cid);
++
++      if (result == 0)
++      {
++              printk("mmc_init: MMC/SD Card ID: ");
++              for (i=0; i<16; i++) {
++                      printk("%02X ", cid[i]);
++              }
++              manufacturer_id=cid[0];
++              strncpy(oem_id,       &cid[1], 2);
++              oem_id[2]='\0';
++              strncpy(product_name, &cid[3], 5);
++              product_name[5]='\0';
++              product_revision_h=(cid[8] >> 4) & 0xf;
++              product_revision_l=cid[8] & 0xf;
++              product_sn=(cid[9]<<24) + (cid[10]<<16) + (cid[11]<<8) + cid[12];
++              tmps=((cid[13]<<8) + cid[14]) & 0x0fff;
++              product_date_y=2000 + (((tmps >> 8) & 0xf) * 10) + ((tmps >> 4) & 0xf);
++              product_date_m=tmps & 0xf;
++              
++              printk("\nManufacturer ID   : %02X\n",  manufacturer_id);
++              printk("OEM/Application ID: %s\n",      oem_id);
++              printk("Product name      : %s\n",      product_name);
++              printk("Product revision  : %d.%d\n",   product_revision_h, product_revision_l);
++              printk("Product SN        : %08X\n",    product_sn);
++              printk("Product Date      : %d-%d\n",   product_date_y, product_date_m);
++              
++      } else {
++              printk("mmc_init: impossible to get card indentification info for reason code: %02x", result);
++      }
++}
++
++
++/*
++static int mmc_spi_hw_test(void)
++{
++    unsigned char result, k;
++    
++    unsigned int i, j, t;
++    
++    printk("mmc_spi_hw_test -> \n\n");
++    k = 0x55;
++    for ( i = 0 ; i < 5; i++) {
++
++      printk("\n0x%2X - ", k);
++      for ( j = 0 ; j < 8; j++ ) {
++            do_gettimeofday( &s_zeit );
++          result = mmc_spi_readwrite_slow(k);
++            do_gettimeofday( &e_zeit );
++                  
++          if ( result != k ) {
++              printk("!>ERROR<! Transfer = 0x%2X Receive = 0x%2X Trail = %d \n", k, result, j);
++              // i = 255; j = 1000;
++          }
++          
++            t = (e_zeit.tv_sec-s_zeit.tv_sec)*1000000+(e_zeit.tv_usec-s_zeit.tv_usec);
++            printk("Durchlauf: %i Versuch: %i von 8 -> Laufzeit: 0x%X s\n", i , j, t);
++          udelay(200);
++      }
++      printk("ready  ");
++
++      // k++;
++    }
++    printk("ready  ");
++    printk("\n\n");
++    return (0);
++}
++*/
++      
++/*
++static int mmc_spi_speed_test(void)
++{
++    unsigned int i, j, k, l, t;
++    
++    MMC_Disable();
++    
++    for (k = 1; k < 6; k++)
++    {
++        l = 10000 * k;
++        for (j = 0; j < 5; j++)
++        {
++            do_gettimeofday( &s_zeit );
++            for (i = 0; i < l; i++)
++              mmc_spi_readwrite(0xff);        
++            do_gettimeofday( &e_zeit );
++            t = (e_zeit.tv_sec-s_zeit.tv_sec)*1000000+(e_zeit.tv_usec-s_zeit.tv_usec);
++            printk("mmc_spi_readwrite: Laufzeit %u x : 0x%X \n", l, t);
++        }
++    }
++    
++    for (k = 1; k < 1; k++)
++    {
++        l = 10000 * k;
++        for (j = 0; j < 1; j++)
++        {
++            do_gettimeofday( &s_zeit );
++            for (i = 0; i < l; i++)
++              mmc_spi_readwrite_slow(0xff);   
++            do_gettimeofday( &e_zeit );
++            t = (e_zeit.tv_sec-s_zeit.tv_sec)*1000000+(e_zeit.tv_usec-s_zeit.tv_usec);
++            printk("mmc_spi_readwrite_slow: Laufzeit %u x : 0x%X \n", l, t);
++        }
++    }
++
++    for (k = 1; k < 6; k++)
++    {
++        l = 10000 * k;
++        for (j = 0; j < 5; j++)
++        {
++            do_gettimeofday( &s_zeit );
++            for (i = 0; i < l; i++)
++              mmc_spi_read_only();    
++            do_gettimeofday( &e_zeit );
++            t = (e_zeit.tv_sec-s_zeit.tv_sec)*1000000+(e_zeit.tv_usec-s_zeit.tv_usec);
++            printk("mmc_spi_read_only: Laufzeit %u x : 0x%X \n", l, t);
++        }
++    }
++
++    for (k = 1; k < 6; k++)
++    {
++        l = 10000 * k;
++        for (j = 0; j < 5; j++)
++        {
++            do_gettimeofday( &s_zeit );
++            for (i = 0; i < l; i++)
++              mmc_spi_write_only(0xff);       
++            do_gettimeofday( &e_zeit );
++            t = (e_zeit.tv_sec-s_zeit.tv_sec)*1000000+(e_zeit.tv_usec-s_zeit.tv_usec);
++            printk("mmc_spi_write_only: Laufzeit %u x : 0x%X \n", l, t);
++        }
++    }
++        
++    return (1); 
++      
++}
++*/
++      
++
++static int mmc_spi_card_init(void)
++{
++    unsigned char result = 0;
++    short i, j;
++
++//     unsigned long flags;
++
++    // save_flags(flags);
++    // cli();
++
++/*
++    printk("GPIO_SD_CS dir: %u alt: %u\n", gpio_getdir(&gp, GPIO_SD_CS), gpio_getalt(&gp, GPIO_SD_CS));
++    printk("GPIO_SD_DI dir: %u alt: %u\n", gpio_getdir(&gp, GPIO_SD_DI), gpio_getalt(&gp, GPIO_SD_DI));
++    printk("GPIO_SD_DO dir: %u alt: %u\n", gpio_getdir(&gp, GPIO_SD_DO), gpio_getalt(&gp, GPIO_SD_DO));
++    printk("GPIO_SD_CS dir: %u alt: %u\n", gpio_getdir(&gp, GPIO_SD_CLK), gpio_getalt(&gp, GPIO_SD_CLK));
++*/
++
++    // printk("\nmmc: mmc_spi_hw_test() *START*\n");
++
++    // mmc_spi_hw_test();
++
++    printk("\nmmc: card init 1/2 (CMD0)\n");
++
++    for (j = 0; j < 10; j++)
++    {
++        MMC_Disable();
++      
++        for (i = 0; i < 10; i++)
++          mmc_spi_readwrite_slow(0xff);
++
++        MMC_Enable();
++      
++      mmc_spi_readwrite_slow(0xff);
++      
++        mmc_spi_readwrite_slow(0x40);
++
++        for (i = 0; i < 4; i++) {
++
++          mmc_spi_readwrite_slow(0x00);
++
++      }
++
++        mmc_spi_readwrite_slow(0x95);
++
++        for (i = 0; i < 8; i++) {
++
++          result = mmc_spi_readwrite_slow(0xff);
++
++#ifdef DEBUG_HD           
++            if (result != 0xff) {
++              if (result > 0x1F && result < 0x80)
++                  printk("mmc: resp. (CMD0) Versuch(%d) BYTE: %d  result = 0x%X  Zeichen = %c\n", j, i, result, result);
++                else
++                  printk("mmc: resp. (CMD0) Versuch(%d) BYTE: %d  result = 0x%X\n", j, i, result);
++          }
++#endif
++          if (result == 0x01)
++              break;
++        }
++              
++      if (result == 0x01)
++          break;
++
++        MMC_Disable();
++        mmc_spi_readwrite_slow(0xff);
++          
++      mdelay(60);
++    }
++    
++    if (result != 0x01) {
++
++        printk("mmc: card init 1/2 error: %d (CMD0) failed\n", result);
++      printk(" -> Hint: MMC/SD-Card realy (fully) inserted ?\n");
++      
++      return (1);
++    }
++
++    printk("mmc: card init 1/2 (CMD0) success\n\n");
++
++    mdelay(1);
++
++    printk("mmc: card init 2/2 (CMD1)\n");
++    for (j = 0; j < 10; j++) {
++
++      mmc_spi_readwrite_slow(0xff);                   
++      mmc_spi_readwrite_slow(0x41);
++      for (i = 0; i < 4; i++)
++          mmc_spi_readwrite_slow(0x00);
++      mmc_spi_readwrite_slow(0x95);
++      for (i = 0; i < 8; i++) {
++          result = mmc_spi_readwrite_slow(0xff);
++#ifdef DEBUG_HD
++          // if (result >= 32 && result <= 127)
++          //     printk("mmc: response (CMD1) Versuch(%d) start token BYTE: %d  result = 0x%X  Zeichen = %c\n", j, i, result, result);
++            // else
++          //     printk("mmc: response (CMD1) Versuch(%d) start token BYTE: %d  result = 0x%X\n", j, i, result);
++#endif
++          if (result == 0x00)
++              break;
++      }
++
++      mmc_spi_readwrite_slow(0xff);
++
++      if (result == 0x00) {
++          printk("mmc: card init 2/2 (CMD1) success\n\n");
++
++          mmc_spi_readwrite_slow(0xff);
++          mmc_spi_readwrite_slow(0x4d);
++          mmc_spi_readwrite_slow(0x00);
++          mmc_spi_readwrite_slow(0x00);
++          mmc_spi_readwrite_slow(0x00);
++          mmc_spi_readwrite_slow(0x00);
++          mmc_spi_readwrite_slow(0x95);
++          for (i = 0; i < 6; i++) {
++              result = mmc_spi_readwrite_slow(0xff);
++#ifdef DEBUG_HD
++              // if (result > 31 && result < 128)
++              //     printk("mmc: response (CMD13) Versuch(%d) start token BYTE: %d  result = 0x%X  Zeichen = %c\n", j, i, result, result);
++              // else
++              //     printk("mmc: response (CMD13) Versuch(%d) start token BYTE: %d  result = 0x%X\n", j, i, result);
++#endif
++              // if (result == 0x00)
++              // break;
++          }
++          // mdelay(60);
++          MMC_Disable();
++          mmc_spi_readwrite_slow(0xff);
++          // mmc_spi_readwrite_slow(0xff);
++          // mdelay(10);
++
++          // restore_flags(flags);
++          
++          return (0);
++      }
++        mdelay(60);   
++    }
++    return (2);
++}
++
++
++static int mmc_spi_card_config(void)
++{
++    unsigned char result = 0;
++    short i, j;
++    unsigned char csd[32];
++    unsigned int c_size;
++    unsigned int c_size_mult;
++    unsigned int mult;
++    unsigned int read_bl_len;
++    unsigned int blocknr = 0;
++    unsigned int block_len = 0;
++    unsigned int size = 0;
++    unsigned char rd_buffer[528];
++//    unsigned long flags;
++    
++    MMC_Enable();
++    
++    mmc_spi_readwrite_slow(0xff);
++    result = mmc_spi_readwrite_slow(0x51); 
++    // mmc_spi_readwrite_slow(0x4A);
++    // mmc_spi_readwrite_slow(0x40+0x0D);
++    // mmc_spi_readwrite_slow(0x42);
++    for (i = 0; i < 4; i++)
++      mmc_spi_readwrite_slow(0x00);
++    mmc_spi_readwrite_slow(0x95);
++
++    // printk("mmc: (CMD17) response von 0x51 result = 0x%X\n", result);
++
++    for (i = 0; i < 8; i++) {
++      result = mmc_spi_readwrite_slow(0xff);
++#ifdef DEBUG_HD
++      // printk("mmc: (CMD17) response (start token) result = 0x%X\n", result);
++#endif
++      if (result == 0x00)
++          break;
++    }
++    if (result != 0x00) {
++      MMC_Disable();
++      mmc_spi_readwrite_slow(0xff);
++      // restore_flags(flags);
++      // mmc_spi_readwrite_slow(0xff);
++      return (1);
++    }
++    // restore_flags(flags);
++    for (i = 0; i < 8; i++) {
++      result = mmc_spi_readwrite_slow(0xff);
++      rd_buffer[i] = result;
++#ifdef DEBUG_HD
++        /*
++      if (result >= 32 && result <= 127)
++          printk("mmc: CMD17 response (start token) result = 0x%X  Zeichen = %c\n", result, result);
++        else
++          printk("mmc: CMD17 response (start token) result = 0x%X\n", result);
++      */
++#endif
++      // if (result == 0xfe)
++      //    break;
++    }
++    /*
++    if (result != 0xfe) {
++        MMC_Disable();
++      mmc_spi_readwrite_slow(0xff);
++      mmc_spi_readwrite_slow(0xff);
++      return(1);
++    }
++    */
++
++    for (i = 8; i < 520; i++) {
++      result = mmc_spi_readwrite_slow(0xff);
++      rd_buffer[i] = result;
++    }
++    for (i = 0; i < 2; i++) {
++      result = mmc_spi_readwrite_slow(0xff);
++    }
++    MMC_Disable();
++    mmc_spi_readwrite_slow(0xff);
++    // mmc_spi_readwrite_slow(0xff);
++
++    printk("Buffer - Start\n");
++    
++    for ( i = 0 ; i < 33 ; i++) {
++      printk("\r\n%4X - ", i*16);
++      for ( j = 0 ; j < 16 ; j++) {
++          if ( rd_buffer[i*16+j] < 16)
++              printk("0%X ", rd_buffer[i*16+j]);
++          else
++              printk("%2X ", rd_buffer[i*16+j]);
++      }
++      for ( j = 0 ; j < 16 ; j++) {
++          if ( rd_buffer[i*16+j] < ' ')
++              printk(".");
++          else
++              printk("%c", rd_buffer[i*16+j]);
++      }
++    }
++
++    printk("\nBuffer - Ende\n");
++
++    mmc_show_cid_info();
++    
++    for(j = 0 ; j < 1; j++) {
++    MMC_Enable();
++
++    // mdelay(1);
++    
++    // save_flags(flags);
++    // cli();
++    mmc_spi_readwrite_slow(0xff);
++    mmc_spi_readwrite_slow(0x49); 
++    // mmc_spi_readwrite_slow(0x4A);
++    // mmc_spi_readwrite_slow(0x40+0x0D);
++    // mmc_spi_readwrite_slow(0x42);
++    for (i = 0; i < 4; i++)
++      mmc_spi_readwrite_slow(0x00);
++    mmc_spi_readwrite_slow(0x95);
++    for (i = 0; i < 8; i++) {
++      result = mmc_spi_readwrite_slow(0xff);
++#ifdef DEBUG_HD
++      // printk("mmc: (CMD9) response (start token) result = 0x%X\n", result);
++#endif
++      if (result == 0x00)
++          break;
++    }
++    // restore_flags(flags);
++    if (result != 0x00) {
++      MMC_Disable();
++      mmc_spi_readwrite_slow(0xff);
++      // mmc_spi_readwrite_slow(0xff);
++      return (1);
++    }
++    for (i = 0; i < 22; i++) {
++      result = mmc_spi_readwrite_slow(0xff);
++#ifdef DEBUG_HD
++      if (result >= 32 && result <= 127)
++          printk("mmc: response (start token) result = 0x%X  Zeichen = %c\n", result, result);
++        else
++          printk("mmc: response (start token) result = 0x%X\n", result);
++#endif
++      if (result == 0xfe)
++          break;
++    }
++    if (result == 0xfe)
++      break;
++        
++    if (result != 0xfe) {
++        MMC_Disable();
++      mmc_spi_readwrite_slow(0xff);
++      // mmc_spi_readwrite_slow(0xff);
++    }
++    mdelay(60);
++    } 
++    
++    if (result != 0xfe) {
++      MMC_Disable();
++      mmc_spi_readwrite_slow(0xff);
++      printk("mmc: mmc card config (CMD9) failed result = 0x%X\n\n", result); 
++      return (2);
++    }
++    for (i = 0; i < 16; i++) {
++      result = mmc_spi_readwrite_slow(0xff);
++      csd[i] = result;
++    }
++    for (i = 0; i < 2; i++) {
++      result = mmc_spi_readwrite_slow(0xff);
++    }
++    MMC_Disable();
++    mmc_spi_readwrite_slow(0xff);
++    // mmc_spi_readwrite_slow(0xff);
++    
++    if (result == 0x00)
++      return (3);
++
++    c_size = (csd[8] & 0xC0) + (csd[7] << 8) + ((csd[6] & 0x03) << 16);
++    c_size >>= 6;
++    c_size_mult = (csd[10] & 0x80) + ((csd[9] & 0x03) << 8);
++    c_size_mult >>= 7;
++    read_bl_len = csd[5] & 0x0f;
++    mult = 1;
++    mult <<= c_size_mult + 2;
++    blocknr = (c_size + 1) * mult;
++    block_len = 1;
++    block_len <<= read_bl_len;
++    size = block_len * blocknr;
++    size >>= 10;
++
++    for (i = 0; i < (1 << 6); i++) {
++      hd_blocksizes[i] = 1024;
++      hd_hardsectsizes[i] = block_len;
++      hd_maxsect[i] = 256;
++    }
++    hd_sizes[0] = size;
++    hd[0].nr_sects = blocknr;
++
++    printk("Size = %d, hardsectsize = %d, sectors = %d\n",
++         size, block_len, blocknr);
++
++    return 0;
++}
++
++
++/*
++ * *******************************************************************
++ *
++ *             End of SPI hardware access functions.
++ *
++ * *******************************************************************
++ */
++
++
++static int mmc_spi_write_block(unsigned int dest_addr, unsigned char *data)
++{
++    unsigned int address;
++    unsigned char result = 0;
++    unsigned char ab0, ab1, ab2, ab3;
++    int i;
++
++    address = dest_addr;
++
++    ab3 = 0xff & (address >> 24);
++    ab2 = 0xff & (address >> 16);
++    ab1 = 0xff & (address >> 8);
++    ab0 = 0xff & address;
++
++    MMC_Enable();
++
++    mmc_spi_readwrite(0xff);
++
++    mmc_spi_readwrite(0x58);
++    mmc_spi_readwrite(ab3);           /* msb */
++    mmc_spi_readwrite(ab2);
++    mmc_spi_readwrite(ab1);
++    mmc_spi_readwrite(ab0);           /* lsb */
++    mmc_spi_readwrite(0xff);
++
++    for (i = 0; i < 8; i++) 
++    {
++        result = mmc_spi_readwrite(0xff);
++        if (result == 0x00)
++        {
++            break;
++        }
++    }
++
++    if (result != 0x00) 
++    {
++        MMC_Disable();
++        mmc_spi_readwrite(0xff);
++        return (1);
++    }
++
++    mmc_spi_readwrite(0xfe);
++
++    for (i = 0; i < 512; i += 32)
++    {
++        mmc_spi_write_only(data[i]);
++        mmc_spi_write_only(data[i+1]);
++        mmc_spi_write_only(data[i+2]);
++        mmc_spi_write_only(data[i+3]);
++        mmc_spi_write_only(data[i+4]);
++        mmc_spi_write_only(data[i+5]);
++        mmc_spi_write_only(data[i+6]);
++        mmc_spi_write_only(data[i+7]);
++        mmc_spi_write_only(data[i+8]);
++        mmc_spi_write_only(data[i+9]);
++        mmc_spi_write_only(data[i+10]);
++        mmc_spi_write_only(data[i+11]);
++        mmc_spi_write_only(data[i+12]);
++        mmc_spi_write_only(data[i+13]);
++        mmc_spi_write_only(data[i+14]);
++        mmc_spi_write_only(data[i+15]);
++        mmc_spi_write_only(data[i+16]);
++        mmc_spi_write_only(data[i+17]);
++        mmc_spi_write_only(data[i+18]);
++        mmc_spi_write_only(data[i+19]);
++        mmc_spi_write_only(data[i+20]);
++        mmc_spi_write_only(data[i+21]);
++        mmc_spi_write_only(data[i+22]);
++        mmc_spi_write_only(data[i+23]);
++        mmc_spi_write_only(data[i+24]);
++        mmc_spi_write_only(data[i+25]);
++        mmc_spi_write_only(data[i+26]);
++        mmc_spi_write_only(data[i+27]);
++        mmc_spi_write_only(data[i+28]);
++        mmc_spi_write_only(data[i+29]);
++        mmc_spi_write_only(data[i+30]);
++        mmc_spi_write_only(data[i+31]);
++    }
++
++    mmc_spi_readwrite(0xff);
++    mmc_spi_readwrite(0xff);    
++
++    for (i = 0; i < 1000000; i++) 
++    {
++        result = mmc_spi_readwrite(0xff);
++        if (result == 0xff)
++        {
++            break;
++        }
++    }
++
++    if (result != 0xff) 
++    {
++        MMC_Disable();
++        mmc_spi_readwrite(0xff);
++        return (3);
++    }
++
++    MMC_Disable();
++    mmc_spi_readwrite(0xff);
++    return (0);
++}
++
++static int mmc_spi_read_block(unsigned char *data, unsigned int src_addr)
++{
++    unsigned int address;
++    unsigned char result = 0;
++    unsigned char ab0, ab1, ab2, ab3;
++    unsigned long flags;
++    int i, j;
++
++    address = src_addr;
++
++    ab3 = 0xff & (address >> 24);
++    ab2 = 0xff & (address >> 16);
++    ab1 = 0xff & (address >> 8);
++    ab0 = 0xff & address;
++
++    MMC_Enable();
++
++    mmc_spi_readwrite(0xff);
++
++    mmc_spi_readwrite(0x51);
++    mmc_spi_readwrite(ab3);           /* msb */
++    mmc_spi_readwrite(ab2);
++    mmc_spi_readwrite(ab1);
++    mmc_spi_readwrite(ab0);           /* lsb */
++    mmc_spi_readwrite(0xff);
++    
++    for (i = 0; i < 8; i++) 
++    {
++        result = mmc_spi_readwrite(0xff);
++        if (result == 0x00)
++        {
++            break;
++        }
++    }
++
++    if (result != 0x00) 
++    {
++        MMC_Disable();
++        mmc_spi_readwrite(0xff);
++        return (1);
++    }
++
++    for (i = 0; i < 100000; i++) 
++    {
++        result = mmc_spi_readwrite(0xff);
++        if (result == 0xfe)
++        {
++            break;
++        }
++    }
++
++    if (result != 0xfe) 
++    {
++        MMC_Disable();
++        mmc_spi_readwrite(0xff);
++        return (2);
++    }
++
++    for (i = 0; i < 512; i += 32 ) 
++    {
++          data[i] = mmc_spi_read_only();
++          data[i+1] = mmc_spi_read_only();
++          data[i+2] = mmc_spi_read_only();
++          data[i+3] = mmc_spi_read_only();
++          data[i+4] = mmc_spi_read_only();
++          data[i+5] = mmc_spi_read_only();
++          data[i+6] = mmc_spi_read_only();
++          data[i+7] = mmc_spi_read_only();
++          data[i+8] = mmc_spi_read_only();
++          data[i+9] = mmc_spi_read_only();
++          data[i+10] = mmc_spi_read_only();
++          data[i+11] = mmc_spi_read_only();
++          data[i+12] = mmc_spi_read_only();
++          data[i+13] = mmc_spi_read_only();
++          data[i+14] = mmc_spi_read_only();
++          data[i+15] = mmc_spi_read_only();
++          data[i+16] = mmc_spi_read_only();
++          data[i+17] = mmc_spi_read_only();
++          data[i+18] = mmc_spi_read_only();
++          data[i+19] = mmc_spi_read_only();
++          data[i+20] = mmc_spi_read_only();
++          data[i+21] = mmc_spi_read_only();
++          data[i+22] = mmc_spi_read_only();
++          data[i+23] = mmc_spi_read_only();
++          data[i+24] = mmc_spi_read_only();
++          data[i+25] = mmc_spi_read_only();
++          data[i+26] = mmc_spi_read_only();
++          data[i+27] = mmc_spi_read_only();
++          data[i+28] = mmc_spi_read_only();
++          data[i+29] = mmc_spi_read_only();
++          data[i+30] = mmc_spi_read_only();
++          data[i+31] = mmc_spi_read_only();
++    }
++
++    result = mmc_spi_readwrite(0xff);
++    result = mmc_spi_readwrite(0xff); 
++
++    MMC_Disable();
++    mmc_spi_readwrite(0xff);
++
++    return (0);
++}
++
++/*
++static int mmc_revalidate(kdev_t dev)
++{
++    int target, max_p, start, i;
++
++    mmc_media_detect = mmc_spi_media_detect();
++
++    if (mmc_media_detect == 0)
++    {
++        return -ENODEV;
++    }
++
++    target = DEVICE_NR(dev);
++
++    max_p = hd_gendisk.max_p;
++    start = target << 6;
++    for (i = max_p - 1; i >= 0; i--) 
++    {
++        int minor = start + i;
++        invalidate_device(MKDEV(MAJOR_NR, minor), 1);
++        hd_gendisk.part[minor].start_sect = 0;
++        hd_gendisk.part[minor].nr_sects = 0;
++    }
++
++    grok_partitions(&hd_gendisk, target, 1 << 6, hd_sizes[0] * 2);
++
++    return 0;
++}
++*/
++
++
++static int mmc_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
++                   unsigned long arg)
++{
++      if (!inode || !inode->i_rdev)
++              return -EINVAL;
++
++      switch (cmd) {
++#if 0
++      case BLKGETSIZE:
++              return put_user(hd[MINOR(inode->i_rdev)].nr_sects,
++                              (unsigned long *)arg);
++      case BLKGETSIZE64:
++              return put_user((u64) hd[MINOR(inode->i_rdev)].
++                              nr_sects, (u64 *) arg);
++      case BLKRRPART:
++              if (!capable(CAP_SYS_ADMIN))
++                      return -EACCES;
++
++              return mmc_revalidate(inode->i_rdev);
++#endif
++      case HDIO_GETGEO:
++              {
++                      struct block_device *bdev = inode->i_bdev;
++                      struct hd_geometry *loc, g;
++                      loc = (struct hd_geometry *)arg;
++                      if (!loc)
++                              return -EINVAL;
++                      memset(loc, 0, sizeof(struct hd_geometry));
++                      g.heads = 4;
++                      g.sectors = 16;
++                      g.cylinders = get_capacity(bdev->bd_disk) / (4*16);
++                      g.start = get_start_sect(bdev);
++                      return copy_to_user(loc, &g, sizeof(g)) ? -EFAULT : 0;
++              }
++      default:
++              return -ENOTTY;
++      }
++}
++
++
++/*
++static int mmc_check_media_change(kdev_t dev)
++{
++    (void) dev;
++    if (mmc_media_changed == 1) 
++    {
++        mmc_media_changed = 0;
++        return 1;
++    } 
++    else
++    {
++        return 0;
++    }
++}
++*/
++
++
++/*
++static int mmc_init(void)
++{
++    int result;
++
++    result = mmc_spi_hardware_init();
++
++    if (result != 0) 
++    {
++        printk("mmc: error %d in mmc_spi_hardware_init\n", result);
++        return -1;
++    }
++
++
++    result = mmc_spi_hw_test();
++
++    if (result != 0) 
++    {
++        printk("\n mmc: mmc_spi_hw_test i.O. \n\n");
++        return -1;
++    }
++
++
++    result = mmc_spi_speed_test();
++
++    if (result != 0) 
++    {
++        printk("\n mmc: mmc_spi_speed_test i.O. \n\n");
++        return -1;
++    }
++
++
++    result = mmc_spi_card_init();
++    mdelay(50);
++    if (result != 0) 
++    {
++        // Give it an extra shot
++        // result = mmc_spi_card_init();
++        if (result != 0) 
++        {
++            printk("mmc: error %d in mmc_card_init\n", result);
++            return -1;
++        }
++    }
++
++    result = mmc_spi_card_config();
++    if (result != 0) 
++    {
++        printk("mmc: error %d in mmc_card_config\n", result);
++        return -1;
++    }
++
++
++    return 0;
++}
++*/
++
++/*
++static void mmc_exit(void)
++{
++}
++*/
++
++
++/*
++static void mmc_check_media(void)
++{
++    int old_state, new_state;
++    int result;
++
++    old_state = mmc_media_detect;
++    new_state = mmc_spi_media_detect();
++
++    if (old_state != new_state) 
++    {
++        mmc_media_changed = 1;
++        if (new_state == PRESENT) 
++        {
++            result = mmc_init();
++            if (result != 0)
++            {
++                printk("mmc: error %d in mmc_init\n", result);
++            } 
++            else 
++            {
++                mmc_exit();
++            }
++        }
++    }
++
++#ifdef CHECK_MEDIA_CHANGE
++    del_timer(&mmc_timer);
++    mmc_timer.expires = jiffies + 10*HZ;
++    add_timer(&mmc_timer);
++#endif
++
++}
++*/
++
++
++/* NB: There might be several requests in the queue, simply dequeuing only one
++      and not checking for more will cause a stall because the block subsystem
++      will not call this function again unless the queue is "plugged" which can
++      only happen if it runs empty... */
++static void mmc_spi_request(struct request_queue *q)
++{
++      struct request *req;
++      int ret;
++      
++      unsigned int mmc_address;
++      unsigned char *buffer_address;
++      int nr_sectors;
++      int i;
++      int result, success;
++
++      if (blk_queue_plugged(q)) {
++              return;
++      }
++
++      spin_lock(&mmc_spi_lock);
++      for(;;) {
++              req = elv_next_request(q);
++              if (!req)
++                      break;
++              
++              if (!blk_fs_request(req)) {
++                      printk("not a blk_fs_request\n");
++                      spin_unlock(&mmc_spi_lock);
++                      continue;
++              }
++
++              mmc_address = req->sector * hd_hardsectsizes[0];
++              buffer_address = req->buffer;
++              nr_sectors = req->current_nr_sectors;
++              success = 1;
++              if (rq_data_dir(req) == READ) {
++                      spin_unlock_irq(q->queue_lock);
++                      for (i = 0; i < nr_sectors; i++) {
++                              result = mmc_spi_read_block(buffer_address, mmc_address);
++                              if (unlikely(result < 0)) {
++                                      printk(KERN_ERR "mmi_spi_block: error reading block (%d)\n", result);
++                                      success = 0;
++                                      break;
++                              }
++                              mmc_address += hd_hardsectsizes[0];
++                              buffer_address += hd_hardsectsizes[0];
++                      }
++                      spin_lock_irq(q->queue_lock);
++              } else {
++                      spin_unlock_irq(q->queue_lock);
++                      for (i = 0; i < nr_sectors; i++) {
++                              result = mmc_spi_write_block(mmc_address, buffer_address);
++                              if (unlikely(result < 0)) {
++                                      printk(KERN_ERR "mmi_spi_block: error writing block (%d)\n", result);
++                                      success = 0;
++                                      break;
++                              }
++                              mmc_address += hd_hardsectsizes[0];
++                              buffer_address += hd_hardsectsizes[0];
++                      }
++                      spin_lock_irq(q->queue_lock);
++              }
++              ret = end_that_request_chunk(req, success, nr_sectors * hd_hardsectsizes[0]);
++              if (!ret) {
++                      blkdev_dequeue_request(req);
++                      end_that_request_last(req, 0);
++              }
++      }
++      spin_unlock(&mmc_spi_lock);
++}
++
++
++static int mmc_open(struct inode *inode, struct file *filp)
++{
++    // int device;
++    (void) filp;
++    mmc_media_detect = mmc_spi_media_detect();
++
++    if (mmc_media_detect == 0)
++        return -ENODEV;
++
++    return 0;
++}
++
++static int mmc_release(struct inode *inode, struct file *filp)
++{
++    return 0;
++}
++
++
++static struct block_device_operations mmc_spi_bdops = {
++      .open = mmc_open,
++      .release = mmc_release,
++      .ioctl = mmc_ioctl,
++      .owner = THIS_MODULE,
++#if 0
++      .check_media_change = mmc_check_media_change,
++      .revalidate = mmc_revalidate,
++#endif
++};
++
++static int detect_card(void)
++{
++      int result;
++
++      result = mmc_spi_card_init();
++      if (result != 0) {
++              // Give it an extra shot
++              result = mmc_spi_card_init();
++              if (result != 0) {
++                      printk(KERN_ERR "mmc_spi_block: error in mmc_card_init (%d)\n", result);
++                      return -ENODEV;
++              }
++      }
++
++      result = mmc_spi_card_config();
++      // result = mmc_spi_speed_test();
++      if (result != 0) {
++              printk(KERN_ERR "mmc_spi_block: error in mmc_card_config (%d)\n", result);
++              return -ENODEV;
++      }
++
++      return 0;
++}
++
++/* Fills in the gendisk structure from the received card
++   data.  */
++static int gendisk_init(struct device *dev, struct gendisk *gd)
++{
++      if (!gd)
++              return -EINVAL;
++
++      gd->major = major;
++      gd->first_minor = 0; /* only one device supported */
++      gd->fops = &mmc_spi_bdops;
++      gd->driverfs_dev = dev;
++
++      gd->queue = blk_init_queue(mmc_spi_request,NULL);
++
++      if (!gd->queue)
++              return -ENOMEM;
++
++      sprintf(gd->disk_name, "mmcblk");
++
++      blk_queue_hardsect_size(gd->queue, hd_hardsectsizes[0]);
++
++      set_capacity(gd, hd_sizes[0]<<1);
++
++      return 0;
++}
++
++static int gendisk_fini(struct gendisk *gd)
++{
++      BUG_ON(!gd);
++
++      if (gd->queue)
++              blk_cleanup_queue(gd->queue);
++
++      del_gendisk(gd);
++}
++
++/* platform driver device instance routines */
++static int mmc_spi_probe(struct platform_device *pdev)
++{
++      int result;
++      printk("$Id: mmc_spi_block.c,v 1.04 2007/05/25 23:27:16 mrdata Exp $\n");
++
++      result = mmc_spi_hardware_init();
++      if (result != 0) {
++              printk(KERN_ERR "mmc_spi_block: error in mmc_spi_hardware_init (%d)\n", result);
++              result = -ENODEV;
++              return result;
++      }
++      
++      result = detect_card();
++      if (result < 0)
++              return result;
++
++      mmc_media_detect = 1;
++
++      result = register_blkdev(major, DEVICE_NAME);
++      if (result < 0)
++              return result;
++
++      if (!major)
++              major = result;
++
++      /* allow 8 partitions per device */
++      BUG_ON(mmc_disk!=NULL);
++      mmc_disk = alloc_disk(1 << 3);
++      if (!mmc_disk) {
++              result = -ENOMEM;
++              goto out;
++      }
++
++      result = gendisk_init(&pdev->dev, mmc_disk);
++      if (result < 0)
++              goto out;
++
++      add_disk(mmc_disk);
++      
++      /*init_timer(&mmc_timer);
++         mmc_timer.expires = jiffies + HZ;
++         mmc_timer.function = (void *)mmc_check_media;
++         add_timer(&mmc_timer); */
++      return 0;
++
++out:
++      if (mmc_disk)
++              put_disk(mmc_disk);
++              
++      unregister_blkdev(major, DEVICE_NAME);
++      return result;
++}
++
++static int mmc_spi_remove(struct platform_device *dev)
++{
++      int ret;
++
++      if (mmc_disk) {
++              gendisk_fini(mmc_disk);
++              put_disk(mmc_disk);
++      }
++
++      ret = unregister_blkdev(major, DEVICE_NAME);
++      return ret;
++}
++
++struct platform_driver mmc_spi_driver = {
++      .probe          = mmc_spi_probe,
++      .remove         = mmc_spi_remove,
++      .driver         = {
++              .name   = "mmc_spi",
++              .owner  = THIS_MODULE,
++      },
++};
++
++
++/* module init/exit */
++static int __init mmc_block_spi_init(void)
++{
++      int ret;
++      spin_lock_init(&mmc_spi_lock);
++      
++      ret = platform_driver_register(&mmc_spi_driver);
++      if (ret < 0)
++              return ret;
++      
++      /* we just support one device */
++      mmc_dev = platform_device_register_simple("mmc_spi", -1, NULL, 0);
++      if (IS_ERR(mmc_dev))
++              return PTR_ERR(mmc_dev);
++      
++      return 0;
++}
++
++
++static void __exit mmc_block_spi_exit(void)
++{
++      platform_driver_unregister(&mmc_spi_driver);
++      if (mmc_dev)
++              platform_device_unregister(mmc_dev);
++}
++
++
++module_init(mmc_block_spi_init);
++module_exit(mmc_block_spi_exit);
++
++MODULE_AUTHOR("Madsuk,Rohde,TaGana,Carsten Juttner <carjay@gmx.net>,Guylhem Aznar <mmc-driver@externe.net>,mrdata");
++MODULE_DESCRIPTION("Driver for MMC/SD-Cards in SPI mode by GPIO");
++MODULE_SUPPORTED_DEVICE("SIMpad");
++MODULE_LICENSE("GPL");
++
++module_param(major, int, 0444);
++MODULE_PARM_DESC(major, "specify the major device number for the MMC/SD SPI driver");
diff --git a/packages/linux/linux/simpad/linux-2.6.21-SIMpad-battery-old-way-but-also-with-sysfs.patch b/packages/linux/linux/simpad/linux-2.6.21-SIMpad-battery-old-way-but-also-with-sysfs.patch
new file mode 100644 (file)
index 0000000..ee18ff2
--- /dev/null
@@ -0,0 +1,571 @@
+diff -uNr linux-2.6.21.vanilla/drivers/mfd/Makefile linux-2.6.21/drivers/mfd/Makefile
+--- linux-2.6.21.vanilla/drivers/mfd/Makefile  2007-05-30 18:00:30.000000000 +0200
++++ linux-2.6.21/drivers/mfd/Makefile  2007-05-30 18:43:10.000000000 +0200
+@@ -12,3 +12,7 @@
+ ifeq ($(CONFIG_SA1100_ASSABET),y)
+ obj-$(CONFIG_MCP_UCB1200)     += ucb1x00-assabet.o
+ endif
++
++ifeq ($(CONFIG_SA1100_SIMPAD),y)
++obj-$(CONFIG_MCP_UCB1200)     += ucb1x00-simpad.o
++endif
+diff -uNr linux-2.6.21.vanilla/drivers/mfd/ucb1x00-simpad.c linux-2.6.21/drivers/mfd/ucb1x00-simpad.c
+--- linux-2.6.21.vanilla/drivers/mfd/ucb1x00-simpad.c  1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.21/drivers/mfd/ucb1x00-simpad.c  2007-05-30 18:35:48.000000000 +0200
+@@ -0,0 +1,226 @@
++/*
++ *  linux/drivers/mfd/ucb1x00-simpad.c
++ *
++ *  Copyright (C) 2001-2003 Russell King, All Rights Reserved.
++ *  2007/03/18 mrdata:
++ *             - adapted ucb1x00-assabet.c
++ *             - transfer ucb1x00-simpad.c from kernel24
++ *               to new structur of kernel26
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License.
++ *
++ *  We handle the machine-specific bits of the UCB1x00 driver here.
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/fs.h>
++#include <linux/proc_fs.h>
++#include <linux/device.h>
++
++#include <linux/apm-emulation.h>
++
++#include <asm/dma.h>
++
++#include <asm/arch/simpad.h>
++#include <asm/arch-sa1100/simpad_pm.h>
++
++#include "ucb1x00.h"
++#include "ucb1x00-simpad.h"
++
++#define UCB1X00_ATTR(name,input,designation) \
++static ssize_t name##_show(struct class_device *dev, char *buf)               \
++{                                                                     \
++      struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);                 \
++      int val;                                                        \
++      ucb1x00_adc_enable(ucb);                                        \
++      val = ucb1x00_adc_read(ucb, input, UCB_NOSYNC);                 \
++      ucb1x00_adc_disable(ucb);                                       \
++      return sprintf(buf, "%d\n", CALIBRATE_##designation(val));      \
++}                                                                     \
++static CLASS_DEVICE_ATTR(name,0444,name##_show,NULL)
++
++UCB1X00_ATTR(vbatt, UCB_ADC_INP_AD1, BATTERY);
++UCB1X00_ATTR(vcharger, UCB_ADC_INP_AD2, SUPPLY);
++UCB1X00_ATTR(icharger, UCB_ADC_INP_AD3, CHARGING);
++
++static struct ucb1x00 *ucb_alt;
++
++#define UCB1X00_WERT(name,input,designation) \
++static int ucb1x00_simpad_read_##name(struct ucb1x00 *ucb_alt)                \
++{                                                                     \
++      int val;                                                        \
++      ucb1x00_adc_enable(ucb_alt);                                    \
++      val = ucb1x00_adc_read(ucb_alt, input, UCB_NOSYNC);             \
++      ucb1x00_adc_disable(ucb_alt);                                   \
++      return CALIBRATE_##designation(val);                            \
++}
++
++UCB1X00_WERT(vbatt, UCB_ADC_INP_AD1, BATTERY);
++UCB1X00_WERT(vcharger, UCB_ADC_INP_AD2, SUPPLY);
++UCB1X00_WERT(icharger, UCB_ADC_INP_AD3, CHARGING);
++
++static int ucb1x00_simpad_add(struct ucb1x00_dev *dev)
++{
++      class_device_create_file(&dev->ucb->cdev, &class_device_attr_vbatt);
++      class_device_create_file(&dev->ucb->cdev, &class_device_attr_vcharger);
++      class_device_create_file(&dev->ucb->cdev, &class_device_attr_icharger);
++      ucb_alt = dev->ucb;
++      return 0;
++}
++
++static void ucb1x00_simpad_remove(struct ucb1x00_dev *dev)
++{
++      class_device_remove_file(&dev->ucb->cdev, &class_device_attr_icharger);
++      class_device_remove_file(&dev->ucb->cdev, &class_device_attr_vcharger);
++      class_device_remove_file(&dev->ucb->cdev, &class_device_attr_vbatt);
++}
++
++static struct ucb1x00_driver ucb1x00_simpad_driver = {
++      .add    = ucb1x00_simpad_add,
++      .remove = ucb1x00_simpad_remove,
++};
++
++static int __init ucb1x00_simpad_init(void)
++{
++      apm_get_power_status = simpad_apm_get_power_status;
++      return ucb1x00_register_driver(&ucb1x00_simpad_driver);
++}
++
++static void __exit ucb1x00_simpad_exit(void)
++{
++      apm_get_power_status = NULL;
++      ucb1x00_unregister_driver(&ucb1x00_simpad_driver);
++}
++
++/****************************************************************************/
++/*  Functions exported for use by the kernel and kernel modules             */
++/****************************************************************************/
++
++int simpad_get_battery(struct simpad_battery_apm *bstat)
++{
++      int icharger, vcharger, vbatt;
++
++      if ( ucb_alt ) {
++              icharger = ucb1x00_simpad_read_icharger( ucb_alt );
++              vcharger = ucb1x00_simpad_read_vcharger( ucb_alt );
++              vbatt    = ucb1x00_simpad_read_vbatt( ucb_alt );
++      } else {
++              bstat->ac_status = SIMPAD_AC_STATUS_AC_UNKNOWN;
++              bstat->status = SIMPAD_BATT_STATUS_UNKNOWN;
++              bstat->percentage = 0x64;    // lets say 100%
++              bstat->life = 330;           // lets say a long time 
++              return 0;
++      }
++
++      /* AC status */
++      bstat->ac_status = SIMPAD_AC_STATUS_AC_OFFLINE;
++      if ( vcharger>MIN_SUPPLY ) {
++              bstat->ac_status = SIMPAD_AC_STATUS_AC_ONLINE;
++      }
++
++      /* charging */
++      bstat->status = 0x0;
++      if ( icharger >= CHARGING_LED_LEVEL ) 
++              bstat->status = SIMPAD_BATT_STATUS_CHARGING;
++
++      if ( vbatt > BATT_LOW )
++              bstat->status |= SIMPAD_BATT_STATUS_HIGH;
++      else if ( vbatt < BATT_CRITICAL )
++              bstat->status |= SIMPAD_BATT_STATUS_CRITICAL;
++      else
++              bstat->status |= SIMPAD_BATT_STATUS_LOW;
++
++      if (bstat->status & SIMPAD_BATT_STATUS_CHARGING) {
++              if (icharger > CHARGING_MAX_LEVEL)
++                      icharger = CHARGING_MAX_LEVEL;
++              if (icharger < CHARGING_LED_LEVEL)
++                      icharger = CHARGING_LED_LEVEL;
++
++              bstat->percentage = 100 - 100 * (icharger - CHARGING_LED_LEVEL) /
++              (CHARGING_MAX_LEVEL - CHARGING_LED_LEVEL);
++      } else {
++              if (vbatt > BATT_FULL)
++                      vbatt = BATT_FULL;
++              if (vbatt < BATT_EMPTY)
++                      vbatt = BATT_EMPTY;
++
++              bstat->percentage = 100 * (vbatt - BATT_EMPTY) / (BATT_FULL - BATT_EMPTY);
++      }
++
++      /* let's assume: full load is 7h */
++      /* bstat->life = 420*bstat->percentage/100; */
++      /* mrdata: think, 4h is more realistic */
++      bstat->life = 240*(bstat->percentage)/100;
++
++#if 0
++      printk("get_battery: ac: %02x / ch: %02x /  perc: %02x / life: %d \n",
++      bstat->ac_status, bstat->status,
++      bstat->percentage, bstat->life );
++#endif
++
++      return 0;
++}
++
++void simpad_apm_get_power_status(struct apm_power_info *info)
++{
++      struct simpad_battery_apm bstat;
++      unsigned char ac    = APM_AC_UNKNOWN;
++      unsigned char level = APM_BATTERY_STATUS_UNKNOWN;
++      int status, result;
++
++      result = simpad_get_battery(&bstat);
++      if (result) {
++              printk("%s: unable to access battery information: result=%d\n", __FUNCTION__, result);
++              return;
++      }
++
++      switch (bstat.ac_status) {
++      case SIMPAD_AC_STATUS_AC_OFFLINE:
++              ac = APM_AC_OFFLINE;
++              break;
++      case SIMPAD_AC_STATUS_AC_ONLINE:
++              ac = APM_AC_ONLINE;
++              break;
++      case SIMPAD_AC_STATUS_AC_BACKUP:
++              ac = APM_AC_BACKUP;
++              break;
++      }
++
++      info->ac_line_status = ac;
++
++      status = bstat.status;
++      if (status & (SIMPAD_BATT_STATUS_CHARGING | SIMPAD_BATT_STATUS_CHARGE_MAIN))
++              level = APM_BATTERY_STATUS_CHARGING;
++      else if (status & (SIMPAD_BATT_STATUS_HIGH | SIMPAD_BATT_STATUS_FULL))
++              level = APM_BATTERY_STATUS_HIGH;
++      else if (status & SIMPAD_BATT_STATUS_LOW)
++              level = APM_BATTERY_STATUS_LOW;
++      else if (status & SIMPAD_BATT_STATUS_CRITICAL)
++              level = APM_BATTERY_STATUS_CRITICAL;
++
++      info->battery_status = level;
++      info->battery_flag = info->battery_status;
++
++      info->battery_life = bstat.percentage;
++
++      /* we have a dumb battery - so we know nothing */
++      info->time = bstat.life;
++      info->units = APM_UNITS_MINS;
++
++#if 0
++      printk("apm_get_power: ac: %02x / bs: %02x / bf: %02x / perc: %02x / life: %d\n",
++             info->ac_line_status, info->battery_status, info->battery_flag,
++             info->battery_life, info->time );
++#endif
++      return;
++}
++
++module_init(ucb1x00_simpad_init);
++module_exit(ucb1x00_simpad_exit);
++
++
++MODULE_AUTHOR("Juergen Messerer <juergen.messerer@freesurf.ch>");
++MODULE_DESCRIPTION("SIMpad noddy testing only example ADC driver");
++MODULE_LICENSE("GPL");
+diff -uNr linux-2.6.21.vanilla/drivers/mfd/ucb1x00-simpad.h linux-2.6.21/drivers/mfd/ucb1x00-simpad.h
+--- linux-2.6.21.vanilla/drivers/mfd/ucb1x00-simpad.h  1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.21/drivers/mfd/ucb1x00-simpad.h  2007-05-30 18:35:48.000000000 +0200
+@@ -0,0 +1,86 @@
++/*
++ *  linux/drivers/mfd/ucb1x00-simpad.h
++ *
++ *  Copyright (C) 2001 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License.
++ */
++#ifndef UCB1300_SIMPAD_H
++#define UCB1300_SIMPAD_H
++
++/*
++ * Conversion from AD -> mV
++ * 7.5V = 1023   7.33137mV/Digit
++ *
++ * 400 Units == 9.7V
++ * a     = ADC value
++ * 2007/03/24 mrdata:
++ *            according UCB1300 datasheet ADC error max. 3 LSB
++ *            5-95% of full scale -> 3*7.33137mV = 21.99mV
++ * // old 
++ * 21    = ADC error 
++ * 12600 = Divident to get 2*7.3242 
++ * 860   = Divider to get 2*7.3242
++ * 170   = Voltagedrop over
++ *
++ * // new
++ * 3     = ADC error 
++ * 12610 = Divident to get 2*7.33139
++ * 860   = Divider  to get 2*7.33139
++ * 170   = Voltagedrop over
++ */
++// #define CALIBRATE_BATTERY(a)   ((((a + 21)*12600)/860) + 170)
++#define CALIBRATE_BATTERY(a)   ((((a + 3)*12610)/860) + 170)
++
++/*
++ * We have two types of batteries a small and a large one
++ * To get the right value we to distinguish between those two
++ * 450 Units == 15 V
++ */
++#ifdef SMALL_BATTERY 
++#define CALIBRATE_SUPPLY(a)   (((a) * 1500) / 51)
++#define MIN_SUPPLY            8500 /* Less then 8.5V means no powersupply */
++#else
++#define CALIBRATE_SUPPLY(a)   (((a) * 1500) / 45)
++//#define MIN_SUPPLY            14000 /* Less then 14V means no powersupply */
++#define MIN_SUPPLY            12000 /* Less then 12V means no powersupply */
++#endif
++
++/*
++ * Charging Current 
++ * if value is >= 50 then charging is on
++ */
++// #define CALIBRATE_CHARGING(a)    (((a) * 1000) / (152/4))
++#define CALIBRATE_CHARGING(a)    (a)
++//#define CHARGING_LED_LEVEL     50
++
++#ifdef CONFIG_SA1100_SIMPAD_SINUSPAD
++
++// type small battery
++#define CHARGING_LED_LEVEL     12
++#define CHARGING_MAX_LEVEL     120
++#define BATT_FULL     8100
++#define BATT_LOW      7300
++#define BATT_CRITICAL 6700
++#define BATT_EMPTY    6400
++
++#else // CONFIG_SA1100_SIMPAD_SINUSPAD
++
++// type large battery
++// because of ADC error CHARGING_LED_LEVEL can changed
++// from 27 to 28
++#define CHARGING_LED_LEVEL     27
++#define CHARGING_MAX_LEVEL     265
++// BATT_FULL with SIMPAD_AC_STATUS_AC_OFFLINE
++#define BATT_FULL     8100
++#define BATT_LOW      7400
++#define BATT_CRITICAL 6800
++#define BATT_EMPTY    6500
++
++#endif // CONFIG_SA1100_SIMPAD_SINUSPAD
++
++// int simpad_get_battery(struct simpad_battery_apm *bstat);
++
++#endif
+diff -uNr linux-2.6.21.vanilla/include/asm-arm/arch-sa1100/simpad_pm.h linux-2.6.21/include/asm-arm/arch-sa1100/simpad_pm.h
+--- linux-2.6.21.vanilla/include/asm-arm/arch-sa1100/simpad_pm.h       1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.21/include/asm-arm/arch-sa1100/simpad_pm.h       2007-05-30 18:36:07.000000000 +0200
+@@ -0,0 +1,236 @@
++/*
++* Abstraction interface for microcontroller connection to rest of system
++*
++* Copyright 2003 Peter Pregler
++* Copyright 2000,1 Compaq Computer Corporation.
++*
++* Use consistent with the GNU GPL is permitted,
++* provided that this copyright notice is
++* preserved in its entirety in all copies and derived works.
++*
++* COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
++* AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
++* FITNESS FOR ANY PARTICULAR PURPOSE.
++*
++* Author: Peter Pregler (based on work for ipaq by Andrew Christian)
++*
++*/
++
++#ifndef __SIMPAD_HAL_H
++#define __SIMPAD_HAL_H
++
++#include <linux/apm-emulation.h>
++
++struct simpad_battery_apm {
++      unsigned char ac_status;        /* line connected yes/no */
++      unsigned char status;           /* battery loading yes/no */
++      unsigned char percentage;       /* percentage loaded */
++      unsigned short life;            /* life till empty */
++};
++
++extern void simpad_apm_get_power_status(struct apm_power_info *);
++
++// extern int simpad_get_battery(struct simpad_battery_apm *bstat);
++
++/* These should match the apm_bios.h definitions */
++#define SIMPAD_AC_STATUS_AC_OFFLINE      0x00
++#define SIMPAD_AC_STATUS_AC_ONLINE       0x01
++#define SIMPAD_AC_STATUS_AC_BACKUP       0x02   /* What does this mean? */
++#define SIMPAD_AC_STATUS_AC_UNKNOWN      0xff
++
++
++/* These bitfields are rarely "or'd" together */
++#define SIMPAD_BATT_STATUS_HIGH          0x01
++#define SIMPAD_BATT_STATUS_LOW           0x02
++#define SIMPAD_BATT_STATUS_CRITICAL      0x04
++#define SIMPAD_BATT_STATUS_CHARGING      0x08
++#define SIMPAD_BATT_STATUS_CHARGE_MAIN   0x10
++#define SIMPAD_BATT_STATUS_DEAD          0x20   /* Battery will not charge */
++#define SIMPAD_BATT_NOT_INSTALLED        0x20   /* For expansion pack batteries */
++#define SIMPAD_BATT_STATUS_FULL          0x40   /* Battery fully charged (and connected to AC) */
++#define SIMPAD_BATT_STATUS_NOBATT        0x80
++#define SIMPAD_BATT_STATUS_UNKNOWN       0xff
++                                                                                                                                           
++#if 0 // FIXME
++#include <linux/simpad_ts.h>
++
++enum simpad_asset_type {
++      ASSET_TCHAR = 0,
++      ASSET_SHORT,
++      ASSET_LONG
++};
++
++#define TTYPE(_type)           (((unsigned int)_type) << 8)
++#define TCHAR(_len)            (TTYPE(ASSET_TCHAR) | (_len))
++#define TSHORT                 TTYPE(ASSET_SHORT)
++#define TLONG                  TTYPE(ASSET_LONG)
++#define ASSET(_type,_num)      ((((unsigned int)_type)<<16) | (_num))
++
++#define ASSET_HM_VERSION        ASSET( TCHAR(10), 0 )   /* 1.1, 1.2 */
++#define ASSET_SERIAL_NUMBER     ASSET( TCHAR(40), 1 )   /* Unique iPAQ serial number */
++#define ASSET_MODULE_ID         ASSET( TCHAR(20), 2 )   /* E.g., "iPAQ 3700" */    
++#define ASSET_PRODUCT_REVISION  ASSET( TCHAR(10), 3 )   /* 1.0, 2.0 */
++#define ASSET_PRODUCT_ID        ASSET( TSHORT,    4 )   /* 2 = Palm-sized computer */
++#define ASSET_FRAME_RATE        ASSET( TSHORT,    5 )
++#define ASSET_PAGE_MODE         ASSET( TSHORT,    6 )   /* 0 = Flash memory */
++#define ASSET_COUNTRY_ID        ASSET( TSHORT,    7 )   /* 0 = USA */
++#define ASSET_IS_COLOR_DISPLAY  ASSET( TSHORT,    8 )   /* Boolean, 1 = yes */
++#define ASSET_ROM_SIZE          ASSET( TSHORT,    9 )   /* 16, 32 */
++#define ASSET_RAM_SIZE          ASSET( TSHORT,   10 )   /* 32768 */
++#define ASSET_HORIZONTAL_PIXELS ASSET( TSHORT,   11 )   /* 240 */
++#define ASSET_VERTICAL_PIXELS   ASSET( TSHORT,   12 )   /* 320 */
++
++#define ASSET_TYPE(_asset)       (((_asset)&0xff000000)>>24)
++#define ASSET_TCHAR_LEN(_asset)  (((_asset)&0x00ff0000)>>16)
++#define ASSET_NUMBER(_asset)     ((_asset)&0x0000ffff)
++
++#define MAX_TCHAR_LEN 40
++
++struct simpad_asset {
++      unsigned int type;
++      union {
++              unsigned char  tchar[ MAX_TCHAR_LEN ];
++              unsigned short vshort;
++              unsigned long  vlong;
++      } a;
++};
++
++/********************************************************************
++ * Interface to the hardware-type specific functions
++ *
++ * get_version           Read the version number of the microcontroller on the option pack SPI bus
++ * spi_read              Reads from the serial EEPROM memory on the option pack SPI bus
++ * spi_write             Write to the serial EEPROM memory on the option pack SPI bus
++ * get_option_detect     Returns whether or not an option pack is present
++ *
++ * get_thermal_sensor    Return measured temperature of the unit, in units of 0.125 deg C
++ * set_notify_led        Turns on, off, or blinks the Green LED
++ * read_light_sensor     Returns the value of the front light sensor
++ * get_battery           Returns the current voltage and charging state of all batteries
++ * audio_clock           Sets the audio CODEC to run at a particular rate
++ * audio_power           Turns on/off audio CODEC (internally calls audio_clock)
++ * audio_mute            Mutes the audio CODEC
++ * asset_read            Extracts PocketPC-style asset information from persistent memory
++ * backlight_control     Adjusts the backlight level  (only on/off for 3100)
++ *
++ *
++ * iPAQ 3100 only
++ * ==============
++ * codec_control         Reset/mute/control level of 3100 audio codec
++ * contrast_control      Adjusts the contrast level   (only for 3100)
++ *
++ * iPAQ 3600, 3700 only
++ * ====================
++ * eeprom_read           Reads from the asset information on the eeprom of a 3600 (deprecated)
++ * eeprom_write          Writes to the asset information on the eeprom (deprecated)
++ *
++ * The interfaces to the EEPROM functions are maintained only because the simpad_ts driver has
++ * a deprecated ioctl call for them.  They are used internally by the "asset_read" function.
++ *
++ * iPAQ 3800, 3900 only
++ * ====================
++ * set_ebat              Tells enhanced PCMCIA sleeves that this iPAQ can handle 
++ *                       a wider voltage range (applies to 3800, 3900)
++ *
++ *********************************************************************/
++
++struct simpad_hal_ops {
++      /* Functions provided by the underlying hardware */
++      int (*get_version)( struct simpad_ts_version * );
++      int (*eeprom_read)( unsigned short address, unsigned char *data, unsigned short len );
++      int (*eeprom_write)( unsigned short address, unsigned char *data, unsigned short len );
++      int (*get_thermal_sensor)( unsigned short * );
++      int (*set_notify_led)( unsigned char mode, unsigned char duration, 
++                             unsigned char ontime, unsigned char offtime );
++      int (*read_light_sensor)( unsigned char *result );
++      int (*get_battery)( struct simpad_battery * );
++      int (*spi_read)( unsigned short address, unsigned char *data, unsigned short len );
++      int (*spi_write)( unsigned short address, unsigned char *data, unsigned short len );
++      int (*codec_control)( unsigned char, unsigned char );
++      int (*get_option_detect)( int *result );
++      int (*audio_clock)( long samplerate );
++      int (*audio_power)( long samplerate );
++      int (*audio_mute)( int mute );
++      int (*asset_read)( struct simpad_asset *asset );
++      int (*set_ebat)( void );
++
++      /* Functions indirectly provided by the underlying hardware */
++      int (*backlight_control)( enum flite_pwr power, unsigned char level );
++      int (*contrast_control)( unsigned char level );
++
++        /* for module use counting */ 
++        struct module *owner;
++};
++
++/* Used by the device-specific hardware module to register itself */
++extern int  simpad_hal_register_interface( struct simpad_hal_ops *ops );
++extern void simpad_hal_unregister_interface( struct simpad_hal_ops *ops );
++
++/* 
++ * Calls into HAL from the device-specific hardware module
++ * These run at interrupt time 
++ */
++extern void simpad_hal_keypress( unsigned char key );
++extern void simpad_hal_touchpanel( unsigned short x, unsigned short y, int down );
++extern void simpad_hal_option_detect( int present );
++
++/* Callbacks registered by device drivers */
++struct simpad_driver_ops {
++      void (*keypress)( unsigned char key );
++      void (*touchpanel)( unsigned short x, unsigned short y, int down );
++      void (*option_detect)( int present );
++};
++
++extern int  simpad_hal_register_driver( struct simpad_driver_ops * );
++extern void simpad_hal_unregister_driver( struct simpad_driver_ops * );
++
++
++/* Calls into HAL from device drivers and other kernel modules */
++extern void simpad_get_flite( struct simpad_ts_backlight *bl );
++extern void simpad_get_contrast( unsigned char *contrast );
++extern int  simpad_set_flite( enum flite_pwr pwr, unsigned char brightness );
++extern int  simpad_set_contrast( unsigned char contrast );
++extern int  simpad_toggle_frontlight( void );
++
++extern int simpad_apm_get_power_status(unsigned char *ac_line_status, unsigned char *battery_status, 
++                                    unsigned char *battery_flag, unsigned char *battery_percentage, 
++                                    unsigned short *battery_life);
++
++extern struct simpad_hal_ops *simpad_hal_ops;
++
++/* Do not use this macro in driver files - instead, use the inline functions defined below */
++#define CALL_HAL( f, args... ) \
++        { int __result = -EIO;                             \
++          if ( simpad_hal_ops && simpad_hal_ops->f ) {       \
++                __MOD_INC_USE_COUNT(simpad_hal_ops->owner); \
++                __result = simpad_hal_ops->f(args);         \
++                __MOD_DEC_USE_COUNT(simpad_hal_ops->owner); \
++          }                                                \
++          return __result; }
++
++#define HFUNC  static __inline__ int
++
++/* The eeprom_read/write address + len has a maximum value of 512.  Both must be even numbers */
++HFUNC simpad_eeprom_read( u16 addr, u8 *data, u16 len )  CALL_HAL(eeprom_read,addr,data,len)
++HFUNC simpad_eeprom_write( u16 addr, u8 *data, u16 len)  CALL_HAL(eeprom_write,addr,data,len)
++HFUNC simpad_spi_read( u8 addr, u8 *data, u16 len)    CALL_HAL(spi_read,addr,data,len)
++HFUNC simpad_spi_write( u8 addr, u8 *data, u16 len)   CALL_HAL(spi_write,addr,data,len)
++HFUNC simpad_get_version( struct simpad_ts_version *v )   CALL_HAL(get_version,v)
++HFUNC simpad_get_thermal_sensor( u16 *thermal )               CALL_HAL(get_thermal_sensor,thermal)
++HFUNC simpad_set_led( u8 mode, u8 dur, u8 ont, u8 offt ) CALL_HAL(set_notify_led, mode, dur, ont, offt)
++HFUNC simpad_get_light_sensor( u8 *result )           CALL_HAL(read_light_sensor,result)
++HFUNC simpad_get_battery( struct simpad_battery *bat )        CALL_HAL(get_battery,bat)
++HFUNC simpad_get_option_detect( int *result)             CALL_HAL(get_option_detect,result)
++HFUNC simpad_audio_clock( long samplerate )              CALL_HAL(audio_clock,samplerate)
++HFUNC simpad_audio_power( long samplerate )              CALL_HAL(audio_power,samplerate)
++HFUNC simpad_audio_mute( int mute )                      CALL_HAL(audio_mute,mute)
++HFUNC simpad_asset_read( struct simpad_asset *asset )     CALL_HAL(asset_read,asset)
++HFUNC simpad_set_ebat( void )                            CALL_HAL(set_ebat)
++
++/* Don't use these functions directly - rather, call {get,set}_{flite,contrast} */
++      /* Functions indirectly provided by the underlying hardware */
++HFUNC simpad_backlight_control( enum flite_pwr p, u8 v ) CALL_HAL(backlight_control,p,v)
++HFUNC simpad_contrast_control( u8 level )                CALL_HAL(contrast_control,level)
++
++#endif
++#endif
diff --git a/packages/linux/linux/simpad/linux-2.6.21-SIMpad-net-shared-irq.patch b/packages/linux/linux/simpad/linux-2.6.21-SIMpad-net-shared-irq.patch
new file mode 100644 (file)
index 0000000..e925781
--- /dev/null
@@ -0,0 +1,63 @@
+diff -uNr linux-2.6.21.vanilla/drivers/net/pcmcia/pcnet_cs.c linux-2.6.21/drivers/net/pcmcia/pcnet_cs.c
+--- linux-2.6.21.vanilla/drivers/net/pcmcia/pcnet_cs.c 2007-05-29 21:35:00.000000000 +0200
++++ linux-2.6.21/drivers/net/pcmcia/pcnet_cs.c 2007-05-30 17:51:21.000000000 +0200
+@@ -26,6 +26,8 @@
+     CCAE support.  Drivers merged back together, and shared-memory
+     Socket EA support added, by Ken Raeburn, September 1995.
++    mrdata: -added shared irq
++
+ ======================================================================*/
+ #include <linux/kernel.h>
+@@ -254,7 +256,7 @@
+     info->p_dev = link;
+     link->priv = dev;
+-    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
++    link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
+     link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+     link->conf.Attributes = CONF_ENABLE_IRQ;
+     link->conf.IntType = INT_MEMORY_AND_IO;
+diff -uNr linux-2.6.21.vanilla/drivers/net/wireless/hostap/hostap_cs.c linux-2.6.21/drivers/net/wireless/hostap/hostap_cs.c
+--- linux-2.6.21.vanilla/drivers/net/wireless/hostap/hostap_cs.c       2007-05-29 21:35:00.000000000 +0200
++++ linux-2.6.21/drivers/net/wireless/hostap/hostap_cs.c       2007-05-30 17:53:20.000000000 +0200
+@@ -1,3 +1,8 @@
++/*
++ *
++ * mrdata: -added shared irq
++ */
++
+ #define PRISM2_PCCARD
+ #include <linux/module.h>
+@@ -695,7 +700,7 @@
+        * irq structure is initialized.
+        */
+       if (link->conf.Attributes & CONF_ENABLE_IRQ) {
+-              link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
++              link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_FIRST_SHARED | IRQ_HANDLE_PRESENT;
+               link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+               link->irq.Handler = prism2_interrupt;
+               link->irq.Instance = dev;
+diff -uNr linux-2.6.21.vanilla/drivers/net/wireless/orinoco_cs.c linux-2.6.21/drivers/net/wireless/orinoco_cs.c
+--- linux-2.6.21.vanilla/drivers/net/wireless/orinoco_cs.c     2007-05-29 21:35:00.000000000 +0200
++++ linux-2.6.21/drivers/net/wireless/orinoco_cs.c     2007-05-30 17:52:19.000000000 +0200
+@@ -8,6 +8,8 @@
+  * cards such as the 3Com AirConnect and Ericsson WLAN.
+  * 
+  * Copyright notice & release notes in file orinoco.c
++ *
++ * mrdata: added shared irq
+  */
+ #define DRIVER_NAME "orinoco_cs"
+@@ -120,7 +122,7 @@
+       link->priv = dev;
+       /* Interrupt setup */
+-      link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
++      link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_FIRST_SHARED | IRQ_HANDLE_PRESENT;
+       link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+       link->irq.Handler = orinoco_interrupt;
+       link->irq.Instance = dev; 
diff --git a/packages/linux/linux/simpad/linux-2.6.21-SIMpad-pcmcia.patch b/packages/linux/linux/simpad/linux-2.6.21-SIMpad-pcmcia.patch
new file mode 100644 (file)
index 0000000..6ff5e37
--- /dev/null
@@ -0,0 +1,162 @@
+diff -uNr linux-2.6.21.vanilla/drivers/pcmcia/cs.c linux-2.6.21/drivers/pcmcia/cs.c
+--- linux-2.6.21.vanilla/drivers/pcmcia/cs.c   2007-05-30 18:00:30.000000000 +0200
++++ linux-2.6.21/drivers/pcmcia/cs.c   2007-05-30 18:10:20.000000000 +0200
+@@ -10,6 +10,8 @@
+  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+  *
+  * (C) 1999           David A. Hinds
++ *
++ * mrdata: -added suspend fix
+  */
+ #include <linux/module.h>
+@@ -60,6 +62,10 @@
+ INT_MODULE_PARM(unreset_delay,        10);            /* centiseconds */
+ INT_MODULE_PARM(unreset_check,        10);            /* centiseconds */
+ INT_MODULE_PARM(unreset_limit,        30);            /* unreset_check's */
++// INT_MODULE_PARM(unreset_delay,     20);            /* centiseconds */
++// INT_MODULE_PARM(unreset_check,     100);           /* centiseconds */
++// INT_MODULE_PARM(unreset_limit,     300);           /* unreset_check's */
++
+ /* Access speed for attribute memory windows */
+ INT_MODULE_PARM(cis_speed,    300);           /* ns */
+@@ -365,6 +371,7 @@
+       skt->ops->set_socket(skt, &skt->socket);
+       msleep(unreset_delay * 10);
++      
+       for (i = 0; i < unreset_limit; i++) {
+               skt->ops->get_status(skt, &status);
+@@ -430,7 +437,7 @@
+       msleep(initial_delay * 10);
+-      for (i = 0; i < 100; i++) {
++      for (i = 0; i < 100; i++) {     
+               skt->ops->get_status(skt, &status);
+               if (!(status & SS_DETECT))
+                       return CS_NO_CARD;
+diff -uNr linux-2.6.21.vanilla/drivers/pcmcia/sa1100_generic.c linux-2.6.21/drivers/pcmcia/sa1100_generic.c
+--- linux-2.6.21.vanilla/drivers/pcmcia/sa1100_generic.c       2007-05-30 18:00:30.000000000 +0200
++++ linux-2.6.21/drivers/pcmcia/sa1100_generic.c       2007-05-30 18:00:40.000000000 +0200
+@@ -28,6 +28,9 @@
+     the provisions above, a recipient may use your version of this
+     file under either the MPL or the GPL.
+     
++    2007 mrnice: added thesings changes from device_driver
++            to platform_driver - many thx to thesing
++
+ ======================================================================*/
+ #include <linux/module.h>
+@@ -81,13 +84,15 @@
+       return ret;
+ }
+-static struct device_driver sa11x0_pcmcia_driver = {
+-      .probe          = sa11x0_drv_pcmcia_probe,
+-      .remove         = soc_common_drv_pcmcia_remove,
+-      .name           = "sa11x0-pcmcia",
+-      .bus            = &platform_bus_type,
+-      .suspend        = pcmcia_socket_dev_suspend,
+-      .resume         = pcmcia_socket_dev_resume,
++static struct platform_driver sa11x0_pcmcia_driver = {
++       .driver        = {
++              .name   = "sa11x0-pcmcia",
++              .probe = sa11x0_drv_pcmcia_probe,
++              .remove        = soc_common_drv_pcmcia_remove,
++              .suspend= pcmcia_socket_dev_suspend,
++              .resume        = pcmcia_socket_dev_resume,
++              //.bus = &platform_bus_type,
++       },
+ };
+ /* sa11x0_pcmcia_init()
+@@ -100,7 +105,7 @@
+  */
+ static int __init sa11x0_pcmcia_init(void)
+ {
+-      return driver_register(&sa11x0_pcmcia_driver);
++        return platform_driver_register(&sa11x0_pcmcia_driver);
+ }
+ /* sa11x0_pcmcia_exit()
+@@ -110,7 +115,7 @@
+  */
+ static void __exit sa11x0_pcmcia_exit(void)
+ {
+-      driver_unregister(&sa11x0_pcmcia_driver);
++        platform_driver_unregister(&sa11x0_pcmcia_driver);
+ }
+ MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
+diff -uNr linux-2.6.21.vanilla/drivers/pcmcia/sa1100_simpad.c linux-2.6.21/drivers/pcmcia/sa1100_simpad.c
+--- linux-2.6.21.vanilla/drivers/pcmcia/sa1100_simpad.c        2007-05-30 18:00:30.000000000 +0200
++++ linux-2.6.21/drivers/pcmcia/sa1100_simpad.c        2007-05-30 18:08:53.000000000 +0200
+@@ -3,6 +3,8 @@
+  *
+  * PCMCIA implementation routines for simpad
+  *
++ * mrdata: -added cs3_ro stuff to get fix voltage issue 
++ *
+  */
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+@@ -14,7 +16,8 @@
+ #include <asm/irq.h>
+ #include <asm/arch/simpad.h>
+ #include "sa1100_generic.h"
+- 
++
++extern long get_cs3_ro(void); 
+ extern long get_cs3_shadow(void);
+ extern void set_cs3_bit(int value); 
+ extern void clear_cs3_bit(int value);
+@@ -25,7 +28,6 @@
+ static int simpad_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+ {
+-
+       clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
+       skt->irq = IRQ_GPIO_CF_IRQ;
+@@ -47,21 +49,15 @@
+                          struct pcmcia_state *state)
+ {
+       unsigned long levels = GPLR;
+-      long cs3reg = get_cs3_shadow();
++      long cs3_ro_reg = get_cs3_ro();
+-      state->detect=((levels & GPIO_CF_CD)==0)?1:0;
+-      state->ready=(levels & GPIO_CF_IRQ)?1:0;
+-      state->bvd1=1; /* Not available on Simpad. */
+-      state->bvd2=1; /* Not available on Simpad. */
+-      state->wrprot=0; /* Not available on Simpad. */
+-  
+-      if((cs3reg & 0x0c) == 0x0c) {
+-              state->vs_3v=0;
+-              state->vs_Xv=0;
+-      } else {
+-              state->vs_3v=1;
+-              state->vs_Xv=0;
+-      }
++      state->detect = ((levels & GPIO_CF_CD) == 0) ? 1 : 0 ;
++      state->ready  = (levels & GPIO_CF_IRQ) ? 1 : 0 ;
++      state->bvd1   = (cs3_ro_reg & PCMCIA_BVD1) ? 1 : 0 ; /* alt: =1 Not available on Simpad. */
++      state->bvd2   = (cs3_ro_reg & PCMCIA_BVD2) ? 1 : 0 ; /* alt: =1 Not available on Simpad. */
++      state->wrprot = 0 ; /* Not available on Simpad. */  
++      state->vs_3v = (cs3_ro_reg & PCMCIA_VS1) ? 0 : 1 ;
++      state->vs_Xv = (cs3_ro_reg & PCMCIA_VS2) ? 0 : 1 ;
+ }
+ static int
+@@ -104,6 +100,7 @@
+ static void simpad_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
+ {
++      clear_cs3_bit(PCMCIA_RESET);
+       soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
+ }
diff --git a/packages/linux/linux/simpad/linux-2.6.21-SIMpad-serial-gpio_keys-and-cs3-ro.patch b/packages/linux/linux/simpad/linux-2.6.21-SIMpad-serial-gpio_keys-and-cs3-ro.patch
new file mode 100644 (file)
index 0000000..081afc8
--- /dev/null
@@ -0,0 +1,332 @@
+diff -uNr linux-2.6.21.vanilla/arch/arm/mach-sa1100/simpad.c linux-2.6.21/arch/arm/mach-sa1100/simpad.c
+--- linux-2.6.21.vanilla/arch/arm/mach-sa1100/simpad.c 2007-05-30 18:00:29.000000000 +0200
++++ linux-2.6.21/arch/arm/mach-sa1100/simpad.c 2007-05-30 18:02:15.000000000 +0200
+@@ -1,5 +1,15 @@
+ /*
+  * linux/arch/arm/mach-sa1100/simpad.c
++ *
++ * 2007/04/11 mrdata:
++ *            - insert simpad_uart_set_mctrl()
++ *                     simpad_uart_get_mctrl()
++ *            - internal RS232/DECT/Bluetooth
++ *              works again (based on 2.4 simpad-serial.patch)
++ *            - added cs3_ro
++ *
++ * 2007/04/12 Bernhard Guillon: 
++ *            -added gpio_keys (based on h3000.c from hh.org)
+  */
+ #include <linux/module.h>
+@@ -9,6 +19,9 @@
+ #include <linux/proc_fs.h>
+ #include <linux/string.h> 
+ #include <linux/pm.h>
++
++#include <linux/apm-emulation.h>
++
+ #include <linux/platform_device.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
+@@ -27,12 +40,21 @@
+ #include <linux/serial_core.h>
+ #include <linux/ioport.h>
++#include <linux/input.h>
++#include <linux/gpio_keys.h>
+ #include <asm/io.h>
+ #include "generic.h"
++long cs3_ro;
+ long cs3_shadow;
++long get_cs3_ro(void)
++{
++      cs3_ro = *(CS3BUSTYPE *)(CS3_BASE);
++      return cs3_ro;
++}
++
+ long get_cs3_shadow(void)
+ {
+       return cs3_shadow;
+@@ -55,9 +77,12 @@
+       *(CS3BUSTYPE *)(CS3_BASE) = cs3_shadow;
+ }
++EXPORT_SYMBOL(get_cs3_ro);
++EXPORT_SYMBOL(get_cs3_shadow);
+ EXPORT_SYMBOL(set_cs3_bit);
+ EXPORT_SYMBOL(clear_cs3_bit);
++
+ static struct map_desc simpad_io_desc[] __initdata = {
+       {       /* MQ200 */
+               .virtual        =  0xf2800000,
+@@ -73,23 +98,71 @@
+ };
++static void simpad_uart_set_mctrl(struct uart_port *port, u_int mctrl)
++{
++        if (port->mapbase == _Ser1UTCR0) {
++                /* internal serial port (ttySA1, DECT/Bluetooth) */
++                if (mctrl & TIOCM_RTS)  GPCR = GPIO_UART1_RTS;
++                else                    GPSR = GPIO_UART1_RTS;
++
++                if (mctrl & TIOCM_DTR)  GPCR = GPIO_UART1_DTR;
++                else                    GPSR = GPIO_UART1_DTR;
++        }
++
++        else if (port->mapbase == _Ser3UTCR0) {
++                /* external serial port (ttySA0, RS232) */
++                if (mctrl & TIOCM_RTS)  GPCR = GPIO_UART3_RTS;
++                else                    GPSR = GPIO_UART3_RTS;
++
++                if (mctrl & TIOCM_DTR)  GPCR = GPIO_UART3_DTR;
++                else                    GPSR = GPIO_UART3_DTR;
++        }              
++}
++
++
++static u_int simpad_uart_get_mctrl(struct uart_port *port)
++{
++        u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
++       
++        if (port->mapbase == _Ser1UTCR0) {
++                /* internal serial port (ttySA1, DECT/Bluetooth) */
++                int gplr = GPLR;
++                if (gplr & GPIO_UART1_DCD) ret &= ~TIOCM_CD;
++                if (gplr & GPIO_UART1_CTS) ret &= ~TIOCM_CTS;
++                if (gplr & GPIO_UART1_DSR) ret &= ~TIOCM_DSR;
++        }
++       
++        else if (port->mapbase == _Ser3UTCR0) {
++                /* external serial port (ttySA0, RS232) */
++                int gplr = GPLR;
++                if (gplr & GPIO_UART3_DCD) ret &= ~TIOCM_CD;
++                if (gplr & GPIO_UART3_CTS) ret &= ~TIOCM_CTS;
++                if (gplr & GPIO_UART3_DSR) ret &= ~TIOCM_DSR;
++        }
++        return ret;
++}
++
++
+ static void simpad_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
+ {
+-      if (port->mapbase == (u_int)&Ser1UTCR0) {
+-              if (state)
+-              {
+-                      clear_cs3_bit(RS232_ON);
+-                      clear_cs3_bit(DECT_POWER_ON);
+-              }else
+-              {
+-                      set_cs3_bit(RS232_ON);
+-                      set_cs3_bit(DECT_POWER_ON);
+-              }
+-      }
++        if (port->mapbase == (u_int)&Ser3UTCR0) {
++                if (state)
++                {
++                        clear_cs3_bit(RS232_ON);
++                        /* clear_cs3_bit(DECT_POWER_ON); */
++                }else
++                {
++                        set_cs3_bit(RS232_ON);
++                        /* set_cs3_bit(DECT_POWER_ON); */
++                }
++        }
+ }
++
+ static struct sa1100_port_fns simpad_port_fns __initdata = {
+-      .pm        = simpad_uart_pm,
++        .set_mctrl = simpad_uart_set_mctrl,
++        .get_mctrl = simpad_uart_get_mctrl,
++        .pm        = simpad_uart_pm,
+ };
+@@ -135,7 +208,6 @@
+ };
+-
+ static void __init simpad_map_io(void)
+ {
+       sa1100_map_io();
+@@ -144,13 +216,12 @@
+       set_cs3_bit (EN1 | EN0 | LED2_ON | DISPLAY_ON | RS232_ON |
+                     ENABLE_5V | RESET_SIMCARD | DECT_POWER_ON);
+-
+-
++                    
+         sa1100_register_uart_fns(&simpad_port_fns);
+       sa1100_register_uart(0, 3);  /* serial interface */
+       sa1100_register_uart(1, 1);  /* DECT             */
+-      // Reassign UART 1 pins
++      /* Reassign UART 1 pins */
+       GAFR |= GPIO_UART_TXD | GPIO_UART_RXD;
+       GPDR |= GPIO_UART_TXD | GPIO_LDD13 | GPIO_LDD15;
+       GPDR &= ~GPIO_UART_RXD;
+@@ -160,7 +231,6 @@
+        * Set up registers for sleep mode.
+        */
+-
+       PWER = PWER_GPIO0| PWER_RTC;
+       PGSR = 0x818;
+       PCFR = 0;
+@@ -171,9 +241,10 @@
+       sa11x0_set_mcp_data(&simpad_mcp_data);
+ }
++
+ static void simpad_power_off(void)
+ {
+-      local_irq_disable(); // was cli
++      local_irq_disable(); /* was cli */
+       set_cs3(0x800);        /* only SD_MEDIAQ */
+       /* disable internal oscillator, float CS lines */
+@@ -191,31 +262,52 @@
+       while(1);
+       local_irq_enable(); /* we won't ever call it */
++}
+-}
++/*
++ * gpio_keys
++*/
++
++static struct gpio_keys_button simpad_button_table[] = {
++      { KEY_POWER, IRQ_GPIO_POWER_BUTTON, 1, "power button" },
++};
++
++static struct gpio_keys_platform_data simpad_keys_data = {
++      .buttons = simpad_button_table,
++      .nbuttons = ARRAY_SIZE(simpad_button_table),
++};
++
++static struct platform_device simpad_keys = {
++      .name = "gpio-keys",
++      .dev = {
++              .platform_data = &simpad_keys_data,
++      },
++};
+ /*
+  * MediaQ Video Device
+  */
++
+ static struct platform_device simpad_mq200fb = {
+       .name = "simpad-mq200",
+       .id   = 0,
+ };
++
+ static struct platform_device *devices[] __initdata = {
+-      &simpad_mq200fb
++      &simpad_keys,
++      &simpad_mq200fb,
+ };
+-
+ static int __init simpad_init(void)
+ {
+       int ret;
+       pm_power_off = simpad_power_off;
+-
++      
+       ret = platform_add_devices(devices, ARRAY_SIZE(devices));
+       if(ret)
+               printk(KERN_WARNING "simpad: Unable to register mq200 framebuffer device");
+diff -uNr linux-2.6.21.vanilla/include/asm-arm/arch-sa1100/simpad.h linux-2.6.21/include/asm-arm/arch-sa1100/simpad.h
+--- linux-2.6.21.vanilla/include/asm-arm/arch-sa1100/simpad.h  2007-05-30 18:00:30.000000000 +0200
++++ linux-2.6.21/include/asm-arm/arch-sa1100/simpad.h  2007-05-30 18:02:56.000000000 +0200
+@@ -12,11 +12,12 @@
+ #define __ASM_ARCH_SIMPAD_H
+-#define GPIO_UART1_RTS        GPIO_GPIO14
++#define GPIO_UART1_RTS        GPIO_GPIO9
+ #define GPIO_UART1_DTR        GPIO_GPIO7
+ #define GPIO_UART1_CTS        GPIO_GPIO8
+ #define GPIO_UART1_DCD        GPIO_GPIO23
+ #define GPIO_UART1_DSR        GPIO_GPIO6
++#define GPIO_UART1_RI GPIO_GPIO19
+ #define GPIO_UART3_RTS        GPIO_GPIO12
+ #define GPIO_UART3_DTR        GPIO_GPIO16
+@@ -48,9 +49,9 @@
+ #define GPIO_SMART_CARD               GPIO_GPIO10
+ #define IRQ_GPIO_SMARD_CARD   IRQ_GPIO10
+-// CS3 Latch is write only, a shadow is necessary
++// CS3 Latch is write only 16-bit , a shadow is necessary
+-#define CS3BUSTYPE unsigned volatile long
++#define CS3BUSTYPE      unsigned volatile long
+ #define CS3_BASE        0xf1000000
+ #define VCC_5V_EN       0x0001 // For 5V PCMCIA
+@@ -70,43 +71,17 @@
+ #define ENABLE_5V       0x4000 // Enable 5V circuit
+ #define RESET_SIMCARD   0x8000
+-#define RS232_ENABLE    0x0440
+-#define PCMCIAMASK      0x402f
++// CS3 Latch is readable only 8-bit interest
++#define PCMCIA_BVD1     0x0001
++#define PCMCIA_BVD2     0x0002
++#define PCMCIA_VS1      0x0004   // PCMCIA card voltage select
++#define PCMCIA_VS2      0x0008   // PCMCIA card voltage select, if both are in high state -> 5V PCMCIA card
++#define LOCK_IND        0x0010
++#define CHARGING_STATE  0x0020   // Ladestatus
++#define PCMCIA_SHORT    0x0040   // low active
+-struct simpad_battery {
+-      unsigned char ac_status;        /* line connected yes/no */
+-      unsigned char status;           /* battery loading yes/no */
+-      unsigned char percentage;       /* percentage loaded */
+-      unsigned short life;            /* life till empty */
+-};
+-
+-/* These should match the apm_bios.h definitions */
+-#define SIMPAD_AC_STATUS_AC_OFFLINE      0x00
+-#define SIMPAD_AC_STATUS_AC_ONLINE       0x01
+-#define SIMPAD_AC_STATUS_AC_BACKUP       0x02   /* What does this mean? */
+-#define SIMPAD_AC_STATUS_AC_UNKNOWN      0xff
+-
+-/* These bitfields are rarely "or'd" together */
+-#define SIMPAD_BATT_STATUS_HIGH          0x01
+-#define SIMPAD_BATT_STATUS_LOW           0x02
+-#define SIMPAD_BATT_STATUS_CRITICAL      0x04
+-#define SIMPAD_BATT_STATUS_CHARGING      0x08
+-#define SIMPAD_BATT_STATUS_CHARGE_MAIN   0x10
+-#define SIMPAD_BATT_STATUS_DEAD          0x20   /* Battery will not charge */
+-#define SIMPAD_BATT_NOT_INSTALLED        0x20   /* For expansion pack batteries */
+-#define SIMPAD_BATT_STATUS_FULL          0x40   /* Battery fully charged (and connected to AC) */
+-#define SIMPAD_BATT_STATUS_NOBATT        0x80
+-#define SIMPAD_BATT_STATUS_UNKNOWN       0xff
+-
+-extern int simpad_get_battery(struct simpad_battery* );
++#define RS232_ENABLE    0x0440
++#define PCMCIAMASK      0x402f
+ #endif // __ASM_ARCH_SIMPAD_H
+-
+-
+-
+-
+-
+-
+-
+-
diff --git a/packages/linux/linux/simpad/linux-2.6.21-SIMpad-ucb1x00-ts-supend-and-accuracy.patch b/packages/linux/linux/simpad/linux-2.6.21-SIMpad-ucb1x00-ts-supend-and-accuracy.patch
new file mode 100644 (file)
index 0000000..8c2c892
--- /dev/null
@@ -0,0 +1,121 @@
+diff -uNr linux-2.6.21.vanilla/drivers/mfd/ucb1x00-ts.c linux-2.6.21/drivers/mfd/ucb1x00-ts.c
+--- linux-2.6.21.vanilla/drivers/mfd/ucb1x00-ts.c      2007-05-30 18:00:30.000000000 +0200
++++ linux-2.6.21/drivers/mfd/ucb1x00-ts.c      2007-05-30 18:14:42.000000000 +0200
+@@ -16,6 +16,10 @@
+  * It is important to note that the signal connected to the ADCSYNC
+  * pin should provide pulses even when the LCD is blanked, otherwise
+  * a pen touch needed to unblank the LCD will never be read.
++ *
++ * mrdata: -added some accuracy improvement based on thesings collie patch
++ *         -added suspend fix 
++ *
+  */
+ #include <linux/module.h>
+ #include <linux/moduleparam.h>
+@@ -105,6 +109,8 @@
+                                 UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
+                                 UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
++              udelay(55);
++
+               return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync);
+       }
+ }
+@@ -131,7 +137,7 @@
+                       UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
+                       UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
+-      udelay(55);
++      udelay(165);
+       return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync);
+ }
+@@ -159,7 +165,7 @@
+                       UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
+                       UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
+-      udelay(55);
++      udelay(165);
+       return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync);
+ }
+@@ -225,13 +231,17 @@
+               signed long timeout;
+               ts->restart = 0;
+-
++              
+               ucb1x00_adc_enable(ts->ucb);
+               x = ucb1x00_ts_read_xpos(ts);
++              ucb1x00_adc_disable(ts->ucb);           
++              ucb1x00_adc_enable(ts->ucb);
+               y = ucb1x00_ts_read_ypos(ts);
++              ucb1x00_adc_disable(ts->ucb);           
++              ucb1x00_adc_enable(ts->ucb);            
+               p = ucb1x00_ts_read_pressure(ts);
+-
++              
+               /*
+                * Switch back to interrupt mode.
+                */
+@@ -240,15 +250,19 @@
+               msleep(10);
++              if ((x < 60) || (y < 60)) {
++                      p = 0;
++              } 
++              
+               ucb1x00_enable(ts->ucb);
+-
+               if (ucb1x00_ts_pen_down(ts)) {
++              
+                       set_task_state(tsk, TASK_INTERRUPTIBLE);
+                       ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, machine_is_collie() ? UCB_RISING : UCB_FALLING);
+                       ucb1x00_disable(ts->ucb);
+-
++                      
+                       /*
+                        * If we spat out a valid sample set last time,
+                        * spit out a "pen off" sample here.
+@@ -259,7 +273,9 @@
+                       }
+                       timeout = MAX_SCHEDULE_TIMEOUT;
++                      
+               } else {
++              
+                       ucb1x00_disable(ts->ucb);
+                       /*
+@@ -278,6 +294,14 @@
+               try_to_freeze();
++              /*
++               * While suspend the ktsd-thread goes sleep -> try_to_freeze()
++               * While resume the ktsd-thread do wakup and must rune one time
++               * again to do a clean re-setup -> enable_irq: UCB_IRQ_TSPX
++               */             
++              if(ts->restart)
++                      timeout = HZ / 100;
++              
+               schedule_timeout(timeout);
+       }
+@@ -360,8 +384,12 @@
+                * TS interrupt mode is set up again
+                * after sleep.
+                */
++
+               ts->restart = 1;
+               wake_up(&ts->irq_wait);
++                              
++              printk(KERN_INFO "ucb1x00-ts.c -> ucb1x00_ts_resume() ktsd - restart *DONE*\n");
++                              
+       }
+       return 0;
+ }
diff --git a/packages/linux/linux/simpad/linux-2.6.21-SIMpad-usb-gadget.patch b/packages/linux/linux/simpad/linux-2.6.21-SIMpad-usb-gadget.patch
new file mode 100644 (file)
index 0000000..00d062b
--- /dev/null
@@ -0,0 +1,3329 @@
+diff -uNr linux-2.6.21.vanilla/drivers/usb/gadget/Kconfig linux-2.6.21/drivers/usb/gadget/Kconfig
+--- linux-2.6.21.vanilla/drivers/usb/gadget/Kconfig    2007-04-26 05:08:32.000000000 +0200
++++ linux-2.6.21/drivers/usb/gadget/Kconfig    2007-06-05 11:58:28.000000000 +0200
+@@ -205,6 +205,21 @@
+       depends on USB_GADGET_AT91
+       default USB_GADGET
++config USB_GADGET_SA1100
++      boolean "SA1100 USB Device Port"
++      depends on ARCH_SA1100
++      select USB_GADGET_SELECTED
++      help
++
++         Say "y" to link the driver statically, or "m" to build a
++         dynamically linked module called "sa1100_udc" and force all
++         gadget drivers to also be dynamically linked.
++
++config USB_SA1100
++      tristate
++      depends on USB_GADGET_SA1100
++      default USB_GADGET
++      
+ config USB_GADGET_DUMMY_HCD
+       boolean "Dummy HCD (DEVELOPMENT)"
+       depends on (USB=y || (USB=m && USB_GADGET=m)) && EXPERIMENTAL
+diff -uNr linux-2.6.21.vanilla/drivers/usb/gadget/Makefile linux-2.6.21/drivers/usb/gadget/Makefile
+--- linux-2.6.21.vanilla/drivers/usb/gadget/Makefile   2007-04-26 05:08:32.000000000 +0200
++++ linux-2.6.21/drivers/usb/gadget/Makefile   2007-06-05 11:58:28.000000000 +0200
+@@ -8,6 +8,7 @@
+ obj-$(CONFIG_USB_OMAP)                += omap_udc.o
+ obj-$(CONFIG_USB_LH7A40X)     += lh7a40x_udc.o
+ obj-$(CONFIG_USB_AT91)                += at91_udc.o
++obj-$(CONFIG_USB_SA1100)      += sa1100_udc.o
+ #
+ # USB gadget drivers
+diff -uNr linux-2.6.21.vanilla/drivers/usb/gadget/ether.c linux-2.6.21/drivers/usb/gadget/ether.c
+--- linux-2.6.21.vanilla/drivers/usb/gadget/ether.c    2007-04-26 05:08:32.000000000 +0200
++++ linux-2.6.21/drivers/usb/gadget/ether.c    2007-06-05 11:59:24.000000000 +0200
+@@ -1456,7 +1456,7 @@
+                       goto done_set_intf;
+               }
+-#ifdef DEV_CONFIG_CDC
++//#ifdef DEV_CONFIG_CDC
+               switch (wIndex) {
+               case 0:         /* control/master intf */
+                       if (wValue != 0)
+@@ -1498,12 +1498,12 @@
+                       value = 0;
+                       break;
+               }
+-#else
++//#else
+               /* FIXME this is wrong, as is the assumption that
+                * all non-PXA hardware talks real CDC ...
+                */
+-              dev_warn (&gadget->dev, "set_interface ignored!\n");
+-#endif /* DEV_CONFIG_CDC */
++//            dev_warn (&gadget->dev, "set_interface ignored!\n");
++//#endif /* DEV_CONFIG_CDC */
+ done_set_intf:
+               spin_unlock (&dev->lock);
+diff -uNr linux-2.6.21.vanilla/drivers/usb/gadget/sa1100_udc.c linux-2.6.21/drivers/usb/gadget/sa1100_udc.c
+--- linux-2.6.21.vanilla/drivers/usb/gadget/sa1100_udc.c       1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.21/drivers/usb/gadget/sa1100_udc.c       2007-06-05 11:58:29.000000000 +0200
+@@ -0,0 +1,2591 @@
++/*
++ * SA1100 USB Device Controller (UDC) driver.
++ *
++ * Copyright (C) Compaq Computer Corporation, 1998, 1999
++ * Copyright (C) Extenex Corporation, 2001
++ * Copyright (C) David Brownell, 2003
++ * Copyright (C) Nick Bane, 2005, 2006
++ *   Many fragments from pxa2xx_udc.c and mach-sa1100 driver with various 
++ *   GPL Copyright authors incl Russel king and Nicolas Pitre
++ *   Port to 2.6.12 by N C Bane
++ *
++ * This file provides interrupt routing and overall coordination for the
++ * sa1100 USB endpoints: ep0, ep1out-bulk, ep2out-bulk, as well as device
++ * initialization and some parts of USB "Chapter 9" device behavior.
++ *
++ * It implements the "USB gadget controller" API, abstracting most hardware
++ * details so that drivers running on top of this API are mostly independent
++ * of hardware.  A key exception is that ep0 logic needs to understand which
++ * endpoints a given controller has, and their capabilities.  Also, hardware
++ * that doesn't fully support USB (like sa1100) may need workarounds in the
++ * protocols implemented by device functions.
++ *
++ * See linux/Documentation/arm/SA1100/SA1100_USB for more info, or the
++ * kerneldoc for the API exposed to gadget drivers.
++ *
++ */
++#define DEBUG 1
++#define       VERBOSE 1
++
++//#define SA1100_USB_DEBUG
++#ifdef SA1100_USB_DEBUG
++static int sa1100_usb_debug=0;
++#endif
++
++#define NCB_DMA_FIX
++#ifdef NCB_DMA_FIX
++#include <linux/slab.h>
++#define SEND_BUFFER_SIZE 4096 /* this is probably a bit big */
++#define RECEIVE_BUFFER_SIZE 256       /* 64 may be all that is necessary */
++static char *send_buffer=NULL;
++static char *receive_buffer=NULL;
++#endif
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/ioport.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/smp_lock.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/timer.h>
++#include <linux/list.h>
++#include <linux/interrupt.h>
++#include <linux/version.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++
++#include <asm/byteorder.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/dma.h>
++#include <asm/system.h>
++#include <asm/mach-types.h>
++#include <asm/unaligned.h>
++
++#include <linux/usb.h>\r
++#include <linux/usb_ch9.h>
++#include <linux/usb_gadget.h>
++
++#if CONFIG_PROC_FS\r
++#include <linux/proc_fs.h>
++#endif
++
++#if defined(CONFIG_SA1100_BALLOON)
++#include <asm/arch/balloon.h>
++#endif
++
++#define       DRIVER_VERSION          __DATE__
++
++#define       DMA_ADDR_INVALID (~(dma_addr_t)0)
++
++
++static const char driver_name [] = "sa1100_udc";
++static const char driver_desc [] = "SA-1110 USB Device Controller";
++
++static const char ep0name [] = "ep0";
++
++#ifdef        DEBUG
++static char *type_string (u8 bmAttributes)
++{
++      switch ( (bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK) {
++      case USB_ENDPOINT_XFER_BULK:    return "bulk";
++      //case USB_ENDPOINT_XFER_ISOC:  return "iso";
++      case USB_ENDPOINT_XFER_INT:     return "intr";
++      };
++      return "control";
++}
++#endif
++
++#include <linux/dma-mapping.h>
++struct usb_stats_t {
++       unsigned long ep0_fifo_write_failures;
++       unsigned long ep0_bytes_written;
++       unsigned long ep0_fifo_read_failures;
++       unsigned long ep0_bytes_read;
++};
++
++struct usb_info_t
++{
++      dma_regs_t *dmaregs_tx, *dmaregs_rx;
++      int state;
++      unsigned char address;
++      struct usb_stats_t stats;
++};
++
++enum { kError=-1, kEvSuspend=0, kEvReset=1,
++         kEvResume=2, kEvAddress=3, kEvConfig=4, kEvDeConfig=5 };
++int usbctl_next_state_on_event( int event ) {
++    return 0;
++}
++static struct usb_info_t usbd_info;
++
++/* receiver */
++void ep1_reset(void);
++void ep1_stall(void);
++int sa1100_usb_recv (struct usb_request *req, void (*callback) (int,int));
++
++/* xmitter */
++void ep2_reset(void);
++void ep2_stall(void);
++int sa1100_usb_send (struct usb_request *req, void (*callback) (int,int));
++
++/* UDC register utility functions */
++#define UDC_write(reg, val) { \
++      int i = 10000; \
++      do { \
++              (reg) = (val); \
++              if (i-- <= 0) { \
++                      printk( "%s [%d]: write %#x to %p (%#x) failed\n", \
++                              __FUNCTION__, __LINE__, (val), &(reg), (reg)); \
++                      break; \
++              } \
++      } while((reg) != (val)); \
++}
++
++#define UDC_set(reg, val) { \
++      int i = 10000; \
++      do { \
++              (reg) |= (val); \
++              if (i-- <= 0) { \
++                      printk( "%s [%d]: set %#x of %p (%#x) failed\n", \
++                              __FUNCTION__, __LINE__, (val), &(reg), (reg)); \
++                      break; \
++              } \
++      } while(!((reg) & (val))); \
++}
++
++#define UDC_clear(reg, val) { \
++      int i = 10000; \
++      do { \
++              (reg) &= ~(val); \
++              if (i-- <= 0) { \
++                      printk( "%s [%d]: clear %#x of %p (%#x) failed\n", \
++                              __FUNCTION__, __LINE__, (val), &(reg), (reg)); \
++                      break; \
++              } \
++      } while((reg) & (val)); \
++}
++
++#define UDC_flip(reg, val) { \
++      int i = 10000; \
++      (reg) = (val); \
++      do { \
++              (reg) = (val); \
++              if (i-- <= 0) { \
++                      printk( "%s [%d]: flip %#x of %p (%#x) failed\n", \
++                              __FUNCTION__, __LINE__, (val), &(reg), (reg)); \
++                      break; \
++              } \
++      } while(((reg) & (val))); \
++}
++
++#include "sa1100_udc.h"
++
++static struct sa1100_udc      *the_controller;
++static void nuke (struct sa1100_ep *, int status);
++static void done (struct sa1100_ep *ep, struct sa1100_request *req, int status);
++static inline void ep0_idle (struct sa1100_udc *dev)
++{
++      dev->ep0state = EP0_IDLE;
++}
++
++// ep0 handlers
++
++// 1 == lots of trace noise,  0 = only "important' stuff
++//#define VERBOSITY 1
++
++#ifndef MIN
++#define MIN( a, b ) ((a)<(b)?(a):(b))
++#endif
++
++#if 1 && !defined( ASSERT )
++#  define ASSERT(expr) \
++          if(!(expr)) { \
++          printk( "Assertion failed! %s,%s,%s,line=%d\n",\
++          #expr,__FILE__,__FUNCTION__,__LINE__); \
++          }
++#else
++#  define ASSERT(expr)
++#endif
++
++#if VERBOSITY
++#define PRINTKD(fmt, args...) printk( fmt , ## args)
++#else
++#define PRINTKD(fmt, args...)
++#endif
++
++/* USB Device Requests */
++typedef struct
++{
++    __u8 bmRequestType;
++    __u8 bRequest;
++    __u16 wValue;
++    __u16 wIndex;
++    __u16 wLength;
++} usb_dev_request_t  __attribute__ ((packed));
++
++/* other subroutines */
++unsigned int (*wrint)(void);
++void  ep0_int_hndlr( void );
++static void ep0_queue(void *buf, unsigned int req, unsigned int act);
++static void write_fifo( void );
++static int read_fifo( struct usb_ctrlrequest * p );
++
++/* some voodo helpers  01Mar01ww */
++static void set_cs_bits( __u32 set_bits );
++static void set_de( void );
++static void set_ipr( void );
++static void set_ipr_and_de( void );
++static bool clear_opr( void );
++
++/***************************************************************************
++Inline Helpers
++***************************************************************************/
++
++/* Data extraction from usb_request_t fields */
++enum { kTargetDevice=0, kTargetInterface=1, kTargetEndpoint=2 };
++static inline int request_target( __u8 b ) { return (int) ( b & 0x0F); }
++
++static inline int windex_to_ep_num( __u16 w ) { return (int) ( w & 0x000F); }
++inline int type_code_from_request( __u8 by ) { return (( by >> 4 ) & 3); }
++
++/* following is hook for self-powered flag in GET_STATUS. Some devices
++   .. might like to override and return real info */
++static inline bool self_powered_hook( void ) { return true; }
++
++#if VERBOSITY
++/* "pcs" == "print control status" */
++static inline void pcs( void )
++{
++       __u32 foo = Ser0UDCCS0;
++       printk( "%8.8X: %s %s %s %s\n",
++                       foo,
++                       foo & UDCCS0_SE ? "SE" : "",
++                       foo & UDCCS0_OPR ? "OPR" : "",
++                       foo & UDCCS0_IPR ? "IPR" : "",
++                       foo & UDCCS0_SST ? "SST" : ""
++       );
++}
++static inline void preq( struct usb_ctrlrequest * pReq )
++{
++       static char * tnames[] = { "dev", "intf", "ep", "oth" };
++       static char * rnames[] = { "std", "class", "vendor", "???" };
++       char * psz;
++       switch( pReq->bRequest ) {
++       case USB_REQ_GET_STATUS: psz = "get stat"; break;
++       case USB_REQ_CLEAR_FEATURE: psz = "clr feat"; break;
++       case USB_REQ_SET_FEATURE: psz = "set feat"; break;
++       case USB_REQ_SET_ADDRESS: psz = "set addr"; break;
++       case USB_REQ_GET_DESCRIPTOR: psz = "get desc"; break;
++       case USB_REQ_SET_DESCRIPTOR: psz = "set desc"; break;
++       case USB_REQ_GET_CONFIGURATION: psz = "get cfg"; break;
++       case USB_REQ_SET_CONFIGURATION: psz = "set cfg"; break;
++       case USB_REQ_GET_INTERFACE: psz = "get intf"; break;
++       case USB_REQ_SET_INTERFACE: psz = "set intf"; break;
++       default: psz = "unknown"; break;
++       }
++       printk( "- [%s: %s req to %s. dir=%s]\n", psz,
++                       rnames[ (pReq->bRequestType >> 5) & 3 ],
++                       tnames[ pReq->bRequestType & 3 ],
++                       ( pReq->bRequestType & 0x80 ) ? "in" : "out" );
++}
++
++static inline void usbctl_dump_request(const char *prefix, const struct usb_ctrlrequest *req)
++{
++      printk("%s: bRequestType=0x%02x bRequest=0x%02x "
++              "wValue=0x%04x wIndex=0x%04x wLength=0x%04x\n",
++              prefix, req->bRequestType, req->bRequest,
++              le16_to_cpu(req->wValue), le16_to_cpu(req->wIndex),
++              le16_to_cpu(req->wLength));
++}
++#else
++static inline void pcs( void ){}
++//static inline void preq( void ){}
++static inline void preq( void *x ){}
++static inline void usbctl_dump_request(const char *prefix, const struct usb_ctrlrequest *req) {}
++#endif
++
++/***************************************************************************
++Globals
++***************************************************************************/
++static const char pszMe[] = "usbep0: ";
++
++
++/* global write struct to keep write
++   ..state around across interrupts */
++static struct {
++              unsigned char *p;
++              int bytes_left;
++} wr;
++
++/***************************************************************************
++Public Interface
++***************************************************************************/
++
++/* reset received from HUB (or controller just went nuts and reset by itself!)
++  so udc core has been reset, track this state here  */
++void
++ep0_reset(void)
++{
++       /* reset state machine */
++       wr.p = NULL;
++       wr.bytes_left = 0;
++       usbd_info.address=0;
++// needed?  Ser0UDCAR = 0;
++}
++
++
++/* handle interrupt for endpoint zero */
++
++inline void ep0_clear_write(void) {
++      wr.p=NULL;
++      wr.bytes_left=0;
++}
++
++/* this is a config packet parser based on that from the updated HH 2.6 udc */
++static void
++ep0_read_packet( void )
++{
++       unsigned char status_buf[2];  /* returned in GET_STATUS */
++       struct usb_ctrlrequest req;
++       int request_type;
++       int n;
++       __u32 address;
++
++       /* reset previous count */
++       the_controller->ep0_req_len=-1;
++
++       /* read the setup request */
++       n = read_fifo( &req );
++       usbctl_dump_request("ep0_read_packet",&req);
++
++       if ( n != sizeof( req ) ) {
++                printk( "%ssetup begin: fifo READ ERROR wanted %d bytes got %d. "
++                                " Stalling out...\n",
++                                pszMe, sizeof( req ), n );
++                /* force stall, serviced out */
++                set_cs_bits( UDCCS0_FST | UDCCS0_SO  );
++                goto sh_sb_end;
++       }
++
++       /* Is it a standard request? (not vendor or class request) */
++       request_type = type_code_from_request( req.bRequestType );
++       if ( request_type != 0 ) {
++                printk( "%ssetup begin: unsupported bRequestType: %d ignored\n",
++                                pszMe, request_type );
++                set_cs_bits( UDCCS0_DE | UDCCS0_SO );
++                goto sh_sb_end;
++       }
++
++      /* save requested reply size */
++      the_controller->ep0_req_len=le16_to_cpu(req.wLength);
++      PRINTKD("%s: request length is %d\n",__FUNCTION__,the_controller->ep0_req_len);
++
++#if VERBOSITY
++       {
++       unsigned char * pdb = (unsigned char *) &req;
++       PRINTKD( "%2.2X %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X ",
++                       pdb[0], pdb[1], pdb[2], pdb[3], pdb[4], pdb[5], pdb[6], pdb[7]
++                );
++       preq( &req );
++       }
++#endif
++
++       /* Handle it */
++       switch( req.bRequest ) {
++
++                /* This first bunch have no data phase */
++
++       case USB_REQ_SET_ADDRESS:
++                address = (__u32) (req.wValue & 0x7F);
++                /* when SO and DE sent, UDC will enter status phase and ack,
++                       ..propagating new address to udc core. Next control transfer
++                       ..will be on the new address. You can't see the change in a
++                       ..read back of CAR until then. (about 250us later, on my box).
++                       ..The original Intel driver sets S0 and DE and code to check
++                       ..that address has propagated here. I tried this, but it
++                       ..would only work sometimes! The rest of the time it would
++                       ..never propagate and we'd spin forever. So now I just set
++                       ..it and pray...
++                */
++                Ser0UDCAR = address;
++                usbd_info.address = address;
++                usbctl_next_state_on_event( kEvAddress );
++                set_cs_bits( UDCCS0_SO | UDCCS0_DE );  /* no data phase */
++                printk( "%sI have been assigned address: %d\n", pszMe, address );
++                break;
++
++
++       case USB_REQ_SET_CONFIGURATION:
++                if ( req.wValue == 1 ) {
++                         /* configured */
++                         if (usbctl_next_state_on_event( kEvConfig ) != kError) {
++                              /* (re)set the out and in max packet sizes */
++                              PRINTKD( "%s: calling the_controller.driver->setup with SET_CONFIGURATION\n", __FUNCTION__ );
++                              the_controller->driver->setup(&the_controller->gadget, &req);
++                                      __u32 in  = __le16_to_cpu( the_controller->ep[1].ep.maxpacket );
++                                      __u32 out = __le16_to_cpu( the_controller->ep[2].ep.maxpacket );
++                                      Ser0UDCOMP = ( out - 1 );
++                                      Ser0UDCIMP = ( in - 1 );
++                              // we are configured
++                              usbd_info.state = USB_STATE_CONFIGURED;
++                              // enable rx and tx interrupts
++                              Ser0UDCCR &= ~(UDCCR_RIM | UDCCR_TIM);
++
++                              printk( "%sConfigured (OMP=%8.8X IMP=%8.8X)\n", pszMe, out, in );
++                              break;
++                         }
++                } else if ( req.wValue == 0 ) {
++                         /* de-configured */
++                         if (usbctl_next_state_on_event( kEvDeConfig ) != kError )
++                                      printk( "%sDe-Configured\n", pszMe );
++                      usbd_info.state = 0;
++                      Ser0UDCCR |= UDCCR_RIM | UDCCR_TIM;
++                      ep1_reset ();
++                      ep2_reset ();
++                      printk("%s: de-configured. Tx and Rx interrupts disabled. ep1 and ep2 reset\n",__FUNCTION__);
++                } else {
++                         printk( "%ssetup phase: Unknown "
++                                         "\"set configuration\" data %d\n",
++                                         pszMe, req.wValue );
++                }
++                set_cs_bits( UDCCS0_SO | UDCCS0_DE );  /* no data phase */
++                break;
++
++       case USB_REQ_CLEAR_FEATURE:
++                /* could check data length, direction...26Jan01ww */
++                if ( req.wValue == 0 ) { /* clearing ENDPOINT_HALT/STALL */
++                         int ep = windex_to_ep_num( req.wIndex );
++                         if ( ep == 1 ) {
++                                      printk( "%sclear feature \"endpoint halt\" "
++                                                      " on receiver\n", pszMe );
++                                      ep1_reset();
++                         }
++                         else if ( ep == 2 ) {
++                                      printk( "%sclear feature \"endpoint halt\" "
++                                                      "on xmitter\n", pszMe );
++                                      ep2_reset();
++                         } else {
++                                      printk( "%sclear feature \"endpoint halt\" "
++                                                      "on unsupported ep # %d\n",
++                                                      pszMe, ep );
++                         }
++                } else {
++                         printk( "%sUnsupported feature selector (%d) "
++                                         "in clear feature. Ignored.\n" ,
++                                         pszMe, req.wValue );
++                }
++                set_cs_bits( UDCCS0_SO | UDCCS0_DE );  /* no data phase */
++                break;
++
++       case USB_REQ_SET_FEATURE:
++                if ( req.wValue == 0 ) { /* setting ENDPOINT_HALT/STALL */
++                         int ep = windex_to_ep_num( req.wValue );
++                         if ( ep == 1 ) {
++                                      printk( "%set feature \"endpoint halt\" "
++                                                      "on receiver\n", pszMe );
++                                      ep1_stall();
++                         }
++                         else if ( ep == 2 ) {
++                                      printk( "%sset feature \"endpoint halt\" "
++                                                      " on xmitter\n", pszMe );
++                                      ep2_stall();
++                         } else {
++                                      printk( "%sset feature \"endpoint halt\" "
++                                                      "on unsupported ep # %d\n",
++                                                      pszMe, ep );
++                         }
++                }
++                else {
++                         printk( "%sUnsupported feature selector "
++                                         "(%d) in set feature\n",
++                                         pszMe, req.wValue );
++                }
++                set_cs_bits( UDCCS0_SO | UDCCS0_DE );  /* no data phase */
++                break;
++
++                /* The rest have a data phase that writes back to the host */
++       case USB_REQ_GET_STATUS:
++                /* return status bit flags */
++                status_buf[0] = status_buf[1] = 0;
++                n = request_target(req.bRequestType);
++                switch( n ) {
++                case kTargetDevice:
++                         if ( self_powered_hook() )
++                                      status_buf[0] |= 1;
++                         break;
++                case kTargetInterface:
++                         break;
++                case kTargetEndpoint:
++                         /* return stalled bit */
++                         n = windex_to_ep_num( req.wIndex );
++                         if ( n == 1 )
++                                      status_buf[0] |= (Ser0UDCCS1 & UDCCS1_FST) >> 4;
++                         else if ( n == 2 )
++                                      status_buf[0] |= (Ser0UDCCS2 & UDCCS2_FST) >> 5;
++                         else {
++                                      printk( "%sUnknown endpoint (%d) "
++                                                      "in GET_STATUS\n", pszMe, n );
++                         }
++                         break;
++                default:
++                         printk( "%sUnknown target (%d) in GET_STATUS\n",
++                                         pszMe, n );
++                         /* fall thru */
++                         break;
++                }
++                PRINTKD("%s: GET_STATUS writing %d\n",__FUNCTION__,req.wLength);
++                ep0_queue( status_buf, req.wLength, sizeof( status_buf ));
++                break;
++       case USB_REQ_GET_DESCRIPTOR:
++                PRINTKD( "%s: calling the_controller.driver->setup with GET_DESCRIPTOR\n", __FUNCTION__ );
++                the_controller->driver->setup(&the_controller->gadget, &req);
++                break;
++       case USB_REQ_GET_CONFIGURATION:
++                PRINTKD( "%s: calling the_controller.driver->setup with GET_CONFIGURATION\n", __FUNCTION__ );
++                the_controller->driver->setup(&the_controller->gadget, &req);
++                break;
++       case USB_REQ_GET_INTERFACE:
++                PRINTKD( "%s: calling the_controller->driver->setup with GET_INTERFACE\n", __FUNCTION__ );
++                the_controller->driver->setup(&the_controller->gadget, &req);
++                break;
++       case USB_REQ_SET_INTERFACE:
++                PRINTKD( "%s: calling the_controller->driver->setup with SET_INTERFACE\n", __FUNCTION__ );
++                the_controller->driver->setup(&the_controller->gadget, &req);
++                break;
++       default :
++                printk("%sunknown request 0x%x\n", pszMe, req.bRequest);
++                break;
++       } /* switch( bRequest ) */
++
++sh_sb_end:
++       return;
++
++}
++
++void
++ep0_int_hndlr( void )
++{
++      u32 cs_reg_in;
++
++      pcs();
++
++      cs_reg_in = Ser0UDCCS0;
++
++
++      /*
++       * If "setup end" has been set, the usb controller has terminated
++       * a setup transaction before we set DE. This happens during
++       * enumeration with some hosts. For example, the host will ask for
++       * our device descriptor and specify a return of 64 bytes. When we
++       * hand back the first 8, the host will know our max packet size
++       * and turn around and issue a new setup immediately. This causes
++       * the UDC to auto-ack the new setup and set SE. We must then
++       * "unload" (process) the new setup, which is what will happen
++       * after this preamble is finished executing.
++       */
++      if (cs_reg_in & UDCCS0_SE) {
++              PRINTKD("UDC: early termination of setup\n");
++
++              /*
++               * Clear setup end
++               */
++              set_cs_bits(UDCCS0_SSE);
++
++              /*
++               * Clear any pending write.
++               */
++              ep0_clear_write();
++      }
++
++      /*
++       * UDC sent a stall due to a protocol violation.
++       */
++      if (cs_reg_in & UDCCS0_SST) {
++//            usb->ep0_stall_sent++;
++
++              PRINTKD("UDC: write_preamble: UDC sent stall\n");
++
++              /*
++               * Clear sent stall
++               */
++              set_cs_bits(UDCCS0_SST);
++
++              /*
++               * Clear any pending write.
++               */
++              ep0_clear_write();
++      }
++
++      switch (cs_reg_in & (UDCCS0_OPR | UDCCS0_IPR)) {
++      case UDCCS0_OPR | UDCCS0_IPR:
++              PRINTKD("UDC: write_preamble: see OPR. Stopping write to "
++                      "handle new SETUP\n");
++
++              /*
++               * very rarely, you can get OPR and
++               * leftover IPR. Try to clear
++               */
++              UDC_clear(Ser0UDCCS0, UDCCS0_IPR);
++
++              /*
++               * Clear any pending write.
++               */
++              ep0_clear_write();
++
++              /*FALLTHROUGH*/
++      case UDCCS0_OPR:
++              /*
++               * A new setup request is pending.  Handle
++               * it. Note that we don't try to read a
++               * packet if SE was set and OPR is clear.
++               */
++              ep0_read_packet();
++              break;
++
++      case 0:
++              // if data pending ...
++              if (wr.p) {
++                      unsigned int cs_bits = 0;
++                      if (wr.bytes_left != 0) {
++                              /*
++                               * More data to go
++                               */
++                              write_fifo();
++                              // packet ready
++                              cs_bits |= UDCCS0_IPR;
++                      }
++
++                      if (wr.bytes_left == 0) {
++                              /*
++                               * All data sent.
++                               */
++                              cs_bits |= wrint();
++                              // a null packet may be following
++                              if (!wrint)
++                                  ep0_clear_write();                          
++                      }
++                      set_cs_bits(cs_bits);
++              }
++              else
++                  PRINTKD("%s: No data - probably an ACK\n",__FUNCTION__);
++              break;
++
++      case UDCCS0_IPR:
++              PRINTKD("UDC: IPR set, not writing\n");
++//            usb->ep0_early_irqs++;
++              break;
++      }
++
++      pcs();
++      PRINTKD( "-end-\n" );
++}
++
++static unsigned int ep0_sh_write_data(void)
++{
++      /*
++       * If bytes left is zero, we are coming in on the
++       * interrupt after the last packet went out. And
++       * we know we don't have to empty packet this
++       * transfer so just set DE and we are done
++       */
++      PRINTKD("UDC: normal packet ended\n");
++      wrint=NULL;
++      return UDCCS0_DE;
++}
++
++static unsigned int ep0_sh_write_with_empty_packet(void)
++{
++      /*
++       * If bytes left is zero, we are coming in on the
++       * interrupt after the last packet went out.
++       * We must do short packet suff, so set DE and IPR
++       */
++      PRINTKD("UDC: short packet sent\n");
++      wrint=NULL;
++      return UDCCS0_IPR | UDCCS0_DE;
++}
++
++static unsigned int ep0_sh_write_data_then_empty_packet(void)
++{
++      PRINTKD("UDC: last packet full. Send empty packet next\n");
++      wrint=ep0_sh_write_with_empty_packet;
++      return 0;
++}
++
++static void ep0_queue(void *buf, unsigned int len, unsigned int req_len)
++{
++      __u32 cs_reg_bits = UDCCS0_IPR;
++
++      PRINTKD("a=%d r=%d\n", len, req_len);
++
++      if (len == 0) {
++          // no output packet to wait for
++          printk("%s: zero byte packet being queued. Setting DE and OPR end exiting\n",__FUNCTION__);
++          set_cs_bits(UDCCS0_DE | UDCCS0_SO);
++          return;
++      }
++      
++      /*
++       * thou shalt not enter data phase until
++       * Out Packet Ready is clear
++       */
++      if (!clear_opr()) {
++              printk("UDC: SO did not clear OPR\n");
++              set_cs_bits(UDCCS0_DE | UDCCS0_SO);
++              return;
++      }
++
++      // note data to xmit stored
++      wr.p=buf;
++      wr.bytes_left=min(len, req_len);
++
++      // write the first block
++      write_fifo();
++
++      // done already?
++      if (wr.bytes_left == 0) {
++              /*
++               * out in one, so data end
++               */
++              cs_reg_bits |= UDCCS0_DE;
++              ep0_clear_write();
++      // rest is a shorter than expected reply?
++      } else if (len < req_len) {
++              /*
++               * we are going to short-change host
++               * so need nul to not stall
++               */
++               if (len % 8) {
++                  PRINTKD("%s: %d more to go ending in a short packet.\n",__FUNCTION__,wr.bytes_left);
++                  wrint=ep0_sh_write_with_empty_packet;
++              }
++              // unless we are on a packet boundary. Then send full packet plus null packet.
++              else {
++                  PRINTKD("%s: %d more to go then add empty packet.\n",__FUNCTION__,wr.bytes_left);
++                  wrint=ep0_sh_write_data_then_empty_packet;
++              }
++      } else {
++              /*
++               * we have as much or more than requested
++               */
++              PRINTKD("%s: %d more to go.\n",__FUNCTION__,wr.bytes_left);
++              wrint=ep0_sh_write_data;
++      }
++
++      /*
++       * note: IPR was set uncondtionally at start of routine
++       */
++      set_cs_bits(cs_reg_bits);
++}
++
++/*
++ * write_fifo()
++ * Stick bytes in the 8 bytes endpoint zero FIFO.
++ * This version uses a variety of tricks to make sure the bytes
++ * are written correctly. 1. The count register is checked to
++ * see if the byte went in, and the write is attempted again
++ * if not. 2. An overall counter is used to break out so we
++ * don't hang in those (rare) cases where the UDC reverses
++ * direction of the FIFO underneath us without notification
++ * (in response to host aborting a setup transaction early).
++ *
++ */
++static void write_fifo( void )
++{
++      int bytes_this_time = MIN( wr.bytes_left, 8 );
++      int bytes_written = 0;
++
++      PRINTKD( "WF=%d: ", bytes_this_time );
++
++      while( bytes_this_time-- ) {
++              unsigned int cwc;
++              int i;
++               PRINTKD( "%2.2X ", *wr.p );
++              cwc = Ser0UDCWC & 15;
++               i = 10;
++               do {
++                        Ser0UDCD0 = *wr.p;
++                        udelay( 20 );  /* voodo 28Feb01ww */
++               } while( (Ser0UDCWC &15) == cwc && --i );
++               
++               if ( i == 0 ) {
++                        printk( "%swrite_fifo: write failure\n", pszMe );
++                        usbd_info.stats.ep0_fifo_write_failures++;
++               }
++
++               wr.p++;
++               bytes_written++;
++      }
++      wr.bytes_left -= bytes_written;
++
++      /* following propagation voodo so maybe caller writing IPR in
++         ..a moment might actually get it to stick 28Feb01ww */
++      udelay( 300 );
++
++      usbd_info.stats.ep0_bytes_written += bytes_written;
++      PRINTKD( "L=%d WCR=%8.8X\n", wr.bytes_left, Ser0UDCWC );
++}
++/*
++ * read_fifo()
++ * Read 1-8 bytes out of FIFO and put in request.
++ * Called to do the initial read of setup requests
++ * from the host. Return number of bytes read.
++ *
++ * Like write fifo above, this driver uses multiple
++ * reads checked agains the count register with an
++ * overall timeout.
++ *
++ */
++static int
++read_fifo( struct usb_ctrlrequest * request )
++{
++      int bytes_read = 0;
++      int fifo_count;
++
++      unsigned char * pOut = (unsigned char*) request;
++
++      fifo_count = ( Ser0UDCWC & 0xFF );
++
++      ASSERT( fifo_count <= 8 );
++      PRINTKD( "RF=%d ", fifo_count );
++
++      while( fifo_count-- ) {
++              unsigned int cwc;
++              int i;
++              
++              cwc = Ser0UDCWC & 15;
++              
++               i = 10;
++               do {
++                        *pOut = (unsigned char) Ser0UDCD0;
++                        udelay( 20 );
++               } while( ( Ser0UDCWC & 15 ) == cwc && --i );
++               
++               if ( i == 0 ) {
++                        printk( "%sread_fifo(): read failure\n", pszMe );
++                        usbd_info.stats.ep0_fifo_read_failures++;
++               }
++               pOut++;
++               bytes_read++;
++      }
++
++      PRINTKD( "fc=%d\n", bytes_read );
++      usbd_info.stats.ep0_bytes_read++;
++      return bytes_read;
++}
++
++/* some voodo I am adding, since the vanilla macros just aren't doing it  1Mar01ww */
++
++#define ABORT_BITS ( UDCCS0_SST | UDCCS0_SE )
++#define OK_TO_WRITE (!( Ser0UDCCS0 & ABORT_BITS ))
++#define BOTH_BITS (UDCCS0_IPR | UDCCS0_DE)
++
++static void set_cs_bits( __u32 bits )
++{
++       if ( bits & ( UDCCS0_SO | UDCCS0_SSE | UDCCS0_FST | UDCCS0_SST) )
++                Ser0UDCCS0 = bits;
++       else if ( (bits & BOTH_BITS) == BOTH_BITS )
++                set_ipr_and_de();
++       else if ( bits & UDCCS0_IPR )
++                set_ipr();
++       else if ( bits & UDCCS0_DE )
++                set_de();
++}
++
++static void set_de( void )
++{
++       int i = 1;
++       while( 1 ) {
++                if ( OK_TO_WRITE ) {
++                              Ser0UDCCS0 |= UDCCS0_DE;
++                } else {
++                         PRINTKD( "%sQuitting set DE because SST or SE set\n", pszMe );
++                         break;
++                }
++                if ( Ser0UDCCS0 & UDCCS0_DE )
++                         break;
++                udelay( i );
++                if ( ++i == 50  ) {
++                         printk( "%sDangnabbbit! Cannot set DE! (DE=%8.8X CCS0=%8.8X)\n",
++                                         pszMe, UDCCS0_DE, Ser0UDCCS0 );
++                         break;
++                }
++       }
++}
++
++static void set_ipr( void )
++{
++       int i = 1;
++       while( 1 ) {
++                if ( OK_TO_WRITE ) {
++                              Ser0UDCCS0 |= UDCCS0_IPR;
++                } else {
++                         PRINTKD( "%sQuitting set IPR because SST or SE set\n", pszMe );
++                         break;
++                }
++                if ( Ser0UDCCS0 & UDCCS0_IPR )
++                         break;
++                udelay( i );
++                if ( ++i == 50  ) {
++                         printk( "%sDangnabbbit! Cannot set IPR! (IPR=%8.8X CCS0=%8.8X)\n",
++                                         pszMe, UDCCS0_IPR, Ser0UDCCS0 );
++                         break;
++                }
++       }
++}
++
++static void set_ipr_and_de( void )
++{
++       int i = 1;
++       while( 1 ) {
++                if ( OK_TO_WRITE ) {
++                         Ser0UDCCS0 |= BOTH_BITS;
++                } else {
++                         PRINTKD( "%sQuitting set IPR/DE because SST or SE set\n", pszMe );
++                         break;
++                }
++                if ( (Ser0UDCCS0 & BOTH_BITS) == BOTH_BITS)
++                         break;
++                udelay( i );
++                if ( ++i == 50  ) {
++                         printk( "%sDangnabbbit! Cannot set DE/IPR! (DE=%8.8X IPR=%8.8X CCS0=%8.8X)\n",
++                                         pszMe, UDCCS0_DE, UDCCS0_IPR, Ser0UDCCS0 );
++                         break;
++                }
++       }
++}
++
++static bool clear_opr( void )
++{
++       int i = 10000;
++       bool is_clear;
++       do {
++                Ser0UDCCS0 = UDCCS0_SO;
++                is_clear  = ! ( Ser0UDCCS0 & UDCCS0_OPR );
++                if ( i-- <= 0 ) {
++                         printk( "%sclear_opr(): failed\n", pszMe );
++                         break;
++                }
++       } while( ! is_clear );
++       return is_clear;
++}
++
++
++
++// ep1 handlers
++
++static char *ep1_buf;
++static int ep1_len;
++static void (*ep1_callback)(int flag, int size);
++static char *ep1_curdmabuf;
++static dma_addr_t ep1_curdmapos;
++static int ep1_curdmalen;
++static int ep1_remain;
++static int ep1_used;
++
++static dma_regs_t *dmaregs_rx = NULL;
++static int rx_pktsize;
++
++static int naking;
++
++static void
++ep1_start(void)
++{
++      sa1100_reset_dma(dmaregs_rx);
++      if (!ep1_curdmalen) {
++              ep1_curdmalen = rx_pktsize;
++              if (ep1_curdmalen > ep1_remain)
++                      ep1_curdmalen = ep1_remain;
++              ep1_curdmapos = dma_map_single(NULL, ep1_curdmabuf, ep1_curdmalen,
++                                             DMA_FROM_DEVICE);
++      }
++
++      UDC_write( Ser0UDCOMP, ep1_curdmalen-1 );
++      
++      sa1100_start_dma(dmaregs_rx, ep1_curdmapos, ep1_curdmalen);
++
++      if ( naking ) {
++              /* turn off NAK of OUT packets, if set */
++              UDC_flip( Ser0UDCCS1, UDCCS1_RPC );
++              naking = 0;
++      }
++}
++
++static void
++ep1_done(int flag)
++{
++      int size = ep1_len - ep1_remain;
++
++      if (!ep1_len)
++              return;
++      if (ep1_curdmalen)
++              dma_unmap_single(NULL, ep1_curdmapos, ep1_curdmalen,
++                               DMA_FROM_DEVICE);
++      ep1_len = ep1_curdmalen = 0;
++      if (ep1_callback)
++              ep1_callback(flag, size);
++}
++
++void
++ep1_state_change_notify( int new_state )
++{
++
++}
++
++void
++ep1_stall( void )
++{
++      /* SET_FEATURE force stall at UDC */
++      UDC_set( Ser0UDCCS1, UDCCS1_FST );
++}
++
++int
++ep1_init(dma_regs_t *dmaregs)
++{
++      dmaregs_rx = dmaregs;
++      sa1100_reset_dma(dmaregs_rx);
++      ep1_done(-EAGAIN);
++      return 0;
++}
++
++void
++ep1_reset(void)
++{
++      if (dmaregs_rx)
++          sa1100_reset_dma(dmaregs_rx);
++      UDC_clear(Ser0UDCCS1, UDCCS1_FST);
++      ep1_done(-EINTR);
++}
++
++void
++ep1_int_hndlr(int udcsr)
++{
++      dma_addr_t dma_addr;
++      unsigned int len;
++      int status = Ser0UDCCS1;
++
++      if ( naking ) printk( "%sEh? in ISR but naking = %d\n", "usbrx: ", naking );
++
++      if (status & UDCCS1_RPC) {
++
++              if (!ep1_curdmalen) {
++                      printk("usb_recv: RPC for non-existent buffer\n");
++                      naking=1;
++                      return;
++              }
++
++              sa1100_stop_dma(dmaregs_rx);
++
++              if (status & UDCCS1_SST) {
++                      printk("usb_recv: stall sent OMP=%d\n",Ser0UDCOMP);
++                      UDC_flip(Ser0UDCCS1, UDCCS1_SST);
++                      ep1_done(-EIO); // UDC aborted current transfer, so we do
++                      return;
++              }
++
++              if (status & UDCCS1_RPE) {
++                      printk("usb_recv: RPError %x\n", status);
++                      UDC_flip(Ser0UDCCS1, UDCCS1_RPC);
++                      ep1_done(-EIO);
++                      return;
++              }
++
++              dma_addr=sa1100_get_dma_pos(dmaregs_rx);
++              dma_unmap_single(NULL, ep1_curdmapos, ep1_curdmalen,
++                               DMA_FROM_DEVICE);
++              len = dma_addr - ep1_curdmapos;
++#ifdef SA1100_USB_DEBUG
++              if (sa1100_usb_debug) {
++                  int i;
++                  printk("usb rx %d :\n  ",len);
++                  if (sa1100_usb_debug>1) {
++                      for (i=0; i<len; i++) {
++                          if ((i % 32)==31)
++                              printk("\n  ");
++//                        printk("%2.2x ",((char *)ep1_buf)[ep1_used+i]);
++                          printk("%2.2x ",((char *)ep1_curdmapos)[i]);
++                      }
++                  }
++                  printk("\n");
++              }
++#endif
++              if (len < ep1_curdmalen) {
++                      char *buf = ep1_curdmabuf + len;
++                      while (Ser0UDCCS1 & UDCCS1_RNE) {
++                              if (len >= ep1_curdmalen) {
++                                      printk("usb_recv: too much data in fifo\n");
++                                      break;
++                              }
++                              *buf++ = Ser0UDCDR;
++                              len++;
++                      }
++              } else if (Ser0UDCCS1 & UDCCS1_RNE) {
++                      printk("usb_recv: fifo screwed, shouldn't contain data\n");
++                      len = 0;
++              }
++
++#if defined(NCB_DMA_FIX)
++//            if (len && (ep1_buf != ep1_curdmabuf))
++//                memcpy(ep1_buf,ep1_curdmabuf,len);
++              if (len)
++                  memcpy(&(((unsigned char *)ep1_buf)[ep1_used]),ep1_curdmabuf,len);
++#endif
++
++              ep1_curdmalen = 0;  /* dma unmap already done */
++              ep1_remain -= len;
++              ep1_used += len;
++//            ep1_curdmabuf += len;   // use same buffer again
++              naking = 1;
++//printk("%s: received %d, %d remaining\n",__FUNCTION__,len,ep1_remain);
++              if (len && (len == rx_pktsize))
++                  ep1_start();
++              else
++              ep1_done((len) ? 0 : -EPIPE);
++      }
++      /* else, you can get here if we are holding NAK */
++}
++
++int
++sa1100_usb_recv(struct usb_request *req, void (*callback)(int flag, int size))
++{
++      unsigned long flags;
++      char *buf=req->buf;
++      int len=req->length;
++
++      if (ep1_len)
++              return -EBUSY;
++
++      local_irq_save(flags);
++      ep1_buf = buf;
++      ep1_len = len;
++      ep1_callback = callback;
++      ep1_remain = len;
++      ep1_used = 0;
++#ifdef NCB_DMA_FIX
++//    if (((size_t)buf)&3)
++      if (1)
++          ep1_curdmabuf = receive_buffer;
++      else
++#else
++      ep1_curdmabuf = buf;
++#endif
++      ep1_curdmalen = 0;
++      ep1_start();
++      local_irq_restore(flags);
++
++      return 0;
++}
++
++// ep2 handlers
++
++static char *ep2_buf;
++static int ep2_len;
++static void (*ep2_callback)(int status, int size);
++static dma_addr_t ep2_dma;
++static dma_addr_t ep2_curdmapos;
++static int ep2_curdmalen;
++static int ep2_remain;
++static dma_regs_t *dmaregs_tx = NULL;
++static int tx_pktsize;
++
++/* device state is changing, async */
++void
++ep2_state_change_notify( int new_state )
++{
++}
++
++/* set feature stall executing, async */
++void
++ep2_stall( void )
++{
++      UDC_set( Ser0UDCCS2, UDCCS2_FST );  /* force stall at UDC */
++}
++
++static void
++ep2_start(void)
++{
++      if (!ep2_len)
++              return;
++              
++      ep2_curdmalen = tx_pktsize;
++      if (ep2_curdmalen > ep2_remain)
++              ep2_curdmalen = ep2_remain;
++
++      /* must do this _before_ queue buffer.. */
++      UDC_flip( Ser0UDCCS2,UDCCS2_TPC );  /* stop NAKing IN tokens */
++      UDC_write( Ser0UDCIMP, ep2_curdmalen-1 );
++
++#if 0
++      /* Remove if never seen...8Mar01ww */
++      {
++               int massive_attack = 20;
++               while ( Ser0UDCIMP != ep2_curdmalen-1 && massive_attack-- ) {
++                        printk( "usbsnd: Oh no you don't! Let me spin..." );
++                        udelay( 500 );
++                        printk( "and try again...\n" );
++                        UDC_write( Ser0UDCIMP, ep2_curdmalen-1 );
++               }
++               if ( massive_attack != 20 ) {
++                        if ( Ser0UDCIMP != ep2_curdmalen-1 )
++                                 printk( "usbsnd: Massive attack FAILED :-( %d\n",
++                                                 20 - massive_attack );
++                        else
++                                 printk( "usbsnd: Massive attack WORKED :-) %d\n",
++                                                 20 - massive_attack );
++               }
++      }
++      /* End remove if never seen... 8Mar01ww */
++#endif
++
++      Ser0UDCAR = usbd_info.address; // fighting stupid silicon bug
++      sa1100_start_dma(dmaregs_tx, ep2_curdmapos, ep2_curdmalen);
++}
++
++static void
++ep2_done(int flag)
++{
++      int size = ep2_len - ep2_remain;
++      if (ep2_len) {
++              dma_unmap_single(NULL, ep2_dma, ep2_len, DMA_TO_DEVICE);
++              ep2_len = 0;
++              if (ep2_callback)
++                      ep2_callback(flag, size);
++      }
++}
++
++int
++ep2_init(dma_regs_t *dmaregs)
++{
++      dmaregs_tx = dmaregs;
++      sa1100_reset_dma(dmaregs_tx);
++      ep2_done(-EAGAIN);
++      return 0;
++}
++
++void
++ep2_reset(void)
++{
++      UDC_clear(Ser0UDCCS2, UDCCS2_FST);
++      if (dmaregs_tx)
++          sa1100_reset_dma(dmaregs_tx);
++      ep2_done(-EINTR);
++}
++
++void
++ep2_int_hndlr(int udcsr)
++{
++      int status = Ser0UDCCS2;
++
++      if (Ser0UDCAR != usbd_info.address) // check for stupid silicon bug.
++              Ser0UDCAR = usbd_info.address;
++
++      if (status & UDCCS2_TPC) {
++
++              UDC_flip(Ser0UDCCS2, UDCCS2_SST);
++
++              sa1100_reset_dma(dmaregs_tx);
++
++              if (status & (UDCCS2_TPE | UDCCS2_TUR)) {
++                      printk("usb_send: transmit error %x\n", status);
++                      ep2_done(-EIO);
++              } else {
++#if 1 // 22Feb01ww/Oleg
++                      ep2_curdmapos += ep2_curdmalen;
++                      ep2_remain -= ep2_curdmalen;
++#else
++                      ep2_curdmapos += Ser0UDCIMP + 1; // this is workaround
++                      ep2_remain -= Ser0UDCIMP + 1;    // for case when setting of Ser0UDCIMP was failed
++#endif
++
++                      if (ep2_remain != 0)
++                              ep2_start();
++                      else
++                              ep2_done(0);
++              }
++      } else {
++              printk("usb_send: Not TPC: UDCCS2 = %x\n", status);
++      }
++}
++
++int
++sa1100_usb_send(struct usb_request *req, void (*callback)(int status, int size))
++{
++      char *buf=req->buf;
++      int len=req->length;
++      unsigned long flags;
++
++      if (usbd_info.state != USB_STATE_CONFIGURED) {
++              PRINTKD("%s: return -ENODEV\n",__FUNCTION__);
++              return -ENODEV;
++      }
++
++      if (ep2_len) {
++              PRINTKD("%s: return -EBUSY\n",__FUNCTION__);
++              return -EBUSY;
++      }
++
++      local_irq_save(flags);
++#ifdef NCB_DMA_FIX
++      // if misaligned, copy to aligned buffer
++//    if (((size_t)buf)&3) {
++      if (1) {
++          PRINTKD("%s: copying %d bytes to send_buffer\n",__FUNCTION__,len);
++          memcpy(send_buffer,buf,len);
++          ep2_buf = send_buffer;
++      }
++      else 
++#endif
++      ep2_buf = buf;
++              
++      ep2_len = len;
++      ep2_dma = dma_map_single(NULL, ep2_buf, len,DMA_TO_DEVICE);
++      PRINTKD("%s: mapped dma to buffer(%p0\n",__FUNCTION__,buf);
++
++      ep2_callback = callback;
++      ep2_remain = len;
++      ep2_curdmapos = ep2_dma;
++
++      PRINTKD("%s: calling ep2_start\n",__FUNCTION__);
++      ep2_start();
++      local_irq_restore(flags);
++
++      return 0;
++}
++/*-------------------------------------------------------------------------*/
++
++static int
++sa1100_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
++{
++      struct sa1100_udc       *dev;
++      struct sa1100_ep        *ep;
++      u32                     max;
++      int                     type;
++
++      ep = container_of (_ep, struct sa1100_ep, ep);
++      if (!_ep || !desc || ep->desc || _ep->name == ep0name
++                      || desc->bDescriptorType != USB_DT_ENDPOINT)\r {
++              PRINTKD("%s: _ep = %p, desc = %p\n",__FUNCTION__,_ep,desc);
++              if (_ep && desc)
++                  PRINTKD("%s: ep->desc = %p, _ep->name = %s desc->bDescriptorType = %s\n",__FUNCTION__,ep->desc,_ep->name, 
++                      (desc->bDescriptorType == USB_DT_ENDPOINT) ? "USB_DT_ENDPOINT":"bad!!");
++              return -EINVAL;
++      }
++
++      dev = ep->dev;
++      if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)\r 
++              return -ESHUTDOWN;
++
++      type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
++      max = le16_to_cpu (desc->wMaxPacketSize);
++      switch (max) {
++      case 64: case 32:
++      /* note:  maxpacket > 16 means DMA might overrun/underrun */
++      case 16: case 8:
++              break;
++      default:
++              if (type == USB_ENDPOINT_XFER_INT && max < 64)
++                      break;
++              return -EDOM;
++      }
++
++      switch (type) {
++      case USB_ENDPOINT_XFER_BULK:
++      case USB_ENDPOINT_XFER_INT:
++              if (ep == &dev->ep[2]) {
++                      if (desc->bEndpointAddress != (USB_DIR_IN|2)\r) {
++                              PRINTKD("%s: ep[2] has invalid endpoint\n",__FUNCTION__);
++                              return -EINVAL;
++                      }
++                      tx_pktsize = max;
++                      Ser0UDCOMP = max - 1;
++                      PRINTKD("%s: ep2 max packet size is %d\n",__FUNCTION__,max);
++                      break;
++              } else if (ep == &dev->ep[1]) {
++                      if (desc->bEndpointAddress != (USB_DIR_OUT|1))\r {
++                              PRINTKD("%s: ep[1] has invalid endpoint\n",__FUNCTION__);
++                              return -EINVAL;
++                      }
++                      rx_pktsize = max;
++                      Ser0UDCIMP = max - 1;
++                      PRINTKD("%s: ep1 max packet size is %d\n",__FUNCTION__,max);
++                      break;
++              }
++              // FALLTHROUGH
++      default:
++              PRINTKD("%s: Invalid endpoint\n",__FUNCTION__);
++              return -EINVAL;
++      }
++
++      _ep->maxpacket = max;
++      ep->desc = desc;
++
++      DEBUG (dev, "enabled %s %s max %04x\n", _ep->name,
++              type_string (desc->bmAttributes), max);
++
++      return 0;
++}
++
++static int sa1100_disable (struct usb_ep *_ep)
++{
++      struct sa1100_ep        *ep;
++
++      ep = container_of (_ep, struct sa1100_ep, ep);
++      if (!_ep || !ep->desc || _ep->name == ep0name)
++              return -EINVAL;
++
++      nuke (ep, -ESHUTDOWN);
++
++      DEBUG (ep->dev, "disabled %s\n", _ep->name);
++
++      ep->desc = NULL;
++      ep->stopped = 1;
++      return 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static struct usb_request *
++sa1100_alloc_request (struct usb_ep *_ep, int gfp_flags)
++{
++      struct sa1100_request   *req;
++
++      if (!_ep)
++              return 0;
++
++      req = kmalloc (sizeof *req, gfp_flags);
++      if (!req)
++              return 0;
++
++      memset (req, 0, sizeof *req);
++      req->req.dma = DMA_ADDR_INVALID;
++      INIT_LIST_HEAD (&req->queue);
++      return &req->req;
++}
++
++static void
++sa1100_free_request (struct usb_ep *_ep, struct usb_request *_req)
++{
++      struct sa1100_request   *req;
++
++#if 0 // NCB
++      struct sa1100_ep        *ep;
++      ep = container_of (_ep, struct sa1100_ep, ep);
++      if (!ep || !_req || (!ep->desc && _ep->name != ep0name))
++              return;
++\r#endif
++
++      req = container_of (_req, struct sa1100_request, req);
++      WARN_ON (!list_empty (&req->queue));
++      kfree(req);     //NCB - see pxa2xx_udc
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* allocate buffers this way to eliminate per-io buffer copies  */
++
++static void *
++sa1100_alloc_buffer (
++      struct usb_ep           *_ep,
++      unsigned                bytes,
++      dma_addr_t              *dma,
++      int                     gfp_flags
++)
++{
++      void                    *retval;
++#if 1 // NCB see pxa2xx_udc
++      retval = kmalloc (bytes, gfp_flags & ~(__GFP_DMA|__GFP_HIGHMEM));
++      if (retval)
++// used in pxa ..             *dma = virt_to_bus (retval);
++              *dma = virt_to_phys (retval);
++#else
++      struct sa1100_ep        *ep;
++
++      ep = container_of (_ep, struct sa1100_ep, ep);
++      if (!ep || (!ep->desc && _ep->name != ep0name))
++              return 0;
++
++      *dma = DMA_ADDR_INVALID;
++      retval = kmalloc (bytes, GFP_DMA | gfp_flags);
++      if (retval)
++              *dma = virt_to_phys (retval);
++\r#endif
++      return retval;
++}
++
++static void
++sa1100_free_buffer (
++      struct usb_ep *_ep,
++      void *buf,
++      dma_addr_t dma,
++      unsigned bytes
++) {
++      kfree (buf);
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void
++done (struct sa1100_ep *ep, struct sa1100_request *req, int status)
++{
++      unsigned                stopped = ep->stopped;
++
++
++      list_del_init (&req->queue);
++
++      if (req->req.status == -EINPROGRESS)
++              req->req.status = status;
++      else
++              status = req->req.status;
++
++      if (status && status != -ESHUTDOWN)
++              VDEBUG (ep->dev, "complete %s req %p stat %d len %u/%u\n",
++                      ep->ep.name, &req->req, status,
++                      req->req.actual, req->req.length);
++
++      /* don't modify queue heads during completion callback */
++      ep->stopped = 1;
++      PRINTKD("%s: calling complete on req\n",__FUNCTION__);
++      req->req.complete (&ep->ep, &req->req);
++      ep->stopped = stopped;
++}
++
++#if 0 // NCB
++void control_done (int value)
++{
++      struct list_head        *entry, *tmp;
++      struct sa1100_request   *req;
++
++      list_for_each_safe (entry, tmp, &the_controller.ep[0].queue) {
++              req = list_entry (entry, struct sa1100_request, queue);
++
++              /* HACK -- assume no control errors */
++              if (value == 0)
++                      req->req.actual = req->req.length;
++#if 1
++              PRINTKD("%s: calling done with ep=%p, req=%p\n",__FUNCTION__,&the_udc.ep[0],req);
++              done (&the_udc.ep[0], req, value);
++#else
++              done (&the_udc.ep0, req, value);
++#endif
++              value = -EPROTO;
++      }
++}
++#endif
++
++/*-------------------------------------------------------------------------*/
++
++/* FIXME move away from the old non-queued api.
++ * - forces extra work on us
++ * - stores request state twice
++ * - doesn't let gadget driver handle dma mapping
++ * - status codes need mapping
++ */
++
++static int map_status (int status)
++{
++      switch (status) {
++      case 0:
++      case -EIO:      /* ep[12]_int_handler */
++              return status;
++      case -EPIPE:    /* ep1_int_handler */
++              return 0;
++      //  case -EAGAIN:       /* ep[12]_init */
++      //  case -EINTR:        /* ep[12]_reset */
++      default:
++              return -ESHUTDOWN;
++      }
++}
++
++static void tx_callback (int status, int size)
++{
++      struct sa1100_ep        *ep = &the_controller->ep[2];
++      struct sa1100_request   *req;
++
++//    PRINTKD("%s: doing ...\n",__FUNCTION__);
++PRINTKD("%s: doing ... status=%d size=%d\n",__FUNCTION__,status,size);
++//PRINTKD("%s: doing ... status=%d\n",__FUNCTION__,status);
++      if (list_empty (&ep->queue)) {
++              if (status != -EAGAIN)
++                      DEBUG (ep->dev, "%s, bogus tx callback %d/%d\n",
++                              ep->ep.name, status, size);
++//                    DEBUG (ep->dev, "%s, bogus tx callback %d\n",
++//                            ep->ep.name, status);
++else
++PRINTKD("%s: list empty.\n",__FUNCTION__);
++              return;
++      }
++      req = list_entry (ep->queue.next, struct sa1100_request, queue);
++      req->req.actual = size;
++      done (ep, req, map_status (status));
++
++PRINTKD("%s: ep->stopped=%s\n",__FUNCTION__,ep->stopped ? "true":"false");
++      if (ep->stopped || list_empty (&ep->queue))
++              return;
++      req = list_entry (ep->queue.next, struct sa1100_request, queue);
++PRINTKD("%s: calling sa1100_usb_send\n",__FUNCTION__);
++      sa1100_usb_send (&req->req, tx_callback);
++}
++
++static void rx_callback (int status, int size)
++{
++      struct sa1100_ep        *ep = &the_controller->ep[1];
++      struct sa1100_request   *req;
++
++//    PRINTKD("%s: doing ...\n",__FUNCTION__);
++PRINTKD("%s: doing ... status=%d\n",__FUNCTION__,status);
++      if (list_empty (&ep->queue)) {
++              if (status != -EAGAIN)
++                      DEBUG (ep->dev, "%s, bogus tx callback %d/%d\n",
++                              ep->ep.name, status, size);
++              return;
++      }
++      req = list_entry (ep->queue.next, struct sa1100_request, queue);
++      req->req.actual = size;
++      done (ep, req, map_status (status));
++
++      if (ep->stopped || list_empty (&ep->queue))
++              return;
++      req = list_entry (ep->queue.next, struct sa1100_request, queue);
++      sa1100_usb_recv (&req->req, rx_callback);
++}
++
++
++static int
++sa1100_queue (struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
++{
++      struct sa1100_request   *req;
++      struct sa1100_ep        *ep;
++      struct sa1100_udc       *dev;
++      unsigned long           flags;
++
++      req = container_of (_req, struct sa1100_request, req);
++      if (!_req || !_req->complete || !_req->buf
++                      || !list_empty (&req->queue))
++              return -EINVAL;
++
++      ep = container_of (_ep, struct sa1100_ep, ep);
++      if (!_ep || (!ep->desc && _ep->name != ep0name))
++              return -EINVAL;
++      dev = ep->dev;
++
++      // handle ep0
++      if (_ep->name == ep0name)\r {
++          ep0_queue( _req->buf, _req->length, dev->ep0_req_len >=0 ? dev->ep0_req_len: _req->length );
++          return 0;
++      } 
++      
++      if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
++              return -ESHUTDOWN;
++
++      /* sa1100 udc can't write zlps */
++      if (ep == &dev->ep[2] && _req->length == 0)
++              return -ERANGE;
++
++      /* the old sa1100 api doesn't use 'unsigned' for lengths */
++      if (_req->length > INT_MAX)
++              return -ERANGE;
++
++#if 0
++      VDEBUG (dev, "%s queue req %p, len %d buf %p\n",
++                      _ep->name, _req, _req->length, _req->buf);
++#endif
++
++      local_irq_save (flags);
++
++      _req->status = -EINPROGRESS;
++      _req->actual = 0;
++
++// NCB        if (list_empty) {
++      if (list_empty (&ep->queue) && !ep->stopped) {
++              /* FIXME this does DMA mapping wrong.  caller is allowed
++               * to provide buffers that don't need mapping, but this
++               * doesn't use them.
++               */
++              if (ep == &ep->dev->ep[2])\r {
++                      PRINTKD("%s: sa1100_usb_send buf %p length %d\n",__FUNCTION__,_req->buf,_req->length);
++                      sa1100_usb_send (_req, tx_callback);
++              }
++              else if (ep == &ep->dev->ep[1])\r {
++                      PRINTKD("%s: sa1100_usb_recv buf %p length %d\n",__FUNCTION__,_req->buf,_req->length);
++                      sa1100_usb_recv (_req, rx_callback);
++              }
++              /* ep0 rx/tx is handled separately */
++      }
++      list_add_tail (&req->queue, &ep->queue);
++
++      local_irq_restore (flags);
++
++      return 0;
++}
++
++/* dequeue ALL requests */
++static void nuke (struct sa1100_ep *ep, int status)
++{
++      struct sa1100_request   *req;
++
++      /* called with irqs blocked */
++      ep->stopped = 1;
++      if (ep == &ep->dev->ep[1])
++              ep1_reset ();
++      else if (ep == &ep->dev->ep[2])
++              ep2_reset ();
++      while (!list_empty (&ep->queue)) {
++              req = list_entry (ep->queue.next,
++                              struct sa1100_request,
++                              queue);
++              done (ep, req, status);
++      }
++}
++
++/* dequeue JUST ONE request */
++static int sa1100_dequeue (struct usb_ep *_ep, struct usb_request *_req)
++{
++      struct sa1100_ep        *ep;
++      struct sa1100_request   *req;
++      unsigned long           flags;
++
++      ep = container_of (_ep, struct sa1100_ep, ep);
++      req = container_of (_req, struct sa1100_request, req);
++      if (!_ep || (!ep->desc && _ep->name != ep0name) || !_req)
++              return -EINVAL;
++
++      local_irq_save (flags);
++
++      /* make sure it's actually queued on this endpoint */
++      list_for_each_entry (req, &ep->queue, queue) {
++              if (&req->req == _req)
++                      break;
++      }
++      if (&req->req != _req) {
++              local_irq_restore(flags);
++              return -EINVAL;
++      }
++
++#if 0
++//#ifdef      USE_DMA
++      if (ep->dma >= 0 && ep->queue.next == &req->queue && !ep->stopped) {
++              cancel_dma(ep);
++              done(ep, req, -ECONNRESET);
++              /* restart i/o */
++              if (!list_empty(&ep->queue)) {
++                      req = list_entry(ep->queue.next,
++                                      struct pxa2xx_request, queue);
++                      kick_dma(ep, req);
++              }
++      } else
++//#endif
++#endif
++      done(ep, req, -ECONNRESET);
++
++      local_irq_restore(flags);
++
++      return 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static int
++sa1100_set_halt (struct usb_ep *_ep, int value)
++{
++      struct sa1100_ep        *ep;
++
++      ep = container_of (_ep, struct sa1100_ep, ep);
++      if (!_ep || (!ep->desc && _ep->name != ep0name))
++              return -EINVAL;
++      if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
++              return -ESHUTDOWN;
++      if ( (ep->desc->bmAttributes & 0x03) == USB_ENDPOINT_XFER_ISOC)
++              return -EINVAL;
++
++      VDEBUG (ep->dev, "%s %s halt\n", _ep->name, value ? "set" : "clear");
++
++      /* set/clear, then synch memory views with the device */
++      if (value) {
++              if (ep == &ep->dev->ep[1])
++                      ep1_stall ();
++              else
++                      ep2_stall ();
++      } else {
++              if (ep == &ep->dev->ep[1])
++                      ep1_reset ();
++              else
++                      ep2_reset ();
++      }
++
++      return 0;
++}
++
++static struct usb_ep_ops sa1100_ep_ops = {
++      .enable         = sa1100_enable,
++      .disable        = sa1100_disable,
++
++      .alloc_request  = sa1100_alloc_request,
++      .free_request   = sa1100_free_request,
++
++      .alloc_buffer   = sa1100_alloc_buffer,
++      .free_buffer    = sa1100_free_buffer,
++
++      .queue          = sa1100_queue,
++      .dequeue        = sa1100_dequeue,
++
++      .set_halt       = sa1100_set_halt,
++      // .fifo_status = sa1100_fifo_status,
++      // .fifo_flush  = sa1100_fifo_flush,
++};
++
++/*-------------------------------------------------------------------------*/
++
++static int sa1100_get_frame (struct usb_gadget *_gadget)
++{
++      return -EOPNOTSUPP;
++}
++
++static int sa1100_wakeup (struct usb_gadget *_gadget)
++{
++      struct sa1100_udc       *dev;
++
++      if (!_gadget)
++              return 0;
++      dev = container_of (_gadget, struct sa1100_udc, gadget);
++
++      // FIXME
++
++      return 0;
++}
++
++static const struct usb_gadget_ops sa1100_ops = {
++      .get_frame      = sa1100_get_frame,
++      .wakeup         = sa1100_wakeup,
++
++      // .set_selfpowered = sa1100_set_selfpowered,
++};
++
++/*-------------------------------------------------------------------------*/
++
++static inline void enable_resume_mask_suspend (void)
++{
++       int i = 0;
++
++       while (1) {
++                Ser0UDCCR |= UDCCR_SUSIM; // mask future suspend events
++                udelay (i);
++                if ( (Ser0UDCCR & UDCCR_SUSIM) || (Ser0UDCSR & UDCSR_RSTIR))
++                         break;
++                if (++i == 50) {
++                         WARN (&the_controller, "%s Could not set SUSIM %8.8X\n",
++                                      __FUNCTION__, Ser0UDCCR);
++                         break;
++                }
++       }
++
++       i = 0;
++       while (1) {
++                Ser0UDCCR &= ~UDCCR_RESIM;
++                udelay (i);
++                if ( (Ser0UDCCR & UDCCR_RESIM) == 0
++                              || (Ser0UDCSR & UDCSR_RSTIR))
++                         break;
++                if (++i == 50) {
++                         WARN (&the_controller, "%s Could not clear RESIM %8.8X\n",
++                                      __FUNCTION__, Ser0UDCCR);
++                         break;
++                }
++       }
++}
++
++static inline void enable_suspend_mask_resume (void)
++{
++       int i = 0;
++       while (1) {
++                Ser0UDCCR |= UDCCR_RESIM; // mask future resume events
++                udelay (i);
++                if (Ser0UDCCR & UDCCR_RESIM || (Ser0UDCSR & UDCSR_RSTIR))
++                         break;
++                if (++i == 50) {
++                         WARN (&the_controller, "%s could not set RESIM %8.8X\n",
++                                      __FUNCTION__, Ser0UDCCR);
++                         break;
++                }
++       }
++       i = 0;
++       while (1) {
++                Ser0UDCCR &= ~UDCCR_SUSIM;
++                udelay (i);
++                if ( (Ser0UDCCR & UDCCR_SUSIM) == 0
++                              || (Ser0UDCSR & UDCSR_RSTIR))
++                         break;
++                if (++i == 50) {
++                         WARN (&the_controller, "%s Could not clear SUSIM %8.8X\n",
++                                      __FUNCTION__, Ser0UDCCR);
++                         break;
++                }
++       }
++}
++
++// HACK DEBUG  3Mar01ww
++// Well, maybe not, it really seems to help!  08Mar01ww
++static void core_kicker (void)
++{
++      u32 car = Ser0UDCAR;
++      u32 imp = Ser0UDCIMP;
++      u32 omp = Ser0UDCOMP;
++
++      UDC_set (Ser0UDCCR, UDCCR_UDD);
++      udelay (300);
++      UDC_clear (Ser0UDCCR, UDCCR_UDD);
++
++      Ser0UDCAR = car;
++      Ser0UDCIMP = imp;
++      Ser0UDCOMP = omp;
++}
++
++// NCB static void
++static irqreturn_t
++udc_int_hndlr (int irq, void *_dev, struct pt_regs *regs)
++{
++      struct sa1100_udc       *dev = _dev;
++      u32                     status = Ser0UDCSR;
++
++      u32                     control = Ser0UDCCR;
++      \rPRINTKD("%s: status = 0x%x and control = 0x%x\n",__FUNCTION__,status,control);
++      /* ReSeT Interrupt Request - UDC has been reset */
++      if (status & UDCSR_RSTIR) {
++      PRINTKD("%s: processing UDCSR_RSTIR\n",__FUNCTION__);
++              if (usbctl_next_state_on_event (kEvReset) != kError) {
++                      /* starting 20ms or so reset sequence now... */
++                      INFO (dev, "Resetting\n");
++                      ep0_reset ();  // just set state to idle
++                      ep1_reset ();  // flush dma, clear false stall
++                      ep2_reset ();  // flush dma, clear false stall
++              }
++              // mask reset ints, they flood during sequence, enable
++              // suspend and resume
++              Ser0UDCCR |= UDCCR_REM;    // mask reset
++              Ser0UDCCR &= ~ (UDCCR_SUSIM | UDCCR_RESIM); // enable suspend and resume
++              UDC_flip ( Ser0UDCSR, status);  // clear all pending sources
++              PRINTKD("%s: setting USB_FULL_SPEED\n",__FUNCTION__);
++              dev->gadget.speed = USB_SPEED_FULL;
++              return IRQ_HANDLED;     // NCB
++      }
++
++      /* else we have done something other than reset,
++       * so be sure reset enabled
++       */
++      UDC_clear (Ser0UDCCR, UDCCR_REM);
++
++      /* RESume Interrupt Request */
++      if (status & UDCSR_RESIR) {
++              struct usb_gadget_driver        *driver = dev->driver;
++
++              PRINTKD("%s: processing UDCSR_RESIR\n",__FUNCTION__);
++              if (driver->resume)
++                      driver->resume (&dev->gadget);
++              core_kicker ();
++              enable_suspend_mask_resume ();
++      }
++
++      /* SUSpend Interrupt Request */
++      if (status & UDCSR_SUSIR) {
++              struct usb_gadget_driver        *driver = dev->driver;
++
++              PRINTKD("%s: processing UDCSR_SUSIR\n",__FUNCTION__);
++              if (driver->suspend)
++                      driver->suspend (&dev->gadget);
++              enable_resume_mask_suspend ();
++      }
++
++      UDC_flip (Ser0UDCSR, status); // clear all pending sources
++
++      if (status & UDCSR_EIR)\r
++               ep0_int_hndlr ();
++
++
++      if (status & UDCSR_RIR)\r {
++              PRINTKD("%s: processing ep1_int_hndlr\n",__FUNCTION__);
++              ep1_int_hndlr (status);
++      }
++      if (status & UDCSR_TIR)\r {
++              PRINTKD("%s: processing ep2_int_hndlr\n",__FUNCTION__);
++              ep2_int_hndlr (status);
++      }
++              
++      return IRQ_HANDLED;     // NCB
++              
++}
++
++/* soft_connect_hook ()
++ * Some devices have platform-specific circuitry to make USB
++ * not seem to be plugged in, even when it is. This allows
++ * software to control when a device 'appears' on the USB bus
++ * (after Linux has booted and this driver has loaded, for
++ * example). If you have such a circuit, control it here.
++ */
++#ifdef CONFIG_SA1100_EXTENEX1
++static void soft_connect_hook (int enable)
++{
++      if (machine_is_extenex1 ()) {
++              if (enable) {
++                      PPDR |= PPC_USB_SOFT_CON;
++                      PPSR |= PPC_USB_SOFT_CON;
++              } else {
++                      PPSR &= ~PPC_USB_SOFT_CON;
++                      PPDR &= ~PPC_USB_SOFT_CON;
++              }
++      }
++}
++#elif defined(CONFIG_SA1100_BALLOON)
++static void soft_connect_hook (int enable)
++{
++      if (machine_is_balloon()) {
++          if (enable)
++              balloon_udc_connect();
++          else
++              balloon_udc_disconnect();
++      }
++}
++#else
++#define soft_connect_hook(x) do { } while (0);
++#endif
++
++/* "function" sysfs attribute */
++static ssize_t
++show_function (struct device *_dev, char *buf)
++{
++      struct sa1100_udc       *dev = dev_get_drvdata (_dev);
++
++      if (!dev->driver
++                      || !dev->driver->function
++                      || strlen (dev->driver->function) > PAGE_SIZE)
++              return 0;
++      return scnprintf (buf, PAGE_SIZE, "%s\n", dev->driver->function);
++}
++static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
++
++/* disable the UDC at the source */
++static void udc_disable (struct sa1100_udc *dev)
++{
++      soft_connect_hook (0);
++      UDC_set (Ser0UDCCR, UDCCR_UDD);
++      dev->gadget.speed = USB_SPEED_UNKNOWN;
++      ep0_idle(dev);
++}
++
++static void udc_reinit(struct sa1100_udc *dev) {
++    
++      u32     i;
++
++      /* Initialize the gadget controller data structure */
++      INIT_LIST_HEAD (&dev->gadget.ep_list);
++      INIT_LIST_HEAD (&dev->gadget.ep0->ep_list);
++      ep0_idle(dev);
++      for ( i = 0 ; i < 3 ; i++) {
++              struct sa1100_ep *ep = &dev->ep[i];
++              if (i != 0) 
++                      list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);
++              ep->desc     = NULL;
++              ep->stopped  = 0;
++              INIT_LIST_HEAD(&ep->queue);
++      }
++}
++
++/*  enable the udc at the source */
++static void udc_enable (struct sa1100_udc *dev)
++{
++      UDC_clear (Ser0UDCCR, UDCCR_UDD);
++      ep0_idle(dev);
++}
++
++static void ep0_start (struct sa1100_udc *dev)
++{
++      udc_enable (dev);
++      udelay (100);
++
++      /* clear stall - receiver seems to start stalled? 19Jan01ww */
++      /* also clear other stuff just to be thurough 22Feb01ww */
++      UDC_clear(Ser0UDCCS1, UDCCS1_FST | UDCCS1_RPE | UDCCS1_RPC );
++      UDC_clear(Ser0UDCCS2, UDCCS2_FST | UDCCS2_TPE | UDCCS2_TPC );
++
++      /* mask everything */
++      Ser0UDCCR = 0xFC;
++
++      /* flush DMA and fire through some -EAGAINs */
++      ep1_init (dev->ep[1].dmaregs);
++      ep2_init (dev->ep[2].dmaregs);
++
++      /* enable any platform specific hardware */
++      soft_connect_hook (1);
++
++      /* clear all top-level sources */
++      Ser0UDCSR = UDCSR_RSTIR | UDCSR_RESIR | UDCSR_EIR   |
++                       UDCSR_RIR   | UDCSR_TIR   | UDCSR_SUSIR ;
++
++      /* EXERIMENT - a short line in the spec says toggling this
++       * bit diddles the internal state machine in the udc to
++       * expect a suspend
++       */
++      Ser0UDCCR  |= UDCCR_RESIM;
++      /* END EXPERIMENT 10Feb01ww */
++
++      /* enable any platform specific hardware */
++      soft_connect_hook (1);
++
++      /* Enable interrupts. If you are unplugged you will immediately
++       * get a suspend interrupt. If you are plugged and have a soft
++       * connect-circuit, you will get a reset.  If you are plugged
++       * without a soft-connect, I think you also get suspend. In short,
++       * start with suspend masked and everything else enabled
++       */
++      UDC_write( Ser0UDCCR, UDCCR_SUSIM );
++}
++
++
++/* when a driver is successfully registered, it will receive
++ * control requests including set_configuration (), which enables
++ * non-control requests.  then usb traffic follows until a
++ * disconnect is reported.  then a host may connect again, or
++ * the driver might get unbound.
++ */
++int usb_gadget_register_driver (struct usb_gadget_driver *driver)
++{
++      struct sa1100_udc       *dev = the_controller;
++      int                     retval;
++
++      if (!driver
++                      || !driver->bind
++                      || !driver->unbind
++                      || !driver->setup)
++              return -EINVAL;
++      if (!dev)
++              return -ENODEV;
++      if (dev->driver)
++              return -EBUSY;
++
++      /* hook up the driver ... */
++      dev->driver = driver;
++      dev->gadget.dev.driver = &driver->driver;
++      
++//    device_add (&dev->gadget.dev);
++      retval = driver->bind (&dev->gadget);
++      if (retval) {
++              DEBUG (dev, "bind to driver %s --> %d\n",
++                              driver->driver.name, retval);
++              device_del(&dev->gadget.dev);
++              dev->driver = NULL;
++              dev->gadget.dev.driver = NULL;
++              return retval;
++      }
++\r     device_create_file(dev->dev, &dev_attr_function);
++
++      /* ... then enable host detection and ep0; and we're ready
++       * for set_configuration as well as eventual disconnect.
++       */
++      ep0_start (dev);
++
++      DEBUG (dev, "%s ready\n", driver->driver.name);
++
++      return 0;
++}
++EXPORT_SYMBOL (usb_gadget_register_driver);
++
++static void
++stop_activity (struct sa1100_udc *dev, struct usb_gadget_driver *driver)
++{
++      int i;
++
++      /* don't disconnect if it's not connected */
++      if (dev->gadget.speed == USB_SPEED_UNKNOWN)
++              driver = NULL;
++\r     dev->gadget.speed = USB_SPEED_UNKNOWN;
++
++      /* mask everything */
++      Ser0UDCCR = 0xFC;
++
++      /* stop hardware; prevent new request submissions;
++       * and kill any outstanding requests.
++       */
++      for (i = 0; i < 3; i++) {
++              struct sa1100_ep *ep = &dev->ep[i];
++
++              ep->stopped = 1;
++              nuke(ep, -ESHUTDOWN);
++      }
++      udc_disable (dev);
++
++      /* report disconnect; the driver is already quiesced */
++      if (driver) {
++//            spin_unlock (&dev->lock);
++              driver->disconnect (&dev->gadget);
++//            spin_lock (&dev->lock);
++      }
++      /* re-init driver-visible data structures */
++      udc_reinit(dev);
++}
++
++int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
++{
++      struct sa1100_udc       *dev = the_controller;
++
++      if (!dev)
++              return -ENODEV;
++      if (!driver || driver != dev->driver)
++              return -EINVAL;
++
++      local_irq_disable();
++      stop_activity (dev, driver);
++      local_irq_enable();
++      driver->unbind (&dev->gadget);
++      dev->driver = 0;
++
++//printk("%s: deleting device\n",__FUNCTION__);
++//    device_del (&dev->gadget.dev);
++      device_remove_file(dev->dev, &dev_attr_function);
++
++      DEBUG (dev, "unregistered driver '%s'\n", driver->driver.name);
++      return 0;
++}
++EXPORT_SYMBOL (usb_gadget_unregister_driver);
++
++
++/*-------------------------------------------------------------------------*/
++
++/*-------------------------------------------------------------------------*/
++
++//////////////////////////////////////////////////////////////////////////////
++// Proc Filesystem Support
++//////////////////////////////////////////////////////////////////////////////
++
++#if CONFIG_PROC_FS
++
++#define SAY(fmt,args...)  p += sprintf (p, fmt, ## args)
++#define SAYV(num)         p += sprintf (p, num_fmt, "Value", num)
++#define SAYC(label,yn)    p += sprintf (p, yn_fmt, label, yn)
++#define SAYS(label,v)     p += sprintf (p, cnt_fmt, label, v)
++
++static int usbctl_read_proc (char *page, char **start, off_t off,
++                          int count, int *eof, void *data)
++{
++       const char * num_fmt   = "%25.25s: %8.8lX\n";
++       const char * cnt_fmt   = "%25.25s: %lu\n";
++       const char * yn_fmt    = "%25.25s: %s\n";
++       const char * yes       = "YES";
++       const char * no        = "NO";
++       unsigned long v;
++       char * p = page;
++       int len;
++
++       SAY ("SA1100 USB Controller Core\n");
++
++       SAYS ("ep0 bytes read", usbd_info.stats.ep0_bytes_read);
++       SAYS ("ep0 bytes written", usbd_info.stats.ep0_bytes_written);
++       SAYS ("ep0 FIFO read failures", usbd_info.stats.ep0_fifo_read_failures);
++       SAYS ("ep0 FIFO write failures", usbd_info.stats.ep0_fifo_write_failures);
++
++       SAY ("\n");
++
++       v = Ser0UDCAR;
++       SAY ("%25.25s: 0x%8.8lX - %ld\n", "Address Register", v, v);
++       v = Ser0UDCIMP;
++       SAY ("%25.25s: %ld (%8.8lX)\n", "IN  max packet size", v+1, v);
++       v = Ser0UDCOMP;
++       SAY ("%25.25s: %ld (%8.8lX)\n", "OUT max packet size", v+1, v);
++
++       v = Ser0UDCCR;
++       SAY ("\nUDC Mask Register\n");
++       SAYV (v);
++       SAYC ("UDC Active", (v & UDCCR_UDA) ? yes : no);
++       SAYC ("Suspend interrupts masked", (v & UDCCR_SUSIM) ? yes : no);
++       SAYC ("Resume interrupts masked", (v & UDCCR_RESIM) ? yes : no);
++       SAYC ("Reset interrupts masked", (v & UDCCR_REM) ? yes : no);
++
++       v = Ser0UDCSR;
++       SAY ("\nUDC Interrupt Request Register\n");
++       SAYV (v);
++       SAYC ("Reset pending", (v & UDCSR_RSTIR) ? yes : no);
++       SAYC ("Suspend pending", (v & UDCSR_SUSIR) ? yes : no);
++       SAYC ("Resume pending", (v & UDCSR_RESIR) ? yes : no);
++       SAYC ("ep0 pending", (v & UDCSR_EIR)   ? yes : no);
++       SAYC ("receiver pending", (v & UDCSR_RIR)   ? yes : no);
++       SAYC ("tramsitter pending", (v & UDCSR_TIR)   ? yes : no);
++
++#ifdef CONFIG_SA1100_EXTENEX1
++       SAYC ("\nSoft connect", (PPSR & PPC_USB_SOFT_CON) ? "Visible" : "Hidden");
++#endif
++
++#if 1
++       SAY ("\nDMA Tx registers\n");
++       {
++       dma_regs_t *r=the_controller->ep[2].dmaregs;
++       SAY (" DDAR");
++       SAYV(r->DDAR);
++       SAY (" DCSR");
++       SAYV(r->RdDCSR);
++       SAY (" DBSA (address buf A) ");
++       SAYV(r->DBSA);
++       SAY (" DBTA (transfer count A) ");
++       SAYV(r->DBTA);
++       SAY (" DBSB (address buf B) ");
++       SAYV(r->DBSB);
++       SAY (" DBTB (transfer count B) ");
++       SAYV(r->DBTB);
++       
++       }
++       SAY ("\nDMA Rx registers\n");
++       {
++       dma_regs_t *r=the_controller->ep[1].dmaregs;
++       SAY (" DDAR");
++       SAYV(r->DDAR);
++       SAY (" DCSR");
++       SAYV(r->RdDCSR);
++       SAY (" DBSA (address buf A) ");
++       SAYV(r->DBSA);
++       SAY (" DBTA (transfer count A) ");
++       SAYV(r->DBTA);
++       SAY (" DBSB (address buf B) ");
++       SAYV(r->DBSB);
++       SAY (" DBTB (transfer count B) ");
++       SAYV(r->DBTB);
++       
++       }
++#endif
++#if 1
++       v = Ser0UDCCS0;
++       SAY ("\nUDC Endpoint Zero Status Register\n");
++       SAYV (v);
++       SAYC ("Out Packet Ready", (v & UDCCS0_OPR) ? yes : no);
++       SAYC ("In Packet Ready", (v & UDCCS0_IPR) ? yes : no);
++       SAYC ("Sent Stall", (v & UDCCS0_SST) ? yes : no);
++       SAYC ("Force Stall", (v & UDCCS0_FST) ? yes : no);
++       SAYC ("Data End", (v & UDCCS0_DE)  ? yes : no);
++       SAYC ("Data Setup End", (v & UDCCS0_SE)  ? yes : no);
++       SAYC ("Serviced (SO)", (v & UDCCS0_SO)  ? yes : no);
++
++       v = Ser0UDCCS1;
++       SAY ("\nUDC Receiver Status Register\n");
++       SAYV (v);
++       SAYC ("Receive Packet Complete", (v & UDCCS1_RPC) ? yes : no);
++       SAYC ("Sent Stall", (v & UDCCS1_SST) ? yes : no);
++       SAYC ("Force Stall", (v & UDCCS1_FST) ? yes : no);
++       SAYC ("Receive Packet Error", (v & UDCCS1_RPE) ? yes : no);
++       SAYC ("Receive FIFO not empty", (v & UDCCS1_RNE) ? yes : no);
++
++       v = Ser0UDCCS2;
++       SAY ("\nUDC Transmitter Status Register\n");
++       SAYV (v);
++       SAYC ("FIFO has < 8 of 16 chars", (v & UDCCS2_TFS) ? yes : no);
++       SAYC ("Transmit Packet Complete", (v & UDCCS2_TPC) ? yes : no);
++       SAYC ("Transmit FIFO underrun", (v & UDCCS2_TUR) ? yes : no);
++       SAYC ("Transmit Packet Error", (v & UDCCS2_TPE) ? yes : no);
++       SAYC ("Sent Stall", (v & UDCCS2_SST) ? yes : no);
++       SAYC ("Force Stall", (v & UDCCS2_FST) ? yes : no);
++#endif
++
++       len = (p - page) - off;
++       if (len < 0)
++                len = 0;
++       *eof = (len <=count) ? 1 : 0;
++       *start = page + off;
++       return len;
++}
++
++static inline void register_proc_entry (void)
++{
++      create_proc_read_entry (driver_name, 0, NULL,
++              usbctl_read_proc, NULL);
++}
++
++static inline void unregister_proc_entry (void)
++{
++      remove_proc_entry (driver_name, NULL);
++}
++
++#else
++
++#define register_proc_entry() do {} while (0)
++#define unregister_proc_entry() do {} while (0)
++
++#endif  /* CONFIG_PROC_FS */
++
++/*-------------------------------------------------------------------------*/
++
++MODULE_DESCRIPTION ("sa1100_udc");
++MODULE_AUTHOR ("Various");
++MODULE_LICENSE ("GPL");
++
++static struct sa1100_udc memory = {
++      .gadget = {
++              .ops            = &sa1100_ops,
++              .ep0            = &memory.ep[0].ep,
++              .name           = driver_name,
++/*
++              .dev = {
++                      .bus_id         = "gadget",
++                      .release        = nop_release,
++              },
++*/
++      },
++
++      /* control endpoint */
++      .ep[0] = {
++              .ep = {
++                      .name           = ep0name,
++                      .ops            = &sa1100_ep_ops,
++                      .maxpacket      = EP0_FIFO_SIZE,
++//                    .maxpacket      = 8,
++              },
++              .dev            = &memory,
++/*
++              .reg_udccs      = &UDCCS0,
++              .reg_uddr       = &UDDR0,
++*/
++      },
++
++      /* first group of endpoints */
++      .ep[1] = {
++              .ep = {
++                      .name           = "ep1out-bulk",
++                      .ops            = &sa1100_ep_ops,
++                      .maxpacket      = BULK_FIFO_SIZE,
++//                    .maxpacket      = 64,
++              },
++              .dev            = &memory,
++/*
++              .fifo_size      = BULK_FIFO_SIZE,
++              .bEndpointAddress = USB_DIR_IN | 1,
++              .bmAttributes   = USB_ENDPOINT_XFER_BULK,
++              .reg_udccs      = &UDCCS1,
++              .reg_uddr       = &UDDR1,
++              drcmr (25)
++*/
++      },
++      .ep[2] = {
++              .ep = {
++                      .name           = "ep2in-bulk",
++                      .ops            = &sa1100_ep_ops,
++                      .maxpacket      = BULK_FIFO_SIZE,
++//                    .maxpacket      = 64,
++              },
++              .dev            = &memory,
++/*
++              .fifo_size      = BULK_FIFO_SIZE,
++              .bEndpointAddress = 2,
++              .bmAttributes   = USB_ENDPOINT_XFER_BULK,
++              .reg_udccs      = &UDCCS2,
++              .reg_ubcr       = &UBCR2,
++              .reg_uddr       = &UDDR2,
++              drcmr (26)
++*/
++      }
++};
++\r
++static int __init sa1100_udc_probe ( struct device *_dev)
++{
++      struct sa1100_udc *dev=&memory;
++      int retval = 0;
++
++      /* setup dev */
++      dev->dev = _dev;
++//    dev->mach = _dev->platform_data;
++
++      device_initialize(&dev->gadget.dev);
++      dev->gadget.dev.parent = _dev;
++      dev->gadget.dev.dma_mask = _dev->dma_mask;
++
++      the_controller = dev;
++      dev_set_drvdata(_dev, dev);
++
++      /* controller stays disabled until gadget driver is bound */
++      udc_disable (dev);
++      udc_reinit(dev);
++
++//    spin_lock_init(&the_udc.lock);
++      register_proc_entry ();
++
++      /* setup dma channels and IRQ */
++      retval = sa1100_request_dma(DMA_Ser0UDCRd, "USB receive",
++                                  NULL, NULL, &dev->ep[1].dmaregs);
++      if (retval) {
++              ERROR (dev, "couldn't get rx dma, err %d\n", retval);
++              goto err_rx_dma;
++      }
++      retval = sa1100_request_dma(DMA_Ser0UDCWr, "USB transmit",
++                                  NULL, NULL, &dev->ep[2].dmaregs);
++      if (retval) {
++              ERROR (dev, "couldn't get tx dma, err %d\n", retval);
++              goto err_tx_dma;
++      }
++      retval = request_irq (IRQ_Ser0UDC, udc_int_hndlr, SA_INTERRUPT,
++              driver_name, dev);
++      if (retval) {
++              ERROR (dev, "couldn't get irq, err %d\n", retval);
++              goto err_irq;
++      }
++
++      INFO (dev, "initialized, rx %p tx %p irq %d\n",
++              dev->ep[1].dmaregs, dev->ep[2].dmaregs, IRQ_Ser0UDC);
++      return 0;
++
++err_irq:
++      sa1100_free_dma (dev->ep[2].dmaregs);
++      usbd_info.dmaregs_rx = 0;
++err_tx_dma:
++      sa1100_free_dma (dev->ep[1].dmaregs);
++      usbd_info.dmaregs_tx = 0;
++err_rx_dma:
++      return retval;
++}
++
++static int __exit sa1100_udc_remove (struct device *_dev)
++{
++      struct sa1100_udc *dev = dev_get_drvdata(_dev);
++      
++      udc_disable (dev);
++      unregister_proc_entry ();
++      usb_gadget_unregister_driver (dev->driver);
++      sa1100_free_dma (dev->ep[1].dmaregs);
++      sa1100_free_dma (dev->ep[2].dmaregs);
++      free_irq (IRQ_Ser0UDC, dev);
++      dev_set_drvdata(_dev,NULL);
++      the_controller = NULL;
++      return 0;
++}
++
++static struct device_driver udc_driver = {
++      .name           = "sa11x0-udc",
++      .bus            = &platform_bus_type,
++      .probe          = sa1100_udc_probe,
++      .remove         = __exit_p(sa1100_udc_remove),
++//    .suspend        = sa1100_udc_suspend,
++//    .resume         = sa1100_udc_resume,
++};
++
++static int __init udc_init(void)
++{
++      printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION);
++#ifdef NCB_DMA_FIX
++      send_buffer = (char*) kmalloc( SEND_BUFFER_SIZE, GFP_KERNEL | GFP_DMA );
++      receive_buffer = (char*) kmalloc( RECEIVE_BUFFER_SIZE, GFP_KERNEL | GFP_DMA );
++#endif
++      return driver_register(&udc_driver);
++}
++module_init(udc_init);
++
++static void __exit udc_exit(void)
++{
++#ifdef NCB_DMA_FIX
++      if (send_buffer) {
++          kfree(send_buffer);
++          send_buffer=NULL;
++      }
++      if (receive_buffer) {
++          kfree(receive_buffer);
++          receive_buffer=NULL;
++      }
++#endif
++      driver_unregister(&udc_driver);
++}
++module_exit(udc_exit);
++
+diff -uNr linux-2.6.21.vanilla/drivers/usb/gadget/sa1100_udc.h linux-2.6.21/drivers/usb/gadget/sa1100_udc.h
+--- linux-2.6.21.vanilla/drivers/usb/gadget/sa1100_udc.h       1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.21/drivers/usb/gadget/sa1100_udc.h       2007-06-05 11:58:29.000000000 +0200
+@@ -0,0 +1,107 @@
++/*\r
++ * internals of "new style" UDC controller\r
++ * <linux/usb_gadget.h> replaces ARM-specific "sa1100_usb.h".\r
++ */\r
++\r
++struct sa1100_ep {\r
++      struct usb_ep                           ep;\r
++      struct sa1100_udc                       *dev;\r
++      //unsigned long                         irqs;\r
++\r
++      const struct usb_endpoint_descriptor    *desc;\r
++      struct list_head                        queue;\r
++      dma_regs_t                              *dmaregs;
++      unsigned                                stopped : 1;\r
++};\r
++\r
++struct sa1100_request {\r
++      struct usb_request                      req;\r
++      struct list_head                        queue;\r
++// NCB        unsigned                                mapped : 1;\r
++};\r
++\r
++enum ep0_state { 
++      EP0_IDLE,
++      EP0_IN_DATA_PHASE,
++      EP0_OUT_DATA_PHASE,
++      EP0_END_XFER,
++      EP0_STALL,
++};
++
++//#define EP0_FIFO_SIZE       ((unsigned)16)
++#define EP0_FIFO_SIZE ((unsigned)8)
++#define BULK_FIFO_SIZE        ((unsigned)64)
++//#define ISO_FIFO_SIZE       ((unsigned)256)
++//#define INT_FIFO_SIZE       ((unsigned)8)
++
++struct udc_stats {
++      struct ep0stats {
++              unsigned long           ops;
++              unsigned long           bytes;
++      } read, write;
++      unsigned long                   irqs;
++};
++
++struct sa1100_udc {\r
++      struct usb_gadget                       gadget;\r
++      struct usb_gadget_driver                *driver;
++      struct device                           *dev;
++      enum ep0_state                          ep0state;
++      struct udc_stats                        stats;
++// NCB        spinlock_t                              lock;\r
++// NCB        dma_regs_t                              *dmaregs_tx, *dmaregs_rx;\r
++      unsigned                                got_irq : 1,
++                                              vbus : 1,
++                                              pullup : 1,
++                                              has_cfr : 1,
++                                              req_pending : 1,
++                                              req_std : 1,
++                                              req_config : 1;
++
++#define start_watchdog(dev) mod_timer(&dev->timer, jiffies + (HZ/200))
++      struct timer_list                       timer;
++      u64 dma_mask;
++      unsigned char                           address;\r
++      struct sa1100_ep                        ep[3];
++      int                                     ep0_req_len;
++};\r
++\r
++/*-------------------------------------------------------------------------*/\r
++\r
++#define xprintk(dev,level,fmt,args...) \\r
++      printk(level "%s: " fmt , driver_name , ## args)\r
++\r
++#ifdef DEBUG\r
++#undef DEBUG\r
++#define DEBUG(dev,fmt,args...) \\r
++      xprintk(dev , KERN_DEBUG , fmt , ## args)\r
++#else\r
++#define DEBUG(dev,fmt,args...) \\r
++      do { } while (0)\r
++#endif /* DEBUG */\r
++\r
++#ifdef VERBOSE\r
++#define VDEBUG DEBUG\r
++#else\r
++#define VDEBUG(dev,fmt,args...) \\r
++      do { } while (0)\r
++#endif        /* VERBOSE */\r
++\r
++#define ERROR(dev,fmt,args...) \\r
++      xprintk(dev , KERN_ERR , fmt , ## args)\r
++#define WARN(dev,fmt,args...) \\r
++      xprintk(dev , KERN_WARNING , fmt , ## args)\r
++#define INFO(dev,fmt,args...) \\r
++      xprintk(dev , KERN_INFO , fmt , ## args)\r
++\r
++/*-------------------------------------------------------------------------*/\r
++\r
++#ifndef       container_of\r
++#define container_of list_entry\r
++#endif\r
++\r
++#ifndef WARN_ON\r
++#define       WARN_ON(x)      do { } while (0)\r
++#endif\r
++\r
++\r
+diff -uNr linux-2.6.21.vanilla/include/linux/usb_ch9.h linux-2.6.21/include/linux/usb_ch9.h
+--- linux-2.6.21.vanilla/include/linux/usb_ch9.h       1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.21/include/linux/usb_ch9.h       2007-06-05 11:58:29.000000000 +0200
+@@ -0,0 +1,555 @@
++/*
++ * This file holds USB constants and structures that are needed for USB
++ * device APIs.  These are used by the USB device model, which is defined
++ * in chapter 9 of the USB 2.0 specification.  Linux has several APIs in C
++ * that need these:
++ *
++ * - the master/host side Linux-USB kernel driver API;
++ * - the "usbfs" user space API; and
++ * - the Linux "gadget" slave/device/peripheral side driver API.
++ *
++ * USB 2.0 adds an additional "On The Go" (OTG) mode, which lets systems
++ * act either as a USB master/host or as a USB slave/device.  That means
++ * the master and slave side APIs benefit from working well together.
++ *
++ * There's also "Wireless USB", using low power short range radios for
++ * peripheral interconnection but otherwise building on the USB framework.
++ */
++
++#ifndef __LINUX_USB_CH9_H
++#define __LINUX_USB_CH9_H
++
++#include <linux/types.h>      /* __u8 etc */
++
++/*-------------------------------------------------------------------------*/
++
++/* CONTROL REQUEST SUPPORT */
++
++/*
++ * USB directions
++ *
++ * This bit flag is used in endpoint descriptors' bEndpointAddress field.
++ * It's also one of three fields in control requests bRequestType.
++ */
++#define USB_DIR_OUT                   0               /* to device */
++#define USB_DIR_IN                    0x80            /* to host */
++
++/*
++ * USB types, the second of three bRequestType fields
++ */
++#define USB_TYPE_MASK                 (0x03 << 5)
++#define USB_TYPE_STANDARD             (0x00 << 5)
++#define USB_TYPE_CLASS                        (0x01 << 5)
++#define USB_TYPE_VENDOR                       (0x02 << 5)
++#define USB_TYPE_RESERVED             (0x03 << 5)
++
++/*
++ * USB recipients, the third of three bRequestType fields
++ */
++#define USB_RECIP_MASK                        0x1f
++#define USB_RECIP_DEVICE              0x00
++#define USB_RECIP_INTERFACE           0x01
++#define USB_RECIP_ENDPOINT            0x02
++#define USB_RECIP_OTHER                       0x03
++
++/*
++ * Standard requests, for the bRequest field of a SETUP packet.
++ *
++ * These are qualified by the bRequestType field, so that for example
++ * TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved
++ * by a GET_STATUS request.
++ */
++#define USB_REQ_GET_STATUS            0x00
++#define USB_REQ_CLEAR_FEATURE         0x01
++#define USB_REQ_SET_FEATURE           0x03
++#define USB_REQ_SET_ADDRESS           0x05
++#define USB_REQ_GET_DESCRIPTOR                0x06
++#define USB_REQ_SET_DESCRIPTOR                0x07
++#define USB_REQ_GET_CONFIGURATION     0x08
++#define USB_REQ_SET_CONFIGURATION     0x09
++#define USB_REQ_GET_INTERFACE         0x0A
++#define USB_REQ_SET_INTERFACE         0x0B
++#define USB_REQ_SYNCH_FRAME           0x0C
++
++#define USB_REQ_SET_ENCRYPTION                0x0D    /* Wireless USB */
++#define USB_REQ_GET_ENCRYPTION                0x0E
++#define USB_REQ_SET_HANDSHAKE         0x0F
++#define USB_REQ_GET_HANDSHAKE         0x10
++#define USB_REQ_SET_CONNECTION                0x11
++#define USB_REQ_SET_SECURITY_DATA     0x12
++#define USB_REQ_GET_SECURITY_DATA     0x13
++#define USB_REQ_SET_WUSB_DATA         0x14
++#define USB_REQ_LOOPBACK_DATA_WRITE   0x15
++#define USB_REQ_LOOPBACK_DATA_READ    0x16
++#define USB_REQ_SET_INTERFACE_DS      0x17
++
++/*
++ * USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and
++ * are read as a bit array returned by USB_REQ_GET_STATUS.  (So there
++ * are at most sixteen features of each type.)
++ */
++#define USB_DEVICE_SELF_POWERED               0       /* (read only) */
++#define USB_DEVICE_REMOTE_WAKEUP      1       /* dev may initiate wakeup */
++#define USB_DEVICE_TEST_MODE          2       /* (wired high speed only) */
++#define USB_DEVICE_BATTERY            2       /* (wireless) */
++#define USB_DEVICE_B_HNP_ENABLE               3       /* (otg) dev may initiate HNP */
++#define USB_DEVICE_WUSB_DEVICE                3       /* (wireless)*/
++#define USB_DEVICE_A_HNP_SUPPORT      4       /* (otg) RH port supports HNP */
++#define USB_DEVICE_A_ALT_HNP_SUPPORT  5       /* (otg) other RH port does */
++#define USB_DEVICE_DEBUG_MODE         6       /* (special devices only) */
++
++#define USB_ENDPOINT_HALT             0       /* IN/OUT will STALL */
++
++
++/**
++ * struct usb_ctrlrequest - SETUP data for a USB device control request
++ * @bRequestType: matches the USB bmRequestType field
++ * @bRequest: matches the USB bRequest field
++ * @wValue: matches the USB wValue field (le16 byte order)
++ * @wIndex: matches the USB wIndex field (le16 byte order)
++ * @wLength: matches the USB wLength field (le16 byte order)
++ *
++ * This structure is used to send control requests to a USB device.  It matches
++ * the different fields of the USB 2.0 Spec section 9.3, table 9-2.  See the
++ * USB spec for a fuller description of the different fields, and what they are
++ * used for.
++ *
++ * Note that the driver for any interface can issue control requests.
++ * For most devices, interfaces don't coordinate with each other, so
++ * such requests may be made at any time.
++ */
++struct usb_ctrlrequest {
++      __u8 bRequestType;
++      __u8 bRequest;
++      __le16 wValue;
++      __le16 wIndex;
++      __le16 wLength;
++} __attribute__ ((packed));
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * STANDARD DESCRIPTORS ... as returned by GET_DESCRIPTOR, or
++ * (rarely) accepted by SET_DESCRIPTOR.
++ *
++ * Note that all multi-byte values here are encoded in little endian
++ * byte order "on the wire".  But when exposed through Linux-USB APIs,
++ * they've been converted to cpu byte order.
++ */
++
++/*
++ * Descriptor types ... USB 2.0 spec table 9.5
++ */
++#define USB_DT_DEVICE                 0x01
++#define USB_DT_CONFIG                 0x02
++#define USB_DT_STRING                 0x03
++#define USB_DT_INTERFACE              0x04
++#define USB_DT_ENDPOINT                       0x05
++#define USB_DT_DEVICE_QUALIFIER               0x06
++#define USB_DT_OTHER_SPEED_CONFIG     0x07
++#define USB_DT_INTERFACE_POWER                0x08
++/* these are from a minor usb 2.0 revision (ECN) */
++#define USB_DT_OTG                    0x09
++#define USB_DT_DEBUG                  0x0a
++#define USB_DT_INTERFACE_ASSOCIATION  0x0b
++/* these are from the Wireless USB spec */
++#define USB_DT_SECURITY                       0x0c
++#define USB_DT_KEY                    0x0d
++#define USB_DT_ENCRYPTION_TYPE                0x0e
++#define USB_DT_BOS                    0x0f
++#define USB_DT_DEVICE_CAPABILITY      0x10
++#define USB_DT_WIRELESS_ENDPOINT_COMP 0x11
++
++/* conventional codes for class-specific descriptors */
++#define USB_DT_CS_DEVICE              0x21
++#define USB_DT_CS_CONFIG              0x22
++#define USB_DT_CS_STRING              0x23
++#define USB_DT_CS_INTERFACE           0x24
++#define USB_DT_CS_ENDPOINT            0x25
++
++/* All standard descriptors have these 2 fields at the beginning */
++struct usb_descriptor_header {
++      __u8  bLength;
++      __u8  bDescriptorType;
++} __attribute__ ((packed));
++
++
++/*-------------------------------------------------------------------------*/
++
++/* USB_DT_DEVICE: Device descriptor */
++struct usb_device_descriptor {
++      __u8  bLength;
++      __u8  bDescriptorType;
++
++      __le16 bcdUSB;
++      __u8  bDeviceClass;
++      __u8  bDeviceSubClass;
++      __u8  bDeviceProtocol;
++      __u8  bMaxPacketSize0;
++      __le16 idVendor;
++      __le16 idProduct;
++      __le16 bcdDevice;
++      __u8  iManufacturer;
++      __u8  iProduct;
++      __u8  iSerialNumber;
++      __u8  bNumConfigurations;
++} __attribute__ ((packed));
++
++#define USB_DT_DEVICE_SIZE            18
++
++
++/*
++ * Device and/or Interface Class codes
++ * as found in bDeviceClass or bInterfaceClass
++ * and defined by www.usb.org documents
++ */
++#define USB_CLASS_PER_INTERFACE               0       /* for DeviceClass */
++#define USB_CLASS_AUDIO                       1
++#define USB_CLASS_COMM                        2
++#define USB_CLASS_HID                 3
++#define USB_CLASS_PHYSICAL            5
++#define USB_CLASS_STILL_IMAGE         6
++#define USB_CLASS_PRINTER             7
++#define USB_CLASS_MASS_STORAGE                8
++#define USB_CLASS_HUB                 9
++#define USB_CLASS_CDC_DATA            0x0a
++#define USB_CLASS_CSCID                       0x0b    /* chip+ smart card */
++#define USB_CLASS_CONTENT_SEC         0x0d    /* content security */
++#define USB_CLASS_VIDEO                       0x0e
++#define USB_CLASS_WIRELESS_CONTROLLER 0xe0
++#define USB_CLASS_APP_SPEC            0xfe
++#define USB_CLASS_VENDOR_SPEC         0xff
++
++/*-------------------------------------------------------------------------*/
++
++/* USB_DT_CONFIG: Configuration descriptor information.
++ *
++ * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the
++ * descriptor type is different.  Highspeed-capable devices can look
++ * different depending on what speed they're currently running.  Only
++ * devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG
++ * descriptors.
++ */
++struct usb_config_descriptor {
++      __u8  bLength;
++      __u8  bDescriptorType;
++
++      __le16 wTotalLength;
++      __u8  bNumInterfaces;
++      __u8  bConfigurationValue;
++      __u8  iConfiguration;
++      __u8  bmAttributes;
++      __u8  bMaxPower;
++} __attribute__ ((packed));
++
++#define USB_DT_CONFIG_SIZE            9
++
++/* from config descriptor bmAttributes */
++#define USB_CONFIG_ATT_ONE            (1 << 7)        /* must be set */
++#define USB_CONFIG_ATT_SELFPOWER      (1 << 6)        /* self powered */
++#define USB_CONFIG_ATT_WAKEUP         (1 << 5)        /* can wakeup */
++#define USB_CONFIG_ATT_BATTERY                (1 << 4)        /* battery powered */
++
++/*-------------------------------------------------------------------------*/
++
++/* USB_DT_STRING: String descriptor */
++struct usb_string_descriptor {
++      __u8  bLength;
++      __u8  bDescriptorType;
++
++      __le16 wData[1];                /* UTF-16LE encoded */
++} __attribute__ ((packed));
++
++/* note that "string" zero is special, it holds language codes that
++ * the device supports, not Unicode characters.
++ */
++
++/*-------------------------------------------------------------------------*/
++
++/* USB_DT_INTERFACE: Interface descriptor */
++struct usb_interface_descriptor {
++      __u8  bLength;
++      __u8  bDescriptorType;
++
++      __u8  bInterfaceNumber;
++      __u8  bAlternateSetting;
++      __u8  bNumEndpoints;
++      __u8  bInterfaceClass;
++      __u8  bInterfaceSubClass;
++      __u8  bInterfaceProtocol;
++      __u8  iInterface;
++} __attribute__ ((packed));
++
++#define USB_DT_INTERFACE_SIZE         9
++
++/*-------------------------------------------------------------------------*/
++
++/* USB_DT_ENDPOINT: Endpoint descriptor */
++struct usb_endpoint_descriptor {
++      __u8  bLength;
++      __u8  bDescriptorType;
++
++      __u8  bEndpointAddress;
++      __u8  bmAttributes;
++      __le16 wMaxPacketSize;
++      __u8  bInterval;
++
++      /* NOTE:  these two are _only_ in audio endpoints. */
++      /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
++      __u8  bRefresh;
++      __u8  bSynchAddress;
++} __attribute__ ((packed));
++
++#define USB_DT_ENDPOINT_SIZE          7
++#define USB_DT_ENDPOINT_AUDIO_SIZE    9       /* Audio extension */
++
++
++/*
++ * Endpoints
++ */
++#define USB_ENDPOINT_NUMBER_MASK      0x0f    /* in bEndpointAddress */
++#define USB_ENDPOINT_DIR_MASK         0x80
++
++#define USB_ENDPOINT_XFERTYPE_MASK    0x03    /* in bmAttributes */
++#define USB_ENDPOINT_XFER_CONTROL     0
++#define USB_ENDPOINT_XFER_ISOC                1
++#define USB_ENDPOINT_XFER_BULK                2
++#define USB_ENDPOINT_XFER_INT         3
++#define USB_ENDPOINT_MAX_ADJUSTABLE   0x80
++
++
++/*-------------------------------------------------------------------------*/
++
++/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */
++struct usb_qualifier_descriptor {
++      __u8  bLength;
++      __u8  bDescriptorType;
++
++      __le16 bcdUSB;
++      __u8  bDeviceClass;
++      __u8  bDeviceSubClass;
++      __u8  bDeviceProtocol;
++      __u8  bMaxPacketSize0;
++      __u8  bNumConfigurations;
++      __u8  bRESERVED;
++} __attribute__ ((packed));
++
++
++/*-------------------------------------------------------------------------*/
++
++/* USB_DT_OTG (from OTG 1.0a supplement) */
++struct usb_otg_descriptor {
++      __u8  bLength;
++      __u8  bDescriptorType;
++
++      __u8  bmAttributes;     /* support for HNP, SRP, etc */
++} __attribute__ ((packed));
++
++/* from usb_otg_descriptor.bmAttributes */
++#define USB_OTG_SRP           (1 << 0)
++#define USB_OTG_HNP           (1 << 1)        /* swap host/device roles */
++
++/*-------------------------------------------------------------------------*/
++
++/* USB_DT_DEBUG:  for special highspeed devices, replacing serial console */
++struct usb_debug_descriptor {
++      __u8  bLength;
++      __u8  bDescriptorType;
++
++      /* bulk endpoints with 8 byte maxpacket */
++      __u8  bDebugInEndpoint;
++      __u8  bDebugOutEndpoint;
++};
++
++/*-------------------------------------------------------------------------*/
++
++/* USB_DT_INTERFACE_ASSOCIATION: groups interfaces */
++struct usb_interface_assoc_descriptor {
++      __u8  bLength;
++      __u8  bDescriptorType;
++
++      __u8  bFirstInterface;
++      __u8  bInterfaceCount;
++      __u8  bFunctionClass;
++      __u8  bFunctionSubClass;
++      __u8  bFunctionProtocol;
++      __u8  iFunction;
++} __attribute__ ((packed));
++
++
++/*-------------------------------------------------------------------------*/
++
++/* USB_DT_SECURITY:  group of wireless security descriptors, including
++ * encryption types available for setting up a CC/association.
++ */
++struct usb_security_descriptor {
++      __u8  bLength;
++      __u8  bDescriptorType;
++
++      __le16 wTotalLength;
++      __u8  bNumEncryptionTypes;
++};
++
++/*-------------------------------------------------------------------------*/
++
++/* USB_DT_KEY:  used with {GET,SET}_SECURITY_DATA; only public keys
++ * may be retrieved.
++ */
++struct usb_key_descriptor {
++      __u8  bLength;
++      __u8  bDescriptorType;
++
++      __u8  tTKID[3];
++      __u8  bReserved;
++      __u8  bKeyData[0];
++};
++
++/*-------------------------------------------------------------------------*/
++
++/* USB_DT_ENCRYPTION_TYPE:  bundled in DT_SECURITY groups */
++struct usb_encryption_descriptor {
++      __u8  bLength;
++      __u8  bDescriptorType;
++
++      __u8  bEncryptionType;
++#define       USB_ENC_TYPE_UNSECURE           0
++#define       USB_ENC_TYPE_WIRED              1       /* non-wireless mode */
++#define       USB_ENC_TYPE_CCM_1              2       /* aes128/cbc session */
++#define       USB_ENC_TYPE_RSA_1              3       /* rsa3072/sha1 auth */
++      __u8  bEncryptionValue;         /* use in SET_ENCRYPTION */
++      __u8  bAuthKeyIndex;
++};
++
++
++/*-------------------------------------------------------------------------*/
++
++/* USB_DT_BOS:  group of wireless capabilities */
++struct usb_bos_descriptor {
++      __u8  bLength;
++      __u8  bDescriptorType;
++
++      __le16 wTotalLength;
++      __u8  bNumDeviceCaps;
++};
++
++/*-------------------------------------------------------------------------*/
++
++/* USB_DT_DEVICE_CAPABILITY:  grouped with BOS */
++struct usb_dev_cap_header {
++      __u8  bLength;
++      __u8  bDescriptorType;
++      __u8  bDevCapabilityType;
++};
++
++#define       USB_CAP_TYPE_WIRELESS_USB       1
++
++struct usb_wireless_cap_descriptor {  /* Ultra Wide Band */
++      __u8  bLength;
++      __u8  bDescriptorType;
++      __u8  bDevCapabilityType;
++
++      __u8  bmAttributes;
++#define       USB_WIRELESS_P2P_DRD            (1 << 1)
++#define       USB_WIRELESS_BEACON_MASK        (3 << 2)
++#define       USB_WIRELESS_BEACON_SELF        (1 << 2)
++#define       USB_WIRELESS_BEACON_DIRECTED    (2 << 2)
++#define       USB_WIRELESS_BEACON_NONE        (3 << 2)
++      __le16 wPHYRates;       /* bit rates, Mbps */
++#define       USB_WIRELESS_PHY_53             (1 << 0)        /* always set */
++#define       USB_WIRELESS_PHY_80             (1 << 1)
++#define       USB_WIRELESS_PHY_107            (1 << 2)        /* always set */
++#define       USB_WIRELESS_PHY_160            (1 << 3)
++#define       USB_WIRELESS_PHY_200            (1 << 4)        /* always set */
++#define       USB_WIRELESS_PHY_320            (1 << 5)
++#define       USB_WIRELESS_PHY_400            (1 << 6)
++#define       USB_WIRELESS_PHY_480            (1 << 7)
++      __u8  bmTFITXPowerInfo; /* TFI power levels */
++      __u8  bmFFITXPowerInfo; /* FFI power levels */
++      __le16 bmBandGroup;
++      __u8  bReserved;
++};
++
++/*-------------------------------------------------------------------------*/
++
++/* USB_DT_WIRELESS_ENDPOINT_COMP:  companion descriptor associated with
++ * each endpoint descriptor for a wireless device
++ */
++struct usb_wireless_ep_comp_descriptor {
++      __u8  bLength;
++      __u8  bDescriptorType;
++
++      __u8  bMaxBurst;
++      __u8  bMaxSequence;
++      __le16 wMaxStreamDelay;
++      __le16 wOverTheAirPacketSize;
++      __u8  bOverTheAirInterval;
++      __u8  bmCompAttributes;
++#define USB_ENDPOINT_SWITCH_MASK      0x03    /* in bmCompAttributes */
++#define USB_ENDPOINT_SWITCH_NO                0
++#define USB_ENDPOINT_SWITCH_SWITCH    1
++#define USB_ENDPOINT_SWITCH_SCALE     2
++};
++
++/*-------------------------------------------------------------------------*/
++
++/* USB_REQ_SET_HANDSHAKE is a four-way handshake used between a wireless
++ * host and a device for connection set up, mutual authentication, and
++ * exchanging short lived session keys.  The handshake depends on a CC.
++ */
++struct usb_handshake {
++      __u8 bMessageNumber;
++      __u8 bStatus;
++      __u8 tTKID[3];
++      __u8 bReserved;
++      __u8 CDID[16];
++      __u8 nonce[16];
++      __u8 MIC[8];
++};
++
++/*-------------------------------------------------------------------------*/
++
++/* USB_REQ_SET_CONNECTION modifies or revokes a connection context (CC).
++ * A CC may also be set up using non-wireless secure channels (including
++ * wired USB!), and some devices may support CCs with multiple hosts.
++ */
++struct usb_connection_context {
++      __u8 CHID[16];          /* persistent host id */
++      __u8 CDID[16];          /* device id (unique w/in host context) */
++      __u8 CK[16];            /* connection key */
++};
++
++/*-------------------------------------------------------------------------*/
++
++/* USB 2.0 defines three speeds, here's how Linux identifies them */
++
++enum usb_device_speed {
++      USB_SPEED_UNKNOWN = 0,                  /* enumerating */
++      USB_SPEED_LOW, USB_SPEED_FULL,          /* usb 1.1 */
++      USB_SPEED_HIGH,                         /* usb 2.0 */
++      USB_SPEED_VARIABLE,                     /* wireless (usb 2.5) */
++};
++
++enum usb_device_state {
++      /* NOTATTACHED isn't in the USB spec, and this state acts
++       * the same as ATTACHED ... but it's clearer this way.
++       */
++      USB_STATE_NOTATTACHED = 0,
++
++      /* chapter 9 and authentication (wireless) device states */
++      USB_STATE_ATTACHED,
++      USB_STATE_POWERED,                      /* wired */
++      USB_STATE_UNAUTHENTICATED,              /* auth */
++      USB_STATE_RECONNECTING,                 /* auth */
++      USB_STATE_DEFAULT,                      /* limited function */
++      USB_STATE_ADDRESS,
++      USB_STATE_CONFIGURED,                   /* most functions */
++
++      USB_STATE_SUSPENDED
++
++      /* NOTE:  there are actually four different SUSPENDED
++       * states, returning to POWERED, DEFAULT, ADDRESS, or
++       * CONFIGURED respectively when SOF tokens flow again.
++       */
++};
++
++#endif        /* __LINUX_USB_CH9_H */