📄 csk_udisk_mgr.c
字号:
/* * UDISK Driver For SUMSUNG Mobile * BY CSK * * SPECIAL THX TO Michael Gee (michael@linuxspecific.com) *///Something to be include...#include <linux/sched.h>#include <linux/errno.h>#include <linux/freezer.h>#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/kthread.h>#include <linux/mutex.h>#include <linux/utsrelease.h>#include <linux/usb.h>#include <linux/usb_usual.h>#include <linux/blkdev.h>#include <linux/smp_lock.h>#include <linux/completion.h>#include <linux/mutex.h>#include <linux/slab.h>#include <linux/highmem.h>//SCSI support#include <scsi/scsi.h>#include <scsi/scsi_cmnd.h>#include <scsi/scsi_devinfo.h>#include <scsi/scsi_device.h>#include <scsi/scsi_host.h>#include <scsi/scsi_eh.h>#include <asm/scatterlist.h>#include <asm/dma.h> // I hate this guy...struct us_data;struct scsi_cmnd;/* command block wrapper */struct bulk_cb_wrap { __le32 Signature; /* contains 'USBC' */ __u32 Tag; /* unique per command id */ __le32 DataTransferLength; /* size of data */ __u8 Flags; /* direction in bit 0 */ __u8 Lun; /* LUN normally 0 */ __u8 Length; /* of of the CDB */ __u8 CDB[16]; /* max command */};#define US_BULK_CB_WRAP_LEN 31#define US_BULK_CB_SIGN 0x43425355 /*spells out USBC */#define US_BULK_FLAG_IN 1#define US_BULK_FLAG_OUT 0/* command status wrapper */struct bulk_cs_wrap { __le32 Signature; /* should = 'USBS' */ __u32 Tag; /* same as original command */ __le32 Residue; /* amount not transferred */ __u8 Status; /* see below */ __u8 Filler[18];};#define US_BULK_CS_WRAP_LEN 13#define US_BULK_CS_SIGN 0x53425355 /* spells out 'USBS' */#define US_BULK_STAT_OK 0#define US_BULK_STAT_FAIL 1#define US_BULK_STAT_PHASE 2/* bulk-only class specific requests */#define US_BULK_RESET_REQUEST 0xff#define US_BULK_GET_MAX_LUN 0xfe#define USB_STOR_XFER_GOOD 0 /* good transfer */#define USB_STOR_XFER_SHORT 1 /* transferred less than expected */#define USB_STOR_XFER_STALLED 2 /* endpoint stalled */#define USB_STOR_XFER_LONG 3 /* device tried to send too much */#define USB_STOR_XFER_ERROR 4 /* transfer died in the middle *//* * Transport return codes */#define USB_STOR_TRANSPORT_GOOD 0 /* Transport good, command good */#define USB_STOR_TRANSPORT_FAILED 1 /* Transport good, command failed */#define USB_STOR_TRANSPORT_NO_SENSE 2 /* Command failed, no auto-sense */#define USB_STOR_TRANSPORT_ERROR 3 /* Transport bad (i.e. device dead) *//* Dynamic flag definitions: used in set_bit() etc. */#define US_FLIDX_URB_ACTIVE 18 /* 0x00040000 current_urb is in use */#define US_FLIDX_SG_ACTIVE 19 /* 0x00080000 current_sg is in use */#define US_FLIDX_ABORTING 20 /* 0x00100000 abort is in progress */#define US_FLIDX_DISCONNECTING 21 /* 0x00200000 disconnect in progress */#define ABORTING_OR_DISCONNECTING ((1UL << US_FLIDX_ABORTING) | \ (1UL << US_FLIDX_DISCONNECTING))#define US_FLIDX_RESETTING 22 /* 0x00400000 device reset in progress */#define US_FLIDX_TIMED_OUT 23 /* 0x00800000 SCSI midlayer timed out */#define USB_STOR_STRING_LEN 32#define US_IOBUF_SIZE 64 /* Size of the DMA-mapped I/O buffer */#define US_SENSE_SIZE 18 /* Size of the autosense data buffer */#define US_SUSPEND 0#define US_RESUME 1/* we use this macro to help us write into the buffer */#undef SPRINTF#define SPRINTF(args...) \ do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0)/* we allocate one of these for every device that we remember */struct us_data { struct mutex dev_mutex; /* protect pusb_dev */ struct usb_device *pusb_dev; /* this usb_device */ struct usb_interface *pusb_intf; /* this interface */ unsigned long flags; /* from filter initially */ unsigned int send_bulk_pipe; /* cached pipe values */ unsigned int recv_bulk_pipe; unsigned int send_ctrl_pipe; unsigned int recv_ctrl_pipe; unsigned int recv_intr_pipe; /* informatioscsi_report_bus_reset(us_to_host(us), 0);n about the device */ __le32 bcs_signature; u8 subclass; u8 protocol; u8 max_lun; u8 ifnum; /* interface number */ u8 ep_bInterval; /* interrupt interval */ /* SCSI interfaces */ struct scsi_cmnd *srb; /* current srb */ unsigned int tag; /* current dCBWTag */ /* control and bulk communications data */ struct urb *current_urb; /* USB requests */ struct usb_ctrlrequest *cr; /* control requests */ struct usb_sg_request current_sg; /* scatter-gather req. */ unsigned char *iobuf; /* I/O buffer */ unsigned char *sensebuf; /* sense data buffer */ dma_addr_t cr_dma; /* buffer DMA addresses */ dma_addr_t iobuf_dma; /* mutual exclusion and synchronization structures */ struct semaphore sema; /* to sleep thread on */ struct completion notify; /* thread begin/end */ wait_queue_head_t delay_wait; /* wait during scan, reset */};static inline struct Scsi_Host *us_to_host(struct us_data *us) { return container_of((void *) us, struct Scsi_Host, hostdata);}static inline struct us_data *host_to_us(struct Scsi_Host *host) { return (struct us_data *) host->hostdata;}#define scsi_unlock(host) spin_unlock_irq(host->host_lock)#define scsi_lock(host) spin_lock_irq(host->host_lock)MODULE_AUTHOR("CSK");MODULE_DESCRIPTION("SAMSUNG MOBILE USB Mass Storage");MODULE_LICENSE("GPL");static atomic_t g_total_workers = ATOMIC_INIT(0);//SAMSUNG MOBILE USB INFO#define USB_MASS_VENDOR_ID 0x04e8#define USB_MASS_PRODUCT_ID 0x665c //REG ITstatic struct usb_device_id storage_usb_ids [] = { { USB_DEVICE(USB_MASS_VENDOR_ID, USB_MASS_PRODUCT_ID) }, { } /* Terminating entry */};MODULE_DEVICE_TABLE (usb, storage_usb_ids);unsigned char usb_stor_sense_invalidCDB[18] = { [0] = 0x70, /* current error */ [2] = ILLEGAL_REQUEST, /* Illegal Request = 0x05 */ [7] = 0x0a, /* additional length */ [12] = 0x24 /* Invalid Field in CDB */};//PROTOTYPEstatic int usb_worker(void * __us);static void FreeUpAll(struct us_data *us);static void quiesce_and_remove_host(struct us_data *us);static void usb_stor_stop_transport(struct us_data *us);static int usb_stor_clear_halt(struct us_data *us, unsigned int pipe);static void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us);static int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us);static int usb_stor_port_reset(struct us_data *us);static void usb_stor_report_device_reset(struct us_data *us);static int usb_stor_Bulk_reset(struct us_data *us);static int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, void *buf, unsigned int length, unsigned int *act_len);static int usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe, void *buf, unsigned int length_left, int use_sg, int *residual);static int usb_stor_control_msg(struct us_data *us, unsigned int pipe, u8 request, u8 requesttype, u16 value, u16 index, void *data, u16 size, int timeout);static int usb_stor_msg_common(struct us_data *us, int timeout);static int interpret_urb_result(struct us_data *us, unsigned int pipe, unsigned int length, int result, unsigned int partial);static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe, struct scatterlist *sg, int num_sg, unsigned int length, unsigned int *act_len);static int usb_stor_Bulk_max_lun(struct us_data *us);static void usb_stor_blocking_completion(struct urb *urb);static int slave_configure(struct scsi_device *sdev);static int slave_alloc (struct scsi_device *sdev);static int bus_reset(struct scsi_cmnd *srb);static int device_reset(struct scsi_cmnd *srb);static int command_abort(struct scsi_cmnd *srb);static int queuecommand(struct scsi_cmnd *srb, void (*done)(struct scsi_cmnd *));static const char* host_info(struct Scsi_Host *host);static int proc_info (struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int inout);static ssize_t store_max_sectors(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);static ssize_t show_max_sectors(struct device *dev, struct device_attribute *attr, char *buf);static DEVICE_ATTR(max_sectors, S_IRUGO | S_IWUSR, show_max_sectors, store_max_sectors);static struct device_attribute *sysfs_device_attr_list[] = { &dev_attr_max_sectors, NULL, };struct scsi_host_template usb_stor_host_template = { /* basic userland interface stuff */ .name = "mobileusb-storage", .proc_name = "mobileusb-storage", .proc_info = proc_info, .info = host_info, /* command interface -- queued only */ .queuecommand = queuecommand, /* error and abort handlers */ .eh_abort_handler = command_abort, .eh_device_reset_handler = device_reset, .eh_bus_reset_handler = bus_reset, /* queue commands only, only one command per LUN */ .can_queue = 1, .cmd_per_lun = 1, /* unknown initiator id */ .this_id = -1, .slave_alloc = slave_alloc, .slave_configure = slave_configure, /* lots of sg segments can be handled */ .sg_tablesize = SG_ALL, /* limit the total size of a transfer to 120 KB */ .max_sectors = 240, /* merge commands... this seems to help performance, but * periodically someone should test to see which setting is more * optimal. */ .use_clustering = 1, /* emulated HBA */ .emulated = 1, /* we do our own delay after a device or bus reset */ .skip_settle_delay = 1, /* sysfs device attributes */ .sdev_attrs = sysfs_device_attr_list, /* module management */ .module = THIS_MODULE};///static void storage_pre_reset(struct usb_interface *iface){ struct us_data *us = usb_get_intfdata(iface); /* Make sure no command runs during the reset */ mutex_lock(&us->dev_mutex);}static void storage_post_reset(struct usb_interface *iface){ struct us_data *us = usb_get_intfdata(iface); /* Report the reset to the SCSI core */ scsi_lock(us_to_host(us)); scsi_report_bus_reset(us_to_host(us), 0); scsi_unlock(us_to_host(us)); /* FIXME: Notify the subdrivers that they need to reinitialize * the device */ mutex_unlock(&us->dev_mutex);}//Begin working...static int storage_probe(struct usb_interface *intf, const struct usb_device_id *id){ struct Scsi_Host *host; struct us_data *us; int Ans; struct task_struct *th; int i; struct usb_endpoint_descriptor *ep; struct usb_endpoint_descriptor *ep_in = NULL; struct usb_endpoint_descriptor *ep_out = NULL; struct usb_endpoint_descriptor *ep_int = NULL; /* * Ask the SCSI layer to allocate a host structure, with extra * space at the end for our private us_data structure. */ host = scsi_host_alloc(&usb_stor_host_template, sizeof(*us)); if (!host) { printk(KERN_WARNING "allocate the scsi host failed\n"); return -ENOMEM; } us = host_to_us(host); memset(us, 0, sizeof(struct us_data)); mutex_init(&(us->dev_mutex)); init_MUTEX_LOCKED(&(us->sema)); init_completion(&(us->notify)); init_waitqueue_head(&us->delay_wait); /* Associate the us_data structure with the USB device */ /* Fill in the device-related fields */ us->pusb_dev = interface_to_usbdev(intf); us->pusb_intf = intf; us->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; /* Store our private data in the interface */ usb_set_intfdata(intf, us); /* Allocate the device-related DMA-mapped buffers */ us->cr = usb_buffer_alloc(us->pusb_dev, sizeof(*us->cr), GFP_KERNEL, &us->cr_dma); if (!us->cr) { goto BadDevice; } us->iobuf = usb_buffer_alloc(us->pusb_dev, US_IOBUF_SIZE, GFP_KERNEL, &us->iobuf_dma); if (!us->iobuf) { goto BadDevice; } us->sensebuf = kmalloc(US_SENSE_SIZE, GFP_KERNEL); if (!us->sensebuf) { goto BadDevice; } us->subclass = us->pusb_intf->cur_altsetting->desc.bInterfaceSubClass; us->protocol = us->pusb_intf->cur_altsetting->desc.bInterfaceProtocol ; us->flags = USB_US_ORIG_FLAGS(id->driver_info); if (us->flags & US_FL_IGNORE_DEVICE) { printk(KERN_INFO "device ignored\n"); goto BadDevice; } /* * This flag is only needed when we're in high-speed, so let's * disable it if we're in full-speed */ if (us->pusb_dev->speed != USB_SPEED_HIGH) us->flags &= ~US_FL_GO_SLOW; /* Get the transport, protocol, and pipe settings */ if (us->protocol != US_PR_BULK){ printk(KERN_INFO "device mismatched\n"); goto BadDevice; } if (us->subclass != US_SC_8020){ printk(KERN_INFO "device mismatched\n"); goto BadDevice; } us->max_lun = 0; /* * Find the endpoints we need. * We are expecting a minimum of 2 endpoints - in and out (bulk). * An optional interrupt is OK (necessary for CBI protocol). * We will ignore any others. */ for (i = 0; i < us->pusb_intf->cur_altsetting->desc.bNumEndpoints; i++) { ep = &us->pusb_intf->cur_altsetting->endpoint[i].desc; /* Is it a BULK endpoint? */ if (usb_endpoint_xfer_bulk(ep)) { /* BULK in or out? */ if (usb_endpoint_dir_in(ep))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -