Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux kernel 如何使用linux驱动程序读取/写入USB存储设备?_Linux Kernel_Usb_Driver_Dma - Fatal编程技术网

Linux kernel 如何使用linux驱动程序读取/写入USB存储设备?

Linux kernel 如何使用linux驱动程序读取/写入USB存储设备?,linux-kernel,usb,driver,dma,Linux Kernel,Usb,Driver,Dma,在尝试为usb闪存驱动器编写自己的简单usb驱动程序时,我在读取写入设备的数据时遇到了困难。 因此,我的第一个问题是: 设备上的传输和存储是如何进行的?(详细信息) 我知道我必须执行以下步骤: 创建urb(USB请求块) 分配DMA缓冲区 将数据从用户空间传输到DMA缓冲区 通过管道将数据发送到设备 我找不到任何关于设备如何处理这些数据的文档 是否可以编写这样的驱动程序,或者是否需要拆解usb设备来发送特殊命令? 我编写的代码看起来像下面的代码,来自ldd3和“”。它只显示重要功能的缩短版本

在尝试为usb闪存驱动器编写自己的简单usb驱动程序时,我在读取写入设备的数据时遇到了困难。 因此,我的第一个问题是:

设备上的传输和存储是如何进行的?(详细信息)

我知道我必须执行以下步骤:

  • 创建urb(USB请求块)
  • 分配DMA缓冲区
  • 将数据从用户空间传输到DMA缓冲区
  • 通过管道将数据发送到设备
我找不到任何关于设备如何处理这些数据的文档

是否可以编写这样的驱动程序,或者是否需要拆解usb设备来发送特殊命令?

我编写的代码看起来像下面的代码,来自ldd3和“”。它只显示重要功能的缩短版本

在将驱动程序加载到内核之后,我可以无错误地向设备写入,但如果读取,则会发生EPIPE错误。Ldd3提到usb_clear_halt()可以解决这个问题,但它没有

// This function is called when the device is plugged in
static int my_driver_probe(struct usb_interface* interface, const struct usb_device_id* id)
{
    struct usb_skel* dev = NULL;
    struct usb_device* udev = interface_to_usbdev(interface);
    struct usb_host_interface* iface_desc;
    struct usb_endpoint_descriptor* endpoint;
    int retval = -ENODEV;
    int i = 0;
    size_t buffer_size;

    dev = kzalloc(sizeof(struct usb_skel), GFP_KERNEL);

    // Check vendor and product id
    // … 

    dev->udev = udev;
    dev->interface = interface;

    // Set up the endpoint information
    iface_desc = interface->cur_altsetting;
    for(i=0; i < iface_desc->desc.bNumEndpoints; ++i) {
        endpoint = &iface_desc->endpoint[i].desc;

        if(!dev->bulk_in_endpointAddr && usb_endpoint_is_bulk_in(endpoint)) {
            buffer_size = endpoint->wMaxPacketSize;
            dev->bulk_in_size = buffer_size;
            dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
            dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
            if(!dev->bulk_in_buffer) {
                printk("Could not allocate bulk_in_buffer\n");
                goto error;
            }
            dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL);
        }
        if(!dev->bulk_out_endpointAddr && usb_endpoint_is_bulk_out(endpoint))
            dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
    }
    // Check that the endpoints are set
    // … 

    // Save our data pointer in this interface device
    usb_set_intfdata(interface, dev);

    // Register the device
    retval = usb_register_dev(interface, &class_descr);
    return retval;
}

