Linux USB设备驱动

  • 二十、Linux USB设备驱动
    • 20.1 USB简介
    • 20.1.1 USB2.0总线拓扑
    • 20.1.2 USB总线枚举和设备布局
    • 20.1.3 USB数据传输
    • 20.1.4 USB设备类别
    • 20.1.5 USB描述符
    • 20.2 Linux USB 子系统
    • 20.3 编写Linux USB设备驱动程序
      • 20.3.1 注册设备驱动
      • 20.3.2 Linux 主机端数据类型
      • 20.3.3 USB请求块
    • 20.4 USB LED模块
    • 20.4 USB LED驱动代码
    • 20.5 USB LED 和开关模块
      • 20.5.1 代码
    • 20.6 连接到USB多显LED的I2C模块
      • 20.6.1 简介
      • 20.6.2 代码

二十、Linux USB设备驱动

20.1 USB简介

USB(通用串行总线)最早的USB总线速率包括低速(1.5Mbps)、高速(480Mbps),USB 3.0规范出现后,速率达到4.8Gbps。USB最大优点是它支持动态连接和移除,一种称”即插即用“的接口。

20.1.1 USB2.0总线拓扑

20.1.2 USB总线枚举和设备布局

USB主机控制轮询总线,其中所有十五均由USB主机发起。
端点、描述符。

20.1.3 USB数据传输

一旦枚举完成,主机和设备就可以自由地进行通信。

四种不同类型的传输:
控制传输;
批量数据传输;
中断数据传输;
等时数据传输;

20.1.4 USB设备类别

常见的有HID、打印机、成像设备、大容量存储设备和通信设备。

20.1.5 USB描述符

设备描述符
配置描述符
接口描述符
端点描述符

20.2 Linux USB 子系统

Linux USB是一类特定API实现,用于支持USB外设和主机控制器。
Linux USB API支持对控制消息和批量消息的同步调用。

20.3 编写Linux USB设备驱动程序

20.3.1 注册设备驱动

注册USB设备驱动程序,usb_driver结构体定义在,如下:

/linux/driver/misc/usbsevseg.c

20.3.2 Linux 主机端数据类型

USB设备驱动程序实际上绑定到接口,而不是绑定到设备。

20.3.3 USB请求块

20.4 USB LED模块

USB HID设备固件,该设备能够使用HID报告来发送和接收数据。

20.4 USB LED驱动代码


