Merge remote branch 'alsa/devel' into topic/misc
[pandora-kernel.git] / drivers / staging / comedi / drivers / pcm3730.c
1 /*
2  * comedi/drivers/pcm3730.c
3  * Driver for PCM3730 and clones
4  * Blaine Lee
5  * from pcl725 by David S.
6  */
7 /*
8 Driver: pcm3730
9 Description: PCM3730
10 Author: Blaine Lee
11 Devices: [Advantech] PCM-3730 (pcm3730)
12 Status: unknown
13
14 Configuration options:
15   [0] - I/O port base
16 */
17
18 #include "../comedidev.h"
19
20 #include <linux/ioport.h>
21
22 #define PCM3730_SIZE 4          /*  consecutive io port addresses */
23
24 #define PCM3730_DOA 0           /*  offsets for each port */
25 #define PCM3730_DOB 2
26 #define PCM3730_DOC 3
27 #define PCM3730_DIA 0
28 #define PCM3730_DIB 2
29 #define PCM3730_DIC 3
30
31 static int pcm3730_attach(struct comedi_device *dev,
32                           struct comedi_devconfig *it);
33 static int pcm3730_detach(struct comedi_device *dev);
34 static struct comedi_driver driver_pcm3730 = {
35         .driver_name = "pcm3730",
36         .module = THIS_MODULE,
37         .attach = pcm3730_attach,
38         .detach = pcm3730_detach,
39 };
40
41 static int __init driver_pcm3730_init_module(void)
42 {
43         return comedi_driver_register(&driver_pcm3730);
44 }
45
46 static void __exit driver_pcm3730_cleanup_module(void)
47 {
48         comedi_driver_unregister(&driver_pcm3730);
49 }
50
51 module_init(driver_pcm3730_init_module);
52 module_exit(driver_pcm3730_cleanup_module);
53
54 static int pcm3730_do_insn_bits(struct comedi_device *dev,
55                                 struct comedi_subdevice *s,
56                                 struct comedi_insn *insn, unsigned int *data)
57 {
58         if (insn->n != 2)
59                 return -EINVAL;
60         if (data[0]) {
61                 s->state &= ~data[0];
62                 s->state |= (data[0] & data[1]);
63                 outb(s->state, dev->iobase + (unsigned long)(s->private));
64         }
65         data[1] = s->state;
66
67         return 2;
68 }
69
70 static int pcm3730_di_insn_bits(struct comedi_device *dev,
71                                 struct comedi_subdevice *s,
72                                 struct comedi_insn *insn, unsigned int *data)
73 {
74         if (insn->n != 2)
75                 return -EINVAL;
76         data[1] = inb(dev->iobase + (unsigned long)(s->private));
77         return 2;
78 }
79
80 static int pcm3730_attach(struct comedi_device *dev,
81                           struct comedi_devconfig *it)
82 {
83         struct comedi_subdevice *s;
84         unsigned long iobase;
85
86         iobase = it->options[0];
87         printk(KERN_INFO "comedi%d: pcm3730: 0x%04lx ", dev->minor, iobase);
88         if (!request_region(iobase, PCM3730_SIZE, "pcm3730")) {
89                 printk("I/O port conflict\n");
90                 return -EIO;
91         }
92         dev->iobase = iobase;
93         dev->board_name = "pcm3730";
94         dev->iobase = dev->iobase;
95         dev->irq = 0;
96
97         if (alloc_subdevices(dev, 6) < 0)
98                 return -ENOMEM;
99
100         s = dev->subdevices + 0;
101         s->type = COMEDI_SUBD_DO;
102         s->subdev_flags = SDF_WRITABLE;
103         s->maxdata = 1;
104         s->n_chan = 8;
105         s->insn_bits = pcm3730_do_insn_bits;
106         s->range_table = &range_digital;
107         s->private = (void *)PCM3730_DOA;
108
109         s = dev->subdevices + 1;
110         s->type = COMEDI_SUBD_DO;
111         s->subdev_flags = SDF_WRITABLE;
112         s->maxdata = 1;
113         s->n_chan = 8;
114         s->insn_bits = pcm3730_do_insn_bits;
115         s->range_table = &range_digital;
116         s->private = (void *)PCM3730_DOB;
117
118         s = dev->subdevices + 2;
119         s->type = COMEDI_SUBD_DO;
120         s->subdev_flags = SDF_WRITABLE;
121         s->maxdata = 1;
122         s->n_chan = 8;
123         s->insn_bits = pcm3730_do_insn_bits;
124         s->range_table = &range_digital;
125         s->private = (void *)PCM3730_DOC;
126
127         s = dev->subdevices + 3;
128         s->type = COMEDI_SUBD_DI;
129         s->subdev_flags = SDF_READABLE;
130         s->maxdata = 1;
131         s->n_chan = 8;
132         s->insn_bits = pcm3730_di_insn_bits;
133         s->range_table = &range_digital;
134         s->private = (void *)PCM3730_DIA;
135
136         s = dev->subdevices + 4;
137         s->type = COMEDI_SUBD_DI;
138         s->subdev_flags = SDF_READABLE;
139         s->maxdata = 1;
140         s->n_chan = 8;
141         s->insn_bits = pcm3730_di_insn_bits;
142         s->range_table = &range_digital;
143         s->private = (void *)PCM3730_DIB;
144
145         s = dev->subdevices + 5;
146         s->type = COMEDI_SUBD_DI;
147         s->subdev_flags = SDF_READABLE;
148         s->maxdata = 1;
149         s->n_chan = 8;
150         s->insn_bits = pcm3730_di_insn_bits;
151         s->range_table = &range_digital;
152         s->private = (void *)PCM3730_DIC;
153
154         printk(KERN_INFO "\n");
155
156         return 0;
157 }
158
159 static int pcm3730_detach(struct comedi_device *dev)
160 {
161         printk(KERN_INFO "comedi%d: pcm3730: remove\n", dev->minor);
162
163         if (dev->iobase)
164                 release_region(dev->iobase, PCM3730_SIZE);
165
166         return 0;
167 }
168
169 MODULE_AUTHOR("Comedi http://www.comedi.org");
170 MODULE_DESCRIPTION("Comedi low-level driver");
171 MODULE_LICENSE("GPL");