⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 linux设备驱动程序学习(4)-高级字符驱动程序操作[(1)ioctl and llseek] - linux设备驱动程序 - tekkaman ninja.htm

📁 Linux设备驱动程序学习(4)-高级字符驱动程序操作[(1)ioctl and llseek] - Linux设备驱动程序.rar
💻 HTM
📖 第 1 页 / 共 5 页
字号:
                                </FONT></SPAN></CODE></P></TD></TR></TBODY></TABLE></P><PRE class=programlisting></PRE>
                              <P>第一个参数应当是 VERIFY_READ(读)或VERIFY_WRITE(读写);addr 
                              参数为用户空间地址,size 为字节数,可使用sizeof()。access_ok 返回一个布尔值: 
                              1 是成功(存取没问题)和 0 是失败(存取有问题)。如果它返回假,驱动应当返回 -EFAULT 
                              给调用者。</P></DIV>
                              <DT>
                              <DIV>
                              <P>注意:首先, <FONT 
                              color=#ff0000>access_ok</FONT>不做校验内存存取的完整工作; 
                              它只检查内存引用是否在这个进程有合理权限的内存范围中,且确保这个地址不指向内核空间内存。其次,大部分驱动代码不需要真正调用 
                              access_ok,而直接使用<SPAN 
                              class=term><SPAN>put_user(datum, ptr)和<SPAN 
                              class=term><SPAN>get_user(local, 
                              ptr),它们带有校验的功能,确保进程能够写入给定的内存地址,成功时返回 0, 并且在错误时返回 
                              -EFAULT.。 
                              <TABLE style="BORDER-COLLAPSE: collapse" 
                              borderColor=#999999 cellSpacing=0 cellPadding=0 
                              width="95%" bgColor=#f1f1f1 border=1>
                                <TBODY>
                                <TR>
                                <TD>
                                <P 
                                style="MARGIN: 5px; LINE-HEIGHT: 150%"><CODE><SPAN 
                                style="COLOR: rgb(0,0,0)"><FONT 
                                face=新宋体>put_user<SPAN 
                                style="COLOR: rgb(0,0,204)">(</SPAN>datum<SPAN 
                                style="COLOR: rgb(0,0,204)">,</SPAN> ptr<SPAN 
                                style="COLOR: rgb(0,0,204)">)</SPAN> 
                                <BR>__put_user<SPAN 
                                style="COLOR: rgb(0,0,204)">(</SPAN>datum<SPAN 
                                style="COLOR: rgb(0,0,204)">,</SPAN> ptr<SPAN 
                                style="COLOR: rgb(0,0,204)">)</SPAN> 
                                <BR>get_user<SPAN 
                                style="COLOR: rgb(0,0,204)">(</SPAN>local<SPAN 
                                style="COLOR: rgb(0,0,204)">,</SPAN> ptr<SPAN 
                                style="COLOR: rgb(0,0,204)">)</SPAN> 
                                <BR>__get_user<SPAN 
                                style="COLOR: rgb(0,0,204)">(</SPAN>local<SPAN 
                                style="COLOR: rgb(0,0,204)">,</SPAN> ptr<SPAN 
                                style="COLOR: rgb(0,0,204)">)</SPAN> 
                                </FONT></SPAN></CODE></P></TD></TR></TBODY></TABLE></SPAN></SPAN></SPAN></SPAN>这些宏它们相对copy_to_user 
                              和copy_from_user快, 
                              并且这些宏已被编写来允许传递任何类型的指针,只要它是一个用户空间地址. 传送的数据大小依赖 prt 
                              参数的类型, 并且在编译时使用 sizeof 和 typeof 等编译器内建宏确定。<FONT 
                              color=#0000ff>他们只传送1、2、4或8 
                              个字节。</FONT>如果使用以上函数来传送一个大小不适合的值,结果常常是一个来自编译器的奇怪消息,如"coversion 
                              to non-scalar type requested". 在这些情况中,必须使用 
                              copy_to_user 或者 copy_from_user。</P></DIV>
                              <DT>
                              <DIV>
                              <P>__put_user和<FONT face=新宋体>__get_user</FONT> 
                              进行更少的检查(不调用 access_ok), 
                              但是仍然能够失败如果被指向的内存对用户是不可写的,所以他们应只用在内存区已经用 access_ok 
                              检查过的时候。作为通用的规则:当实现一个 read 方法时,调用 __put_user 
                              来节省几个周期, 或者当你拷贝几个项时,因此,在第一次数据传送之前调用 access_ok 
                              一次。</P></DIV>
                              <DT>
                              <DIV>
                              <P><FONT color=#0000ff 
                              size=4><STRONG>权能与受限操作</STRONG></FONT></P></DIV>
                              <DT>
                              <DIV>
                              <P>Linux 内核提供了一个更加灵活的系统, 
                              称为权能(capability)。内核专为许可管理上使用权能并导出了两个系统调用 capget 和 
                              capset,这样可以从用户空间管理权能,其定义在&nbsp;<FONT 
                              color=#0000ff>&lt;linux/capability.h&gt;</FONT> 
                              中。对设备驱动编写者有意义的权能如下: 
                              <TABLE style="BORDER-COLLAPSE: collapse" 
                              borderColor=#999999 cellSpacing=0 cellPadding=0 
                              width="95%" bgColor=#f1f1f1 border=1>
                                <TBODY>
                                <TR>
                                <TD>
                                <P 
                                style="MARGIN: 5px; LINE-HEIGHT: 150%"><CODE><SPAN 
                                style="COLOR: rgb(0,0,0)"><FONT 
                                face=新宋体>CAP_DAC_OVERRIDE <SPAN 
                                style="COLOR: rgb(255,153,0)">/*越过在文件和目录上的访问限制(数据访问控制或 
                                DAC)的能力。*/</SPAN><BR><BR>CAP_NET_ADMIN <SPAN 
                                style="COLOR: rgb(255,153,0)">/*进行网络管理任务的能力, 
                                包括那些能够影响网络接口的任务*/</SPAN><BR><BR>CAP_SYS_MODULE 
                                <SPAN 
                                style="COLOR: rgb(255,153,0)">/*加载或去除内核模块的能力*/</SPAN><BR><BR>CAP_SYS_RAWIO 
                                <SPAN style="COLOR: rgb(255,153,0)">/*进行 
                                "raw"(裸)I/O 操作的能力. 例子包括存取设备端口或者直接和 USB 
                                设备通讯*/</SPAN><BR><BR>CAP_SYS_ADMIN <SPAN 
                                style="COLOR: rgb(255,153,0)">/*截获的能力, 
                                提供对许多系统管理操作的途径*/</SPAN><BR><BR>CAP_SYS_TTY_CONFIG 
                                <SPAN style="COLOR: rgb(255,153,0)">/*执行 tty 
                                配置任务的能力*/</SPAN></FONT></SPAN></CODE></P></TD></TR></TBODY></TABLE></P>
                              <P>在进行一个特权操作之前, 一个设备驱动应当检查调用进程有合适的能力,检查是通过 capable 
                              函数来进行的(定义在 <FONT 
                              color=#0000ff>&lt;linux/sched.h&gt;</FONT> )范例如下: 
                              <TABLE style="BORDER-COLLAPSE: collapse" 
                              borderColor=#999999 cellSpacing=0 cellPadding=0 
                              width="95%" bgColor=#f1f1f1 border=1>
                                <TBODY>
                                <TR>
                                <TD>
                                <P 
                                style="MARGIN: 5px; LINE-HEIGHT: 150%"><CODE><SPAN 
                                style="COLOR: rgb(0,0,0)"><FONT face=新宋体><SPAN 
                                style="COLOR: rgb(0,0,255)">if</SPAN> <SPAN 
                                style="COLOR: rgb(0,0,204)">(</SPAN><SPAN 
                                style="COLOR: rgb(0,0,204)">!</SPAN> capable 
                                <SPAN 
                                style="COLOR: rgb(0,0,204)">(</SPAN>CAP_SYS_ADMIN<SPAN 
                                style="COLOR: rgb(0,0,204)">)</SPAN><SPAN 
                                style="COLOR: rgb(0,0,204)">)</SPAN><BR>&nbsp;<SPAN 
                                style="COLOR: rgb(0,0,255)">return</SPAN> <SPAN 
                                style="COLOR: rgb(0,0,204)">-</SPAN>EPERM<SPAN 
                                style="COLOR: rgb(0,0,204)">;</SPAN></FONT></SPAN></CODE></P></TD></TR></TBODY></TABLE></P>
                              <HR id=null>
                              <STRONG><FONT color=#0000ff 
                              size=4>二、定位设备(llseek实现)</FONT></STRONG> 
                              <P></P></DIV>
                              <DT>
                              <DIV>
                              <P>llseek是修改文件中的当前读写位置的系统调用。内核中的缺省的实现进行移位通过修改 
                              filp-&gt;f_pos, 这是文件中的当前读写位置。对于 lseek 
                              系统调用要正确工作,读和写方法必须通过更新它们收到的偏移量来配合。</P></DIV>
                              <DT>
                              <DIV>
                              <P>如果设备是不允许移位的,你不能只制止声明 llseek 
                              操作,因为缺省的方法允许移位。应当在你的 open 方法中,通过调用 
                              nonseekable_open 通知内核你的设备不支持 llseek : 
                              <TABLE style="BORDER-COLLAPSE: collapse" 
                              borderColor=#999999 cellSpacing=0 cellPadding=0 
                              width="95%" bgColor=#f1f1f1 border=1>
                                <TBODY>
                                <TR>
                                <TD>
                                <P 
                                style="MARGIN: 5px; LINE-HEIGHT: 150%"><CODE><SPAN 
                                style="COLOR: rgb(0,0,0)"><FONT face=新宋体><SPAN 
                                style="COLOR: rgb(0,0,255)">int</SPAN> 
                                nonseekable_open<SPAN 
                                style="COLOR: rgb(0,0,204)">(</SPAN><SPAN 
                                style="COLOR: rgb(0,0,255)">struct</SPAN> inode 
                                <SPAN 
                                style="COLOR: rgb(0,0,204)">*</SPAN>inode<SPAN 
                                style="COLOR: rgb(0,0,204)">;</SPAN> <SPAN 
                                style="COLOR: rgb(0,0,255)">struct</SPAN> <SPAN 
                                style="COLOR: rgb(255,0,0)">file</SPAN> <SPAN 
                                style="COLOR: rgb(0,0,204)">*</SPAN>filp<SPAN 
                                style="COLOR: rgb(0,0,204)">)</SPAN><SPAN 
                                style="COLOR: rgb(0,0,204)">;</SPAN> 
                                </FONT></SPAN></CODE></P></TD></TR></TBODY></TABLE></P>
                              <P>完整起见, 你也应该在你的 file_operations 结构中设置 llseek 
                              方法到一个特殊的帮助函数 no_llseek(定义在 <FONT 
                              color=#0000ff>&lt;linux/fs.h&gt;</FONT> )。 
                              具体的应用在试验程序中学习. </P>
                              <HR id=null>
                              <STRONG><FONT color=#0000ff 
                              size=4>三、ioctl和llseek实验。</FONT></STRONG>
                              <P></P></DIV><FONT color=#ff0000 size=3><FONT 
                              face=新宋体><FONT color=#000000 
                              size=3>模块程序链接:</FONT></FONT></FONT><A 
                              href="http://blogimg.chinaunix.net/blog/upfile2/071101182632.gz" 
                              target=_blank>ioctl_and_llseek</A>
                              <P><FONT size=3>模块测试程序</FONT><FONT color=#ff0000 
                              size=3><FONT face=新宋体><FONT color=#000000 
                              size=3>链接</FONT></FONT></FONT><FONT 
                              size=3>:</FONT><A 
                              href="http://blogimg.chinaunix.net/blog/upfile2/071101182648.gz" 
                              target=_blank>ioctl_and_llseek-test</A></P><FONT 
                              size=4><SPAN 
                              style="COLOR: rgb(0,1,255)">ARM9实验板的实验现象是:</SPAN></FONT><BR>
                              <TABLE style="BORDER-COLLAPSE: collapse" 
                              borderColor=#999999 cellSpacing=0 cellPadding=0 
                              width="95%" bgColor=#f1f1f1 border=1>
                                <TBODY>
                                <TR>
                                <TD>
                                <P 
                                style="MARGIN: 5px; LINE-HEIGHT: 150%"><CODE><SPAN 
                                style="COLOR: rgb(0,0,0)"><SPAN 
                                style="COLOR: rgb(0,0,204)">[</SPAN>Tekkaman2440@SBC2440V4<SPAN 
                                style="COLOR: rgb(0,0,204)">]</SPAN><SPAN 
                                style="COLOR: rgb(0,0,204)">#</SPAN>cd <SPAN 
                                style="COLOR: rgb(0,0,204)">/</SPAN>lib<SPAN 
                                style="COLOR: rgb(0,0,204)">/</SPAN>modules<SPAN 
                                style="COLOR: rgb(0,0,204)">/</SPAN><BR><SPAN 
                                style="COLOR: rgb(0,0,204)">[</SPAN>Tekkaman2440@SBC2440V4<SPAN 
                                style="COLOR: rgb(0,0,204)">]</SPAN><SPAN 
                                style="COLOR: rgb(0,0,204)">#</SPAN>insmod 
                                scull<SPAN 
                                style="COLOR: rgb(0,0,204)">.</SPAN>ko 
                                scull_nr_devs<SPAN 
                                style="COLOR: rgb(0,0,204)">=</SPAN>1<BR><SPAN 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -