1578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell/*
2578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell    comedi/drivers/serial2002.c
3578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell    Skeleton code for a Comedi driver
4578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
5578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell    COMEDI - Linux Control and Measurement Device Interface
6578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell    Copyright (C) 2002 Anders Blomdell <anders.blomdell@control.lth.se>
7578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
8578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell    This program is free software; you can redistribute it and/or modify
9578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell    it under the terms of the GNU General Public License as published by
10578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell    the Free Software Foundation; either version 2 of the License, or
11578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell    (at your option) any later version.
12578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
13578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell    This program is distributed in the hope that it will be useful,
14578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell    but WITHOUT ANY WARRANTY; without even the implied warranty of
15578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell    GNU General Public License for more details.
17578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
18578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell    You should have received a copy of the GNU General Public License
19578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell    along with this program; if not, write to the Free Software
20578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
22578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell*/
23578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
24578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell/*
25578c0183545d8fe99f8a65cfb1483360d18c1253Anders BlomdellDriver: serial2002
26578c0183545d8fe99f8a65cfb1483360d18c1253Anders BlomdellDescription: Driver for serial connected hardware
27578c0183545d8fe99f8a65cfb1483360d18c1253Anders BlomdellDevices:
28578c0183545d8fe99f8a65cfb1483360d18c1253Anders BlomdellAuthor: Anders Blomdell
29578c0183545d8fe99f8a65cfb1483360d18c1253Anders BlomdellUpdated: Fri,  7 Jun 2002 12:56:45 -0700
30578c0183545d8fe99f8a65cfb1483360d18c1253Anders BlomdellStatus: in development
31578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
32578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell*/
33578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
34578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell#include "../comedidev.h"
35578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
36578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell#include <linux/delay.h>
37578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell#include <linux/ioport.h>
38029214841ba8a1fae48a4a108d138b302d8a1afbGreg Kroah-Hartman#include <linux/sched.h>
395a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
40578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
41b041267ea819054aa9b406efc94fe8821ea2e67bRavishankar#include <linux/termios.h>
42578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell#include <asm/ioctls.h>
43578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell#include <linux/serial.h>
44578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell#include <linux/poll.h>
45578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
46578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell/*
47578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell * Board descriptions for two imaginary boards.  Describing the
48578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell * boards in this way is optional, and completely driver-dependent.
49578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell * Some drivers use arrays such as this, other do not.
50578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell */
51ca9ed0f295a5e85861c63713406d86643e570580Bill Pembertonstruct serial2002_board {
52578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	const char *name;
53ca9ed0f295a5e85861c63713406d86643e570580Bill Pemberton};
54578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
55ca9ed0f295a5e85861c63713406d86643e570580Bill Pembertonstatic const struct serial2002_board serial2002_boards[] = {
56578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	{
570a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .name = "serial2002"}
58578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell};
59578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
60578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell/*
61578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell * Useful for shorthand access to the particular board structure
62578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell */
63ca9ed0f295a5e85861c63713406d86643e570580Bill Pemberton#define thisboard ((const struct serial2002_board *)dev->board_ptr)
64578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
65b3fb588d463c575706fe80e9c30bf4b1c7702034Bill Pembertonstruct serial2002_range_table_t {
66b3fb588d463c575706fe80e9c30bf4b1c7702034Bill Pemberton
672696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	/*  HACK... */
68578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	int length;
691f6325d629ce03501e8927480495685828561f26Bill Pemberton	struct comedi_krange range;
70b3fb588d463c575706fe80e9c30bf4b1c7702034Bill Pemberton};
71b3fb588d463c575706fe80e9c30bf4b1c7702034Bill Pemberton
72e21ffa44f55ebf7f6f7d1e60a49463ca579c056aBill Pembertonstruct serial2002_private {
73e21ffa44f55ebf7f6f7d1e60a49463ca579c056aBill Pemberton
742696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	int port;		/*  /dev/ttyS<port> */
752696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	int speed;		/*  baudrate */
76578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	struct file *tty;
77790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	unsigned int ao_readback[32];
78578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	unsigned char digital_in_mapping[32];
79578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	unsigned char digital_out_mapping[32];
80578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	unsigned char analog_in_mapping[32];
81578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	unsigned char analog_out_mapping[32];
82578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	unsigned char encoder_in_mapping[32];
83b3fb588d463c575706fe80e9c30bf4b1c7702034Bill Pemberton	struct serial2002_range_table_t in_range[32], out_range[32];
84e21ffa44f55ebf7f6f7d1e60a49463ca579c056aBill Pemberton};
85e21ffa44f55ebf7f6f7d1e60a49463ca579c056aBill Pemberton
86578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell/*
87578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell * most drivers define the following macro to make it easy to
88578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell * access the private structure.
89578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell */
90e21ffa44f55ebf7f6f7d1e60a49463ca579c056aBill Pemberton#define devpriv ((struct serial2002_private *)dev->private)
91578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
920a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int serial2002_attach(struct comedi_device *dev,
930a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_devconfig *it);
94da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int serial2002_detach(struct comedi_device *dev);
95139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88Bill Pembertonstruct comedi_driver driver_serial2002 = {
9668c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.driver_name = "serial2002",
9768c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.module = THIS_MODULE,
9868c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.attach = serial2002_attach,
9968c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.detach = serial2002_detach,
10068c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.board_name = &serial2002_boards[0].name,
10168c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.offset = sizeof(struct serial2002_board),
1028629efa4cbf6f89a54a85af4b8bc31762af01800Bill Pemberton	.num_names = ARRAY_SIZE(serial2002_boards),
103578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell};
104578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
1050a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int serial2002_di_rinsn(struct comedi_device *dev,
1060a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *s,
1070a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_insn *insn, unsigned int *data);
1080a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int serial2002_do_winsn(struct comedi_device *dev,
1090a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *s,
1100a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_insn *insn, unsigned int *data);
1110a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int serial2002_ai_rinsn(struct comedi_device *dev,
1120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *s,
1130a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_insn *insn, unsigned int *data);
1140a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int serial2002_ao_winsn(struct comedi_device *dev,
1150a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *s,
1160a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_insn *insn, unsigned int *data);
1170a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int serial2002_ao_rinsn(struct comedi_device *dev,
1180a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *s,
1190a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_insn *insn, unsigned int *data);
120578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
121578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdellstruct serial_data {
122578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	enum { is_invalid, is_digital, is_channel } kind;
123578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	int index;
124578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	unsigned long value;
125578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell};
126578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
127578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdellstatic long tty_ioctl(struct file *f, unsigned op, unsigned long param)
128578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell{
12900a1855c21ab1efc71db98b0a87ea3d0ee7b8d92Shawn Bohrer	if (f->f_op->unlocked_ioctl)
130578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		return f->f_op->unlocked_ioctl(f, op, param);
13100a1855c21ab1efc71db98b0a87ea3d0ee7b8d92Shawn Bohrer
132578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	return -ENOSYS;
133578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell}
134578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
135578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdellstatic int tty_write(struct file *f, unsigned char *buf, int count)
136578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell{
137578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	int result;
138578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	mm_segment_t oldfs;
139578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
140578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	oldfs = get_fs();
141578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	set_fs(KERNEL_DS);
142578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	f->f_pos = 0;
143578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	result = f->f_op->write(f, buf, count, &f->f_pos);
144578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	set_fs(oldfs);
145578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	return result;
146578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell}
147578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
148578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell#if 0
149578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell/*
150578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell * On 2.6.26.3 this occaisonally gave me page faults, worked around by
151578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell * settings.c_cc[VMIN] = 0; settings.c_cc[VTIME] = 0
152578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell */
153578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdellstatic int tty_available(struct file *f)
154578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell{
155578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	long result = 0;
156578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	mm_segment_t oldfs;
157578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
158578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	oldfs = get_fs();
159578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	set_fs(KERNEL_DS);
160578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	tty_ioctl(f, FIONREAD, (unsigned long)&result);
161578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	set_fs(oldfs);
162578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	return result;
163578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell}
164578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell#endif
165578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
166578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdellstatic int tty_read(struct file *f, int timeout)
167578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell{
168578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	int result;
169578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
170578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	result = -1;
171578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	if (!IS_ERR(f)) {
172578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		mm_segment_t oldfs;
173578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
174578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		oldfs = get_fs();
175578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		set_fs(KERNEL_DS);
176578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		if (f->f_op->poll) {
177578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			struct poll_wqueues table;
178578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			struct timeval start, now;
179578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
180578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			do_gettimeofday(&start);
181578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			poll_initwait(&table);
182578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			while (1) {
183578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				long elapsed;
184578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				int mask;
185578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
186578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				mask = f->f_op->poll(f, &table.pt);
187578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				if (mask & (POLLRDNORM | POLLRDBAND | POLLIN |
1880a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					    POLLHUP | POLLERR)) {
189578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					break;
190578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				}
191578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				do_gettimeofday(&now);
192578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				elapsed =
1930a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    (1000000 * (now.tv_sec - start.tv_sec) +
1940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				     now.tv_usec - start.tv_usec);
195b041267ea819054aa9b406efc94fe8821ea2e67bRavishankar				if (elapsed > timeout)
196578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					break;
197578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				set_current_state(TASK_INTERRUPTIBLE);
198578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				schedule_timeout(((timeout -
1990a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						   elapsed) * HZ) / 10000);
200578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			}
201578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			poll_freewait(&table);
202578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			{
2030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				unsigned char ch;
204578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
2050a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				f->f_pos = 0;
206b041267ea819054aa9b406efc94fe8821ea2e67bRavishankar				if (f->f_op->read(f, &ch, 1, &f->f_pos) == 1)
2070a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					result = ch;
208578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			}
209578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		} else {
210578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			/* Device does not support poll, busy wait */
211578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			int retries = 0;
212578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			while (1) {
213356cdbcb838ebcc234a43ec81621a39231fdcb7aBill Pemberton				unsigned char ch;
214578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
215578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				retries++;
216b041267ea819054aa9b406efc94fe8821ea2e67bRavishankar				if (retries >= timeout)
217578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					break;
218578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
219578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				f->f_pos = 0;
220578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				if (f->f_op->read(f, &ch, 1, &f->f_pos) == 1) {
221356cdbcb838ebcc234a43ec81621a39231fdcb7aBill Pemberton					result = ch;
222578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					break;
223578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				}
2245f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman				udelay(100);
225578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			}
226578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		}
227578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		set_fs(oldfs);
228578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	}
229578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	return result;
230578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell}
231578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
232578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdellstatic void tty_setspeed(struct file *f, int speed)
233578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell{
234578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	mm_segment_t oldfs;
235578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
236578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	oldfs = get_fs();
237578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	set_fs(KERNEL_DS);
238578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	{
2392696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton		/*  Set speed */
240578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		struct termios settings;
241578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
242578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		tty_ioctl(f, TCGETS, (unsigned long)&settings);
2432696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton/* printk("Speed: %d\n", settings.c_cflag & (CBAUD | CBAUDEX)); */
244578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		settings.c_iflag = 0;
245578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		settings.c_oflag = 0;
246578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		settings.c_lflag = 0;
247578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		settings.c_cflag = CLOCAL | CS8 | CREAD;
248578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		settings.c_cc[VMIN] = 0;
249578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		settings.c_cc[VTIME] = 0;
250578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		switch (speed) {
251578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		case 2400:{
252578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				settings.c_cflag |= B2400;
253578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			}
254578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			break;
255578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		case 4800:{
256578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				settings.c_cflag |= B4800;
257578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			}
258578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			break;
259578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		case 9600:{
260578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				settings.c_cflag |= B9600;
261578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			}
262578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			break;
263578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		case 19200:{
264578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				settings.c_cflag |= B19200;
265578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			}
266578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			break;
267578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		case 38400:{
268578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				settings.c_cflag |= B38400;
269578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			}
270578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			break;
271578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		case 57600:{
272578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				settings.c_cflag |= B57600;
273578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			}
274578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			break;
275578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		case 115200:{
276578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				settings.c_cflag |= B115200;
277578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			}
278578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			break;
279578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		default:{
280578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				settings.c_cflag |= B9600;
281578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			}
282578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			break;
283578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		}
284578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		tty_ioctl(f, TCSETS, (unsigned long)&settings);
2852696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton/* printk("Speed: %d\n", settings.c_cflag & (CBAUD | CBAUDEX)); */
286578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	}
287578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	{
2882696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton		/*  Set low latency */
289578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		struct serial_struct settings;
290578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
291578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		tty_ioctl(f, TIOCGSERIAL, (unsigned long)&settings);
292578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		settings.flags |= ASYNC_LOW_LATENCY;
293578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		tty_ioctl(f, TIOCSSERIAL, (unsigned long)&settings);
294578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	}
295578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
296578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	set_fs(oldfs);
297578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell}
298578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
299578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdellstatic void poll_digital(struct file *f, int channel)
300578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell{
301578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	char cmd;
302578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
303578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	cmd = 0x40 | (channel & 0x1f);
304578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	tty_write(f, &cmd, 1);
305578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell}
306578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
307578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdellstatic void poll_channel(struct file *f, int channel)
308578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell{
309578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	char cmd;
310578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
311578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	cmd = 0x60 | (channel & 0x1f);
312578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	tty_write(f, &cmd, 1);
313578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell}
314578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
315578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdellstatic struct serial_data serial_read(struct file *f, int timeout)
316578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell{
317578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	struct serial_data result;
318578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	int length;
319578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
320578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	result.kind = is_invalid;
321578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	result.index = 0;
322578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	result.value = 0;
323578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	length = 0;
324578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	while (1) {
325578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		int data = tty_read(f, timeout);
326578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
327578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		length++;
328578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		if (data < 0) {
329b041267ea819054aa9b406efc94fe8821ea2e67bRavishankar			printk(KERN_ERR "serial2002 error\n");
330578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			break;
331578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		} else if (data & 0x80) {
332578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			result.value = (result.value << 7) | (data & 0x7f);
333578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		} else {
334578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			if (length == 1) {
335578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				switch ((data >> 5) & 0x03) {
336578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				case 0:{
337578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell						result.value = 0;
338578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell						result.kind = is_digital;
339578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					}
340578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					break;
341578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				case 1:{
342578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell						result.value = 1;
343578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell						result.kind = is_digital;
344578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					}
345578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					break;
346578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				}
347578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			} else {
348578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				result.value =
3490a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    (result.value << 2) | ((data & 0x60) >> 5);
350578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				result.kind = is_channel;
351578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			}
352578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			result.index = data & 0x1f;
353578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			break;
354578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		}
355578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	}
356578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	return result;
357578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
358578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell}
359578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
360578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdellstatic void serial_write(struct file *f, struct serial_data data)
361578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell{
362578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	if (data.kind == is_digital) {
363578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		unsigned char ch =
3640a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    ((data.value << 5) & 0x20) | (data.index & 0x1f);
365578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		tty_write(f, &ch, 1);
366578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	} else {
367578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		unsigned char ch[6];
368578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		int i = 0;
369578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		if (data.value >= (1L << 30)) {
370578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			ch[i] = 0x80 | ((data.value >> 30) & 0x03);
371578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			i++;
372578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		}
373578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		if (data.value >= (1L << 23)) {
374578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			ch[i] = 0x80 | ((data.value >> 23) & 0x7f);
375578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			i++;
376578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		}
377578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		if (data.value >= (1L << 16)) {
378578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			ch[i] = 0x80 | ((data.value >> 16) & 0x7f);
379578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			i++;
380578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		}
381578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		if (data.value >= (1L << 9)) {
382578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			ch[i] = 0x80 | ((data.value >> 9) & 0x7f);
383578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			i++;
384578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		}
385578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		ch[i] = 0x80 | ((data.value >> 2) & 0x7f);
386578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		i++;
387578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		ch[i] = ((data.value << 5) & 0x60) | (data.index & 0x1f);
388578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		i++;
389578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		tty_write(f, ch, i);
390578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	}
391578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell}
392578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
3933c17ba0743d75f9888d905ddf9f8551c7dd36493Ian Abbottstatic int serial_2002_open(struct comedi_device *dev)
394578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell{
3953c17ba0743d75f9888d905ddf9f8551c7dd36493Ian Abbott	int result;
396578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	char port[20];
397578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
398578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	sprintf(port, "/dev/ttyS%d", devpriv->port);
3992021937c6d8ec1212b8f4fa01e86f852c9b96368OGAWA Hirofumi	devpriv->tty = filp_open(port, O_RDWR, 0);
400578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	if (IS_ERR(devpriv->tty)) {
4013c17ba0743d75f9888d905ddf9f8551c7dd36493Ian Abbott		result = (int)PTR_ERR(devpriv->tty);
402b041267ea819054aa9b406efc94fe8821ea2e67bRavishankar		printk(KERN_ERR "serial_2002: file open error = %d\n", result);
403578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	} else {
404e2b523aab1b04e7edc092588abbafa67f560deb4Bill Pemberton		struct config_t {
405e2b523aab1b04e7edc092588abbafa67f560deb4Bill Pemberton
40667a6efb1f86eb51e4b702c4e8e735ca24e3427d8Ian Abbott			short int kind;
40767a6efb1f86eb51e4b702c4e8e735ca24e3427d8Ian Abbott			short int bits;
408578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			int min;
409578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			int max;
410e2b523aab1b04e7edc092588abbafa67f560deb4Bill Pemberton		};
411e2b523aab1b04e7edc092588abbafa67f560deb4Bill Pemberton
412668f272e57e80ece987bed273096f8e3a707123cIan Abbott		struct config_t *dig_in_config;
413668f272e57e80ece987bed273096f8e3a707123cIan Abbott		struct config_t *dig_out_config;
414668f272e57e80ece987bed273096f8e3a707123cIan Abbott		struct config_t *chan_in_config;
415668f272e57e80ece987bed273096f8e3a707123cIan Abbott		struct config_t *chan_out_config;
416578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		int i;
417578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
4189e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott		result = 0;
419668f272e57e80ece987bed273096f8e3a707123cIan Abbott		dig_in_config = kcalloc(32, sizeof(struct config_t),
420668f272e57e80ece987bed273096f8e3a707123cIan Abbott				GFP_KERNEL);
421668f272e57e80ece987bed273096f8e3a707123cIan Abbott		dig_out_config = kcalloc(32, sizeof(struct config_t),
422668f272e57e80ece987bed273096f8e3a707123cIan Abbott				GFP_KERNEL);
423668f272e57e80ece987bed273096f8e3a707123cIan Abbott		chan_in_config = kcalloc(32, sizeof(struct config_t),
424668f272e57e80ece987bed273096f8e3a707123cIan Abbott				GFP_KERNEL);
425668f272e57e80ece987bed273096f8e3a707123cIan Abbott		chan_out_config = kcalloc(32, sizeof(struct config_t),
426668f272e57e80ece987bed273096f8e3a707123cIan Abbott				GFP_KERNEL);
427668f272e57e80ece987bed273096f8e3a707123cIan Abbott		if (!dig_in_config || !dig_out_config
428668f272e57e80ece987bed273096f8e3a707123cIan Abbott		    || !chan_in_config || !chan_out_config) {
429668f272e57e80ece987bed273096f8e3a707123cIan Abbott			result = -ENOMEM;
430668f272e57e80ece987bed273096f8e3a707123cIan Abbott			goto err_alloc_configs;
431578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		}
432578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
433578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		tty_setspeed(devpriv->tty, devpriv->speed);
4342696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton		poll_channel(devpriv->tty, 31);	/*  Start reading configuration */
435578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		while (1) {
436578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			struct serial_data data;
437578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
438578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			data = serial_read(devpriv->tty, 1000);
439578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			if (data.kind != is_channel || data.index != 31
4400a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    || !(data.value & 0xe0)) {
441578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				break;
442578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			} else {
443578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				int command, channel, kind;
444c5da20905c8ce21a73a9b443e5d7ef0dc623cff0Ian Abbott				struct config_t *cur_config = NULL;
445578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
446578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				channel = data.value & 0x1f;
447578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				kind = (data.value >> 5) & 0x7;
448578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				command = (data.value >> 8) & 0x3;
449578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				switch (kind) {
450578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				case 1:{
451578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell						cur_config = dig_in_config;
452578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					}
453578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					break;
454578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				case 2:{
455578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell						cur_config = dig_out_config;
456578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					}
457578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					break;
458578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				case 3:{
459578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell						cur_config = chan_in_config;
460578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					}
461578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					break;
462578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				case 4:{
463578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell						cur_config = chan_out_config;
464578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					}
465578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					break;
466578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				case 5:{
467578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell						cur_config = chan_in_config;
468578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					}
469578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					break;
470578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				}
471578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
472578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				if (cur_config) {
473578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					cur_config[channel].kind = kind;
474578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					switch (command) {
475578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					case 0:{
4760a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							cur_config[channel].bits
4770a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    =
4780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    (data.value >> 10) &
4790a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    0x3f;
480578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell						}
481578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell						break;
482578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					case 1:{
483578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell							int unit, sign, min;
4840a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							unit =
4850a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    (data.value >> 10) &
4860a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    0x7;
4870a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							sign =
4880a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    (data.value >> 13) &
4890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    0x1;
4900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							min =
4910a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    (data.value >> 14) &
4920a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    0xfffff;
493578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
494578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell							switch (unit) {
495578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell							case 0:{
4960a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									min =
4970a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									    min
4980a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									    *
4990a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									    1000000;
500578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell								}
501578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell								break;
502578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell							case 1:{
5030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									min =
5040a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									    min
5050a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									    *
5060a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									    1000;
507578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell								}
508578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell								break;
509578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell							case 2:{
5100a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									min =
5110a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									    min
5120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									    * 1;
513578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell								}
514578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell								break;
515578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell							}
516e9d1cf89ed5561adc1d36aea6d1349d12dfedd74Ravishankar							if (sign)
517578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell								min = -min;
5180a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							cur_config[channel].min
5190a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    = min;
520578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell						}
521578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell						break;
522578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					case 2:{
523578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell							int unit, sign, max;
5240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							unit =
5250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    (data.value >> 10) &
5260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    0x7;
5270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							sign =
5280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    (data.value >> 13) &
5290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    0x1;
5300a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							max =
5310a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    (data.value >> 14) &
5320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    0xfffff;
533578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
534578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell							switch (unit) {
535578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell							case 0:{
5360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									max =
5370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									    max
5380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									    *
5390a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									    1000000;
540578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell								}
541578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell								break;
542578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell							case 1:{
5430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									max =
5440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									    max
5450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									    *
5460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									    1000;
547578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell								}
548578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell								break;
549578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell							case 2:{
5500a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									max =
5510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									    max
5520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									    * 1;
553578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell								}
554578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell								break;
555578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell							}
556e9d1cf89ed5561adc1d36aea6d1349d12dfedd74Ravishankar							if (sign)
557578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell								max = -max;
5580a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							cur_config[channel].max
5590a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    = max;
560578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell						}
561578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell						break;
562578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					}
563578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				}
564578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			}
565578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		}
566578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		for (i = 0; i <= 4; i++) {
5672696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton			/*  Fill in subdev data */
568e2b523aab1b04e7edc092588abbafa67f560deb4Bill Pemberton			struct config_t *c;
569c5da20905c8ce21a73a9b443e5d7ef0dc623cff0Ian Abbott			unsigned char *mapping = NULL;
570c5da20905c8ce21a73a9b443e5d7ef0dc623cff0Ian Abbott			struct serial2002_range_table_t *range = NULL;
571578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			int kind = 0;
572578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
573578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			switch (i) {
574578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			case 0:{
575578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					c = dig_in_config;
576578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					mapping = devpriv->digital_in_mapping;
577578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					kind = 1;
578578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				}
579578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				break;
580578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			case 1:{
581578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					c = dig_out_config;
582578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					mapping = devpriv->digital_out_mapping;
583578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					kind = 2;
584578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				}
585578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				break;
586578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			case 2:{
587578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					c = chan_in_config;
588578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					mapping = devpriv->analog_in_mapping;
589578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					range = devpriv->in_range;
590578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					kind = 3;
591578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				}
592578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				break;
593578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			case 3:{
594578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					c = chan_out_config;
595578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					mapping = devpriv->analog_out_mapping;
596578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					range = devpriv->out_range;
597578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					kind = 4;
598578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				}
599578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				break;
600578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			case 4:{
601578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					c = chan_in_config;
602578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					mapping = devpriv->encoder_in_mapping;
603578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					range = devpriv->in_range;
604578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					kind = 5;
605578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				}
606578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				break;
607578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			default:{
608c5da20905c8ce21a73a9b443e5d7ef0dc623cff0Ian Abbott					c = NULL;
609578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				}
610578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				break;
611578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			}
612578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			if (c) {
61334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton				struct comedi_subdevice *s;
6140a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				const struct comedi_lrange **range_table_list =
6150a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    NULL;
616578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				unsigned int *maxdata_list;
617578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				int j, chan;
618578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
619578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				for (chan = 0, j = 0; j < 32; j++) {
620e9d1cf89ed5561adc1d36aea6d1349d12dfedd74Ravishankar					if (c[j].kind == kind)
621578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell						chan++;
622578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				}
623578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				s = &dev->subdevices[i];
624578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				s->n_chan = chan;
625578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				s->maxdata = 0;
6269e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott				kfree(s->maxdata_list);
627578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				s->maxdata_list = maxdata_list =
6280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    kmalloc(sizeof(unsigned int) * s->n_chan,
6290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					    GFP_KERNEL);
6309e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott				if (!s->maxdata_list)
6319e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott					break;	/* error handled below */
6329e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott				kfree(s->range_table_list);
6339e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott				s->range_table = NULL;
6349e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott				s->range_table_list = NULL;
635578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				if (range) {
636578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					s->range_table_list = range_table_list =
6370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					    kmalloc(sizeof
6380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						    (struct
6390a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						     serial2002_range_table_t) *
6400a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						    s->n_chan, GFP_KERNEL);
6419e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott					if (!s->range_table_list)
6429e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott						break;	/* err handled below */
643578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				}
644578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				for (chan = 0, j = 0; j < 32; j++) {
645578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					if (c[j].kind == kind) {
646e9d1cf89ed5561adc1d36aea6d1349d12dfedd74Ravishankar						if (mapping)
647578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell							mapping[chan] = j;
648578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell						if (range) {
649578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell							range[j].length = 1;
650578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell							range[j].range.min =
6510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    c[j].min;
652578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell							range[j].range.max =
6530a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    c[j].max;
654578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell							range_table_list[chan] =
6550a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    (const struct
6560a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							     comedi_lrange *)
6570a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    &range[j];
658578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell						}
659578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell						maxdata_list[chan] =
6600a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						    ((long long)1 << c[j].bits)
6610a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						    - 1;
662578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell						chan++;
663578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell					}
664578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				}
665578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			}
666578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		}
6679e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott		if (i <= 4) {
6689e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott			/* Failed to allocate maxdata_list or range_table_list
6699e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott			 * for a subdevice that needed it.  */
6709e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott			result = -ENOMEM;
6719e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott			for (i = 0; i <= 4; i++) {
6729e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott				struct comedi_subdevice *s;
6739e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott
6749e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott				s = &dev->subdevices[i];
6759e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott				kfree(s->maxdata_list);
6769e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott				s->maxdata_list = NULL;
6779e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott				kfree(s->range_table_list);
6789e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott				s->range_table_list = NULL;
6799e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott			}
6809e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott		}
681668f272e57e80ece987bed273096f8e3a707123cIan Abbott
682668f272e57e80ece987bed273096f8e3a707123cIan Abbotterr_alloc_configs:
683668f272e57e80ece987bed273096f8e3a707123cIan Abbott		kfree(dig_in_config);
684668f272e57e80ece987bed273096f8e3a707123cIan Abbott		kfree(dig_out_config);
685668f272e57e80ece987bed273096f8e3a707123cIan Abbott		kfree(chan_in_config);
686668f272e57e80ece987bed273096f8e3a707123cIan Abbott		kfree(chan_out_config);
687668f272e57e80ece987bed273096f8e3a707123cIan Abbott
6889e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott		if (result) {
6899e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott			if (devpriv->tty) {
6909e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott				filp_close(devpriv->tty, 0);
6919e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott				devpriv->tty = NULL;
6929e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott			}
6939e7f2256883c954691e5d395d471e0f125f6b30bIan Abbott		}
694578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	}
6953c17ba0743d75f9888d905ddf9f8551c7dd36493Ian Abbott	return result;
696578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell}
697578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
698da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void serial_2002_close(struct comedi_device *dev)
699578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell{
700e9d1cf89ed5561adc1d36aea6d1349d12dfedd74Ravishankar	if (!IS_ERR(devpriv->tty) && (devpriv->tty != 0))
701578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		filp_close(devpriv->tty, 0);
702578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell}
703578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
7040a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int serial2002_di_rinsn(struct comedi_device *dev,
7050a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *s,
7060a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_insn *insn, unsigned int *data)
707578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell{
708578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	int n;
709578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	int chan;
710578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
711578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	chan = devpriv->digital_in_mapping[CR_CHAN(insn->chanspec)];
712578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	for (n = 0; n < insn->n; n++) {
713578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		struct serial_data read;
714578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
715578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		poll_digital(devpriv->tty, chan);
716578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		while (1) {
717578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			read = serial_read(devpriv->tty, 1000);
718e9d1cf89ed5561adc1d36aea6d1349d12dfedd74Ravishankar			if (read.kind != is_digital || read.index == chan)
719578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				break;
720578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		}
721578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		data[n] = read.value;
722578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	}
723578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	return n;
724578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell}
725578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
7260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int serial2002_do_winsn(struct comedi_device *dev,
7270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *s,
7280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_insn *insn, unsigned int *data)
729578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell{
730578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	int n;
731578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	int chan;
732578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
733578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	chan = devpriv->digital_out_mapping[CR_CHAN(insn->chanspec)];
734578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	for (n = 0; n < insn->n; n++) {
735578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		struct serial_data write;
736578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
737578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		write.kind = is_digital;
738578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		write.index = chan;
739578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		write.value = data[n];
740578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		serial_write(devpriv->tty, write);
741578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	}
742578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	return n;
743578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell}
744578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
7450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int serial2002_ai_rinsn(struct comedi_device *dev,
7460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *s,
7470a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_insn *insn, unsigned int *data)
748578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell{
749578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	int n;
750578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	int chan;
751578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
752578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	chan = devpriv->analog_in_mapping[CR_CHAN(insn->chanspec)];
753578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	for (n = 0; n < insn->n; n++) {
754578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		struct serial_data read;
755578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
756578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		poll_channel(devpriv->tty, chan);
757578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		while (1) {
758578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			read = serial_read(devpriv->tty, 1000);
759e9d1cf89ed5561adc1d36aea6d1349d12dfedd74Ravishankar			if (read.kind != is_channel || read.index == chan)
760578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				break;
761578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		}
762578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		data[n] = read.value;
763578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	}
764578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	return n;
765578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell}
766578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
7670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int serial2002_ao_winsn(struct comedi_device *dev,
7680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *s,
7690a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_insn *insn, unsigned int *data)
770578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell{
771578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	int n;
772578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	int chan;
773578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
774578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	chan = devpriv->analog_out_mapping[CR_CHAN(insn->chanspec)];
775578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	for (n = 0; n < insn->n; n++) {
776578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		struct serial_data write;
777578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
778578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		write.kind = is_channel;
779578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		write.index = chan;
780578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		write.value = data[n];
781578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		serial_write(devpriv->tty, write);
782578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		devpriv->ao_readback[chan] = data[n];
783578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	}
784578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	return n;
785578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell}
786578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
7870a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int serial2002_ao_rinsn(struct comedi_device *dev,
7880a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *s,
7890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_insn *insn, unsigned int *data)
790578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell{
791578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	int n;
792578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	int chan = CR_CHAN(insn->chanspec);
793578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
794e9d1cf89ed5561adc1d36aea6d1349d12dfedd74Ravishankar	for (n = 0; n < insn->n; n++)
795578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		data[n] = devpriv->ao_readback[chan];
796578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
797578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	return n;
798578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell}
799578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
8000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int serial2002_ei_rinsn(struct comedi_device *dev,
8010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *s,
8020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_insn *insn, unsigned int *data)
803578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell{
804578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	int n;
805578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	int chan;
806578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
807578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	chan = devpriv->encoder_in_mapping[CR_CHAN(insn->chanspec)];
808578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	for (n = 0; n < insn->n; n++) {
809578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		struct serial_data read;
810578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
811578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		poll_channel(devpriv->tty, chan);
812578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		while (1) {
813578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell			read = serial_read(devpriv->tty, 1000);
814e9d1cf89ed5561adc1d36aea6d1349d12dfedd74Ravishankar			if (read.kind != is_channel || read.index == chan)
815578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell				break;
816578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		}
817578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		data[n] = read.value;
818578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	}
819578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	return n;
820578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell}
821578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
8220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int serial2002_attach(struct comedi_device *dev,
8230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_devconfig *it)
824578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell{
82534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
826578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
8273dbeb83c245bbdc906eb54821d1cd77a25f56741Ravishankar karkala Mallikarjunayya	dev_dbg(dev->hw_dev, "comedi%d: attached\n", dev->minor);
828578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	dev->board_name = thisboard->name;
829e9d1cf89ed5561adc1d36aea6d1349d12dfedd74Ravishankar	if (alloc_private(dev, sizeof(struct serial2002_private)) < 0)
830578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		return -ENOMEM;
831578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	dev->open = serial_2002_open;
832578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	dev->close = serial_2002_close;
833578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	devpriv->port = it->options[0];
834578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	devpriv->speed = it->options[1];
8353dbeb83c245bbdc906eb54821d1cd77a25f56741Ravishankar karkala Mallikarjunayya	dev_dbg(dev->hw_dev, "/dev/ttyS%d @ %d\n", devpriv->port,
8363dbeb83c245bbdc906eb54821d1cd77a25f56741Ravishankar karkala Mallikarjunayya		devpriv->speed);
837578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
838578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	if (alloc_subdevices(dev, 5) < 0)
839578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		return -ENOMEM;
840578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
841578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	/* digital input subdevice */
842578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s = dev->subdevices + 0;
843578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->type = COMEDI_SUBD_DI;
844578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->subdev_flags = SDF_READABLE;
845578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->n_chan = 0;
846578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->maxdata = 1;
847578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->range_table = &range_digital;
848578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->insn_read = &serial2002_di_rinsn;
849578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
850578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	/* digital output subdevice */
851578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s = dev->subdevices + 1;
852578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->type = COMEDI_SUBD_DO;
853578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->subdev_flags = SDF_WRITEABLE;
854578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->n_chan = 0;
855578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->maxdata = 1;
856578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->range_table = &range_digital;
857578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->insn_write = &serial2002_do_winsn;
858578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
859578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	/* analog input subdevice */
860578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s = dev->subdevices + 2;
861578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->type = COMEDI_SUBD_AI;
862578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->subdev_flags = SDF_READABLE | SDF_GROUND;
863578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->n_chan = 0;
864578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->maxdata = 1;
865578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->range_table = 0;
866578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->insn_read = &serial2002_ai_rinsn;
867578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
868578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	/* analog output subdevice */
869578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s = dev->subdevices + 3;
870578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->type = COMEDI_SUBD_AO;
871578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->subdev_flags = SDF_WRITEABLE;
872578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->n_chan = 0;
873578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->maxdata = 1;
874578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->range_table = 0;
875578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->insn_write = &serial2002_ao_winsn;
876578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->insn_read = &serial2002_ao_rinsn;
877578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
878578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	/* encoder input subdevice */
879578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s = dev->subdevices + 4;
880578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->type = COMEDI_SUBD_COUNTER;
881578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
882578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->n_chan = 0;
883578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->maxdata = 1;
884578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->range_table = 0;
885578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	s->insn_read = &serial2002_ei_rinsn;
886578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
887578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	return 1;
888578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell}
889578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
890da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int serial2002_detach(struct comedi_device *dev)
891578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell{
89234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
893578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	int i;
894578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
8953dbeb83c245bbdc906eb54821d1cd77a25f56741Ravishankar karkala Mallikarjunayya	dev_dbg(dev->hw_dev, "comedi%d: remove\n", dev->minor);
896fa3b5d9ab0487f58b45d55a37070aa0d417f59d5Ian Abbott	for (i = 0; i < 5; i++) {
897578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell		s = &dev->subdevices[i];
898e4e1f289be88a75dc8b63d50ade1f9a2e6168021Ilia Mirkin		kfree(s->maxdata_list);
899e4e1f289be88a75dc8b63d50ade1f9a2e6168021Ilia Mirkin		kfree(s->range_table_list);
900578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	}
901578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell	return 0;
902578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell}
903578c0183545d8fe99f8a65cfb1483360d18c1253Anders Blomdell
9047114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasstatic int __init driver_serial2002_init_module(void)
9057114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas{
9067114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas	return comedi_driver_register(&driver_serial2002);
9077114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas}
9087114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas
9097114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasstatic void __exit driver_serial2002_cleanup_module(void)
9107114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas{
9117114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas	comedi_driver_unregister(&driver_serial2002);
9127114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas}
9137114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas
9147114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasmodule_init(driver_serial2002_init_module);
9157114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasmodule_exit(driver_serial2002_cleanup_module);
91690f703d30dd3e0c16ff80f35e34e511385a05ad5Arun Thomas
91790f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_AUTHOR("Comedi http://www.comedi.org");
91890f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_DESCRIPTION("Comedi low-level driver");
91990f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_LICENSE("GPL");
920