Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/teigland/dlm
[cascardo/linux.git] / drivers / staging / comedi / drivers / pcl725.c
1 /*
2  * comedi/drivers/pcl725.c
3  * Driver for PCL725 and clones
4  * David A. Schleef
5  */
6 /*
7 Driver: pcl725
8 Description: Advantech PCL-725 (& compatibles)
9 Author: ds
10 Status: unknown
11 Devices: [Advantech] PCL-725 (pcl725)
12 */
13
14 #include "../comedidev.h"
15
16 #include <linux/ioport.h>
17
18 #define PCL725_SIZE 2
19
20 #define PCL725_DO 0
21 #define PCL725_DI 1
22
23 static int pcl725_attach(struct comedi_device *dev,
24                          struct comedi_devconfig *it);
25 static int pcl725_detach(struct comedi_device *dev);
26 static struct comedi_driver driver_pcl725 = {
27         .driver_name = "pcl725",
28         .module = THIS_MODULE,
29         .attach = pcl725_attach,
30         .detach = pcl725_detach,
31 };
32
33 static int __init driver_pcl725_init_module(void)
34 {
35         return comedi_driver_register(&driver_pcl725);
36 }
37
38 static void __exit driver_pcl725_cleanup_module(void)
39 {
40         comedi_driver_unregister(&driver_pcl725);
41 }
42
43 module_init(driver_pcl725_init_module);
44 module_exit(driver_pcl725_cleanup_module);
45
46 static int pcl725_do_insn(struct comedi_device *dev, struct comedi_subdevice *s,
47                           struct comedi_insn *insn, unsigned int *data)
48 {
49         if (insn->n != 2)
50                 return -EINVAL;
51
52         if (data[0]) {
53                 s->state &= ~data[0];
54                 s->state |= (data[0] & data[1]);
55                 outb(s->state, dev->iobase + PCL725_DO);
56         }
57
58         data[1] = s->state;
59
60         return 2;
61 }
62
63 static int pcl725_di_insn(struct comedi_device *dev, struct comedi_subdevice *s,
64                           struct comedi_insn *insn, unsigned int *data)
65 {
66         if (insn->n != 2)
67                 return -EINVAL;
68
69         data[1] = inb(dev->iobase + PCL725_DI);
70
71         return 2;
72 }
73
74 static int pcl725_attach(struct comedi_device *dev, struct comedi_devconfig *it)
75 {
76         struct comedi_subdevice *s;
77         unsigned long iobase;
78
79         iobase = it->options[0];
80         printk(KERN_INFO "comedi%d: pcl725: 0x%04lx ", dev->minor, iobase);
81         if (!request_region(iobase, PCL725_SIZE, "pcl725")) {
82                 printk("I/O port conflict\n");
83                 return -EIO;
84         }
85         dev->board_name = "pcl725";
86         dev->iobase = iobase;
87         dev->irq = 0;
88
89         if (alloc_subdevices(dev, 2) < 0)
90                 return -ENOMEM;
91
92         s = dev->subdevices + 0;
93         /* do */
94         s->type = COMEDI_SUBD_DO;
95         s->subdev_flags = SDF_WRITABLE;
96         s->maxdata = 1;
97         s->n_chan = 8;
98         s->insn_bits = pcl725_do_insn;
99         s->range_table = &range_digital;
100
101         s = dev->subdevices + 1;
102         /* di */
103         s->type = COMEDI_SUBD_DI;
104         s->subdev_flags = SDF_READABLE;
105         s->maxdata = 1;
106         s->n_chan = 8;
107         s->insn_bits = pcl725_di_insn;
108         s->range_table = &range_digital;
109
110         printk(KERN_INFO "\n");
111
112         return 0;
113 }
114
115 static int pcl725_detach(struct comedi_device *dev)
116 {
117         printk(KERN_INFO "comedi%d: pcl725: remove\n", dev->minor);
118
119         if (dev->iobase)
120                 release_region(dev->iobase, PCL725_SIZE);
121
122         return 0;
123 }
124
125 MODULE_AUTHOR("Comedi http://www.comedi.org");
126 MODULE_DESCRIPTION("Comedi low-level driver");
127 MODULE_LICENSE("GPL");