#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 */
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);
}
*/
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);
}
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) {
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));
}
/*
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;
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)
{
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);
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;
}
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);
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;
}
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);
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);