我正在学习Linux设备驱动程序编程 - 特别是USB驱动程序。 USB驱动程序的所有教程都需要usbfs,它已在较新的内核中被禁用。解决方案,我希望有人在这里向我证实,是在启用usbfs的情况下构建内核。
首先,我正在寻找原因 - 为什么usbfs被禁用了?其中一个人模糊地提到了udev的一些问题。
其次,有没有办法在没有usbfs的情况下编写驱动程序?如果它被禁用,开发人员会提供一些替代方案(这是我猜测)。
继承我的代码......
ddk.h
#ifndef DDK_H
#define DDK_H
#ifdef __KERNEL__
#include <linux/usb.h>
#define DDK_VENDOR_ID 0x16c0
#define DDK_PRODUCT_ID 0x05dc
#define ENABLE_FILE_OPS
//#define ENABLE_USB_DEV // TODO: Debug enabling this
/* Crashing possibly because udev is doing something on its vendor, device id match */
#define CUSTOM_RQ_SET_LED_STATUS 1
#define CUSTOM_RQ_GET_LED_STATUS 2
#define CUSTOM_RQ_SET_MEM_RD_OFFSET 3
#define CUSTOM_RQ_GET_MEM_RD_OFFSET 4
#define CUSTOM_RQ_SET_MEM_WR_OFFSET 5
#define CUSTOM_RQ_GET_MEM_WR_OFFSET 6
#define CUSTOM_RQ_GET_MEM_SIZE 7
#define MAX_ENDPOINTS 4
#define MEM_EP_IN (USB_DIR_IN | 0x01)
#define MEM_EP_OUT 0x01
#define SER_EP_IN (USB_DIR_IN | 0x02)
#define SER_EP_OUT 0x02
#endif
#endif
ddk_led.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/usb.h>
#include <linux/errno.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include "ddk_led.h"
static struct ddk_device ddk_dev; // Need to be persistent
#ifdef ENABLE_FILE_OPS
static dev_t dev;
static struct cdev c_dev;
static struct class *cl;
static int ddk_open(struct inode *i, struct file *f)
{
return 0;
}
static int ddk_close(struct inode *i, struct file *f)
{
return 0;
}
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35))
static int ddk_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg)
#else
static long ddk_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
#endif
{
char buf;
int val;
int retval;
switch (cmd)
{
case DDK_LED_GET:
/* Control IN */
retval = usb_control_msg(ddk_dev.device, usb_rcvctrlpipe(ddk_dev.device, 0),
CUSTOM_RQ_GET_LED_STATUS, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, 0, &buf, sizeof(buf), 0);
if (retval < 0)
{
printk(KERN_ERR "Control message returned %d\n", retval);
return retval;
}
val = buf;
if (copy_to_user((int *)arg, &val, sizeof(int)))
{
return -EFAULT;
}
break;
case DDK_LED_SET:
/* Control OUT */
val = arg;
retval = usb_control_msg(ddk_dev.device, usb_sndctrlpipe(ddk_dev.device, 0),
CUSTOM_RQ_SET_LED_STATUS, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
val, 0, NULL, 0, 0);
if (retval < 0)
{
printk(KERN_ERR "Control message returned %d\n", retval);
return retval;
}
break;
default:
return -EINVAL;
break;
}
return 0;
}
static struct file_operations fops =
{
.open = ddk_open,
.release = ddk_close,
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35))
.ioctl = ddk_ioctl,
#else
.unlocked_ioctl = ddk_ioctl,
#endif
};
static int char_register_dev(struct usb_interface *interface, struct usb_class_driver *class)
{
int ret;
struct device *dev_ret;
if ((ret = alloc_chrdev_region(&dev, 0, 1, "ddk_led")) < 0)
{
printk(KERN_INFO "Error retrieving MAj Min numbers\n");
return ret;
}
printk(KERN_INFO "(Major, Minor): (%d, %d)\n", MAJOR(dev), MINOR(dev));
interface->minor = MINOR(dev);
cdev_init(&c_dev, class->fops);
if ((ret = cdev_add(&c_dev, dev, 1)) < 0)
{
return ret;
}
if (IS_ERR(cl = class_create(THIS_MODULE, "usb")))
{
cdev_del(&c_dev);
unregister_chrdev_region(dev, 1);
return PTR_ERR(cl);
}
if (IS_ERR(dev_ret = device_create(cl, NULL, dev, NULL, class->name, 0)))
{
class_destroy(cl);
cdev_del(&c_dev);
unregister_chrdev_region(dev, 1);
return PTR_ERR(dev_ret);
}
return 0;
}
static void char_deregister_dev(struct usb_interface *interface, struct usb_class_driver *class)
{
device_destroy(cl, dev);
class_destroy(cl);
cdev_del(&c_dev);
unregister_chrdev_region(dev, 1);
}
#endif
static int ddk_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
int i;
int retval;
iface_desc = interface->cur_altsetting;
printk(KERN_INFO "DDK USB i/f %d now probed: (%04X:%04X)\n",
iface_desc->desc.bInterfaceNumber, id->idVendor, id->idProduct);
printk(KERN_INFO "ID->bNumEndpoints: %02X\n", iface_desc->desc.bNumEndpoints);
printk(KERN_INFO "ID->bInterfaceClass: %02X\n", iface_desc->desc.bInterfaceClass);
/* Set up the endpoint information. Assuming there is 1 in & 1 out */
memset(&ddk_dev, 0, sizeof(ddk_dev));
for (i = 0; i < iface_desc->desc.bNumEndpoints; i++)
{
endpoint = &iface_desc->endpoint[i].desc;
printk(KERN_INFO "ED[%d]->bEndpointAddress: 0x%02X\n", i, endpoint->bEndpointAddress);
printk(KERN_INFO "ED[%d]->bmAttributes: 0x%02X\n", i, endpoint->bmAttributes);
printk(KERN_INFO "ED[%d]->wMaxPacketSize: 0x%04X (%d)\n", i, endpoint->wMaxPacketSize, endpoint->wMaxPacketSize);
}
ddk_dev.device = interface_to_usbdev(interface);
#ifdef ENABLE_FILE_OPS
ddk_dev.class.name = "usb/ddk_led%d";
ddk_dev.class.fops = &fops;
retval = char_register_dev(interface, &ddk_dev.class);
if (retval)
{
/* Something prevented us from registering this driver */
printk(KERN_ERR "Not able to get a minor for this device.\n");
return retval;
}
else
{
printk(KERN_INFO "Minor obtained: %d\n", interface->minor);
}
#else
interface->minor = iface_desc->desc.bInterfaceNumber;
#endif
return 0;
}
static void ddk_disconnect(struct usb_interface *interface)
{
printk(KERN_INFO "Releasing Minor: %d\n", interface->minor);
#ifdef ENABLE_FILE_OPS
/* Give back our minor */
char_deregister_dev(interface, &ddk_dev.class);
#endif
printk(KERN_INFO "DDK USB i/f %d now disconnected\n",
interface->cur_altsetting->desc.bInterfaceNumber);
}
/* Table of devices that work with this driver */
static struct usb_device_id ddk_table[] =
{
{
USB_DEVICE(DDK_VENDOR_ID, DDK_PRODUCT_ID)
},
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, ddk_table);
static struct usb_driver ddk_driver =
{
.name = "ddk_led",
.probe = ddk_probe,
.disconnect = ddk_disconnect,
.id_table = ddk_table,
};
static int __init ddk_init(void)
{
int result;
/* Register this driver with the USB subsystem */
if ((result = usb_register(&ddk_driver)))
{
printk(KERN_ERR "usb_register failed. Error number %d\n", result);
}
printk(KERN_INFO "DDK usb_registered\n");
return result;
}
static void __exit ddk_exit(void)
{
/* Deregister this driver with the USB subsystem */
usb_deregister(&ddk_driver);
printk(KERN_INFO "DDK usb_deregistered\n");
}
module_init(ddk_init);
module_exit(ddk_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Anil Kumar Pugalia <email@sarika-pugs.com>");
MODULE_DESCRIPTION("USB LED Device Driver for DDK v1.1");
ddk_led.h
#ifndef DDK_LED_H
#define DDK_LED_H
#include <linux/ioctl.h>
#ifdef __KERNEL__
#include "ddk.h"
struct ddk_device
{
struct usb_device *device;
struct usb_class_driver class;
};
#endif
#define DDK_LED_GET _IOR('u', 1, int *)
#define DDK_LED_SET _IOW('u', 2, int)
#endif
代码用于操纵LDDK套件上的LED - 基于AVR的电路板。 它无法在/ dev / usb /中创建设备文件(首先没有名为usb的目录!)
赞赏一些阅读材料的链接。谢谢。
答案 0 :(得分:1)
答案 1 :(得分:1)
关于你的第二个问题 - linux usb驱动程序最重要的部分(最低级别)是用内核空间而不是用户空间编写的。在内核空间中,软件直接与硬件对话。
Usbfs只是用户空间程序/库(如libusb)的某种接口。