2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > Linux USB 驱动入门之发送SCSI 指令READ_10给U盘读取数据

Linux USB 驱动入门之发送SCSI 指令READ_10给U盘读取数据

时间:2023-10-02 17:22:39

相关推荐

Linux USB 驱动入门之发送SCSI 指令READ_10给U盘读取数据

以下模块实现了发送SCSI指令READ_10给U盘,然后读取指定Block的数据。

只是证明此模块的READ_10的实现没有问题,没有对读取的数据做任何处理,只是打印了接收到多少个Byte。

#define MY_LBA 1#define QUEST_BLOCK_NUMBER 8

MY_LBA 指定了Block的起始地址,就是从第几个Block开始读,注意编号是从0开始的。

QUEST_BLOCK_NUMBER 指定一次读几个Block,这个程序最多支持8个Block。

参考了 Bus Hound的抓包数据 。

#include <linux/init.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/device.h>#include <linux/usb.h>#include <linux/slab.h>#include <linux/timer.h>#include <linux/usb/storage.h>#include <scsi/scsi_proto.h>#include <asm-generic/errno-base.h>#include <uapi/asm-generic/errno.h>#include <uapi/linux/cciss_defs.h>/*** USB Mass Storage Class** /library/view/linux-device-drivers/0596005903/ch13.html** /doc/html/v4.12/driver-api/usb/writing_usb_driver.html** http://www.linux-/** /tutorials/linux/device-drivers/usb-device-driver-basics/** /Embetronicx/Tutorials/blob/master/Linux/Device_Driver/usb_device_driver/usb_driver.c** /sites/default/files/Mass_Storage_Specification_Overview_v1.4_2-19-.pdf** /sites/default/files/Mass_Storage_Specification_Overview_v1.4_2-19-.pdf** /content/www/us/en/products/docs/io/universal-serial-bus/universal-serial-bus-specifications.html*** https://www.linux.it/~rubini/docs/usb/usb.html** http://www.linux-/devices.html*** /wiki/SCSI** /wiki/SCSI_command*** /lists/2op.htm** /USB_Mass_Storage_Class_Devices*** /enterprise/zh/doc/EDOC1000149331/ec501220** Devices usually have one or more configurations.*** Whenever a USB device is attached to the bus it will be enumerated by theUSB subsystem - i.e an unique device number (1-127) is assigned and then thedevice descriptor is read. Such a desciptor is a data structure which containsinformation about the device and its properties.Configurations often have one or more interfaces.Interfaces usually have one or more settings.Interfaces have zero or more endpoints.*** lsusb* usb-devices** Bulk Only Mass Storage Devices are the most common type of USB storage device, and they include most USB thumb drives, hard drives, CD,* DVD and Blu-ray drives as well. They normally use the SCSI Command Set,* but the USB Mass Storage specifications allow devices to use other command sets as well.** USB Mass Storage Class Bulk-Only (BBB) Transport** Universal Serial Bus Specification*** In SCSI terminology, communication takes place between an initiator and a target. The initiator sends a command to the target, which then responds.* SCSI commands are sent in a Command Descriptor Block (CDB).* The CDB consists of a one byte operation code followed by five or more bytes containing command-specific parameters.*** At the end of the command sequence, the target returns a status code byte, such as 00h for success,* 02h for an error (called a Check Condition), or 08h for busy**There are four categories of SCSI commands: N (non-data), W (writing data from initiator to target), R (reading data), and B (bidirectional).**Test unit ready: Queries device to see if it is ready for data transfers (disk spun up, media loaded, etc.).Inquiry: Returns basic device information.Request sense: Returns any error codes from the previous command that returned an error status.Send diagnostic and Receive diagnostic results: runs a simple self-test, or a specialised test defined in a diagnostic page.Start/Stop unit: Spins disks up and down, or loads/unloads media (CD, tape, etc.).Read capacity: Returns storage capacity.Format unit: Prepares a storage medium for use. In a disk, a low level format will occur. Some tape drives will erase the tape in response to this command.Read: (four variants): Reads data from a device.Write: (four variants): Writes data to a device.Log sense: Returns current information from log pages.Mode sense: Returns current device parameters from mode pages.Mode select: Sets device parameters in a mode page.SCSI commands are sent in a command descriptor block (CDB), which consists of a one byte operation code (opcode) followed by fiveor more bytes containing command-specific parameters.Upon receiving and processing the CDB the device will return a status code byte and other information.The target usually provides the initiators one or more logical unit numbers (LUN).In a storage area, a LUN often represents a SCSI disk on which a host can perform a read and write operation.Every endpoint in a device can handle a queue of urbs, so that multiple urbs can be sent to the same endpoint before the queue is emptyT: Bus=06 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 3 Spd=5000 MxCh= 0D: Ver= 3.20 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 9 #Cfgs= 1P: Vendor=0951 ProdID=1666 Rev=01.10S: Manufacturer=KingstonS: Product=DataTraveler 3.0S: SerialNumber=E0D55EA573EB165178570CE3C: #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=144mAI: If#=0x0 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=andy_usbdriver**/#define USB_VENDOR_ID (0x0951)#define USB_PRODUCT_ID (0x1666)#define MYTAG 1333#define MY_BLOCK_SIZE 512#define MY_LBA 1#define REQUEST_BLOCK_NUMBER 1#define RETURN_DATA_LENGTH (MY_BLOCK_SIZE * REQUEST_BLOCK_NUMBER)//#define inquiry_device_identification#define inquiry_supported_vpd_pages#define PRINT_USB_ENDPOINT_DESCRIPTOR( i )\{\pr_info("USB_INTERFACE_DESCRIPTOR:\n");\pr_info("-----------------------------\n"); \pr_info("bLength: 0x%x\n", i.bLength);\pr_info("bDescriptorType: 0x%x\n", i.bDescriptorType);\pr_info("bInterfaceNumber: 0x%x\n", i.bInterfaceNumber); \pr_info("bAlternateSetting: 0x%x\n", i.bAlternateSetting);\pr_info("bNumEndpoints: 0x%x\n", i.bNumEndpoints); \pr_info("bInterfaceClass: 0x%x\n", i.bInterfaceClass);\pr_info("bInterfaceSubClass: 0x%x\n", i.bInterfaceSubClass); \pr_info("bInterfaceProtocol: 0x%x\n", i.bInterfaceProtocol); \pr_info("iInterface: 0x%x\n", i.iInterface);\pr_info("\n");\}struct usb_device *usb_dev;int endpoint_out_addr;int endpoint_in_addr;struct bulk_cs_wrap *bcs;struct bulk_cb_wrap *bcb;u8 *buffer;#define MAX_BYTES 1024static void readcmd(void) {int status;int actual_length = 0;bcb = kmalloc(sizeof(*bcb), GFP_KERNEL);memset(bcb, 0, sizeof(struct bulk_cb_wrap));bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);bcb->DataTransferLength = RETURN_DATA_LENGTH;bcb->Flags = US_BULK_FLAG_IN;bcb->Lun = 0;bcb->Length = 10;bcb->Tag = MYTAG;bcb->CDB[0] = READ_10;bcb->CDB[1] = 0x00;bcb->CDB[2] = MY_LBA & 0xff000000 >> 24;bcb->CDB[3] = MY_LBA & 0xff0000 >> 16;bcb->CDB[4] = MY_LBA & 0xff00 >> 8;bcb->CDB[5] = MY_LBA & 0xff;bcb->CDB[6] = 0x00;bcb->CDB[7] = 0x00;bcb->CDB[8] = REQUEST_BLOCK_NUMBER;bcb->CDB[9] = 0x00;buffer = kmalloc(MAX_BYTES, GFP_KERNEL);memset(buffer, 0, MAX_BYTES);status = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, endpoint_out_addr),bcb, US_BULK_CB_WRAP_LEN, &actual_length, 1000);if (status) {dev_info(&usb_dev->dev, "usb_bulk_msg fail ,status %d\n", status);return;}dev_info(&usb_dev->dev, "usb_bulk_msg success \n");dev_info(&usb_dev->dev, "actual_length = %d\n", actual_length);if (actual_length == US_BULK_CB_WRAP_LEN) {dev_info(&usb_dev->dev, "actual_length success");}dev_info(&usb_dev->dev, "start receive data from usb device\n");//read response from usb device;status = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, endpoint_in_addr),buffer, RETURN_DATA_LENGTH, &actual_length, 1000);if (status) {dev_info(&usb_dev->dev, "usb_bulk_msg fail ,status %d\n", status);return;}dev_info(&usb_dev->dev, "usb_bulk_msg success \n");dev_info(&usb_dev->dev, "actual_length = %d\n", actual_length);if (actual_length == 0) {dev_info(&usb_dev->dev, "no date received\n");return;}if (actual_length == 13) {dev_info(&usb_dev->dev, "only bcs received\n");bcs = (struct bulk_cs_wrap*) buffer;if (bcs->Status == 0) {dev_info(&usb_dev->dev, "bcs Status success\n");}dev_info(&usb_dev->dev, "bcs Tag 0x%x\n", bcs->Tag);dev_info(&usb_dev->dev, "bcs Residue %d\n", bcs->Residue);if (bcs->Tag == MYTAG) {dev_info(&usb_dev->dev, "bcs Tag success\n");} else {dev_info(&usb_dev->dev, "bcs Tag fail\n");}return;}if (actual_length != 13) {//response = (Response*) buffer;//totalsize = (response->total_size[0] << 24) |(response->total_size[1] << 16) | (response->total_size[2] << 8) | (response->total_size[3]);//dev_info(&usb_dev->dev, "totalsize = %d\n", totalsize);////blocksize = (response->block_size[0] << 24) |(response->block_size[1] << 16) | (response->block_size[2] << 8) | (response->block_size[3]);//dev_info(&usb_dev->dev, "block_size = %d\n", blocksize);//now read bcsbcs = kmalloc(sizeof(*bcs), GFP_ATOMIC);memset(bcs, 0, sizeof(struct bulk_cb_wrap));bcs->Status = 10; //just check to see if the result status will be changed to 0 by the usb device .status = usb_bulk_msg(usb_dev,usb_rcvbulkpipe(usb_dev, endpoint_in_addr), bcs,US_BULK_CS_WRAP_LEN, &actual_length, 50);if (status == 0) {dev_info(&usb_dev->dev, "actual_length2 %d\n", actual_length);dev_info(&usb_dev->dev, "bcs Status %d\n", bcs->Status);if (bcs->Status == 0) {dev_info(&usb_dev->dev, "bcs Status success\n");}dev_info(&usb_dev->dev, "bcs Tag 0x%x\n", bcs->Tag);if (bcs->Tag == MYTAG) {dev_info(&usb_dev->dev, "bcs Tag success\n");} else {dev_info(&usb_dev->dev, "bcs Tag fail\n");}}}}struct vdsk_dev {unsigned long size;u8 *data;spinlock_t lock;struct gendisk *mydisk;struct request_queue *queue;};struct vdsk_dev *dev;int myprobe(struct usb_interface *interface, const struct usb_device_id *id) {unsigned int i;unsigned int endpoints_count;int endpoint_type;int interfaceClass;int interfaceSubClass;int interfaceProtocol;struct usb_endpoint_descriptor endpoint_descriptor;struct usb_host_interface *iface_desc = interface->cur_altsetting;usb_dev = interface_to_usbdev(interface);dev_info(&interface->dev, "myprobe start\n");dev_info(&interface->dev, "idVendor = %x\n", id->idVendor);dev_info(&interface->dev, "idProduct = %x\n", id->idProduct);endpoints_count = iface_desc->desc.bNumEndpoints;dev_info(&interface->dev, "endpoints_count = %d\n", endpoints_count);interfaceClass = iface_desc->desc.bInterfaceClass;interfaceSubClass = iface_desc->desc.bInterfaceSubClass;interfaceProtocol = iface_desc->desc.bInterfaceProtocol;//dev_info(&interface->dev, "bInterfaceClass = 0x%x\n", interfaceClass);//dev_info(&interface->dev, "interfaceSubClass = 0x%x\n", interfaceSubClass);//dev_info(&interface->dev, "interfaceProtocol = 0x%x\n", interfaceProtocol);switch (interfaceClass) {case USB_CLASS_MASS_STORAGE:dev_info(&interface->dev, "interfaceClass: USB_CLASS_MASS_STORAGE\n");break;default:dev_info(&interface->dev, "never \n");break;}switch (interfaceSubClass) {case USB_SC_SCSI:dev_info(&interface->dev, "interfaceSubClass: USB_SC_SCSI\n");break;default:dev_info(&interface->dev, "never \n");break;}switch (interfaceProtocol) {case USB_PR_BULK:dev_info(&interface->dev, "interfaceProtocol: USB_PR_BULK\n");break;default:dev_info(&interface->dev, "never \n");break;}for (i = 0; i < endpoints_count; i++) {endpoint_descriptor = iface_desc->endpoint[i].desc;if (usb_endpoint_is_bulk_out(&endpoint_descriptor)) {endpoint_out_addr = endpoint_descriptor.bEndpointAddress;}if (usb_endpoint_is_bulk_in(&endpoint_descriptor)) {endpoint_in_addr = endpoint_descriptor.bEndpointAddress;}dev_info(&interface->dev, "endpoint %d bDescriptorType = %d\n", i,endpoint_descriptor.bDescriptorType);dev_info(&interface->dev, "endpoint %d bEndpointAddress = %d\n", i,endpoint_descriptor.bEndpointAddress);endpoint_type = endpoint_descriptor.bmAttributes& USB_ENDPOINT_XFERTYPE_MASK;switch (endpoint_type) {case USB_ENDPOINT_XFER_CONTROL:dev_info(&interface->dev, "control endpoint\n");break;case USB_ENDPOINT_XFER_ISOC:dev_info(&interface->dev, "ISOCHRONOUS endpoint\n");break;case USB_ENDPOINT_XFER_BULK:dev_info(&interface->dev, "bulk endpoint\n");break;case USB_ENDPOINT_XFER_INT:dev_info(&interface->dev, "Interrupt endpoint\n");break;default:dev_info(&interface->dev, "never \n");break;}}readcmd();dev_info(&interface->dev, "myprobe end\n");return 0;}void mydisconnect(struct usb_interface *intf) {dev_info(&intf->dev, "mydisconnect\n");kfree(bcs);kfree(bcb);kfree(buffer);}static struct usb_device_id my_id_table[] = {{USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE,USB_SC_SCSI, USB_PR_BULK) }, {} };//static struct usb_device_id my_id_table[] = { { USB_DEVICE(USB_VENDOR_ID,//USB_PRODUCT_ID) }, { } };MODULE_DEVICE_TABLE(usb, my_id_table);static struct usb_driver my_usbdriver = {.name = "andy_usbdriver", .probe =myprobe, .disconnect = mydisconnect, .id_table = my_id_table, };module_usb_driver( my_usbdriver);MODULE_LICENSE("GPL");MODULE_AUTHOR("Andy");

欢迎评论 。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。