~ubuntu-branches/ubuntu/saucy/linux-ti-omap4/saucy-proposed

« back to all changes in this revision

Viewing changes to drivers/staging/comedi/drivers/pcmuio.c

  • Committer: Package Import Robot
  • Author(s): Paolo Pisati, Paolo Pisati, Stefan Bader, Upstream Kernel Changes
  • Date: 2012-08-15 17:17:43 UTC
  • Revision ID: package-import@ubuntu.com-20120815171743-h5wnuf51xe7pvdid
Tags: 3.5.0-207.13
[ Paolo Pisati ]

* Start new release

[ Stefan Bader ]

* (config) Enable getabis to use local package copies

[ Upstream Kernel Changes ]

* fixup: gargabe collect iva_seq[0|1] init
* [Config] enable all SND_OMAP_SOC_*s
* fixup: cm2xxx_3xxx.o is needed for omap2_cm_read|write_reg
* fixup: add some snd_soc_dai* helper functions
* fixup: s/snd_soc_dpcm_params/snd_soc_dpcm/g
* fixup: typo, no_host_mode and useless SDP4430 init
* fixup: enable again aess hwmod

Show diffs side-by-side

added added

removed removed

Lines of Context:
155
155
        const int num_ports;
156
156
};
157
157
 
158
 
static const struct pcmuio_board pcmuio_boards[] = {
159
 
        {
160
 
         .name = "pcmuio48",
161
 
         .num_asics = 1,
162
 
         .num_ports = 6,
163
 
         },
164
 
        {
165
 
         .name = "pcmuio96",
166
 
         .num_asics = 2,
167
 
         .num_ports = 12,
168
 
         },
169
 
};
170
 
 
171
158
/*
172
159
 * Useful for shorthand access to the particular board structure
173
160
 */
218
205
 */
219
206
#define devpriv ((struct pcmuio_private *)dev->private)
220
207
#define subpriv ((struct pcmuio_subdev_private *)s->private)
221
 
/*
222
 
 * The struct comedi_driver structure tells the Comedi core module
223
 
 * which functions to call to configure/deconfigure (attach/detach)
224
 
 * the board, and also about the kernel module that contains
225
 
 * the device code.
226
 
 */
227
 
static int pcmuio_attach(struct comedi_device *dev,
228
 
                         struct comedi_devconfig *it);
229
 
static int pcmuio_detach(struct comedi_device *dev);
230
 
 
231
 
static struct comedi_driver driver = {
232
 
        .driver_name = "pcmuio",
233
 
        .module = THIS_MODULE,
234
 
        .attach = pcmuio_attach,
235
 
        .detach = pcmuio_detach,
236
 
/* It is not necessary to implement the following members if you are
237
 
 * writing a driver for a ISA PnP or PCI card */
238
 
        /* Most drivers will support multiple types of boards by
239
 
         * having an array of board structures.  These were defined
240
 
         * in pcmuio_boards[] above.  Note that the element 'name'
241
 
         * was first in the structure -- Comedi uses this fact to
242
 
         * extract the name of the board without knowing any details
243
 
         * about the structure except for its length.
244
 
         * When a device is attached (by comedi_config), the name
245
 
         * of the device is given to Comedi, and Comedi tries to
246
 
         * match it by going through the list of board names.  If
247
 
         * there is a match, the address of the pointer is put
248
 
         * into dev->board_ptr and driver->attach() is called.
249
 
         *
250
 
         * Note that these are not necessary if you can determine
251
 
         * the type of board in software.  ISA PnP, PCI, and PCMCIA
252
 
         * devices are such boards.
253
 
         */
254
 
        .board_name = &pcmuio_boards[0].name,
255
 
        .offset = sizeof(struct pcmuio_board),
256
 
        .num_names = ARRAY_SIZE(pcmuio_boards),
257
 
};
258
 
 
259
 
