【发布时间】:2022-09-18 20:46:28
【问题描述】:
精简版
我想为自定义 USB 设备编写 Linux 驱动程序。在编写驱动程序之前,我使用 libusb-1.0 来测试设备。通过以下函数调用,我可以从设备中读取 uin16_t 值:
status = libusb_control_transfer(handle, /* Device Handle */
0x80, /* bRequestType */
0x10, /* bRequest */
value, /* wValue */
0x0, /* wIndex */
((uint8_t *) &value), /* data */
2, /* wLength */
100); /* timeout */
在这个调用之后,我在 value 变量中得到了一个新值。
现在我想在我的驱动程序中完成相同的调用。我在我的 USB 驱动程序的探测功能中尝试了以下内容:
status = usb_control_msg(data->udev, usb_rcvctrlpipe(data->udev, 0), 0x10, USB_DIR_IN, 0, 0, (u8*) &my_data, 2, 100);
我得到的只是返回值 -11,在我的设备上我什么也看不到。
在这次通话之前我唯一要做的就是调用data->udev = interface_to_usbdev(intf); 从我的接口获取 USB 设备。
有谁知道,如果我错过了什么或者我做错了什么?
长版
我想学习如何在 Linux 中编写 USB 驱动程序。作为我可以为其编写驱动程序的 DUT,我选择了 Raspberry Pi Pico 和 dev_lowlevel USB example。我稍微修改了代码,所以我可以使用 bRequest 0x10 和 bRequestType 0x0 (USB_DIR_OUT) 的控制传输来打开或关闭 Pico 的板载 LED,并使用 bRequest 0x10 和 bRequestType 0x80 (USB_DIR_IN) 的控制传输来回读LED 的电流值。
使用用户空间程序和以下代码,我可以读出 LED 的值并将其打开或关闭:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <libusb-1.0/libusb.h>
#define VID 0x0000
#define DID 0x0001
int main(int argc, char **argv) {
int status, len;
libusb_device_handle *handle = NULL;
/* Init Libusb */
status = libusb_init(NULL);
if(status < 0) {
printf("Error init USB!\n");
return status;
}
handle = libusb_open_device_with_vid_pid(NULL, VID, DID);
if(!handle) {
printf("No device found with %04x:%04x\n", VID, DID);
libusb_exit(NULL);
return -1;
}
if(argc > 1)
value = atoi(argv[1]);
else {
/* Do control transfer */
status = libusb_control_transfer(handle, /* Device Handle */
0x80, /* bRequestType */
0x10, /* bRequest */
value, /* wValue */
0x0, /* wIndex */
((uint8_t *) &value), /* data */
2, /* wLength */
100); /* timeout */
if(status < 0) {
printf("Error during control transfer!\n");
libusb_close(handle);
libusb_exit(NULL);
return -1;
}
printf("Got: %d\n", value);
value = (value + 1) & 0x1;
}
/* Do control transfer */
status = libusb_control_transfer(handle, 0x0, 0x10, value, 0x0, NULL, 0, 100);
if(status < 0) {
printf("Error during control transfer!\n");
libusb_close(handle);
libusb_exit(NULL);
return -1;
}
libusb_close(handle);
libusb_exit(NULL);
return 0;
}
现在我想通过 USB 驱动程序控制我的设备。这是我已经得到的:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb.h>
#include <linux/slab.h>
/* Meta Information */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Johannes 4 GNU/Linux");
MODULE_DESCRIPTION("Driver for my custom RPi Pico USB device");
struct pico_usb {
struct usb_device *udev;
};
#define PICO_VID 0x0000
#define PICO_PID 0x0001
static struct usb_device_id pico_usb_table [] = {
{ USB_DEVICE(PICO_VID, PICO_PID) },
{},
};
MODULE_DEVICE_TABLE(usb, pico_usb_table);
static int pico_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) {
struct pico_usb *data;
int status;
int my_data;
printk("pico_usb_drv - Now I am in the Probe function!\n");
data = kzalloc(sizeof(struct pico_usb), GFP_KERNEL);
if(!data) {
printk("pico_usb_drv - Out of memory\n");
return -ENOMEM;
}
data->udev = interface_to_usbdev(intf);
usb_set_intfdata(intf, data);
/* Turn the LED on */
status = usb_control_msg(data->udev, usb_sndctrlpipe(data->udev, 0), 0x10, USB_DIR_OUT, 1, 0, 0, 0, 100);
/* Read LED state */
printk("pico_usb_drv - status USB_DIR_OUT: %d\n", status);
status = usb_control_msg(data->udev, usb_rcvctrlpipe(data->udev, 0), 0x10, USB_DIR_IN, 0, 0, (u8*) &my_data, 2, 100);
printk("pico_usb_drv - status USB_DIR_IN: %d\n", status);
return 0;
}
static void pico_usb_disconnect(struct usb_interface *intf) {
struct pico_usb *data;
printk("pico_usb_drv - Now I am in the Disconnect function!\n");
data = usb_get_intfdata(intf);
kfree(data);
}
static struct usb_driver pico_usb_driver = {
//.owner = THIS_MODULE,
.name = "pico_usb",
.id_table = pico_usb_table,
.probe = pico_usb_probe,
.disconnect = pico_usb_disconnect,
};
/**
* @brief This function is called, when the module is loaded into the kernel
*/
static int __init pico_usb_init(void) {
int result;
printk("pico_usb_drv - Registering the PICO USB device\n");
result = usb_register(&pico_usb_driver);
if(result) {
printk("pico_usb_drv - Error registering the PICO USB device\n");
return -result;
}
return 0;
}
/**
* @brief This function is called, when the module is removed from the kernel
*/
static void __exit pcio_usb_exit(void) {
printk("pico_usb_drv - Unregistering the PICO USB device\n");
usb_deregister(&pico_usb_driver);
}
module_init(pico_usb_init);
module_exit(pcio_usb_exit);
第一条控制消息有效,我的 LED 已打开。但是第二条控制消息没有做任何事情,而是给了我错误代码-11。
有谁知道,如果我错过了什么或者我做错了什么?
【问题讨论】:
-
您要求 0 毫秒超时。 -11 是 -EAGAIN 意味着它没有在超时内完成。您的 libusb 版本要求 100 毫秒。
-
谢谢,我在驱动程序中将超时更改为 100 毫秒,但我仍然收到 -11 -EAGAIN 错误代码。
-
第二条控制消息从您的设备读取数据。如果您的设备在 100 毫秒内没有发送任何内容,则 usb_control_msg 返回错误
-
但是我必须向设备发送什么来触发设备向我发送数据?我的意思是,在用户空间示例中,我可以触发设备向我发送数据,但是如何在内核空间中执行此操作?
标签: c linux linux-kernel linux-device-driver libusb