usb 转 uart cp210x 驱动解析
USB 转 uart (cp210x.c) 驱动解析
#### * usb_serial_driver 结构体解析
```
	include/linux/usb/serial.h
	/**                     描述一个usb 串口设备驱动
 	* usb_serial_driver - describes a usb serial driver
	*  将一串描述这个驱动的字符串保存在其中,这个指针在syslog中打印当设备被插入或被拔出
 	* @description: pointer to a string that describes this driver.  This string
 	*  used in the syslog messages when a device is inserted or removed.
 	*  指向一个列表有关  usb 设备ID结构体 ,这个结构体定义了所有能支持的设备
 	* @id_table: pointer to a list of usb_device_id structures that define all
 	*  of the devices this structure can support.
	*  这个设备将有不同的端口
 	* @num_ports: the number of different ports this device will have.
 	*  bulk-in 缓冲区最小的申请的空间
 	* @bulk_in_size: minimum number of bytes to allocate for bulk-in buffer
 	*  (0 = end-point size)
 	*  申请的bulk-out 缓冲区大小
 	* @bulk_out_size: bytes to allocate for bulk-out buffer (0 = end-point size)
	*  指向一个函数去决定多少个端口这个设备已经动态申请,这个将在probe 之后被调用
 	* @calc_num_ports: pointer to a function to determine how many ports this
 	*  device has dynamically.  It will be called after the probe()
 	*  callback is called, but before attach()
 	*  指向一个驱动的 probe 函数
 	* @probe: pointer to the driver's probe function.
 	*  这个函数将在设备被插入的时候被调用,但是这个设备必须完全被usb_serial系统完全初始化
 	*  This will be called when the device is inserted into the system,
 	*  but before the device has been fully initialized by the usb_serial
 	*  subsystem.  Use this function to download any firmware to the device,
 	*  or any other early initialization that might be needed.
 	*  Return 0 to continue on with the initialization sequence.  Anything
 	*  else will abort it.
 	*  指向驱动的attach 函数
 	* @attach: pointer to the driver's attach function.
 	*  这个函数将在usb_serial 结构体完全启动后被调用
 	*  This will be called when the struct usb_serial structure is fully set
 	*  set up.  Do any local initialization of the device, or any private
 	*  memory structure allocation at this point in time.
 	*  指向驱动断开连接函数,这个函数将在设备被断开活被释放的时候被调用
 	* @disconnect: pointer to the driver's disconnect function.  This will be
 	*  called when the device is unplugged or unbound from the driver.
 	*  指向驱动释放函数,这个将在usb_serial 数据结构体被销毁的时候被调用
 	* @release: pointer to the driver's release function.  This will be called
 	*  when the usb_serial data structure is about to be destroyed.
 	*  指向控制这个设备的usb_driver 结构体,这个是必须动态添加这个驱动在 sysfs里面
 	* @usb_driver: pointer to the struct usb_driver that controls this
 	*  device.  This is necessary to allow dynamic ids to be added to
 	*  the driver from sysfs.
 	*  这个结构体是定义了USB serial 驱动,他提供了所有的信息有关usb serial 核心代码需要。
 	*  如果这个功能被定义,那么当对应的 tty 端口要使用对应功能的时候被调用
 	* This structure is defines a USB Serial driver.  It provides all of
 	* the information that the USB serial core code needs.  If the function
 	* pointers are defined, then the USB serial core code will call them when
 	* the corresponding tty port functions are called.  If they are not
 	* called, the generic serial function will be used instead.
 	*
 	* The driver.owner field should be set to the module owner of this driver.
 	* The driver.name field should be set to the name of this driver (remember
 	* it will show up in sysfs, so it needs to be short and to the point.
 	* Using the module name is a good idea.)
 	*/
```
	struct usb_serial_driver {
	    const char *description;
	    const struct usb_device_id *id_table;
	    char    num_ports;                                                          
	    struct list_head    driver_list;
	    struct device_driver    driver;
	    struct usb_driver   *usb_driver;
	    struct usb_dynids   dynids;                                                 
	    size_t          bulk_in_size;
	    size_t          bulk_out_size;                                              
	    int (*probe)(struct usb_serial *serial, const struct usb_device_id *id);
	    int (*attach)(struct usb_serial *serial);
	    int (*calc_num_ports) (struct usb_serial *serial);                          
	    void (*disconnect)(struct usb_serial *serial);
	    void (*release)(struct usb_serial *serial);                                 
	    int (*port_probe)(struct usb_serial_port *port);
	    int (*port_remove)(struct usb_serial_port *port);                           
	    int (*suspend)(struct usb_serial *serial, pm_message_t message);
	    int (*resume)(struct usb_serial *serial);                                   
	    /* serial function calls */
	    /* Called by console and by the tty layer */
	    int  (*open)(struct tty_struct *tty, struct usb_serial_port *port);
	    void (*close)(struct usb_serial_port *port);
	    int  (*write)(struct tty_struct *tty, struct usb_serial_port *port,
	            const unsigned char *buf, int count);
	    /* Called only by the tty layer */
	    int  (*write_room)(struct tty_struct *tty);
	    int  (*ioctl)(struct tty_struct *tty,
	              unsigned int cmd, unsigned long arg);
	    void (*set_termios)(struct tty_struct *tty,
	            struct usb_serial_port *port, struct ktermios *old);
	    void (*break_ctl)(struct tty_struct *tty, int break_state);
	    int  (*chars_in_buffer)(struct tty_struct *tty);
	    void (*throttle)(struct tty_struct *tty);
	    void (*unthrottle)(struct tty_struct *tty);
	    int  (*tiocmget)(struct tty_struct *tty);
	    int  (*tiocmset)(struct tty_struct *tty,
	             unsigned int set, unsigned int clear);
	    int  (*get_icount)(struct tty_struct *tty,
	            struct serial_icounter_struct *icount);
	    /* Called by the tty layer for port level work. There may or may not
	       be an attached tty at this point */
	    void (*dtr_rts)(struct usb_serial_port *port, int on);
	    int  (*carrier_raised)(struct usb_serial_port *port);
	    /* Called by the usb serial hooks to allow the user to rework the
	       termios state */
	    void (*init_termios)(struct tty_struct *tty);
	    /* USB events */
	    void (*read_int_callback)(struct urb *urb);
	    void (*write_int_callback)(struct urb *urb);
	    void (*read_bulk_callback)(struct urb *urb);
	    void (*write_bulk_callback)(struct urb *urb);
	    /* Called by the generic read bulk callback */
	    void (*process_read_urb)(struct urb *urb);
	    /* Called by the generic write implementation */
	    int (*prepare_write_buffer)(struct usb_serial_port *port,
	                        void *dest, size_t size);
	};
