gpio-test updated for interrupt tests
[pub/spi-gpio-pp.git] / gpio_parport.c
index 73a16b1..0bddbcd 100644 (file)
 #include <linux/spinlock.h>
 #define sCONFIG_GPIO_PARPORT_MUTEX ""
 #endif
-
+#ifdef CONFIG_GPIO_PARPORT_EXCLUSIVE
+#define sCONFIG_GPIO_PARPORT_EXCLUSIVE " CONFIG_GPIO_PARPORT_EXCLUSIVE"
+#undef CONFIG_GPIO_PARPORT_NOCLAIME
+#else
+#define sCONFIG_GPIO_PARPORT_EXCLUSIVE ""
+#endif
+#ifdef CONFIG_GPIO_PARPORT_NOCLAIME
+#define sCONFIG_GPIO_PARPORT_NOCLAIME " CONFIG_GPIO_PARPORT_NOCLAIME"
+#else
+#define sCONFIG_GPIO_PARPORT_NOCLAIME ""
+#endif
 
 /* ToDo:
  * - proper handling error flags for gpio_to_irq ...
- * - using pp->dev-port should be equal to pp->port ...
  * - Sharing parport with other devices controled by module load
  *   paramter with using mutex mode ... but check with releasing parport IRQ handler  
  * - Verifing Parport modes
- * - Add sysfs Debug functionality
  * - Support PM functions like resume, suspend
  *
  *   Parallel                
  *     Port      Direction  Register Name                   Signal
  *  -----------  ---------  -------- ---------------------- ------
- *   nStrobe  1     -->     nC0      PARPORT_CONTROL_STROBE nGPO08
+ *   nStrobe  1     -->     nC0      PARPORT_CONTROL_STROBE  GPO08
  *      D0    2     -->      D0      (1 << 0)                GPO00
  *      D1    3     -->      D1      (1 << 1)                GPO01
  *      D2    4     -->      D2      (1 << 2)                GPO02
  *      D6    8     -->      D6      (1 << 6)                GPO06
  *      D7    9     -->      D7      (1 << 7)                GPO07
  *   nAckn   10     <--      S6      PARPORT_STATUS_ACK      GPI15*
- *    Busy   11     <--     nS7      PARPORT_STATUS_BUSY    nGPI16
+ *    Busy   11     <--     nS7      PARPORT_STATUS_BUSY     GPI16
  *    Paper  12     <--      S5      PARPORT_STATUS_PAPEROUT GPI14
  *    Sel    13     <--      S4      PARPORT_STATUS_SELECT   GPI13
- *   nFeed   14     -->     nC1      PARPORT_CONTROL_AUTOFD nGPO09
+ *   nFeed   14     -->     nC1      PARPORT_CONTROL_AUTOFD  GPO09
  *   nError  15     <--      S3      PARPORT_STATUS_ERROR    GPI12
  *   nInit   16     -->      C2      PARPORT_CONTROL_INIT    GPO10
- *   nSelIn  17     -->     nC3      PARPORT_CONTROL_SELECT nGPO11 
+ *   nSelIn  17     -->     nC3      PARPORT_CONTROL_SELECT  GPO11 
  *     GND   25     --       --                              GND
  *
  *  Signal:
  *  - GPOx  : general purpose output only
  *  - GPIx  : general purpose input only
  *  - GPIx* : interrupt in
- *  - nGPXx : signal is inverted
  */
 
 //*****************************************************************************
 #define GPIO_PARPORT_STAT_PORT_OFF   3    /* parport status port needs internally 3 bit offset */
 #define GPIO_PARPORT_INTERRUPT      15    /* gpio offset for parport pin Acknolge, which support interrupt */
 #define GPIO_PARPORT_NR_GPIOS       17    /* parport support up to 17 general purpose (dedicated) Inputs and Outputs */
+#define GPIO_PARPORT_STATUS_INV   0x80    /* invert internal bit 7 of status parport bit (Busy) */
+#define GPIO_PARPORT_CONTROL_INV  0x0b    /* invert internal bit 0, 1 and 3 of control parport bits (strobe, autofd, select) */
 
