1/*
2 * comedi/drivers/pcm3730.c
3 * Driver for PCM3730 and clones
4 * Blaine Lee
5 * from pcl725 by David S.
6 */
7/*
8Driver: pcm3730
9Description: PCM3730
10Author: Blaine Lee
11Devices: [Advantech] PCM-3730 (pcm3730)
12Status: unknown
13
14Configuration 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
31static int pcm3730_attach(struct comedi_device *dev,
32			  struct comedi_devconfig *it);
33static int pcm3730_detach(struct comedi_device *dev);
34static struct comedi_driver driver_pcm3730 = {
35	.driver_name = "pcm3730",
36	.module = THIS_MODULE,
37	.attach = pcm3730_attach,
38	.detach = pcm3730_detach,
39};
40
41static int __init driver_pcm3730_init_module(void)
42{
43	return comedi_driver_register(&driver_pcm3730);
44}
45
46static void __exit driver_pcm3730_cleanup_module(void)
47{
48	comedi_driver_unregister(&driver_pcm3730);
49}
50
51module_init(driver_pcm3730_init_module);
52module_exit(driver_pcm3730_cleanup_module);
53
54static 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
70static 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
80static 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
159static 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
169MODULE_AUTHOR("Comedi http://www.comedi.org");
170MODULE_DESCRIPTION("Comedi low-level driver");
171MODULE_LICENSE("GPL");
172