#include <linux/slab.h>
#include <linux/module.h>
#include <linux/usb.h>//创建ID表示支持热插拔
#define USBLED_VENDOR_ID    0x04D8
#define USBLED_PRODUCT_ID   0x003F  /* table of devices that work with this driver */
static const struct usb_device_id id_table[] = {{ USB_DEVICE(USBLED_VENDOR_ID, USBLED_PRODUCT_ID) },{ }
};
MODULE_DEVICE_TABLE(usb, id_table);//创建一个结构来存储驱动程序数据
struct usb_led {struct usb_device *udev;u8 led_number;
};static ssize_t led_show(struct device *dev, struct device_attribute *attr,char *buf)
{struct usb_interface *intf = to_usb_interface(dev);struct usb_led *led = usb_get_intfdata(intf);         return sprintf(buf, "%d\n", led->led_number);
}static ssize_t led_store(struct device *dev, struct device_attribute *attr,const char *buf, size_t count)
{struct usb_interface *intf = to_usb_interface(dev);struct usb_led *led = usb_get_intfdata(intf);u8 val;int error, retval;dev_info(&intf->dev, "led_store() function is called.\n");/* transform char array to u8 value */error = kstrtou8(buf, 10, &val);if (error)return error;led->led_number = val;if (val == 1 || val == 2 || val == 3)dev_info(&led->udev->dev, "led = %d\n", led->led_number);else {dev_info(&led->udev->dev, "unknown led %d\n", led->led_number);retval = -EINVAL;return retval;}/* Toggle led */retval = usb_bulk_msg(led->udev, usb_sndctrlpipe(led->udev, 1),&led->led_number, 1,NULL, 0);if (retval) {retval = -EFAULT;return retval;}return count;
}
static DEVICE_ATTR_RW(led);static int led_probe(struct usb_interface *interface,const struct usb_device_id *id)
{struct usb_device *udev = interface_to_usbdev(interface);struct usb_led *dev = NULL;int retval = -ENOMEM;dev_info(&interface->dev, "led_probe() function is called.\n");dev = kzalloc(sizeof(struct usb_led), GFP_KERNEL);if (!dev) {dev_err(&interface->dev, "out of memory\n");retval = -ENOMEM;goto error;}dev->udev = usb_get_dev(udev);usb_set_intfdata(interface, dev);retval = device_create_file(&interface->dev, &dev_attr_led);if (retval)goto error_create_file;return 0;error_create_file:usb_put_dev(udev);usb_set_intfdata(interface, NULL);
error:kfree(dev);return retval;
}static void led_disconnect(struct usb_interface *interface)
{struct usb_led *dev;dev = usb_get_intfdata(interface);device_remove_file(&interface->dev, &dev_attr_led);usb_set_intfdata(interface, NULL);usb_put_dev(dev->udev);kfree(dev);dev_info(&interface->dev, "USB LED now disconnected\n");
}static struct usb_driver led_driver = {.name =       "usbled",.probe =    led_probe,.disconnect =    led_disconnect,.id_table = id_table,
};//将驱动注册到USB总线
module_usb_driver(led_driver);MODULE_LICENSE("GPL");
MODULE_AUTHOR(" ");
MODULE_DESCRIPTION("This is a synchronous led usb controlled module");

20.5 USB LED 和开关模块

20.5.1 代码

#include <linux/slab.h>
#include <linux/module.h>
#include <linux/usb.h>#define USBLED_VENDOR_ID    0x04D8
#define USBLED_PRODUCT_ID   0x003F  static void led_urb_out_callback(struct urb *urb);
static void led_urb_in_callback(struct urb *urb);/* table of devices that work with this driver */
static const struct usb_device_id id_table[] = {{ USB_DEVICE(USBLED_VENDOR_ID, USBLED_PRODUCT_ID) },{ }
};
MODULE_DEVICE_TABLE(usb, id_table);struct usb_led {struct usb_device *udev;struct usb_interface *intf;struct urb      *interrupt_out_urb;struct urb       *interrupt_in_urb;struct usb_endpoint_descriptor *interrupt_out_endpoint;struct usb_endpoint_descriptor *interrupt_in_endpoint;u8       irq_data;u8         led_number;u8           ibuffer;int         interrupt_out_interval;int ep_in;int ep_out;
};static ssize_t led_show(struct device *dev, struct device_attribute *attr,char *buf)
{struct usb_interface *intf = to_usb_interface(dev);struct usb_led *led = usb_get_intfdata(intf);         \\return sprintf(buf, "%d\n", led->led_number);
}static ssize_t led_store(struct device *dev, struct device_attribute *attr,const char *buf, size_t count)
{/* interface: related set of endpoints which present a single feature or function to the host */struct usb_interface *intf = to_usb_interface(dev);struct usb_led *led = usb_get_intfdata(intf);u8 val;int error, retval;dev_info(&intf->dev, "led_store() function is called.\n");/* transform char array to u8 value */error = kstrtou8(buf, 10, &val);if (error)return error;led->led_number = val;led->irq_data = val;if (val == 0)dev_info(&led->udev->dev, "read status\n");else if (val == 1 || val == 2 || val == 3)dev_info(&led->udev->dev, "led = %d\n", led->led_number);else {dev_info(&led->udev->dev, "unknown value %d\n", val);retval = -EINVAL;return retval;}/* send the data out */retval = usb_submit_urb(led->interrupt_out_urb, GFP_KERNEL);if (retval) {dev_err(&led->udev->dev,"Couldn't submit interrupt_out_urb %d\n", retval);return retval;}return count;
}
static DEVICE_ATTR_RW(led);static void led_urb_out_callback(struct urb *urb)
{struct usb_led *dev;dev = urb->context;dev_info(&dev->udev->dev, "led_urb_out_callback() function is called.\n");/* sync/async unlink faults aren't errors */if (urb->status) {if (!(urb->status == -ENOENT ||urb->status == -ECONNRESET ||urb->status == -ESHUTDOWN))dev_err(&dev->udev->dev,"%s - nonzero write status received: %d\n",__func__, urb->status);}
}static void led_urb_in_callback(struct urb *urb)
{int retval;struct usb_led *dev;dev = urb->context;dev_info(&dev->udev->dev, "led_urb_in_callback() function is called.\n");if (urb->status) {if (!(urb->status == -ENOENT ||urb->status == -ECONNRESET ||urb->status == -ESHUTDOWN))dev_err(&dev->udev->dev,"%s - nonzero write status received: %d\n",__func__, urb->status);}if (dev->ibuffer == 0x00)pr_info ("switch is ON.\n");else if (dev->ibuffer == 0x01)pr_info ("switch is OFF.\n");elsepr_info ("bad value received\n");retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);if (retval) dev_err(&dev->udev->dev,"Couldn't submit interrupt_in_urb %d\n", retval);
}static int led_probe(struct usb_interface *intf,const struct usb_device_id *id)
{struct usb_device *udev = interface_to_usbdev(intf);struct usb_host_interface *altsetting = intf->cur_altsetting;struct usb_endpoint_descriptor *endpoint;struct usb_led *dev = NULL;int ep;int ep_in, ep_out;int retval, size, res;retval = 0;dev_info(&intf->dev, "led_probe() function is called.\n");res = usb_find_last_int_out_endpoint(altsetting, &endpoint);if (res) {dev_info(&intf->dev, "no endpoint found");return res;}ep = usb_endpoint_num(endpoint); /* value from 0 to 15, it is 1 */size = usb_endpoint_maxp(endpoint);/* Validate endpoint and size */if (size <= 0) {dev_info(&intf->dev, "invalid size (%d)", size);return -ENODEV;}dev_info(&intf->dev, "endpoint size is (%d)", size);dev_info(&intf->dev, "endpoint number is (%d)", ep);ep_in = altsetting->endpoint[0].desc.bEndpointAddress;ep_out = altsetting->endpoint[1].desc.bEndpointAddress;dev_info(&intf->dev, "endpoint in address is (%d)", ep_in);dev_info(&intf->dev, "endpoint out address is (%d)", ep_out);dev = kzalloc(sizeof(struct usb_led), GFP_KERNEL);if (!dev) return -ENOMEM;dev->ep_in = ep_in;dev->ep_out = ep_out;dev->udev = usb_get_dev(udev);dev->intf = intf;/* allocate int_out_urb structure */dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);if (!dev->interrupt_out_urb)goto error_out;/* initialize int_out_urb */usb_fill_int_urb(dev->interrupt_out_urb, dev->udev, usb_sndintpipe(dev->udev, ep_out), (void *)&dev->irq_data,1,led_urb_out_callback, dev, 1);/* allocate int_in_urb structure */dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);if (!dev->interrupt_in_urb)goto error_out;/* initialize int_in_urb */usb_fill_int_urb(dev->interrupt_in_urb, dev->udev, usb_rcvintpipe(dev->udev, ep_in), (void *)&dev->ibuffer,1,led_urb_in_callback, dev, 1);usb_set_intfdata(intf, dev);retval = device_create_file(&intf->dev, &dev_attr_led);if (retval)goto error_create_file;retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);if (retval) {dev_err(&dev->udev->dev,"Couldn't submit interrupt_in_urb %d\n", retval);device_remove_file(&intf->dev, &dev_attr_led);goto error_create_file;}dev_info(&dev->udev->dev,"int_in_urb submitted\n");return 0;error_create_file:usb_free_urb(dev->interrupt_out_urb);usb_free_urb(dev->interrupt_in_urb);usb_put_dev(udev);usb_set_intfdata(intf, NULL);error_out:kfree(dev);return retval;
}static void led_disconnect(struct usb_interface *interface)
{struct usb_led *dev;dev = usb_get_intfdata(interface);device_remove_file(&interface->dev, &dev_attr_led);usb_free_urb(dev->interrupt_out_urb);usb_free_urb(dev->interrupt_in_urb);usb_set_intfdata(interface, NULL);usb_put_dev(dev->udev);kfree(dev);dev_info(&interface->dev, "USB LED now disconnected\n");
}static struct usb_driver led_driver = {.name =       "usbled",.probe =    led_probe,.disconnect =    led_disconnect,.id_table = id_table,
};module_usb_driver(led_driver);MODULE_LICENSE("GPL");
MODULE_AUTHOR(" ");
MODULE_DESCRIPTION("This is a led/switch usb controlled module with irq in/out endpoints");

20.6 连接到USB多显LED的I2C模块

20.6.1 简介

使用芯片LTC3206 I2C 多显LED控制器。

20.6.2 代码

#include <linux/module.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/i2c.h>/* i2cset -y 4 0x1b 0x00 0xf0 0x00 i -> this is a full I2C block write blue and toggle the leds
i2cset -y 4 0x1b 0xf0 0x00 0x00 i -> red full
i2cset -y 4 0x1b 0x10 0x00 0x00 i -> red low
i2cset -y 4 0x1b 0x00 0x0f 0x00 i -> green full
i2cset -y 4 0x1b 0x00 0x0f 0x0f i -> sub and green full
i2cset -y 4 0x1b 0x00 0x00 0xf0 i -> main full */#define DRIVER_NAME "usb-ltc3206"#define USB_VENDOR_ID_LTC3206        0x04d8
#define USB_DEVICE_ID_LTC3206       0x003f#define LTC3206_OUTBUF_LEN        3   /* USB write packet length */
#define LTC3206_I2C_DATA_LEN        3/* Structure to hold all of our device specific stuff */
struct i2c_ltc3206 {u8 obuffer[LTC3206_OUTBUF_LEN]; /* USB write buffer *//* I2C/SMBus data buffer */u8 user_data_buffer[LTC3206_I2C_DATA_LEN];int ep_out;                  /* out endpoint */struct usb_device *usb_dev;   /* the usb device for this device */struct usb_interface *interface;/* the interface for this device */struct i2c_adapter adapter;  /* i2c related things *//* wq to wait for an ongoing write */wait_queue_head_t usb_urb_completion_wait;bool ongoing_usb_ll_op;      /* all is in progress */struct urb *interrupt_out_urb;
};/** Return list of I2C supported functionality*/
static u32 ltc3206_usb_func(struct i2c_adapter *a)
{return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL;
}/* usb out urb callback function */
static void ltc3206_usb_cmpl_cbk(struct urb *urb)
{struct i2c_ltc3206 *dev = urb->context;int status = urb->status;int retval;switch (status) {case 0:            /* success */break;case -ECONNRESET:    /* unlink */case -ENOENT:case -ESHUTDOWN:return;/* -EPIPE:  should clear the halt */default:        /* error */goto resubmit;}/* * wake up the waiting function* modify the flag indicating the ll status */dev->ongoing_usb_ll_op = 0; /* communication is OK */wake_up_interruptible(&dev->usb_urb_completion_wait);return;resubmit:retval = usb_submit_urb(urb, GFP_ATOMIC);if (retval) {dev_err(&dev->interface->dev,"ltc3206(irq): can't resubmit intrerrupt urb, retval %d\n",retval);}
}static int ltc3206_ll_cmd(struct i2c_ltc3206 *dev)
{int rv;/* * tell everybody to leave the URB alone* we are going to write to the LTC3206*/dev->ongoing_usb_ll_op = 1; /* doing USB communication *//* submit the interrupt out ep packet */if (usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL)) {dev_err(&dev->interface->dev,"ltc3206(ll): usb_submit_urb intr out failed\n");dev->ongoing_usb_ll_op = 0;return -EIO;}/* wait for its completion, the USB URB callback will signal it */rv = wait_event_interruptible(dev->usb_urb_completion_wait,(!dev->ongoing_usb_ll_op));if (rv < 0) {dev_err(&dev->interface->dev, "ltc3206(ll): wait interrupted\n");goto ll_exit_clear_flag;}return 0;ll_exit_clear_flag:dev->ongoing_usb_ll_op = 0;return rv;
}//分配并初始化用于主机和设备之间通信的中断输出URB
static int ltc3206_init(struct i2c_ltc3206 *dev)
{int ret;/* initialize the LTC3206 */dev_info(&dev->interface->dev,"LTC3206 at USB bus %03d address %03d -- ltc3206_init()\n",dev->usb_dev->bus->busnum, dev->usb_dev->devnum);dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);if (!dev->interrupt_out_urb){ret = -ENODEV;goto init_error;}usb_fill_int_urb(dev->interrupt_out_urb, dev->usb_dev,usb_sndintpipe(dev->usb_dev,dev->ep_out),(void *)&dev->obuffer, LTC3206_OUTBUF_LEN, ltc3206_usb_cmpl_cbk, dev,1);ret = 0;goto init_no_error;init_error:dev_err(&dev->interface->dev, "ltc3206_init: Error = %d\n", ret);return ret;init_no_error:dev_info(&dev->interface->dev, "ltc3206_init: Success\n");return ret;
}static int ltc3206_i2c_write(struct i2c_ltc3206 *dev,struct i2c_msg *pmsg)
{u8 ucXferLen;int rv;u8 *pSrc, *pDst;if (pmsg->len > LTC3206_I2C_DATA_LEN){pr_info ("problem with the lenght\n");return -EINVAL;}/* I2C write lenght */ucXferLen = (u8)pmsg->len;pSrc = &pmsg->buf[0];pDst = &dev->obuffer[0];memcpy(pDst, pSrc, ucXferLen);pr_info("oubuffer[0] = %d\n", dev->obuffer[0]);pr_info("oubuffer[1] = %d\n", dev->obuffer[1]);pr_info("oubuffer[2] = %d\n", dev->obuffer[2]);rv = ltc3206_ll_cmd(dev);if (rv < 0)return -EFAULT;return 0;
}/* device layer */
static int ltc3206_usb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msgs, int num)
{struct i2c_ltc3206 *dev = i2c_get_adapdata(adap);struct i2c_msg *pmsg;int ret, count;pr_info("number of i2c msgs is = %d\n", num);for (count = 0; count < num; count++) {pmsg = &msgs[count];ret = ltc3206_i2c_write(dev, pmsg);if (ret < 0)goto abort;}/* if all the messages were transferred ok, return "num" */ret = num;
abort:return ret;
}static const struct i2c_algorithm ltc3206_usb_algorithm = {.master_xfer = ltc3206_usb_i2c_xfer,.functionality = ltc3206_usb_func,
};static const struct usb_device_id ltc3206_table[] = {{ USB_DEVICE(USB_VENDOR_ID_LTC3206, USB_DEVICE_ID_LTC3206) },{ }
};
MODULE_DEVICE_TABLE(usb, ltc3206_table);static void ltc3206_free(struct i2c_ltc3206 *dev)
{usb_put_dev(dev->usb_dev);usb_set_intfdata(dev->interface, NULL);kfree(dev);
}static int ltc3206_probe(struct usb_interface *interface,const struct usb_device_id *id)
{struct usb_host_interface *hostif = interface->cur_altsetting;struct i2c_ltc3206 *dev;int ret;dev_info(&interface->dev, "ltc3206_probe() function is called.\n");/* allocate memory for our device state and initialize it */dev = kzalloc(sizeof(*dev), GFP_KERNEL);if (dev == NULL) {pr_info("i2c-ltc3206(probe): no memory for device state\n");ret = -ENOMEM;goto error;}/* get ep_out */dev->ep_out = hostif->endpoint[1].desc.bEndpointAddress;dev->usb_dev = usb_get_dev(interface_to_usbdev(interface));dev->interface = interface;init_waitqueue_head(&dev->usb_urb_completion_wait);/* save our data pointer in this interface device */usb_set_intfdata(interface, dev);/* setup i2c adapter description */dev->adapter.owner = THIS_MODULE;dev->adapter.class = I2C_CLASS_HWMON;dev->adapter.algo = &ltc3206_usb_algorithm;i2c_set_adapdata(&dev->adapter, dev);snprintf(dev->adapter.name, sizeof(dev->adapter.name),DRIVER_NAME " at bus %03d device %03d",dev->usb_dev->bus->busnum, dev->usb_dev->devnum);dev->adapter.dev.parent = &dev->interface->dev;/* initialize ltc3206 i2c device */ret = ltc3206_init(dev);if (ret < 0) {  dev_err(&interface->dev, "failed to initialize adapter\n");goto error_init;}/* and finally attach to i2c layer */ret = i2c_add_adapter(&dev->adapter);if (ret < 0) {dev_info(&interface->dev, "failed to add I2C adapter\n");goto error_i2c;}dev_info(&dev->interface->dev,"ltc3206_probe() -> chip connected -> Success\n");return 0;error_init:usb_free_urb(dev->interrupt_out_urb);error_i2c:usb_set_intfdata(interface, NULL);ltc3206_free(dev);
error:return ret;
}static void ltc3206_disconnect(struct usb_interface *interface)
{struct i2c_ltc3206 *dev = usb_get_intfdata(interface);i2c_del_adapter(&dev->adapter);usb_kill_urb(dev->interrupt_out_urb);usb_free_urb(dev->interrupt_out_urb);usb_set_intfdata(interface, NULL);ltc3206_free(dev);pr_info("i2c-ltc3206(disconnect) -> chip disconnected");
}static struct usb_driver ltc3206_driver = {.name = DRIVER_NAME,.probe = ltc3206_probe,.disconnect = ltc3206_disconnect,.id_table = ltc3206_table,
};module_usb_driver(ltc3206_driver);MODULE_AUTHOR(" ");
MODULE_DESCRIPTION("This is a usb controlled i2c ltc3206 device");
MODULE_LICENSE("GPL");

