gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-04 05:27:50 24 4
gpt4 key购买 nike

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

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

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

  • 创建一个 urb(USB 请求 block )
  • 分配一个 DMA 缓冲区
  • 将数据从用户空间传输到 DMA 缓冲区
  • 通过管道将数据发送到设备

我找不到任何关于设备如何处理这些数据的文档。

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

我编写的代码类似于以下内容,来自 ldd3 和“http://lxr.free-electrons.com/source/drivers/usb/usb-skeleton.c”。它仅显示重要功能的简化版本。

将驱动程序加载到内核后,我可以毫无错误地写入设备,但如果我读取,则会出现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;
}

最佳答案

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

SCSI 是一个庞大的协议(protocol),对于学习 USB 设备驱动程序开发,最好从简单的设备开始,例如 USB 转串口设备。

关于linux-kernel - 如何使用 linux 驱动程序读取/写入 USB 存储设备?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37899193/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com