<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></title> 
<link>http://jackxiang.com/index.php</link> 
<description><![CDATA[赢在IT，Playin' with IT,Focus on Killer Application,Marketing Meets Technology.]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></copyright>
<item>
<link>http://jackxiang.com/post//</link>
<title><![CDATA[有空了解：浅析ttyUSB驱动usb_serial_driver-ch341]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[WEB2.0]]></category>
<pubDate>Wed, 30 Jun 2010 14:45:38 +0000</pubDate> 
<guid>http://jackxiang.com/post//</guid> 
<description>
<![CDATA[ 
	浅析ttyUSB驱动usb_serial_driver-ch341<br/><br/>sudo insmod /lib/modules/2.6.22-14-generic/kernel/drivers/usb/serial/usbserial.ko vendor=0x8086 product=0xd001<br/>安装之后可以通过ttyUSBx与任何usb设备进行数据传输，但是如果usb设备端接收pc下发的数据速度跟不上，比如设备端可能需要处理pc下发的数据用掉一段时间，这时tty-&gt;driver-&gt;write(tty, b, nr);可能返回0，也就是在执行usb_serial_generic_write()函数时，因为port-&gt;write_urb_busy = 1;发送正繁忙，进而会执行schedule让出cpu，虽然使用usbserial.ko模块可以与任何usb设备进行通信，但是当进行大量数据传输时，速度并不乐观，下面会做一个粗略的分析，找到了速度慢的原因，和一个保守的解决方案[gliethttp_20080526]。<br/><br/>usb_register(&amp;ch341_driver)-&gt;含有如下两行语句，<br/>drvwrap.driver.bus = &amp;usb_bus_type;<br/>drvwrap.driver.probe = usb_probe_interface;<br/><br/>usb总线发现硬件之后，会在恰当的时候调用__driver_attach()函数，__driver_attach()会调用usb_bus_type.match(),对于usb设备一定返回成功,<br/>然后执行really_probe(dev, drv);暂时将dev-&gt;driver = drv;之后执行<br/>device_driver-&gt;probe函数,对于usb总线上的设备就是调用usb_probe_interface，<br/>usb_probe_interface函数会搜索所有usb总线上挂接的usb_driver驱动，检查是否和该dev设备的id匹配，如果匹配，那么调用usb_driver-&gt;probe()函数，对于usbserial驱动来说，就是调用usb_serial_probe，在该函数中如果<br/>usbserial所属的usb_serial_driver驱动包含probe函数,那么调用之，对于ch341没有，在usb_serial_probe函数中分配完port对应的管道缓冲区之后，执行usb_serial_driver-&gt;attach()函数，对于ch341来说就是ch341_attach，使用control控制管道，发送波特率设置参数给ch341串口设备，紧接着调用get_free_serial (serial, num_ports, &amp;minor)；<br/>该函数会查找serial_table[i]的空缺位置，然后serial-&gt;minor = minor;于是serial有了次设备号minor,<br/>应用程序会调用serial_open()-&gt;serial-&gt;type-&gt;open(port, filp);也就是ch341_open详细的打开serial串口,<br/>对于ch341，就是将波特率配置值发送给串口ch341设备而已，<br/>用户调用serial_write()来向ch341发送串口数据,serial_write()会调用port-&gt;serial-&gt;type-&gt;write(port, buf, count);因为ch341没有定义自己的write写函数，所以会调用usb_serial_generic_write函数实现具体的发送操作，但每次最多只能发送一个输出端点大小的数据，具体发送流程是这样的：<br/><br/>sys_write()-&gt;vfs_write()-&gt;<br/>drivers/char/tty_io.c-&gt;tty_fops.tty_write()-&gt;do_tty_write()-&gt;<br/>tty_ldisc_N_TTY.write_chan()-&gt;调用<br/>tty-&gt;driver-&gt;write(tty, b, nr)-&gt;<br/>serial_write(struct tty_struct * tty, const unsigned char *buf, int count)-&gt;<br/>port-&gt;serial-&gt;type-&gt;write(port, buf, count)-&gt;<br/>usb_serial_generic_write()<br/><br/>对于open的安装过程简单来说是这样的<br/>sys_open()-&gt;tty_open()-&gt;<br/>然后设置操作函数集filp-&gt;f_op = &amp;tty_fops;<br/>这样操作函数集tty_fops会调用ch341的驱动，因为ch341没有设置read和write函数，所以对于ch341的ttyUSBx写操作，最终调用usb_serial_generic_write，同理读调用usb_serial_generic_read，对于generic类型串口读写函数，每次最大收发字节数为相应端点的端点大小，<br/>tty_write会检测所有的counts待收发数据是否全部完成，如果循环完成了，tty_write返回，进而vfs_write返回，进而sys_write返回，于是read()和write()<br/><br/>对于usb_serial串口发送数据速度超级慢，不是因为usb_serial_generic_write函数速度慢，它的速度已经是全速了，问题主要出在调用usb_serial_generic_write函数的上级函数中，主要原因在这里：<br/>do_tty_write()<br/>...<br/>chunk = 2048;<br/>...<br/>&nbsp;&nbsp;&nbsp;&nbsp;/* Do the write .. */<br/>&nbsp;&nbsp;&nbsp;&nbsp;for (;;) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;size_t size = count;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (size &gt; chunk)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;size = chunk;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret = -EFAULT;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (copy_from_user(tty-&gt;write_buf, buf, size))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lock_kernel();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret = write(tty, file, tty-&gt;write_buf, size);<br/>//gliethttp_20080526<br/>//write就是<br/>//write_chan()，在write_chan函数中<br/>//while (1) &#123;<br/>// while (nr &gt; 0) &#123;<br/>// c = tty-&gt;driver-&gt;write(tty, b, nr);<br/>//因为pc主机速度很快，所以c经常会等于0，说明上一次提交的发送数据还没有发送完毕，busy中，所以返回0<br/>// if (c &lt; 0) &#123;<br/>// retval = c;<br/>// goto break_out;<br/>// &#125;<br/>// if (!c)<br/>// break;<br/>// b += c;<br/>// nr -= c;<br/>// &#125;<br/>// schedule();//当c==0时，也就是usb通信管道繁忙时，将会执行schedule<br/>//&#125;<br/>//对于ch341或者其他的usbserial硬件,c等于out端点大小，一般为16字节或者64字节，大多数等于0，<br/>//所以上面copy_from_user(tty-&gt;write_buf, buf, size)拷贝了2k的数据，<br/>//将在write(tty, file, tty-&gt;write_buf, size);中以端点大小为单位，通过tty-&gt;driver-&gt;write一组组的循环发送出去<br/>//当c==0时，也就是usb通信管道繁忙时，将会执行schedule，内核调度出本task之后，什么时候返回是未知的，因为当前<br/>//的task没有等待任何事件，所以属于变相告诉kernel，“我现在闲的很，什么事情都没有了，kernel你让其他task执行吧，<br/>//如果没有任何人需要cpu的时候，你就回过头来看看我，不用把我放在心上了”，而事实上本task还有很多数据在堆积，等待发送处理，<br/>//但就是因为没有使用wakeup之类的咚咚机制，来等待事件完成后的即时唤醒，傻傻的让出cpu，<br/>//所以当连续发送大量数据的时候，这种切换出去、切换回来时间不确定性会导致速度指数级下降！<br/>//所以我觉得，在tty-&gt;driver-&gt;write(tty, b, nr)中使用信号等待机制，等待数据发送完毕，这将使得数据发送速度指数级提升！<br/>//或者直接使用usb_bulk_msg完成1个端点大小数据发送，这样可以一直等到数据发送完毕！<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unlock_kernel();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (ret &lt;= 0)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;written += ret;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buf += ret;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;count -= ret;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (!count)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret = -ERESTARTSYS;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (signal_pending(current))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cond_resched();<br/>//为了均衡系统，尝试调度出自己，这是在为系统的其他线程做好事，这样的不霸道行为也是降低速度的原因之一！<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>因为是内核研读笔记，比较凌乱，凑活了[gliethttp_20080526]<br/>来源：http://blog.chinaunix.net/u1/38994/showart_706533.html
]]>
</description>
</item><item>
<link>http://jackxiang.com/post//#blogcomment</link>
<title><![CDATA[[评论] 有空了解：浅析ttyUSB驱动usb_serial_driver-ch341]]></title> 
<author> &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate> 
<guid>http://jackxiang.com/post//#blogcomment</guid> 
<description>
<![CDATA[ 
	
]]>
</description>
</item>
</channel>
</rss>