static int pcmuio_dio_insn_bits(struct comedi_device *dev,
260
 
                                struct comedi_subdevice *s,
261
 
                                struct comedi_insn *insn, unsigned int *data);
262
 
static int pcmuio_dio_insn_config(struct comedi_device *dev,
263
 
                                  struct comedi_subdevice *s,
264
 
                                  struct comedi_insn *insn, unsigned int *data);
265
 
 
266
 
static irqreturn_t interrupt_pcmuio(int irq, void *d);
267
 
static void pcmuio_stop_intr(struct comedi_device *, struct comedi_subdevice *);
268
 
static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
269
 
static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
270
 
static int pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
271
 
                          struct comedi_cmd *cmd);
272
 
 
273
 
/* some helper functions to deal with specifics of this device's registers */
274
 
static void init_asics(struct comedi_device *dev);      /* sets up/clears ASIC chips to defaults */
275
 
static void switch_page(struct comedi_device *dev, int asic, int page);
276
 
#ifdef notused
277
 
static void lock_port(struct comedi_device *dev, int asic, int port);
278
 
static void unlock_port(struct comedi_device *dev, int asic, int port);
279
 
#endif
280
 
 
281
 
/*
282
 
 * Attach is called by the Comedi core to configure the driver
283
 
 * for a particular board.  If you specified a board_name array
284
 
 * in the driver structure, dev->board_ptr contains that
285
 
 * address.
286
 
 */
287
 
static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
288
 
{
289
 
        struct comedi_subdevice *s;
290
 
        int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0;
291
 
        unsigned long iobase;
292
 
        unsigned int irq[MAX_ASICS];
293
 
 
294
 
        iobase = it->options[0];
295
 
        irq[0] = it->options[1];
296
 
        irq[1] = it->options[2];
297
 
 
298
 
        dev_dbg(dev->hw_dev, "comedi%d: %s: io: %lx attached\n", dev->minor,
299
 
                driver.driver_name, iobase);
300
 
 
301
 
        dev->iobase = iobase;
302
 
 
303
 
        if (!iobase || !request_region(iobase,
304
 
                                       thisboard->num_asics * ASIC_IOSIZE,
305
 
                                       driver.driver_name)) {
306
 
                dev_err(dev->hw_dev, "I/O port conflict\n");
307
 
                return -EIO;
308
 
        }
309
 
 
310
 
/*
311
 
 * Initialize dev->board_name.  Note that we can use the "thisboard"
312
 
 * macro now, since we just initialized it in the last line.
313
 
 */
314
 
        dev->board_name = thisboard->name;
315
 
 
316
 
/*
317
 
 * Allocate the private structure area.  alloc_private() is a
318
 
 * convenient macro defined in comedidev.h.
319
 
 */
320
 
        if (alloc_private(dev, sizeof(struct pcmuio_private)) < 0) {
321
 
                dev_warn(dev->hw_dev, "cannot allocate private data structure\n");
322
 
                return -ENOMEM;
323
 
        }
324
 
 
325
 
        for (asic = 0; asic < MAX_ASICS; ++asic) {
326
 
                devpriv->asics[asic].num = asic;
327
 
                devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE;
328
 
                devpriv->asics[asic].irq = 0;   /* this gets actually set at the end of
329
 
                                                   this function when we
330
 
                                                   request_irqs */
331
 
                spin_lock_init(&devpriv->asics[asic].spinlock);
332
 
        }
333
 
 
334
 
        chans_left = CHANS_PER_ASIC * thisboard->num_asics;
335
 
        n_subdevs = CALC_N_SUBDEVS(chans_left);
336
 
        devpriv->sprivs =
337
 
            kcalloc(n_subdevs, sizeof(struct pcmuio_subdev_private),
338
 
                    GFP_KERNEL);
339
 
        if (!devpriv->sprivs) {
340
 
                dev_warn(dev->hw_dev, "cannot allocate subdevice private data structures\n");
341
 
                return -ENOMEM;
342
 
        }
343
 
        /*
344
 
         * Allocate the subdevice structures.  alloc_subdevice() is a
345
 
         * convenient macro defined in comedidev.h.
346
 
         *
347
 
         * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
348
 
         * 96-channel version of the board.
349
 
         */
350
 
        if (alloc_subdevices(dev, n_subdevs) < 0) {
351
 
                dev_dbg(dev->hw_dev, "cannot allocate subdevice data structures\n");
352
 
                return -ENOMEM;
353
 
        }
354
 
 
355
 
        port = 0;
356
 
        asic = 0;
357
 
        for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
358
 
                int byte_no;
359
 
 
360
 
                s = dev->subdevices + sdev_no;
361
 
                s->private = devpriv->sprivs + sdev_no;
362
 
                s->maxdata = 1;
363
 
                s->range_table = &range_digital;
364
 
                s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
365
 
                s->type = COMEDI_SUBD_DIO;
366
 
                s->insn_bits = pcmuio_dio_insn_bits;
367
 
                s->insn_config = pcmuio_dio_insn_config;
368
 
                s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
369
 
                subpriv->intr.asic = -1;
370
 
                subpriv->intr.first_chan = -1;
371
 
                subpriv->intr.asic_chan = -1;
372
 
                subpriv->intr.num_asic_chans = -1;
373
 
                subpriv->intr.active = 0;
374
 
                s->len_chanlist = 1;
375
 
 
376
 
                /* save the ioport address for each 'port' of 8 channels in the
377
 
                   subdevice */
378
 
                for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
379
 
                        if (port >= PORTS_PER_ASIC) {
380
 
                                port = 0;
381
 
                                ++asic;
382
 
                                thisasic_chanct = 0;
383
 
                        }
384
 
                        subpriv->iobases[byte_no] =
385
 
                            devpriv->asics[asic].iobase + port;
386
 
 
387
 
                        if (thisasic_chanct <
388
 
                            CHANS_PER_PORT * INTR_PORTS_PER_ASIC
389
 
                            && subpriv->intr.asic < 0) {
390
 
                                /* this is an interrupt subdevice, so setup the struct */
391
 
                                subpriv->intr.asic = asic;
392
 
                                subpriv->intr.active = 0;
393
 
                                subpriv->intr.stop_count = 0;
394
 
                                subpriv->intr.first_chan = byte_no * 8;
395
 
                                subpriv->intr.asic_chan = thisasic_chanct;
396
 
                                subpriv->intr.num_asic_chans =
397
 
                                    s->n_chan - subpriv->intr.first_chan;
398
 
                                dev->read_subdev = s;
399
 
                                s->subdev_flags |= SDF_CMD_READ;
400
 
                                s->cancel = pcmuio_cancel;
401
 
                                s->do_cmd = pcmuio_cmd;
402
 
                                s->do_cmdtest = pcmuio_cmdtest;
403
 
                                s->len_chanlist = subpriv->intr.num_asic_chans;
404
 
                        }
405
 
                        thisasic_chanct += CHANS_PER_PORT;
406
 
                }
407
 
                spin_lock_init(&subpriv->intr.spinlock);
408
 
 
409
 
                chans_left -= s->n_chan;
410
 
 
411
 
                if (!chans_left) {
412
 
                        asic = 0;       /* reset the asic to our first asic, to do intr subdevs */
413
 
                        port = 0;
414
 
                }
415
 
 
416
 
        }
417
 
 
418
 
        init_asics(dev);        /* clear out all the registers, basically */
419
 
 
420
 
        for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
421
 
                if (irq[asic]
422
 
                    && request_irq(irq[asic], interrupt_pcmuio,
423
 
                                   IRQF_SHARED, thisboard->name, dev)) {
424
 
                        int i;
425
 
                        /* unroll the allocated irqs.. */
426
 
                        for (i = asic - 1; i >= 0; --i) {
427
 
                                free_irq(irq[i], dev);
428
 
                                devpriv->asics[i].irq = irq[i] = 0;
429
 
                        }
430
 
                        irq[asic] = 0;
431
 
                }
432
 
                devpriv->asics[asic].irq = irq[asic];
433
 
        }
434
 
 
435
 
        dev->irq = irq[0];      /* grr.. wish comedi dev struct supported multiple
436
 
                                   irqs.. */
437
 
 
438
 
        if (irq[0]) {
439
 
                dev_dbg(dev->hw_dev, "irq: %u\n", irq[0]);
440
 
                if (irq[1] && thisboard->num_asics == 2)
441
 
                        dev_dbg(dev->hw_dev, "second ASIC irq: %u\n", irq[1]);
442
 
        } else {
443
 
                dev_dbg(dev->hw_dev, "(IRQ mode disabled)\n");
444
 
        }
445
 
 
446
 
 
447
 
        return 1;
448
 
}
449
 
 
450
 
/*
451
 
 * _detach is called to deconfigure a device.  It should deallocate
452
 
 * resources.
453
 
 * This function is also called when _attach() fails, so it should be
454
 
 * careful not to release resources that were not necessarily
455
 
 * allocated by _attach().  dev->private and dev->subdevices are
456
 
 * deallocated automatically by the core.
457
 
 */
458
 
static int pcmuio_detach(struct comedi_device *dev)
459
 
{
460
 
        int i;
461
 
 
462
 
        dev_dbg(dev->hw_dev, "comedi%d: %s: remove\n", dev->minor,
463
 
                driver.driver_name);
464
 
        if (dev->iobase)
465
 
                release_region(dev->iobase, ASIC_IOSIZE * thisboard->num_asics);
466
 
 
467
 
        for (i = 0; i < MAX_ASICS; ++i) {
468
 
                if (devpriv->asics[i].irq)
469
 
                        free_irq(devpriv->asics[i].irq, dev);
470
 
        }
471
 
 
472
 
        if (devpriv && devpriv->sprivs)
473
 
                kfree(devpriv->sprivs);
474
 
 
475
 
        return 0;
476
 
}
477
208
 
478
209
/* DIO devices are slightly special.  Although it is possible to
479
210
 * implement the insn_read/insn_write interface, it is much more
621
352
        return insn->n;
622
353
}
623
354
 
 
355
static void switch_page(struct comedi_device *dev, int asic, int page)
 
356
{
 
357
        if (asic < 0 || asic >= thisboard->num_asics)
 
358
                return;         /* paranoia */
 
359
        if (page < 0 || page >= NUM_PAGES)
 
360
                return;         /* more paranoia */
 
361
 
 
362
        devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
 
363
        devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
 
364
 
 
365
        /* now write out the shadow register */
 
366
        outb(devpriv->asics[asic].pagelock,
 
367
             dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
 
368
}
 
369
 
624
370
static void init_asics(struct comedi_device *dev)
625
371
{                               /* sets up an
626
372
                                   ASIC chip to defaults */
658
404
        }
659
405
}
660
406
 
661
 
static void switch_page(struct comedi_device *dev, int asic, int page)
662
 
{
663
 
        if (asic < 0 || asic >= thisboard->num_asics)
664
 
                return;         /* paranoia */
665
 
        if (page < 0 || page >= NUM_PAGES)
666
 
                return;         /* more paranoia */
667
 
 
668
 
        devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
669
 
        devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
670
 
 
671
 
        /* now write out the shadow register */
672
 
        outb(devpriv->asics[asic].pagelock,
673
 
             dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
674
 
}
675
 
 
676
407
#ifdef notused
677
408
static void lock_port(struct comedi_device *dev, int asic, int port)
678
409
{
700
431
}
701
432
#endif /* notused */
702
433
 
 
434
static void pcmuio_stop_intr(struct comedi_device *dev,
 
435
                             struct comedi_subdevice *s)
 
436
{
 
437
        int nports, firstport, asic, port;
 
438
 
 
439
        asic = subpriv->intr.asic;
 
440
        if (asic < 0)
 
441
                return;         /* not an interrupt subdev */
 
442
 
 
443
        subpriv->intr.enabled_mask = 0;
 
444
        subpriv->intr.active = 0;
 
445
        s->async->inttrig = 0;
 
446
        nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
 
447
        firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
 
448
        switch_page(dev, asic, PAGE_ENAB);
 
449
        for (port = firstport; port < firstport + nports; ++port) {
 
450
                /* disable all intrs for this subdev.. */
 
451
                outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
 
452
        }
 
453
}
 
454
 
703
455
static irqreturn_t interrupt_pcmuio(int irq, void *d)
704
456
{
705
457
        int asic, got1 = 0;
852
604
        return IRQ_HANDLED;
853
605
}
854
606
 
855
 
static void pcmuio_stop_intr(struct comedi_device *dev,
856
 
                             struct comedi_subdevice *s)
857
 
{
858
 
        int nports, firstport, asic, port;
859
 
 
860
 
        asic = subpriv->intr.asic;
861
 
        if (asic < 0)
862
 
                return;         /* not an interrupt subdev */
863
 
 
864
 
        subpriv->intr.enabled_mask = 0;
865
 
        subpriv->intr.active = 0;
866
 
        s->async->inttrig = 0;
867
 
        nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
868
 
        firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
869
 
        switch_page(dev, asic, PAGE_ENAB);
870
 
        for (port = firstport; port < firstport + nports; ++port) {
871
 
                /* disable all intrs for this subdev.. */
872
 
                outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
873
 
        }
874
 
}
875
 
 
876
607
static int pcmuio_start_intr(struct comedi_device *dev,
877
608
                             struct comedi_subdevice *s)
878
609
{
1014
745
        return comedi_pcm_cmdtest(dev, s, cmd);
1015
746
}
1016
747
 
1017
 
/*
1018
 
 * A convenient macro that defines init_module() and cleanup_module(),
1019
 
 * as necessary.
1020
 
 */
1021
 
static int __init driver_init_module(void)
1022
 
{
1023
 
        return comedi_driver_register(&driver);
1024
 
}
1025
 
 
1026
 
static void __exit driver_cleanup_module(void)
1027
 
{
1028
 
        comedi_driver_unregister(&driver);
1029
 
}
1030
 
 
1031
 
module_init(driver_init_module);
1032
 
module_exit(driver_cleanup_module);
 
748
static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
749
{
 
750
        struct comedi_subdevice *s;
 
751
        int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0;
 
752
        unsigned long iobase;
 
753
        unsigned int irq[MAX_ASICS];
 
754
 
 
755
        iobase = it->options[0];
 
756
        irq[0] = it->options[1];
 
757
        irq[1] = it->options[2];
 
758
 
 
759
        dev_dbg(dev->hw_dev, "comedi%d: %s: io: %lx attached\n", dev->minor,
 
760
                dev->driver->driver_name, iobase);
 
761
 
 
762
        dev->iobase = iobase;
 
763
 
 
764
        if (!iobase || !request_region(iobase,
 
765
                                       thisboard->num_asics * ASIC_IOSIZE,
 
766
                                       dev->driver->driver_name)) {
 
767
                dev_err(dev->hw_dev, "I/O port conflict\n");
 
768
                return -EIO;
 
769
        }
 
770
 
 
771
/*
 
772
 * Initialize dev->board_name.  Note that we can use the "thisboard"
 
773
 * macro now, since we just initialized it in the last line.
 
774
 */
 
775
        dev->board_name = thisboard->name;
 
776
 
 
777
/*
 
778
 * Allocate the private structure area.  alloc_private() is a
 
779
 * convenient macro defined in comedidev.h.
 
780
 */
 
781
        if (alloc_private(dev, sizeof(struct pcmuio_private)) < 0) {
 
782
                dev_warn(dev->hw_dev, "cannot allocate private data structure\n");
 
783
                return -ENOMEM;
 
784
        }
 
785
 
 
786
        for (asic = 0; asic < MAX_ASICS; ++asic) {
 
787
                devpriv->asics[asic].num = asic;
 
788
                devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE;
 
789
                devpriv->asics[asic].irq = 0;   /* this gets actually set at the end of
 
790
                                                   this function when we
 
791
                                                   request_irqs */
 
792
                spin_lock_init(&devpriv->asics[asic].spinlock);
 
793
        }
 
794
 
 
795
        chans_left = CHANS_PER_ASIC * thisboard->num_asics;
 
796
        n_subdevs = CALC_N_SUBDEVS(chans_left);
 
797
        devpriv->sprivs =
 
798
            kcalloc(n_subdevs, sizeof(struct pcmuio_subdev_private),
 
799
                    GFP_KERNEL);
 
800
        if (!devpriv->sprivs) {
 
801
                dev_warn(dev->hw_dev, "cannot allocate subdevice private data structures\n");
 
802
                return -ENOMEM;
 
803
        }
 
804
        /*
 
805
         * Allocate the subdevice structures.  alloc_subdevice() is a
 
806
         * convenient macro defined in comedidev.h.
 
807
         *
 
808
         * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
 
809
         * 96-channel version of the board.
 
810
         */
 
811
        if (alloc_subdevices(dev, n_subdevs) < 0) {
 
812
                dev_dbg(dev->hw_dev, "cannot allocate subdevice data structures\n");
 
813
                return -ENOMEM;
 
814
        }
 
815
 
 
816
        port = 0;
 
817
        asic = 0;
 
818
        for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
 
819
                int byte_no;
 
820
 
 
821
                s = dev->subdevices + sdev_no;
 
822
                s->private = devpriv->sprivs + sdev_no;
 
823
                s->maxdata = 1;
 
824
                s->range_table = &range_digital;
 
825
                s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 
826
                s->type = COMEDI_SUBD_DIO;
 
827
                s->insn_bits = pcmuio_dio_insn_bits;
 
828
                s->insn_config = pcmuio_dio_insn_config;
 
829
                s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
 
830
                subpriv->intr.asic = -1;
 
831
                subpriv->intr.first_chan = -1;
 
832
                subpriv->intr.asic_chan = -1;
 
833
                subpriv->intr.num_asic_chans = -1;
 
834
                subpriv->intr.active = 0;
 
835
                s->len_chanlist = 1;
 
836
 
 
837
                /* save the ioport address for each 'port' of 8 channels in the
 
838
                   subdevice */
 
839
                for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
 
840
                        if (port >= PORTS_PER_ASIC) {
 
841
                                port = 0;
 
842
                                ++asic;
 
843
                                thisasic_chanct = 0;
 
844
                        }
 
845
                        subpriv->iobases[byte_no] =
 
846
                            devpriv->asics[asic].iobase + port;
 
847
 
 
848
                        if (thisasic_chanct <
 
849
                            CHANS_PER_PORT * INTR_PORTS_PER_ASIC
 
850
                            && subpriv->intr.asic < 0) {
 
851
                                /* this is an interrupt subdevice, so setup the struct */
 
852
                                subpriv->intr.asic = asic;
 
853
                                subpriv->intr.active = 0;
 
854
                                subpriv->intr.stop_count = 0;
 
855
                                subpriv->intr.first_chan = byte_no * 8;
 
856
                                subpriv->intr.asic_chan = thisasic_chanct;
 
857
                                subpriv->intr.num_asic_chans =
 
858
                                    s->n_chan - subpriv->intr.first_chan;
 
859
                                dev->read_subdev = s;
 
860
                                s->subdev_flags |= SDF_CMD_READ;
 
861
                                s->cancel = pcmuio_cancel;
 
862
                                s->do_cmd = pcmuio_cmd;
 
863
                                s->do_cmdtest = pcmuio_cmdtest;
 
864
                                s->len_chanlist = subpriv->intr.num_asic_chans;
 
865
                        }
 
866
                        thisasic_chanct += CHANS_PER_PORT;
 
867
                }
 
868
                spin_lock_init(&subpriv->intr.spinlock);
 
869
 
 
870
                chans_left -= s->n_chan;
 
871
 
 
872
                if (!chans_left) {
 
873
                        asic = 0;       /* reset the asic to our first asic, to do intr subdevs */
 
874
                        port = 0;
 
875
                }
 
876
 
 
877
        }
 
878
 
 
879
        init_asics(dev);        /* clear out all the registers, basically */
 
880
 
 
881
        for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
 
882
                if (irq[asic]
 
883
                    && request_irq(irq[asic], interrupt_pcmuio,
 
884
                                   IRQF_SHARED, thisboard->name, dev)) {
 
885
                        int i;
 
886
                        /* unroll the allocated irqs.. */
 
887
                        for (i = asic - 1; i >= 0; --i) {
 
888
                                free_irq(irq[i], dev);
 
889
                                devpriv->asics[i].irq = irq[i] = 0;
 
890
                        }
 
891
                        irq[asic] = 0;
 
892
                }
 
893
                devpriv->asics[asic].irq = irq[asic];
 
894
        }
 
895
 
 
896
        dev->irq = irq[0];      /* grr.. wish comedi dev struct supported multiple
 
897
                                   irqs.. */
 
898
 
 
899
        if (irq[0]) {
 
900
                dev_dbg(dev->hw_dev, "irq: %u\n", irq[0]);
 
901
                if (irq[1] && thisboard->num_asics == 2)
 
902
                        dev_dbg(dev->hw_dev, "second ASIC irq: %u\n", irq[1]);
 
903
        } else {
 
904
                dev_dbg(dev->hw_dev, "(IRQ mode disabled)\n");
 
905
        }
 
