📄 sample_gpio_driver.html
字号:
<span class="br0">}</span> </pre></div><!-- SECTION [2850-3645] --><h3><a name="write_function" id="write_function">Write Function</a></h3><div class="level3"><p> The write function allows the user code to set or clear the output leds</p><pre class="code c"> <span class="kw4">static</span> ssize_tpflags_write <span class="br0">(</span><span class="kw4">struct</span> file *filp, <span class="kw4">const</span> <span class="kw4">char</span> *buf, size_t size, loff_t * offp<span class="br0">)</span><span class="br0">{</span> <span class="kw4">int</span> minor = check_minor <span class="br0">(</span>filp->f_dentry->d_inode<span class="br0">)</span>; <span class="kw4">volatile</span> <span class="kw4">unsigned</span> <span class="kw4">short</span> *set_or_clear; 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; <span class="kw1">if</span> <span class="br0">(</span>!buf<span class="br0">)</span> <span class="kw1">return</span> -EFAULT; <span class="co1">// clear if '0' set if '1'</span> set_or_clear = <span class="br0">(</span>buf<span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span> == <span class="st0">'0'</span><span class="br0">)</span> ? <span class="br0">(</span><span class="br0">(</span><span class="kw4">volatile</span> <span class="kw4">unsigned</span> <span class="kw4">short</span> *<span class="br0">)</span> FIO_FLAG_C<span class="br0">)</span> : <span class="br0">(</span><span class="br0">(</span><span class="kw4">volatile</span> <span class="kw4">unsigned</span> <span class="kw4">short</span> *<span class="br0">)</span> FIO_FLAG_S<span class="br0">)</span>; *set_or_clear = <span class="br0">(</span><span class="nu0">1</span> << minor<span class="br0">)</span>; <span class="kw1">return</span> size; <span class="br0">}</span> </pre></div><!-- SECTION [3646-4347] --><h3><a name="interrupt_handler" id="interrupt_handler">Interrupt Handler</a></h3><div class="level3"><p> This will clear the interrupt and input the flags state and detect a change.</p><p>(Note It should possibly only mask the pins of interest )</p><p>The interrupt handler will wake up the <strong>pflags_in_waitq</strong> wait queue.</p><pre class="code c"> <span class="kw4">static</span> irqreturn_t pflags_irq_handler <span class="br0">(</span> <span class="kw4">int</span> irq, <span class="kw4">void</span> *dev_id, <span class="kw4">struct</span> pt_regs *regs <span class="br0">)</span><span class="br0">{</span> <span class="kw4">short</span> pflags_nextstate = *pFIO_FLAG_D; <span class="coMULTI">/* FIXME: Clear only status of flag pin that caused the interrupt */</span> *pFIO_FLAG_C = 0xFFFF; <span class="coMULTI">/* clear irq status on interrupt lines */</span> printk<span class="br0">(</span><span class="st0">"pflags_irq_handler <span class="es0">\n</span>"</span><span class="br0">)</span>; pflags_statechanged = pflags_laststate ^ pflags_nextstate; pflags_laststate = pflags_nextstate; wake_up<span class="br0">(</span> &pflags_in_waitq <span class="br0">)</span>; <span class="kw1">return</span> IRQ_HANDLED; <span class="br0">}</span> </pre></div><!-- SECTION [4348-5076] --><h3><a name="poll_function" id="poll_function">Poll Function</a></h3><div class="level3"><p> The Poll function is optional. It will indicate that the state of the input pins has changed.</p><pre class="code c"><span class="kw4">static</span> <span class="kw4">unsigned</span> <span class="kw4">int</span> pflags_poll<span class="br0">(</span><span class="kw4">struct</span> file *filp, <span class="kw4">struct</span> poll_table_struct *wait<span class="br0">)</span><span class="br0">{</span> <span class="kw4">int</span> minor = check_minor<span class="br0">(</span> filp->f_dentry->d_inode <span class="br0">)</span>; <span class="kw4">int</span> changed=<span class="nu0">0</span>; <span class="kw4">unsigned</span> <span class="kw4">int</span> mask = <span class="nu0">0</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="co1">// *pFIO_MASKA_C |= (1 << minor);</span> *pFIO_MASKA_S |= <span class="br0">(</span><span class="nu0">1</span> << minor<span class="br0">)</span>; *pFIO_INEN |= <span class="br0">(</span><span class="nu0">1</span> << minor<span class="br0">)</span>; <span class="kw1">if</span> <span class="br0">(</span>filp->f_mode & FMODE_READ<span class="br0">)</span><span class="br0">{</span> <span class="coMULTI">/* attention! this wakes up when /any/ of the flags changes */</span> poll_wait<span class="br0">(</span>filp, &pflags_in_waitq, wait<span class="br0">)</span>; changed = pflags_statechanged & <span class="br0">(</span><span class="nu0">1</span><<minor<span class="br0">)</span>; <span class="kw1">if</span> <span class="br0">(</span> changed <span class="br0">)</span> mask |= POLLIN | POLLRDNORM; <span class="br0">}</span> <span class="coMULTI">/* we can always write */</span> <span class="kw1">if</span> <span class="br0">(</span>filp->f_mode & FMODE_WRITE<span class="br0">)</span> mask |= POLLOUT | POLLWRNORM; <span class="kw1">return</span> mask;<span class="br0">}</span> </pre></div><!-- SECTION [5077-5909] --><h3><a name="exit_function" id="exit_function">Exit Function</a></h3><div class="level3"><p>A simple exit function removes the proc interface </p><pre class="code"> (NOTE the Poll Irq is not removed !! )</pre><pre class="code c"><span class="kw4">void</span> __exitblackfin_plags_exit <span class="br0">(</span><span class="kw4">void</span><span class="br0">)</span><span class="br0">{</span> remove_proc_entry <span class="br0">(</span><span class="st0">"driver/pflags"</span>, <span class="kw2">NULL</span><span class="br0">)</span>; <span class="br0">}</span> module_exit <span class="br0">(</span>blackfin_plags_exit<span class="br0">)</span>; </pre></div><!-- SECTION [5910-6172] --><h3><a name="ioctl_code" id="ioctl_code">IOCTL Code</a></h3><div class="level3"><pre class="code c"><span class="kw4">static</span> <span class="kw4">int</span>pflags_ioctl <span class="br0">(</span><span class="kw4">struct</span> inode *inode, <span class="kw4">struct</span> file *filp, uint cmd, <span class="kw4">unsigned</span> <span class="kw4">long</span> arg<span class="br0">)</span><span class="br0">{</span> <span class="kw4">int</span> minor = check_minor <span class="br0">(</span>filp->f_dentry->d_inode<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; 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">switch</span> <span class="br0">(</span>cmd<span class="br0">)</span> <span class="br0">{</span> <span class="kw1">case</span> SET_FIO_DIR: DPRINTK <span class="br0">(</span><span class="st0">"pflags_ioctl: SET_FIO_DIR <span class="es0">\n</span>"</span><span class="br0">)</span>; <span class="kw1">if</span> <span class="br0">(</span>arg<span class="br0">)</span> <span class="br0">{</span> <span class="co1">// OUTPUT</span> *pFIO_DIR |= <span class="br0">(</span><span class="nu0">1</span> << minor<span class="br0">)</span>; <span class="br0">}</span> <span class="kw1">else</span> <span class="br0">{</span> <span class="co1">// INPUT</span> *pFIO_DIR &= ~<span class="br0">(</span><span class="nu0">1</span> << minor<span class="br0">)</span>; <span class="br0">}</span> <span class="kw2">break</span>; <span class="kw1">case</span> SET_FIO_POLAR: DPRINTK <span class="br0">(</span><span class="st0">"pflags_ioctl: SET_FIO_POLAR <span class="es0">\n</span>"</span>, arg<span class="br0">)</span>; <span class="kw1">if</span> <span class="br0">(</span>arg<span class="br0">)</span> <span class="br0">{</span> <span class="co1">// ACTIVELOW_FALLINGEDGE</span> *pFIO_POLAR |= <span class="br0">(</span><span class="nu0">1</span> << minor<span class="br0">)</span>; <span class="br0">}</span> <span class="kw1">else</span> <span class="br0">{</span> <span class="co1">// ACTIVEHIGH_RISINGEDGE</span> *pFIO_POLAR &= ~<span class="br0">(</span><span class="nu0">1</span> << minor<span class="br0">)</span>; <span class="br0">}</span> <span class="kw2">break</span>; <span class="kw1">case</span> SET_FIO_EDGE: DPRINTK <span class="br0">(</span><span class="st0">"pflags_ioctl: SET_FIO_EDGE <span class="es0">\n</span>"</span><span class="br0">)</span>; <span class="kw1">if</span> <span class="br0">(</span>arg<span class="br0">)</span> <span class="br0">{</span> <span class="co1">// EDGE</span> *pFIO_EDGE |= <span class="br0">(</span><span class="nu0">1</span> << minor<span class="br0">)</span>; <span class="br0">}</span> <span class="kw1">else</span> <span class="br0">{</span> <span class="co1">// LEVEL</span> *pFIO_EDGE &= ~<span class="br0">(</span><span class="nu0">1</span> << minor<span class="br0">)</span>; <span class="br0">}</span> <span class="kw2">break</span>; <span class="kw1">case</span> SET_FIO_BOTH: DPRINTK <span class="br0">(</span><span class="st0">"pflags_ioctl: SET_FIO_BOTH <span class="es0">\n</span>"</span><span class="br0">)</span>; <span class="kw1">if</span> <span class="br0">(</span>arg<span class="br0">)</span> <span class="br0">{</span> <span class="co1">// BOTHEDGES</span> *pFIO_BOTH |= <span class="br0">(</span><span class="nu0">1</span> << minor<span class="br0">)</span>; <span class="br0">}</span> <span class="kw1">else</span> <span class="br0">{</span> <span class="co1">// SINGLEEDGE</span> *pFIO_BOTH &= ~<span class="br0">(</span><span class="nu0">1</span> << minor<span class="br0">)</span>; <span class="br0">}</span> <span class="kw2">break</span>; <span class="kw1">case</span> SET_FIO_INEN: DPRINTK <span class="br0">(</span><span class="st0">"pflags_ioctl: SET_FIO_INEN <span class="es0">\n</span>"</span><span class="br0">)</span>; <span class="kw1">if</span> <span class="br0">(</span>arg<span class="br0">)</span> <span class="br0">{</span> <span class="co1">// OUTPUT_ENABLE</span> *pFIO_INEN |= <span class="br0">(</span><span class="nu0">1</span> << minor<span class="br0">)</span>; <span class="br0">}</span> <span class="kw1">else</span> <span class="br0">{</span> <span class="co1">// INPUT_DISABLE</span> *pFIO_INEN &= ~<span class="br0">(</span><span class="nu0">1</span> << minor<span class="br0">)</span>; <span class="br0">}</span> <span class="kw2">break</span>; <span class="kw1">default</span>: <span class="kw1">return</span> -EINVAL; <span class="br0">}</span> <span class="co1">// end switch</span> <span class="kw1">return</span> <span class="nu0">0</span>;<span class="br0">}</span> </pre></div><!-- SECTION [6173-8124] --><h3><a name="proc_interface" id="proc_interface">Proc Interface</a></h3><div class="level3"><p> This driver has an example proc interface This uses a small function to populate a string buffer (<strong>page</strong>) with data to be returned to the user.</p><p>This code has some additional complexity in that is handles part of the multi page capibility of the proc interface.</p><p>In this case this ios not needed. A simpler </p><pre class="code c"> <span class="co1">// from the source example </span><span class="kw4">static</span> <span class="kw4">int</span>pflags_read_proc <span class="br0">(</span><span class="kw4">char</span> *page, <span class="kw4">char</span> **start, off_t off, <span class="kw4">int</span> count, <span class="kw4">int</span> *eof, <span class="kw4">void</span> *data<span class="br0">)</span><span class="br0">{</span> <span class="kw4">int</span> len = <span class="nu0">0</span>;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -