📄 sample_gpio_driver.html
字号:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html><head> <title></title> <link rel="stylesheet" media="screen" type="text/css" href="./style.css" /> <link rel="stylesheet" media="screen" type="text/css" href="./design.css" /> <link rel="stylesheet" media="print" type="text/css" href="./print.css" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head><body><a href=start.html>start</a></br><div class="toc"><div class="tocheader toctoggle" id="toc__header">Table of Contents</div><div id="toc__inside"><ul class="toc"><li class="clear"><ul class="toc"><li class="level2"><div class="li"><span class="li"><a href="#sample_gpio_driver" class="toc">Sample GPIO Driver</a></span></div><ul class="toc"><li class="level3"><div class="li"><span class="li"><a href="#init_function" class="toc">Init Function</a></span></div></li><li class="level3"><div class="li"><span class="li"><a href="#file_operations_table" class="toc">File Operations Table</a></span></div></li><li class="level3"><div class="li"><span class="li"><a href="#open_function" class="toc">Open Function</a></span></div></li><li class="level3"><div class="li"><span class="li"><a href="#release_function" class="toc">Release Function</a></span></div></li><li class="level3"><div class="li"><span class="li"><a href="#write_function" class="toc">Write Function</a></span></div></li><li class="level3"><div class="li"><span class="li"><a href="#interrupt_handler" class="toc">Interrupt Handler</a></span></div></li><li class="level3"><div class="li"><span class="li"><a href="#poll_function" class="toc">Poll Function</a></span></div></li><li class="level3"><div class="li"><span class="li"><a href="#exit_function" class="toc">Exit Function</a></span></div></li><li class="level3"><div class="li"><span class="li"><a href="#ioctl_code" class="toc">IOCTL Code</a></span></div></li><li class="level3"><div class="li"><span class="li"><a href="#proc_interface" class="toc">Proc Interface</a></span></div></li><li class="level3"><div class="li"><span class="li"><a href="#test_the_driver" class="toc">Test the Driver</a></span></div></li><li class="level3"><div class="li"><span class="li"><a href="#sample_proc_output" class="toc">Sample Proc Output</a></span></div></li></ul></li></ul></li></ul></div></div><h2><a name="sample_gpio_driver" id="sample_gpio_driver">Sample GPIO Driver</a></h2><div class="level2"><p> This is a driver that allows the user to manipulate the programmable flags on the Blackfin STAMP boards.</p><p>The driver has a number of interesting features. </p><ul><li class="level1"><div class="li"> Normal Open, Release, Read, and Write IOCTL functions</div></li><li class="level1"><div class="li"> Interrupt on rising/falling or both edged</div></li><li class="level1"><div class="li"> Poll interface to allow user code to be triggered by a button press</div></li><li class="level1"><div class="li"> Proc interface to allow inspection of the system state</div></li></ul><p> For the STAMP board, the flags are connected to LEDS and Switches: </p><pre class="code"> /* STAMP Board Connections are made as follows: PF2 -> GUI_LED1 // output leds PF3 -> GUI_LED2 PF4 -> GUI_LED3 GUI_BUT1 -> PF5 // input push buttons GUI_BUT2 -> PF6 GUI_BUT3 -> PF8 */</pre><p> The Driver uses this Major Number: </p><pre class="code"> PFLAG_MAJOR 253 //experimental</pre><p> A different minor number is set up for each IO Port.</p><p>If the arg has a value then the first option is used.</p><p>IOCTL Functions are as follows :</p><pre class="code"> SET_FIO_DIR - Set Output / Input SET_FIO_POLAR - Set Active Low, Falling Edge / Active High Rising Edge SET_FIO_EDGE - Set Edge / Level Triggered SET_FIO_BOTH - Interrupt on Both / Single edges SET_FIO_INEN - Output enable / disable</pre></div><!-- SECTION [1-1251] --><h3><a name="init_function" id="init_function">Init Function</a></h3><div class="level3"><p> The init function does the following:</p><ul><li class="level1"><div class="li"> Registers the char device</div></li><li class="level1"><div class="li"> Creates a <strong>proc</strong> entry </div></li><li class="level1"><div class="li"> Sets up the Pflags Mask</div></li><li class="level1"><div class="li"> Sets up the Poll IRQ handler</div></li></ul><pre class="code c"> <span class="kw4">static</span> <span class="kw4">int</span> __initblackfin_pflags_init <span class="br0">(</span><span class="kw4">void</span><span class="br0">)</span><span class="br0">{</span> register_chrdev <span class="br0">(</span>PFLAG_MAJOR, <span class="st0">"pflag"</span>, &pflags_fops<span class="br0">)</span>; create_proc_read_entry <span class="br0">(</span><span class="st0">"driver/pflags"</span>, <span class="nu0">0</span>, <span class="nu0">0</span>, pflags_read_proc, <span class="kw2">NULL</span><span class="br0">)</span>; *pFIO_MASKA_C = <span class="br0">(</span>PF8 | PF6 | PF5<span class="br0">)</span>; *pFIO_EDGE &= ~<span class="br0">(</span>PF8 | PF6 | PF5<span class="br0">)</span>; <span class="co2">#ifdef ENABLE_POLL</span> <span class="kw1">if</span><span class="br0">(</span> request_irq <span class="br0">(</span>IRQ_PROG_INTA, pflags_irq_handler, SA_INTERRUPT, <span class="st0">"pflags"</span>, <span class="kw2">NULL</span><span class="br0">)</span> <span class="br0">)</span><span class="br0">{</span> printk <span class="br0">(</span>KERN_WARNING <span class="st0">"pflags: IRQ %d is not free.<span class="es0">\n</span>"</span>, IRQ_PROG_INTA<span class="br0">)</span>; <span class="kw1">return</span> -EIO; <span class="br0">}</span> init_waitqueue_head <span class="br0">(</span>&pflags_in_waitq<span class="br0">)</span>; pflags_laststate = *pFIO_FLAG_D; pflags_statechanged = 0xffff; printk <span class="br0">(</span><span class="st0">"pfx: pfbits driver for bf53x IRQ %d<span class="es0">\n</span>"</span>, IRQ_PROG_INTA<span class="br0">)</span>;<span class="co2">#else</span> printk <span class="br0">(</span><span class="st0">"pfx: pfbits driver for bf53x<span class="es0">\n</span>"</span><span class="br0">)</span>;<span class="co2">#endif</span><span class="co1">// enable_irq(IRQ_PROG_INTA);</span> <span class="kw1">return</span> <span class="nu0">0</span>;<span class="br0">}</span> module_init <span class="br0">(</span>blackfin_pflags_init<span class="br0">)</span>; </pre></div><!-- SECTION [1252-2230] --><h3><a name="file_operations_table" id="file_operations_table">File Operations Table</a></h3><div class="level3"><p> This has the normal open, release, read, write and ioctl functions.</p><p>It also has an optional POLL function</p><pre class="code">static struct file_operations pflags_fops = { .read = pflags_read, .write = pflags_write, .ioctl = pflags_ioctl, .open = pflags_open, .release = pflags_release,#ifdef ENABLE_POLL .poll = pflags_poll,#endif};</pre></div><!-- SECTION [2231-2627] --><h3><a name="open_function" id="open_function">Open Function</a></h3><div class="level3"><p> The open function just checks the minor number</p><pre class="code c"><span class="kw4">static</span> <span class="kw4">int</span>pflags_open <span class="br0">(</span><span class="kw4">struct</span> inode *inode, <span class="kw4">struct</span> file *filp<span class="br0">)</span><span class="br0">{</span> <span class="kw1">if</span> <span class="br0">(</span>check_minor <span class="br0">(</span>inode<span class="br0">)</span> < <span class="nu0">0</span><span class="br0">)</span> <span class="kw1">return</span> -ENODEV; <span class="kw1">return</span> <span class="nu0">0</span>;<span class="br0">}</span></pre></div><!-- SECTION [2628-2849] --><h3><a name="release_function" id="release_function">Release Function</a></h3><div class="level3"><p> The release function also just checks the minor number ( this check is not really needed !!)</p><pre class="code c"><span class="kw4">static</span> <span class="kw4">int</span>pflags_release <span class="br0">(</span><span class="kw4">struct</span> inode *inode, <span class="kw4">struct</span> file *filp<span class="br0">)</span><span class="br0">{</span> <span class="kw1">if</span> <span class="br0">(</span>check_minor <span class="br0">(</span>inode<span class="br0">)</span> < <span class="nu0">0</span><span class="br0">)</span> <span class="kw1">return</span> -ENODEV; <span class="kw1">return</span> <span class="nu0">0</span>;<span class="br0">}</span> ==== Read <span class="kw2">Function</span> ==== The Read <span class="kw2">Function</span> returns the state of the flag <span class="br0">(</span> selected by minor number <span class="br0">)</span> <code c><span class="kw4">static</span> ssize_tpflags_read <span class="br0">(</span><span class="kw4">struct</span> file *filp, <span class="kw4">char</span> *buf, size_t size, loff_t * offp<span class="br0">)</span><span class="br0">{</span> <span class="kw4">const</span> <span class="kw4">char</span> *bit; <span class="kw4">int</span> minor = check_minor <span class="br0">(</span>filp->f_dentry->d_inode<span class="br0">)</span>; DPRINTK <span class="br0">(</span><span class="st0">"pfbits driver for bf53x minor = %d<span class="es0">\n</span>"</span>, minor<span class="br0">)</span>; <span class="kw1">if</span> <span class="br0">(</span>minor < <span class="nu0">0</span><span class="br0">)</span> <span class="kw1">return</span> -ENODEV; <span class="kw1">if</span> <span class="br0">(</span>size < <span class="nu0">2</span><span class="br0">)</span> <span class="kw1">return</span> -EMSGSIZE; bit = <span class="br0">(</span>*pFIO_FLAG_D & <span class="br0">(</span><span class="nu0">1</span> << minor<span class="br0">)</span><span class="br0">)</span> ? <span class="st0">"1"</span> : <span class="st0">"0"</span>; <span class="kw1">return</span> <span class="br0">(</span>copy_to_user <span class="br0">(</span>buf, bit, <span class="nu0">2</span><span class="br0">)</span><span class="br0">)</span> ? -EFAULT : <span class="nu0">2</span>;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -