1 #include "../comedidev.h"
3 #include "amcc_s5933.h"
5 #include "addi-data/addi_common.h"
7 #include "addi-data/addi_eeprom.c"
8 #include "addi-data/hwdrv_apci3501.c"
10 static const struct addi_board apci3501_boardtypes[] = {
12 .pc_DriverName = "apci3501",
13 .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
16 .i_IorangeBase1 = APCI3501_ADDRESS_RANGE,
17 .i_PCIEeprom = ADDIDATA_EEPROM,
18 .pc_EepromChip = ADDIDATA_S5933,
20 .pr_AoRangelist = &range_apci3501_ao,
21 .ao_config = i_APCI3501_ConfigAnalogOutput,
22 .ao_write = i_APCI3501_WriteAnalogOutput,
26 static int apci3501_di_insn_bits(struct comedi_device *dev,
27 struct comedi_subdevice *s,
28 struct comedi_insn *insn,
31 data[1] = inl(dev->iobase + APCI3501_DIGITAL_IP) & 0x3;
36 static int apci3501_do_insn_bits(struct comedi_device *dev,
37 struct comedi_subdevice *s,
38 struct comedi_insn *insn,
41 unsigned int mask = data[0];
42 unsigned int bits = data[1];
44 s->state = inl(dev->iobase + APCI3501_DIGITAL_OP);
47 s->state |= (bits & mask);
49 outl(s->state, dev->iobase + APCI3501_DIGITAL_OP);
57 static int i_ADDIDATA_InsnReadEeprom(struct comedi_device *dev,
58 struct comedi_subdevice *s,
59 struct comedi_insn *insn,
62 const struct addi_board *this_board = comedi_board(dev);
63 struct addi_private *devpriv = dev->private;
64 unsigned short w_Address = CR_CHAN(insn->chanspec);
65 unsigned short w_Data;
67 w_Data = addi_eeprom_readw(devpriv->i_IobaseAmcc,
68 this_board->pc_EepromChip, 2 * w_Address);
74 static irqreturn_t apci3501_interrupt(int irq, void *d)
76 struct comedi_device *dev = d;
77 struct addi_private *devpriv = dev->private;
78 unsigned int ui_Timer_AOWatchdog;
79 unsigned long ul_Command1;
82 /* Disable Interrupt */
84 inl(dev->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG);
86 ul_Command1 = (ul_Command1 & 0xFFFFF9FDul);
88 dev->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG);
91 inl(dev->iobase + APCI3501_WATCHDOG +
92 APCI3501_TCW_IRQ) & 0x1;
94 if ((!ui_Timer_AOWatchdog)) {
95 comedi_error(dev, "IRQ from unknown source");
99 /* Enable Interrupt Send a signal to from kernel to user space */
100 send_sig(SIGIO, devpriv->tsk_Current, 0);
102 inl(dev->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG);
103 ul_Command1 = ((ul_Command1 & 0xFFFFF9FDul) | 1 << 1);
105 dev->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG);
106 i_temp = inl(dev->iobase + APCI3501_WATCHDOG +
107 APCI3501_TCW_TRIG_STATUS) & 0x1;
112 static int apci3501_reset(struct comedi_device *dev)
114 int i_Count = 0, i_temp = 0;
115 unsigned int ul_Command1 = 0, ul_Polarity, ul_DAC_Ready = 0;
117 outl(0x0, dev->iobase + APCI3501_DIGITAL_OP);
118 outl(1, dev->iobase + APCI3501_ANALOG_OUTPUT +
119 APCI3501_AO_VOLT_MODE);
121 ul_Polarity = 0x80000000;
123 for (i_Count = 0; i_Count <= 7; i_Count++) {
124 ul_DAC_Ready = inl(dev->iobase + APCI3501_ANALOG_OUTPUT);
126 while (ul_DAC_Ready == 0) {
128 inl(dev->iobase + APCI3501_ANALOG_OUTPUT);
129 ul_DAC_Ready = (ul_DAC_Ready >> 8) & 1;
133 /* Output the Value on the output channels. */
135 (unsigned int) ((unsigned int) (i_Count & 0xFF) |
136 (unsigned int) ((i_temp << 0x8) & 0x7FFFFF00L) |
137 (unsigned int) (ul_Polarity));
139 dev->iobase + APCI3501_ANALOG_OUTPUT +
147 static const void *addi_find_boardinfo(struct comedi_device *dev,
148 struct pci_dev *pcidev)
150 const void *p = dev->driver->board_name;
151 const struct addi_board *this_board;
154 for (i = 0; i < dev->driver->num_names; i++) {
156 if (this_board->i_VendorId == pcidev->vendor &&
157 this_board->i_DeviceId == pcidev->device)
159 p += dev->driver->offset;
164 static int apci3501_auto_attach(struct comedi_device *dev,
165 unsigned long context_unused)
167 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
168 const struct addi_board *this_board;
169 struct addi_private *devpriv;
170 struct comedi_subdevice *s;
171 int ret, n_subdevices;
173 this_board = addi_find_boardinfo(dev, pcidev);
176 dev->board_ptr = this_board;
177 dev->board_name = this_board->pc_DriverName;
179 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
182 dev->private = devpriv;
184 ret = comedi_pci_enable(pcidev, dev->board_name);
188 dev->iobase = pci_resource_start(pcidev, 1);
189 devpriv->i_IobaseAmcc = pci_resource_start(pcidev, 0);
191 /* Initialize parameters that can be overridden in EEPROM */
192 devpriv->s_EeParameters.i_NbrAoChannel = this_board->i_NbrAoChannel;
193 devpriv->s_EeParameters.i_AoMaxdata = this_board->i_AoMaxdata;
195 if (pcidev->irq > 0) {
196 ret = request_irq(pcidev->irq, apci3501_interrupt, IRQF_SHARED,
197 dev->board_name, dev);
199 dev->irq = pcidev->irq;
202 addi_eeprom_read_info(dev, pci_resource_start(pcidev, 0));
205 ret = comedi_alloc_subdevices(dev, n_subdevices);
209 /* Allocate and Initialise AI Subdevice Structures */
210 s = &dev->subdevices[0];
211 s->type = COMEDI_SUBD_UNUSED;
213 /* Allocate and Initialise AO Subdevice Structures */
214 s = &dev->subdevices[1];
215 if (devpriv->s_EeParameters.i_NbrAoChannel) {
216 s->type = COMEDI_SUBD_AO;
217 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON;
218 s->n_chan = devpriv->s_EeParameters.i_NbrAoChannel;
219 s->maxdata = devpriv->s_EeParameters.i_AoMaxdata;
221 devpriv->s_EeParameters.i_NbrAoChannel;
222 s->range_table = this_board->pr_AoRangelist;
223 s->insn_config = this_board->ao_config;
224 s->insn_write = this_board->ao_write;
226 s->type = COMEDI_SUBD_UNUSED;
228 /* Allocate and Initialise DI Subdevice Structures */
229 s = &dev->subdevices[2];
230 s->type = COMEDI_SUBD_DI;
231 s->subdev_flags = SDF_READABLE;
234 s->range_table = &range_digital;
235 s->insn_bits = apci3501_di_insn_bits;
237 /* Initialize the digital output subdevice */
238 s = &dev->subdevices[3];
239 s->type = COMEDI_SUBD_DO;
240 s->subdev_flags = SDF_WRITEABLE;
243 s->range_table = &range_digital;
244 s->insn_bits = apci3501_do_insn_bits;
246 /* Allocate and Initialise Timer Subdevice Structures */
247 s = &dev->subdevices[4];
248 s->type = COMEDI_SUBD_TIMER;
249 s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON;
253 s->range_table = &range_digital;
254 s->insn_write = i_APCI3501_StartStopWriteTimerCounterWatchdog;
255 s->insn_read = i_APCI3501_ReadTimerCounterWatchdog;
256 s->insn_config = i_APCI3501_ConfigTimerCounterWatchdog;
258 /* Allocate and Initialise TTL */
259 s = &dev->subdevices[5];
260 s->type = COMEDI_SUBD_UNUSED;
263 s = &dev->subdevices[6];
264 if (this_board->i_PCIEeprom) {
265 s->type = COMEDI_SUBD_MEMORY;
266 s->subdev_flags = SDF_READABLE | SDF_INTERNAL;
269 s->insn_read = i_ADDIDATA_InsnReadEeprom;
271 s->type = COMEDI_SUBD_UNUSED;
278 static void apci3501_detach(struct comedi_device *dev)
280 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
281 struct addi_private *devpriv = dev->private;
287 free_irq(dev->irq, dev);
291 comedi_pci_disable(pcidev);
295 static struct comedi_driver apci3501_driver = {
296 .driver_name = "addi_apci_3501",
297 .module = THIS_MODULE,
298 .auto_attach = apci3501_auto_attach,
299 .detach = apci3501_detach,
300 .num_names = ARRAY_SIZE(apci3501_boardtypes),
301 .board_name = &apci3501_boardtypes[0].pc_DriverName,
302 .offset = sizeof(struct addi_board),
305 static int apci3501_pci_probe(struct pci_dev *dev,
306 const struct pci_device_id *ent)
308 return comedi_pci_auto_config(dev, &apci3501_driver);
311 static void apci3501_pci_remove(struct pci_dev *dev)
313 comedi_pci_auto_unconfig(dev);
316 static DEFINE_PCI_DEVICE_TABLE(apci3501_pci_table) = {
317 { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3001) },
320 MODULE_DEVICE_TABLE(pci, apci3501_pci_table);
322 static struct pci_driver apci3501_pci_driver = {
323 .name = "addi_apci_3501",
324 .id_table = apci3501_pci_table,
325 .probe = apci3501_pci_probe,
326 .remove = apci3501_pci_remove,
328 module_comedi_pci_driver(apci3501_driver, apci3501_pci_driver);
330 MODULE_AUTHOR("Comedi http://www.comedi.org");
331 MODULE_DESCRIPTION("Comedi low-level driver");
332 MODULE_LICENSE("GPL");