📄 storage.c
字号:
/* * storage_fd/storage.c * * 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> * * Copyright (C) 2002 Toshiba Corporation * * Changes copyright (C) 2003 MontaVista Software, Inc. * * 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. * *//* * This module implements USB Mass Storage Class * (SubClass: RBC, Transport: Bulk-Only) * * Usage: */#include <linux/config.h>#include <linux/module.h>#include "../usbd-export.h"#include "../usbd-build.h"#include "../usbd-module.h"MODULE_AUTHOR("sl@lineo.com, tbr@lineo.com, TOSHIBA Corporation");MODULE_LICENSE("GPL");MODULE_DESCRIPTION("USB Device Mass Storage Function");#define STORAGE_MOD_NAME "storage_fd"USBD_MODULE_INFO(STORAGE_MOD_NAME " 0.1-beta");#ifndef MODULE#undef GET_USE_COUNT#define GET_USE_COUNT(foo) 1#endif#include <linux/init.h>#include <linux/kernel.h>#include <linux/list.h>#include <asm/uaccess.h>#include <asm/unaligned.h>#include <linux/netdevice.h>#include <linux/smp_lock.h>#include <linux/ctype.h>#include <linux/timer.h>#include <linux/string.h>#include <linux/proc_fs.h>#include <scsi/scsi.h>#define __KERNEL_SYSCALLS__static int errno;#include <asm/unistd.h>#include "../usbd.h"#include "../usbd-func.h"#include "../usbd-bus.h"#include "../usbd-debug.h"#include "../usbd-inline.h"#include "../usbd-arch.h"#define MAX_STORAGES 1#define STORAGE_DEFAULT_FILENAME "/dev/ram0"#define STORAGE_BLOCK_SIZE 512#define STORAGE_PROC_NAME "driver/" STORAGE_MOD_NAME#define USB_REQ_BO_MASS_STORAGE_RESET 0xFF#define USB_REQ_GET_MAX_LUN 0xFE#if 0/* RBC 6.1 states "RBC devices are identified by a PERIPHERAL DEVICE * TYPE 0Eh" */#define PERIPHERAL_DEVICE_TYPE 0x0e#else/* XXX: Linux sd,scsi stack seems to expect this value... */#define PERIPHERAL_DEVICE_TYPE 0x00#endif#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 CONFIG_USBD_STORAGE_VENDORID #undef CONFIG_USBD_VENDORID #define CONFIG_USBD_VENDORID CONFIG_USBD_STORAGE_VENDORID#endif#if CONFIG_USBD_STORAGE_PRODUCTID #undef CONFIG_USBD_PRODUCTID #define CONFIG_USBD_PRODUCTID CONFIG_USBD_STORAGE_PRODUCTID#endif#ifndef CONFIG_USBD_SERIAL_NUMBER_STR #define CONFIG_USBD_SERIAL_NUMBER_STR "000000000000"#endif#ifdef CONFIG_USBD_SELFPOWERED #define BMATTRIBUTE BMATTRIBUTE_RESERVED | BMATTRIBUTE_SELF_POWERED #define BMAXPOWER 0#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_OUT_ENDPOINT #define CONFIG_USBD_STORAGE_OUT_ENDPOINT 1#endif#ifndef CONFIG_USBD_STORAGE_IN_ENDPOINT #define CONFIG_USBD_STORAGE_IN_ENDPOINT 2#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 #define CONFIG_USBD_STORAGE_OUT_ENDPOINT ABS_OUT_ADDR #endif#if defined(ABS_IN_ADDR) #warning #warning USING ABS ENDPOINT IN ADDRESS #undef CONFIG_USBD_STORAGE_IN_ENDPOINT #if ABS_IN_ADDR #define CONFIG_USBD_STORAGE_IN_ENDPOINT ABS_IN_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 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#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#endifenum usb_storage_device_state { STATE_INVALID, STATE_IDLE, /* Device intends to receive command */ STATE_DN, /* Device intends to transfer no data */ STATE_DI, /* Device intends to send data to the host */ STATE_DO, /* Device intends to receive data from the host */};#define CSW_STAT_GOOD 0x00#define CSW_STAT_FAILED 0x01#define CSW_STAT_PERR 0x02 /* Phase Error *//* Command Block Wrapper */#define MAX_CBLENGTH 16struct CBW { u32 dSignature; u32 dTag; u32 dDataTransferLength; u8 bmFlags; u8 bLUN; u8 bCBLength; u8 CB[MAX_CBLENGTH];} __attribute__((packed));#define CBW_SIGNATURE 0x43425355/* Command Status Wrapper */struct CSW { u32 dSignature; u32 dTag; u32 dDataResidue; u8 bStatus;} __attribute__((packed));#define CSW_SIGNATURE 0x53425355struct usb_storage_threaddata { int busy; struct CBW cbw; /* cpu endian */ struct CSW csw; /* cpu endian */ u8 *data_buf; /* NOTE: data_len CAN exceed cbw.dDataTransferLength */ unsigned int data_len; unsigned int data_alloclen; /* sense data */ struct { u8 key; u32 info; u32 cmdinfo; u8 code; } sense; /* real storage */ struct file *real_fd; char filename[128]; unsigned int num_blocks; /* statistics */ struct { /* transmit statistics */ unsigned int read_blocks; unsigned int write_blocks; /* command statictics */ unsigned int inquiry; unsigned int mode_select; unsigned int mode_sense; unsigned int read_10; unsigned int read_capacity; unsigned int request_sense; unsigned int start_stop; unsigned int test_unit_ready; unsigned int verify; unsigned int write_10; unsigned int write_buffer; unsigned int unsupported; } stat;};struct usb_storage_private { struct usb_device_instance *device; enum usb_storage_device_state devstate; struct usb_storage_threaddata tdata;};static spinlock_t storage_lock;static struct usb_storage_private storage_private; // one and only storagestatic DECLARE_MUTEX_LOCKED(storage_sem_start);static DECLARE_MUTEX_LOCKED(storage_sem_work);static int storage_thread_terminating;static void storage_thread_poke(void){ up(&storage_sem_work);}/* SCSI related definitions *//* * Sense codes */ #define SENCODE_NO_SENSE 0x00#define SENCODE_END_OF_DATA 0x00#define SENCODE_BECOMING_READY 0x04#define SENCODE_INIT_CMD_REQUIRED 0x04#define SENCODE_PARAM_LIST_LENGTH_ERROR 0x1A#define SENCODE_INVALID_COMMAND 0x20#define SENCODE_LBA_OUT_OF_RANGE 0x21#define SENCODE_INVALID_CDB_FIELD 0x24#define SENCODE_LUN_NOT_SUPPORTED 0x25#define SENCODE_INVALID_PARAM_FIELD 0x26#define SENCODE_PARAM_NOT_SUPPORTED 0x26#define SENCODE_PARAM_VALUE_INVALID 0x26#define SENCODE_RESET_OCCURRED 0x29#define SENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x3E#define SENCODE_INQUIRY_DATA_CHANGED 0x3F#define SENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x39#define SENCODE_DIAGNOSTIC_FAILURE 0x40#define SENCODE_INTERNAL_TARGET_FAILURE 0x44#define SENCODE_INVALID_MESSAGE_ERROR 0x49#define SENCODE_LUN_FAILED_SELF_CONFIG 0x4c#define SENCODE_OVERLAPPED_COMMAND 0x4E/* Module Parameters ************************************************************************* */static char *dbg = NULL;static u32 vendor_id;static u32 product_id;static char *serial_number = NULL;static char *filename = NULL;MODULE_PARM(dbg, "s");MODULE_PARM(vendor_id, "i");MODULE_PARM(product_id, "i");MODULE_PARM(serial_number, "s");MODULE_PARM(filename, "s");MODULE_PARM_DESC(dbg, "USB Device Debug options");MODULE_PARM_DESC(vendor_id, "USB Device Vendor ID");MODULE_PARM_DESC(product_id, "USB Device Product ID");MODULE_PARM_DESC(serial_number, "USB Device Serial Number");MODULE_PARM_DESC(filename, "USB Device Storage Filename");/* Debug switches (module parameter "dbg=...") *********************************************** */extern int dbgflg_usbdfd_init;int dbgflg_usbdfd_ep0;int dbgflg_usbdfd_usbe;int dbgflg_usbdfd_tx;int dbgflg_usbdfd_rx;static debug_option dbg_table[] = { {&dbgflg_usbdfd_init,NULL,"init","initialization and termination"}, {&dbgflg_usbdfd_ep0,NULL,"ep0","End Point 0 (setup) packet handling"}, {&dbgflg_usbdfd_usbe,NULL,"usbe","USB events"}, {&dbgflg_usbdfd_tx,NULL,"tx","transmit (to host)"}, {&dbgflg_usbdfd_rx,NULL,"rx","receive (from host)"}, {NULL,NULL,NULL,NULL}};#define dbg_init(lvl,fmt,args...) dbgPRINT(dbgflg_usbdfd_init,lvl,fmt,##args)#define dbg_ep0(lvl,fmt,args...) dbgPRINT(dbgflg_usbdfd_ep0,lvl,fmt,##args)#define dbg_usbe(lvl,fmt,args...) dbgPRINT(dbgflg_usbdfd_usbe,lvl,fmt,##args)#define dbg_tx(lvl,fmt,args...) dbgPRINT(dbgflg_usbdfd_tx,lvl,fmt,##args)#define dbg_rx(lvl,fmt,args...) dbgPRINT(dbgflg_usbdfd_rx,lvl,fmt,##args)/* ******************************************************************************************* *//* Mass Storage Class descriptions */#define STORAGE_TRANSFER_SIZE 2048 /* XXX max 0xfff. why? (see usbd-bi.c) */static struct usb_endpoint_description storage_default[] = { { bEndpointAddress: CONFIG_USBD_STORAGE_OUT_ENDPOINT, bmAttributes: BULK, wMaxPacketSize: CONFIG_USBD_STORAGE_OUT_PKTSIZE, bInterval: 0, direction: OUT, transferSize: STORAGE_TRANSFER_SIZE, }, { bEndpointAddress: CONFIG_USBD_STORAGE_IN_ENDPOINT, bmAttributes: BULK, wMaxPacketSize: CONFIG_USBD_STORAGE_IN_PKTSIZE, bInterval: 0, direction: IN, transferSize: STORAGE_TRANSFER_SIZE, },};/* Data Interface Alternate description(s) */static __initdata struct usb_alternate_description storage_data_alternate_descriptions[] = { { iInterface: "Simple Mass Storage Data Interface - Bulk-Only", bAlternateSetting: 0, classes: 0, class_list: NULL, endpoints: sizeof(storage_default)/sizeof(struct usb_endpoint_description), endpoint_list: storage_default, },};/* Interface description(s) */static __initdata struct usb_interface_description storage_interfaces[] = { { iInterface: "Simple Mass Storage Data Interface", bInterfaceClass: USB_CLASS_MASS_STORAGE, bInterfaceSubClass: 0x05, /*removeble*/ bInterfaceProtocol: 0x50, /* Bulk-Only Transport */ alternates: sizeof(storage_data_alternate_descriptions)/sizeof(struct usb_alternate_description), alternate_list: storage_data_alternate_descriptions, },};/* Configuration description(s) */struct __initdata usb_configuration_description storage_description[] = { { iConfiguration: "USB Simple Mass Storage Configuration", bmAttributes: BMATTRIBUTE, bMaxPower: BMAXPOWER, interfaces: sizeof(storage_interfaces)/sizeof(struct usb_interface_description), interface_list: storage_interfaces, },};/* Device Description */struct __initdata usb_device_description storage_device_description = { bDeviceClass: 0, bDeviceSubClass: 0, bDeviceProtocol: 0, idVendor: CONFIG_USBD_VENDORID, idProduct: CONFIG_USBD_PRODUCTID, iManufacturer: CONFIG_USBD_MANUFACTURER, iProduct: CONFIG_USBD_PRODUCT_NAME, iSerialNumber: CONFIG_USBD_SERIAL_NUMBER_STR,};static int storage_receive_CBW(struct usb_storage_private *private, u8 *buf, unsigned int len){ struct CBW *cbwp = (struct CBW *)buf; struct usb_storage_threaddata *tdata = &private->tdata;#if 0 /* bad bi driver */ if (len < sizeof(struct CBW)) { printk(KERN_ERR STORAGE_MOD_NAME ": bad CBW length (%d)\n", len); return -1; }#else if (len != sizeof(struct CBW)) { printk(KERN_ERR STORAGE_MOD_NAME ": bad CBW length (%d)\n", len); return -1; }#endif if (le32_to_cpu(cbwp->dSignature) != CBW_SIGNATURE) { printk(KERN_ERR STORAGE_MOD_NAME ": bad CBW signature (%x)\n", le32_to_cpu(cbwp->dSignature)); return -1; } if (cbwp->bLUN != 0) { printk(KERN_ERR STORAGE_MOD_NAME ": bad CBW LUN (%x)\n", cbwp->bLUN); return -1; } tdata->cbw = *cbwp; tdata->cbw.dSignature = le32_to_cpu(tdata->cbw.dSignature); tdata->cbw.dTag = le32_to_cpu(tdata->cbw.dTag); tdata->cbw.dDataTransferLength = le32_to_cpu(tdata->cbw.dDataTransferLength); tdata->csw.dSignature = CSW_SIGNATURE; tdata->csw.dTag = tdata->cbw.dTag; tdata->csw.dDataResidue = tdata->cbw.dDataTransferLength; tdata->csw.bStatus = CSW_STAT_GOOD; return len - sizeof(struct CBW);}static int storage_send_CSW(struct usb_storage_private *private){ struct urb *urb; int port = 0; // XXX compound device struct usb_storage_threaddata *tdata = &private->tdata; urb = usbd_alloc_urb(private->device, private->device->function_instance_array+port, CONFIG_USBD_STORAGE_IN_ENDPOINT | IN, sizeof (struct CSW)); if (!urb) { printk(KERN_ERR STORAGE_MOD_NAME ": failed to alloc CSW urb\n"); return -EINVAL; } tdata->csw.dSignature = cpu_to_le32(tdata->csw.dSignature); tdata->csw.dTag = cpu_to_le32(tdata->csw.dTag); tdata->csw.dDataResidue = cpu_to_le32(tdata->csw.dDataResidue); memcpy(urb->buffer, &tdata->csw, sizeof(struct CSW)); urb->actual_length = sizeof(struct CSW); dbg_rx(3,"CSW (length %d)", urb->actual_length); dbgPRINTmem(dbgflg_usbdfd_tx,3,urb->buffer,min(urb->actual_length, 32u)); if (usbd_send_urb(urb)) return -EINVAL; return 0;}/* storage_urb_sent - called to indicate URB transmit finished * @urb: pointer to struct urb * @rc: result
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -