【驱动】USB驱动·入门
Preface
USB是目前最流行的系统总线之一。随着计算机周围硬件的不断扩展,各种设备使用不同的总线接口,导致计算机外部总线种类繁多,管理困难。USB总线正是因此而诞生的。
USB总线提供了所有外部设备的统一连接方式,并且支持热插拔,方便了厂商开发设备和用户使用设备。
USB遵循原则
USB的设计目标是对现有的PC机体系进行扩充,但是目前不仅是PC机,许多的嵌入式系统都开始支持USB总线和接口标准。USB设计主要遵循下面几个原则:
易于扩充外部设备:USB支持一个接口最多127个设备。
灵活的传输协议: 支持同步和异步数据传输。
设备兼容性好: 可以兼容不同类型的设备。
接口标准统一:不同的设备之间使用相同的设备接口。
USB体系概述
USB接口标准支持主机和外部设备之间进行数据传输。
在USB体系结构中,主机预定了各种类型外部设备使用的总线带宽。当外部设备和主机在运行时,USB总线允许添加、设置、使用和拆除外设。
在USB体系结构中,一个USB系统可以分成USB互联、USB设备和USB主机三个部分。
USB互联是USB设备和USB主机之间进行连接通信的操作,主要包括:
总线拓扑结构:USB主机和USB设备之间的连接方式。
数据流模式:描述USB通信系统中数据如何从产生方传递到使用方。
USB调度:USB总线是一个共享连接,对可以使用的连接进行了调试以支持同步数据传输,并且避免优先级判定的开销。
USB的物理连接是一个有层次的星形结构。
在一个节点上连接多个设备需要使用 USB集线器(USB HUB)。
USB体系结构规定,在一个 USB系统中,只有唯一的一个主机。USB和主机系统的接口称做主机控制器,主机控制器由主机控制器芯片、固件程序和软件共同实现的。
USB设备包括USB集线器和功能器件。其中USB集线器的作用是扩展总线端点,向总线提供更多的连接点;功能器件是用户使用的外部设备,如键盘,鼠标等。
USB设备需要支持 USB总线协议,对主机的操作提供反馈并且提供设备性能的描述信息。
USB体系工作流程
USB总线采用轮询方式控制,主机控制设置初始化所有的数据传输。
USB总线每次执行传输动作最多可以传输三个数据包。每次开始传输时,主机控制器发送一个描述符描述传输动作的种类和方向,这个数据包称作标志数据包(Token Packet)。USB设备收到主机发送的标志数据包后解析出数据自己的数据。
USB数据传输的方向只有两种:主机到设备或者设备到主机。
在一个数据传输开始时,由标志包标示数据的传输方向,然后发送端开始发送包含信息的数据。接收端发送一个握手的数据包表明数据是否传送成功。
在主机和设备之间的USB数据传输可以看做一个通道。USB数据传输有流和消息两种通道。消息是有格式的数据,而流是没有数据格式的。
USB有一个缺省的控制消息通道,在设备启动的时候被创建,因此设备的设置查询和输入控制信息都可以使用缺省消息控制通道完成。
USB驱动程序框架
Linux内核提供了完整的USB驱动程序框架。
USB总线采用树形结构,在一条总线上只能有唯一的主机设备。
Linux内核从主机和设备两个角度观察USB总线结构。
Linux内核USB驱动框架
左侧是主机驱动结构。
主机驱动的最底层是 USB主机控制器,提供了 OHCI/EHCI/UHCI这3种类型的总线控制功能。
在USB控制器的上一层是主机控制器的驱动,分别对应OHCI/EHCI/UHCI这3种类型的总线接口。
USB核心部分连接了 USB控制器驱动和设备驱动,是两者之间的转换接口。
USB设备驱动层提供了各种设备的驱动程序。
所有类型的 USB设备都是用相同的电气接口,使用的传输协议也基本相同。
向用户提供某种特定类型的 USB设备时,需要处理 USB总线协议。内核完成所有的 USB总线协议处理,并且向用户提供编程接口。
右侧是设备驱动结构。
与USB主机类似,USB设备提供了相同的层次结构与之对应。但是在 USB设备一侧使用名为 Gadget API的结构作为核心。
Gadget API是 Linux内核实现的对应 USB设备的核心结构。Gadget API屏蔽了 USB设备控制器的细节,控制具体的 USB设备实现。
设备
每个 USB设备提供了不同级别的配置信息。
一个 USB设备可以包含一个或多个配置,不同的配置使设备表现出不同的特点。其中,设备的配置是通过接口组成的。
Linux内核定义了 USB设备描述结构如下:
//源定义在Usb_ch9.h
/* USB_DT_DEVICE: Device descriptor */
struct usb_device_descriptor {__u8 bLength; //设备描述符长度__u8 bDescriptorType; //设备类型__le16 bcdUSB; // USB版本号(使用 BCD编码)__u8 bDeviceClass; // USB设备类型__u8 bDeviceSubClass; // USB设备子类型__u8 bDeviceProtocol; // USB设备协议号__u8 bMaxPacketSize0; //传输数据的最大包长__le16 idVendor; //厂商编号__le16 idProduct; //产品编号__le16 bcdDevice; //设备出厂号__u8 iManufacturer; //厂商字符串索引__u8 iProduct; //产品字符串索引__u8 iSerialNumber; //产品序列号索引__u8 bNumConfigurations; //最大的配置数量
} __attribute__ ((packed));
从 usb_device_descrptor结构定义看出,一个设备描述定义了与 USB设备有关的所有信息。
接口
在 USB体系中,接口是由多个端点组成的。
一个接口代表一个基本的功能,是 USB设备驱动程序控制的对象。
一个 USB设备最少有一个接口,功能复杂的 USB设备可以有多个接口。接口描述定义如下:Usb
//源定义在 Usb_ch9.h
/* USB_DT_INTERFACE: Interface descriptor */
struct usb_interface_descriptor {__u8 bLength; //描述符长度__u8 bDescriptorType; //描述符类型__u8 bInterfaceNumber; //接口编号__u8 bAlternateSetting; //备用接口编号__u8 bNumEndpoints; //端点数量__u8 bInterfaceClass; //接口类型__u8 bInterfaceSubClass; //接口子类型__u8 bInterfaceProtocol; //接口使用的协议__u8 iInterface; //接口索引字符串数值
} __attribute__ ((packed));
端点
端点是 USB总线通信的基本形式,每个 USB设备接口可以认为是端点的集合。
主机只能通过端点与设备通信。
USB体系结构规定每个端点都有一个唯一的地址,由设备地址和端点号决定端点地址。
端点还包括了与主机通信用到的属性,如传输方式、总线访问频率、带宽和端点号等。
端点的通信是单向的,通过端点传输的数据只能是从主机到设备或者从设备到主机。
端点的定义描述如下:
/* USB_DT_ENDPOINT: Endpoint descriptor */
struct usb_endpoint_descriptor {__u8 bLength; //描述符长度__u8 bDescriptorType; //描述符类型__u8 bEndpointAddress; //端点地址__u8 bmAttributes; //端点属性__le16 wMaxPacketSize; //端点接收的最大数据包长度__u8 bInterval;/* NOTE: these two are _only_ in audio endpoints. *//* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */__u8 bRefresh;__u8 bSynchAddress;
} __attribute__ ((packed));
配置
配置是一个接口的集合。
Linux内核配置的定义如下:
struct usb_config_descriptor {__u8 bLength; //描述符长度__u8 bDescriptorType; //描述符类型__le16 wTotalLength; //配置返回数据长度__u8 bNumInterfaces; //最大接口数__u8 bConfigurationValue; //配置参数值__u8 iConfiguration; //配置描述字符串索引__u8 bmAttributes; //供电模式__u8 bMaxPower; //接口的最大电流
} __attribute__ ((packed));
主机驱动结构
USB主机控制器有三种类型:
OHCI,英文全称是Open Host Controller Interface。OHCI是用于SiS和Ali芯片组的USB控制器。
UHCI,英文全称是Universal Host Controller Interface。UHCI用于Intel和AMD芯片组的USB控制器。UHCI类型的控制器比OHCI控制器硬件结构要简单,但是需要额外的驱动支持,因此从理论上说速度要慢。
EHCI,USB2.0规范提出的一种控制器标准,可以兼容UHCI和OHCI。
USB主机控制器驱动
Linux内核使用 usb_hcd结构描述 USB主机控制器驱动。
usb_hcd结构描述了 USB主机控制器的硬件信息、状态和操作函数。定义如下:
//源定义在Hcd.h
struct usb_hcd { /* usb_bus.hcpriv points to this *//** housekeeping //控制器基本信息*/struct usb_bus self; /* hcd is-a bus */const char *product_desc; /* product/vendor string */ //厂商名称字符串char irq_descr[24]; /* driver + bus # */ //驱动和总线类型struct timer_list rh_timer; /* drives root-hub polling */ //根 hub轮询时间间隔struct urb *status_urb; /* the current status urb */ //当前 urb状态/** hardware info/state //硬件信息和状态*/const struct hc_driver *driver; /* hw-specific hooks */ //控制器驱动使用的回调函数/* Flags that need to be manipulated atomically */unsigned long flags;
#define HCD_FLAG_HW_ACCESSIBLE 0x00000001
#define HCD_FLAG_SAW_IRQ 0x00000002unsigned rh_registered:1;/* is root hub registered? */ //是否注册根 hub/* The next flag is a stopgap, to be removed when all the HCDs* support the new root-hub polling mechanism. */unsigned uses_new_polling:1; //是否允许轮询根 hub状态unsigned poll_rh:1; /* poll for rh status? */unsigned poll_pending:1; /* status has changed? */ //状态是否改变int irq; /* irq allocated */ //控制器的中断请求号void __iomem *regs; /* device memory/io */ //控制器使用的内存和 I/Ou64 rsrc_start; /* memory/io resource start */ //控制器使用的内存和 I/O起始地址u64 rsrc_len; /* memory/io resource length */ //控制器使用的内存和 I/O资源长度unsigned power_budget; /* in mA, 0 = no limit */
#define HCD_BUFFER_POOLS 4struct dma_pool *pool [HCD_BUFFER_POOLS];int state;
# define __ACTIVE 0x01
# define __SUSPEND 0x04
# define __TRANSIENT 0x80
# define HC_STATE_HALT 0
# define HC_STATE_RUNNING (__ACTIVE)
# define HC_STATE_QUIESCING (__SUSPEND|__TRANSIENT|__ACTIVE)
# define HC_STATE_RESUMING (__SUSPEND|__TRANSIENT)
# define HC_STATE_SUSPENDED (__SUSPEND)
#define HC_IS_RUNNING(state) ((state) & __ACTIVE)
#define HC_IS_SUSPENDED(state) ((state) & __SUSPEND)/* more shared queuing code would be good; it should support* smarter scheduling, handle transaction translators, etc;* input size of periodic table to an interrupt scheduler.* (ohci 32, uhci 1024, ehci 256/512/1024).*//* The HC driver's private data is stored at the end of* this structure.*/unsigned long hcd_priv[0]__attribute__ ((aligned (sizeof(unsigned long))));
};
OHCI控制器驱动
usb_hcd结构可以理解为一个通用的 USB控制器描述结构,OHCI主机控制器是 usb_hcd结构的具体实现。
内核使用 ohci_hcd结构描述 OHCI主机控制器,定义如下:
struct ohci_hcd {spinlock_t lock;/** I/O memory used to communicate with the HC (dma-consistent) //用于 HC通信的 I/O内存地址*/struct ohci_regs __iomem *regs;/** main memory used to communicate with the HC (dma-consistent)。 //用于 HC 通告的主内存地址* hcd adds to schedule for a live hc any time, but removals finish* only at the start of the next frame.*/struct ohci_hcca *hcca;dma_addr_t hcca_dma;struct ed *ed_rm_list; /* to be removed */ //将被移除列表struct ed *ed_bulktail; /* last in bulk list */ //列表最后一项struct ed *ed_controltail; /* last in ctrl list */ //控制列表最后一项struct ed *periodic [NUM_INTS]; /* shadow int_table *//** OTG controllers and transceivers need software interaction;* other external transceivers should be software-transparent*/struct otg_transceiver *transceiver;/** memory management for queue data structures //内存管理队列使用的数据结构*/struct dma_pool *td_cache;struct dma_pool *ed_cache;struct td *td_hash [TD_HASH_SIZE];struct list_head pending;/** driver state*/int num_ports;int load [NUM_INTS];u32 hc_control; /* copy of hc control reg */ // HC控制寄存器复制unsigned long next_statechange; /* suspend/resume */ //挂起 恢复u32 fminterval; /* saved register */ //保存的寄存器struct notifier_block reboot_notifier;unsigned long flags; /* for HC bugs */
#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */
#define OHCI_QUIRK_SUPERIO 0x02 /* natsemi */
#define OHCI_QUIRK_INITRESET 0x04 /* SiS, OPTi, ... */
#define OHCI_BIG_ENDIAN 0x08 /* big endian HC */
#define OHCI_QUIRK_ZFMICRO 0x10 /* Compaq ZFMicro chipset*/// there are also chip quirks/bugs in init logic //芯片的初始化逻辑里也同样会有怪异的 Bug
};
OHCI主机控制器是嵌入式系统最常用的一种 USB主机控制器。
设备驱动结构
USB协议规定了许多种USB设备类型。Linux内核实现了音频设备、通信设备、人机接口、存储设备、电源设备、打印设备等几种USB设备类。
基本概念
Linux内核实现的 USB设备驱动都是针对通用的设备类型设计的。
只要 USB存储设备是按照标准的 USB存储设备规范实现的,就可以直接被内核 USB存储设备驱动。如果一个 USB设备是非标准的,则需要编写对应设备的驱动程序。
设备驱动结构
内核使用 usb_driver结构体描述 USB设备驱动,定义如下:
struct usb_driver {const char *name;int (*probe) (struct usb_interface *intf,const struct usb_device_id *id); //探测函数void (*disconnect) (struct usb_interface *intf); //断开连接函数int (*ioctl) (struct usb_interface *intf, unsigned int code,void *buf); // I/O控制函数int (*suspend) (struct usb_interface *intf, pm_message_t message); //挂起函数int (*resume) (struct usb_interface *intf); //恢复函数void (*pre_reset) (struct usb_interface *intf);void (*post_reset) (struct usb_interface *intf);const struct usb_device_id *id_table;struct usb_dynids dynids;struct device_driver driver;unsigned int no_dynamic_id:1;
};
实现一个 USB设备的驱动主要是实现 probe()和 disconnect()函数接口。
probe()函数在插入 USB设备的时候被调用,disconnect()函数在拔出 USB设备的时候被调用。
USB请求块
USB请求块(USB request block,urb)的功能类似于网络设备中的 sk_buff,用于描述 USB设备与主机通信的基本数据结构。
urb结构在内核中定义如下:
//源定义在 Usb.h
struct urb
{/* private: usb core and host controller only fields in the urb */struct kref kref; /* reference count of the URB */ // urb引用计数spinlock_t lock; /* lock for the URB */ // urb锁void *hcpriv; /* private data for host controller */ //主机控制器私有数据int bandwidth; /* bandwidth for INT/ISO request */ //请求带宽atomic_t use_count; /* concurrent submissions counter */ //并发传输计数u8 reject; /* submissions will fail */ //传输即将失败标志/* public: documented fields in the urb that can be used by drivers */ //公有数据,可以被驱动使用struct list_head urb_list; /* list head for use by the urb's //链表头* current owner */struct usb_device *dev; /* (in) pointer to associated device */ //关联的 USB设备unsigned int pipe; /* (in) pipe information */ //管道信息int status; /* (return) non-ISO status */ //当前信息unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/void *transfer_buffer; /* (in) associated data buffer */ //数据缓冲区dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */ //DMA使用的缓冲区int transfer_buffer_length; /* (in) data buffer length */ //缓冲区大小int actual_length; /* (return) actual transfer length */ //实际接收或发送数据的长度unsigned char *setup_packet; /* (in) setup packet (control only) */dma_addr_t setup_dma; /* (in) dma addr for setup_packet */ //设置数据包缓冲区int start_frame; /* (modify) start frame (ISO) */ //等时传输中返回初始帧int number_of_packets; /* (in) number of ISO packets */ //等时传输中缓冲区数据int interval; /* (modify) transfer interval //轮询的时间间隔* (INT/ISO) */int error_count; /* (return) number of ISO errors */ //出错次数void *context; /* (in) context for completion */usb_complete_t complete; /* (in) completion routine */struct usb_iso_packet_descriptor iso_frame_desc[0];/* (in) ISO ONLY */
};
内核提供了一组函数 urb类型的结构变量。urb的使用流程如下:
创建 urb。在使用之前,USB设备驱动需要调用 usb_alloc_urb()函数创建一个 urb;内核还提供释放 urb的函数,在不使用 urb的时候(退出驱动种马或者挂起驱动),需要使用 usb_free_urb()函数释放 urb。
初始化 urb。设置 USB设备的端点。使用内核提供的 usb_init_urb()函数设置 urb初始结构。
提交 urb到 USB核心。在分配并设置 urb完毕后,使用 urb_submit_urb()函数把新的 urb提交到 USB核心。
USB驱动程序框架
Linux内核代码driver/usb/usb-skeleton.c文件是一个标准的USB设备驱动程序。
编写一个USB设备的驱动可以参考usb-skeleton.c文件,实际上,可以直接修改该文件驱动新的USB设备。
基本数据结构
usb-skel设备使用自定义结构 usb_skel记录设备驱动用到的所有描述符,该结构定义如下:
/* Structure to hold all of our device specific stuff */
struct usb_skel {struct usb_device * udev; /* the usb device for this device */// USB设备描述符struct usb_interface * interface; /* the interface for this device */// USB接口描述符struct semaphore limit_sem; /* limiting the number of writes in progress */// 互斥信号量unsigned char * bulk_in_buffer; /* the buffer to receive data */// 数据接收缓冲区size_t bulk_in_size; /* the size of the receive buffer */// 数据接收缓冲区大小__u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */// 入端点地址__u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */// 出端点地址struct kref kref;
};
usb-skel设备驱动把 usb_skel结构存放在了 urb结构的 context指针里。通过 urb,设备的所有操作函数都可以访问到 usb_skel结构。
其中,limit_sem成员是一个信号量,当多个 usb-skel类型的设备存在于系统中的时候,需要控制设备之间的数据同步。
驱动程序初始化和注销
与其他所有的 Linux设备驱动程序一样,usb-skel驱动使用 module_init()宏设置初始化函数,使用 module_exit()宏设置注销函数。
usb-skel驱动的初始化函数是 usb_skel_init()函数,定义如下:
static int __init usb_skel_init(void)
{int result;/* register this driver with the USB subsystem */result = usb_register(&skel_driver); //注册 USB设备驱动if (result)err("usb_register failed. Error number %d", result);return result;
}
usb_skel_init()函数调用内核提供的 usb_register()函数注册了一个 usb_driver类型的结构变量,该变量定义如下:
static struct usb_driver skel_driver = {.name = "skeleton", // USB设备名称.probe = skel_probe, // USB设备初始化函数.disconnect = skel_disconnect, // USB设备注销函数.id_table = skel_table, // USB设备 ID映射表
};
skel_driver结构变量中,定义了 usb-skel设备的名、设备初始化函数、设备注销函数和 USB ID映射表。
其中 usb-skel设备的 USB ID映射表定义如下:
/* table of devices that work with this driver */
static struct usb_device_id skel_table [] = {{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },{ } /* Terminating entry */
};
skel_table中只有一项,定义了一个默认的 usb-skel设备的 ID,其中,USB_SKEL_VENDOR_ID是 USB设备的厂商 ID,USB_SKEL_PRODUCT_ID是 USB设备 ID。
设备初始化
从 skel_driver结构可以知道 usb-skel设备的初始化函数是 skel_probe()函数。
设备初始化主要是探测设备类型,分配 USB设备用到的 urb资源,注册 USB设备操作函数等。
skel_class结构变量记录了 usb-skel设备信息,定义如下:
/** usb class driver info in order to get a minor number from the usb core,* and to have the device registered with the driver core*/
static struct usb_class_driver skel_class = {.name = "skel%d", //设备名称.fops = &skel_fops, //设备操作函数.minor_base = USB_SKEL_MINOR_BASE,
};
name变量使用 %d通配符表示一个整形变量,当一个 usb-skel类型的设备连接到 USB总线后会按照子设备编号自动设置设备名称。
fops是设备操作函数结构变量,定义如下:
static struct file_operations skel_fops = {.owner = THIS_MODULE,.read = skel_read, //读操作.write = skel_write, //写操作.open = skel_open, //打开操作.release = skel_release, //关闭操作
};
skel_ops定义了 usb-skel设备的操作函数。当在 usb-skel设备上发生相关事件时,USB文件系统会调用对应的函数处理。
设备注销
skel_disconnect()函数在注销设备的时候被调用,定义如下:
static void skel_disconnect(struct usb_interface *interface)
{struct usb_skel *dev;int minor = interface->minor;/* prevent skel_open() from racing skel_disconnect() */lock_kernel(); //在操作之前加锁dev = usb_get_intfdata(interface); //获得 USB设备接口描述usb_set_intfdata(interface, NULL); //设置 USB设备接口描述无效/* give back our minor */usb_deregister_dev(interface, &skel_class); //注销 USB设备操作供述unlock_kernel(); //操作完毕解锁/* decrement our usage count */kref_put(&dev->kref, skel_delete); //减小引用计数info("USB Skeleton #%d now disconnected", minor);
}
static struct usb_driver skel_driver = {.name = "skeleton", // USB设备名称.probe = skel_probe, // USB设备初始化函数.disconnect = skel_disconnect, // USB设备注销函数.id_table = skel_table, // USB设备 ID映射表
};
skel_disconnect()函数释放 usb-skel设备用到的资源。
首先获取 USB设备接口描述,之后设置为无效;然后调用 usb_deregister_dev()函数注销 USB设备的操作描述符,注销操作本身需要加锁;注销设备描述符后,更新内核对 usb-skel设备的引用计数。
本文出自 “成鹏致远” 博客,请务必保留此出处http://infohacker.blog.51cto.com/6751239/1226257
转载于:https://www.cnblogs.com/lcw/p/3159371.html
【驱动】USB驱动·入门相关推荐
- s3c2440 LCD驱动,USB驱动,触摸屏以及ADC驱动移植
这篇驱动移植文章,目的是实现相应的功能,分享我在做移植过程中所碰到的一些问题以及解决的方法. 交叉编译器环境:arm-linux-gcc-4.5.4 开发板平台:FL2440 Linux内核版本: 3 ...
- Air780E模块USB驱动
USB驱动 USB驱动无需安装,插入电脑后会虚拟出如下端口:前2个口81,82可以用来发送AT命令,83口对应的为LOG口(也可能是前2个口是LOG口,已实际测试为准).
- linux usb驱动教学视频教程,详解linux usb host驱动编写入门
usb协议是一个复杂的协议,目前涉及到的版本就有usb1.0, usb2.0, usb3.0.大家如果打开kernel usb host目录,就会发现下面包含了ohci,uhci,ehci,xhci, ...
- 简单说说驱动程序设计的入门
简单说说驱动程序设计的入门,其实初级驱动设计中也能使用C++,也能使用类,但和用户程序中的用法有一些区别,一些特殊的地方需要特别注意.从笔者的经验来看,WDK给出的AVStream小端口驱动示例工程, ...
- 2008年12月13日上海USB驱动开发深度解析讲座PPT
讲座PPT:宋宝华2008年12月13日上海USB驱动开发深度解析讲座PPT [url]http://www.linuxdriver.cn/200812/20081213172619_836.rar[ ...
- 嵌入式Linux USB驱动开发之教你一步步编写USB驱动程序
2019独角兽企业重金招聘Python工程师标准>>> 编写与一个USB设备驱动程序的方法和其他总线驱动方式类似,驱动程序把驱动程序对象注册到USB子系统中,稍后再使用制造商和设备标 ...
- MF Porting之USB驱动开发
花费了近三个礼拜的时间,终于完成了TI开发板的USB驱动开发,现在回头想一想,其实也没有什么,具体硬件方面的通信由DM355实现了,软件层面的数据交互由MF Porting实现了,所做的也就是熟悉了解 ...
- Linux USB 驱动开发(五)—— USB驱动程序开发过程简单总结
http://blog.csdn.net/zqixiao_09/article/details/51057086 设备驱动程序是操作系统内核和机器硬件之间的接口,由一组函数和一些私有数据组成,是应用程 ...
- linux usb驱动
0.usb协议 usb的版本: 硬件 usb 1.0 OHCI 微软 硬件 > 软件 usb ...
最新文章
- POJ - 1661 Help Jimmy DP
- 【FFmpeg】Hello World!尝试如何编译FFmpeg程序
- 如何利用PN结来测量温度?
- 16-Understanding the Armv8.x extensions
- python websocket server_用Python实现一个简单的WebSocket服务器
- 由Android 65K方法数限制引发的思考
- 【推荐系统】推荐系统概述
- 修改大表字段属性报主键冲突
- 如何理解Bounce Rate和Exit Rate
- python运行方法_对python中执行DOS命令的3种方法总结
- 服务器新硬盘如何挂在,Ubuntu服务器挂载新硬盘的步骤
- VirtualBox中,LINUX与Windows可以通过链接来跳转
- 2、http网络编程——libcurl的使用
- rpg人物制作软件_RPG制作大师下载_RPG制作大师官方下载-太平洋下载中心
- Hadoop版本比较
- GAEfan qiang教程
- Java版漏斗计时器_新学期新气象 教你在《我的世界》做出特别铃声
- 人像抠图软件哪个好?这些软件助你实现人像抠图
- 人工智能换脸技术python_人工智能几行代码实现换脸,python+dlib实现图文教程
- FPGA实现的SPI协议(二)----基于SPI接口的FLASH芯片M25P16的使用
热门文章
- Python数据结构与算法(2.7)——跳表
- Python strftime()
- 开课吧:C++入门必知必会的基础知识汇总
- nginx+tomcat+msm实现seesion共享
- Java RESTful Web Service实战(第2版) 2.3 传输格式
- mybatis 3的TypeHandler深入解析(及null值的处理)
- 换教室(NOIP2016提高组Day1T3)
- Swift面向对象基础(中)——Swift中的方法
- Visual studio 2013 添加 GitHub
- 如何在20130513image上,备份NAND到SD卡,然后把这个SD卡做成可以自启动的SD卡