主要参考了以下资料: usbmassbulk_10.pdf , usbmass-ufi10.pdf, SCSI Commands Reference Manual,spc-3.pdf

以下驱动模块通过usb接口发送 READ_CAPACITY 指令给U盘,然后读取U盘响应。

最终打印了block的总数以及一个block 的length。

要成功运行此模块,需要在内核中禁用 CONFIG_USB_STORAGE ,不然不会被USB设备匹配上。

内核版本 : 4.4.194 。

另外具体格式参考了 windows 下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** https://www.oreilly.com/library/view/linux-device-drivers/0596005903/ch13.html** https://www.kernel.org/doc/html/v4.12/driver-api/usb/writing_usb_driver.html** http://www.linux-usb.org/** https://embetronicx.com/tutorials/linux/device-drivers/usb-device-driver-basics/** https://github.com/Embetronicx/Tutorials/blob/master/Linux/Device_Driver/usb_device_driver/usb_driver.c** https://www.usb.org/sites/default/files/Mass_Storage_Specification_Overview_v1.4_2-19-2010.pdf** https://www.usb.org/sites/default/files/Mass_Storage_Specification_Overview_v1.4_2-19-2010.pdf** https://www.intel.com/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-usb.org/devices.html*** https://en.wikipedia.org/wiki/SCSI** https://en.wikipedia.org/wiki/SCSI_command*** https://www.t10.org/lists/2op.htm** https://wiki.osdev.org/USB_Mass_Storage_Class_Devices*** https://support.huawei.com/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 TestUnitReady#define Inquiry
#define  MYTAG  1333//#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 1024typedef struct {BYTE total_size[4];BYTE block_size[4];
} Response;static void sendcmd(void) {int status;int actual_length = 0;int totalsize;int blocksize;Response *response;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 = MAX_BYTES;bcb->Flags = US_BULK_FLAG_IN;bcb->Lun = 0;bcb->Length = 12;bcb->Tag = MYTAG;bcb->CDB[0] = READ_CAPACITY;bcb->CDB[1] = 0x00;bcb->CDB[2] = 0x00;bcb->CDB[3] = 0x00;bcb->CDB[4] = 0x00;bcb->CDB[5] = 0x00;bcb->CDB[6] = 0x00;bcb->CDB[7] = 0x00;bcb->CDB[8] = 0x00;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, MAX_BYTES, &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;}}sendcmd();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");

linux USB大容量设备驱动入门之读取U盘容量相关推荐

  1. hid设备驱动linux,linux usb hid设备驱动(3)

    本文分析了蓝牙bluez协议栈中HID协议的实现. 1. 基本概念 HID协议用于人机输入设备.Bluez中关于HID的实现代码在其根目录下的input目录.蓝牙规范中包含关于HID的profile, ...

  2. linux选择usb功能,USB gadget设备驱动解析(1)——功能体验

    利用Linux USB gadget设备驱动可以实现一些比较有意思的功能,举两个例子: 1.一个嵌入式产品中的某个存储设备,或是一个存储设备的某个分区,可以作为一个U盘被PC:设别,从而非常方便的完成 ...

  3. USB gadget设备驱动解析

    利用Linux USB gadget设备驱动可以实现一些比较有意思的功能,举两个例子: 1.一个嵌入式产品中的某个存储设备,或是一个存储设备的某个分区,可以作为一个U盘被PC:设别,从而非常方便的完成 ...

  4. 零基础学Linux内核之设备驱动篇(8)_设备模型

    零基础学Linux内核系列文章目录 前置知识篇 1. 进程 2. 线程 进程间通信篇 1. IPC概述 2. 信号 3. 消息传递 4. 同步 5. 共享内存区 编译相关篇 1. GCC编译 2. 静 ...

  5. Linux和Windows设备驱动架构比较

    毕业后一直在学操作系统, 有时候觉得什么都懂了,有时候又觉得好像什么都不懂,但总体来说自认为对操作系统实现机制的了解比周围的人还是要多一些.去年曾花了几个星期的晚上时间断断续续翻译了这篇对Linux和 ...

  6. Linux下LED设备驱动开发(LED灯实现闪烁)

    文章目录 一.配置连接说明 二.更新设备树 (1)将led灯引脚添加到pinctrl子系统 (2)设备树中添加LDE灯的设备树节点 (3)编译更新设备树 三.驱动开发与测试 (1)编写设备驱动代码 ( ...

  7. linux内核中kset是什么意思,Linux内核之设备驱动-底层数据结构kobject/kset

    Linux内核之设备驱动-底层数据结构kobject/kset kobject kobject是组成device.driver.bus.class的基本结构.如果把前者看成基类,则后者均为它的派生产物 ...

  8. usb audio设备驱动

    本文引用自ls.cq<usb audio设备驱动> http://bbs.driverdevelop.com/read.php?tid-118579-page-1.html 已基本完成wa ...

  9. Linux设备驱动入门----globalmem字符设备驱动

    1.什么是globalmem虚拟设备 (1).globalmem字符设备驱动中,分配一片内存大小为GLOBALMEM_SIZE(4K)的空间 (2).提供对该片内存的读写.控制和定位函数 (3).用户 ...

最新文章

  1. 面试必考-从URL输入到页面展现到底发生了什么
  2. 模板方法模式(TemplateMethod) 简介
  3. Redis-学习笔记01【Redis环境搭建】
  4. 从零开始入门 K8s:深入剖析 Linux 容器
  5. Angular开发模式下的编译器和运行时的代码比较
  6. Error:Internal error: org.gradle.tooling.BuildException: Could not run build action using Gradle dis
  7. LintCode MySQL 1928. 网课上课情况分析 I
  8. Intel Sandy Bridge/Ivy Bridge架构/微架构/流水线 (1) - 特性概述
  9. 浅谈前后端分离与实践 之 nodejs 中间层服务
  10. java socket 清理缓冲器_2021年Java全套面试题抢先看!中篇(更新中......)
  11. Fontmin字体生成,网站开发字体生成,@font-face字体格式生成,html网站字体引入,html网站字体格式转换器
  12. Makefile里的wildcard 理解
  13. 天津大学计算机学院杜朴风,PseAAC-Builder 2.0 一种从蛋白质序列数据快速生成伪氨基酸组分表示的软件.doc...
  14. ktt算法 约化_矩阵特征与特征向量的计算
  15. php图片生成邀请函,科学网—如何制作邀请函 - 樊晓英的博文
  16. Android 字体库的使用。引入外部字体
  17. [SOA介绍]什么是SOA?
  18. JAVA EE--13元老
  19. 线性代数几种特殊类型行列式_及其计算
  20. 信息安全国内测评认证标准

热门文章

  1. 用单链表的写一个通讯录管理系统
  2. 【Unity】Mod形式的Dll及AssetBundle外部加载插件
  3. 计算机专业 发展,计算机专业三年发展计划
  4. java相似度判断(余弦相似度)
  5. 【js】2019.2.19元宵 canvas实现上浮气球(花灯)(未完)
  6. 基于深度学习的花卉识别
  7. 我也读ADD的人生整理术
  8. 5个在线制作APP开发工具介绍和APP公司酷站欣赏
  9. 软件工程网络15个人阅读作业1(201521123010徐璐琳)
  10. CURSORINFO