感谢阅读,祝君成功!
-by aiziyou

嵌入式Linux设备驱动程序开发指南20(Linux USB设备驱动)——读书笔记相关推荐

  1. 嵌入式Linux设备驱动程序开发指南9(平台设备驱动)——读书笔记

    平台设备驱动 九.平台设备驱动 9.1 平台设备驱动概述 9.2 GPIO驱动 9.2.1 简介 9.2.2 硬件名称 9.2.3 引脚控制器 9.2.4 引脚控制子系统 9.2.5 GPIO控制器驱 ...

  2. wdm设备驱动程序开发pdf_世界顶级Linux技术大师力作1000页Linux开发实战

    20世纪90年代初,Linux操作系统诞生,随着虚拟化.云计算.大数据.容器技术的出现和人工智能时代的来临,Linux 以迅雷不及掩耳之势飞速发展,占据着整个服务器行业的半壁江山,但同时也面临着巨大的 ...

  3. VxWorks设备驱动程序开发指南---驱动程序的分类

    8D Spaces Reliability & Stability & Efficiency 目录视图 摘要视图 订阅 VxWorks设备驱动程序开发指南(三)---驱动程序的分类 2 ...

  4. 嵌入式Linux设备驱动程序开发指南17(IIO子系统一)——读书笔记

    IIO子系统一 十七.IIO子系统(一) 17.1 简介 17.2 数模转换--DAC实验 17.2.1 IIO缓冲区 17.2.2 触发器 17.2.3 工业I/O事件 17.2.4 iio工具 1 ...

  5. 嵌入式Linux设备驱动程序开发指南14(Linux设备驱动使用DMA)——读书笔记

    Linux设备驱动使用DMA 十四.Linux设备驱动使用DMA 14.1 简介 14.2 缓存一致性 14.3 DMA控制器接口 14.4 流式DMA模块 14.4.1 sdma_sam_m2m.c ...

  6. 嵌入式Linux设备驱动程序开发指南3(构建Microchip SAMA5D2嵌入式 Linux系统)——读书笔记

    构建Microchip SAMA5D2嵌入式 Linux系统 三.构建Microchip SAMA5D2嵌入式 Linux系统 3.1 获取驱动代码 3.2 配置编译 3.2.1 bootstrap编 ...

  7. 嵌入式Linux设备驱动程序开发指南18(IIO子系统(二)具有硬件触发功能的IIO子系统ADC模块)——读书笔记

    IIO子系统二 具有硬件触发功能的IIO子系统ADC模块 十八.IIO子系统(二) 具有硬件触发功能的IIO子系统ADC模块 18.1 简介 18.2 设备树 18.3 硬件触发驱动功能分析 18.3 ...

  8. 组策略中分类别禁用设备驱动程序安装,可以用来禁用USB设备

    允许安装与下列设备ID相匹配的设备(设备ID可以在设备管器的硬件ID中找到) 允许使用与下列设备安装程序类相匹配的驱动程序安装设备(该设备安装程序类可以在设备管器的设备类GUID中找到) 参考链接: ...

  9. VxWorks驱动程序开发指南--驱动程序的组织结构

    8D Spaces Reliability & Stability & Efficiency 目录视图 摘要视图 订阅 VxWorks驱动程序开发指南(四)--驱动程序的组织结构 20 ...

最新文章

  1. angular5 清除定时器
  2. Luogu P1262 间谍网络 【强连通分量/缩点】By cellur925
  3. jQuery的显示与隐藏
  4. Google DayDream VR开发
  5. Win10微软帐户切换不回Administrator本地帐户的解决方法【亲测】
  6. 【matlab】syms x y 用法
  7. ESP32-C3入门教程 IoT篇⑤——阿里云 物联网平台 EspAliYun RGB LED 实战之设备生产流程
  8. 随手练——字符串按最小(大)字典序拼接
  9. NPDP产品经理证书在中国有用吗?
  10. 差分信号,共模与差模,共模滤波,差模滤波
  11. prompt综述论文阅读:Pre-train, Prompt, and Predict: A Systematic Survey of Prompting Methods in Natural La
  12. 7个最好的Java机器学习开发库
  13. VirtualBox-7.0.6 下载与安装
  14. 爬虫入门经典(十) | 一文带你快速爬取网易云音乐
  15. 【zzq‘笔记】HDR成像技术学习(一)
  16. Acme Corporation UVA11613 网络流
  17. git基于某个Tag修改提交
  18. 俄罗斯方块源码分享 html+css+js
  19. 联想拯救者连不上网?
  20. MAC 自定义通知提醒 (定时提醒喝水)

热门文章

  1. 浅谈Android模块化设计(模块化的一些思考)
  2. 什么是JWT? Token? 如何基于Token进行身份验证?
  3. 互联网大厂2021中秋礼盒battle,把我都看馋了
  4. 机器学习:基于朴素贝叶斯(Naive Bayes)的分类预测
  5. 2020-11-22 如何在C#中往数据库插入数据
  6. 虚拟机克隆教程——用于集群搭建等
  7. 字节对齐不慎引发的挂死问题
  8. MPU866ADS初始化配置
  9. ng-zorro select 下拉框
  10. A Bio-Inspired Multi-Exposure Fusion Frameworkfor Low-light Image Enhancement