aboutsummaryrefslogtreecommitdiffstats
path: root/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/usb-storage.patch
diff options
context:
space:
mode:
Diffstat (limited to 'linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/usb-storage.patch')
-rw-r--r--linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/usb-storage.patch3433
1 files changed, 3433 insertions, 0 deletions
diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/usb-storage.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/usb-storage.patch
index e69de29bb2..c9296cf224 100644
--- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/usb-storage.patch
+++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/usb-storage.patch
@@ -0,0 +1,3433 @@
+diff -Nur linux-2.4.18/drivers/usb/device/bi/sa1100.c linux-2.4.18-usb-storage/drivers/usb/device/bi/sa1100.c
+--- linux-2.4.18/drivers/usb/device/bi/sa1100.c 2003-05-13 13:18:44.000000000 +0400
++++ linux-2.4.18-usb-storage/drivers/usb/device/bi/sa1100.c 2004-03-01 07:20:38.000000000 +0300
+@@ -440,6 +440,7 @@
+ udc_interrupts, *(UDCSR), *(UDCCS0), *(UDCAR));
+
+ usbd_device_event (udc_device, DEVICE_RESET, 0);
++ usbd_device_event (udc_device, DEVICE_ADDRESS_ASSIGNED,0);
+ }
+
+ if (status & UDCSR_SUSIR) {
+diff -Nur linux-2.4.18/drivers/usb/device/Config.in linux-2.4.18-usb-storage/drivers/usb/device/Config.in
+--- linux-2.4.18/drivers/usb/device/Config.in 2003-05-13 13:18:45.000000000 +0400
++++ linux-2.4.18-usb-storage/drivers/usb/device/Config.in 2003-11-07 05:35:14.000000000 +0300
+@@ -34,6 +34,7 @@
+ comment 'USB Device functions'
+ source drivers/usb/device/net_fd/Config.in
+ source drivers/usb/device/serial_fd/Config.in
++ source drivers/usb/device/storage_fd/Config.in
+
+ comment 'USB Device bus interfaces'
+ source drivers/usb/device/bi/Config.in
+diff -Nur linux-2.4.18/drivers/usb/device/Makefile linux-2.4.18-usb-storage/drivers/usb/device/Makefile
+--- linux-2.4.18/drivers/usb/device/Makefile 2003-05-13 13:18:45.000000000 +0400
++++ linux-2.4.18-usb-storage/drivers/usb/device/Makefile 2003-11-07 05:35:01.000000000 +0300
+@@ -20,6 +20,7 @@
+
+ subdir-$(CONFIG_USBD_NET) += net_fd
+ subdir-$(CONFIG_USBD_SERIAL) += serial_fd
++subdir-$(CONFIG_USBD_STORAGE) += storage_fd
+
+ #subdir-$(CONFIG_USBD_GENERIC_BUS) += gen_bi
+ #subdir-$(CONFIG_USBD_L7205_BUS) += l7205_bi
+diff -Nur linux-2.4.18/drivers/usb/device/storage_fd/Config.help linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/Config.help
+--- linux-2.4.18/drivers/usb/device/storage_fd/Config.help 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/Config.help 2003-11-07 05:34:43.000000000 +0300
+@@ -0,0 +1,55 @@
++CONFIG_USBD_STORAGE
++ Enable the generic mass storage function driver. This function is
++ used emulating a Linux block driver.
++
++CONFIG_USBD_STORAGE_VENDORID
++ Optionally specify the mass storage USB Device Vendor ID. The top
++ level Vendor ID will be used if this is not specified.
++
++CONFIG_USBD_STORAGE_PRODUCTID
++ Optionally specify the mass storage USB Device Product ID. The top
++ level Vendor ID will be used if this is not specified.
++
++CONFIG_USBD_STORAGE_OUT_ENDPOINT
++ Specify the preferred OUT (received data) endpoint number. This is a
++ number from 0-15 and must be allowed by the bus interface device.
++
++ Some devices such as the SA-1110 or L7205/L7210 may override this
++ value with a fixed value.
++
++CONFIG_USBD_STORAGE_IN_ENDPOINT
++ Specify the preferred IN (transmit data) endpoint number. This is a
++ number from 0-15 and must be allowed by the bus interface device.
++
++ Some devices such as the SA-1110 or L7205/L7210 may override this
++ value with a fixed value.
++
++CONFIG_USBD_STORAGE_INT_ENDPOINT
++ Specify the preferred INT (interrupt) endpoint number. This is a
++ number from 0-15 and must be allowed by the bus interface device.
++
++ Some devices such as the L7205/L7210 may override this value with a
++ fixed value. Others such as the SA-1110 do not allow an interrupt
++ value.
++
++CONFIG_USBD_STORAGE_OUT_PKTSIZE
++ Specify the maximum packet size for the OUT endpoint. This allowable
++ values are normally 16, 32 and 64.
++
++ Some devices such as the Linkup L7205/L7210 may override this value
++ with a lower maximum value (such as 32).
++
++CONFIG_USBD_STORAGE_IN_PKTSIZE
++ Specify the maximum packet size for the IN endpoint. This allowable
++ values are normally 16, 32 and 64.
++
++ Some devices such as the Linkup L7205/L7210 may override this value
++ with a lower maximum value (such as 32).
++
++CONFIG_USBD_STORAGE_INT_PKTSIZE
++ Specify the maximum packet size for the INT endpoint. This allowable
++ values are normally 8 and 16. Some bus interface devices may not
++ support all values.
++
++CONFIG_USBD_STORAGE_DEF_DEVICE_NAME
++ Specify the default block device name to used on mass storage.
+diff -Nur linux-2.4.18/drivers/usb/device/storage_fd/Config.in linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/Config.in
+--- linux-2.4.18/drivers/usb/device/storage_fd/Config.in 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/Config.in 2003-11-07 05:34:43.000000000 +0300
+@@ -0,0 +1,29 @@
++#
++# Generic Mass Storage Function Driver
++#
++# Copyright (c) 2003 Communication Technology Inc.
++# Copyright (C) 2001 Lineo, Inc.
++# Copyright (C) 2001 Hewlett-Packard Co.
++mainmenu_option next_comment
++comment "Mass Storage Function"
++
++dep_tristate ' Mass Storage Function Driver' CONFIG_USBD_STORAGE $CONFIG_USBD
++if [ "$CONFIG_USBD_STORAGE" = "y" -o "$CONFIG_USBD_STORAGE" = "m" ]; then
++ hex ' Overide VendorID (hex value)' CONFIG_USBD_STORAGE_VENDORID "0000"
++ hex ' Overide ProductID (hex value)' CONFIG_USBD_STORAGE_PRODUCTID "0000"
++
++ # allow setting of endpoint configurations for some architectures
++ int ' OUT Endpoint (0-15)' CONFIG_USBD_STORAGE_OUT_ENDPOINT "1"
++ int ' OUT PacketSize (16, 32, 64)' CONFIG_USBD_STORAGE_OUT_PKTSIZE "64"
++ int ' IN Endpoint (0-15)' CONFIG_USBD_STORAGE_IN_ENDPOINT "2"
++ int ' IN PacketSize (16, 32, 64)' CONFIG_USBD_STORAGE_IN_PKTSIZE "64"
++
++ if [ ! "$CONFIG_ARCH_SA1100" = "y" -a ! "$CONFIG_ARCH_L7200" = "y" ]; then
++ int ' INT Endpoint (0-15)' CONFIG_USBD_STORAGE_INT_ENDPOINT "3"
++ int ' INT PacketSize (8, 16)' CONFIG_USBD_STORAGE_INT_PKTSIZE "16"
++ fi
++
++ string ' Default Mass Storage device name' CONFIG_USBD_STORAGE_DEF_DEVICE_NAME ""
++fi
++
++endmenu
+diff -Nur linux-2.4.18/drivers/usb/device/storage_fd/Makefile linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/Makefile
+--- linux-2.4.18/drivers/usb/device/storage_fd/Makefile 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/Makefile 2003-11-07 05:34:43.000000000 +0300
+@@ -0,0 +1,58 @@
++#
++# SA1100 Function driver for a network USB Device
++#
++# Copyright (C) 2001 Lineo, Inc.
++# Copyright (C) 2001 Hewlett-Packard Co.
++
++
++O_TARGET := storage_fd_drv.o
++list-multi := storage_fd.o
++
++storage_fd-objs := storage-fd.o storageproto.o schedule_task.o # netproto.o crc32.o
++
++# Object file lists.
++
++obj-y :=
++obj-m :=
++obj-n :=
++obj- :=
++
++# Each configuration option enables a list of files.
++
++obj-$(CONFIG_USBD_STORAGE) += storage_fd.o
++
++# Extract lists of the multi-part drivers.
++# The 'int-*' lists are the intermediate files used to build the multi's.
++
++multi-y := $(filter $(list-multi), $(obj-y))
++multi-m := $(filter $(list-multi), $(obj-m))
++int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
++int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
++
++# Files that are both resident and modular: remove from modular.
++
++obj-m := $(filter-out $(obj-y), $(obj-m))
++int-m := $(filter-out $(int-y), $(int-m))
++
++# Translate to Rules.make lists.
++
++O_OBJS := $(filter-out $(export-objs), $(obj-y))
++OX_OBJS := $(filter $(export-objs), $(obj-y))
++M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
++MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
++MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m)))
++MIX_OBJS := $(sort $(filter $(export-objs), $(int-m)))
++
++# The global Rules.make.
++
++include $(TOPDIR)/Rules.make
++
++# Link rules for multi-part drivers.
++
++storage_fd.o: $(storage_fd-objs)
++ $(LD) -r -o $@ $(storage_fd-objs)
++
++# dependencies:
++
++storage-fd.o: ../usbd.h ../usbd-bus.h ../usbd-func.h
++
+diff -Nur linux-2.4.18/drivers/usb/device/storage_fd/schedule_task.c linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/schedule_task.c
+--- linux-2.4.18/drivers/usb/device/storage_fd/schedule_task.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/schedule_task.c 2003-11-07 05:34:43.000000000 +0300
+@@ -0,0 +1,230 @@
++/*
++ * linux/drivers/usb/device/storage_fd/schedule_task.c - schedule task library
++ *
++ * Copyright (c) 2003 Lineo Solutions, Inc.
++ *
++ * Written by Shunnosuke kabata
++ *
++ * 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, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/******************************************************************************
++** Include File
++******************************************************************************/
++#include <linux/config.h>
++#include <linux/fs.h>
++#include <linux/string.h>
++#include <linux/mm.h>
++#include <linux/dcache.h>
++#include <linux/init.h>
++#include <linux/quotaops.h>
++#include <linux/slab.h>
++#include <linux/cache.h>
++#include <linux/swap.h>
++#include <linux/swapctl.h>
++#include <linux/prefetch.h>
++#include <linux/locks.h>
++#include <asm/uaccess.h>
++
++#include "schedule_task.h"
++
++/******************************************************************************
++** Macro Define
++******************************************************************************/
++#define TASK_DESC_NUM (512)
++
++/******************************************************************************
++** Structure Define
++******************************************************************************/
++
++/**************************************
++** TASK_DESC
++**************************************/
++typedef struct _TASK_DESC{
++ struct _TASK_DESC* next;
++ SCHEDULE_TASK_FUNC task_entry;
++ int task_param1;
++ int task_param2;
++ int task_param3;
++ int task_param4;
++ int task_param5;
++ char* file;
++ int line;
++} TASK_DESC;
++
++/**************************************
++** OS_WRP_TASK_DATA
++**************************************/
++typedef struct{
++ volatile TASK_DESC* read_desc;
++ volatile TASK_DESC* write_desc;
++ TASK_DESC desc_pool[TASK_DESC_NUM];
++ spinlock_t spin_lock;
++ struct tq_struct task_que;
++ unsigned long use_num;
++ unsigned long max_num;
++} TASK_DATA;
++
++/******************************************************************************
++** Variable Declaration
++******************************************************************************/
++static TASK_DATA TaskData;
++
++/******************************************************************************
++** Local Function Prototype
++******************************************************************************/
++static void task_entry(void*);
++
++/******************************************************************************
++** Global Function
++******************************************************************************/
++void schedule_task_init(void)
++{
++ int i;
++
++ /* 0 clear */
++ memset(&TaskData, 0x00, sizeof(TaskData));
++
++ /* Read/write pointer initialize */
++ TaskData.read_desc = TaskData.write_desc = &TaskData.desc_pool[0];
++
++ /* Ling buffer initialize */
++ for(i=0; i<(TASK_DESC_NUM-1); i++){
++ TaskData.desc_pool[i].next = &TaskData.desc_pool[i+1];
++ }
++ TaskData.desc_pool[i].next = &TaskData.desc_pool[0];
++
++ /* Spin lock initialize */
++ spin_lock_init(&TaskData.spin_lock);
++
++ /* Task queue initialize */
++ PREPARE_TQUEUE(&TaskData.task_que, task_entry, &TaskData);
++
++ return;
++}
++
++int schedule_task_register(SCHEDULE_TASK_FUNC entry, int param1, int param2,
++ int param3, int param4, int param5)
++{
++ unsigned long flags = 0;
++
++ spin_lock_irqsave(&TaskData.spin_lock, flags);
++
++ /* Free descriptor check */
++ if(TaskData.write_desc->next == TaskData.read_desc){
++ printk(KERN_INFO "storage_fd: schedule task no descriptor.\n");
++ spin_unlock_irqrestore(&TaskData.spin_lock, flags);
++ return -1;
++ }
++
++ /* Descriptor set */
++ TaskData.write_desc->task_entry = entry;
++ TaskData.write_desc->task_param1 = param1;
++ TaskData.write_desc->task_param2 = param2;
++ TaskData.write_desc->task_param3 = param3;
++ TaskData.write_desc->task_param4 = param4;
++ TaskData.write_desc->task_param5 = param5;
++
++ /* Pointer update */
++ TaskData.write_desc = TaskData.write_desc->next;
++
++ /* Statistics set */
++ TaskData.use_num++;
++ if(TaskData.use_num > TaskData.max_num){
++ TaskData.max_num = TaskData.use_num;
++ }
++
++ spin_unlock_irqrestore(&TaskData.spin_lock, flags);
++
++ /* Task queue register */
++ schedule_task(&TaskData.task_que);
++
++ return 0;
++}
++
++void schedule_task_all_unregister(void)
++{
++ unsigned long flags = 0;
++
++ spin_lock_irqsave(&TaskData.spin_lock, flags);
++ TaskData.read_desc = TaskData.write_desc;
++ TaskData.use_num = 0;
++ spin_unlock_irqrestore(&TaskData.spin_lock, flags);
++}
++
++ssize_t schedule_task_proc_read(struct file* file, char* buf, size_t count,
++ loff_t* pos)
++{
++ char string[1024];
++ int len = 0;
++
++ len += sprintf(string + len, "Schedule task max num:0x%d\n",
++ TASK_DESC_NUM);
++
++ len += sprintf(string + len, "Schedule task use num:0x%ld\n",
++ TaskData.use_num);
++
++ len += sprintf(string + len, "Schedule task max use num:0x%ld\n",
++ TaskData.max_num);
++
++ *pos += len;
++ if(len > count){
++ len = -EINVAL;
++ }
++ else
++ if(len > 0 && copy_to_user(buf, string, len)) {
++ len = -EFAULT;
++ }
++
++ return len;
++}
++
++/******************************************************************************
++** Local Function
++******************************************************************************/
++static void task_entry(void* data)
++{
++ int cond;
++ unsigned long flags = 0;
++ volatile TASK_DESC* desc;
++
++ for(;;){
++
++ spin_lock_irqsave(&TaskData.spin_lock, flags);
++ desc = TaskData.read_desc;
++ cond = (TaskData.read_desc == TaskData.write_desc);
++ spin_unlock_irqrestore(&TaskData.spin_lock, flags);
++
++ if(cond) break;
++
++ /* Task call */
++ desc->task_entry(desc->task_param1, desc->task_param2,
++ desc->task_param3, desc->task_param4, desc->task_param5);
++
++ spin_lock_irqsave(&TaskData.spin_lock, flags);
++
++ /* Pointer update */
++ TaskData.read_desc = TaskData.read_desc->next;
++
++ /* Statistics set */
++ TaskData.use_num--;
++
++ spin_unlock_irqrestore(&TaskData.spin_lock, flags);
++ }
++
++ return;
++}
++
+diff -Nur linux-2.4.18/drivers/usb/device/storage_fd/schedule_task.h linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/schedule_task.h
+--- linux-2.4.18/drivers/usb/device/storage_fd/schedule_task.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/schedule_task.h 2003-11-07 05:34:43.000000000 +0300
+@@ -0,0 +1,41 @@
++/*
++ * linux/drivers/usb/device/storage_fd/schedule_task.h - schedule task library header
++ *
++ * Copyright (c) 2003 Lineo Solutions, Inc.
++ *
++ * Written by Shunnosuke kabata
++ *
++ * 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, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#ifndef _SCHEDULE_TASK_H_
++#define _SCHEDULE_TASK_H_
++
++/******************************************************************************
++** Macro Define
++******************************************************************************/
++typedef int (*SCHEDULE_TASK_FUNC)(int, int, int, int, int);
++
++/******************************************************************************
++** Global Function Prototype
++******************************************************************************/
++void schedule_task_init(void);
++int schedule_task_register(SCHEDULE_TASK_FUNC, int, int, int, int, int);
++void schedule_task_all_unregister(void);
++ssize_t schedule_task_proc_read(struct file*, char*, size_t, loff_t*);
++
++#endif /* _SCHEDULE_TASK_H_ */
++
+diff -Nur linux-2.4.18/drivers/usb/device/storage_fd/storage-fd.c linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/storage-fd.c
+--- linux-2.4.18/drivers/usb/device/storage_fd/storage-fd.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/storage-fd.c 2003-11-07 05:34:43.000000000 +0300
+@@ -0,0 +1,865 @@
++/*
++ * linux/drivers/usb/device/storage_fd/storage-fd.c - mass storage function driver
++ *
++ * Copyright (c) 2003 Lineo Solutions, Inc.
++ *
++ * Written by Shunnosuke kabata
++ *
++ * 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, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Based on
++ *
++ * linux/drivers/usbd/net_fd/net-fd.c - network function driver
++ *
++ * Copyright (c) 2000, 2001, 2002 Lineo
++ * Copyright (c) 2001 Hewlett Packard
++ *
++ * By:
++ * Stuart Lynne <sl@lineo.com>,
++ * Tom Rushworth <tbr@lineo.com>,
++ * Bruce Balden <balden@lineo.com>
++ *
++ * 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, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/******************************************************************************
++** Include File
++******************************************************************************/
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include "../usbd-export.h"
++#include "../usbd-build.h"
++#include "../usbd-module.h"
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/netdevice.h>
++#include <linux/skbuff.h>
++#include <linux/etherdevice.h>
++#include <linux/rtnetlink.h>
++#include <linux/smp_lock.h>
++#include <linux/ctype.h>
++#include <linux/timer.h>
++#include <linux/string.h>
++#include <linux/atmdev.h>
++#include <linux/pkt_sched.h>
++#include <linux/delay.h>
++#include <asm/uaccess.h>
++#include <asm/system.h>
++#include <net/arp.h>
++
++#include <linux/autoconf.h>
++
++#include "../usbd.h"
++#include "../usbd-func.h"
++#include "../usbd-bus.h"
++#include "../usbd-inline.h"
++#include "../usbd-arch.h"
++#include "../hotplug.h"
++
++#include "schedule_task.h"
++#include "storageproto.h"
++
++/******************************************************************************
++** Macro Define
++******************************************************************************/
++
++/**************************************
++** Module Information
++**************************************/
++
++MODULE_AUTHOR("Shunnosuke kabata");
++MODULE_DESCRIPTION("USB Device Mass Storage Function");
++USBD_MODULE_INFO("storage_fd 0.1");
++
++/**************************************
++** Configration Check
++**************************************/
++
++#if !defined (CONFIG_USBD_VENDORID) && !defined(CONFIG_USBD_STORAGE_VENDORID)
++#error No Vendor ID
++#endif
++#if !defined (CONFIG_USBD_PRODUCTID) && !defined(CONFIG_USBD_STORAGE_PRODUCTID)
++#error No Product ID
++#endif
++
++#if defined(CONFIG_USBD_STORAGE_VENDORID) && (CONFIG_USBD_STORAGE_VENDORID > 0)
++#undef CONFIG_USBD_VENDORID
++#define CONFIG_USBD_VENDORID CONFIG_USBD_STORAGE_VENDORID
++#endif
++
++#if defined(CONFIG_USBD_STORAGE_PRODUCTID) && (CONFIG_USBD_STORAGE_PRODUCTID > 0)
++#undef CONFIG_USBD_PRODUCTID
++#define CONFIG_USBD_PRODUCTID CONFIG_USBD_STORAGE_PRODUCTID
++#endif
++
++#ifndef CONFIG_USBD_MAXPOWER
++#define CONFIG_USBD_MAXPOWER 0
++#endif
++
++#ifndef CONFIG_USBD_MANUFACTURER
++#define CONFIG_USBD_MANUFACTURER "Sharp"
++#endif
++
++#define MAXTRANSFER (512)
++
++#ifndef CONFIG_USBD_VENDORID
++#error "CONFIG_USBD_VENDORID not defined"
++#endif
++
++#ifndef CONFIG_USBD_PRODUCTID
++#error "CONFIG_USBD_PRODUCTID not defined"
++#endif
++
++#ifndef CONFIG_USBD_PRODUCT_NAME
++#define CONFIG_USBD_PRODUCT_NAME "Linux Mass Storage Driver"
++#endif
++
++#ifndef CONFIG_USBD_SERIAL_NUMBER_STR
++#define CONFIG_USBD_SERIAL_NUMBER_STR ""
++#endif
++
++/*
++ * USB 2.0 spec does not mention it, but MaxPower is expected to be at least one
++ * and is tested for in USB configuration tests.
++ */
++
++#ifdef CONFIG_USBD_SELFPOWERED
++#define BMATTRIBUTE BMATTRIBUTE_RESERVED | BMATTRIBUTE_SELF_POWERED
++#define BMAXPOWER 1
++#else
++#define BMATTRIBUTE BMATTRIBUTE_RESERVED
++#define BMAXPOWER CONFIG_USBD_MAXPOWER
++#endif
++
++/*
++ * setup some default values for pktsizes and endpoint addresses.
++ */
++
++#ifndef CONFIG_USBD_STORAGE_OUT_PKTSIZE
++#define CONFIG_USBD_STORAGE_OUT_PKTSIZE 64
++#endif
++
++#ifndef CONFIG_USBD_STORAGE_IN_PKTSIZE
++#define CONFIG_USBD_STORAGE_IN_PKTSIZE 64
++#endif
++
++#ifndef CONFIG_USBD_STORAGE_INT_PKTSIZE
++#define CONFIG_USBD_STORAGE_INT_PKTSIZE 16
++#endif
++
++#ifndef CONFIG_USBD_STORAGE_OUT_ENDPOINT
++#define CONFIG_USBD_STORAGE_OUT_ENDPOINT 1
++#endif
++
++#ifndef CONFIG_USBD_STORAGE_IN_ENDPOINT
++#define CONFIG_USBD_STORAGE_IN_ENDPOINT 2
++#endif
++
++#ifndef CONFIG_USBD_STORAGE_INT_ENDPOINT
++#define CONFIG_USBD_STORAGE_INT_ENDPOINT 3
++#endif
++
++/*
++ * check for architecture specific endpoint configurations
++ */
++
++#if defined(ABS_OUT_ADDR)
++ //#warning
++ //#warning USING ABS ENDPOINT OUT ADDRESS
++ #undef CONFIG_USBD_STORAGE_OUT_ENDPOINT
++
++ #if ABS_OUT_ADDR > 0
++ #define CONFIG_USBD_STORAGE_OUT_ENDPOINT ABS_OUT_ADDR
++ #endif
++
++#elif defined(MAX_OUT_ADDR) && defined(CONFIG_USBD_STORAGE_OUT_ENDPOINT) && (CONFIG_USBD_STORAGE_OUT_ENDPOINT > MAX_OUT_ADDR)
++ //#warning
++ //#warning USING DEFAULT ENDPOINT OUT ADDRESS
++ #undef CONFIG_USBD_STORAGE_OUT_ENDPOINT
++ #define CONFIG_USBD_STORAGE_OUT_ENDPOINT DFL_OUT_ADDR
++
++#endif /* elif */
++
++#if defined(ABS_IN_ADDR)
++ //#warning
++ //#warning USING ABS ENDPOINT IN ADDRESS
++ #undef CONFIG_USBD_STORAGE_IN_ENDPOINT
++
++ #if ABS_IN_ADDR > 0
++ #define CONFIG_USBD_STORAGE_IN_ENDPOINT ABS_IN_ADDR
++ #endif
++
++#elif defined(MAX_IN_ADDR) && defined(CONFIG_USBD_STORAGE_IN_ENDPOINT) && (CONFIG_USBD_STORAGE_IN_ENDPOINT > MAX_IN_ADDR)
++ //#warning
++ //#warning USING DEFAULT ENDPOINT IN ADDRESS
++ #undef CONFIG_USBD_STORAGE_IN_ENDPOINT
++ #define CONFIG_USBD_STORAGE_IN_ENDPOINT DFL_IN_ADDR
++
++#endif /* elif */
++
++#if defined(ABS_INT_ADDR)
++ //#warning
++ //#warning USING ABS ENDPOINT INT ADDRESS
++ #undef CONFIG_USBD_STORAGE_INT_ENDPOINT
++
++ #if ABS_INT_ADDR
++ #define CONFIG_USBD_STORAGE_INT_ENDPOINT ABS_INT_ADDR
++ #endif
++
++#elif defined(MAX_INT_ADDR) && defined(CONFIG_USBD_STORAGE_INT_ENDPOINT) && (CONFIG_USBD_STORAGE_INT_ENDPOINT > MAX_INT_ADDR)
++ //#warning
++ //#warning USING DEFAULT ENDPOINT INT ADDRESS
++ #undef CONFIG_USBD_STORAGE_INT_ENDPOINT
++ #define CONFIG_USBD_STORAGE_INT_ENDPOINT DFL_INT_ADDR
++
++#endif /* elif */
++
++#if defined(MAX_OUT_PKTSIZE) && defined(CONFIG_USBD_STORAGE_OUT_PKTSIZE) && CONFIG_USBD_STORAGE_OUT_PKTSIZE > MAX_OUT_PKTSIZE
++ //#warning
++ //#warning OVERIDING ENDPOINT OUT PKTSIZE
++ #undef CONFIG_USBD_STORAGE_OUT_PKTSIZE
++ #define CONFIG_USBD_STORAGE_OUT_PKTSIZE MAX_OUT_PKTSIZE
++#endif
++
++#if defined(MAX_IN_PKTSIZE) && defined(CONFIG_USBD_STORAGE_IN_PKTSIZE) && CONFIG_USBD_STORAGE_IN_PKTSIZE > MAX_IN_PKTSIZE
++ //#warning
++ //#warning OVERIDING ENDPOINT IN PKTSIZE
++ #undef CONFIG_USBD_STORAGE_IN_PKTSIZE
++ #define CONFIG_USBD_STORAGE_IN_PKTSIZE MAX_IN_PKTSIZE
++#endif
++
++#if defined(MAX_INT_PKTSIZE) && defined(CONFIG_USBD_STORAGE_INT_PKTSIZE) && CONFIG_USBD_STORAGE_INT_PKTSIZE > MAX_INT_PKTSIZE
++ //#warning
++ //#warning OVERIDING ENDPOINT INT PKTSIZE
++ #undef CONFIG_USBD_STORAGE_INT_PKTSIZE
++ #define CONFIG_USBD_STORAGE_INT_PKTSIZE MAX_INT_PKTSIZE
++#endif
++
++/******************************************************************************
++** Variable Declaration
++******************************************************************************/
++
++/**************************************
++** Module Parameters
++**************************************/
++
++static u32 vendor_id;
++static u32 product_id;
++static int out_pkt_sz = CONFIG_USBD_STORAGE_OUT_PKTSIZE;
++static int in_pkt_sz = CONFIG_USBD_STORAGE_IN_PKTSIZE;
++
++MODULE_PARM(vendor_id, "i");
++MODULE_PARM(product_id, "i");
++MODULE_PARM(out_pkt_sz, "i");
++MODULE_PARM(in_pkt_sz, "i");
++
++MODULE_PARM_DESC(vendor_id, "vendor id");
++MODULE_PARM_DESC(product_id, "product id");
++
++/**************************************
++** Mass Storage Configuration
++**************************************/
++
++/*
++ * Data Interface Alternate 1 endpoints
++ */
++static __initdata struct usb_endpoint_description StorageAlt1Endpoints[] = {
++ {
++ bEndpointAddress:CONFIG_USBD_STORAGE_OUT_ENDPOINT,
++ bmAttributes:BULK,
++ wMaxPacketSize:CONFIG_USBD_STORAGE_OUT_PKTSIZE,
++ bInterval:0,
++ direction:OUT,
++ transferSize:MAXTRANSFER,
++ },
++
++ {
++ bEndpointAddress:CONFIG_USBD_STORAGE_IN_ENDPOINT,
++ bmAttributes:BULK,
++ wMaxPacketSize:CONFIG_USBD_STORAGE_IN_PKTSIZE,
++ bInterval:0,
++ direction:IN,
++ transferSize:MAXTRANSFER,
++ },
++
++#if defined(CONFIG_USBD_STORAGE_INT_ENDPOINT) && (CONFIG_USBD_STORAGE_INT_ENDPOINT > 0)
++ {
++ bEndpointAddress:CONFIG_USBD_STORAGE_INT_ENDPOINT,
++ bmAttributes:INTERRUPT,
++ wMaxPacketSize:CONFIG_USBD_STORAGE_INT_PKTSIZE,
++ bInterval:10,
++ direction:IN,
++ transferSize:CONFIG_USBD_STORAGE_INT_PKTSIZE,
++ },
++#endif
++};
++
++
++/*
++ * Data Interface Alternate description(s)
++ */
++static __initdata struct usb_alternate_description StorageAlternateDescriptions[] = {
++ {
++ #if defined(CONFIG_USBD_STORAGE_NO_STRINGS)
++ iInterface:"",
++ #else
++ iInterface:"Mass Storage Interface",
++ #endif
++ bAlternateSetting:0,
++ classes:0,
++ class_list:NULL,
++ endpoints:sizeof (StorageAlt1Endpoints) / sizeof (struct usb_endpoint_description),
++ endpoint_list:StorageAlt1Endpoints,
++ },
++};
++
++/*
++ * Interface description(s)
++ */
++static __initdata struct usb_interface_description StorageInterfaces[] = {
++ {
++ #if defined(CONFIG_USBD_STORAGE_NO_STRINGS)
++ iInterface:"",
++ #else
++ iInterface:"Mass Storage Interface",
++ #endif
++ bInterfaceClass:MASS_STORAGE_CLASS,
++ bInterfaceSubClass:MASS_STORAGE_SUBCLASS_SCSI,
++ bInterfaceProtocol:MASS_STORAGE_PROTO_BULK_ONLY,
++ alternates:sizeof (StorageAlternateDescriptions) / sizeof (struct usb_alternate_description),
++ alternate_list:StorageAlternateDescriptions,
++ },
++};
++
++/******************************************************************************
++** USB Configuration
++******************************************************************************/
++
++/*
++ * Configuration description(s)
++ */
++struct __initdata usb_configuration_description StorageDescription[] = {
++ {
++ #if defined(CONFIG_USBD_STORAGE_NO_STRINGS)
++ iConfiguration:"",
++ #else
++ iConfiguration:"Mass Storage Configuration",
++ #endif
++ bmAttributes:BMATTRIBUTE,
++ bMaxPower:BMAXPOWER,
++ interfaces:sizeof (StorageInterfaces) / sizeof (struct usb_interface_description),
++ interface_list:StorageInterfaces,
++ },
++};
++
++/*
++ * Device Description
++ */
++struct __initdata usb_device_description StorageDeviceDescription = {
++ bDeviceClass:0,
++ bDeviceSubClass:0, // XXX
++ bDeviceProtocol:0, // XXX
++ idVendor:CONFIG_USBD_VENDORID,
++ idProduct:CONFIG_USBD_PRODUCTID,
++ iManufacturer:CONFIG_USBD_MANUFACTURER,
++ iProduct:CONFIG_USBD_PRODUCT_NAME,
++ iSerialNumber:CONFIG_USBD_SERIAL_NUMBER_STR,
++};
++
++/**************************************
++** Other Variable
++**************************************/
++static int storage_exit_flag = 0;
++static pid_t storage_pid = 0;
++static struct semaphore storage_sem;
++struct timer_list storage_usb_event_tim;
++
++
++/******************************************************************************
++** Global Function
++******************************************************************************/
++
++void storage_urb_send(struct usb_device_instance* device, void* buffer,
++ int length)
++{
++ int port = 0;
++ struct urb* urb;
++
++ if(!(urb = usbd_alloc_urb(device,
++ device->function_instance_array + port,
++ CONFIG_USBD_STORAGE_IN_ENDPOINT,
++ length + 5 + in_pkt_sz))){
++ printk(KERN_INFO "storage_fd: usbd_alloc_urb failed. length '%d'.\n", length);
++ return;
++ }
++
++ if(buffer){
++ memcpy(urb->buffer, buffer, length);
++ }
++ else{
++ memset(urb->buffer, 0x00, length);
++ }
++ urb->actual_length = length;
++
++ if(usbd_send_urb(urb)){
++ printk(KERN_INFO "storage_fd: usbd_send_urb failed.\n");
++ usbd_dealloc_urb(urb);
++ return;
++ }
++
++ return;
++}
++
++/******************************************************************************
++** Local Function
++******************************************************************************/
++
++/**************************************
++** Called when a USB Device is created or destroyed
++**************************************/
++
++static int storage_thread(void *_c)
++{
++ siginfo_t info;
++ unsigned long signr;
++ char buff[32];
++
++ /* current status set */
++ daemonize();
++
++ /* PID set */
++ storage_pid = current->pid;
++
++ /* thread name set */
++ sprintf(current->comm, STORAGE_THREAD_NAME);
++ (current)->nice = 10;
++
++ /* signal register */
++ spin_lock_irq(&current->sigmask_lock);
++ siginitsetinv(&current->blocked,
++ sigmask(SIGUSR1) | sigmask(SIGHUP) | sigmask(SIGKILL) |
++ sigmask(SIGSTOP) | sigmask(SIGCONT) | sigmask(SIGTERM) |
++ sigmask(SIGALRM));
++ recalc_sigpending(current);
++ spin_unlock_irq(&current->sigmask_lock);
++
++ /* media open */
++ schedule_task_register(
++ (SCHEDULE_TASK_FUNC)storageproto_media_status_check, CONTEXT_STORAGE,
++ 0, 0, 0, 0);
++
++ /* thread active indicate */
++ sprintf(buff, "%d\n", storage_pid);
++ hotplug("usbdstorage", buff, "active");
++
++ for(;;){
++ set_current_state(TASK_INTERRUPTIBLE);
++
++ if (!signal_pending(current)) {
++ schedule();
++ continue;
++ }
++
++ spin_lock_irq(&current->sigmask_lock);
++ signr = dequeue_signal(&current->blocked, &info);
++ spin_unlock_irq(&current->sigmask_lock);
++
++ switch(signr) {
++ case SIGHUP:
++ /* media signal indicate */
++ schedule_task_register(
++ (SCHEDULE_TASK_FUNC)storageproto_media_status_check, CONTEXT_STORAGE,
++ 0, 0, 0, 0);
++
++ DBG_STORAGE_FD(KERN_INFO "storage_fd: signal receive 'SIGHUP'.\n");
++ break;
++
++ default:
++ DBG_STORAGE_FD(KERN_INFO "storage_fd: signal receive '%ld'\n", signr);
++ break;
++ }
++
++ if(storage_exit_flag) break;
++ }
++ /* current status set */
++ current->state = TASK_RUNNING;
++
++ /* PID clear */
++ storage_pid = 0;
++
++ /* thread inactive indicate */
++ hotplug("usbdstorage", buff, "inactive");
++
++ up(&storage_sem);
++
++ return 0;
++}
++
++static void storage_function_init(struct usb_bus_instance* bus,
++ struct usb_device_instance* device,
++ struct usb_function_driver* function_driver)
++{
++ /* schedule task init */
++ schedule_task_init();
++
++ /* storage protocol initialize */
++ storageproto_init();
++
++ /* semaphore init */
++ sema_init(&storage_sem, 0);
++
++ /* timer initialize */
++ init_timer(&storage_usb_event_tim);
++
++ /* thread create */
++ storage_pid = kernel_thread(storage_thread, NULL, 0);
++
++ return;
++}
++
++static void storage_function_exit(struct usb_device_instance* device)
++{
++ /* thread kill */
++ storage_exit_flag = 1;
++ kill_proc(storage_pid, SIGKILL, 1);
++ down(&storage_sem);
++
++ /* delete timer */
++ del_timer(&storage_usb_event_tim);
++
++ /* storage protocol exit */
++ storageproto_exit();
++
++ /* schedule task delete */
++ schedule_task_all_unregister();
++
++ return;
++}
++
++
++/**************************************
++** Called to handle USB Events
++**************************************/
++
++static void storage_usb_event_delay_timeout(unsigned long param)
++{
++ /* media signal indicate */
++ schedule_task_register(
++ (SCHEDULE_TASK_FUNC)storageproto_usb_status_check, (int)param,
++ 0, 0, 0, 0);
++
++ return;
++}
++
++/*
++ * storage_event - process a device event
++ * @device: usb device
++ * @event: the event that happened
++ *
++ * Called by the usb device core layer to respond to various USB events.
++ *
++ * This routine IS called at interrupt time. Please use the usual precautions.
++ *
++ */
++void storage_event(struct usb_device_instance* device,
++ usb_device_event_t event, int data)
++{
++#if 0
++ static struct {
++ usb_device_event_t event;
++ char* string;
++ } eventAnal[] = {
++ {DEVICE_UNKNOWN, "DEVICE_UNKNOWN"},
++ {DEVICE_INIT, "DEVICE_INIT"},
++ {DEVICE_CREATE, "DEVICE_CREATE"},
++ {DEVICE_HUB_CONFIGURED, "DEVICE_HUB_CONFIGURED"},
++ {DEVICE_RESET, "DEVICE_RESET"},
++ {DEVICE_ADDRESS_ASSIGNED, "DEVICE_ADDRESS_ASSIGNED"},
++ {DEVICE_CONFIGURED, "DEVICE_CONFIGURED"},
++ {DEVICE_SET_INTERFACE, "DEVICE_SET_INTERFACE"},
++ {DEVICE_SET_FEATURE, "DEVICE_SET_FEATURE"},
++ {DEVICE_CLEAR_FEATURE, "DEVICE_CLEAR_FEATURE"},
++ {DEVICE_DE_CONFIGURED, "DEVICE_DE_CONFIGURED"},
++ {DEVICE_BUS_INACTIVE, "DEVICE_BUS_INACTIVE"},
++ {DEVICE_BUS_ACTIVITY, "DEVICE_BUS_ACTIVITY"},
++ {DEVICE_POWER_INTERRUPTION, "DEVICE_POWER_INTERRUPTION"},
++ {DEVICE_HUB_RESET, "DEVICE_HUB_RESET"},
++ {DEVICE_DESTROY, "DEVICE_DESTROY"},
++ {DEVICE_FUNCTION_PRIVATE, "DEVICE_FUNCTION_PRIVATE"}
++ };
++ int i;
++
++ for(i=0; i<(sizeof(eventAnal)/sizeof(eventAnal[0])); i++){
++ if(event == eventAnal[i].event){
++ DBG_STORAGE_FD(KERN_INFO "storage_fd: event receive '%s'.\n",
++ eventAnal[i].string);
++ break;
++ }
++ }
++ if(i == (sizeof(eventAnal)/sizeof(eventAnal[0]))){
++ DBG_STORAGE_FD(KERN_INFO "storage_fd: unknown event receive.\n");
++ }
++#endif
++
++ switch(event){
++ case DEVICE_ADDRESS_ASSIGNED:
++ {
++ static int Is1stCheck = 1;
++ if(Is1stCheck){
++ Is1stCheck = 0;
++
++ /* delay timer set */
++ del_timer(&storage_usb_event_tim);
++ storage_usb_event_tim.expires = jiffies + ((USB_EVENT_DELAY_TIM * HZ) / 1000);
++ storage_usb_event_tim.data = USB_DISCONNECT;
++ storage_usb_event_tim.function = storage_usb_event_delay_timeout;
++ add_timer(&storage_usb_event_tim);
++ break;
++ }
++ }
++ case DEVICE_BUS_ACTIVITY:
++ /* delay timer set */
++ del_timer(&storage_usb_event_tim);
++ storage_usb_event_tim.expires = jiffies + ((USB_EVENT_DELAY_TIM * HZ) / 1000);
++ storage_usb_event_tim.data = USB_CONNECT;
++ storage_usb_event_tim.function = storage_usb_event_delay_timeout;
++ add_timer(&storage_usb_event_tim);
++ break;
++
++ case DEVICE_BUS_INACTIVE:
++ /* delay timer set */
++ del_timer(&storage_usb_event_tim);
++ storage_usb_event_tim.expires = jiffies + ((USB_EVENT_DELAY_TIM * HZ) / 1000);
++ storage_usb_event_tim.data = USB_DISCONNECT;
++ storage_usb_event_tim.function = storage_usb_event_delay_timeout;
++ add_timer(&storage_usb_event_tim);
++ break;
++
++ case DEVICE_RESET:
++ schedule_task_register(
++ (SCHEDULE_TASK_FUNC)storageproto_usb_reset_ind,
++ 0, 0, 0, 0, 0);
++ break;
++
++ default:
++ break;
++ }
++
++ return;
++}
++
++/*
++ * storage_recv_setup - called with a control URB
++ * @urb - pointer to struct urb
++ *
++ * Check if this is a setup packet, process the device request, put results
++ * back into the urb and return zero or non-zero to indicate success (DATA)
++ * or failure (STALL).
++ *
++ * This routine IS called at interrupt time. Please use the usual precautions.
++ *
++ */
++int storage_recv_setup(struct urb* urb)
++{
++ return 0;
++}
++
++/*
++ * storage_recv_urb - called with a received URB
++ * @urb - pointer to struct urb
++ *
++ * Return non-zero if we failed and urb is still valid (not disposed)
++ *
++ * This routine IS called at interrupt time. Please use the usual precautions.
++ *
++ */
++int storage_recv_urb(struct urb* urb)
++{
++ int port = 0; // XXX compound device
++ struct usb_device_instance* device;
++ struct usb_function_instance* function;
++
++ if(!urb || !(device = urb->device) ||
++ !(function = device->function_instance_array + port)){
++ return -EINVAL;
++ }
++
++ if(urb->status != RECV_OK){
++ return -EINVAL;
++ }
++
++ /* URB urb_analysis */
++ schedule_task_register(
++ (SCHEDULE_TASK_FUNC)storageproto_urb_analysis, (int)urb,
++ 0, 0, 0, 0);
++
++ return 0;
++}
++
++/*
++ * storage_urb_sent - called to indicate URB transmit finished
++ * @urb: pointer to struct urb
++ * @rc: result
++ *
++ * The usb device core layer will use this to let us know when an URB has
++ * been finished with.
++ *
++ * This routine IS called at interrupt time. Please use the usual precautions.
++ *
++ */
++int storage_urb_sent(struct urb* urb, int rc)
++{
++ int port = 0; // XXX compound device
++ struct usb_device_instance* device;
++ struct usb_function_instance* function;
++
++ if(!urb || !(device = urb->device) ||
++ !(function = device->function_instance_array + port)){
++ return -EINVAL;
++ }
++
++ usbd_dealloc_urb (urb);
++
++ return 0;
++}
++
++/**************************************
++** Proc file system
++**************************************/
++
++static ssize_t storage_proc_read(struct file* file, char* buf, size_t count,
++ loff_t* pos)
++{
++ int len = 0, ret;
++
++ if(*pos > 0) return 0;
++
++ if((ret = storageproto_proc_read(file, buf + len, count - len, pos)) < 0){
++ return ret;
++ }
++ len += ret;
++
++ if((ret = schedule_task_proc_read(file, buf + len, count - len, pos)) < 0){
++ return ret;
++ }
++ len += ret;
++
++ return len;
++}
++
++static struct file_operations StorageProcOps = {
++ read:storage_proc_read,
++};
++
++/**************************************
++** Module init and exit
++**************************************/
++
++struct usb_function_operations StorageFunctionOps = {
++ event:storage_event,
++ recv_urb:storage_recv_urb,
++ recv_setup:storage_recv_setup,
++ urb_sent:storage_urb_sent,
++ function_init:storage_function_init,
++ function_exit:storage_function_exit,
++};
++
++struct usb_function_driver StorageFunctionDriver = {
++ name:"Mass Storage",
++ ops:&StorageFunctionOps,
++ device_description:&StorageDeviceDescription,
++ configurations:sizeof (StorageDescription) / sizeof (struct usb_configuration_description),
++ configuration_description:StorageDescription,
++ this_module:THIS_MODULE,
++};
++
++/*
++ * net_modinit - module init
++ *
++ */
++static int __init net_modinit(void)
++{
++ struct proc_dir_entry* proc_entry;
++
++ printk(KERN_INFO "storage_fd: %s (OUT=%d,IN=%d)\n",
++ __usbd_module_info, out_pkt_sz, in_pkt_sz);
++
++ printk(KERN_INFO "storage_fd: vendorID: %x productID: %x\n",
++ CONFIG_USBD_VENDORID, CONFIG_USBD_PRODUCTID);
++
++ // verify pkt sizes not too small
++ if (out_pkt_sz < 3 || in_pkt_sz < 3){
++ printk(KERN_INFO "storage_fd: Rx pkt size %d or Tx pkt size %d too small\n",
++ out_pkt_sz, in_pkt_sz);
++ return (-EINVAL);
++ }
++
++ if(vendor_id){
++ StorageDeviceDescription.idVendor = vendor_id;
++ }
++ if(product_id){
++ StorageDeviceDescription.idProduct = product_id;
++ }
++
++ // register us with the usb device support layer
++ if(usbd_register_function(&StorageFunctionDriver)){
++ printk(KERN_INFO "storage_fd: usbd_register_function failed.\n");
++ return -EINVAL;
++ }
++
++ // create proc entry
++ if ((proc_entry = create_proc_entry("usb-storage", 0, 0)) == NULL) {
++ usbd_deregister_function (&StorageFunctionDriver);
++ printk(KERN_INFO "storage_fd: create_proc_entry failed.\n");
++ return -ENOMEM;
++ }
++ proc_entry->proc_fops = &StorageProcOps;
++
++ return 0;
++}
++
++/*
++ * function_exit - module cleanup
++ *
++ */
++static void __exit net_modexit (void)
++{
++ // de-register us with the usb device support layer
++ usbd_deregister_function (&StorageFunctionDriver);
++
++ // remove proc entry
++ remove_proc_entry("usb-storage", NULL);
++
++ return;
++}
++
++module_init (net_modinit);
++module_exit (net_modexit);
+diff -Nur linux-2.4.18/drivers/usb/device/storage_fd/storageproto.c linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/storageproto.c
+--- linux-2.4.18/drivers/usb/device/storage_fd/storageproto.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/storageproto.c 2003-11-07 05:34:43.000000000 +0300
+@@ -0,0 +1,1505 @@
++/*
++ * linux/drivers/usb/device/storage_fd/storageproto.c - mass storage protocol library
++ *
++ * Copyright (c) 2003 Lineo Solutions, Inc.
++ *
++ * Written by Shunnosuke kabata
++ *
++ * 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, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/******************************************************************************
++** Include File
++******************************************************************************/
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include "../usbd-export.h"
++#include "../usbd-build.h"
++#include "../usbd-module.h"
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/netdevice.h>
++#include <linux/skbuff.h>
++#include <linux/etherdevice.h>
++#include <linux/rtnetlink.h>
++#include <linux/smp_lock.h>
++#include <linux/ctype.h>
++#include <linux/timer.h>
++#include <linux/string.h>
++#include <linux/atmdev.h>
++#include <linux/pkt_sched.h>
++#include <linux/delay.h>
++#include <linux/blkdev.h>
++#include <linux/file.h>
++#include <asm/uaccess.h>
++#include <asm/system.h>
++#include <net/arp.h>
++
++#include <linux/autoconf.h>
++
++#include "../usbd.h"
++#include "../usbd-func.h"
++#include "../usbd-bus.h"
++#include "../usbd-inline.h"
++#include "../usbd-arch.h"
++#include "../hotplug.h"
++
++#include "schedule_task.h"
++#include "storageproto.h"
++
++/******************************************************************************
++** macro define
++******************************************************************************/
++
++#define DEVICE_BLOCK_SIZE 512
++
++#define BLOCK_BUFFER_SIZE (1024 * 64)
++
++#define DEF_NUMBER_OF_HEADS 0x10
++#define DEF_SECTORS_PER_TRACK 0x20
++
++/******************************************************************************
++** Structure Define
++******************************************************************************/
++
++typedef struct{
++ unsigned char scsi_command;
++ unsigned char* command_name;
++ void (*scsi_func)(struct usb_device_instance*,
++ COMMAND_BLOCK_WRAPPER*);
++} SCSI_ANALYSIS_TBL;
++
++typedef struct{
++ unsigned char scsi_command;
++ unsigned char* command_name;
++ void (*bulkout_func)(struct usb_device_instance*,
++ void*, int);
++} SCSI_BULKOUT_ANALYSIS_TBL;
++
++/******************************************************************************
++** Variable Declaration
++******************************************************************************/
++
++/**************************************
++** Module Parameters
++**************************************/
++
++static char* storage_device = CONFIG_USBD_STORAGE_DEF_DEVICE_NAME;
++MODULE_PARM(storage_device, "s");
++
++/**************************************
++** Device Information
++**************************************/
++
++static struct file* DeviceFile = NULL;
++static int DeviceSize = 0;
++static int DeviceBlockSize = DEVICE_BLOCK_SIZE;
++static int DeviceWrProtect = WR_PROTECT_OFF;
++
++/**************************************
++** Status
++**************************************/
++
++static int StorageStatus = STORAGE_IDLE;
++static int UsbStatus = USB_DISCONNECT;
++static int MediaStatus = MEDIA_EJECT;
++static int MediaChange = MEDIA_CHANGE_OFF;
++
++/**************************************
++** Keep Information
++**************************************/
++
++static SCSI_REQUEST_SENSE_DATA RequestSenseData;
++static COMMAND_BLOCK_WRAPPER KeepCBW;
++static unsigned long BulkOutLength = 0;
++static unsigned char BlockBuffer[BLOCK_BUFFER_SIZE];
++
++/**************************************
++** Statistics
++**************************************/
++static unsigned long StatMaxBulkInSize = 0;
++static unsigned long StatMaxBulkOutSize = 0;
++static unsigned long StatDevWriteError = 0;
++static unsigned long StatDevReadError = 0;
++static unsigned long StatDevFlushError = 0;
++static unsigned long StatWriteTimout = 0;
++static unsigned long StatMaxWriteTime = 0;
++
++/**************************************
++** Timer
++**************************************/
++static struct timer_list BulkOutTim;
++static struct timer_list MediaCheckTim;
++
++/******************************************************************************
++** Local Function
++******************************************************************************/
++
++static void storage_bulkout_timeout(unsigned long param)
++{
++ /* statistics update */
++ StatWriteTimout++;
++ printk(KERN_INFO "storage_fd: write bulk out timeout. length '%ld/%ld'.\n",
++ BulkOutLength, KeepCBW.dCBWDataTransferLength);
++
++ return;
++}
++
++static void media_check_timeout(unsigned long param)
++{
++ /* media check */
++ schedule_task_register(
++ (SCHEDULE_TASK_FUNC)storageproto_media_status_check, CONTEXT_TIMER,
++ 0, 0, 0, 0);
++
++ return;
++}
++
++static void request_sense_data_set(unsigned char sense_key, unsigned char asc,
++ unsigned char ascq, unsigned long info)
++{
++ /*
++ * set REQUEST SENSE DATA
++ */
++
++ memset(&RequestSenseData, 0x00, sizeof(RequestSenseData));
++
++ RequestSenseData.ErrorCode = 0x70;
++ RequestSenseData.Valid = (info) ? 1 : 0;
++ RequestSenseData.SenseKey = sense_key;
++ memcpy(RequestSenseData.Information, &info, sizeof(info));
++ RequestSenseData.AdditionalSenseLength = 0x0a;
++ RequestSenseData.AdditionalSenseCode = asc;
++ RequestSenseData.AdditionalSenseCodeQualifier = ascq;
++
++ return;
++}
++
++static void scsi_inquiry_analysis(struct usb_device_instance* device,
++ COMMAND_BLOCK_WRAPPER* cbw)
++{
++ SCSI_INQUIRY_DATA data;
++ COMMAND_STATUS_WRAPPER csw;
++ unsigned long data_len;
++
++ /*
++ * data transport
++ */
++
++ memset(&data, 0x00, sizeof(data));
++
++ data.PeripheralDeviceType = 0x00;
++ data.RMB = 1;
++ data.ResponseDataFormat = 0x01;
++ data.AdditionalLength = 0x1f;
++ strncpy(data.VendorInformation, CONFIG_USBD_MANUFACTURER,
++ sizeof(data.VendorInformation));
++ strncpy(data.ProductIdentification, CONFIG_USBD_PRODUCT_NAME,
++ sizeof(data.ProductIdentification));
++ strncpy(data.ProductRevisionLevel, PRODUCT_REVISION_LEVEL,
++ sizeof(data.ProductRevisionLevel));
++
++ data_len = sizeof(data);
++ if(cbw->dCBWDataTransferLength < data_len){
++ data_len = cbw->dCBWDataTransferLength;
++ }
++
++ storage_urb_send(device, &data, data_len);
++
++ /*
++ * status transport
++ */
++
++ memset(&csw, 0x00, sizeof(csw));
++
++ csw.dCSWSignature = CSW_SIGNATURE;
++ csw.dCSWTag = cbw->dCBWTag;
++ csw.dCSWDataResidue = cbw->dCBWDataTransferLength - data_len;
++ csw.bCSWStatus = 0;
++
++ storage_urb_send(device, &csw, sizeof(csw));
++
++ return;
++}
++
++static void scsi_read_format_capacity_analysis(struct usb_device_instance* device,
++ COMMAND_BLOCK_WRAPPER* cbw)
++{
++ SCSI_READ_FORMAT_CAPACITY_DATA data;
++ COMMAND_STATUS_WRAPPER csw;
++ unsigned long block_num, data_len;
++ unsigned short block_len;
++
++ /*
++ * data transport
++ */
++
++ block_num = 0xffffffff;
++ block_len = (unsigned short)DeviceBlockSize;
++ block_num = htonl(block_num);
++ block_len = htons(block_len);
++
++ memset(&data, 0x00, sizeof(data));
++
++ data.CapacityListHeader.CapacityListLength =
++ sizeof(data.CurrentMaximumCapacityDescriptor);
++ memcpy(data.CurrentMaximumCapacityDescriptor.NumberofBlocks, &block_num,
++ sizeof(block_num));
++ data.CurrentMaximumCapacityDescriptor.DescriptorCode = 0x03;
++ memcpy(data.CurrentMaximumCapacityDescriptor.BlockLength + 1, &block_len,
++ sizeof(block_len));
++
++ data_len = sizeof(data);
++ if(cbw->dCBWDataTransferLength < data_len){
++ data_len = cbw->dCBWDataTransferLength;
++ }
++
++ storage_urb_send(device, &data, data_len);
++
++ /*
++ * status transport
++ */
++
++ memset(&csw, 0x00, sizeof(csw));
++
++ csw.dCSWSignature = CSW_SIGNATURE;
++ csw.dCSWTag = cbw->dCBWTag;
++ csw.dCSWDataResidue = cbw->dCBWDataTransferLength - data_len;
++ csw.bCSWStatus = 0;
++
++ storage_urb_send(device, &csw, sizeof(csw));
++
++ return;
++}
++
++static void scsi_read_capacity_analysis(struct usb_device_instance* device,
++ COMMAND_BLOCK_WRAPPER* cbw)
++{
++ SCSI_READ_CAPACITY_DATA data;
++ COMMAND_STATUS_WRAPPER csw;
++ unsigned char data_len, status = 0;
++
++ if(DeviceFile == NULL){
++ /* 0 clear */
++ memset(&data, 0x00, sizeof(data));
++
++ /* data length set */
++ data_len = cbw->dCBWDataTransferLength;
++
++ /* status set */
++ status = 1;
++
++ /* error code save REQUEST SENSE */
++ request_sense_data_set(0x02, 0x3a, 0x00, 0x00);
++ }
++ else
++ if(MediaChange == MEDIA_CHANGE_ON){
++ /* 0 clear */
++ memset(&data, 0x00, sizeof(data));
++
++ /* data length set */
++ data_len = cbw->dCBWDataTransferLength;
++
++ /* status set */
++ status = 1;
++
++ /* error code save REQUEST SENSE */
++ request_sense_data_set(0x06, 0x28, 0x00, 0x00);
++
++ /* media change flag off */
++ MediaChange = MEDIA_CHANGE_OFF;
++ }
++ else{
++ unsigned long last_lba, block_len;
++
++ /* 0 clear */
++ memset(&data, 0x00, sizeof(data));
++
++ /* data set */
++ last_lba = (DeviceSize / DeviceBlockSize) - 1;
++ block_len = DeviceBlockSize;
++ last_lba = htonl(last_lba);
++ block_len = htonl(block_len);
++
++ memcpy(data.LastLogicalBlockAddress, &last_lba, sizeof(last_lba));
++ memcpy(data.BlockLengthInBytes, &block_len, sizeof(block_len));
++
++ /* data length set */
++ data_len = sizeof(data);
++
++ /* status set */
++ status = 0;
++ }
++
++ /*
++ * data transport
++ */
++
++ if(cbw->dCBWDataTransferLength < data_len){
++ data_len = cbw->dCBWDataTransferLength;
++ }
++
++ storage_urb_send(device, &data, data_len);
++
++ /*
++ * status transport
++ */
++
++ memset(&csw, 0x00, sizeof(csw));
++
++ csw.dCSWSignature = CSW_SIGNATURE;
++ csw.dCSWTag = cbw->dCBWTag;
++ csw.dCSWDataResidue = cbw->dCBWDataTransferLength - data_len;
++ csw.bCSWStatus = status;
++
++ storage_urb_send(device, &csw, sizeof(csw));
++
++ return;
++}
++
++static void scsi_request_sense_analysis(struct usb_device_instance* device,
++ COMMAND_BLOCK_WRAPPER* cbw)
++{
++ COMMAND_STATUS_WRAPPER csw;
++ unsigned long data_len;
++
++ /*
++ * data transport
++ */
++
++ data_len = sizeof(RequestSenseData);
++ if(cbw->dCBWDataTransferLength < data_len){
++ data_len = cbw->dCBWDataTransferLength;
++ }
++
++ storage_urb_send(device, &RequestSenseData, data_len);
++
++ /*
++ * status transport
++ */
++
++ memset(&csw, 0x00, sizeof(csw));
++
++ csw.dCSWSignature = CSW_SIGNATURE;
++ csw.dCSWTag = cbw->dCBWTag;
++ csw.dCSWDataResidue = cbw->dCBWDataTransferLength - data_len;
++ csw.bCSWStatus = 0;
++
++ storage_urb_send(device, &csw, sizeof(csw));
++
++ return;
++}
++
++static void scsi_read_10_analysis(struct usb_device_instance* device,
++ COMMAND_BLOCK_WRAPPER* cbw)
++{
++ SCSI_READ_10_COMMAND* command = (SCSI_READ_10_COMMAND*)cbw->CBWCB;
++ COMMAND_STATUS_WRAPPER csw;
++ unsigned char status = 0;
++ unsigned short len;
++ unsigned long lba, size, offset;
++
++ memcpy(&lba, command->LogicalBlockAddress, sizeof(lba));
++ memcpy(&len, command->TransferLength, sizeof(len));
++ lba = ntohl(lba);
++ len = ntohs(len);
++ offset = lba * DeviceBlockSize;
++ size = cbw->dCBWDataTransferLength;
++
++ if(DeviceFile == NULL){
++ /* command fail */
++ status = 1;
++
++ /* error code save REQUEST SENSE */
++ request_sense_data_set(0x02, 0x3a, 0x00, 0x00);
++
++ /*
++ * data transport
++ */
++
++ storage_urb_send(device, NULL, size);
++ }
++ else
++ if(MediaChange == MEDIA_CHANGE_ON){
++ /* command fail */
++ status = 1;
++
++ /* error code save REQUEST SENSE */
++ request_sense_data_set(0x06, 0x28, 0x00, 0x00);
++
++ /* media change flag off */
++ MediaChange = MEDIA_CHANGE_OFF;
++
++ /*
++ * data transport
++ */
++
++ storage_urb_send(device, NULL, size);
++ }
++ else{
++ unsigned long count, read_size;
++
++ /*
++ * data transport
++ */
++
++ /* device seek */
++ DeviceFile->f_op->llseek(DeviceFile, offset, 0);
++
++ /* device read */
++ for(count = size; count; count -= read_size){
++ read_size = (count > sizeof(BlockBuffer)) ?
++ sizeof(BlockBuffer) : count;
++ if(DeviceFile &&
++ DeviceFile->f_op->read(DeviceFile, BlockBuffer, read_size,
++ &DeviceFile->f_pos) != read_size){
++
++ /* command fail */
++ status = 1;
++
++ /* error code save REQUEST SENSE */
++ request_sense_data_set(0x02, 0x3a, 0x00, 0x00);
++
++ /* statistics update */
++ StatDevReadError++;
++ printk(KERN_INFO "storage_fd: device read error. length '%ld'.\n", read_size);
++ }
++
++ storage_urb_send(device, BlockBuffer, read_size);
++ }
++ }
++
++ /*
++ * status transport
++ */
++
++ memset(&csw, 0x00, sizeof(csw));
++
++ csw.dCSWSignature = CSW_SIGNATURE;
++ csw.dCSWTag = cbw->dCBWTag;
++ csw.dCSWDataResidue = cbw->dCBWDataTransferLength - size;
++ csw.bCSWStatus = status;
++
++ storage_urb_send(device, &csw, sizeof(csw));
++
++ return;
++}
++
++static void scsi_mode_sense_analysis(struct usb_device_instance* device,
++ COMMAND_BLOCK_WRAPPER* cbw)
++{
++ static READ_WRITE_ERROR_RECOVERY_PAGE page_01 = {
++ PageCode:0x01,
++ PageLength:0x0A,
++ ReadRetryCount:0x03,
++ WriteRetryCount:0x80,
++ };
++ static FLEXIBLE_DISK_PAGE page_05 = {
++ PageCode:0x05,
++ PageLength:0x1E,
++ TransferRate:{0x00, 0xFA},
++ NumberofHeads:0xA0,
++ SectorsperTrack:0x00,
++ DataBytesperSector:{0x02, 0x00},
++ NumberofCylinders:{0x00, 0x00},
++ MotorOnDelay:0x05,
++ MotorOffDelay:0x1E,
++ MediumRotationRate:{0x01, 0x68},
++ };
++ static REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGE page_1b = {
++ PageCode:0x1B,
++ PageLength:0x0A,
++ TLUN:0x01,
++ };
++ static TIMER_AND_PROTECT_PAGE page_1c = {
++ PageCode:0x1c,
++ PageLength:0x06,
++ InactivityTimeMultiplier:0x0A,
++ };
++
++
++ SCSI_MODE_SENSE_COMMAND* command = (SCSI_MODE_SENSE_COMMAND*)cbw->CBWCB;
++ SCSI_MODE_SENSE_DATA data;
++ COMMAND_STATUS_WRAPPER csw;
++ unsigned char data_len, status = 0;
++ unsigned short cylinder, sector;
++ unsigned long size;
++
++ /*
++ * data transport
++ */
++
++ memset(&data, 0x00, sizeof(data));
++
++ /* set write protect */
++ data.ModeParameterHeader.WP = DeviceWrProtect;
++
++ /* set Flexible Disk Page */
++ if(DeviceFile == NULL){
++ sector = (unsigned short)DeviceBlockSize;
++ cylinder = 0;
++ sector = htons(sector);
++ cylinder = htons(cylinder);
++
++ page_05.NumberofHeads = 0;
++ page_05.SectorsperTrack = 0;
++ memcpy(page_05.DataBytesperSector, &sector, sizeof(sector));
++ memcpy(page_05.NumberofCylinders, &cylinder, sizeof(cylinder));
++ }
++ else{
++ sector = (unsigned short)DeviceBlockSize;
++ size = DEF_NUMBER_OF_HEADS * DEF_SECTORS_PER_TRACK * sector;
++ cylinder = DeviceSize / size;
++ sector = htons(sector);
++ cylinder = htons(cylinder);
++
++ page_05.NumberofHeads = DEF_NUMBER_OF_HEADS;
++ page_05.SectorsperTrack = DEF_SECTORS_PER_TRACK;
++ memcpy(page_05.DataBytesperSector, &sector, sizeof(sector));
++ memcpy(page_05.NumberofCylinders, &cylinder, sizeof(cylinder));
++ }
++
++ if(command->PC == 0 && command->PageCode == 0x01){
++ data_len = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_01);
++ data.ModeParameterHeader.ModeDataLength = data_len - 1;
++ memcpy(&data.ModePages, &page_01, sizeof(page_01));
++ }
++ else
++ if(command->PC == 0 && command->PageCode == 0x05){
++ data_len = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_05);
++ data.ModeParameterHeader.ModeDataLength = data_len - 1;
++ memcpy(&data.ModePages, &page_05, sizeof(page_05));
++ }
++ else
++ if(command->PC == 0 && command->PageCode == 0x1b){
++ data_len = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_1b);
++ data.ModeParameterHeader.ModeDataLength = data_len - 1;
++ memcpy(&data.ModePages, &page_1b, sizeof(page_1b));
++ }
++ else
++ if(command->PC == 0 && command->PageCode == 0x1c){
++ data_len = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_1c);
++ data.ModeParameterHeader.ModeDataLength = data_len - 1;
++ memcpy(&data.ModePages, &page_1c, sizeof(page_1c));
++ }
++ else
++ if(command->PC == 0 && command->PageCode == 0x3f){
++ data_len = sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_ALL_PAGES);
++ data.ModeParameterHeader.ModeDataLength = data_len - 1;
++ memcpy(&data.ModePages.ModeAllPages.ReadWriteErrorRecoveryPage,
++ &page_01, sizeof(page_01));
++ memcpy(&data.ModePages.ModeAllPages.FlexibleDiskPage,
++ &page_05, sizeof(page_05));
++ memcpy(&data.ModePages.ModeAllPages.RemovableBlockAccessCapabilitiesPage,
++ &page_1b, sizeof(page_1b));
++ memcpy(&data.ModePages.ModeAllPages.TimerAndProtectPage,
++ &page_1c, sizeof(page_1c));
++ }
++ else{
++ /* command fail */
++ status = 1;
++ data_len = cbw->dCBWDataTransferLength;
++
++ /* error code save REQUEST SENSE */
++ request_sense_data_set(0x05, 0x24, 0x00, 0x00);
++ }
++
++ if(cbw->dCBWDataTransferLength < data_len){
++ data_len = cbw->dCBWDataTransferLength;
++ }
++
++ storage_urb_send(device, &data, data_len);
++
++ /*
++ * status transport
++ */
++
++ memset(&csw, 0x00, sizeof(csw));
++
++ csw.dCSWSignature = CSW_SIGNATURE;
++ csw.dCSWTag = cbw->dCBWTag;
++ csw.dCSWDataResidue = cbw->dCBWDataTransferLength - data_len;
++ csw.bCSWStatus = status;
++
++ storage_urb_send(device, &csw, sizeof(csw));
++
++ return;
++}
++
++static void scsi_test_unit_ready_analysis(struct usb_device_instance* device,
++ COMMAND_BLOCK_WRAPPER* cbw)
++{
++ COMMAND_STATUS_WRAPPER csw;
++ unsigned char status = 0;
++
++ if(DeviceFile == NULL){
++ /* command fail */
++ status = 1;
++
++ /* error code save REQUEST SENSE */
++ request_sense_data_set(0x02, 0x3a, 0x00, 0x00);
++ }
++ else
++ if(MediaChange == MEDIA_CHANGE_ON){
++ /* command fail */
++ status = 1;
++
++ /* error code save REQUEST SENSE */
++ request_sense_data_set(0x06, 0x28, 0x00, 0x00);
++
++ /* media change flag off */
++ MediaChange = MEDIA_CHANGE_OFF;
++ }
++
++ /*
++ * status transport
++ */
++
++ memset(&csw, 0x00, sizeof(csw));
++
++ csw.dCSWSignature = CSW_SIGNATURE;
++ csw.dCSWTag = cbw->dCBWTag;
++ csw.dCSWDataResidue = cbw->dCBWDataTransferLength;
++ csw.bCSWStatus = status;
++
++ storage_urb_send(device, &csw, sizeof(csw));
++
++ return;
++}
++
++static void scsi_prevent_allow_medium_removal_analysis(struct usb_device_instance* device,
++ COMMAND_BLOCK_WRAPPER* cbw)
++{
++ SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL_COMMAND* command = (SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL_COMMAND*)cbw->CBWCB;
++ COMMAND_STATUS_WRAPPER csw;
++ unsigned char status = 0;
++
++ if(command->Prevent){
++ /* command fail */
++ status = 1;
++
++ /* error code save REQUEST SENSE */
++ request_sense_data_set(0x05, 0x24, 0x00, 0x00);
++ }
++
++ /*
++ * status transport
++ */
++
++ memset(&csw, 0x00, sizeof(csw));
++
++ csw.dCSWSignature = CSW_SIGNATURE;
++ csw.dCSWTag = cbw->dCBWTag;
++ csw.dCSWDataResidue = cbw->dCBWDataTransferLength;
++ csw.bCSWStatus = status;
++
++ storage_urb_send(device, &csw, sizeof(csw));
++
++ return;
++}
++
++static void scsi_start_stop_analysis(struct usb_device_instance* device,
++ COMMAND_BLOCK_WRAPPER* cbw)
++{
++ SCSI_START_STOP_COMMAND* command = (SCSI_START_STOP_COMMAND*)cbw->CBWCB;
++ COMMAND_STATUS_WRAPPER csw;
++ unsigned char status = 0;
++
++ if(DeviceFile == NULL){
++ /* command fail */
++ status = 1;
++
++ /* error code save REQUEST SENSE */
++ request_sense_data_set(0x02, 0x3a, 0x00, 0x00);
++ }
++ else
++ if(MediaChange == MEDIA_CHANGE_ON){
++ /* command fail */
++ status = 1;
++
++ /* error code save REQUEST SENSE */
++ request_sense_data_set(0x06, 0x28, 0x00, 0x00);
++
++ /* media change flag off */
++ MediaChange = MEDIA_CHANGE_OFF;
++ }
++ else
++ if(command->Start && command->LoEj){
++ /* command fail */
++ status = 1;
++
++ /* error code save REQUEST SENSE */
++ request_sense_data_set(0x05, 0x24, 0x00, 0x00);
++ }
++
++ /* device buffer flush */
++ if(DeviceFile && DeviceFile->f_op->ioctl(DeviceFile->f_dentry->d_inode,
++ DeviceFile, BLKFLSBUF, 0) != 0){
++ /* statistics update */
++ StatDevFlushError++;
++ printk(KERN_INFO "storage_fd: device flush error.\n");
++ }
++
++ /*
++ * status transport
++ */
++
++ memset(&csw, 0x00, sizeof(csw));
++
++ csw.dCSWSignature = CSW_SIGNATURE;
++ csw.dCSWTag = cbw->dCBWTag;
++ csw.dCSWDataResidue = cbw->dCBWDataTransferLength;
++ csw.bCSWStatus = status;
++
++ storage_urb_send(device, &csw, sizeof(csw));
++
++ return;
++}
++
++static void scsi_write_10_analysis(struct usb_device_instance* device,
++ COMMAND_BLOCK_WRAPPER* cbw)
++{
++ /* status set */
++ BulkOutLength = 0;
++ StorageStatus = STORAGE_BULKOUT;
++
++ /* timer set */
++ del_timer(&BulkOutTim);
++ BulkOutTim.expires = jiffies + ((WR_BULKOUT_CHK_TIM * HZ) / 1000);
++ BulkOutTim.data = 0;
++ BulkOutTim.function = storage_bulkout_timeout;
++ add_timer(&BulkOutTim);
++
++ return;
++}
++
++static void scsi_verify_analysis(struct usb_device_instance* device,
++ COMMAND_BLOCK_WRAPPER* cbw)
++{
++ COMMAND_STATUS_WRAPPER csw;
++ unsigned char status = 0;
++
++ if(DeviceFile == NULL){
++ /* command fail */
++ status = 1;
++
++ /* error code save REQUEST SENSE */
++ request_sense_data_set(0x02, 0x3a, 0x00, 0x00);
++ }
++ else
++ if(MediaChange == MEDIA_CHANGE_ON){
++ /* command fail */
++ status = 1;
++
++ /* error code save REQUEST SENSE */
++ request_sense_data_set(0x06, 0x28, 0x00, 0x00);
++
++ /* media change flag off */
++ MediaChange = MEDIA_CHANGE_OFF;
++ }
++
++ /*
++ * status transport
++ */
++
++ memset(&csw, 0x00, sizeof(csw));
++
++ csw.dCSWSignature = CSW_SIGNATURE;
++ csw.dCSWTag = cbw->dCBWTag;
++ csw.dCSWDataResidue = cbw->dCBWDataTransferLength;
++ csw.bCSWStatus = status;
++
++ storage_urb_send(device, &csw, sizeof(csw));
++
++ return;
++}
++
++static void scsi_unsupport_analysis(struct usb_device_instance* device,
++ COMMAND_BLOCK_WRAPPER* cbw)
++{
++ COMMAND_STATUS_WRAPPER csw;
++ unsigned char data_len = 0;
++
++ if(((cbw->bmCBWFlags & 0x80) == 0x00) && (cbw->dCBWDataTransferLength)){
++ /* BLKOUT */
++
++ /* status set */
++ BulkOutLength = 0;
++ StorageStatus = STORAGE_BULKOUT;
++ }
++ else{
++ /* BLKIN */
++
++ if(cbw->dCBWDataTransferLength){
++ data_len = cbw->dCBWDataTransferLength;
++ storage_urb_send(device, NULL, data_len);
++ }
++
++ /*
++ * status transport
++ */
++
++ memset(&csw, 0x00, sizeof(csw));
++
++ csw.dCSWSignature = CSW_SIGNATURE;
++ csw.dCSWTag = cbw->dCBWTag;
++ csw.dCSWDataResidue = cbw->dCBWDataTransferLength - data_len;
++ csw.bCSWStatus = 0x01;
++ storage_urb_send(device, &csw, sizeof(csw));
++
++ }
++
++ /* error code save REQUEST SENSE */
++ request_sense_data_set(0x05, 0x20, 0x00, 0x00);
++
++ return;
++}
++
++static void scsi_bulkout_write_10_analysis(struct usb_device_instance* device,
++ void* buffer, int length)
++{
++ COMMAND_STATUS_WRAPPER csw;
++ unsigned char status = 0;
++ unsigned long buff_used_len, buff_offset;
++ unsigned long s_tick, e_tick, wr_tick;
++
++ buff_offset = BulkOutLength % sizeof(BlockBuffer);
++
++ memcpy(BlockBuffer + buff_offset, buffer, length);
++ BulkOutLength += length;
++
++ buff_used_len = BulkOutLength % sizeof(BlockBuffer);
++ if(buff_used_len == 0) buff_used_len = sizeof(BlockBuffer);
++
++ /* delete timer */
++ if(BulkOutLength >= KeepCBW.dCBWDataTransferLength){
++ del_timer(&BulkOutTim);
++ }
++
++ if(buff_used_len >= sizeof(BlockBuffer) ||
++ BulkOutLength >= KeepCBW.dCBWDataTransferLength){
++
++ /* buffer full */
++ SCSI_WRITE_10_COMMAND* command = (SCSI_WRITE_10_COMMAND*)&KeepCBW.CBWCB;
++ unsigned short len;
++ unsigned long lba, offset;
++
++ memcpy(&lba, command->LogicalBlockAddress, sizeof(lba));
++ memcpy(&len, command->TransferLength, sizeof(len));
++ lba = ntohl(lba);
++ len = ntohs(len);
++
++ offset = (lba * DeviceBlockSize) +
++ (sizeof(BlockBuffer) * ((BulkOutLength - 1) / sizeof(BlockBuffer)));
++
++ /* device check */
++ if(DeviceFile &&
++ MediaChange != MEDIA_CHANGE_ON &&
++ DeviceWrProtect != WR_PROTECT_ON){
++
++ /* write before jiffies get */
++ s_tick = jiffies;
++
++ /* device seek */
++ DeviceFile->f_op->llseek(DeviceFile, offset, 0);
++
++ /* device write */
++ if(DeviceFile->f_op->write(DeviceFile, BlockBuffer, buff_used_len,
++ &DeviceFile->f_pos) != buff_used_len){
++ /* statistics update */
++ StatDevWriteError++;
++ printk(KERN_INFO "storage_fd: device write error. length '%ld'.\n", buff_used_len);
++ }
++
++ /* write after jiffies get */
++ e_tick = jiffies;
++
++ /* statistics update */
++ wr_tick = e_tick - s_tick;
++ if(wr_tick > StatMaxWriteTime){
++ StatMaxWriteTime = wr_tick;
++ }
++ }
++ }
++
++ if(BulkOutLength >= KeepCBW.dCBWDataTransferLength){
++ if(DeviceFile == NULL){
++ /* command fail */
++ status = 1;
++
++ /* error code save REQUEST SENSE */
++ request_sense_data_set(0x02, 0x3a, 0x00, 0x00);
++ }
++ else
++ if(MediaChange == MEDIA_CHANGE_ON){
++ /* command fail */
++ status = 1;
++
++ /* error code save REQUEST SENSE */
++ request_sense_data_set(0x06, 0x28, 0x00, 0x00);
++
++ /* media change flag off */
++ MediaChange = MEDIA_CHANGE_OFF;
++ }
++ else
++ if(DeviceWrProtect == WR_PROTECT_ON){
++ /* command fail */
++ status = 1;
++
++ /* error code save REQUEST SENSE */
++ request_sense_data_set(0x07, 0x27, 0x00, 0x00);
++
++ /* media change flag off */
++ MediaChange = MEDIA_CHANGE_OFF;
++ }
++
++ /*
++ * status transport
++ */
++
++ memset(&csw, 0x00, sizeof(csw));
++
++ csw.dCSWSignature = CSW_SIGNATURE;
++ csw.dCSWTag = KeepCBW.dCBWTag;
++ csw.dCSWDataResidue = KeepCBW.dCBWDataTransferLength - BulkOutLength;
++ csw.bCSWStatus = status;
++
++ storage_urb_send(device, &csw, sizeof(csw));
++
++ /* status reset */
++ BulkOutLength = 0;
++ StorageStatus = STORAGE_IDLE;
++
++ /* flush before jiffies get */
++ s_tick = jiffies;
++
++ /* device buffer flush */
++ if(DeviceFile && DeviceFile->f_op->ioctl(DeviceFile->f_dentry->d_inode,
++ DeviceFile, BLKFLSBUF, 0) != 0){
++ /* statistics update */
++ StatDevFlushError++;
++ printk(KERN_INFO "storage_fd: device flush error.\n");
++ }
++
++ /* flush after jiffies get */
++ e_tick = jiffies;
++
++ /* statistics update */
++ wr_tick = e_tick - s_tick;
++ if(wr_tick > StatMaxWriteTime){
++ StatMaxWriteTime = wr_tick;
++ }
++
++ }
++
++ return;
++}
++
++static void scsi_bulkout_unsupport_analysis(struct usb_device_instance* device,
++ void* buffer, int length)
++{
++ COMMAND_STATUS_WRAPPER csw;
++
++ BulkOutLength += length;
++
++ if(BulkOutLength >= KeepCBW.dCBWDataTransferLength){
++ /*
++ * status transport
++ */
++
++ memset(&csw, 0x00, sizeof(csw));
++
++ csw.dCSWSignature = CSW_SIGNATURE;
++ csw.dCSWTag = KeepCBW.dCBWTag;
++ csw.dCSWDataResidue = KeepCBW.dCBWDataTransferLength - BulkOutLength;
++ csw.bCSWStatus = 1;
++
++ storage_urb_send(device, &csw, sizeof(csw));
++
++ /* error code save REQUEST SENSE */
++ request_sense_data_set(0x05, 0x20, 0x00, 0x00);
++
++ /* status reset */
++ BulkOutLength = 0;
++ StorageStatus = STORAGE_IDLE;
++ }
++
++ return;
++}
++
++/******************************************************************************
++** Global Function
++******************************************************************************/
++
++static SCSI_ANALYSIS_TBL ScsiAnalysisTbl[] = {
++ {SCSI_FORMAT_UNT, "SCSI_FORMAT_UNT", NULL},
++ {SCSI_INQUIRY, "SCSI_INQUIRY", scsi_inquiry_analysis},
++ {SCSI_START_STOP, "SCSI_START_STOP", scsi_start_stop_analysis},
++ {SCSI_MODE_SELECT, "SCSI_MODE_SELECT", NULL},
++ {SCSI_MODE_SENSE, "SCSI_MODE_SENSE", scsi_mode_sense_analysis},
++ {SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL, "SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL", scsi_prevent_allow_medium_removal_analysis},
++ {SCSI_READ_10, "SCSI_READ_10", scsi_read_10_analysis},
++ {SCSI_READ_12, "SCSI_READ_12", NULL},
++ {SCSI_READ_CAPACITY, "SCSI_READ_CAPACITY", scsi_read_capacity_analysis},
++ {SCSI_READ_FORMAT_CAPACITY, "SCSI_READ_FORMAT_CAPACITY", scsi_read_format_capacity_analysis},
++ {SCSI_REQUEST_SENSE, "SCSI_REQUEST_SENSE", scsi_request_sense_analysis},
++ {SCSI_REZERO_UNIT, "SCSI_REZERO_UNIT", NULL},
++ {SCSI_SEEK_10, "SCSI_SEEK_10", NULL},
++ {SCSI_SEND_DIAGNOSTIC, "SCSI_SEND_DIAGNOSTIC", NULL},
++ {SCSI_TEST_UNIT_READY, "SCSI_TEST_UNIT_READY", scsi_test_unit_ready_analysis},
++ {SCSI_VERIFY, "SCSI_VERIFY", scsi_verify_analysis},
++ {SCSI_WRITE_10, "SCSI_WRITE_10", scsi_write_10_analysis},
++ {SCSI_WRITE_12, "SCSI_WRITE_12", NULL},
++ {SCSI_WRITE_AND_VERIFY, "SCSI_WRITE_AND_VERIFY", NULL}
++};
++
++static SCSI_BULKOUT_ANALYSIS_TBL ScsiBlkOutAnalysisTbl[] = {
++ {SCSI_WRITE_10, "SCSI_WRITE_10", scsi_bulkout_write_10_analysis},
++};
++
++void storageproto_urb_analysis(struct urb* urb)
++{
++ COMMAND_BLOCK_WRAPPER* cbw = (COMMAND_BLOCK_WRAPPER*)urb->buffer;
++ int i;
++
++ /* status BLKOUT check */
++ if(StorageStatus == STORAGE_BULKOUT){
++ for(i = 0;
++ i < sizeof(ScsiBlkOutAnalysisTbl) / sizeof(SCSI_ANALYSIS_TBL);
++ i++){
++ if(ScsiBlkOutAnalysisTbl[i].scsi_command == KeepCBW.CBWCB[0]){
++ if(ScsiBlkOutAnalysisTbl[i].bulkout_func){
++ ScsiBlkOutAnalysisTbl[i].bulkout_func(urb->device,
++ urb->buffer,
++ urb->actual_length);
++ goto RETURN_LABEL;
++ }
++ break;
++ }
++ }
++ scsi_bulkout_unsupport_analysis(urb->device, urb->buffer, urb->actual_length);
++ goto RETURN_LABEL;
++ }
++
++ /* signature check */
++ if(cbw->dCBWSignature != CBW_SIGNATURE){
++ printk(KERN_INFO "storage_fd: signature error. '0x%08lx'.\n",
++ cbw->dCBWSignature);
++ goto RETURN_LABEL;
++ }
++
++ /* statistics set */
++ if(cbw->dCBWDataTransferLength){
++ if(((cbw->bmCBWFlags & 0x80) == 0x00) && (cbw->dCBWDataTransferLength)){
++ /* BULK OUT */
++ if(StatMaxBulkOutSize < cbw->dCBWDataTransferLength){
++ StatMaxBulkOutSize = cbw->dCBWDataTransferLength;
++ }
++ }
++ else{
++ /* BULK IN */
++ if(StatMaxBulkInSize < cbw->dCBWDataTransferLength){
++ StatMaxBulkInSize = cbw->dCBWDataTransferLength;
++ }
++ }
++ }
++
++ /* save CBW and set storage status */
++ memcpy(&KeepCBW, cbw, sizeof(KeepCBW));
++
++ /* UFI command analysis */
++ for(i = 0; i < sizeof(ScsiAnalysisTbl) / sizeof(SCSI_ANALYSIS_TBL); i++){
++ if(ScsiAnalysisTbl[i].scsi_command == cbw->CBWCB[0]){
++ if(ScsiAnalysisTbl[i].scsi_func){
++ ScsiAnalysisTbl[i].scsi_func(urb->device, cbw);
++ goto RETURN_LABEL;
++ }
++ break;
++ }
++ }
++
++ scsi_unsupport_analysis(urb->device, cbw);
++ printk(KERN_INFO "storage_fd: SCSI command error. '0x%02x'.\n",
++ cbw->CBWCB[0]);
++ goto RETURN_LABEL;
++
++RETURN_LABEL:
++
++ /* URB free */
++ usbd_recycle_urb(urb);
++
++ return;
++}
++
++int storageproto_device_open_check(void)
++{
++ struct file* file;
++ struct inode* inode;
++ kdev_t dev;
++ int read_org;
++
++ /* device already open check */
++ if(DeviceFile){
++ storageproto_device_close();
++ }
++
++ /* device open */
++ file = filp_open(storage_device, O_RDWR, 0000);
++ if(IS_ERR(file)){
++ file = filp_open(storage_device, O_RDONLY, 0000);
++ if(IS_ERR(file)){
++ storageproto_device_close();
++ return MEDIA_EJECT;
++ }
++ DeviceWrProtect = WR_PROTECT_ON;
++ }
++
++ file->f_op->llseek(file, 0, 0);
++ if(file->f_op->read(file, (void*)&read_org, sizeof(read_org), &file->f_pos)
++ != sizeof(read_org)){
++ filp_close(file, NULL);
++ storageproto_device_close();
++ return MEDIA_EJECT;
++ }
++
++ /* struct file pointer save */
++ DeviceFile = file;
++
++ /* device information */
++ inode = file->f_dentry->d_inode;
++ dev = inode->i_rdev;
++
++ if (blk_size[MAJOR(dev)]){
++ DeviceSize = blk_size[MAJOR(dev)][MINOR(dev)] << BLOCK_SIZE_BITS;
++ }
++ else{
++ DeviceSize = INT_MAX << BLOCK_SIZE_BITS;
++ }
++
++ if(blksize_size[MAJOR(dev)] && blksize_size[MAJOR(dev)][MINOR(dev)]){
++ DeviceBlockSize = DEVICE_BLOCK_SIZE;
++ }
++ else{
++ DeviceBlockSize = DEVICE_BLOCK_SIZE;
++ }
++
++ return MEDIA_INSERT;
++}
++
++void storageproto_device_close(void)
++{
++ if(DeviceFile){
++ filp_close(DeviceFile, NULL);
++ DeviceFile = NULL;
++ DeviceSize = 0;
++ DeviceBlockSize = DEVICE_BLOCK_SIZE;
++ DeviceWrProtect = WR_PROTECT_OFF;
++ }
++
++ return;
++}
++
++void storageproto_usb_status_check(int status)
++{
++ static int Is1stCheck = 1;
++
++ /* USB status check */
++ if(Is1stCheck){
++ Is1stCheck = 0;
++ }
++ else{
++ if(UsbStatus == status) goto RETURN_LABEL;
++ }
++
++ /* set status */
++ UsbStatus = status;
++
++ switch(UsbStatus){
++ case USB_CONNECT:
++ /* media status check */
++ storageproto_media_status_check(CONTEXT_SCHEDULE);
++
++ switch(MediaStatus){
++ case MEDIA_EJECT:
++ break;
++
++ case MEDIA_INSERT:
++ hotplug("usbdstorage", storage_device, "umount");
++ break;
++
++ default:
++ break;
++ }
++ hotplug("usbdstorage", storage_device, "connect");
++ break;
++
++ case USB_DISCONNECT:
++ /* device close */
++ storageproto_device_close();
++
++ switch(MediaStatus){
++ case MEDIA_EJECT:
++ break;
++
++ case MEDIA_INSERT:
++ hotplug("usbdstorage", storage_device, "mount");
++ break;
++
++ default:
++ break;
++ }
++ hotplug("usbdstorage", storage_device, "disconnect");
++ break;
++
++ default:
++ break;
++ }
++
++RETURN_LABEL:
++ DBG_STORAGE_FD(KERN_INFO "storage_fd: USB check '%s' '%s' 'file:%p'.\n",
++ (UsbStatus) ? "USB_CONNECT" : "USB_DISCONNECT",
++ (MediaStatus) ? "MEDIA_INSERT" : "MEDIA_EJECT", DeviceFile);
++
++ return;
++}
++
++void storageproto_media_status_check(int call_context)
++{
++ static unsigned long RetryCount = 0;
++ int status;
++
++ /* media open check */
++ status = storageproto_device_open_check();
++
++ /* media status check retry */
++ if(status == MEDIA_EJECT){
++ switch(call_context){
++ case CONTEXT_STORAGE:
++
++ /* retry counter init */
++ RetryCount = 0;
++
++ /* timer set */
++ del_timer(&MediaCheckTim);
++ MediaCheckTim.expires = jiffies + ((MEDIA_CHECK_TIM * HZ) / 1000);
++ MediaCheckTim.data = 0;
++ MediaCheckTim.function = media_check_timeout;
++ add_timer(&MediaCheckTim);
++
++ break;
++
++ case CONTEXT_TIMER:
++
++ /* retry counter update */
++ RetryCount++;
++
++ /* retry counter check */
++ if(RetryCount >= MEDIA_CHECK_RETRY) break;
++
++ /* timer set */
++ del_timer(&MediaCheckTim);
++ MediaCheckTim.expires = jiffies + ((MEDIA_CHECK_TIM * HZ) / 1000);
++ MediaCheckTim.data = 0;
++ MediaCheckTim.function = media_check_timeout;
++ add_timer(&MediaCheckTim);
++
++ break;
++
++ default:
++ break;
++ }
++ }
++ else
++ if(status == MEDIA_INSERT){
++ /* delete timer */
++ del_timer(&MediaCheckTim);
++ }
++
++ /* media status check */
++ if(status == MediaStatus){
++ if(UsbStatus == USB_DISCONNECT){
++ storageproto_device_close();
++ }
++ if(MediaStatus == MEDIA_INSERT){
++ if(call_context == CONTEXT_STORAGE || call_context == CONTEXT_TIMER){
++ MediaChange = MEDIA_CHANGE_ON;
++ }
++ }
++ goto RETURN_LABEL;
++ }
++
++ /* set status */
++ MediaStatus = status;
++
++ switch(MediaStatus){
++ case MEDIA_INSERT:
++ /* set status */
++ MediaChange = MEDIA_CHANGE_ON;
++
++ switch(UsbStatus){
++ case USB_DISCONNECT:
++ storageproto_device_close();
++ break;
++
++ case USB_CONNECT:
++ break;
++
++ default:
++ break;
++ }
++ hotplug("usbdstorage", storage_device, "insert");
++ break;
++
++ case MEDIA_EJECT:
++ switch(UsbStatus){
++ case USB_DISCONNECT:
++ storageproto_device_close();
++ break;
++
++ case USB_CONNECT:
++ break;
++
++ default:
++ break;
++ }
++ hotplug("usbdstorage", storage_device, "eject");
++ break;
++
++ default:
++ break;
++ }
++
++RETURN_LABEL:
++ DBG_STORAGE_FD(KERN_INFO "storage_fd: media check. '%s' '%s' 'file:%p' '%s'.\n",
++ (UsbStatus) ? "USB_CONNECT" : "USB_DISCONNECT",
++ (MediaStatus) ? "MEDIA_INSERT" : "MEDIA_EJECT", DeviceFile,
++ (call_context == CONTEXT_SCHEDULE) ? "CONTEXT_SCHEDULE" :
++ (call_context == CONTEXT_STORAGE) ? "CONTEXT_STORAGE" : "CONTEXT_TIMER");
++
++ return;
++}
++
++void storageproto_usb_reset_ind(void)
++{
++ /* status reset */
++ BulkOutLength = 0;
++ StorageStatus = STORAGE_IDLE;
++
++ DBG_STORAGE_FD(KERN_INFO "storage_fd: storage protocol reset.\n");
++
++ return;
++}
++
++void storageproto_init(void)
++{
++ /* timer init */
++ init_timer(&BulkOutTim);
++
++ /* timer init */
++ init_timer(&MediaCheckTim);
++
++ return;
++}
++
++void storageproto_exit(void)
++{
++ /* device close */
++ storageproto_device_close();
++
++ /* delete timer */
++ del_timer(&BulkOutTim);
++
++ /* delete timer */
++ del_timer(&MediaCheckTim);
++
++ return;
++}
++
++ssize_t storageproto_proc_read(struct file* file, char* buf, size_t count,
++ loff_t* pos)
++{
++ char string[1024];
++ int len = 0;
++
++ len += sprintf(string + len, "Protocol status:%s\n",
++ (StorageStatus == STORAGE_IDLE) ? "STORAGE_IDLE" :
++ (StorageStatus == STORAGE_BULKIN) ? "STORAGE_BULKIN" :
++ "STORAGE_BULKOUT");
++
++ len += sprintf(string + len, "USB status:%s\n",
++ (UsbStatus == USB_DISCONNECT) ? "USB_DISCONNECT" :
++ "USB_CONNECT");
++
++ len += sprintf(string + len, "Media status:%s\n",
++ (MediaStatus == MEDIA_EJECT) ? "MEDIA_EJECT" :
++ "MEDIA_INSERT");
++
++ len += sprintf(string + len, "Media chage:%s\n",
++ (MediaChange == MEDIA_CHANGE_OFF) ? "MEDIA_CHANGE_OFF" :
++ "MEDIA_CHANGE_ON");
++
++ len += sprintf(string + len, "Device name:%s\n",
++ storage_device);
++
++ len += sprintf(string + len, "Device file descriptor:0x%p\n",
++ DeviceFile);
++
++ len += sprintf(string + len, "Device size:0x%d\n",
++ DeviceSize);
++
++ len += sprintf(string + len, "Device block size:0x%d\n",
++ DeviceBlockSize);
++
++ len += sprintf(string + len, "Device write protect:%s\n",
++ (DeviceWrProtect == WR_PROTECT_OFF) ? "WR_PROTECT_OFF":
++ "WR_PROTECT_ON");
++
++ len += sprintf(string + len, "Bulk in max size:%ld\n",
++ StatMaxBulkInSize);
++
++ len += sprintf(string + len, "Bulk out max size:%ld\n",
++ StatMaxBulkOutSize);
++
++ len += sprintf(string + len, "device write error:%ld\n",
++ StatDevWriteError);
++
++ len += sprintf(string + len, "device read error:%ld\n",
++ StatDevReadError);
++
++ len += sprintf(string + len, "device flush error:%ld\n",
++ StatDevFlushError);
++
++ len += sprintf(string + len, "write data bulk out timout:%ld\n",
++ StatWriteTimout);
++
++ len += sprintf(string + len, "device write max time:%ld msec\n",
++ (StatMaxWriteTime * 1000) / HZ);
++
++ *pos += len;
++ if(len > count){
++ len = -EINVAL;
++ }
++ else
++ if(len > 0 && copy_to_user(buf, string, len)) {
++ len = -EFAULT;
++ }
++
++ return len;
++}
++
+diff -Nur linux-2.4.18/drivers/usb/device/storage_fd/storageproto.h linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/storageproto.h
+--- linux-2.4.18/drivers/usb/device/storage_fd/storageproto.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/storageproto.h 2003-11-07 05:34:43.000000000 +0300
+@@ -0,0 +1,585 @@
++/*
++ * linux/drivers/usb/device/storage_fd/storageproto.h - mass storage protocol library header
++ *
++ * Copyright (c) 2003 Lineo Solutions, Inc.
++ *
++ * Written by Shunnosuke kabata
++ *
++ * 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, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#ifndef _STORAGEPROTO_H_
++#define _STORAGEPROTO_H_
++
++/******************************************************************************
++** Macro Define
++******************************************************************************/
++
++/**************************************
++** Class Code
++**************************************/
++
++/*
++ * Class
++ */
++
++#define MASS_STORAGE_CLASS 0x08
++
++/*
++ * SubClass
++ */
++
++#define MASS_STORAGE_SUBCLASS_RBC 0x01
++#define MASS_STORAGE_SUBCLASS_SFF8020I 0x02
++#define MASS_STORAGE_SUBCLASS_QIC157 0x03
++#define MASS_STORAGE_SUBCLASS_UFI 0x04
++#define MASS_STORAGE_SUBCLASS_SFF8070I 0x05
++#define MASS_STORAGE_SUBCLASS_SCSI 0x06
++
++/*
++ * Protocol
++ */
++
++#define MASS_STORAGE_PROTO_CBI_WITH_COMP 0x00
++#define MASS_STORAGE_PROTO_CBI_NO_COMP 0x01
++#define MASS_STORAGE_PROTO_BULK_ONLY 0x50
++
++/**************************************
++** SCSI Command
++**************************************/
++
++#define SCSI_FORMAT_UNT 0x04
++#define SCSI_INQUIRY 0x12
++#define SCSI_START_STOP 0x1b
++#define SCSI_MODE_SELECT 0x55
++#define SCSI_MODE_SENSE 0x1a
++#define SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e
++#define SCSI_READ_10 0x28
++#define SCSI_READ_12 0xa8
++#define SCSI_READ_CAPACITY 0x25
++#define SCSI_READ_FORMAT_CAPACITY 0x23
++#define SCSI_REQUEST_SENSE 0x03
++#define SCSI_REZERO_UNIT 0x01
++#define SCSI_SEEK_10 0x2b
++#define SCSI_SEND_DIAGNOSTIC 0x1d
++#define SCSI_TEST_UNIT_READY 0x00
++#define SCSI_VERIFY 0x2f
++#define SCSI_WRITE_10 0x2a
++#define SCSI_WRITE_12 0xaa
++#define SCSI_WRITE_AND_VERIFY 0x2e
++
++/**************************************
++** SCSI Command Parameter
++**************************************/
++
++#define CBW_SIGNATURE 0x43425355 /* USBC */
++#define CSW_SIGNATURE 0x53425355 /* USBS */
++
++#define PRODUCT_REVISION_LEVEL "1.00"
++
++/**************************************
++** Status
++**************************************/
++
++#define WR_PROTECT_OFF 0
++#define WR_PROTECT_ON 1
++
++#define STORAGE_IDLE 0
++#define STORAGE_BULKIN 1
++#define STORAGE_BULKOUT 2
++
++#define USB_DISCONNECT 0
++#define USB_CONNECT 1
++
++#define MEDIA_EJECT 0
++#define MEDIA_INSERT 1
++
++#define MEDIA_CHANGE_OFF 0
++#define MEDIA_CHANGE_ON 1
++
++/**************************************
++** Mass Storage Thread Name
++**************************************/
++
++#define STORAGE_THREAD_NAME "usbdstorage"
++
++/**************************************
++** Media Signal Delay Time(ms)
++**************************************/
++
++#define USB_EVENT_DELAY_TIM 1000
++
++/**************************************
++** Write Bulk Out Check Time(ms)
++**************************************/
++
++#define WR_BULKOUT_CHK_TIM 1000
++
++/**************************************
++** Media Check Time(ms)
++**************************************/
++
++#define MEDIA_CHECK_TIM 3000
++#define MEDIA_CHECK_RETRY 3
++
++/**************************************
++** Context
++**************************************/
++
++#define CONTEXT_SCHEDULE 0
++#define CONTEXT_STORAGE 1
++#define CONTEXT_TIMER 2
++
++/**************************************
++** Debug Message
++**************************************/
++#if 0
++#define DBG_STORAGE_FD(fmt, args...) printk(fmt, ##args)
++#else
++#define DBG_STORAGE_FD(fmt, args...)
++#endif
++
++/******************************************************************************
++** Structure Define
++******************************************************************************/
++
++/**************************************
++** Command Block Wrapper / Command Status Wrapper
++**************************************/
++
++/*
++ * Command Block Wrapper
++ */
++typedef struct{
++ unsigned long dCBWSignature;
++ unsigned long dCBWTag;
++ unsigned long dCBWDataTransferLength;
++ unsigned char bmCBWFlags;
++ unsigned char bCBWLUN:4,
++ Reserved:4;
++ unsigned char bCBWCBLength:5,
++ Reserved2:3;
++ unsigned char CBWCB[16];
++} __attribute__((packed)) COMMAND_BLOCK_WRAPPER;
++
++/*
++ * Command Status Wrapper
++ */
++typedef struct{
++ unsigned long dCSWSignature;
++ unsigned long dCSWTag;
++ unsigned long dCSWDataResidue;
++ unsigned char bCSWStatus;
++} __attribute__((packed)) COMMAND_STATUS_WRAPPER;
++
++/**************************************
++** SCSI Command
++**************************************/
++
++/*
++ * INQUIRY
++ */
++
++typedef struct{
++ unsigned char OperationCode;
++ unsigned char EVPD:1,
++ Reserved1:4,
++ LogicalUnitNumber:3;
++ unsigned char PageCode;
++ unsigned char Reserved2;
++ unsigned char AllocationLength;
++ unsigned char Reserved3;
++ unsigned char Reserved4;
++ unsigned char Reserved5;
++ unsigned char Reserved6;
++ unsigned char Reserved7;
++ unsigned char Reserved8;
++ unsigned char Reserved9;
++} __attribute__((packed)) SCSI_INQUIRY_COMMAND;
++
++typedef struct{
++ unsigned char PeripheralDeviceType:5,
++ Reserved1:3;
++ unsigned char Reserved2:7,
++ RMB:1;
++ unsigned char ANSIVersion:3,
++ ECMAVersion:3,
++ ISOVersion:2;
++ unsigned char ResponseDataFormat:4,
++ Reserved3:4;
++ unsigned char AdditionalLength;
++ unsigned char Reserved4;
++ unsigned char Reserved5;
++ unsigned char Reserved6;
++ unsigned char VendorInformation[8];
++ unsigned char ProductIdentification[16];
++ unsigned char ProductRevisionLevel[4];
++} __attribute__((packed)) SCSI_INQUIRY_DATA;
++
++/*
++ * READ FORMAT CAPACITY
++ */
++
++typedef struct{
++ unsigned char OperationCode;
++ unsigned char Reserved1:5,
++ LogicalUnitNumber:3;
++ unsigned char Reserved2;
++ unsigned char Reserved3;
++ unsigned char Reserved4;
++ unsigned char Reserved5;
++ unsigned char Reserved6;
++ unsigned char AllocationLength[2];
++ unsigned char Reserved7;
++ unsigned char Reserved8;
++ unsigned char Reserved9;
++} __attribute__((packed)) SCSI_READ_FORMAT_CAPACITY_COMMAND;
++
++typedef struct{
++ struct{
++ unsigned char Reserved1;
++ unsigned char Reserved2;
++ unsigned char Reserved3;
++ unsigned char CapacityListLength;
++ } __attribute__((packed)) CapacityListHeader;
++ struct{
++ unsigned char NumberofBlocks[4];
++ unsigned char DescriptorCode:2,
++ Reserved1:6;
++ unsigned char BlockLength[3];
++ } __attribute__((packed)) CurrentMaximumCapacityDescriptor;
++} __attribute__((packed)) SCSI_READ_FORMAT_CAPACITY_DATA;
++
++/*
++ * READ FORMAT CAPACITY
++ */
++
++typedef struct{
++ unsigned char OperationCode;
++ unsigned char RelAdr:1,
++ Reserved1:4,
++ LogicalUnitNumber:3;
++ unsigned char LogicalBlockAddress[4];
++ unsigned char Reserved2;
++ unsigned char Reserved3;
++ unsigned char PMI:1,
++ Reserved4:7;
++ unsigned char Reserved5;
++ unsigned char Reserved6;
++ unsigned char Reserved7;
++} __attribute__((packed)) SCSI_READ_CAPACITY_COMMAND;
++
++typedef struct{
++ unsigned char LastLogicalBlockAddress[4];
++ unsigned char BlockLengthInBytes[4];
++} __attribute__((packed)) SCSI_READ_CAPACITY_DATA;
++
++/*
++ * REQUEST SENSE
++ */
++
++typedef struct{
++ unsigned char OperationCode;
++ unsigned char Reserved1:5,
++ LogicalUnitNumber:3;
++ unsigned char Reserved2;
++ unsigned char Reserved3;
++ unsigned char AllocationLength;
++ unsigned char Reserved4;
++ unsigned char Reserved5;
++ unsigned char Reserved6;
++ unsigned char Reserved7;
++ unsigned char Reserved8;
++ unsigned char Reserved9;
++ unsigned char Reserved10;
++} __attribute__((packed)) SCSI_REQUEST_SENSE_COMMAND;
++
++typedef struct{
++ unsigned char ErrorCode:7,
++ Valid:1;
++ unsigned char Reserved1;
++ unsigned char SenseKey:4,
++ Reserved2:4;
++ unsigned char Information[4];
++ unsigned char AdditionalSenseLength;
++ unsigned char Reserved3[4];
++ unsigned char AdditionalSenseCode;
++ unsigned char AdditionalSenseCodeQualifier;
++ unsigned char Reserved4;
++ unsigned char Reserved5[3];
++} __attribute__((packed)) SCSI_REQUEST_SENSE_DATA;
++
++/*
++ * READ(10)
++ */
++
++typedef struct{
++ unsigned char OperationCode;
++ unsigned char RelAdr:1,
++ Reserved1:2,
++ FUA:1,
++ DPO:1,
++ LogicalUnitNumber:3;
++ unsigned char LogicalBlockAddress[4];
++ unsigned char Reserved2;
++ unsigned char TransferLength[2];
++ unsigned char Reserved3;
++ unsigned char Reserved4;
++ unsigned char Reserved5;
++} __attribute__((packed)) SCSI_READ_10_COMMAND;
++
++/*
++ * MODE SENSE
++ */
++
++typedef struct{
++ unsigned char OperationCode;
++ unsigned char Reserved1:3,
++ DBD:1,
++ Reserved2:1,
++ LogicalUnitNumber:3;
++ unsigned char PageCode:6,
++ PC:2;
++ unsigned char Reserved3;
++ unsigned char Reserved4;
++ unsigned char Reserved5;
++ unsigned char Reserved6;
++ unsigned char ParameterListLength[2];
++ unsigned char Reserved7;
++ unsigned char Reserved8;
++ unsigned char Reserved9;
++} __attribute__((packed)) SCSI_MODE_SENSE_COMMAND;
++
++typedef struct{
++ unsigned char ModeDataLength;
++ unsigned char MediumTypeCode;
++ unsigned char Reserved1:4,
++ DPOFUA:1,
++ Reserved2:2,
++ WP:1;
++ unsigned char Reserved3;
++} __attribute__((packed)) MODE_PARAMETER_HEADER;
++
++typedef struct{
++ unsigned char PageCode:6,
++ Reserved1:1,
++ PS:1;
++ unsigned char PageLength;
++ unsigned char DCR:1,
++ Reserved2:1,
++ PER:1,
++ Reserved3:1,
++ RC:1,
++ Reserved4:1,
++ Reserved5:1,
++ AWRE:1;
++ unsigned char ReadRetryCount;
++ unsigned char Reserved6[4];
++ unsigned char WriteRetryCount;
++ unsigned char Reserved7[3];
++} __attribute__((packed)) READ_WRITE_ERROR_RECOVERY_PAGE;
++
++typedef struct{
++ unsigned char PageCode:6,
++ Reserved1:1,
++ PS:1;
++ unsigned char PageLength;
++ unsigned char TransferRate[2];
++ unsigned char NumberofHeads;
++ unsigned char SectorsperTrack;
++ unsigned char DataBytesperSector[2];
++ unsigned char NumberofCylinders[2];
++ unsigned char Reserved2[9];
++ unsigned char MotorOnDelay;
++ unsigned char MotorOffDelay;
++ unsigned char Reserved3[7];
++ unsigned char MediumRotationRate[2];
++ unsigned char Reserved4;
++ unsigned char Reserved5;
++} __attribute__((packed)) FLEXIBLE_DISK_PAGE;
++
++typedef struct{
++ unsigned char PageCode:6,
++ Reserved1:1,
++ PS:1;
++ unsigned char PageLength;
++ unsigned char Reserved2:6,
++ SRFP:1,
++ SFLP:1;
++ unsigned char TLUN:3,
++ Reserved3:3,
++ SML:1,
++ NCD:1;
++ unsigned char Reserved4[8];
++} __attribute__((packed)) REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGE;
++
++typedef struct{
++ unsigned char PageCode:6,
++ Reserved1:1,
++ PS:1;
++ unsigned char PageLength;
++ unsigned char Reserved2;
++ unsigned char InactivityTimeMultiplier:4,
++ Reserved3:4;
++ unsigned char SWPP:1,
++ DISP:1,
++ Reserved4:6;
++ unsigned char Reserved5;
++ unsigned char Reserved6;
++ unsigned char Reserved7;
++} __attribute__((packed)) TIMER_AND_PROTECT_PAGE;
++
++typedef struct{
++ READ_WRITE_ERROR_RECOVERY_PAGE ReadWriteErrorRecoveryPage;
++ FLEXIBLE_DISK_PAGE FlexibleDiskPage;
++ REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGE RemovableBlockAccessCapabilitiesPage;
++ TIMER_AND_PROTECT_PAGE TimerAndProtectPage;
++} __attribute__((packed)) MODE_ALL_PAGES;
++
++typedef struct{
++ MODE_PARAMETER_HEADER ModeParameterHeader;
++ union{
++ READ_WRITE_ERROR_RECOVERY_PAGE ReadWriteErrorRecoveryPage;
++ FLEXIBLE_DISK_PAGE FlexibleDiskPage;
++ REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGE RemovableBlockAccessCapabilitiesPage;
++ TIMER_AND_PROTECT_PAGE TimerAndProtectPage;
++ MODE_ALL_PAGES ModeAllPages;
++ } __attribute__((packed)) ModePages;
++} __attribute__((packed)) SCSI_MODE_SENSE_DATA;
++
++/*
++ * TEST UNIT READY
++ */
++
++typedef struct{
++ unsigned char OperationCode;
++ unsigned char Reserved1:5,
++ LogicalUnitNumber:3;
++ unsigned char Reserved2;
++ unsigned char Reserved3;
++ unsigned char Reserved4;
++ unsigned char Reserved5;
++ unsigned char Reserved6;
++ unsigned char Reserved7;
++ unsigned char Reserved8;
++ unsigned char Reserved9;
++ unsigned char Reserved10;
++ unsigned char Reserved11;
++} __attribute__((packed)) SCSI_TEST_UNIT_READY_COMMAND;
++
++/*
++ * PREVENT-ALLOW MEDIUM REMOVAL
++ */
++
++typedef struct{
++ unsigned char OperationCode;
++ unsigned char Reserved1:5,
++ LogicalUnitNumber:3;
++ unsigned char Reserved2;
++ unsigned char Reserved3;
++ unsigned char Prevent:1,
++ Reserved4:7;
++ unsigned char Reserved5;
++ unsigned char Reserved6;
++ unsigned char Reserved7;
++ unsigned char Reserved8;
++ unsigned char Reserved9;
++ unsigned char Reserved10;
++ unsigned char Reserved11;
++} __attribute__((packed)) SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL_COMMAND;
++
++/*
++ * START-STOP UNIT
++ */
++
++typedef struct{
++ unsigned char OperationCode;
++ unsigned char IMMED:1,
++ Reserved1:4,
++ LogicalUnitNumber:3;
++ unsigned char Reserved2;
++ unsigned char Reserved3;
++ unsigned char Start:1,
++ LoEj:1,
++ Reserved4:6;
++ unsigned char Reserved5;
++ unsigned char Reserved6;
++ unsigned char Reserved7;
++ unsigned char Reserved8;
++ unsigned char Reserved9;
++ unsigned char Reserved10;
++ unsigned char Reserved11;
++} __attribute__((packed)) SCSI_START_STOP_COMMAND;
++
++/*
++ * WRITE(10)
++ */
++
++typedef struct{
++ unsigned char OperationCode;
++ unsigned char RelAdr:1,
++ Reserved1:2,
++ FUA:1,
++ DPO:1,
++ LogicalUnitNumber:3;
++ unsigned char LogicalBlockAddress[4];
++ unsigned char Reserved2;
++ unsigned char TransferLength[2];
++ unsigned char Reserved3;
++ unsigned char Reserved4;
++ unsigned char Reserved5;
++} __attribute__((packed)) SCSI_WRITE_10_COMMAND;
++
++/*
++ * VERIFY
++ */
++
++typedef struct{
++ unsigned char OperationCode;
++ unsigned char RelAdr:1,
++ ByteChk:1,
++ Reserved1:1,
++ Reserved2:1,
++ DPO:1,
++ LogicalUnitNumber:3;
++ unsigned char LogicalBlockAddress[4];
++ unsigned char Reserved3;
++ unsigned char VerificationLength[2];
++ unsigned char Reserved4;
++ unsigned char Reserved5;
++ unsigned char Reserved6;
++} __attribute__((packed)) SCSI_VERIFY_COMMAND;
++
++/******************************************************************************
++** Global Function Prototype
++******************************************************************************/
++
++/* storage-fd.c */
++void storage_urb_send(struct usb_device_instance*, void*, int);
++
++/* storageproto.c */
++void storageproto_urb_analysis(struct urb*);
++int storageproto_device_open_check(void);
++void storageproto_device_close(void);
++void storageproto_usb_status_check(int);
++void storageproto_media_status_check(int);
++void storageproto_usb_reset_ind(void);
++ssize_t storageproto_proc_read(struct file*, char*, size_t, loff_t* pos);
++void storageproto_init(void);
++void storageproto_exit(void);
++
++#endif /* _STORAGEPROTO_H_ */
++