1 /*
2  * serial2002.c
3  * Comedi driver for serial connected hardware
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 
19 /*
20  * Driver: serial2002
21  * Description: Driver for serial connected hardware
22  * Devices:
23  * Author: Anders Blomdell
24  * Updated: Fri,  7 Jun 2002 12:56:45 -0700
25  * Status: in development
26  */
27 
28 #include <linux/module.h>
29 #include "../comedidev.h"
30 
31 #include <linux/delay.h>
32 #include <linux/sched.h>
33 #include <linux/slab.h>
34 #include <linux/ktime.h>
35 
36 #include <linux/termios.h>
37 #include <asm/ioctls.h>
38 #include <linux/serial.h>
39 #include <linux/poll.h>
40 
41 struct serial2002_range_table_t {
42 	/*  HACK... */
43 	int length;
44 	struct comedi_krange range;
45 };
46 
47 struct serial2002_private {
48 	int port;		/*  /dev/ttyS<port> */
49 	int speed;		/*  baudrate */
50 	struct file *tty;
51 	unsigned int ao_readback[32];
52 	unsigned char digital_in_mapping[32];
53 	unsigned char digital_out_mapping[32];
54 	unsigned char analog_in_mapping[32];
55 	unsigned char analog_out_mapping[32];
56 	unsigned char encoder_in_mapping[32];
57 	struct serial2002_range_table_t in_range[32], out_range[32];
58 };
59 
60 struct serial_data {
61 	enum { is_invalid, is_digital, is_channel } kind;
62 	int index;
63 	unsigned long value;
64 };
65 
66 /*
67  * The configuration serial_data.value read from the device is
68  * a bitmask that defines specific options of a channel:
69  *
70  * 4:0 - the channel to configure
71  * 7:5 - the kind of channel
72  * 9:8 - the command used to configure the channel
73  *
74  * The remaining bits vary in use depending on the command:
75  *
76  * BITS     15:10 - the channel bits (maxdata)
77  * MIN/MAX  12:10 - the units multiplier for the scale
78  *          13    - the sign of the scale
79  *          33:14 - the base value for the range
80  */
81 #define S2002_CFG_CHAN(x)		((x) & 0x1f)
82 #define S2002_CFG_KIND(x)		(((x) >> 5) & 0x7)
83 #define S2002_CFG_KIND_INVALID		0
84 #define S2002_CFG_KIND_DIGITAL_IN	1
85 #define S2002_CFG_KIND_DIGITAL_OUT	2
86 #define S2002_CFG_KIND_ANALOG_IN	3
87 #define S2002_CFG_KIND_ANALOG_OUT	4
88 #define S2002_CFG_KIND_ENCODER_IN	5
89 #define S2002_CFG_CMD(x)		(((x) >> 8) & 0x3)
90 #define S2002_CFG_CMD_BITS		0
91 #define S2002_CFG_CMD_MIN		1
92 #define S2002_CFG_CMD_MAX		2
93 #define S2002_CFG_BITS(x)		(((x) >> 10) & 0x3f)
94 #define S2002_CFG_UNITS(x)		(((x) >> 10) & 0x7)
95 #define S2002_CFG_SIGN(x)		(((x) >> 13) & 0x1)
96 #define S2002_CFG_BASE(x)		(((x) >> 14) & 0xfffff)
97 
serial2002_tty_ioctl(struct file * f,unsigned op,unsigned long param)98 static long serial2002_tty_ioctl(struct file *f, unsigned op,
99 				 unsigned long param)
100 {
101 	if (f->f_op->unlocked_ioctl)
102 		return f->f_op->unlocked_ioctl(f, op, param);
103 
104 	return -ENOTTY;
105 }
106 
serial2002_tty_write(struct file * f,unsigned char * buf,int count)107 static int serial2002_tty_write(struct file *f, unsigned char *buf, int count)
108 {
109 	const char __user *p = (__force const char __user *)buf;
110 	int result;
111 	loff_t offset = 0;
112 	mm_segment_t oldfs;
113 
114 	oldfs = get_fs();
115 	set_fs(KERNEL_DS);
116 	result = __vfs_write(f, p, count, &offset);
117 	set_fs(oldfs);
118 	return result;
119 }
120 
serial2002_tty_read_poll_wait(struct file * f,int timeout)121 static void serial2002_tty_read_poll_wait(struct file *f, int timeout)
122 {
123 	struct poll_wqueues table;
124 	ktime_t start, now;
125 
126 	start = ktime_get();
127 	poll_initwait(&table);
128 	while (1) {
129 		long elapsed;
130 		int mask;
131 
132 		mask = f->f_op->poll(f, &table.pt);
133 		if (mask & (POLLRDNORM | POLLRDBAND | POLLIN |
134 			    POLLHUP | POLLERR)) {
135 			break;
136 		}
137 		now = ktime_get();
138 		elapsed = ktime_us_delta(now, start);
139 		if (elapsed > timeout)
140 			break;
141 		set_current_state(TASK_INTERRUPTIBLE);
142 		schedule_timeout(((timeout - elapsed) * HZ) / 10000);
143 	}
144 	poll_freewait(&table);
145 }
146 
serial2002_tty_read(struct file * f,int timeout)147 static int serial2002_tty_read(struct file *f, int timeout)
148 {
149 	unsigned char ch;
150 	int result;
151 
152 	result = -1;
153 	if (!IS_ERR(f)) {
154 		mm_segment_t oldfs;
155 		char __user *p = (__force char __user *)&ch;
156 		loff_t offset = 0;
157 
158 		oldfs = get_fs();
159 		set_fs(KERNEL_DS);
160 		if (f->f_op->poll) {
161 			serial2002_tty_read_poll_wait(f, timeout);
162 
163 			if (__vfs_read(f, p, 1, &offset) == 1)
164 				result = ch;
165 		} else {
166 			/* Device does not support poll, busy wait */
167 			int retries = 0;
168 
169 			while (1) {
170 				retries++;
171 				if (retries >= timeout)
172 					break;
173 
174 				if (__vfs_read(f, p, 1, &offset) == 1) {
175 					result = ch;
176 					break;
177 				}
178 				usleep_range(100, 1000);
179 			}
180 		}
181 		set_fs(oldfs);
182 	}
183 	return result;
184 }
185 
serial2002_tty_setspeed(struct file * f,int speed)186 static void serial2002_tty_setspeed(struct file *f, int speed)
187 {
188 	struct termios termios;
189 	struct serial_struct serial;
190 	mm_segment_t oldfs;
191 
192 	oldfs = get_fs();
193 	set_fs(KERNEL_DS);
194 
195 	/* Set speed */
196 	serial2002_tty_ioctl(f, TCGETS, (unsigned long)&termios);
197 	termios.c_iflag = 0;
198 	termios.c_oflag = 0;
199 	termios.c_lflag = 0;
200 	termios.c_cflag = CLOCAL | CS8 | CREAD;
201 	termios.c_cc[VMIN] = 0;
202 	termios.c_cc[VTIME] = 0;
203 	switch (speed) {
204 	case 2400:
205 		termios.c_cflag |= B2400;
206 		break;
207 	case 4800:
208 		termios.c_cflag |= B4800;
209 		break;
210 	case 9600:
211 		termios.c_cflag |= B9600;
212 		break;
213 	case 19200:
214 		termios.c_cflag |= B19200;
215 		break;
216 	case 38400:
217 		termios.c_cflag |= B38400;
218 		break;
219 	case 57600:
220 		termios.c_cflag |= B57600;
221 		break;
222 	case 115200:
223 		termios.c_cflag |= B115200;
224 		break;
225 	default:
226 		termios.c_cflag |= B9600;
227 		break;
228 	}
229 	serial2002_tty_ioctl(f, TCSETS, (unsigned long)&termios);
230 
231 	/* Set low latency */
232 	serial2002_tty_ioctl(f, TIOCGSERIAL, (unsigned long)&serial);
233 	serial.flags |= ASYNC_LOW_LATENCY;
234 	serial2002_tty_ioctl(f, TIOCSSERIAL, (unsigned long)&serial);
235 
236 	set_fs(oldfs);
237 }
238 
serial2002_poll_digital(struct file * f,int channel)239 static void serial2002_poll_digital(struct file *f, int channel)
240 {
241 	char cmd;
242 
243 	cmd = 0x40 | (channel & 0x1f);
244 	serial2002_tty_write(f, &cmd, 1);
245 }
246 
serial2002_poll_channel(struct file * f,int channel)247 static void serial2002_poll_channel(struct file *f, int channel)
248 {
249 	char cmd;
250 
251 	cmd = 0x60 | (channel & 0x1f);
252 	serial2002_tty_write(f, &cmd, 1);
253 }
254 
serial2002_read(struct file * f,int timeout)255 static struct serial_data serial2002_read(struct file *f, int timeout)
256 {
257 	struct serial_data result;
258 	int length;
259 
260 	result.kind = is_invalid;
261 	result.index = 0;
262 	result.value = 0;
263 	length = 0;
264 	while (1) {
265 		int data = serial2002_tty_read(f, timeout);
266 
267 		length++;
268 		if (data < 0) {
269 			break;
270 		} else if (data & 0x80) {
271 			result.value = (result.value << 7) | (data & 0x7f);
272 		} else {
273 			if (length == 1) {
274 				switch ((data >> 5) & 0x03) {
275 				case 0:
276 					result.value = 0;
277 					result.kind = is_digital;
278 					break;
279 				case 1:
280 					result.value = 1;
281 					result.kind = is_digital;
282 					break;
283 				}
284 			} else {
285 				result.value =
286 				    (result.value << 2) | ((data & 0x60) >> 5);
287 				result.kind = is_channel;
288 			}
289 			result.index = data & 0x1f;
290 			break;
291 		}
292 	}
293 	return result;
294 }
295 
serial2002_write(struct file * f,struct serial_data data)296 static void serial2002_write(struct file *f, struct serial_data data)
297 {
298 	if (data.kind == is_digital) {
299 		unsigned char ch =
300 		    ((data.value << 5) & 0x20) | (data.index & 0x1f);
301 		serial2002_tty_write(f, &ch, 1);
302 	} else {
303 		unsigned char ch[6];
304 		int i = 0;
305 
306 		if (data.value >= (1L << 30)) {
307 			ch[i] = 0x80 | ((data.value >> 30) & 0x03);
308 			i++;
309 		}
310 		if (data.value >= (1L << 23)) {
311 			ch[i] = 0x80 | ((data.value >> 23) & 0x7f);
312 			i++;
313 		}
314 		if (data.value >= (1L << 16)) {
315 			ch[i] = 0x80 | ((data.value >> 16) & 0x7f);
316 			i++;
317 		}
318 		if (data.value >= (1L << 9)) {
319 			ch[i] = 0x80 | ((data.value >> 9) & 0x7f);
320 			i++;
321 		}
322 		ch[i] = 0x80 | ((data.value >> 2) & 0x7f);
323 		i++;
324 		ch[i] = ((data.value << 5) & 0x60) | (data.index & 0x1f);
325 		i++;
326 		serial2002_tty_write(f, ch, i);
327 	}
328 }
329 
330 struct config_t {
331 	short int kind;
332 	short int bits;
333 	int min;
334 	int max;
335 };
336 
serial2002_setup_subdevice(struct comedi_subdevice * s,struct config_t * cfg,struct serial2002_range_table_t * range,unsigned char * mapping,int kind)337 static int serial2002_setup_subdevice(struct comedi_subdevice *s,
338 				      struct config_t *cfg,
339 				      struct serial2002_range_table_t *range,
340 				      unsigned char *mapping,
341 				      int kind)
342 {
343 	const struct comedi_lrange **range_table_list = NULL;
344 	unsigned int *maxdata_list;
345 	int j, chan;
346 
347 	for (chan = 0, j = 0; j < 32; j++) {
348 		if (cfg[j].kind == kind)
349 			chan++;
350 	}
351 	s->n_chan = chan;
352 	s->maxdata = 0;
353 	kfree(s->maxdata_list);
354 	maxdata_list = kmalloc_array(s->n_chan, sizeof(unsigned int),
355 				     GFP_KERNEL);
356 	if (!maxdata_list)
357 		return -ENOMEM;
358 	s->maxdata_list = maxdata_list;
359 	kfree(s->range_table_list);
360 	s->range_table = NULL;
361 	s->range_table_list = NULL;
362 	if (kind == 1 || kind == 2) {
363 		s->range_table = &range_digital;
364 	} else if (range) {
365 		range_table_list = kmalloc_array(s->n_chan, sizeof(*range),
366 						 GFP_KERNEL);
367 		if (!range_table_list)
368 			return -ENOMEM;
369 		s->range_table_list = range_table_list;
370 	}
371 	for (chan = 0, j = 0; j < 32; j++) {
372 		if (cfg[j].kind == kind) {
373 			if (mapping)
374 				mapping[chan] = j;
375 			if (range && range_table_list) {
376 				range[j].length = 1;
377 				range[j].range.min = cfg[j].min;
378 				range[j].range.max = cfg[j].max;
379 				range_table_list[chan] =
380 				    (const struct comedi_lrange *)&range[j];
381 			}
382 			maxdata_list[chan] = ((long long)1 << cfg[j].bits) - 1;
383 			chan++;
384 		}
385 	}
386 	return 0;
387 }
388 
serial2002_setup_subdevs(struct comedi_device * dev)389 static int serial2002_setup_subdevs(struct comedi_device *dev)
390 {
391 	struct serial2002_private *devpriv = dev->private;
392 	struct config_t *di_cfg;
393 	struct config_t *do_cfg;
394 	struct config_t *ai_cfg;
395 	struct config_t *ao_cfg;
396 	struct config_t *cfg;
397 	struct comedi_subdevice *s;
398 	int result = 0;
399 	int i;
400 
401 	/* Allocate the temporary structs to hold the configuration data */
402 	di_cfg = kcalloc(32, sizeof(*cfg), GFP_KERNEL);
403 	do_cfg = kcalloc(32, sizeof(*cfg), GFP_KERNEL);
404 	ai_cfg = kcalloc(32, sizeof(*cfg), GFP_KERNEL);
405 	ao_cfg = kcalloc(32, sizeof(*cfg), GFP_KERNEL);
406 	if (!di_cfg || !do_cfg || !ai_cfg || !ao_cfg) {
407 		result = -ENOMEM;
408 		goto err_alloc_configs;
409 	}
410 
411 	/* Read the configuration from the connected device */
412 	serial2002_tty_setspeed(devpriv->tty, devpriv->speed);
413 	serial2002_poll_channel(devpriv->tty, 31);
414 	while (1) {
415 		struct serial_data data = serial2002_read(devpriv->tty, 1000);
416 		int kind = S2002_CFG_KIND(data.value);
417 		int channel = S2002_CFG_CHAN(data.value);
418 		int range = S2002_CFG_BASE(data.value);
419 		int cmd = S2002_CFG_CMD(data.value);
420 
421 		if (data.kind != is_channel || data.index != 31 ||
422 		    kind == S2002_CFG_KIND_INVALID)
423 			break;
424 
425 		switch (kind) {
426 		case S2002_CFG_KIND_DIGITAL_IN:
427 			cfg = di_cfg;
428 			break;
429 		case S2002_CFG_KIND_DIGITAL_OUT:
430 			cfg = do_cfg;
431 			break;
432 		case S2002_CFG_KIND_ANALOG_IN:
433 			cfg = ai_cfg;
434 			break;
435 		case S2002_CFG_KIND_ANALOG_OUT:
436 			cfg = ao_cfg;
437 			break;
438 		case S2002_CFG_KIND_ENCODER_IN:
439 			cfg = ai_cfg;
440 			break;
441 		default:
442 			cfg = NULL;
443 			break;
444 		}
445 		if (!cfg)
446 			continue;	/* unknown kind, skip it */
447 
448 		cfg[channel].kind = kind;
449 
450 		switch (cmd) {
451 		case S2002_CFG_CMD_BITS:
452 			cfg[channel].bits = S2002_CFG_BITS(data.value);
453 			break;
454 		case S2002_CFG_CMD_MIN:
455 		case S2002_CFG_CMD_MAX:
456 			switch (S2002_CFG_UNITS(data.value)) {
457 			case 0:
458 				range *= 1000000;
459 				break;
460 			case 1:
461 				range *= 1000;
462 				break;
463 			case 2:
464 				range *= 1;
465 				break;
466 			}
467 			if (S2002_CFG_SIGN(data.value))
468 				range = -range;
469 			if (cmd == S2002_CFG_CMD_MIN)
470 				cfg[channel].min = range;
471 			else
472 				cfg[channel].max = range;
473 			break;
474 		}
475 	}
476 
477 	/* Fill in subdevice data */
478 	for (i = 0; i <= 4; i++) {
479 		unsigned char *mapping = NULL;
480 		struct serial2002_range_table_t *range = NULL;
481 		int kind = 0;
482 
483 		s = &dev->subdevices[i];
484 
485 		switch (i) {
486 		case 0:
487 			cfg = di_cfg;
488 			mapping = devpriv->digital_in_mapping;
489 			kind = S2002_CFG_KIND_DIGITAL_IN;
490 			break;
491 		case 1:
492 			cfg = do_cfg;
493 			mapping = devpriv->digital_out_mapping;
494 			kind = S2002_CFG_KIND_DIGITAL_OUT;
495 			break;
496 		case 2:
497 			cfg = ai_cfg;
498 			mapping = devpriv->analog_in_mapping;
499 			range = devpriv->in_range;
500 			kind = S2002_CFG_KIND_ANALOG_IN;
501 			break;
502 		case 3:
503 			cfg = ao_cfg;
504 			mapping = devpriv->analog_out_mapping;
505 			range = devpriv->out_range;
506 			kind = S2002_CFG_KIND_ANALOG_OUT;
507 			break;
508 		case 4:
509 			cfg = ai_cfg;
510 			mapping = devpriv->encoder_in_mapping;
511 			range = devpriv->in_range;
512 			kind = S2002_CFG_KIND_ENCODER_IN;
513 			break;
514 		}
515 
516 		if (serial2002_setup_subdevice(s, cfg, range, mapping, kind))
517 			break;	/* err handled below */
518 	}
519 	if (i <= 4) {
520 		/*
521 		 * Failed to allocate maxdata_list or range_table_list
522 		 * for a subdevice that needed it.
523 		 */
524 		result = -ENOMEM;
525 		for (i = 0; i <= 4; i++) {
526 			s = &dev->subdevices[i];
527 			kfree(s->maxdata_list);
528 			s->maxdata_list = NULL;
529 			kfree(s->range_table_list);
530 			s->range_table_list = NULL;
531 		}
532 	}
533 
534 err_alloc_configs:
535 	kfree(di_cfg);
536 	kfree(do_cfg);
537 	kfree(ai_cfg);
538 	kfree(ao_cfg);
539 
540 	if (result) {
541 		if (devpriv->tty) {
542 			filp_close(devpriv->tty, NULL);
543 			devpriv->tty = NULL;
544 		}
545 	}
546 
547 	return result;
548 }
549 
serial2002_open(struct comedi_device * dev)550 static int serial2002_open(struct comedi_device *dev)
551 {
552 	struct serial2002_private *devpriv = dev->private;
553 	int result;
554 	char port[20];
555 
556 	sprintf(port, "/dev/ttyS%d", devpriv->port);
557 	devpriv->tty = filp_open(port, O_RDWR, 0);
558 	if (IS_ERR(devpriv->tty)) {
559 		result = (int)PTR_ERR(devpriv->tty);
560 		dev_err(dev->class_dev, "file open error = %d\n", result);
561 	} else {
562 		result = serial2002_setup_subdevs(dev);
563 	}
564 	return result;
565 }
566 
serial2002_close(struct comedi_device * dev)567 static void serial2002_close(struct comedi_device *dev)
568 {
569 	struct serial2002_private *devpriv = dev->private;
570 
571 	if (!IS_ERR(devpriv->tty) && devpriv->tty)
572 		filp_close(devpriv->tty, NULL);
573 }
574 
serial2002_di_insn_read(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)575 static int serial2002_di_insn_read(struct comedi_device *dev,
576 				   struct comedi_subdevice *s,
577 				   struct comedi_insn *insn,
578 				   unsigned int *data)
579 {
580 	struct serial2002_private *devpriv = dev->private;
581 	int n;
582 	int chan;
583 
584 	chan = devpriv->digital_in_mapping[CR_CHAN(insn->chanspec)];
585 	for (n = 0; n < insn->n; n++) {
586 		struct serial_data read;
587 
588 		serial2002_poll_digital(devpriv->tty, chan);
589 		while (1) {
590 			read = serial2002_read(devpriv->tty, 1000);
591 			if (read.kind != is_digital || read.index == chan)
592 				break;
593 		}
594 		data[n] = read.value;
595 	}
596 	return n;
597 }
598 
serial2002_do_insn_write(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)599 static int serial2002_do_insn_write(struct comedi_device *dev,
600 				    struct comedi_subdevice *s,
601 				    struct comedi_insn *insn,
602 				    unsigned int *data)
603 {
604 	struct serial2002_private *devpriv = dev->private;
605 	int n;
606 	int chan;
607 
608 	chan = devpriv->digital_out_mapping[CR_CHAN(insn->chanspec)];
609 	for (n = 0; n < insn->n; n++) {
610 		struct serial_data write;
611 
612 		write.kind = is_digital;
613 		write.index = chan;
614 		write.value = data[n];
615 		serial2002_write(devpriv->tty, write);
616 	}
617 	return n;
618 }
619 
serial2002_ai_insn_read(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)620 static int serial2002_ai_insn_read(struct comedi_device *dev,
621 				   struct comedi_subdevice *s,
622 				   struct comedi_insn *insn,
623 				   unsigned int *data)
624 {
625 	struct serial2002_private *devpriv = dev->private;
626 	int n;
627 	int chan;
628 
629 	chan = devpriv->analog_in_mapping[CR_CHAN(insn->chanspec)];
630 	for (n = 0; n < insn->n; n++) {
631 		struct serial_data read;
632 
633 		serial2002_poll_channel(devpriv->tty, chan);
634 		while (1) {
635 			read = serial2002_read(devpriv->tty, 1000);
636 			if (read.kind != is_channel || read.index == chan)
637 				break;
638 		}
639 		data[n] = read.value;
640 	}
641 	return n;
642 }
643 
serial2002_ao_insn_write(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)644 static int serial2002_ao_insn_write(struct comedi_device *dev,
645 				    struct comedi_subdevice *s,
646 				    struct comedi_insn *insn,
647 				    unsigned int *data)
648 {
649 	struct serial2002_private *devpriv = dev->private;
650 	int n;
651 	int chan;
652 
653 	chan = devpriv->analog_out_mapping[CR_CHAN(insn->chanspec)];
654 	for (n = 0; n < insn->n; n++) {
655 		struct serial_data write;
656 
657 		write.kind = is_channel;
658 		write.index = chan;
659 		write.value = data[n];
660 		serial2002_write(devpriv->tty, write);
661 		devpriv->ao_readback[chan] = data[n];
662 	}
663 	return n;
664 }
665 
serial2002_ao_insn_read(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)666 static int serial2002_ao_insn_read(struct comedi_device *dev,
667 				   struct comedi_subdevice *s,
668 				   struct comedi_insn *insn,
669 				   unsigned int *data)
670 {
671 	struct serial2002_private *devpriv = dev->private;
672 	int n;
673 	int chan = CR_CHAN(insn->chanspec);
674 
675 	for (n = 0; n < insn->n; n++)
676 		data[n] = devpriv->ao_readback[chan];
677 
678 	return n;
679 }
680 
serial2002_encoder_insn_read(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)681 static int serial2002_encoder_insn_read(struct comedi_device *dev,
682 					struct comedi_subdevice *s,
683 					struct comedi_insn *insn,
684 					unsigned int *data)
685 {
686 	struct serial2002_private *devpriv = dev->private;
687 	int n;
688 	int chan;
689 
690 	chan = devpriv->encoder_in_mapping[CR_CHAN(insn->chanspec)];
691 	for (n = 0; n < insn->n; n++) {
692 		struct serial_data read;
693 
694 		serial2002_poll_channel(devpriv->tty, chan);
695 		while (1) {
696 			read = serial2002_read(devpriv->tty, 1000);
697 			if (read.kind != is_channel || read.index == chan)
698 				break;
699 		}
700 		data[n] = read.value;
701 	}
702 	return n;
703 }
704 
serial2002_attach(struct comedi_device * dev,struct comedi_devconfig * it)705 static int serial2002_attach(struct comedi_device *dev,
706 			     struct comedi_devconfig *it)
707 {
708 	struct serial2002_private *devpriv;
709 	struct comedi_subdevice *s;
710 	int ret;
711 
712 	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
713 	if (!devpriv)
714 		return -ENOMEM;
715 
716 	devpriv->port = it->options[0];
717 	devpriv->speed = it->options[1];
718 
719 	ret = comedi_alloc_subdevices(dev, 5);
720 	if (ret)
721 		return ret;
722 
723 	/* digital input subdevice */
724 	s = &dev->subdevices[0];
725 	s->type		= COMEDI_SUBD_DI;
726 	s->subdev_flags	= SDF_READABLE;
727 	s->n_chan	= 0;
728 	s->maxdata	= 1;
729 	s->range_table	= &range_digital;
730 	s->insn_read	= serial2002_di_insn_read;
731 
732 	/* digital output subdevice */
733 	s = &dev->subdevices[1];
734 	s->type		= COMEDI_SUBD_DO;
735 	s->subdev_flags	= SDF_WRITABLE;
736 	s->n_chan	= 0;
737 	s->maxdata	= 1;
738 	s->range_table	= &range_digital;
739 	s->insn_write	= serial2002_do_insn_write;
740 
741 	/* analog input subdevice */
742 	s = &dev->subdevices[2];
743 	s->type		= COMEDI_SUBD_AI;
744 	s->subdev_flags	= SDF_READABLE | SDF_GROUND;
745 	s->n_chan	= 0;
746 	s->maxdata	= 1;
747 	s->range_table	= NULL;
748 	s->insn_read	= serial2002_ai_insn_read;
749 
750 	/* analog output subdevice */
751 	s = &dev->subdevices[3];
752 	s->type		= COMEDI_SUBD_AO;
753 	s->subdev_flags	= SDF_WRITABLE;
754 	s->n_chan	= 0;
755 	s->maxdata	= 1;
756 	s->range_table	= NULL;
757 	s->insn_write	= serial2002_ao_insn_write;
758 	s->insn_read	= serial2002_ao_insn_read;
759 
760 	/* encoder input subdevice */
761 	s = &dev->subdevices[4];
762 	s->type		= COMEDI_SUBD_COUNTER;
763 	s->subdev_flags	= SDF_READABLE | SDF_LSAMPL;
764 	s->n_chan	= 0;
765 	s->maxdata	= 1;
766 	s->range_table	= NULL;
767 	s->insn_read	= serial2002_encoder_insn_read;
768 
769 	dev->open	= serial2002_open;
770 	dev->close	= serial2002_close;
771 
772 	return 0;
773 }
774 
serial2002_detach(struct comedi_device * dev)775 static void serial2002_detach(struct comedi_device *dev)
776 {
777 	struct comedi_subdevice *s;
778 	int i;
779 
780 	for (i = 0; i < dev->n_subdevices; i++) {
781 		s = &dev->subdevices[i];
782 		kfree(s->maxdata_list);
783 		kfree(s->range_table_list);
784 	}
785 }
786 
787 static struct comedi_driver serial2002_driver = {
788 	.driver_name	= "serial2002",
789 	.module		= THIS_MODULE,
790 	.attach		= serial2002_attach,
791 	.detach		= serial2002_detach,
792 };
793 module_comedi_driver(serial2002_driver);
794 
795 MODULE_AUTHOR("Comedi http://www.comedi.org");
796 MODULE_DESCRIPTION("Comedi low-level driver");
797 MODULE_LICENSE("GPL");
798