#### * usb_serial 实现的各个函数描述
```c
	include/linux/usb/serial.h
	#  利用usb_serial_driver 里面的某一个成员找到整个结构体
	#define to_usb_serial_driver(d) \
	    container_of(d, struct usb_serial_driver, driver)
	#  register usb 串口驱动注册
	extern int  usb_serial_register(struct usb_serial_driver *driver);
	#  deregister 解除注册
	extern void usb_serial_deregister(struct usb_serial_driver *driver);
	extern void usb_serial_port_softint(struct usb_serial_port *port);
	#  usb serial 的probe 函数
	extern int usb_serial_probe(struct usb_interface *iface,
	                const struct usb_device_id *id);
	#  disconnect 断开连接函数
	extern void usb_serial_disconnect(struct usb_interface *iface);
	#  suspend 挂起,可以理解为睡眠状态
	extern int usb_serial_suspend(struct usb_interface *intf, pm_message_t message);
	#  resume 重新启动
	extern int usb_serial_resume(struct usb_interface *intf);
extern int ezusb_writememory(struct usb_serial *serial, int address,
                 unsigned char *data, int length, __u8 bRequest);
extern int ezusb_set_reset(struct usb_serial *serial, unsigned char reset_bit);
/* USB Serial console functions */
#ifdef CONFIG_USB_SERIAL_CONSOLE
#  usb serial 控制台初始化
extern void usb_serial_console_init(int debug, int minor);
#  退出
extern void usb_serial_console_exit(void);
#  断开连接
extern void usb_serial_console_disconnect(struct usb_serial *serial);
#else
static inline void usb_serial_console_init(int debug, int minor) { }
static inline void usb_serial_console_exit(void) { }
static inline void usb_serial_console_disconnect(struct usb_serial *serial) {}
#endif
/* Functions needed by other parts of the usbserial core */
#  usb serial 核心的其他部分功能
extern struct usb_serial *usb_serial_get_by_index(unsigned int minor);
#
extern void usb_serial_put(struct usb_serial *serial);
extern int usb_serial_generic_open(struct tty_struct *tty,
    struct usb_serial_port *port);
extern int usb_serial_generic_write(struct tty_struct *tty,
    struct usb_serial_port *port, const unsigned char *buf, int count);
extern void usb_serial_generic_close(struct usb_serial_port *port);
extern int usb_serial_generic_resume(struct usb_serial *serial);
extern int usb_serial_generic_write_room(struct tty_struct *tty);
extern int usb_serial_generic_chars_in_buffer(struct tty_struct *tty);
extern void usb_serial_generic_read_bulk_callback(struct urb *urb);
extern void usb_serial_generic_write_bulk_callback(struct urb *urb);
extern void usb_serial_generic_throttle(struct tty_struct *tty);
extern void usb_serial_generic_unthrottle(struct tty_struct *tty);
extern void usb_serial_generic_disconnect(struct usb_serial *serial);
extern void usb_serial_generic_release(struct usb_serial *serial);
extern int usb_serial_generic_register(int debug);
extern void usb_serial_generic_deregister(void);
extern int usb_serial_generic_submit_read_urb(struct usb_serial_port *port,
                         gfp_t mem_flags);
extern void usb_serial_generic_process_read_urb(struct urb *urb);
extern int usb_serial_generic_prepare_write_buffer(struct usb_serial_port *port,
                        void *dest, size_t size);
extern int usb_serial_handle_sysrq_char(struct usb_serial_port *port,
                    unsigned int ch);
extern int usb_serial_handle_break(struct usb_serial_port *port);
extern void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port,
                     struct tty_struct *tty,
                     unsigned int status);                                      
extern int usb_serial_bus_register(struct usb_serial_driver *device);
extern void usb_serial_bus_deregister(struct usb_serial_driver *device);    
extern struct usb_serial_driver usb_serial_generic_device;
extern struct bus_type usb_serial_bus_type;
extern struct tty_driver *usb_serial_tty_driver;
</br>
#### * cp210x.c
```c
	drivers/usb/serial/cp210x.c  (kernel 3.2.0)
	887 module_init(cp210x_init);   # 模块入口函数
	888 module_exit(cp210x_exit);   # 模块出口函数
	889
	890 MODULE_DESCRIPTION(DRIVER_DESC); # 模块描述
	891 MODULE_VERSION(DRIVER_VERSION);  # 模块版本
	892 MODULE_LICENSE("GPL");           # 遵循 GPL 协议
	893
	894 module_param(debug, bool, S_IRUGO | S_IWUSR);
	895 MODULE_PARM_DESC(debug, "Enable verbose debugging messages");                   
	# ---> 入口
	860 static int __init cp210x_init(void)
	861 {
	862     int retval;
	863               # usb 串口设备注册
	864     retval = usb_serial_register(&cp210x_device);
	865     if (retval)
	866         return retval; /* Failed to register */
	867               # usb 串口驱动注册
	868     retval = usb_register(&cp210x_driver);
	869     if (retval) {
	870         /* Failed to register */
	871         usb_serial_deregister(&cp210x_device);
	872         return retval;
	873     }
	874
	875     /* Success */
	876     printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
	877            DRIVER_DESC "\n");
	878     return 0;
	879 }     
	# ---> cp210x_device 结构体
	155 static struct usb_serial_driver cp210x_device = {
	156     .driver = {
	157         .owner =    THIS_MODULE,
	158         .name =     "cp210x",
	159     },
	160     .usb_driver     = &cp210x_driver,
	161     .id_table       = id_table,
	162     .num_ports      = 1,
	163     .bulk_in_size       = 256,
	164     .bulk_out_size      = 256,
	165     .open           = cp210x_open,      # 打开函数
	166     .close          = cp210x_close,     # 关闭函数
	167     .break_ctl      = cp210x_break_ctl,
	168     .set_termios        = cp210x_set_termios,
	169     .tiocmget       = cp210x_tiocmget,
	170     .tiocmset       = cp210x_tiocmset,
	171     .attach         = cp210x_startup,   # 设备启动函数
	172     .dtr_rts        = cp210x_dtr_rts
	173 };  
	#  ---> cp210x_driver 结构体
	147 static struct usb_driver cp210x_driver = {
	148     .name       = "cp210x",
	149     .probe      = usb_serial_probe,
	150     .disconnect = usb_serial_disconnect,
	151     .id_table   = id_table,
	152     .no_dynamic_id  =   1,
	153 };                                                                              