906
 
 
907
 
 
908
        return 1;
 
909
}
 
910
 
 
911
static void pcmuio_detach(struct comedi_device *dev)
 
912
{
 
913
        int i;
 
914
 
 
915
        if (dev->iobase)
 
916
                release_region(dev->iobase, ASIC_IOSIZE * thisboard->num_asics);
 
917
        for (i = 0; i < MAX_ASICS; ++i) {
 
918
                if (devpriv->asics[i].irq)
 
919
                        free_irq(devpriv->asics[i].irq, dev);
 
920
        }
 
921
        if (devpriv && devpriv->sprivs)
 
922
                kfree(devpriv->sprivs);
 
923
}
 
924
 
 
925
static const struct pcmuio_board pcmuio_boards[] = {
 
926
        {
 
927
                .name           = "pcmuio48",
 
928
                .num_asics      = 1,
 
929
                .num_ports      = 6,
 
930
        }, {
 
931
                .name           = "pcmuio96",
 
932
                .num_asics      = 2,
 
933
                .num_ports      = 12,
 
934
        },
 
935
};
 
936
 
 
937
static struct comedi_driver pcmuio_driver = {
 
938
        .driver_name    = "pcmuio",
 
939
        .module         = THIS_MODULE,
 
940
        .attach         = pcmuio_attach,
 
941
        .detach         = pcmuio_detach,
 
942
        .board_name     = &pcmuio_boards[0].name,
 
943
        .offset         = sizeof(struct pcmuio_board),
 
944
        .num_names      = ARRAY_SIZE(pcmuio_boards),
 
945
};
 
946
module_comedi_driver(pcmuio_driver);
1033
947
 
1034
948
MODULE_AUTHOR("Comedi http://www.comedi.org");
1035
949
MODULE_DESCRIPTION("Comedi low-level driver");