Commit | Line | Data |
---|---|---|
be06e5d5 BL |
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 | ||
2696fb57 | 22 | #define PCM3730_SIZE 4 /* consecutive io port addresses */ |
be06e5d5 | 23 | |
2696fb57 | 24 | #define PCM3730_DOA 0 /* offsets for each port */ |
be06e5d5 BL |
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 | ||
0a85b6f0 MT |
31 | static int pcm3730_attach(struct comedi_device *dev, |
32 | struct comedi_devconfig *it); | |
da91b269 | 33 | static int pcm3730_detach(struct comedi_device *dev); |
139dfbdf | 34 | static struct comedi_driver driver_pcm3730 = { |
68c3dbff BP |
35 | .driver_name = "pcm3730", |
36 | .module = THIS_MODULE, | |
37 | .attach = pcm3730_attach, | |
38 | .detach = pcm3730_detach, | |
be06e5d5 BL |
39 | }; |
40 | ||
7114a280 AT |
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); | |
be06e5d5 | 53 | |
0a85b6f0 MT |
54 | static int pcm3730_do_insn_bits(struct comedi_device *dev, |
55 | struct comedi_subdevice *s, | |
56 | struct comedi_insn *insn, unsigned int *data) | |
be06e5d5 BL |
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 | ||
0a85b6f0 MT |
70 | static int pcm3730_di_insn_bits(struct comedi_device *dev, |
71 | struct comedi_subdevice *s, | |
72 | struct comedi_insn *insn, unsigned int *data) | |
be06e5d5 BL |
73 | { |
74 | if (insn->n != 2) | |
75 | return -EINVAL; | |
76 | data[1] = inb(dev->iobase + (unsigned long)(s->private)); | |
77 | return 2; | |
78 | } | |
79 | ||
0a85b6f0 MT |
80 | static int pcm3730_attach(struct comedi_device *dev, |
81 | struct comedi_devconfig *it) | |
be06e5d5 | 82 | { |
34c43922 | 83 | struct comedi_subdevice *s; |
be06e5d5 BL |
84 | unsigned long iobase; |
85 | ||
86 | iobase = it->options[0]; | |
b1e68ea5 | 87 | printk(KERN_INFO "comedi%d: pcm3730: 0x%04lx ", dev->minor, iobase); |
be06e5d5 BL |
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 | ||
b1e68ea5 | 154 | printk(KERN_INFO "\n"); |
be06e5d5 BL |
155 | |
156 | return 0; | |
157 | } | |
158 | ||
da91b269 | 159 | static int pcm3730_detach(struct comedi_device *dev) |
be06e5d5 | 160 | { |
b1e68ea5 | 161 | printk(KERN_INFO "comedi%d: pcm3730: remove\n", dev->minor); |
be06e5d5 BL |
162 | |
163 | if (dev->iobase) | |
164 | release_region(dev->iobase, PCM3730_SIZE); | |
165 | ||
166 | return 0; | |
167 | } | |
90f703d3 AT |
168 | |
169 | MODULE_AUTHOR("Comedi http://www.comedi.org"); | |
170 | MODULE_DESCRIPTION("Comedi low-level driver"); | |
171 | MODULE_LICENSE("GPL"); |