#### * 具体的各个函数实现解析
- open 函数
 
	//---> open 函数
	399 static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
	400 {
	401     int result;
	402
	403     dbg("%s - port %d", __func__, port->number);
	404        /* 这里面是通过USB传输控制信号使能cp210x  */
	405     if (cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_ENABLE)) {
	406         dev_err(&port->dev, "%s - Unable to enable UART\n",
	407                 __func__);
	408         return -EPROTO;
	409     }
	410
	411     result = usb_serial_generic_open(tty, port);
	412     if (result)
	413         return result;
	414
	415     /* Configure the termios structure */
	416     cp210x_get_termios(tty, port);  /*获取termios 信息,包括波特率数据位等信息*/
	417     return 0;
	418 }   
	// ---> cp210x_get_termios 函数
	438 static void cp210x_get_termios(struct tty_struct *tty,
	439     struct usb_serial_port *port)
	440 {
	441     unsigned int baud;
	442
	443     if (tty) {     // 获取相关终端的信息
	444         cp210x_get_termios_port(tty->driver_data,
	445             &tty->termios->c_cflag, &baud);
	446         tty_encode_baud_rate(tty, baud, baud);
	447     }
	448
	449     else {
	450         unsigned int cflag;
	451         cflag = 0;
	452         cp210x_get_termios_port(port, &cflag, &baud);
	453     }
	454 }                                                                               
	// ---> cp210x_get_termios_port 函数
	460 static void cp210x_get_termios_port(struct usb_serial_port *port,
	461     unsigned int *cflagp, unsigned int *baudp)
	462 {
	463     unsigned int cflag, modem_ctl[4];
	464     unsigned int baud;
	465     unsigned int bits;
	466
	467     dbg("%s - port %d", __func__, port->number);
	468     //  核心是通过这个函数进行获取相关的配置信息,读取到baud rate
	469     cp210x_get_config(port, CP210X_GET_BAUDDIV, &baud, 2);
	470     /* Convert to baudrate */
	471     if (baud)    // 波特率的计算
	472         baud = cp210x_quantise_baudrate((BAUD_RATE_GEN_FREQ + baud/2)/ baud);
	 		// ... ...
	475     *baudp = baud;
	476
	477     cflag = *cflagp;
	478                                              读取数据位
	479     cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
			// ... ...
	583     *cflagp = cflag;
	584 }
	585                                                                                 
	// --->  cp210x_get_config  函数
	248 /*
	249  * cp210x_get_config    从cp210x 配置寄存器中读取相关信息
	250  * Reads from the CP210x configuration registers
	251  * 'size' is specified in bytes.
	252  * 'data' is a pointer to a pre-allocated array of integers large
	253  * enough to hold 'size' bytes (with 4 bytes to each integer)
	254  */                 data 即是读到的数据
	255 static int cp210x_get_config(struct usb_serial_port *port, u8 request,
	256         unsigned int *data, int size)
	257 {
	258     struct usb_serial *serial = port->serial;
	259     __le32 *buf;
	260     int result, i, length;
	261
	262     /* Number of integers required to contain the array */
	263     length = (((size - 1) | 3) + 1)/4;
    264     // 申请一段空间
	265     buf = kcalloc(length, sizeof(__le32), GFP_KERNEL);
	266     if (!buf) {
	267         dev_err(&port->dev, "%s - out of memory.\n", __func__);
	268         return -ENOMEM;
	269     }
	270
	271     /* Issue the request, attempting to read 'size' bytes */
				    /*   通过USB的控制传输读取相关数据 ,读到buf里面 */
	272     result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
	273                 request, REQTYPE_DEVICE_TO_HOST, 0x0000,
	274                 0, buf, size, 300);
	275
	276     /* Convert data into an array of integers */
	277     for (i = 0; i < length; i++)
	278         data[i] = le32_to_cpu(buf[i]);
    279             // 转换成data
	280     kfree(buf);
	281
	282     if (result != size) {
	283         dbg("%s - Unable to send config request, "
	284                 "request=0x%x size=%d result=%d\n",
	285                 __func__, request, size, result);
	286         return -EPROTO;
	287     }
	288
	289     return 0;
	290 }                                                                               
