В настоящее время я пишу Linux USB-драйвер для микрофона, и я ориентируюсь на этот драйвер скелета: https://elixir.bootlin.com/linux/latest/source/drivers/usb/usb-skeleton.c
Для целей тестирования он настроен как символьный драйвер, так что я могу заполнить буфер в функции чтения вручную и прочитать его в приложении пространства пользователя. К сожалению, вызов
interface = usb_find_interface(&mic_driver, subminor);
в моей открытой функции приводит к NULL Pointer для интерфейса. Таким образом, интерфейс не найден. Я дважды проверил идентификаторы поставщиков и продуктов для моего микрофона с помощью «lsusb». Я был бы рад, если бы кто-нибудь мог указать мне на то, что мне не хватает.
#include <linux/kernel.h>
#include <linux/slab.h> // kmalloc
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/tty.h>
#include <linux/sched.h>
#include <linux/fs.h> // File S
#include <asm/uaccess.h> //copy_to_user
#include <linux/init.h>
#include <linux/cdev.h>
#define USB_VENDOR_ID 0x8086
#define USB_PRODUCT_ID 0x0808
static char *mes = "Driver works as intended";
static char *mp;
static const struct usb_device_id mic_table[] = {
{ USB_DEVICE(USB_VENDOR_ID, USB_PRODUCT_ID) },
{ }
};
MODULE_DEVICE_TABLE (usb, mic_table); //usb is just a type
struct usb_all {
struct usb_device *udev; //device
struct usb_interface *interface; //neccessary interface
struct urb *in_urb;
};
static struct tty_struct *my_tty;
static int use_count;
static struct usb_driver mic_driver;
static char device_name[] = "MicDriver";
int device_open (struct inode *inode, struct file *file) {
struct usb_all *dev;
struct usb_interface *interface;
int subminor;
subminor = iminor(inode);
mp = mes; // For character test
printk(KERN_INFO "Subminor: %i \n", subminor);
printk(KERN_INFO "Address: %i \n", &mic_driver);
if (&mic_driver == NULL) { printk(KERN_INFO "Mic Driver NULL"); }
interface = usb_find_interface(&mic_driver, subminor);
if (interface == NULL) {
printk(KERN_INFO "No interface found in open function\n");
goto exit;
}
dev = usb_get_intfdata(interface);
file->private_data = dev;
exit:
return 0;
};
static int mic_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
printk(KERN_INFO "USB Microphone connected \n");
struct usb_all *dev;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (interface == NULL) {
printk(KERN_INFO "No interface in probe function \n");
goto exit;
}
if(dev == NULL) {
printk(KERN_INFO "No struct usb_all in probe function \n");
goto exit;
}
dev->udev = usb_get_dev(interface_to_usbdev(interface)); //usb_dev from interface
dev->interface = usb_get_intf(interface);
usb_set_intfdata(interface, dev); // link to open
exit:
return 0;
};
static void mic_disconnect(struct usb_interface *interface) {
printk(KERN_INFO "USB Microphone disconnected \n");
};
//read, open, release // ssize_t ist signed size of allocated memory
ssize_t device_read (struct file *file, char *buffer, size_t len, loff_t *offs) {
struct urb *urb1;
struct usb_all *dev;
int reval = 0;
/*
dev = file->private_data;
urb1 = usb_alloc_urb(1, GFP_KERNEL); //Isopackages, mem_flag
if (urb1 == NULL) {
return -EAGAIN;
};
*/
reval = copy_to_user(buffer, mp, 16);
mp += 16;
return reval;
};
void device_release (struct inode *inode, struct file *file) {
struct usb_all *dev;
dev = file->private_data;
if (dev != NULL) {
usb_put_intf(dev->interface);
usb_put_dev(dev->udev);
kfree(dev);
}
};
int completion_handler(struct urb *urb) {
if (urb != NULL) {
usb_free_coherent(urb->dev, urb->transfer_buffer_length,urb->transfer_buffer, urb->transfer_dma);
usb_free_urb(urb);
}
return 0;
};
static struct file_operations fops = {
read: device_read,
open: device_open,
release: device_release,
owner: THIS_MODULE
};
static struct usb_driver mic_driver =
{
.name = "MicDriver",
.id_table = mic_table, // Type usb_device_id
.probe = mic_probe,
.disconnect = mic_disconnect,
};
static dev_t dev2; // Major und minor
static struct cdev *my_cdev; // Character device
int mic_init(void) {
int ret = 0;
char message[64];
ret = alloc_chrdev_region(&dev2, 0, 1, device_name);
if (ret < 0 ) { return -1;}
my_cdev = cdev_alloc();
my_cdev->ops = &fops;
my_cdev->owner = THIS_MODULE;
ret = cdev_add(my_cdev, dev2, 1);
if (ret < 0 ) {
unregister_chrdev_region(dev2, 1);
return -1;
}
ret = usb_register(&mic_driver);
my_tty = get_current_tty();
if (my_tty == NULL) return -ENOTTY;
sprintf(message, "USB Driver created \r\n");
(my_tty->ops->write)
(my_tty, message, strlen(message));
printk(KERN_INFO "Init okay");
return ret;
}
void mic_exit(void) {
char message[64];
usb_deregister(&mic_driver);
sprintf(message, "USB Driver removed \r\n");
(my_tty->ops->write)
(my_tty, message, strlen(message));
cdev_del(my_cdev);
unregister_chrdev_region(dev2, 1);
}
MODULE_LICENSE("GPL v2");
module_init(mic_init);
module_exit(mic_exit);