<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>记录点滴 &#187; 驱动</title>
	<atom:link href="http://ganquan.org/blog/category/driver/feed/" rel="self" type="application/rss+xml" />
	<link>http://ganquan.org/blog</link>
	<description>http://ganquan.org</description>
	<lastBuildDate>Sun, 05 Feb 2012 14:51:54 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>呃，内核报错</title>
		<link>http://ganquan.org/blog/2010/02/kernel-failure/</link>
		<comments>http://ganquan.org/blog/2010/02/kernel-failure/#comments</comments>
		<pubDate>Fri, 12 Feb 2010 11:08:53 +0000</pubDate>
		<dc:creator>ganquan</dc:creator>
				<category><![CDATA[驱动]]></category>

		<guid isPermaLink="false">http://ganquan.org/blog/?p=709</guid>
		<description><![CDATA[剛才測試驅動程序的時候內核報錯了，呃，只是一個小問題。 我第一次造成內核錯誤，截圖紀念一下。以後仔細檢查了再加載模塊，不過我覺得做驅動的話肯定會經常造成內核報錯。。。。。]]></description>
			<content:encoded><![CDATA[<p><span style="font-size: medium;">剛才測試驅動程序的時候內核報錯了，呃，只是一個小問題。</span></p>
<p><span style="font-size: medium;">我第一次造成內核錯誤，截圖紀念一下。以後仔細檢查了再加載模塊，不過我覺得做驅動的話肯定會經常造成內核報錯。。。。。</span></p>
<p><span style="font-size: medium;"><a href="http://ganquan.org/blog/wp-content/uploads/2010/02/2010-02-12-184519_470x246_scrot.png"><img class="aligncenter size-full wp-image-712" title="2010-02-12-184519_470x246_scrot" src="http://ganquan.org/blog/wp-content/uploads/2010/02/2010-02-12-184519_470x246_scrot.png" alt="" width="470" height="246" /></a><br />
</span></p>
]]></content:encoded>
			<wfw:commentRss>http://ganquan.org/blog/2010/02/kernel-failure/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>mini2440 button驱动分析</title>
		<link>http://ganquan.org/blog/2009/08/mini2440-button%e9%a9%b1%e5%8a%a8%e5%88%86%e6%9e%90/</link>
		<comments>http://ganquan.org/blog/2009/08/mini2440-button%e9%a9%b1%e5%8a%a8%e5%88%86%e6%9e%90/#comments</comments>
		<pubDate>Mon, 24 Aug 2009 17:34:21 +0000</pubDate>
		<dc:creator>ganquan</dc:creator>
				<category><![CDATA[嵌入式]]></category>
		<category><![CDATA[驱动]]></category>

		<guid isPermaLink="false">http://imganquan.org/blog/?p=372</guid>
		<description><![CDATA[基本上读懂了，有些几个地方还不明白。 由于wp-syntax插件显示代码实在让我看着眼睛难受，我决定换一种方式贴代码。点击下面的链接试试： mini2440 button驱动注释 mini2440 leds驱动注释]]></description>
			<content:encoded><![CDATA[<p>基本上读懂了，有些几个地方还不明白。</p>
<p>由于wp-syntax插件显示代码实在让我看着眼睛难受，我决定换一种方式贴代码。点击下面的链接试试：</p>
<p><a href="http://www.imganquan.org/code/modules/mini2440_buttons.c.html" target="_blank">mini2440 button驱动注释</a></p>
<p><a href="http://www.imganquan.org/code/modules/mini2440_leds.c.html" target="_blank">mini2440 leds驱动注释</a></p>
]]></content:encoded>
			<wfw:commentRss>http://ganquan.org/blog/2009/08/mini2440-button%e9%a9%b1%e5%8a%a8%e5%88%86%e6%9e%90/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>mini2440 LED驱动详解</title>
		<link>http://ganquan.org/blog/2009/08/mini2440-led%e9%a9%b1%e5%8a%a8%e8%af%a6%e8%a7%a3/</link>
		<comments>http://ganquan.org/blog/2009/08/mini2440-led%e9%a9%b1%e5%8a%a8%e8%af%a6%e8%a7%a3/#comments</comments>
		<pubDate>Fri, 21 Aug 2009 13:22:01 +0000</pubDate>
		<dc:creator>ganquan</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[嵌入式]]></category>
		<category><![CDATA[驱动]]></category>

		<guid isPermaLink="false">http://imganquan.org/blog/?p=357</guid>
		<description><![CDATA[从最简单的LED驱动入手，彻底细致的分析一遍mini2440的LED驱动。 官方手册上写，mini2440的四个LED与CPU的GPIO相连，LED1, LED2, LED3, LED4分别对应的 是GPB5, GPB6, GPB7, GPB8。那什么是GPIO呢？ GPIO是通用输入输出口的简称，只需要设置相应的CPU寄存器，就可以改变引脚的用途。 控制硬件，其实就是控制对应的寄存器。 四个LED的采用GPBCON寄存器上的4组2bit位来配置对应引脚的状态。4组2bit位的功能都 一样：00表示输入，01表示输出，10为特殊功能，11是保留的。 LED1对应的是GPB5, GPB5使用[11:10]位 LED2对应的是GPB6, GPB6使用[12:13]位 LED3对应的是GPB7, GPB7使用[14:15]位 LED4对应的是GPB8, GPB8使用[16:17]位 驱动需要先设置LED为输出状态，也就是要把对应的GPBX设置为01。 四个LED采用CPBDAT寄存器来对应4个LED的数值状态，GPBDAT5就对应GPB5，GPBDAT6就对 应GPB6，以此类推。手册上写低电平有效，就是说当GPBDAT寄存器位置为0时，LED就发光。 在三星官方的手册S3C2440.pdf中描述的寄存器状态如下： GPB8 [17:16] 00 = Input 01 = Output 10 = nXDREQ1 11 = Reserved GPB7 [15:14] 00 = Input 01 = Output 10 = nXDACK1 11 = Reserved GPB6 [13:12] [...]]]></description>
			<content:encoded><![CDATA[<p>从最简单的LED驱动入手，彻底细致的分析一遍mini2440的LED驱动。</p>
<p>官方手册上写，mini2440的四个LED与CPU的GPIO相连，LED1, LED2, LED3, LED4分别对应的<br />
是GPB5, GPB6, GPB7, GPB8。那什么是GPIO呢？</p>
<p>GPIO是通用输入输出口的简称，只需要设置相应的CPU寄存器，就可以改变引脚的用途。<br />
控制硬件，其实就是控制对应的寄存器。</p>
<p>四个LED的采用GPBCON寄存器上的4组2bit位来配置对应引脚的状态。4组2bit位的功能都<br />
一样：00表示输入，01表示输出，10为特殊功能，11是保留的。<br />
LED1对应的是GPB5, GPB5使用[11:10]位<br />
LED2对应的是GPB6, GPB6使用[12:13]位<br />
LED3对应的是GPB7, GPB7使用[14:15]位<br />
LED4对应的是GPB8, GPB8使用[16:17]位<br />
驱动需要先设置LED为输出状态，也就是要把对应的GPBX设置为01。</p>
<p>四个LED采用CPBDAT寄存器来对应4个LED的数值状态，GPBDAT5就对应GPB5，GPBDAT6就对<br />
应GPB6，以此类推。手册上写低电平有效，就是说当GPBDAT寄存器位置为0时，LED就发光。</p>
<p>在三星官方的手册S3C2440.pdf中描述的寄存器状态如下：<br />
GPB8 [17:16] 00 = Input 01 = Output<br />
10 = nXDREQ1 11 = Reserved<br />
GPB7 [15:14] 00 = Input 01 = Output<br />
10 = nXDACK1 11 = Reserved<br />
GPB6 [13:12] 00 = Input 01 = Output<br />
10 = nXBREQ 11 = reserved<br />
GPB5 [11:10] 00 = Input 01 = Output<br />
10 = nXBACK 11 = reserved</p>
<p>GPBDAT Bit Description<br />
GPB[10:0] [10:0] When the port is configured as input port, the corresponding<br />
bit is the pin state. When the port is configured as output port, the pin state is the same<br />
as the corresponding bit. When the port is configured as functional pin, the<br />
undefined value will be read.</p>
<p>贴出添加注释后的代码，非常简单的驱动。</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#include &lt;linux/miscdevice.h&gt;</span>
<span style="color: #339933;">#include &lt;linux/delay.h&gt;</span>
<span style="color: #339933;">#include &lt;asm/irq.h&gt;</span>
<span style="color: #339933;">#include &lt;mach/regs-gpio.h&gt;</span>
<span style="color: #339933;">#include &lt;mach/hardware.h&gt;</span>
<span style="color: #339933;">#include &lt;linux/kernel.h&gt;</span>
<span style="color: #339933;">#include &lt;linux/module.h&gt;</span>
<span style="color: #339933;">#include &lt;linux/init.h&gt;</span>
<span style="color: #339933;">#include &lt;linux/mm.h&gt;</span>
<span style="color: #339933;">#include &lt;linux/fs.h&gt;</span>
<span style="color: #339933;">#include &lt;linux/types.h&gt;</span>
<span style="color: #339933;">#include &lt;linux/delay.h&gt;</span>
<span style="color: #339933;">#include &lt;linux/moduleparam.h&gt;</span>
<span style="color: #339933;">#include &lt;linux/slab.h&gt;</span>
<span style="color: #339933;">#include &lt;linux/errno.h&gt;</span>
<span style="color: #339933;">#include &lt;linux/ioctl.h&gt;</span>
<span style="color: #339933;">#include &lt;linux/cdev.h&gt;</span>
<span style="color: #339933;">#include &lt;linux/string.h&gt;</span>
<span style="color: #339933;">#include &lt;linux/list.h&gt;</span>
<span style="color: #339933;">#include &lt;linux/pci.h&gt;</span>
<span style="color: #339933;">#include &lt;asm/uaccess.h&gt;</span>
<span style="color: #339933;">#include &lt;asm/atomic.h&gt;</span>
<span style="color: #339933;">#include &lt;asm/unistd.h&gt;</span>
&nbsp;
<span style="color: #339933;">#define DEVICE_NAME &quot;leds&quot; /* /dev目录下的设备名 */</span>
&nbsp;
<span style="color: #808080; font-style: italic;">/* GPBX */</span>
<span style="color: #993333;">static</span> <span style="color: #993333;">unsigned</span> <span style="color: #993333;">long</span> led_table <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span>
	S3C2410_GPB5<span style="color: #339933;">,</span>
	S3C2410_GPB6<span style="color: #339933;">,</span>
	S3C2410_GPB7<span style="color: #339933;">,</span>
	S3C2410_GPB8<span style="color: #339933;">,</span>
<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
<span style="color: #808080; font-style: italic;">/* GPBX的输出状态 */</span>
<span style="color: #993333;">static</span> <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> led_cfg_table <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span>
	S3C2410_GPB5_OUTP<span style="color: #339933;">,</span>
	S3C2410_GPB6_OUTP<span style="color: #339933;">,</span>
	S3C2410_GPB7_OUTP<span style="color: #339933;">,</span>
	S3C2410_GPB8_OUTP<span style="color: #339933;">,</span>
<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">/* 驱动接口函数
* ioctl的内核空间版本和用户控件的版本不同
* 内核版为：
* int (*ioctl)( struct inode *inode, struct file *file, unsigned int
* cmd, unsigned long arg);
* */</span>
<span style="color: #993333;">static</span> <span style="color: #993333;">int</span> sbc2440_leds_ioctl<span style="color: #009900;">&#40;</span>
	<span style="color: #993333;">struct</span> inode <span style="color: #339933;">*</span>inode<span style="color: #339933;">,</span>
	<span style="color: #993333;">struct</span> file <span style="color: #339933;">*</span>file<span style="color: #339933;">,</span>
	<span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> cmd<span style="color: #339933;">,</span>
	<span style="color: #993333;">unsigned</span> <span style="color: #993333;">long</span> arg<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	<span style="color: #b1b100;">switch</span><span style="color: #009900;">&#40;</span>cmd<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #b1b100;">case</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">:</span>
	<span style="color: #b1b100;">case</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">:</span>
		<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>arg <span style="color: #339933;">&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000dd;">4</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #b1b100;">return</span> <span style="color: #339933;">-</span>EINVAL<span style="color: #339933;">;</span> <span style="color: #808080; font-style: italic;">/* Invalid argument,非法参数 */</span>
		<span style="color: #009900;">&#125;</span>
       <span style="color: #808080; font-style: italic;">/* 设置数据寄存器GPBDAT
		* 低电平有效，用户程序传来的cmd取反
		* */</span>
		s3c2410_gpio_setpin<span style="color: #009900;">&#40;</span>led_table<span style="color: #009900;">&#91;</span>arg<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #339933;">!</span>cmd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">default</span><span style="color: #339933;">:</span>
		<span style="color: #b1b100;">return</span> <span style="color: #339933;">-</span>EINVAL<span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">/* 接口对象 */</span>
<span style="color: #993333;">static</span> <span style="color: #993333;">struct</span> file_operations dev_fops <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span>
	.<span style="color: #202020;">owner</span>	<span style="color: #339933;">=</span>	THIS_MODULE<span style="color: #339933;">,</span>
	.<span style="color: #202020;">ioctl</span>	<span style="color: #339933;">=</span>	sbc2440_leds_ioctl<span style="color: #339933;">,</span>
<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">/* 设备对象 */</span>
<span style="color: #993333;">static</span> <span style="color: #993333;">struct</span> miscdevice misc <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span>
	.<span style="color: #202020;">minor</span> <span style="color: #339933;">=</span> MISC_DYNAMIC_MINOR<span style="color: #339933;">,</span> <span style="color: #808080; font-style: italic;">/* 动态设备号 */</span>
	.<span style="color: #202020;">name</span> <span style="color: #339933;">=</span> DEVICE_NAME<span style="color: #339933;">,</span> <span style="color: #808080; font-style: italic;">/* 将在/dev目录生成led设备 */</span>
	.<span style="color: #202020;">fops</span> <span style="color: #339933;">=</span> <span style="color: #339933;">&amp;</span>amp<span style="color: #339933;">;</span>dev_fops<span style="color: #339933;">,</span> <span style="color: #808080; font-style: italic;">/* 驱动接口 */</span>
<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #993333;">static</span> <span style="color: #993333;">int</span> __init dev_init<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	<span style="color: #993333;">int</span> ret<span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #993333;">int</span> i<span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>i <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&amp;</span>lt<span style="color: #339933;">;</span> <span style="color: #0000dd;">4</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #808080; font-style: italic;">/*设置GPIO对应的配置寄存器GPIOCON为输出状态*/</span>
		s3c2410_gpio_cfgpin<span style="color: #009900;">&#40;</span>led_table<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> led_cfg_table<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #808080; font-style: italic;">/*设置GPIO对应的数据寄存器GPIODAT为低电平
		 *在模块加载结束后，四个LED应该是全部都是发光状态*/</span>
		s3c2410_gpio_setpin<span style="color: #009900;">&#40;</span>led_table<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	ret <span style="color: #339933;">=</span> misc_register<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>amp<span style="color: #339933;">;</span>misc<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #808080; font-style: italic;">/* 注册设备 */</span>
&nbsp;
	printk <span style="color: #009900;">&#40;</span>DEVICE_NAME<span style="color: #ff0000;">&quot;<span style="color: #000099; font-weight: bold;">\t</span>initialized<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #808080; font-style: italic;">/* dmesg */</span>
&nbsp;
	<span style="color: #b1b100;">return</span> ret<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #993333;">static</span> <span style="color: #993333;">void</span> __exit dev_exit<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	misc_deregister<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>amp<span style="color: #339933;">;</span>misc<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>                     <span style="color: #808080; font-style: italic;">/* 注销设备 */</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
module_init<span style="color: #009900;">&#40;</span>dev_init<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #808080; font-style: italic;">/* 声明加载模块初始化函数 */</span>
module_exit<span style="color: #009900;">&#40;</span>dev_exit<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #808080; font-style: italic;">/* 声明卸载模块清除函数 */</span>
MODULE_LICENSE<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;GPL&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #808080; font-style: italic;">/* 许可证声明 */</span>
MODULE_AUTHOR<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;FriendlyARM Inc.&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #808080; font-style: italic;">/* 作者信息 */</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://ganquan.org/blog/2009/08/mini2440-led%e9%a9%b1%e5%8a%a8%e8%af%a6%e8%a7%a3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>USB驱动学习笔记（2）</title>
		<link>http://ganquan.org/blog/2009/07/usb%e9%a9%b1%e5%8a%a8%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0%ef%bc%882%ef%bc%89/</link>
		<comments>http://ganquan.org/blog/2009/07/usb%e9%a9%b1%e5%8a%a8%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0%ef%bc%882%ef%bc%89/#comments</comments>
		<pubDate>Wed, 01 Jul 2009 09:02:59 +0000</pubDate>
		<dc:creator>ganquan</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[驱动]]></category>

		<guid isPermaLink="false">http://imganquan.org/blog/?p=183</guid>
		<description><![CDATA[1.期末考终于结束了，这下可以看看USB驱动了。 上次看了几个基本的数据结构，现在看看函数都是干嘛的。驱动被加载之后调用了usb_register函数，从这个函数又转到了usb_register_driver() 函数，然后在usb_register_driver()中调用了一个名为driver_register()的函数，从名字来看，显然是为了用来注册驱动的，这个函数的传入参数就是封装在struct usbdrv_wrap里面的driver成员。 在看driver_register()函数之前，注意到usb_register_driver()函数中一句： 725          new_driver-&#62;drvwrap.driver.bus = &#38;usb_bus_type; 这个bus就是驱动程序要去挂牌的地方。 现在进入driver_register()函数去看看。在driver_register() 中，调用了driver_find(drv-&#62;name, drv-&#62;bus)函数，这里是干啥呢？这里是先去驱动打算挂牌的地方先查找一下，这个驱动是否已经挂牌（注册）过了。在哪里查找呢？代码中写得很清楚，去bus-&#62;p-&#62;drivers_kset中查找，看到这里，我决定这里不要再继续展开细细的分析，否则永远都无法把内核看明白，有时候必须对细节很了解，有时候只要明白他的工作原理就可以，不必太细碎。简单的看，drivers_kset就是一个klist链表，链表的节点都是内核对象，也就是kobject。kset中的kobject可以是不同“类型”的(different “type”)，kset只是把一类需要用进行相同处理的kobject放在一起。driver_find函数其实也不干活，它是调用kset_find_obj函数去遍历链表根据drv-&#62;name去寻找，我不管找的过程，反正如果找到了driver_find()就返回指向已经注册的驱动的指针，如果没找到就返回NULL。 回到driver_register() ，如果驱动已经注册过了，那就退出好了。如果没有注册，接下来调用bus_add_driver(struct device_driver *drv) 函数注册驱动。这个函数有点长，主要作用就是把drv放到drv-&#62;bus-&#62;p-&#62;klist_drivers链表的尾部。到此就完成注册工作。 阅读了一些老手的笔记，看了一点内核代码，看了LDD，再加上自己的猜测，现在对驱动的工作机制有了一点认识。 内核在维护两条链表，一个用来记录devices,一个用来记录drivers。系统接电开机后，总线就扫一遍有哪些设备接到计算机上了，每个设备都对应一个设备对象，然后就把设备对象填入到记录devices的链表中。接着系统继续启动，到了加载驱动的过程，把驱动对象都填入到记录drivers的链表中。每加载一个驱动，就去遍历一次devices链表，看看有没有自己要服务的设备，如果有，就把该设备对象的驱动指针指向自己，同时把该设备对象加入到驱动程序维护的设备链表中，该设备链表记录了这个驱动能够服务的设备。这是在开机之前硬件就和计算机连接好的工作方式，但是现在更实用的是另外一种工作方式，就是热插拔。 热插拔意味着设备和驱动没有谁先谁后进入系统，因为都有可能。所以工作方式就是一旦有一个设备插入，总线把对应的设备对象加入到记录devices的链表后就去查找那条记录drivers链表，看看有没有能够驱动这个设备的驱动，如果有驱动对象和设备对象就互相指向，这样驱动就能为该设备服务。如果没有找到驱动呢？很简单，设备不工作呗。这个设备就只好等待自己需要的驱动被加载，驱动会去找他。反过来说，驱动可能在设备插入之前被加载，同样的，驱动没有在记录devices的链表上找到她要服务的设备，驱动也就只好等待设备被插入的时候来找她。 那么下一步，就应该看一下驱动和设备的联系过程了。假期就这样顺着设备和驱动的工作流程，慢慢看吧。希望在暑假结束时，能够对Linux平台的USB驱动有比较深入的理解和认识，不求自己能写出实际可用的驱动来，只要能明白驱动的工作机制就算是假期的收获了。]]></description>
			<content:encoded><![CDATA[<p>1.期末考终于结束了，这下可以看看USB驱动了。<br />
上次看了几个基本的数据结构，现在看看函数都是干嘛的。驱动被加载之后调用了usb_register函数，从这个函数又转到了usb_register_driver() 函数，然后在usb_register_driver()中调用了一个名为driver_register()的函数，从名字来看，显然是为了用来注册驱动的，这个函数的传入参数就是封装在struct usbdrv_wrap里面的driver成员。<br />
在看driver_register()函数之前，注意到usb_register_driver()函数中一句：</p>
<p>725          new_driver-&gt;drvwrap.driver.bus = &amp;usb_bus_type;</p>
<p>这个bus就是驱动程序要去挂牌的地方。</p>
<p>现在进入driver_register()函数去看看。在driver_register() 中，调用了driver_find(drv-&gt;name, drv-&gt;bus)函数，这里是干啥呢？这里是先去驱动打算挂牌的地方先查找一下，这个驱动是否已经挂牌（注册）过了。在哪里查找呢？代码中写得很清楚，去bus-&gt;p-&gt;drivers_kset中查找，看到这里，我决定这里不要再继续展开细细的分析，否则永远都无法把内核看明白，有时候必须对细节很了解，有时候只要明白他的工作原理就可以，不必太细碎。简单的看，drivers_kset就是一个klist链表，链表的节点都是内核对象，也就是kobject。kset中的kobject可以是不同“类型”的(different “type”)，kset只是把一类需要用进行相同处理的kobject放在一起。driver_find函数其实也不干活，它是调用kset_find_obj函数去遍历链表根据drv-&gt;name去寻找，我不管找的过程，反正如果找到了driver_find()就返回指向已经注册的驱动的指针，如果没找到就返回NULL。<br />
回到driver_register() ，如果驱动已经注册过了，那就退出好了。如果没有注册，接下来调用bus_add_driver(struct device_driver *drv) 函数注册驱动。这个函数有点长，主要作用就是把drv放到drv-&gt;bus-&gt;p-&gt;klist_drivers链表的尾部。到此就完成注册工作。<br />
阅读了一些老手的笔记，看了一点内核代码，看了LDD，再加上自己的猜测，现在对驱动的工作机制有了一点认识。<br />
内核在维护两条链表，一个用来记录devices,一个用来记录drivers。系统接电开机后，总线就扫一遍有哪些设备接到计算机上了，每个设备都对应一个设备对象，然后就把设备对象填入到记录devices的链表中。接着系统继续启动，到了加载驱动的过程，把驱动对象都填入到记录drivers的链表中。每加载一个驱动，就去遍历一次devices链表，看看有没有自己要服务的设备，如果有，就把该设备对象的驱动指针指向自己，同时把该设备对象加入到驱动程序维护的设备链表中，该设备链表记录了这个驱动能够服务的设备。这是在开机之前硬件就和计算机连接好的工作方式，但是现在更实用的是另外一种工作方式，就是热插拔。<br />
热插拔意味着设备和驱动没有谁先谁后进入系统，因为都有可能。所以工作方式就是一旦有一个设备插入，总线把对应的设备对象加入到记录devices的链表后就去查找那条记录drivers链表，看看有没有能够驱动这个设备的驱动，如果有驱动对象和设备对象就互相指向，这样驱动就能为该设备服务。如果没有找到驱动呢？很简单，设备不工作呗。这个设备就只好等待自己需要的驱动被加载，驱动会去找他。反过来说，驱动可能在设备插入之前被加载，同样的，驱动没有在记录devices的链表上找到她要服务的设备，驱动也就只好等待设备被插入的时候来找她。<br />
那么下一步，就应该看一下驱动和设备的联系过程了。假期就这样顺着设备和驱动的工作流程，慢慢看吧。希望在暑假结束时，能够对Linux平台的USB驱动有比较深入的理解和认识，不求自己能写出实际可用的驱动来，只要能明白驱动的工作机制就算是假期的收获了。</p>
]]></content:encoded>
			<wfw:commentRss>http://ganquan.org/blog/2009/07/usb%e9%a9%b1%e5%8a%a8%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0%ef%bc%882%ef%bc%89/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>USB驱动学习笔记（1）</title>
		<link>http://ganquan.org/blog/2009/06/usb%e9%a9%b1%e5%8a%a8%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0%ef%bc%881%ef%bc%89/</link>
		<comments>http://ganquan.org/blog/2009/06/usb%e9%a9%b1%e5%8a%a8%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0%ef%bc%881%ef%bc%89/#comments</comments>
		<pubDate>Tue, 16 Jun 2009 17:18:17 +0000</pubDate>
		<dc:creator>ganquan</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[驱动]]></category>

		<guid isPermaLink="false">http://imganquan.org/blog/?p=156</guid>
		<description><![CDATA[LDD 3rd 中文版实在是让我忍无可忍，USB驱动一章翻译得那是相当的晦涩，看得我云里雾里，索性扔下书来看代码，以后主要靠自己分析代码学习，多读网上前辈的笔记，这样不仅能加深对代码的理解，也看到了别人的思维角度，比抱着LDD 3rd啃强多了，开搞！ 新手自学笔记，比较罗嗦，冗长，学到什么地方就写到什么地方，没有具体的层次和顺序。写这个笔记的目的，仅仅是当作备忘和一个过程的记录，如果高手看到了谬误之处，敬请斧正。 全部代码、笔记、实验都在Debian GNU/Linux 下进行，内核版本如下： ganquan@debian:~$ uname -r 2.6.26-2-686 0.先从阅读usb-skeleton.c开始 ganquan@debian:~$ cat /usr/src/linux-source-2.6.26/drivers/usb/usb-skeleton.c &#124; wc -l 525 还好，只有525行。不算吓人。 从驱动程序的Hello World开始看： 504    static int __init usb_skel_init&#40;void&#41; &#160; 505    &#123; &#160; 506        int result; &#160; 507 &#160; 508        /* register this driver with the USB subsystem */ &#160; 509        result = [...]]]></description>
			<content:encoded><![CDATA[<p>LDD 3rd 中文版实在是让我忍无可忍，USB驱动一章翻译得那是相当的晦涩，看得我云里雾里，索性扔下书来看代码，以后主要靠自己分析代码学习，多读网上前辈的笔记，这样不仅能加深对代码的理解，也看到了别人的思维角度，比抱着LDD 3rd啃强多了，开搞！</p>
<p>新手自学笔记，比较罗嗦，冗长，学到什么地方就写到什么地方，没有具体的层次和顺序。写这个笔记的目的，仅仅是当作备忘和一个过程的记录，如果高手看到了谬误之处，敬请斧正。</p>
<p>全部代码、笔记、实验都在Debian GNU/Linux 下进行，内核版本如下：</p>
<p>ganquan@debian:~$ uname -r</p>
<p>2.6.26-2-686</p>
<p>0.先从阅读usb-skeleton.c开始</p>
<p>ganquan@debian:~$ cat /usr/src/linux-source-2.6.26/drivers/usb/usb-skeleton.c | wc -l</p>
<p>525</p>
<p>还好，只有525行。不算吓人。</p>
<p>从驱动程序的Hello World开始看：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #0000dd;">504</span>    <span style="color: #993333;">static</span> <span style="color: #993333;">int</span> __init usb_skel_init<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
&nbsp;
<span style="color: #0000dd;">505</span>    <span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #0000dd;">506</span>        <span style="color: #993333;">int</span> result<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">507</span>
&nbsp;
<span style="color: #0000dd;">508</span>        <span style="color: #808080; font-style: italic;">/* register this driver with the USB subsystem */</span>
&nbsp;
<span style="color: #0000dd;">509</span>        result <span style="color: #339933;">=</span> usb_register<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>skel_driver<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">510</span>        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>result<span style="color: #009900;">&#41;</span>
&nbsp;
<span style="color: #0000dd;">511</span>            err<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;usb_register failed. Error number %d&quot;</span><span style="color: #339933;">,</span> result<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">512</span>
&nbsp;
<span style="color: #0000dd;">513</span>        <span style="color: #b1b100;">return</span> result<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">514</span>    <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #0000dd;">515</span>
&nbsp;
<span style="color: #0000dd;">516</span>    <span style="color: #993333;">static</span> <span style="color: #993333;">void</span> __exit usb_skel_exit<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
&nbsp;
<span style="color: #0000dd;">517</span>    <span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #0000dd;">518</span>        <span style="color: #808080; font-style: italic;">/* deregister this driver with the USB subsystem */</span>
&nbsp;
<span style="color: #0000dd;">519</span>        usb_deregister<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>skel_driver<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">520</span>    <span style="color: #009900;">&#125;</span></pre></div></div>

<p>显然的，504行的usb_skel_init(void)就是insmod之后被运行的初始化函数，它只干了一件事：调用usb_register函数，注册了一个叫skel_driver的东西，skel_driver是在usb-skeleton.c 文件67行定义的一个usb_driver类型的结构体。再来看看usb_driver到底是何方妖孽。</p>
<p>在linux-source-2.6.26/include/linux/usb.h里面，991行到1015行定义了这个结构体如下：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #0000dd;">991</span> <span style="color: #993333;">struct</span> usb_driver <span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #0000dd;">992</span> <span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>name<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">993</span>
&nbsp;
<span style="color: #0000dd;">994</span> <span style="color: #993333;">int</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>probe<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> usb_interface <span style="color: #339933;">*</span>intf<span style="color: #339933;">,</span>
&nbsp;
<span style="color: #0000dd;">995</span> <span style="color: #993333;">const</span> <span style="color: #993333;">struct</span> usb_device_id <span style="color: #339933;">*</span>id<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">996</span>
&nbsp;
<span style="color: #0000dd;">997</span> <span style="color: #993333;">void</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>disconnect<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> usb_interface <span style="color: #339933;">*</span>intf<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">998</span>
&nbsp;
<span style="color: #0000dd;">999</span> <span style="color: #993333;">int</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>ioctl<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> usb_interface <span style="color: #339933;">*</span>intf<span style="color: #339933;">,</span> <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> code<span style="color: #339933;">,</span>
&nbsp;
<span style="color: #0000dd;">1000</span> <span style="color: #993333;">void</span> <span style="color: #339933;">*</span>buf<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">1001</span>
&nbsp;
<span style="color: #0000dd;">1002</span> <span style="color: #993333;">int</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>suspend<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> usb_interface <span style="color: #339933;">*</span>intf<span style="color: #339933;">,</span> pm_message_t message<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">1003</span> <span style="color: #993333;">int</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>resume<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> usb_interface <span style="color: #339933;">*</span>intf<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">1004</span> <span style="color: #993333;">int</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>reset_resume<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> usb_interface <span style="color: #339933;">*</span>intf<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">1005</span>
&nbsp;
<span style="color: #0000dd;">1006</span> <span style="color: #993333;">int</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>pre_reset<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> usb_interface <span style="color: #339933;">*</span>intf<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">1007</span> <span style="color: #993333;">int</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>post_reset<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> usb_interface <span style="color: #339933;">*</span>intf<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">1008</span>
&nbsp;
<span style="color: #0000dd;">1009</span> <span style="color: #993333;">const</span> <span style="color: #993333;">struct</span> usb_device_id <span style="color: #339933;">*</span>id_table<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">1010</span>
&nbsp;
<span style="color: #0000dd;">1011</span> <span style="color: #993333;">struct</span> usb_dynids dynids<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">1012</span> <span style="color: #993333;">struct</span> usbdrv_wrap drvwrap<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">1013</span> <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> no_dynamic_id<span style="color: #339933;">:</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">1014</span> <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> supports_autosuspend<span style="color: #339933;">:</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">1015</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span></pre></div></div>

<p>可见这个结构体包含了不少函数指针，通过名字大概猜了一下各个回调函数里面应该干啥，结构体中各个字段在内核代码中都有详细注释，不再一一叙述。总之，这个结构体现在看来，是用于标识我的USB驱动程序的。</p>
<p>搞清楚了传递给usb_register函数的参数，再看来看这个函数是干啥的。</p>
<p>还是在linux-source-2.6.26/include/linux/usb.h里面，有：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #0000dd;">1075</span> <span style="color: #993333;">static</span> <span style="color: #000000; font-weight: bold;">inline</span> <span style="color: #993333;">int</span> usb_register<span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> usb_driver <span style="color: #339933;">*</span>driver<span style="color: #009900;">&#41;</span>
&nbsp;
<span style="color: #0000dd;">1076</span> <span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #0000dd;">1077</span> <span style="color: #b1b100;">return</span> usb_register_driver<span style="color: #009900;">&#40;</span>driver<span style="color: #339933;">,</span> THIS_MODULE<span style="color: #339933;">,</span> KBUILD_MODNAME<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">1078</span> <span style="color: #009900;">&#125;</span></pre></div></div>

<p>这个内联函数居然又调用了另外一个函数，内核真是一个蜘蛛网，一点也不假，继续看：</p>
<p>usb_register_driver函数，第一个参数是用来标识USB驱动程序的usb_driver类型的结构体，第二、三个参数都是宏，但是第二个参数其实是一个module类型的结构体，第三个参数是字符指针，这两个参数暂时不分析。先放着就可以了。</p>
<p>接下来看一下usb_register_driver函数又干了什么。</p>
<p>在linux-source-2.6.26/driver/usb/core/driver.c中：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #0000dd;">715</span> <span style="color: #993333;">int</span> usb_register_driver<span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> usb_driver <span style="color: #339933;">*</span>new_driver<span style="color: #339933;">,</span> <span style="color: #993333;">struct</span> module <span style="color: #339933;">*</span>owner<span style="color: #339933;">,</span>
&nbsp;
<span style="color: #0000dd;">716</span> <span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>mod_name<span style="color: #009900;">&#41;</span>
&nbsp;
<span style="color: #0000dd;">717</span> <span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #0000dd;">718</span> <span style="color: #993333;">int</span> retval <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">719</span>
&nbsp;
<span style="color: #0000dd;">720</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>usb_disabled<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
&nbsp;
<span style="color: #0000dd;">721</span> <span style="color: #b1b100;">return</span> <span style="color: #339933;">-</span>ENODEV<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">722</span>
&nbsp;
<span style="color: #0000dd;">723</span> new_driver<span style="color: #339933;">-&gt;</span>drvwrap.<span style="color: #202020;">for_devices</span> <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">724</span> new_driver<span style="color: #339933;">-&gt;</span>drvwrap.<span style="color: #202020;">driver</span>.<span style="color: #202020;">name</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> <span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span> new_driver<span style="color: #339933;">-&gt;</span>name<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">725</span> new_driver<span style="color: #339933;">-&gt;</span>drvwrap.<span style="color: #202020;">driver</span>.<span style="color: #202020;">bus</span> <span style="color: #339933;">=</span> <span style="color: #339933;">&amp;</span>usb_bus_type<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">726</span> new_driver<span style="color: #339933;">-&gt;</span>drvwrap.<span style="color: #202020;">driver</span>.<span style="color: #202020;">probe</span> <span style="color: #339933;">=</span> usb_probe_interface<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">727</span> new_driver<span style="color: #339933;">-&gt;</span>drvwrap.<span style="color: #202020;">driver</span>.<span style="color: #202020;">remove</span> <span style="color: #339933;">=</span> usb_unbind_interface<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">728</span> new_driver<span style="color: #339933;">-&gt;</span>drvwrap.<span style="color: #202020;">driver</span>.<span style="color: #202020;">owner</span> <span style="color: #339933;">=</span> owner<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">729</span> new_driver<span style="color: #339933;">-&gt;</span>drvwrap.<span style="color: #202020;">driver</span>.<span style="color: #202020;">mod_name</span> <span style="color: #339933;">=</span> mod_name<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">730</span> spin_lock_init<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>new_driver<span style="color: #339933;">-&gt;</span>dynids.<span style="color: #202020;">lock</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">731</span> INIT_LIST_HEAD<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>new_drive<span style="color: #339933;">-&gt;</span>dynids.<span style="color: #202020;">list</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">732</span>
&nbsp;
<span style="color: #0000dd;">733</span> retval <span style="color: #339933;">=</span> driver_register<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>new_driver<span style="color: #339933;">-&gt;</span>drvwrap.<span style="color: #202020;">driver</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">734</span>
&nbsp;
<span style="color: #0000dd;">735</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>retval<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #0000dd;">736</span> pr_info<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%s: registered new interface driver %s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span>
&nbsp;
<span style="color: #0000dd;">737</span> usbcore_name<span style="color: #339933;">,</span> new_driver<span style="color: #339933;">-&gt;</span>name<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">738</span> usbfs_update_special<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">739</span> usb_create_newid_file<span style="color: #009900;">&#40;</span>new_driver<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">740</span> <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #0000dd;">741</span> printk<span style="color: #009900;">&#40;</span>KERN_ERR <span style="color: #ff0000;">&quot;%s: error %d registering interface &quot;</span>
&nbsp;
<span style="color: #0000dd;">742</span> <span style="color: #ff0000;">&quot; driver %s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span>
&nbsp;
<span style="color: #0000dd;">743</span> usbcore_name<span style="color: #339933;">,</span> retval<span style="color: #339933;">,</span> new_driver<span style="color: #339933;">-&gt;</span>name<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">744</span> <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #0000dd;">745</span>
&nbsp;
<span style="color: #0000dd;">746</span> <span style="color: #b1b100;">return</span> retval<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">747</span> <span style="color: #009900;">&#125;</span></pre></div></div>

<p>以上可见usb_register_driver函数中对usb_driver结构体的一个成员赋值，也就是对drvwrap成员。drvwrap是一个结构体，函数中对它的driver成员的各个字段进行赋值，并且usb_register_driver函数中还调用了一个driver_register函数，传入参数是drvwap的driver字段，看来这个drvwap成员分量不轻，现在去探究一下 这个usbdrv_wrap类型的drvwrap又是什么。</p>
<p>在linux-source-2.6.26/include/linux/usb.h中：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #0000dd;">934</span> <span style="color: #993333;">struct</span> usbdrv_wrap <span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #0000dd;">935</span> <span style="color: #993333;">struct</span> device_driver driver<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">936</span> <span style="color: #993333;">int</span> for_devices<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">937</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span></pre></div></div>

<p>可见，usbdrv_wrap只不过是一个对device_driver的封装，继续深入看一下device_driver又是什么。</p>
<p>在linux-source-2.6.26/include/linux/device.h中：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #0000dd;">120</span> <span style="color: #993333;">struct</span> device_driver <span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #0000dd;">121</span> <span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>name<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">122</span> <span style="color: #993333;">struct</span> bus_type <span style="color: #339933;">*</span>bus<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">123</span>
&nbsp;
<span style="color: #0000dd;">124</span> <span style="color: #993333;">struct</span> module <span style="color: #339933;">*</span>owner<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">125</span> <span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>mod_name<span style="color: #339933;">;</span> <span style="color: #808080; font-style: italic;">/* used for built-in modules */</span>
&nbsp;
<span style="color: #0000dd;">126</span>
&nbsp;
<span style="color: #0000dd;">127</span> <span style="color: #993333;">int</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>probe<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> device <span style="color: #339933;">*</span>dev<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">128</span> <span style="color: #993333;">int</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>remove<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> device <span style="color: #339933;">*</span>dev<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">129</span> <span style="color: #993333;">void</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>shutdown<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> device <span style="color: #339933;">*</span>dev<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">130</span> <span style="color: #993333;">int</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>suspend<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> device <span style="color: #339933;">*</span>dev<span style="color: #339933;">,</span> pm_message_t state<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">131</span> <span style="color: #993333;">int</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>resume<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> device <span style="color: #339933;">*</span>dev<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">132</span> <span style="color: #993333;">struct</span> attribute_group <span style="color: #339933;">**</span>groups<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">133</span>
&nbsp;
<span style="color: #0000dd;">134</span> <span style="color: #993333;">struct</span> driver_private <span style="color: #339933;">*</span>p<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">135</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span></pre></div></div>

<p>注意到device_driver的定义，134行又是一个driver_private结构体指针。非常有必要弄清楚这个结构体。</p>
<p>在linux-source-2.6.26/driver/base/base.h中，有：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #0000dd;">30</span> <span style="color: #993333;">struct</span> driver_private <span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #0000dd;">31</span> <span style="color: #993333;">struct</span> kobject kobj<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">32</span> <span style="color: #993333;">struct</span> klist klist_devices<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">33</span> <span style="color: #993333;">struct</span> klist_node knode_bus<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">34</span> <span style="color: #993333;">struct</span> module_kobject <span style="color: #339933;">*</span>mkobj<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">35</span> <span style="color: #993333;">struct</span> device_driver <span style="color: #339933;">*</span>driver<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">36</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span></pre></div></div>

<p>继续深入看看kobject又长什么样子。</p>
<p>在linux-source-2.6.26/include/linux/kobject.h中：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #0000dd;">60</span> <span style="color: #993333;">struct</span> kobject <span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #0000dd;">61</span> <span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>name<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">62</span> <span style="color: #993333;">struct</span> kref kref<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">63</span> <span style="color: #993333;">struct</span> list_head entry<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">64</span> <span style="color: #993333;">struct</span> kobject <span style="color: #339933;">*</span>parent<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">65</span> <span style="color: #993333;">struct</span> kset <span style="color: #339933;">*</span>kset<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">66</span> <span style="color: #993333;">struct</span> kobj_type <span style="color: #339933;">*</span>ktype<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">67</span> <span style="color: #993333;">struct</span> sysfs_dirent <span style="color: #339933;">*</span>sd<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">68</span> <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> state_initialized<span style="color: #339933;">:</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">69</span> <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> state_in_sysfs<span style="color: #339933;">:</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">70</span> <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> state_add_uevent_sent<span style="color: #339933;">:</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">71</span> <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> state_remove_uevent_sent<span style="color: #339933;">:</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #0000dd;">72</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span></pre></div></div>

<p>到底了，为啥到底了。去看看linux-source-2.6.26/Document/kobject.txt就知道为啥到底了。</p>
<p>那么kobject到底是个啥？</p>
<p>kobject就是组成Linux的设备模型的基本数据结构。kobject的任务有：</p>
<p>(1)对内核对象的计数，对应数据结构就是struct kref</p>
<p>(2)sysfs表述</p>
<p>(3)数据结构关联</p>
<p>(4)热插拔处理</p>
<p>对usb_driver一层一层的拨开，最后走到了kobject。在内核设计中也用到了面向对象的思想，kobject就可以当作基类，其他的类都是从kobject继承的，由于C语言不能像C++那样继承，所以就一次又一次的封装。</p>
<p>我现在搞清楚了各个struct之间的关系：</p>
<p>kobject&#8212;>driver_private&#8212;>device_driver&#8212;>usbdrv_wrap&#8212;>usb_driver</p>
<p>总结他们之间的关系如下：</p>
<p>kobject是Linux设备模型的基本数据结构，它被作为“基类”，其他“子类”都是“继承”了kobject。在我分析的这个例子中，driver_private就是一个“子类”，它直接“继承”了kobject。事实上，老版本的内核(2.6.10)直接把kobject放在device_driver中，新版本的内核则是用driver_private来存放kobject，然后再把driver_private封装在device_driver中。device_driver中除了包含driver_private，还有很多函数指针，也就是驱动程序需要提供的服务。接下来，usbdrv_wrap再次封装了device_driver，这次封装很简单，没有增加过多额外的字段。最后usb_driver来封装usbdrv_wrap，usb_driver中也有很多的函数指针。</p>
<p>这些结构体的各个字段，具体作用是什么？尤其是最接近“基类”的那些“子类”的以k开头的字段，都用来实现什么功能？</p>
<p>驱动程序提供的服务又是什么样子，以及USB驱动程序在总线上的挂牌过程，这些都需要弄明白，下一篇笔记看看能不能弄清楚。</p>
]]></content:encoded>
			<wfw:commentRss>http://ganquan.org/blog/2009/06/usb%e9%a9%b1%e5%8a%a8%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0%ef%bc%881%ef%bc%89/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>我的第一个Linux驱动程序</title>
		<link>http://ganquan.org/blog/2009/06/%e6%88%91%e7%9a%84%e7%ac%ac%e4%b8%80%e4%b8%aalinux%e9%a9%b1%e5%8a%a8%e7%a8%8b%e5%ba%8f/</link>
		<comments>http://ganquan.org/blog/2009/06/%e6%88%91%e7%9a%84%e7%ac%ac%e4%b8%80%e4%b8%aalinux%e9%a9%b1%e5%8a%a8%e7%a8%8b%e5%ba%8f/#comments</comments>
		<pubDate>Tue, 09 Jun 2009 15:02:23 +0000</pubDate>
		<dc:creator>ganquan</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[程序设计]]></category>
		<category><![CDATA[驱动]]></category>

		<guid isPermaLink="false">http://imganquan.org/blog/?p=104</guid>
		<description><![CDATA[实现一个虚拟设备“自增器”，该设备把写入的数据自增1。 ganquan@debian:~/Driver/01$ cat Add.h ganquan@debian:~/Driver/01$ cat Add.c 不变的Makefile： ganquan@debian:~/Driver/01$ cat Makefile 驱动加载脚本： ganquan@debian:~/Driver/01$ cat addload 驱动卸载脚本： ganquan@debian:~/Driver/01$ cat addunload 很简单的测试程序： ganquan@debian:~/Driver/01$ cat test.c 测试结果：]]></description>
			<content:encoded><![CDATA[<p>实现一个虚拟设备“自增器”，该设备把写入的数据自增1。</p>
<p>ganquan@debian:~/Driver/01$ cat Add.h</p>
<pre class="brush: cpp; title: ; notranslate">
#ifndef _MYDRIVER_H
#define _MYDRIVER_H

#include &lt;linux/cdev.h&gt;       /*cdev*/
#include &lt;linux/types.h&gt;    /*ssize_t*/

/*设备对象*/
struct Add
{
struct cdev MyChrDevice;    /*Char device structure*/
};

/*驱动程序要实现的函数*/
ssize_t Add_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
ssize_t Add_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);

#endif    /*_MYDRIVER_H*/
</pre>
<p>ganquan@debian:~/Driver/01$ cat Add.c</p>
<pre class="brush: cpp; title: ; notranslate">
#include &lt;linux/init.h&gt;			/*包含用于声明装载模块初始化和清除函数的宏*/
#include &lt;linux/module.h&gt;		/*包含装载模块需要的符号和函数定义*/
#include &lt;linux/kernel.h&gt;		/*printk()*/
#include &lt;linux/fs.h&gt;			/*申请设备号函数和数据结构,file_operation*/
#include &lt;linux/types.h&gt;		/*dev_t*/
#include &lt;linux/kdev_t.h&gt;		/*包含获取主设备号和次设备号的宏*/
#include &lt;linux/slab.h&gt;			/*kmalloc()*/
#include &lt;linux/cdev.h&gt;			/*cdev,cdev_init(),cdev_add()*/
#include &lt;asm/uaccess.h&gt;		/*copy_to_user(),copy_from_user()*/

#include &quot;Add.h&quot;

static int global_var = 0;
int Add_major = 0;	/*主设备号*/
int Add_minor = 0;	/*次设备号*/

struct Add *mydev;

struct file_operations Add_fops = {
	.owner = THIS_MODULE,
	.read = Add_read,
	.write = Add_write,
};

ssize_t Add_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
	if(copy_to_user(buf,&amp;global_var,sizeof(int)))
	{
		return -EFAULT;
	}

	return sizeof(int);
}
ssize_t Add_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
	if(copy_from_user(&amp;global_var,buf,sizeof(int)))
	{
		return -EFAULT;
	}
	if(global_var != 0)
		global_var++;

	return sizeof(int);
}

static int MyDriver_init(void)
{
	int ret;
	int devno;
	dev_t dev;

	/*申请设备号*/
	ret = alloc_chrdev_region(&amp;dev,0,1,&quot;Add&quot;);
	if(ret &lt; 0)
	{
		printk(KERN_ALERT &quot;Can not get dev_t\n&quot;);
	}
	else
	{
		Add_major = MAJOR(dev);		/*MAJOR in &lt;linux/kdev_t.h&gt;*/
		Add_minor = MINOR(dev);		/*MINOR in &lt;linux/kdev_t.h&gt;*/
	}
	/*申请设备号结束*/

	/*分配设备内存空间*/
	mydev = kmalloc(sizeof(struct Add),GFP_KERNEL);
	if(!mydev)
	{
		printk(KERN_ALERT &quot;kmalloc error\n&quot;);
	}
	/*分配内存空间结束*/

	/*初始化内存空间*/
	memset(mydev,0,sizeof(struct Add));

	/*注册字符设备*/
	devno = MKDEV(Add_major,Add_minor);
	cdev_init(&amp;mydev-&gt;MyChrDevice,&amp;Add_fops);
	mydev-&gt;MyChrDevice.owner = THIS_MODULE;
	mydev-&gt;MyChrDevice.ops = &amp;Add_fops;
	ret = cdev_add(&amp;mydev-&gt;MyChrDevice,devno,1);
	if(ret)
		printk(KERN_ALERT &quot;Error %d adding Add\n&quot;,ret);
	/*注册字符设备结束*/
	return 0;
}

static void MyDriver_exit(void)
{
	dev_t devno;

    devno = MKDEV(Add_major,Add_minor);
	cdev_del(&amp;mydev-&gt;MyChrDevice);
	unregister_chrdev_region(devno,1);
	kfree(mydev);
}

module_init(MyDriver_init);	/*声明模块加载初始化函数*/
module_exit(MyDriver_exit);	/*声明模块卸载清除函数*/

MODULE_LICENSE(&quot;GPL&quot;);		/*驱动许可证协议*/
MODULE_AUTHOR(&quot;GanQuan&quot;);	/*作者*/
MODULE_VERSION(&quot;0.0.1&quot;);	/*版本号*/
</pre>
<p>不变的Makefile：<br />
ganquan@debian:~/Driver/01$ cat Makefile</p>
<pre class="brush: plain; title: ; notranslate">
obj-m := Add.o
	KDIR ?= /lib/modules/$(shell uname -r)/build
	PWD := $(shell pwd)
all:
	    $(MAKE) -C $(KDIR) M=$(PWD)

.PHONY:clean
clean:
	    rm -f *.mod.c *.mod.o *.ko *.o *.tmp_versions
</pre>
<p>驱动加载脚本：<br />
ganquan@debian:~/Driver/01$ cat addload</p>
<pre class="brush: bash; title: ; notranslate">
#!/bin/bash
#author ganqan
#	imganquan@gmail.com
#load a module

module=&quot;Add&quot;
device=&quot;Add&quot;
mode=&quot;777&quot;

/sbin/insmod ./${module}.ko || exit 1

major=$(awk &quot;\$2==\&quot;$module\&quot; {print \$1}&quot; /proc/devices)

mknod /dev/${module} c $major 0
chmod $mode /dev/${device}

devinfo=`ls -l /dev/${device}`

echo &quot;insmod	:$module.ko&quot;
echo &quot;major	:$major&quot;
echo &quot;devinfo	:$devinfo&quot;
</pre>
<p>驱动卸载脚本：<br />
ganquan@debian:~/Driver/01$ cat addunload</p>
<pre class="brush: bash; title: ; notranslate">
#!/bin/bash
#author ganquan
#	imganquan@gmail.com
#unload a module

module=&quot;Add&quot;
device=&quot;Add&quot;
/sbin/rmmod $module || exit 1
rm -f /dev/${device}
</pre>
<p>很简单的测试程序：<br />
ganquan@debian:~/Driver/01$ cat test.c</p>
<pre class="brush: cpp; title: ; notranslate">
#include &lt;sys/stat.h&gt;
#include &lt;stdio.h&gt;
#include &lt;fcntl.h&gt;
int main()
{
	int fd,num;
	fd = open(&quot;/dev/Add&quot;, O_RDWR, S_IRUSR | S_IWUSR);
	if (fd != -1)
	{
		read(fd, &amp;num, sizeof(int));
		printf(&quot;The MyDevice is %d\n&quot;, num);

		printf(&quot;Please input the num written to MyDevice\n&quot;);
		scanf(&quot;%d&quot;, &amp;num);
		write(fd, &amp;num, sizeof(int));
		read(fd, &amp;num, sizeof(int));
		printf(&quot;The MyDevice is %d\n&quot;, num);
		close(fd);
	}
	else
		printf(&quot;Device open failure\n&quot;);
		return 0;
}
</pre>
<p>测试结果：</p>
<pre class="brush: bash; title: ; notranslate">
ganquan@debian:~/Driver/01$ sudo ./addload
insmod	:Add.ko
major	:249
devinfo	:crwxrwxrwx 1 root root 249, 0 2009-06-09 22:55 /dev/Add
ganquan@debian:~/Driver/01$ ./test
The MyDevice is 0
Please input the num written to MyDevice
7
The MyDevice is 8
ganquan@debian:~/Driver/01$ sudo ./addunload
</pre>
]]></content:encoded>
			<wfw:commentRss>http://ganquan.org/blog/2009/06/%e6%88%91%e7%9a%84%e7%ac%ac%e4%b8%80%e4%b8%aalinux%e9%a9%b1%e5%8a%a8%e7%a8%8b%e5%ba%8f/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

