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_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 }