Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / staging / comedi / drivers / pcl730.c
CommitLineData
96a2d5f0
JLS
1/*
2 * comedi/drivers/pcl730.c
3 * Driver for Advantech PCL-730 and clones
4 * José Luis Sánchez
5 */
6/*
7Driver: pcl730
8Description: Advantech PCL-730 (& compatibles)
9Author: José Luis Sánchez (jsanchezv@teleline.es)
10Status: untested
11Devices: [Advantech] PCL-730 (pcl730), [ICP] ISO-730 (iso730),
12 [Adlink] ACL-7130 (acl7130)
13
14Interrupts are not supported.
15The ACL-7130 card have an 8254 timer/counter not supported by this driver.
16*/
17
18#include "../comedidev.h"
19
20#include <linux/ioport.h>
21
22#define PCL730_SIZE 4
23#define ACL7130_SIZE 8
24#define PCL730_IDIO_LO 0 /* Isolated Digital I/O low byte (ID0-ID7) */
25#define PCL730_IDIO_HI 1 /* Isolated Digital I/O high byte (ID8-ID15) */
26#define PCL730_DIO_LO 2 /* TTL Digital I/O low byte (D0-D7) */
27#define PCL730_DIO_HI 3 /* TTL Digital I/O high byte (D8-D15) */
28
0a85b6f0
MT
29static int pcl730_attach(struct comedi_device *dev,
30 struct comedi_devconfig *it);
da91b269 31static int pcl730_detach(struct comedi_device *dev);
96a2d5f0 32
292090dc
BP
33struct pcl730_board {
34
2696fb57
BP
35 const char *name; /* board name */
36 unsigned int io_range; /* len of I/O space */
292090dc
BP
37};
38
292090dc 39static const struct pcl730_board boardtypes[] = {
96a2d5f0
JLS
40 {"pcl730", PCL730_SIZE,},
41 {"iso730", PCL730_SIZE,},
42 {"acl7130", ACL7130_SIZE,},
43};
44
292090dc
BP
45#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl730_board))
46#define this_board ((const struct pcl730_board *)dev->board_ptr)
96a2d5f0 47
139dfbdf 48static struct comedi_driver driver_pcl730 = {
68c3dbff
BP
49 .driver_name = "pcl730",
50 .module = THIS_MODULE,
51 .attach = pcl730_attach,
52 .detach = pcl730_detach,
53 .board_name = &boardtypes[0].name,
54 .num_names = n_boardtypes,
55 .offset = sizeof(struct pcl730_board),
96a2d5f0
JLS
56};
57
7114a280
AT
58static int __init driver_pcl730_init_module(void)
59{
60 return comedi_driver_register(&driver_pcl730);
61}
62
63static void __exit driver_pcl730_cleanup_module(void)
64{
65 comedi_driver_unregister(&driver_pcl730);
66}
67
68module_init(driver_pcl730_init_module);
69module_exit(driver_pcl730_cleanup_module);
96a2d5f0 70
da91b269 71static int pcl730_do_insn(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 72 struct comedi_insn *insn, unsigned int *data)
96a2d5f0
JLS
73{
74 if (insn->n != 2)
75 return -EINVAL;
76
77 if (data[0]) {
78 s->state &= ~data[0];
79 s->state |= (data[0] & data[1]);
80 }
81 if (data[0] & 0x00ff)
82 outb(s->state & 0xff,
0a85b6f0 83 dev->iobase + ((unsigned long)s->private));
96a2d5f0
JLS
84 if (data[0] & 0xff00)
85 outb((s->state >> 8),
0a85b6f0 86 dev->iobase + ((unsigned long)s->private) + 1);
96a2d5f0
JLS
87
88 data[1] = s->state;
89
90 return 2;
91}
92
da91b269 93static int pcl730_di_insn(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 94 struct comedi_insn *insn, unsigned int *data)
96a2d5f0
JLS
95{
96 if (insn->n != 2)
97 return -EINVAL;
98
99 data[1] = inb(dev->iobase + ((unsigned long)s->private)) |
0a85b6f0 100 (inb(dev->iobase + ((unsigned long)s->private) + 1) << 8);
96a2d5f0
JLS
101
102 return 2;
103}
104
da91b269 105static int pcl730_attach(struct comedi_device *dev, struct comedi_devconfig *it)
96a2d5f0 106{
34c43922 107 struct comedi_subdevice *s;
96a2d5f0
JLS
108 unsigned long iobase;
109 unsigned int iorange;
110
111 iobase = it->options[0];
112 iorange = this_board->io_range;
615d5b6c 113 printk(KERN_INFO "comedi%d: pcl730: board=%s 0x%04lx ", dev->minor,
0a85b6f0 114 this_board->name, iobase);
96a2d5f0
JLS
115 if (!request_region(iobase, iorange, "pcl730")) {
116 printk("I/O port conflict\n");
117 return -EIO;
118 }
119 dev->board_name = this_board->name;
120 dev->iobase = iobase;
121 dev->irq = 0;
122
123 if (alloc_subdevices(dev, 4) < 0)
124 return -ENOMEM;
125
126 s = dev->subdevices + 0;
127 /* Isolated do */
128 s->type = COMEDI_SUBD_DO;
129 s->subdev_flags = SDF_WRITABLE;
130 s->maxdata = 1;
131 s->n_chan = 16;
132 s->insn_bits = pcl730_do_insn;
133 s->range_table = &range_digital;
134 s->private = (void *)PCL730_IDIO_LO;
135
136 s = dev->subdevices + 1;
137 /* Isolated di */
138 s->type = COMEDI_SUBD_DI;
139 s->subdev_flags = SDF_READABLE;
140 s->maxdata = 1;
141 s->n_chan = 16;
142 s->insn_bits = pcl730_di_insn;
143 s->range_table = &range_digital;
144 s->private = (void *)PCL730_IDIO_LO;
145
146 s = dev->subdevices + 2;
147 /* TTL do */
148 s->type = COMEDI_SUBD_DO;
149 s->subdev_flags = SDF_WRITABLE;
150 s->maxdata = 1;
151 s->n_chan = 16;
152 s->insn_bits = pcl730_do_insn;
153 s->range_table = &range_digital;
154 s->private = (void *)PCL730_DIO_LO;
155
156 s = dev->subdevices + 3;
157 /* TTL di */
158 s->type = COMEDI_SUBD_DI;
159 s->subdev_flags = SDF_READABLE;
160 s->maxdata = 1;
161 s->n_chan = 16;
162 s->insn_bits = pcl730_di_insn;
163 s->range_table = &range_digital;
164 s->private = (void *)PCL730_DIO_LO;
165
615d5b6c 166 printk(KERN_INFO "\n");
96a2d5f0
JLS
167
168 return 0;
169}
170
da91b269 171static int pcl730_detach(struct comedi_device *dev)
96a2d5f0 172{
615d5b6c 173 printk(KERN_INFO "comedi%d: pcl730: remove\n", dev->minor);
96a2d5f0
JLS
174
175 if (dev->iobase)
176 release_region(dev->iobase, this_board->io_range);
177
178 return 0;
179}
90f703d3
AT
180
181MODULE_AUTHOR("Comedi http://www.comedi.org");
182MODULE_DESCRIPTION("Comedi low-level driver");
183MODULE_LICENSE("GPL");