diff --git a/drivers/staging/comedi/drivers/addi_apci_2032.c b/drivers/staging/comedi/drivers/addi_apci_2032.c index 9b1dee46c2b3..4cac92cff875 100644 --- a/drivers/staging/comedi/drivers/addi_apci_2032.c +++ b/drivers/staging/comedi/drivers/addi_apci_2032.c @@ -56,6 +56,10 @@ static unsigned int ui_InterruptData, ui_Type; +struct apci2032_private { + unsigned int wdog_ctrl; +}; + static int i_APCI2032_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -106,47 +110,69 @@ static int apci2032_do_insn_bits(struct comedi_device *dev, return insn->n; } -static int i_APCI2032_ConfigWatchdog(struct comedi_device *dev, +/* + * The watchdog subdevice is configured with two INSN_CONFIG instructions: + * + * Enable the watchdog and set the reload timeout: + * data[0] = INSN_CONFIG_ARM + * data[1] = timeout reload value + * + * Disable the watchdog: + * data[0] = INSN_CONFIG_DISARM + */ +static int apci2032_wdog_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - if (data[0] == 0) { - /* Disable the watchdog */ - outl(0x0, dev->iobase + APCI2032_WDOG_CTRL_REG); - /* Loading the Reload value */ - outl(data[1], dev->iobase + APCI2032_WDOG_RELOAD_REG); - } else { - printk("\nThe input parameters are wrong\n"); - return -EINVAL; - } + struct apci2032_private *devpriv = dev->private; + unsigned int reload; - return insn->n; -} - -static int i_APCI2032_StartStopWriteWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ switch (data[0]) { - case 0: /* stop the watchdog */ - outl(0x0, dev->iobase + APCI2032_WDOG_CTRL_REG); + case INSN_CONFIG_ARM: + devpriv->wdog_ctrl = APCI2032_WDOG_CTRL_ENABLE; + reload = data[1] & s->maxdata; + outw(reload, dev->iobase + APCI2032_WDOG_RELOAD_REG); + + /* Time base is 20ms, let the user know the timeout */ + dev_info(dev->class_dev, "watchdog enabled, timeout:%dms\n", + 20 * reload + 20); break; - case 1: /* start the watchdog */ - outl(0x0001, dev->iobase + APCI2032_WDOG_CTRL_REG); - break; - case 2: /* Software trigger */ - outl(0x0201, dev->iobase + APCI2032_WDOG_CTRL_REG); + case INSN_CONFIG_DISARM: + devpriv->wdog_ctrl = 0; break; default: - printk("\nSpecified functionality does not exist\n"); return -EINVAL; } + + outw(devpriv->wdog_ctrl, dev->iobase + APCI2032_WDOG_CTRL_REG); + return insn->n; } -static int apci1516_wdog_insn_read(struct comedi_device *dev, +static int apci2032_wdog_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci2032_private *devpriv = dev->private; + int i; + + if (devpriv->wdog_ctrl == 0) { + dev_warn(dev->class_dev, "watchdog is disabled\n"); + return -EINVAL; + } + + /* "ping" the watchdog */ + for (i = 0; i < insn->n; i++) { + outw(devpriv->wdog_ctrl | APCI2032_WDOG_CTRL_SW_TRIG, + dev->iobase + APCI2032_WDOG_CTRL_REG); + } + + return insn->n; +} + +static int apci2032_wdog_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -211,11 +237,17 @@ static int apci2032_auto_attach(struct comedi_device *dev, unsigned long context_unused) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct apci2032_private *devpriv; struct comedi_subdevice *s; int ret; dev->board_name = dev->driver->driver_name; + devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); + if (!devpriv) + return -ENOMEM; + dev->private = devpriv; + ret = comedi_pci_enable(pcidev, dev->board_name); if (ret) return ret; @@ -248,12 +280,11 @@ static int apci2032_auto_attach(struct comedi_device *dev, s->type = COMEDI_SUBD_TIMER; s->subdev_flags = SDF_WRITEABLE; s->n_chan = 1; - s->maxdata = 0; - s->len_chanlist = 1; + s->maxdata = 0xff; s->range_table = &range_digital; - s->insn_write = i_APCI2032_StartStopWriteWatchdog; - s->insn_read = apci1516_wdog_insn_read; - s->insn_config = i_APCI2032_ConfigWatchdog; + s->insn_write = apci2032_wdog_insn_write; + s->insn_read = apci2032_wdog_insn_read; + s->insn_config = apci2032_wdog_insn_config; apci2032_reset(dev); return 0;