<div dir="ltr">I am writing a simple driver that hooks the parallel port irq and when written to, enables the port for generating interrupts (the pins 9&amp;10 are wired together) and then toggles the high bit once for every byte in the written input. This means that if I do: <div>
&gt;echo &quot;0123456789&quot; &gt;&gt; /dev/foobar </div><div><br></div><div>I expect to toggle that bit 10 times, and generate 10 interrupts. My ISR is a simple counter that bumps a number every time it is called. </div>
<div><br></div><div>I am seeing that I am missing about 85% or more of my interrupts. Sometimes I get 2/10 but more often only 1/10. I have tried udelay()-ing between the port toggles but no go, and of course that is not really a solution. I am not trying to protect the counter but nothing else is accessing it. </div>
<div><br></div><div>I would expect to see *some* losses here, but not that many. What is going on? </div><div><br></div><div>Code follows. </div><div><br></div><div>Thanks loads</div><div><br></div><div>Eric</div><div>///////////////////////////////-----------cut here------------------------</div>
<div><div><div><div>#include &lt;linux/kernel.h&gt;</div><div>#include &lt;linux/module.h&gt;</div><div>#include &lt;linux/fs.h&gt;</div><div>#include &lt;linux/ioport.h&gt;</div><div>#include &lt;linux/cdev.h&gt;</div><div>
#include &lt;linux/slab.h&gt;</div><div>#include &lt;linux/init.h&gt;</div><div>#include &lt;linux/delay.h&gt;</div><div>#include &lt;asm/uaccess.h&gt;</div><div>#include &lt;linux/seq_file.h&gt;</div><div>#include &lt;linux/interrupt.h&gt;</div>
<div><br></div><div>MODULE_LICENSE(&quot;GPL&quot;);</div><div><br></div><div>#define NUM_DEVICES (1)</div><div>#define DEVNAME &quot;foobar&quot;</div><div>#define FOOBAR_MAJOR (248)</div><div>#define FOOBAR_MINOR (0) </div>
<div> </div><div>int foobar_init(void); </div><div>void foobar_exit(void); </div><div>int foobar_release(struct inode *, struct file*);</div><div>ssize_t foobar_read(struct file *, char __user *, size_t, loff_t *); </div>
<div>ssize_t foobar_write(struct file *, const char __user *, size_t, loff_t *);</div><div>int foobar_open(struct inode * inode, struct file * file);</div><div>void set_port_and_irq(void);</div><div>static irqreturn_t irqhandler(int irq, void * data);</div>
<div>int foobar_set_irq(void);</div><div><br></div><div>int port_address = -1;</div><div>module_param(port_address, int, 0); </div><div><br></div><div>unsigned int irq = 0; </div><div>module_param(irq, uint, 0);</div><div>
<br></div><div>int irqavail = -1;</div><div>size_t chars_read = 0; </div><div><br></div><div>static struct file_operations foobar_i_fops = </div><div>  {</div><div>    .owner = THIS_MODULE, </div><div>    .read =  foobar_read, </div>
<div>    .write = foobar_write,</div><div>    .open = foobar_open,</div><div>    .release = foobar_release,</div><div>  };</div><div><br></div><div>struct resource * region = NULL;</div><div><br></div><div>static  unsigned long mask; </div>
<div>static  unsigned long probe;</div><div><br></div><div>static dev_t g_dev;</div><div>unsigned dev_id = (unsigned)&amp;foobar_i_fops;</div><div><br></div><div>int foobar_init(void)</div><div>{</div><div>  int result = 0; </div>
<div>  </div><div>  result = register_chrdev(0, DEVNAME, &amp;foobar_i_fops); </div><div>  g_dev = MKDEV(result, FOOBAR_MINOR); </div><div>  if(result &lt; 0)</div><div>  {</div><div>      printk(KERN_WARNING &quot;foobar: can&#39;t get device number, returning %d&quot;, result); </div>
<div>      return result; </div><div>  }</div><div>    </div><div>  printk(KERN_WARNING &quot;foobar: Module %s got device number %d, minor is %d, result is %d\n&quot;, THIS_MODULE-&gt;name, MAJOR(g_dev), MINOR(g_dev), result); </div>
<div>  g_dev = MKDEV(MAJOR(g_dev), FOOBAR_MINOR + NUM_DEVICES);</div><div><br></div><div>  set_port_and_irq();</div><div><br></div><div>  region = request_region(port_address, 1, DEVNAME);</div><div>  printk(KERN_WARNING &quot;Port address is 0x%x, IRQ is %d, region is 0x%p\n&quot;, port_address, irq, region);  </div>
<div><br></div><div> if(region == 0)</div><div>    {</div><div>      printk(KERN_WARNING &quot;Can&#39;t get region&quot;); </div><div>      return -ENODEV;</div><div>    }</div><div>  mask = probe_irq_on(); </div><div>  return 0; </div>
<div>}</div><div><br></div><div>void foobar_exit(void)</div><div>{</div><div>  int major = MAJOR(g_dev); </div><div><br></div><div>  release_region(port_address, 1); </div><div>  </div><div>  printk(KERN_WARNING &quot;unregister_chrdev(%d) called for %s, dev # is %d\n&quot;, major, DEVNAME, g_dev); </div>
<div><br></div><div>  unregister_chrdev(major, DEVNAME); </div><div>}</div><div><br></div><div>int foobar_open(struct inode * inode, struct file * file)</div><div>{</div><div>  irqavail = request_irq(irq, irqhandler, IRQF_SHARED, DEVNAME, (void*)dev_id);</div>
<div>  printk(KERN_WARNING &quot;IRQ:%d\tPort Address:0x%x\tAvailable:%s\n&quot;, irq, port_address, irqavail == 0 ? &quot;true&quot; : &quot;false&quot;); </div><div><br></div><div>  return irqavail; </div><div>}</div><div>
<br></div><div>int foobar_release(struct inode * inode, struct file * filp)</div><div>{</div><div>  printk(KERN_WARNING &quot;foobar_release() is called, fil is 0x%p, inode is 0x%p\n&quot;, filp, inode);</div><div><br></div>
<div>  if(irqavail == 0)</div><div>    {</div><div>      printk(KERN_WARNING &quot;Freeing irq %d, dev_id is 0x%x\n&quot;, irq, dev_id);</div><div>      free_irq(irq, (void*)dev_id);</div><div>    }</div><div>  else</div>
<div>      printk(KERN_WARNING &quot;NOT freeing irq %d, dev_id is 0x%x\n&quot;, irq, dev_id);</div><div><br></div><div>  probe = probe_irq_off(mask);</div><div>  return 0;</div><div>} </div><div><br></div><div>ssize_t foobar_read(struct file * filp, char __user * buf, size_t count, loff_t * f_pos)</div>
<div>{</div><div>  if(chars_read == 0)</div><div>    {</div><div>      printk(KERN_WARNING &quot;Read is called, nothing to return.&quot;);</div><div>      return 0; </div><div>    }</div><div><br></div><div>  sprintf(buf, &quot;Chars&gt;%d\n&quot;, chars_read); </div>
<div>  chars_read = 0; </div><div>  printk(KERN_WARNING &quot;Read is called, returning %s, length is %d\n&quot;, buf, strlen(buf));</div><div>  return count;</div><div>}</div><div><br></div><div>ssize_t foobar_write(struct file * filp, const char __user * buf, size_t count, loff_t *f_pos)</div>
<div>{</div><div>  size_t idx; </div><div>  unsigned long address = (unsigned long)port_address;</div><div> </div><div>  printk(KERN_WARNING &quot;Write is called, count is %d, address is 0x%lx, buffer is %s\n&quot;, count, address, buf);</div>
<div>  outb_p(0x10, address + 2); </div><div>  for(idx = 0; idx &lt; strlen(buf); ++idx)</div><div>    {  </div><div>      outb_p(0x00, address); </div><div>      udelay(100);</div><div>      outb_p(0xff, address);</div><div>
      udelay(100);</div><div>    }</div><div><br></div><div>  outb_p(0x00, address + 2);</div><div>  udelay(5);</div><div><br></div><div>  printk(KERN_WARNING &quot;probe_irq_off(0x%lx) returned 0x%lx&quot;, mask, probe);</div>
<div>  if(f_pos)</div><div>    * f_pos = 0; </div><div>  return count; </div><div>}</div><div><br></div><div>static irqreturn_t irqhandler(int irq, void * data)</div><div>{</div><div>  chars_read++;</div><div>  printk(KERN_WARNING &quot;Interrupt is fired, IRQ is %d, data is 0x%p, chars %d\n&quot;, irq, data, chars_read);</div>
<div>  return IRQ_HANDLED;</div><div>}</div><div><br></div><div>void set_port_and_irq(void)</div><div>{</div><div>  if(irq &lt; 0)</div><div>      switch(port_address)</div><div><span class="" style="white-space:pre">        </span>{</div>
<div><span class="" style="white-space:pre">        </span>case 0x378:</div><div><span class="" style="white-space:pre">        </span>  irq = 7; </div><div><span class="" style="white-space:pre">        </span>  break; </div><div><br></div><div>
<span class="" style="white-space:pre">        </span>case 0x278:</div><div><span class="" style="white-space:pre">        </span>  irq = 2; </div><div><span class="" style="white-space:pre">        </span>  break; </div><div><span class="" style="white-space:pre">        </span>}</div>
<div><br></div><div>    switch(irq)</div><div>      {</div><div>      case 2:</div><div><span class="" style="white-space:pre">        </span>port_address = 0x278; </div><div><span class="" style="white-space:pre">        </span>break; </div>
<div><br></div><div>      case 7:</div><div><span class="" style="white-space:pre">        </span>port_address = 0x378; </div><div><span class="" style="white-space:pre">        </span>break; </div><div> </div><div>     }    </div><div>
}</div><div><br></div><div>module_init(foobar_init); </div><div>module_exit(foobar_exit); </div></div></div></div><div><br></div><div><br></div><div><br clear="all"><div><br></div>
</div></div>