- cp210x_break_ctl 函数解析
 
	// ---> cp210x_break_ctl 函数
	838 static void cp210x_break_ctl (struct tty_struct *tty, int break_state)
	839 {
	840     struct usb_serial_port *port = tty->driver_data;
	841     unsigned int state;
	842
	843     dbg("%s - port %d", __func__, port->number);
	844     if (break_state == 0)
	845         state = BREAK_OFF;
	846     else
	847         state = BREAK_ON;
	848     dbg("%s - turning break %s", __func__,
	849             state == BREAK_OFF ? "off" : "on");
	850     cp210x_set_config(port, CP210X_SET_BREAK, &state, 2);
	851 }     // 设置 break 的状态,如果break_state为0,state == BREAK_OFF
	// --->   // request表示要设置什么,data 表示设置的数据,size 为大小
	298 static int cp210x_set_config(struct usb_serial_port *port, u8 request,
	299         unsigned int *data, int size)
	300 {
	301     struct usb_serial *serial = port->serial;
	302     __le32 *buf;
	303     int result, i, length;
	304
	305     if (request == CP210X_SET_BAUDDIV)
	306     {
	307         printk("---------------baud  rate : %d\n", *data);
	308     }
	309     /* Number of integers required to contain the array */
	310     length = (((size - 1) | 3) + 1)/4;
	311     // 申请一段大小的空间
	312     buf = kmalloc(length * sizeof(__le32), GFP_KERNEL);
	313     if (!buf) {
	314         dev_err(&port->dev, "%s - out of memory.\n",
	315                 __func__);
	316         return -ENOMEM;
	317     }
	318
	319     /* Array of integers into bytes */
	320     for (i = 0; i < length; i++)
	321         buf[i] = cpu_to_le32(data[i]);
	322     // 判断数据大小是否大于2
	323     if (size > 2) {
	324         result = usb_control_msg(serial->dev,
	325                 usb_sndctrlpipe(serial->dev, 0),
	326                 request, REQTYPE_HOST_TO_DEVICE, 0x0000,
	327                 0, buf, size, 300);
	328     } else {
	329         result = usb_control_msg(serial->dev,
	330                 usb_sndctrlpipe(serial->dev, 0),
	331                 request, REQTYPE_HOST_TO_DEVICE, data[0],
	332                 0, NULL, 0, 300);
	333     }
	334     // 释放
	335     kfree(buf);
	336
	337     if ((size > 2 && result != size) || result < 0) {
	338         dbg("%s - Unable to send request, "
	339                 "request=0x%x size=%d result=%d\n",
	340                 __func__, request, size, result);
	341         return -EPROTO;
	342     }
	343
	344     return 0;
	345 }
