serial2002.c revision fa3b5d9ab0487f58b45d55a37070aa0d417f59d5
1/*
2    comedi/drivers/serial2002.c
3    Skeleton code for a Comedi driver
4
5    COMEDI - Linux Control and Measurement Device Interface
6    Copyright (C) 2002 Anders Blomdell <anders.blomdell@control.lth.se>
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22*/
23
24/*
25Driver: serial2002
26Description: Driver for serial connected hardware
27Devices:
28Author: Anders Blomdell
29Updated: Fri,  7 Jun 2002 12:56:45 -0700
30Status: in development
31
32*/
33
34#include "../comedidev.h"
35
36#include <linux/delay.h>
37#include <linux/ioport.h>
38#include <linux/sched.h>
39#include <linux/slab.h>
40
41#include <asm/termios.h>
42#include <asm/ioctls.h>
43#include <linux/serial.h>
44#include <linux/poll.h>
45
46/*
47 * Board descriptions for two imaginary boards.  Describing the
48 * boards in this way is optional, and completely driver-dependent.
49 * Some drivers use arrays such as this, other do not.
50 */
51struct serial2002_board {
52	const char *name;
53};
54
55static const struct serial2002_board serial2002_boards[] = {
56	{
57	 .name = "serial2002"}
58};
59
60/*
61 * Useful for shorthand access to the particular board structure
62 */
63#define thisboard ((const struct serial2002_board *)dev->board_ptr)
64
65struct serial2002_range_table_t {
66
67	/*  HACK... */
68	int length;
69	struct comedi_krange range;
70};
71
72struct serial2002_private {
73
74	int port;		/*  /dev/ttyS<port> */
75	int speed;		/*  baudrate */
76	struct file *tty;
77	unsigned int ao_readback[32];
78	unsigned char digital_in_mapping[32];
79	unsigned char digital_out_mapping[32];
80	unsigned char analog_in_mapping[32];
81	unsigned char analog_out_mapping[32];
82	unsigned char encoder_in_mapping[32];
83	struct serial2002_range_table_t in_range[32], out_range[32];
84};
85
86/*
87 * most drivers define the following macro to make it easy to
88 * access the private structure.
89 */
90#define devpriv ((struct serial2002_private *)dev->private)
91
92static int serial2002_attach(struct comedi_device *dev,
93			     struct comedi_devconfig *it);
94static int serial2002_detach(struct comedi_device *dev);
95struct comedi_driver driver_serial2002 = {
96	.driver_name = "serial2002",
97	.module = THIS_MODULE,
98	.attach = serial2002_attach,
99	.detach = serial2002_detach,
100	.board_name = &serial2002_boards[0].name,
101	.offset = sizeof(struct serial2002_board),
102	.num_names = ARRAY_SIZE(serial2002_boards),
103};
104
105static int serial2002_di_rinsn(struct comedi_device *dev,
106			       struct comedi_subdevice *s,
107			       struct comedi_insn *insn, unsigned int *data);
108static int serial2002_do_winsn(struct comedi_device *dev,
109			       struct comedi_subdevice *s,
110			       struct comedi_insn *insn, unsigned int *data);
111static int serial2002_ai_rinsn(struct comedi_device *dev,
112			       struct comedi_subdevice *s,
113			       struct comedi_insn *insn, unsigned int *data);
114static int serial2002_ao_winsn(struct comedi_device *dev,
115			       struct comedi_subdevice *s,
116			       struct comedi_insn *insn, unsigned int *data);
117static int serial2002_ao_rinsn(struct comedi_device *dev,
118			       struct comedi_subdevice *s,
119			       struct comedi_insn *insn, unsigned int *data);
120
121struct serial_data {
122	enum { is_invalid, is_digital, is_channel } kind;
123	int index;
124	unsigned long value;
125};
126
127static long tty_ioctl(struct file *f, unsigned op, unsigned long param)
128{
129	if (f->f_op->unlocked_ioctl)
130		return f->f_op->unlocked_ioctl(f, op, param);
131
132	return -ENOSYS;
133}
134
135static int tty_write(struct file *f, unsigned char *buf, int count)
136{
137	int result;
138	mm_segment_t oldfs;
139
140	oldfs = get_fs();
141	set_fs(KERNEL_DS);
142	f->f_pos = 0;
143	result = f->f_op->write(f, buf, count, &f->f_pos);
144	set_fs(oldfs);
145	return result;
146}
147
148#if 0
149/*
150 * On 2.6.26.3 this occaisonally gave me page faults, worked around by
151 * settings.c_cc[VMIN] = 0; settings.c_cc[VTIME] = 0
152 */
153static int tty_available(struct file *f)
154{
155	long result = 0;
156	mm_segment_t oldfs;
157
158	oldfs = get_fs();
159	set_fs(KERNEL_DS);
160	tty_ioctl(f, FIONREAD, (unsigned long)&result);
161	set_fs(oldfs);
162	return result;
163}
164#endif
165
166static int tty_read(struct file *f, int timeout)
167{
168	int result;
169
170	result = -1;
171	if (!IS_ERR(f)) {
172		mm_segment_t oldfs;
173
174		oldfs = get_fs();
175		set_fs(KERNEL_DS);
176		if (f->f_op->poll) {
177			struct poll_wqueues table;
178			struct timeval start, now;
179
180			do_gettimeofday(&start);
181			poll_initwait(&table);
182			while (1) {
183				long elapsed;
184				int mask;
185
186				mask = f->f_op->poll(f, &table.pt);
187				if (mask & (POLLRDNORM | POLLRDBAND | POLLIN |
188					    POLLHUP | POLLERR)) {
189					break;
190				}
191				do_gettimeofday(&now);
192				elapsed =
193				    (1000000 * (now.tv_sec - start.tv_sec) +
194				     now.tv_usec - start.tv_usec);
195				if (elapsed > timeout) {
196					break;
197				}
198				set_current_state(TASK_INTERRUPTIBLE);
199				schedule_timeout(((timeout -
200						   elapsed) * HZ) / 10000);
201			}
202			poll_freewait(&table);
203			{
204				unsigned char ch;
205
206				f->f_pos = 0;
207				if (f->f_op->read(f, &ch, 1, &f->f_pos) == 1) {
208					result = ch;
209				}
210			}
211		} else {
212			/* Device does not support poll, busy wait */
213			int retries = 0;
214			while (1) {
215				unsigned char ch;
216
217				retries++;
218				if (retries >= timeout) {
219					break;
220				}
221
222				f->f_pos = 0;
223				if (f->f_op->read(f, &ch, 1, &f->f_pos) == 1) {
224					result = ch;
225					break;
226				}
227				udelay(100);
228			}
229		}
230		set_fs(oldfs);
231	}
232	return result;
233}
234
235static void tty_setspeed(struct file *f, int speed)
236{
237	mm_segment_t oldfs;
238
239	oldfs = get_fs();
240	set_fs(KERNEL_DS);
241	{
242		/*  Set speed */
243		struct termios settings;
244
245		tty_ioctl(f, TCGETS, (unsigned long)&settings);
246/* printk("Speed: %d\n", settings.c_cflag & (CBAUD | CBAUDEX)); */
247		settings.c_iflag = 0;
248		settings.c_oflag = 0;
249		settings.c_lflag = 0;
250		settings.c_cflag = CLOCAL | CS8 | CREAD;
251		settings.c_cc[VMIN] = 0;
252		settings.c_cc[VTIME] = 0;
253		switch (speed) {
254		case 2400:{
255				settings.c_cflag |= B2400;
256			}
257			break;
258		case 4800:{
259				settings.c_cflag |= B4800;
260			}
261			break;
262		case 9600:{
263				settings.c_cflag |= B9600;
264			}
265			break;
266		case 19200:{
267				settings.c_cflag |= B19200;
268			}
269			break;
270		case 38400:{
271				settings.c_cflag |= B38400;
272			}
273			break;
274		case 57600:{
275				settings.c_cflag |= B57600;
276			}
277			break;
278		case 115200:{
279				settings.c_cflag |= B115200;
280			}
281			break;
282		default:{
283				settings.c_cflag |= B9600;
284			}
285			break;
286		}
287		tty_ioctl(f, TCSETS, (unsigned long)&settings);
288/* printk("Speed: %d\n", settings.c_cflag & (CBAUD | CBAUDEX)); */
289	}
290	{
291		/*  Set low latency */
292		struct serial_struct settings;
293
294		tty_ioctl(f, TIOCGSERIAL, (unsigned long)&settings);
295		settings.flags |= ASYNC_LOW_LATENCY;
296		tty_ioctl(f, TIOCSSERIAL, (unsigned long)&settings);
297	}
298
299	set_fs(oldfs);
300}
301
302static void poll_digital(struct file *f, int channel)
303{
304	char cmd;
305
306	cmd = 0x40 | (channel & 0x1f);
307	tty_write(f, &cmd, 1);
308}
309
310static void poll_channel(struct file *f, int channel)
311{
312	char cmd;
313
314	cmd = 0x60 | (channel & 0x1f);
315	tty_write(f, &cmd, 1);
316}
317
318static struct serial_data serial_read(struct file *f, int timeout)
319{
320	struct serial_data result;
321	int length;
322
323	result.kind = is_invalid;
324	result.index = 0;
325	result.value = 0;
326	length = 0;
327	while (1) {
328		int data = tty_read(f, timeout);
329
330		length++;
331		if (data < 0) {
332			printk("serial2002 error\n");
333			break;
334		} else if (data & 0x80) {
335			result.value = (result.value << 7) | (data & 0x7f);
336		} else {
337			if (length == 1) {
338				switch ((data >> 5) & 0x03) {
339				case 0:{
340						result.value = 0;
341						result.kind = is_digital;
342					}
343					break;
344				case 1:{
345						result.value = 1;
346						result.kind = is_digital;
347					}
348					break;
349				}
350			} else {
351				result.value =
352				    (result.value << 2) | ((data & 0x60) >> 5);
353				result.kind = is_channel;
354			}
355			result.index = data & 0x1f;
356			break;
357		}
358	}
359	return result;
360
361}
362
363static void serial_write(struct file *f, struct serial_data data)
364{
365	if (data.kind == is_digital) {
366		unsigned char ch =
367		    ((data.value << 5) & 0x20) | (data.index & 0x1f);
368		tty_write(f, &ch, 1);
369	} else {
370		unsigned char ch[6];
371		int i = 0;
372		if (data.value >= (1L << 30)) {
373			ch[i] = 0x80 | ((data.value >> 30) & 0x03);
374			i++;
375		}
376		if (data.value >= (1L << 23)) {
377			ch[i] = 0x80 | ((data.value >> 23) & 0x7f);
378			i++;
379		}
380		if (data.value >= (1L << 16)) {
381			ch[i] = 0x80 | ((data.value >> 16) & 0x7f);
382			i++;
383		}
384		if (data.value >= (1L << 9)) {
385			ch[i] = 0x80 | ((data.value >> 9) & 0x7f);
386			i++;
387		}
388		ch[i] = 0x80 | ((data.value >> 2) & 0x7f);
389		i++;
390		ch[i] = ((data.value << 5) & 0x60) | (data.index & 0x1f);
391		i++;
392		tty_write(f, ch, i);
393	}
394}
395
396static int serial_2002_open(struct comedi_device *dev)
397{
398	int result;
399	char port[20];
400
401	sprintf(port, "/dev/ttyS%d", devpriv->port);
402	devpriv->tty = filp_open(port, O_RDWR, 0);
403	if (IS_ERR(devpriv->tty)) {
404		result = (int)PTR_ERR(devpriv->tty);
405		printk("serial_2002: file open error = %d\n", result);
406	} else {
407		struct config_t {
408
409			short int kind;
410			short int bits;
411			int min;
412			int max;
413		};
414
415		struct config_t dig_in_config[32];
416		struct config_t dig_out_config[32];
417		struct config_t chan_in_config[32];
418		struct config_t chan_out_config[32];
419		int i;
420
421		result = 0;
422		for (i = 0; i < 32; i++) {
423			dig_in_config[i].kind = 0;
424			dig_in_config[i].bits = 0;
425			dig_in_config[i].min = 0;
426			dig_in_config[i].max = 0;
427			dig_out_config[i].kind = 0;
428			dig_out_config[i].bits = 0;
429			dig_out_config[i].min = 0;
430			dig_out_config[i].max = 0;
431			chan_in_config[i].kind = 0;
432			chan_in_config[i].bits = 0;
433			chan_in_config[i].min = 0;
434			chan_in_config[i].max = 0;
435			chan_out_config[i].kind = 0;
436			chan_out_config[i].bits = 0;
437			chan_out_config[i].min = 0;
438			chan_out_config[i].max = 0;
439		}
440
441		tty_setspeed(devpriv->tty, devpriv->speed);
442		poll_channel(devpriv->tty, 31);	/*  Start reading configuration */
443		while (1) {
444			struct serial_data data;
445
446			data = serial_read(devpriv->tty, 1000);
447			if (data.kind != is_channel || data.index != 31
448			    || !(data.value & 0xe0)) {
449				break;
450			} else {
451				int command, channel, kind;
452				struct config_t *cur_config = 0;
453
454				channel = data.value & 0x1f;
455				kind = (data.value >> 5) & 0x7;
456				command = (data.value >> 8) & 0x3;
457				switch (kind) {
458				case 1:{
459						cur_config = dig_in_config;
460					}
461					break;
462				case 2:{
463						cur_config = dig_out_config;
464					}
465					break;
466				case 3:{
467						cur_config = chan_in_config;
468					}
469					break;
470				case 4:{
471						cur_config = chan_out_config;
472					}
473					break;
474				case 5:{
475						cur_config = chan_in_config;
476					}
477					break;
478				}
479
480				if (cur_config) {
481					cur_config[channel].kind = kind;
482					switch (command) {
483					case 0:{
484							cur_config[channel].bits
485							    =
486							    (data.value >> 10) &
487							    0x3f;
488						}
489						break;
490					case 1:{
491							int unit, sign, min;
492							unit =
493							    (data.value >> 10) &
494							    0x7;
495							sign =
496							    (data.value >> 13) &
497							    0x1;
498							min =
499							    (data.value >> 14) &
500							    0xfffff;
501
502							switch (unit) {
503							case 0:{
504									min =
505									    min
506									    *
507									    1000000;
508								}
509								break;
510							case 1:{
511									min =
512									    min
513									    *
514									    1000;
515								}
516								break;
517							case 2:{
518									min =
519									    min
520									    * 1;
521								}
522								break;
523							}
524							if (sign) {
525								min = -min;
526							}
527							cur_config[channel].min
528							    = min;
529						}
530						break;
531					case 2:{
532							int unit, sign, max;
533							unit =
534							    (data.value >> 10) &
535							    0x7;
536							sign =
537							    (data.value >> 13) &
538							    0x1;
539							max =
540							    (data.value >> 14) &
541							    0xfffff;
542
543							switch (unit) {
544							case 0:{
545									max =
546									    max
547									    *
548									    1000000;
549								}
550								break;
551							case 1:{
552									max =
553									    max
554									    *
555									    1000;
556								}
557								break;
558							case 2:{
559									max =
560									    max
561									    * 1;
562								}
563								break;
564							}
565							if (sign) {
566								max = -max;
567							}
568							cur_config[channel].max
569							    = max;
570						}
571						break;
572					}
573				}
574			}
575		}
576		for (i = 0; i <= 4; i++) {
577			/*  Fill in subdev data */
578			struct config_t *c;
579			unsigned char *mapping = 0;
580			struct serial2002_range_table_t *range = 0;
581			int kind = 0;
582
583			switch (i) {
584			case 0:{
585					c = dig_in_config;
586					mapping = devpriv->digital_in_mapping;
587					kind = 1;
588				}
589				break;
590			case 1:{
591					c = dig_out_config;
592					mapping = devpriv->digital_out_mapping;
593					kind = 2;
594				}
595				break;
596			case 2:{
597					c = chan_in_config;
598					mapping = devpriv->analog_in_mapping;
599					range = devpriv->in_range;
600					kind = 3;
601				}
602				break;
603			case 3:{
604					c = chan_out_config;
605					mapping = devpriv->analog_out_mapping;
606					range = devpriv->out_range;
607					kind = 4;
608				}
609				break;
610			case 4:{
611					c = chan_in_config;
612					mapping = devpriv->encoder_in_mapping;
613					range = devpriv->in_range;
614					kind = 5;
615				}
616				break;
617			default:{
618					c = 0;
619				}
620				break;
621			}
622			if (c) {
623				struct comedi_subdevice *s;
624				const struct comedi_lrange **range_table_list =
625				    NULL;
626				unsigned int *maxdata_list;
627				int j, chan;
628
629				for (chan = 0, j = 0; j < 32; j++) {
630					if (c[j].kind == kind) {
631						chan++;
632					}
633				}
634				s = &dev->subdevices[i];
635				s->n_chan = chan;
636				s->maxdata = 0;
637				kfree(s->maxdata_list);
638				s->maxdata_list = maxdata_list =
639				    kmalloc(sizeof(unsigned int) * s->n_chan,
640					    GFP_KERNEL);
641				if (!s->maxdata_list)
642					break;	/* error handled below */
643				kfree(s->range_table_list);
644				s->range_table = NULL;
645				s->range_table_list = NULL;
646				if (range) {
647					s->range_table_list = range_table_list =
648					    kmalloc(sizeof
649						    (struct
650						     serial2002_range_table_t) *
651						    s->n_chan, GFP_KERNEL);
652					if (!s->range_table_list)
653						break;	/* err handled below */
654				}
655				for (chan = 0, j = 0; j < 32; j++) {
656					if (c[j].kind == kind) {
657						if (mapping) {
658							mapping[chan] = j;
659						}
660						if (range) {
661							range[j].length = 1;
662							range[j].range.min =
663							    c[j].min;
664							range[j].range.max =
665							    c[j].max;
666							range_table_list[chan] =
667							    (const struct
668							     comedi_lrange *)
669							    &range[j];
670						}
671						maxdata_list[chan] =
672						    ((long long)1 << c[j].bits)
673						    - 1;
674						chan++;
675					}
676				}
677			}
678		}
679		if (i <= 4) {
680			/* Failed to allocate maxdata_list or range_table_list
681			 * for a subdevice that needed it.  */
682			result = -ENOMEM;
683			for (i = 0; i <= 4; i++) {
684				struct comedi_subdevice *s;
685
686				s = &dev->subdevices[i];
687				kfree(s->maxdata_list);
688				s->maxdata_list = NULL;
689				kfree(s->range_table_list);
690				s->range_table_list = NULL;
691			}
692		}
693		if (result) {
694			if (devpriv->tty) {
695				filp_close(devpriv->tty, 0);
696				devpriv->tty = NULL;
697			}
698		}
699	}
700	return result;
701}
702
703static void serial_2002_close(struct comedi_device *dev)
704{
705	if (!IS_ERR(devpriv->tty) && (devpriv->tty != 0)) {
706		filp_close(devpriv->tty, 0);
707	}
708}
709
710static int serial2002_di_rinsn(struct comedi_device *dev,
711			       struct comedi_subdevice *s,
712			       struct comedi_insn *insn, unsigned int *data)
713{
714	int n;
715	int chan;
716
717	chan = devpriv->digital_in_mapping[CR_CHAN(insn->chanspec)];
718	for (n = 0; n < insn->n; n++) {
719		struct serial_data read;
720
721		poll_digital(devpriv->tty, chan);
722		while (1) {
723			read = serial_read(devpriv->tty, 1000);
724			if (read.kind != is_digital || read.index == chan) {
725				break;
726			}
727		}
728		data[n] = read.value;
729	}
730	return n;
731}
732
733static int serial2002_do_winsn(struct comedi_device *dev,
734			       struct comedi_subdevice *s,
735			       struct comedi_insn *insn, unsigned int *data)
736{
737	int n;
738	int chan;
739
740	chan = devpriv->digital_out_mapping[CR_CHAN(insn->chanspec)];
741	for (n = 0; n < insn->n; n++) {
742		struct serial_data write;
743
744		write.kind = is_digital;
745		write.index = chan;
746		write.value = data[n];
747		serial_write(devpriv->tty, write);
748	}
749	return n;
750}
751
752static int serial2002_ai_rinsn(struct comedi_device *dev,
753			       struct comedi_subdevice *s,
754			       struct comedi_insn *insn, unsigned int *data)
755{
756	int n;
757	int chan;
758
759	chan = devpriv->analog_in_mapping[CR_CHAN(insn->chanspec)];
760	for (n = 0; n < insn->n; n++) {
761		struct serial_data read;
762
763		poll_channel(devpriv->tty, chan);
764		while (1) {
765			read = serial_read(devpriv->tty, 1000);
766			if (read.kind != is_channel || read.index == chan) {
767				break;
768			}
769		}
770		data[n] = read.value;
771	}
772	return n;
773}
774
775static int serial2002_ao_winsn(struct comedi_device *dev,
776			       struct comedi_subdevice *s,
777			       struct comedi_insn *insn, unsigned int *data)
778{
779	int n;
780	int chan;
781
782	chan = devpriv->analog_out_mapping[CR_CHAN(insn->chanspec)];
783	for (n = 0; n < insn->n; n++) {
784		struct serial_data write;
785
786		write.kind = is_channel;
787		write.index = chan;
788		write.value = data[n];
789		serial_write(devpriv->tty, write);
790		devpriv->ao_readback[chan] = data[n];
791	}
792	return n;
793}
794
795static int serial2002_ao_rinsn(struct comedi_device *dev,
796			       struct comedi_subdevice *s,
797			       struct comedi_insn *insn, unsigned int *data)
798{
799	int n;
800	int chan = CR_CHAN(insn->chanspec);
801
802	for (n = 0; n < insn->n; n++) {
803		data[n] = devpriv->ao_readback[chan];
804	}
805
806	return n;
807}
808
809static int serial2002_ei_rinsn(struct comedi_device *dev,
810			       struct comedi_subdevice *s,
811			       struct comedi_insn *insn, unsigned int *data)
812{
813	int n;
814	int chan;
815
816	chan = devpriv->encoder_in_mapping[CR_CHAN(insn->chanspec)];
817	for (n = 0; n < insn->n; n++) {
818		struct serial_data read;
819
820		poll_channel(devpriv->tty, chan);
821		while (1) {
822			read = serial_read(devpriv->tty, 1000);
823			if (read.kind != is_channel || read.index == chan) {
824				break;
825			}
826		}
827		data[n] = read.value;
828	}
829	return n;
830}
831
832static int serial2002_attach(struct comedi_device *dev,
833			     struct comedi_devconfig *it)
834{
835	struct comedi_subdevice *s;
836
837	printk("comedi%d: serial2002: ", dev->minor);
838	dev->board_name = thisboard->name;
839	if (alloc_private(dev, sizeof(struct serial2002_private)) < 0) {
840		return -ENOMEM;
841	}
842	dev->open = serial_2002_open;
843	dev->close = serial_2002_close;
844	devpriv->port = it->options[0];
845	devpriv->speed = it->options[1];
846	printk("/dev/ttyS%d @ %d\n", devpriv->port, devpriv->speed);
847
848	if (alloc_subdevices(dev, 5) < 0)
849		return -ENOMEM;
850
851	/* digital input subdevice */
852	s = dev->subdevices + 0;
853	s->type = COMEDI_SUBD_DI;
854	s->subdev_flags = SDF_READABLE;
855	s->n_chan = 0;
856	s->maxdata = 1;
857	s->range_table = &range_digital;
858	s->insn_read = &serial2002_di_rinsn;
859
860	/* digital output subdevice */
861	s = dev->subdevices + 1;
862	s->type = COMEDI_SUBD_DO;
863	s->subdev_flags = SDF_WRITEABLE;
864	s->n_chan = 0;
865	s->maxdata = 1;
866	s->range_table = &range_digital;
867	s->insn_write = &serial2002_do_winsn;
868
869	/* analog input subdevice */
870	s = dev->subdevices + 2;
871	s->type = COMEDI_SUBD_AI;
872	s->subdev_flags = SDF_READABLE | SDF_GROUND;
873	s->n_chan = 0;
874	s->maxdata = 1;
875	s->range_table = 0;
876	s->insn_read = &serial2002_ai_rinsn;
877
878	/* analog output subdevice */
879	s = dev->subdevices + 3;
880	s->type = COMEDI_SUBD_AO;
881	s->subdev_flags = SDF_WRITEABLE;
882	s->n_chan = 0;
883	s->maxdata = 1;
884	s->range_table = 0;
885	s->insn_write = &serial2002_ao_winsn;
886	s->insn_read = &serial2002_ao_rinsn;
887
888	/* encoder input subdevice */
889	s = dev->subdevices + 4;
890	s->type = COMEDI_SUBD_COUNTER;
891	s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
892	s->n_chan = 0;
893	s->maxdata = 1;
894	s->range_table = 0;
895	s->insn_read = &serial2002_ei_rinsn;
896
897	return 1;
898}
899
900static int serial2002_detach(struct comedi_device *dev)
901{
902	struct comedi_subdevice *s;
903	int i;
904
905	printk("comedi%d: serial2002: remove\n", dev->minor);
906	for (i = 0; i < 5; i++) {
907		s = &dev->subdevices[i];
908		if (s->maxdata_list) {
909			kfree(s->maxdata_list);
910		}
911		if (s->range_table_list) {
912			kfree(s->range_table_list);
913		}
914	}
915	return 0;
916}
917
918COMEDI_INITCLEANUP(driver_serial2002);
919