欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

usb 转 uart cp210x 驱动解析

发布时间:2025/5/22 编程问答 41 豆豆
生活随笔 收集整理的这篇文章主要介绍了 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 实现的各个函数描述

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;

* cp210x.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_port760 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 驱动解析的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。