- 配置函数 cp210x_set_termios
 
	639 static void cp210x_set_termios(struct tty_struct *tty,
	640         struct usb_serial_port *port, struct ktermios *old_termios)
	641 {
	642     unsigned int cflag, old_cflag;
	643     unsigned int baud = 0, bits;
	644     unsigned int modem_ctl[4];
	645
	646     dbg("%s - port %d", __func__, port->number);
	647
	648     if (!tty)
	649         return;
	650
	651     tty->termios->c_cflag &= ~CMSPAR;
	652     cflag = tty->termios->c_cflag;
	653     old_cflag = old_termios->c_cflag;
	654
	655     // 改变其波特率,这个是我根据kernel4.4.12的函数该过来的
	656     cp210x_change_speed(tty, port, old_termios);
	657     // 如果数据位需要升级
	658     /* If the number of data bits is to be updated */
	659     if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
				// 先读旧的数据位
	660         cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
	661         bits &= ~BITS_DATA_MASK;
	662         switch (cflag & CSIZE) {
	663         case CS5:
	664             bits |= BITS_DATA_5;
	665             dbg("%s - data bits = 5", __func__);
	666             break;
				// ... ...
	689         }              // 设置数据位
	690         if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
	691             dbg("Number of data bits requested "
	692                     "not supported by device\n");
	693     }
			// ... ...  8n1 115200  各种配置
	750
	751 }
- cp210x_tiocmget 函数
 
	797 static int cp210x_tiocmget (struct tty_struct *tty)
	798 {
	799     struct usb_serial_port *port = tty->driver_data;
	800     unsigned int control;
	801     int result;
	802
	803     dbg("%s - port %d", __func__, port->number);
	804
	805     cp210x_get_config(port, CP210X_GET_MDMSTS, &control, 1);
	806
	807     result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0)
	808         |((control & CONTROL_RTS) ? TIOCM_RTS : 0)
	809         |((control & CONTROL_CTS) ? TIOCM_CTS : 0)
	810         |((control & CONTROL_DSR) ? TIOCM_DSR : 0)
	811         |((control & CONTROL_RING)? TIOCM_RI  : 0)
	812         |((control & CONTROL_DCD) ? TIOCM_CD  : 0);
	813     将所有的状态 | 在一起返回结果
	814     dbg("%s - control = 0x%.2x", __func__, control);
	815
	816     return result;
	817 }
- cp210x_tiocmset 函数,设置相关的配置
 
	753 static int cp210x_tiocmset (struct tty_struct *tty,
	754         unsigned int set, unsigned int clear)
	755 {
	756     struct usb_serial_port *port = tty->driver_data;
	757     return cp210x_tiocmset_port(port, set, clear);
	758 }
	759  
	// ---> cp210x_tiocmset_port
	760 static int cp210x_tiocmset_port(struct usb_serial_port *port,
	761         unsigned int set, unsigned int clear)
	762 {
	763     unsigned int control = 0;
	764
	765     dbg("%s - port %d", __func__, port->number);
	766
	767     if (set & TIOCM_RTS) {
	768         control |= CONTROL_RTS;
	769         control |= CONTROL_WRITE_RTS;
	770     }
	771     if (set & TIOCM_DTR) {
	772         control |= CONTROL_DTR;
	773         control |= CONTROL_WRITE_DTR;
	774     }
	775     if (clear & TIOCM_RTS) {
	776         control &= ~CONTROL_RTS;
	777         control |= CONTROL_WRITE_RTS;
	778     }
	779     if (clear & TIOCM_DTR) {
	780         control &= ~CONTROL_DTR;
	781         control |= CONTROL_WRITE_DTR;
	782     }
    783
	784     dbg("%s - control = 0x%.4x", __func__, control);
	785     //  配置函数
	786     return cp210x_set_config(port, CP210X_SET_MHS, &control, 2);
	787 }
- cp210x_dtr_rts 函数
 
	789 static void cp210x_dtr_rts(struct usb_serial_port *p, int on)
	790 {
	791     if (on)
	792         cp210x_tiocmset_port(p, TIOCM_DTR|TIOCM_RTS, 0);
	793     else
	794         cp210x_tiocmset_port(p, 0, TIOCM_DTR|TIOCM_RTS);
	795 }
												
											usb 转 uart cp210x 驱动解析的更多相关文章
- Linux kernel 之 uart 驱动解析
		
uart 是一种非常之常见的总线,比如DEBUG信息输出,小数据量数据传输,485,以及蓝牙的控制,GPS,很多都是通过uart 进行数据传输并进行控制. 在Linux kernel 内部,uart ...
 - ubuntu arm妙算加载cp210x驱动
		