-
-static int modparam_gpiobase = -1         /* dynamic assingment */;
+/* Module load parameter */
+static int irq=-1;                        /* force irq for parport pin 10 */ 
+static int gpiobase = -1                  /* default dynamic assignment */;
 
 typedef struct {
        struct pardevice        *dev;     /* parport device entry */
@@ -161,7 +171,7 @@ static inline int gpio_parport_data_get(gpio_pp_struct *pp, unsigned mask)
 static inline int gpio_parport_ctrl_get(gpio_pp_struct *pp, unsigned mask)
 {
         // good idea to update also the cache
-       pp->ccache = parport_read_control(pp->port);
+       pp->ccache = GPIO_PARPORT_CONTROL_INV ^ parport_read_control(pp->port);
        return ((pp->ccache & mask) != 0);
 }
 
@@ -170,7 +180,7 @@ static inline int gpio_parport_ctrl_get(gpio_pp_struct *pp, unsigned mask)
 */
 static inline int gpio_parport_status_get(gpio_pp_struct *pp, unsigned mask)
 {
-        unsigned int cache = parport_read_status(pp->port);
+        unsigned int cache = GPIO_PARPORT_STATUS_INV ^ parport_read_status(pp->port);
        return ((cache & mask) != 0);
 }
 
@@ -181,7 +191,7 @@ static inline int gpio_parport_status_get(gpio_pp_struct *pp, unsigned mask)
 static int gpio_parport_get(struct gpio_chip *gpio, unsigned offset)
 {
         gpio_pp_struct *pp = container_of(gpio, gpio_pp_struct, gpio);
-       int            status = 0; /* inititalization ensures returm zero for unhandled bits */
+       int            status = 0; /* inititalization ensures return zero for unhandled bits */
        unsigned       long flags;
 
        if (offset < GPIO_PARPORT_CTRL_PORT_BITS) {
@@ -232,7 +242,7 @@ static inline void gpio_parport_ctrl_set(gpio_pp_struct *pp, unsigned mask, int
        else
                byte &= ~mask;
        pp->ccache = byte;   // restore cache
-       return parport_write_control(pp->port, byte);
+       return parport_write_control(pp->port, (GPIO_PARPORT_CONTROL_INV ^ byte));
 }
 
 /*
@@ -342,7 +352,7 @@ static void gpio_parport_gpio_setup(gpio_pp_struct *pp)
        c->free = NULL;
        c->to_irq = gpio_parport_gpio_to_irq;
 #endif
-       c->base = modparam_gpiobase;
+       c->base = gpiobase;
        c->ngpio = GPIO_PARPORT_NR_GPIOS;
         #ifdef CONFIG_GPIO_PARPORT_MUTEX
            c->can_sleep = 1;
@@ -359,10 +369,10 @@ static void gpio_parport_gpio_setup(gpio_pp_struct *pp)
 static LIST_HEAD(gpio_parport_hosts);
 
 /*
-** attach driver to parport is currently done with exclusive access. Unfortunately 
-** the driver is still loaded, although the attach might not be done successful.
-** If you have  already registered e.g. the lp driver, please unload this drivers
-** first as long as no shared supported is here implemented.
+** If attaching the driver to parport is done with exclusive access, the driver
+** is still loaded, although the attach might not be done successful.
+** If you have already registered e.g. the lp driver, please unload any drivers
+** first as long as you use exclusive access.
 */
 static int __gpio_parport_attach(struct parport *pb)
 {
@@ -394,7 +404,11 @@ static int __gpio_parport_attach(struct parport *pb)
                                          NULL, /* preemption fkt */ 
                                          NULL, /* wake-up fkt */
                                          NULL, /* interrupt handler */
-                                         PARPORT_FLAG_EXCL, /* flags */
+                                          #ifdef CONFIG_GPIO_PARPORT_EXCLUSIVE
+                                             PARPORT_FLAG_EXCL, /* flags */
+                                         #else
+                                             0, /* flags, 0 means used port shared */
+                                         #endif
                                          pp /* handle */ );
        if (pp->dev == NULL) {
                pr_err("%s: unable to register with parport\n", DRVNAME);
@@ -402,25 +416,37 @@ static int __gpio_parport_attach(struct parport *pb)
                goto err_release_mem;
        }
 
+       #ifndef CONFIG_GPIO_PARPORT_NOCLAIME
        err = parport_claim(pp->dev);
        if (err < 0) {
                pr_err("%s: unable to claim parport\n", DRVNAME);
                err = -ENODEV;
                goto err_unregister_parport;
        }
+       #endif
 
         /* ------------- GPIO PARPORT init --------------- */  
        /* cache initialisation just preventing changing unused bits */
        pp->dcache = parport_read_data(pp->port);
-       pp->ccache = parport_read_control(pp->port);
-
-       /* interrrut initialidation */
-        /* works for x86 arch, because we have nothing special to handle here */
-       if(pp->dev->port->irq != PARPORT_IRQ_NONE) {
-               pp->irq = pp->dev->port->irq;
+       pp->ccache = GPIO_PARPORT_CONTROL_INV ^ parport_read_control(pp->port);
+
+       /* interrrut initialization */
+        /* tested on x86 arch, because irq has nothing special to handle here */
+       if(irq >= 0) {
+                pp->irq = irq;
+               pr_info("%s: force usage IRQ %d\n", DRVNAME, pp->irq);
+               if(pp->port->irq == pp->irq) {
+                       /* we free the standard parport handler, because we want to use our own later */
+                       free_irq(pp->irq, pp->port);
+                       pr_info("%s: Note parport driver will claim later irq as already freed during its module unload\n", 
+                               DRVNAME);
+               }
+       } else if(pp->port->irq != PARPORT_IRQ_NONE) {
+                pp->irq = pp->port->irq;
                /* we free the standard parport handler, because we want to use our own later */
-               free_irq(pp->irq, pp->dev->port);
-               pr_info("%s: IRQ %d is available\n", DRVNAME, pp->irq);
+               free_irq(pp->irq, pp->port);
+               pr_info("%s: will use IRQ %d exclusive\n", DRVNAME, pp->irq);
+               pr_info("%s: Note parport driver will claim later irq as already freed during its module unload\n", DRVNAME);
        } else {
                pp->irq = -ENXIO;
        }
@@ -440,8 +466,10 @@ static int __gpio_parport_attach(struct parport *pb)
        return 0;
 
  err_release_parport:
+       #ifndef CONFIG_GPIO_PARPORT_NOCLAIME
        parport_release(pp->dev);
  err_unregister_parport:
+       #endif
        parport_unregister_device(pp->dev);
  err_release_mem:
        kfree(pp);
@@ -465,9 +493,10 @@ static int gpio_parport_remove(gpio_pp_struct *pp)
        err = gpiochip_remove(&pp->gpio);
        if (err < 0)
                pr_err("%s: gpio_remove error: %d\n", DRVNAME, err);
+       #ifndef CONFIG_GPIO_PARPORT_NOCLAIME
        parport_release(pp->dev);
+       #endif
         parport_unregister_device(pp->dev);
-       //ToDo: Check the unregister return value
        return err;
 }
 
@@ -476,7 +505,7 @@ static void gpio_parport_detach(struct parport *pb)
        gpio_pp_struct *pp;
 
        list_for_each_entry(pp, &gpio_parport_hosts, list) {
-               if (pp->dev->port == pb) {
+               if (pp->port == pb) {
                        (void)gpio_parport_remove(pp);   
                        list_del_init(&pp->list);
                        kfree(pp);
@@ -508,5 +537,11 @@ MODULE_AUTHOR("Option Wireless");
 MODULE_DESCRIPTION("GPIO master controller driver for Parport Adapter");
 MODULE_LICENSE("GPL");
 
-MODULE_INFO(Flags, sCONFIG_GPIO_PARPORT_MUTEX);
+module_param(irq, uint, S_IRUGO);
+MODULE_PARM_DESC(irq, "force set IRQ for parport pin 10");
+
+module_param_named(base, gpiobase, uint, S_IRUGO);
+MODULE_PARM_DESC(base, "force set GPIO base address");
+
+MODULE_INFO(Flags, sCONFIG_GPIO_PARPORT_MUTEX sCONFIG_GPIO_PARPORT_EXCLUSIVE sCONFIG_GPIO_PARPORT_NOCLAIME);
 MODULE_INFO(Version, DRIVER_VERSION);