Search code examples
linuxlinux-device-driverinterruptdevice-driverparallel-port

work with parallel port interrupt


I am working on parallel port driver. Now i had seen the methods to get interrupt from parallel port.

by one of them,

First make 4th pin of control reg 1(IRQ). then make nACK low.

so i make a switch in between data pin 8 and nACK. so, if i write some data which has msb 1 then it will be interrupted, if that switch is on. Now i have a problem. If i disconnected that switch and again connect then it will not give me interrupt.

So, how can i do that thing by which i got interrupt by means of switch is connect or not.

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/parport.h>
#include <asm/uaccess.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <linux/errno.h>
#include <asm/irq.h>
#include <linux/kthread.h>

#define DEVICE_NAME "parlelport"

struct pardevice *pdev;
static int dummy;
int ret;

static irqreturn_t recv_handler(int irq, void *dev_id)
{
    printk("we inside if isr"); 

    return 0;
}

int led_open(struct inode *inode, struct file *file)
{
    printk("1\n");
    printk("Device File Opened\n");

    char byte1;
    byte1=inb(0x37A);
    printk("%d     \n",byte1);

    return 0;
}

ssize_t led_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
    printk("2\n");

    char byte=inb(0x37A);
    printk("%d",byte);
    byte = byte | 0x10;     // 0x10= 00010000, 4th pin of CTRL reg
    outb(byte, 0x37A);      //which enable IRQ

    char kbuf;
    copy_from_user(&kbuf, buf, 1);
    parport_claim_or_block(pdev);       /* Claim the port */
    parport_write_data(pdev->port, kbuf);   /* Write to the device */
    //parport_release (pdev);

    return count;
}

int led_release(struct inode *inode, struct file *file)
{
    printk("3\n");
    printk("Device File Released\n");

    char byte;
    byte=inb(0x37A);
    printk("%d", byte);
    return 0;
}

static struct file_operations led_fops = {
    .owner = THIS_MODULE,
    .open = led_open,
    .write = led_write,
    .release = led_release,
};


static int led_preempt(void *handle)
{
    printk("4\n");
    return 1;
}

static void led_attach(struct parport *port)
{
    printk("5\n");
    pdev = parport_register_device(port, DEVICE_NAME, led_preempt, NULL, NULL, 0, NULL);
    printk("Port attached\n");

    char byte1;
    byte1=inb(0x37A);
    printk("%d \n",byte1);
}

static void led_detach(struct parport *port)
{
    printk("6\n");
    parport_unregister_device (pdev);
    printk("Port Deattached\n");
}

static struct parport_driver led_driver = {
    .name= "led",
    .attach = led_attach,
    .detach = led_detach,
};

int __init led_init(void)
{
    printk("7\n");


    if (register_chrdev(89, DEVICE_NAME, &led_fops)) 
    {
    printk("Can't register device\n");
    return -1;
    }

    char byte=inb(0x37A);
    printk("%d",byte);
    byte = byte | 0x10;
    outb(byte, 0x37A);

    char byte1;
    byte1=inb(0x37A);
    printk("%d     %d \n",byte,byte1);

    parport_register_driver(&led_driver);

    ret= request_irq(7, recv_handler, IRQF_SHARED, "parlelport", &dummy);   
    printk("%d",ret);

    return 0;
}

void __exit led_cleanup(void)
{
    printk("8\n");
    unregister_chrdev(89, DEVICE_NAME);

    if(!ret)
    free_irq(7, &dummy);

    parport_unregister_driver(&led_driver);
    printk("LED Driver unregistered.\n");
    return;
}

module_init(led_init);
module_exit(led_cleanup);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Vikrant Patel");

Test.c file

int main()
{ 


    int fd=open("/dev/parlelport",O_RDWR);
    char byte;

    printf("Enter Value to send on parallel port");
    scanf("%c",&byte);

    printf("Byte value is %c\n",byte);
    if(write(fd,&byte,sizeof(char)))
    {
        printf("\nSuccessfully written on port");
    }

    getchar();
    getchar();

    close(fd);
}