在妙算TK1上安装ros后,插上usb串口竟然没有驱动 无奈装 从http://www.silabs.com/products/mcu/pages/usbtouartbridgevcpdrivers. ...
 - 《网蜂A8实战演练》——8.Linux USB 主机控制器和设备驱动
		
USB 的全称是 Universal Serial Bus,顾名思义:通用串行总线. 提到总线,联想一下,在你心目中总线总是用来干嘛的?还记得 I2C 总线? I2C 总线上挂有二条信号线,一条是 S ...
 - 【转】USB协议架构及驱动架构
		
1. USB协议 1.1 USB主机系统 在USB主机系统中,通过根集线器与外部USB从机设备相连的处理芯片,称为USB主机控制器.USB主机控制器包含硬件.软件和固件一部分. 1.2 USB设备系统 ...
 - 实现Linux下的U盘(USB Mass Storage)驱动
		
如何实现Linux下的U盘(USB Mass Storage)驱动 版本:v0.7 How to Write Linux USB MSC (Mass Storage Class) Driver Cri ...
 - 如何实现Linux下的U盘(USB Mass Storage)驱动
		
如何实现Linux下的U盘(USB Mass Storage)驱动 版本:v0.7 How to Write Linux USB MSC (Mass Storage Class) Driver Cri ...
 - (转)支持 PS/2 与 USB 的键盘过滤驱动(可卸载)
		
Author: sinisterEmail: sinister@whitecell.orgHomepage:http://www.whitecell.org Date: 2007-02-2 ...
 - 乾坤合一~Linux设备驱动之USB主机和设备驱动
		
如果不能陪你到最后 是否后悔当初我们牵手 如果当初没能遇见你 现在的我 在哪里逗留 所有的爱都是冒险 那就心甘情愿 等待我们一生中 所有悬念 我一往情深的恋人 她是我的爱人 她给我的爱就像是 带着露水 ...
 - USB to UART
		
USB to UART: 芯片选用CH340: 电源部分连接两个电容分别是0.1微法和10微法: 晶振连接12MHz; D+ D- 连接单片机的D+ D-
 
随机推荐
- Spring MVC request flow
			
1. When we enter a URL in the browser, the request comes to the dispatcher servlet.The dispatcher se ...
 - PHP中的一些新特性
			
PHP 5.6 1.可以使用表达式定义常量 https://php.net/manual/zh/migration56.new-features.php 在之前的 PHP 版本中,必须使用静态值来定义 ...
 - HDUOJ--2079选课时间(题目已修改,注意读题)
			
选课时间(题目已修改,注意读题) Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
 - HDUOJ-----取(m堆)石子游戏
			
取(m堆)石子游戏 Time Limit : 3000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other) Total Sub ...
 - android通过USB使用真机调试程序
			
我的机子很老,开启个android模拟器都要好几分钟,但幸亏有个android的真机,这样直接在andriod手机上调试也是一个不错的选择.下面我就介绍 一下使用android手机来调试android ...
 - iOS CPU占有率达到了100%甚至更多,然后导致App闪退
			
今天在真机调试的过程中,发现了一个严重的问题,发现CPU的使用率竟然达到了100%,以至于会导致运行内存占用过高,被系统的看门狗机制给杀掉. 下面就讲一讲怎么去定位这个问题: 1.打开Xcode,把项 ...
 - wamp2.4-- 为WAMP中的mysql设置密码密码
			
WAMP安装好后,mysql密码是为空的,那么要如何修改呢?其实很简单,通过几条指令就行了,下面我就一步步来操作. 1.首先,通过WAMP打开mysql控制台.提示输入密码,因为现在是空,所以直接按回 ...
 - Linux时间子系统(一) 基本概念
			
本文使用Q & A的方式来和大家以前探讨一下时间的基本概念 一.什么是时间? 这个问题实在是太复杂了,我都不知道这是一个物理学.宇宙学.还是热力学异或是哲学问题,我只是想从几个侧面来了解一下时 ...
 - struts2 循环标签使用
			
struts2 counter循环标签的使用: struts2随提供了循环控制标签<s:iterator/>,,使用起来也比较方便,但在具体的应用中,也有不方便之处,他没有像struts1 ...
 - spring mvc 依赖包
			
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop&l ...