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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 , + * Tom Rushworth , + * Bruce Balden + * + * 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 +#include + +#include "../usbd-export.h" +#include "../usbd-build.h" +#include "../usbd-module.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#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 +#include + +#include "../usbd-export.h" +#include "../usbd-build.h" +#include "../usbd-module.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#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_