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 /*
25 Driver: serial2002
26 Description: Driver for serial connected hardware
27 Devices:
28 Author: Anders Blomdell
29 Updated: Fri,  7 Jun 2002 12:56:45 -0700
30 Status: 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  */
51 struct serial2002_board {
52 	const char *name;
53 };
54 
55 static 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 
65 struct serial2002_range_table_t {
66 
67 	/*  HACK... */
68 	int length;
69 	struct comedi_krange range;
70 };
71 
72 struct 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 
92 static int serial2002_attach(struct comedi_device *dev,
93 			     struct comedi_devconfig *it);
94 static int serial2002_detach(struct comedi_device *dev);
95 struct 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 
105 static int serial2002_di_rinsn(struct comedi_device *dev,
106 			       struct comedi_subdevice *s,
107 			       struct comedi_insn *insn, unsigned int *data);
108 static int serial2002_do_winsn(struct comedi_device *dev,
109 			       struct comedi_subdevice *s,
110 			       struct comedi_insn *insn, unsigned int *data);
111 static int serial2002_ai_rinsn(struct comedi_device *dev,
112 			       struct comedi_subdevice *s,
113 			       struct comedi_insn *insn, unsigned int *data);
114 static int serial2002_ao_winsn(struct comedi_device *dev,
115 			       struct comedi_subdevice *s,
116 			       struct comedi_insn *insn, unsigned int *data);
117 static int serial2002_ao_rinsn(struct comedi_device *dev,
118 			       struct comedi_subdevice *s,
119 			       struct comedi_insn *insn, unsigned int *data);
120 
121 struct serial_data {
122 	enum { is_invalid, is_digital, is_channel } kind;
123 	int index;
124 	unsigned long value;
125 };
126 
tty_ioctl(struct file * f,unsigned op,unsigned long param)127 static 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 
tty_write(struct file * f,unsigned char * buf,int count)135 static 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  */
153 static 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 
tty_read(struct file * f,int timeout)166 static 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 
tty_setspeed(struct file * f,int speed)235 static 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 
poll_digital(struct file * f,int channel)302 static 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 
poll_channel(struct file * f,int channel)310 static 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 
serial_read(struct file * f,int timeout)318 static 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 
serial_write(struct file * f,struct serial_data data)363 static 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 
serial_2002_open(struct comedi_device * dev)396 static 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;
416 		struct config_t *dig_out_config;
417 		struct config_t *chan_in_config;
418 		struct config_t *chan_out_config;
419 		int i;
420 
421 		result = 0;
422 		dig_in_config = kcalloc(32, sizeof(struct config_t),
423 				GFP_KERNEL);
424 		dig_out_config = kcalloc(32, sizeof(struct config_t),
425 				GFP_KERNEL);
426 		chan_in_config = kcalloc(32, sizeof(struct config_t),
427 				GFP_KERNEL);
428 		chan_out_config = kcalloc(32, sizeof(struct config_t),
429 				GFP_KERNEL);
430 		if (!dig_in_config || !dig_out_config
431 		    || !chan_in_config || !chan_out_config) {
432 			result = -ENOMEM;
433 			goto err_alloc_configs;
434 		}
435 
436 		tty_setspeed(devpriv->tty, devpriv->speed);
437 		poll_channel(devpriv->tty, 31);	/*  Start reading configuration */
438 		while (1) {
439 			struct serial_data data;
440 
441 			data = serial_read(devpriv->tty, 1000);
442 			if (data.kind != is_channel || data.index != 31
443 			    || !(data.value & 0xe0)) {
444 				break;
445 			} else {
446 				int command, channel, kind;
447 				struct config_t *cur_config = NULL;
448 
449 				channel = data.value & 0x1f;
450 				kind = (data.value >> 5) & 0x7;
451 				command = (data.value >> 8) & 0x3;
452 				switch (kind) {
453 				case 1:{
454 						cur_config = dig_in_config;
455 					}
456 					break;
457 				case 2:{
458 						cur_config = dig_out_config;
459 					}
460 					break;
461 				case 3:{
462 						cur_config = chan_in_config;
463 					}
464 					break;
465 				case 4:{
466 						cur_config = chan_out_config;
467 					}
468 					break;
469 				case 5:{
470 						cur_config = chan_in_config;
471 					}
472 					break;
473 				}
474 
475 				if (cur_config) {
476 					cur_config[channel].kind = kind;
477 					switch (command) {
478 					case 0:{
479 							cur_config[channel].bits
480 							    =
481 							    (data.value >> 10) &
482 							    0x3f;
483 						}
484 						break;
485 					case 1:{
486 							int unit, sign, min;
487 							unit =
488 							    (data.value >> 10) &
489 							    0x7;
490 							sign =
491 							    (data.value >> 13) &
492 							    0x1;
493 							min =
494 							    (data.value >> 14) &
495 							    0xfffff;
496 
497 							switch (unit) {
498 							case 0:{
499 									min =
500 									    min
501 									    *
502 									    1000000;
503 								}
504 								break;
505 							case 1:{
506 									min =
507 									    min
508 									    *
509 									    1000;
510 								}
511 								break;
512 							case 2:{
513 									min =
514 									    min
515 									    * 1;
516 								}
517 								break;
518 							}
519 							if (sign) {
520 								min = -min;
521 							}
522 							cur_config[channel].min
523 							    = min;
524 						}
525 						break;
526 					case 2:{
527 							int unit, sign, max;
528 							unit =
529 							    (data.value >> 10) &
530 							    0x7;
531 							sign =
532 							    (data.value >> 13) &
533 							    0x1;
534 							max =
535 							    (data.value >> 14) &
536 							    0xfffff;
537 
538 							switch (unit) {
539 							case 0:{
540 									max =
541 									    max
542 									    *
543 									    1000000;
544 								}
545 								break;
546 							case 1:{
547 									max =
548 									    max
549 									    *
550 									    1000;
551 								}
552 								break;
553 							case 2:{
554 									max =
555 									    max
556 									    * 1;
557 								}
558 								break;
559 							}
560 							if (sign) {
561 								max = -max;
562 							}
563 							cur_config[channel].max
564 							    = max;
565 						}
566 						break;
567 					}
568 				}
569 			}
570 		}
571 		for (i = 0; i <= 4; i++) {
572 			/*  Fill in subdev data */
573 			struct config_t *c;
574 			unsigned char *mapping = NULL;
575 			struct serial2002_range_table_t *range = NULL;
576 			int kind = 0;
577 
578 			switch (i) {
579 			case 0:{
580 					c = dig_in_config;
581 					mapping = devpriv->digital_in_mapping;
582 					kind = 1;
583 				}
584 				break;
585 			case 1:{
586 					c = dig_out_config;
587 					mapping = devpriv->digital_out_mapping;
588 					kind = 2;
589 				}
590 				break;
591 			case 2:{
592 					c = chan_in_config;
593 					mapping = devpriv->analog_in_mapping;
594 					range = devpriv->in_range;
595 					kind = 3;
596 				}
597 				break;
598 			case 3:{
599 					c = chan_out_config;
600 					mapping = devpriv->analog_out_mapping;
601 					range = devpriv->out_range;
602 					kind = 4;
603 				}
604 				break;
605 			case 4:{
606 					c = chan_in_config;
607 					mapping = devpriv->encoder_in_mapping;
608 					range = devpriv->in_range;
609 					kind = 5;
610 				}
611 				break;
612 			default:{
613 					c = NULL;
614 				}
615 				break;
616 			}
617 			if (c) {
618 				struct comedi_subdevice *s;
619 				const struct comedi_lrange **range_table_list =
620 				    NULL;
621 				unsigned int *maxdata_list;
622 				int j, chan;
623 
624 				for (chan = 0, j = 0; j < 32; j++) {
625 					if (c[j].kind == kind) {
626 						chan++;
627 					}
628 				}
629 				s = &dev->subdevices[i];
630 				s->n_chan = chan;
631 				s->maxdata = 0;
632 				kfree(s->maxdata_list);
633 				s->maxdata_list = maxdata_list =
634 				    kmalloc(sizeof(unsigned int) * s->n_chan,
635 					    GFP_KERNEL);
636 				if (!s->maxdata_list)
637 					break;	/* error handled below */
638 				kfree(s->range_table_list);
639 				s->range_table = NULL;
640 				s->range_table_list = NULL;
641 				if (range) {
642 					s->range_table_list = range_table_list =
643 					    kmalloc(sizeof
644 						    (struct
645 						     serial2002_range_table_t) *
646 						    s->n_chan, GFP_KERNEL);
647 					if (!s->range_table_list)
648 						break;	/* err handled below */
649 				}
650 				for (chan = 0, j = 0; j < 32; j++) {
651 					if (c[j].kind == kind) {
652 						if (mapping) {
653 							mapping[chan] = j;
654 						}
655 						if (range) {
656 							range[j].length = 1;
657 							range[j].range.min =
658 							    c[j].min;
659 							range[j].range.max =
660 							    c[j].max;
661 							range_table_list[chan] =
662 							    (const struct
663 							     comedi_lrange *)
664 							    &range[j];
665 						}
666 						maxdata_list[chan] =
667 						    ((long long)1 << c[j].bits)
668 						    - 1;
669 						chan++;
670 					}
671 				}
672 			}
673 		}
674 		if (i <= 4) {
675 			/* Failed to allocate maxdata_list or range_table_list
676 			 * for a subdevice that needed it.  */
677 			result = -ENOMEM;
678 			for (i = 0; i <= 4; i++) {
679 				struct comedi_subdevice *s;
680 
681 				s = &dev->subdevices[i];
682 				kfree(s->maxdata_list);
683 				s->maxdata_list = NULL;
684 				kfree(s->range_table_list);
685 				s->range_table_list = NULL;
686 			}
687 		}
688 
689 err_alloc_configs:
690 		kfree(dig_in_config);
691 		kfree(dig_out_config);
692 		kfree(chan_in_config);
693 		kfree(chan_out_config);
694 
695 		if (result) {
696 			if (devpriv->tty) {
697 				filp_close(devpriv->tty, 0);
698 				devpriv->tty = NULL;
699 			}
700 		}
701 	}
702 	return result;
703 }
704 
serial_2002_close(struct comedi_device * dev)705 static void serial_2002_close(struct comedi_device *dev)
706 {
707 	if (!IS_ERR(devpriv->tty) && (devpriv->tty != 0)) {
708 		filp_close(devpriv->tty, 0);
709 	}
710 }
711 
serial2002_di_rinsn(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)712 static int serial2002_di_rinsn(struct comedi_device *dev,
713 			       struct comedi_subdevice *s,
714 			       struct comedi_insn *insn, unsigned int *data)
715 {
716 	int n;
717 	int chan;
718 
719 	chan = devpriv->digital_in_mapping[CR_CHAN(insn->chanspec)];
720 	for (n = 0; n < insn->n; n++) {
721 		struct serial_data read;
722 
723 		poll_digital(devpriv->tty, chan);
724 		while (1) {
725 			read = serial_read(devpriv->tty, 1000);
726 			if (read.kind != is_digital || read.index == chan) {
727 				break;
728 			}
729 		}
730 		data[n] = read.value;
731 	}
732 	return n;
733 }
734 
serial2002_do_winsn(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)735 static int serial2002_do_winsn(struct comedi_device *dev,
736 			       struct comedi_subdevice *s,
737 			       struct comedi_insn *insn, unsigned int *data)
738 {
739 	int n;
740 	int chan;
741 
742 	chan = devpriv->digital_out_mapping[CR_CHAN(insn->chanspec)];
743 	for (n = 0; n < insn->n; n++) {
744 		struct serial_data write;
745 
746 		write.kind = is_digital;
747 		write.index = chan;
748 		write.value = data[n];
749 		serial_write(devpriv->tty, write);
750 	}
751 	return n;
752 }
753 
serial2002_ai_rinsn(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)754 static int serial2002_ai_rinsn(struct comedi_device *dev,
755 			       struct comedi_subdevice *s,
756 			       struct comedi_insn *insn, unsigned int *data)
757 {
758 	int n;
759 	int chan;
760 
761 	chan = devpriv->analog_in_mapping[CR_CHAN(insn->chanspec)];
762 	for (n = 0; n < insn->n; n++) {
763 		struct serial_data read;
764 
765 		poll_channel(devpriv->tty, chan);
766 		while (1) {
767 			read = serial_read(devpriv->tty, 1000);
768 			if (read.kind != is_channel || read.index == chan) {
769 				break;
770 			}
771 		}
772 		data[n] = read.value;
773 	}
774 	return n;
775 }
776 
serial2002_ao_winsn(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)777 static int serial2002_ao_winsn(struct comedi_device *dev,
778 			       struct comedi_subdevice *s,
779 			       struct comedi_insn *insn, unsigned int *data)
780 {
781 	int n;
782 	int chan;
783 
784 	chan = devpriv->analog_out_mapping[CR_CHAN(insn->chanspec)];
785 	for (n = 0; n < insn->n; n++) {
786 		struct serial_data write;
787 
788 		write.kind = is_channel;
789 		write.index = chan;
790 		write.value = data[n];
791 		serial_write(devpriv->tty, write);
792 		devpriv->ao_readback[chan] = data[n];
793 	}
794 	return n;
795 }
796 
serial2002_ao_rinsn(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)797 static int serial2002_ao_rinsn(struct comedi_device *dev,
798 			       struct comedi_subdevice *s,
799 			       struct comedi_insn *insn, unsigned int *data)
800 {
801 	int n;
802 	int chan = CR_CHAN(insn->chanspec);
803 
804 	for (n = 0; n < insn->n; n++) {
805 		data[n] = devpriv->ao_readback[chan];
806 	}
807 
808 	return n;
809 }
810 
serial2002_ei_rinsn(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)811 static int serial2002_ei_rinsn(struct comedi_device *dev,
812 			       struct comedi_subdevice *s,
813 			       struct comedi_insn *insn, unsigned int *data)
814 {
815 	int n;
816 	int chan;
817 
818 	chan = devpriv->encoder_in_mapping[CR_CHAN(insn->chanspec)];
819 	for (n = 0; n < insn->n; n++) {
820 		struct serial_data read;
821 
822 		poll_channel(devpriv->tty, chan);
823 		while (1) {
824 			read = serial_read(devpriv->tty, 1000);
825 			if (read.kind != is_channel || read.index == chan) {
826 				break;
827 			}
828 		}
829 		data[n] = read.value;
830 	}
831 	return n;
832 }
833 
serial2002_attach(struct comedi_device * dev,struct comedi_devconfig * it)834 static int serial2002_attach(struct comedi_device *dev,
835 			     struct comedi_devconfig *it)
836 {
837 	struct comedi_subdevice *s;
838 
839 	printk("comedi%d: serial2002: ", dev->minor);
840 	dev->board_name = thisboard->name;
841 	if (alloc_private(dev, sizeof(struct serial2002_private)) < 0) {
842 		return -ENOMEM;
843 	}
844 	dev->open = serial_2002_open;
845 	dev->close = serial_2002_close;
846 	devpriv->port = it->options[0];
847 	devpriv->speed = it->options[1];
848 	printk("/dev/ttyS%d @ %d\n", devpriv->port, devpriv->speed);
849 
850 	if (alloc_subdevices(dev, 5) < 0)
851 		return -ENOMEM;
852 
853 	/* digital input subdevice */
854 	s = dev->subdevices + 0;
855 	s->type = COMEDI_SUBD_DI;
856 	s->subdev_flags = SDF_READABLE;
857 	s->n_chan = 0;
858 	s->maxdata = 1;
859 	s->range_table = &range_digital;
860 	s->insn_read = &serial2002_di_rinsn;
861 
862 	/* digital output subdevice */
863 	s = dev->subdevices + 1;
864 	s->type = COMEDI_SUBD_DO;
865 	s->subdev_flags = SDF_WRITEABLE;
866 	s->n_chan = 0;
867 	s->maxdata = 1;
868 	s->range_table = &range_digital;
869 	s->insn_write = &serial2002_do_winsn;
870 
871 	/* analog input subdevice */
872 	s = dev->subdevices + 2;
873 	s->type = COMEDI_SUBD_AI;
874 	s->subdev_flags = SDF_READABLE | SDF_GROUND;
875 	s->n_chan = 0;
876 	s->maxdata = 1;
877 	s->range_table = 0;
878 	s->insn_read = &serial2002_ai_rinsn;
879 
880 	/* analog output subdevice */
881 	s = dev->subdevices + 3;
882 	s->type = COMEDI_SUBD_AO;
883 	s->subdev_flags = SDF_WRITEABLE;
884 	s->n_chan = 0;
885 	s->maxdata = 1;
886 	s->range_table = 0;
887 	s->insn_write = &serial2002_ao_winsn;
888 	s->insn_read = &serial2002_ao_rinsn;
889 
890 	/* encoder input subdevice */
891 	s = dev->subdevices + 4;
892 	s->type = COMEDI_SUBD_COUNTER;
893 	s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
894 	s->n_chan = 0;
895 	s->maxdata = 1;
896 	s->range_table = 0;
897 	s->insn_read = &serial2002_ei_rinsn;
898 
899 	return 1;
900 }
901 
serial2002_detach(struct comedi_device * dev)902 static int serial2002_detach(struct comedi_device *dev)
903 {
904 	struct comedi_subdevice *s;
905 	int i;
906 
907 	printk("comedi%d: serial2002: remove\n", dev->minor);
908 	for (i = 0; i < 5; i++) {
909 		s = &dev->subdevices[i];
910 		kfree(s->maxdata_list);
911 		kfree(s->range_table_list);
912 	}
913 	return 0;
914 }
915 
driver_serial2002_init_module(void)916 static int __init driver_serial2002_init_module(void)
917 {
918 	return comedi_driver_register(&driver_serial2002);
919 }
920 
driver_serial2002_cleanup_module(void)921 static void __exit driver_serial2002_cleanup_module(void)
922 {
923 	comedi_driver_unregister(&driver_serial2002);
924 }
925 
926 module_init(driver_serial2002_init_module);
927 module_exit(driver_serial2002_cleanup_module);
928 
929 MODULE_AUTHOR("Comedi http://www.comedi.org");
930 MODULE_DESCRIPTION("Comedi low-level driver");
931 MODULE_LICENSE("GPL");
932