// Is called when another program writes into /dev/my_usb_driver
static ssize_t my_driver_write( struct file* file, const char __user* user_buffer, size_t count, loff_t* offs)
{
    struct usb_skel* dev = file->private_data;
    struct urb* urb = NULL;
    char* buf = NULL;
    int retval = 0;
    size_t writesize = min(count, (size_t)MAX_TRANSFER);

    // Create a urb, and a buffer for it, and copy the data to the urb
    urb = usb_alloc_urb(0, GFP_KERNEL);

    // Creates a DMA buffer
    buf = usb_alloc_coherent(dev->udev, writesize, GFP_KERNEL, &urb->transfer_dma);

    // The data that is passed to the driver should be copied into the DMA buffer
    copy_from_user(buf, user_buffer, writesize;

    // Initialize the urb proberly
    usb_fill_bulk_urb(urb, dev->udev, 
                  usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
                  buf, writesize, (void*)my_write_bulk_callback, dev);

    // Send the data out the bulk port
    urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

    usb_submit_urb(urb, GFP_KERNEL);

    return writesize; 
}

// Is called when another program reads from /dev/my_usb_driver
static ssize_t my_driver_read( struct file *file, char* buffer, size_t count, loff_t* offs) 
{
    struct usb_skel* dev = file->private_data;
    int retval = 0;

    // Check that we have data to read
    // … 

    usb_fill_bulk_urb(dev->bulk_in_urb, dev->udev, 
                  usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
                  dev->bulk_in_buffer, 
                  min(dev->bulk_in_size, count), read_bulk_callback, dev);  

    retval = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL);

    // If the read was succesful, copy the data to user space
    copy_to_user(buffer, dev->bulk_in_buffer, count);

    return retval;
}
//插入设备时调用此函数
静态int my_驱动程序_探测器(结构usb_接口*接口,常量结构usb_设备_id*id)
{
结构usb_skel*dev=NULL;
结构usb_设备*udev=接口U至usbdev(接口);
结构usb_主机_接口*iface_desc;
结构usb_端点_描述符*端点;
int retval=-ENODEV;
int i=0;
大小\u t缓冲区\u大小;
dev=kzalloc(sizeof(struct usb_skel),GFP_内核);
//检查供应商和产品id
// … 
dev->udev=udev;
开发->接口=接口;
//设置端点信息
iface\u desc=接口->当前设置;
对于(i=0;idesc.bNumEndpoints;++i){
端点=&iface\u desc->endpoint[i].desc;
如果(!dev->bulk_in_endpointAddr&&usb_endpoint_是_bulk_in(endpoint)){
缓冲区大小=端点->wMaxPacketSize;
dev->bulk\u in\u size=缓冲区大小;
dev->bulk\u in\u endpointAddr=endpoint->bEndpointAddress;
dev->bulk\u in\u buffer=kmalloc(缓冲区大小,GFP\u内核);
如果(!dev->bulk\u在\u缓冲区中){
printk(“无法在缓冲区中分配批量\n”);
转到错误;
}
dev->bulk\u in\u urb=usb\u alloc\u urb(0,GFP\u内核);
}
如果(!dev->bulk_out_endpointAddr&&usb_endpoint_是_bulk_out(endpoint))
dev->bulk\u out\u endpointAddr=endpoint->bEndpointAddress;
}
//检查端点是否已设置
// … 
//将数据指针保存在此接口设备中
usb设置接口数据(接口,开发);
//注册设备
retval=usb寄存器开发(接口和类描述);
返回返回;
}
//当另一个程序写入/dev/my_usb_驱动程序时调用
静态ssize\u t my\u driver\u write(结构文件*文件、常量字符*用户*用户缓冲区、大小\u t计数、loff\u t*offs)
{
结构usb_skel*dev=file->private_数据;
结构urb*urb=NULL;
char*buf=NULL;
int-retval=0;
大小写入大小=最小(计数,(大小写入)最大传输);
//创建urb及其缓冲区,并将数据复制到urb
urb=usb_alloc_urb(0,GFP_内核);
//创建DMA缓冲区
buf=usb分配一致性(开发->udev,写化,GFP内核,&urb->传输dma);
//传递给驱动程序的数据应复制到DMA缓冲区中
从用户复制用户(buf、用户缓冲区、写大小;
//可能会初始化urb
usb_-fill_-bulk_-urb(urb,dev->udev,
usb_sndbulkpipe(dev->udev,dev->bulk_out_endpointAddr),
buf,writesize,(void*)我的写批量回调,dev);
//将数据发送到大容量端口
urb->transfer_flags |=urb_NO_transfer_DMA_MAP;
usb_提交_urb(urb,GFP_内核);
返回writesize;
}
//当另一个程序读取/dev/my_usb_驱动程序时调用
静态ssize\u t my\u driver\u read(结构文件*文件,字符*缓冲区,大小计数,loff\u t*关闭)
{
结构usb_skel*dev=file->private_数据;
int-retval=0;
//检查我们是否有要读取的数据
// … 
usb填充块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块块,
usb_rcvbulkpipe(dev->udev,dev->bulk_in_endpointAddr),
开发->批量存储在缓冲区中,
min(dev->bulk\u in\u size,count),read\u bulk\u回调,dev);
retval=usb_submit_urb(dev->bulk_-in_urb,GFP_内核);
//如果读取成功,请将数据复制到用户空间
复制到用户(buffer,dev->bulk\u in\u buffer,count);
返回返回;
}

USB只是一个传输层。存储设备通常实现SCSI协议。创建一个SCSI命令,用于读取或写入用户空间发送的数据。然后为SCSI命令创建URB并将其发送到USB设备

SCSI是一个庞大的协议,为了学习USB设备驱动程序的开发,最好从简单的设备(如USB到串行设备)开始