今天我们来看看linux kernel driver中的glue:sdio_uart.c。
顾名思义,这个文件把以TTY和sdio设备驱动贴合在一起,实现了TTY(一般为串口)到sdio设备的转
换,也就是TTY over sdio。该文件实现的功能框图如下:
+-------------------+---------------------+
| | |
| | TTY device |
| | |
| sdio_uart.c +---------------------+
| | |
| | sdio device |
| | |
+------------------+---------------------+
我们先来看一下sdio_uart_port这个结构:
67 struct sdio_uart_port {
68 struct tty_port port; //TTY port
69 unsigned int index;
70 struct sdio_func *func; //sdio device
71 struct mutex func_lock;
72 struct task_struct *in_sdio_uart_irq;
73 unsigned int regs_offset;
74 struct kfifo xmit_fifo;
75 spinlock_t write_lock;
76 struct uart_icount icount;
77 unsigned int uartclk;
78 unsigned int mctrl;
79 unsigned int rx_mctrl;
80 unsigned int read_status_mask;
81 unsigned int ignore_status_mask;
82 unsigned char x_char;
83 unsigned char ier;
84 unsigned char lcr;
85 };
在这个结构中,我们可以看到两个很重要的成员:struct tty_port port;和 struct sdio_func
*func;由此可知,这个结构是TTY到sdio func的枢纽,它是胶水层的主要结构。
我们简单来看看,这两个结构之间设备和对应的驱动序列chart:
sdio_uart_init
+
|
+---> alloc_tty_driver
|
|
++--> tty_register_driver
|
|
+---> sdio_register_driver
可以看到,在init中,就是向tty core和sdio core分别注册了driver,驱动的名字都是
叫“sdio_uart”;接下去,就是在BUS(不是公交车)上等待另一半的到来了。。。。
若有sdio func设备调用了:
302 /*
303 * Register a new SDIO function with the driver model.
304 */
305 int sdio_add_func(struct sdio_func *func)
306 {
307 int ret;
308
309 dev_set_name(&func->dev, "%s:%d", mmc_card_id(func->card), func->num);
310
311 ret = device_add(&func->dev);
312 if (ret == 0)
313 sdio_func_set_present(func);
314
315 return ret;
316 }
那么,sdio的driver中的probe将被调用
1069 static int sdio_uart_probe(struct sdio_func *func,
1070 const struct sdio_device_id *id)
1071 {
1072 struct sdio_uart_port *port;
1073 int ret;
1074
//媒人婆出现了
1075 port = kzalloc(sizeof(struct sdio_uart_port), GFP_KERNEL);
1076 if (!port)
1077 return -ENOMEM;
//一手拉住了sdio function
1123 port->func = func;
1124 sdio_set_drvdata(func, port);
//一手拉住了tty port
1125 tty_port_init(&port->port);
1126 port->port.ops = &sdio_uart_port_ops;
1127
1128 ret = sdio_uart_add_port(port);
1129 if (ret) {
1130 kfree(port);
1131 } else {
1132 struct device *dev;
//在这里增加了TTY device的注册
1133 dev = tty_port_register_device(&port->port,
1134 sdio_uart_tty_driver, port->index, &func->dev);
1135 if (IS_ERR(dev)) {
1136 sdio_uart_port_remove(port);
1137 ret = PTR_ERR(dev);
1138 }
1139 }
1140
1141 return ret;
1142 }
接下来,我们简单来看看,tty 调用后,如何转换为sdio操作的。
1048 static const struct tty_operations sdio_uart_ops = {
1049 .open = sdio_uart_open,
1050 .close = sdio_uart_close,
1051 .write = sdio_uart_write,
1052 .write_room = sdio_uart_write_room,
1053 .chars_in_buffer = sdio_uart_chars_in_buffer,
1054 .send_xchar = sdio_uart_send_xchar,
1055 .throttle = sdio_uart_throttle,
1056 .unthrottle = sdio_uart_unthrottle,
1057 .set_termios = sdio_uart_set_termios,
1058 .hangup = sdio_uart_hangup,
1059 .break_ctl = sdio_uart_break_ctl,
1060 .tiocmget = sdio_uart_tiocmget,
1061 .tiocmset = sdio_uart_tiocmset,
1062 .install = sdio_uart_install,
1063 .cleanup = sdio_uart_cleanup,
1064 .proc_fops = &sdio_uart_proc_fops,
1065 };
sdio_uart_write
+
|
+---> sdio_uart_start_tx
|
|
++--> sdio_out
|
|
+---> sdio_writeb
|
|
+---> mmc_io_rw_direct
|
|
+---> mmc_io_rw_direct_host
|
|
+---> mmc_wait_for_cmd(host, &cmd, 0);
选择好host,封装好cmd,GO