diff options
Diffstat (limited to 'packages/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/usb-storage.patch')
-rw-r--r-- | packages/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/usb-storage.patch | 3433 |
1 files changed, 3433 insertions, 0 deletions
diff --git a/packages/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/usb-storage.patch b/packages/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/usb-storage.patch index e69de29bb2..c9296cf224 100644 --- a/packages/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/usb-storage.patch +++ b/packages/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(¤t->sigmask_lock); ++ siginitsetinv(¤t->blocked, ++ sigmask(SIGUSR1) | sigmask(SIGHUP) | sigmask(SIGKILL) | ++ sigmask(SIGSTOP) | sigmask(SIGCONT) | sigmask(SIGTERM) | ++ sigmask(SIGALRM)); ++ recalc_sigpending(current); ++ spin_unlock_irq(¤t->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(¤t->sigmask_lock); ++ signr = dequeue_signal(¤t->blocked, &info); ++ spin_unlock_irq(¤t->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, §or, 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, §or, 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_ */ ++ |