<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&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>
>echo "0123456789" >> /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 <linux/kernel.h></div><div>#include <linux/module.h></div><div>#include <linux/fs.h></div><div>#include <linux/ioport.h></div><div>#include <linux/cdev.h></div><div>
#include <linux/slab.h></div><div>#include <linux/init.h></div><div>#include <linux/delay.h></div><div>#include <asm/uaccess.h></div><div>#include <linux/seq_file.h></div><div>#include <linux/interrupt.h></div>
<div><br></div><div>MODULE_LICENSE("GPL");</div><div><br></div><div>#define NUM_DEVICES (1)</div><div>#define DEVNAME "foobar"</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)&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, &foobar_i_fops); </div><div> g_dev = MKDEV(result, FOOBAR_MINOR); </div><div> if(result < 0)</div><div> {</div><div> printk(KERN_WARNING "foobar: can't get device number, returning %d", result); </div>
<div> return result; </div><div> }</div><div> </div><div> printk(KERN_WARNING "foobar: Module %s got device number %d, minor is %d, result is %d\n", THIS_MODULE->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 "Port address is 0x%x, IRQ is %d, region is 0x%p\n", port_address, irq, region); </div>
<div><br></div><div> if(region == 0)</div><div> {</div><div> printk(KERN_WARNING "Can't get region"); </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 "unregister_chrdev(%d) called for %s, dev # is %d\n", 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 "IRQ:%d\tPort Address:0x%x\tAvailable:%s\n", irq, port_address, irqavail == 0 ? "true" : "false"); </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 "foobar_release() is called, fil is 0x%p, inode is 0x%p\n", filp, inode);</div><div><br></div>
<div> if(irqavail == 0)</div><div> {</div><div> printk(KERN_WARNING "Freeing irq %d, dev_id is 0x%x\n", irq, dev_id);</div><div> free_irq(irq, (void*)dev_id);</div><div> }</div><div> else</div>
<div> printk(KERN_WARNING "NOT freeing irq %d, dev_id is 0x%x\n", 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 "Read is called, nothing to return.");</div><div> return 0; </div><div> }</div><div><br></div><div> sprintf(buf, "Chars>%d\n", chars_read); </div>
<div> chars_read = 0; </div><div> printk(KERN_WARNING "Read is called, returning %s, length is %d\n", 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 "Write is called, count is %d, address is 0x%lx, buffer is %s\n", count, address, buf);</div>
<div> outb_p(0x10, address + 2); </div><div> for(idx = 0; idx < 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 "probe_irq_off(0x%lx) returned 0x%lx", 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 "Interrupt is fired, IRQ is %d, data is 0x%p, chars %d\n", 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 < 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>