Solution

  • I got it.

    First make a thread put the Enable IRQ code in that thread so it will continuously execute it whenever i connect pins at my hardware then it will be interrupted.

    check this code for your ref.

    #include <linux/module.h>
    #include <linux/parport.h>
    #include <asm/io.h>
    #include <linux/interrupt.h>
    #include <linux/kthread.h>
    
    #define DEVICE_NAME "parlelport"
    #define DATA 0x378
    #define STATUS 0x379
    #define CONTROL 0x37A
    
    struct pardevice *pdev;
    struct task_struct *ts1, *ts2;
    
    int dummy;
    char buf1='1',buf2='2';
    char byte='0';
    
    int thread1(void *data)
    {
        while(1)
        {
            outb(byte, CONTROL);            /* 0x30 = 0011 0000 , makes IRQ pin(5th bit) enable */
    
            printk("Thread1\n");
            parport_claim_or_block(pdev);       /* Claim the port */
            parport_write_data(pdev->port, buf1);   /* Write to the device */
            parport_release(pdev);          /* Release the port */
    
            msleep(4000);
            if (kthread_should_stop())
            break;
    
        }
        return 0;
    }
    
    
    int thread2(void *data)
    {
        while(1)
        {
            outb(byte,CONTROL);         /* 0x30 = 0011 0000 , makes IRQ pin(5th bit) enable */
    
            printk("Thread2\n");
            parport_claim_or_block(pdev);       /* Claim the port */
            parport_write_data(pdev->port, buf2);   /* Write to the device */
            parport_release(pdev);          /* Release the port */
    
            msleep(4000);
            if (kthread_should_stop())
            break;
    
        }
        return 0;
    }
    
    
    int led_open(struct inode *inode, struct file *file)
    {
        printk("Device File Opened\n");
    
        ts1=kthread_run(thread1,NULL,"kthread");        /* Initiation of thread 1 */
        msleep(2000);
        ts2=kthread_run(thread2,NULL,"kthread");        /* Initiation of thread 2 */
    
        return 0;
    }
    
    ssize_t led_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
    {
        return count;   
    }
    
    int led_release(struct inode *inode, struct file *file)
    {
        printk("Device File Released\n");
        kthread_stop(ts1);
        kthread_stop(ts2);
    
        buf1='1';
        buf2='2';
    
        outb_p(0x00,DATA);
        return 0;
    }
    
    static irqreturn_t recv_handler(int irq, void *unused)
    {
        printk("we inside of isr");
    
        buf1= buf1 ^ 0x7F;
        buf2= buf2 ^ 0x7F;
    
        return 0;
    }
    
    static struct file_operations led_fops = {
        .owner = THIS_MODULE,
        .open = led_open,
        .write = led_write,
        .release = led_release,
    };
    
    static int led_preempt(void *handle)
    {
        return 1;
    }
    
    static void led_attach(struct parport *port)
    {
        pdev = parport_register_device(port, DEVICE_NAME, led_preempt, NULL, NULL, 0, NULL);
        printk("Port attached\n");
    }
    
    static void led_detach(struct parport *port)
    {
        parport_unregister_device (pdev);
        printk("Port Deattached\n");
    }
    
    
    static struct parport_driver led_driver = {
        .name= "led",
        .attach = led_attach,
        .detach = led_detach,
    };
    
    
    int __init led_init(void)
    {
    
        /*Register our ISR with the kernel for PARALLEL_IRQ */
        if (request_irq(7, recv_handler, IRQF_SHARED, DEVICE_NAME ,&dummy))
        {       
            printk("Registering ISR failed\n");
            return -ENODEV;
        }
    
        /*Register Character Device Driver at 89 Major number*/
        if (register_chrdev(89, DEVICE_NAME, &led_fops)) 
        {
            printk("Can't register device\n");
            return -1;
        }
    
        /*Register parallel port driver with parport structure led_driver*/
        parport_register_driver(&led_driver);
    
        return 0;
    
    }
    
    
    
    void __exit led_cleanup(void)
    {
        unregister_chrdev(89, DEVICE_NAME);     /* Unregister char driver */
        free_irq(7, &dummy);                /* Free the ISR from IRQ7 */
        parport_unregister_driver(&led_driver);     /* Unregister the parallel port driver */
    
        printk("LED Driver unregistered.\n");
        return;
    }
    
    module_init(led_init);
    module_exit(led_cleanup);
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("Vikrant Patel");