Staging: comedi: fix sched.h build breakage
[linux-2.6/mini2440.git] / drivers / staging / comedi / drivers / serial2002.c
blob82aa86e718b2c819ff6e81e33282eda355ea8e08
1 /*
2 comedi/drivers/serial2002.c
3 Skeleton code for a Comedi driver
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 2002 Anders Blomdell <anders.blomdell@control.lth.se>
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.
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.
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.
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
34 #include "../comedidev.h"
36 #include <linux/delay.h>
37 #include <linux/ioport.h>
38 #include <linux/sched.h>
40 #include <asm/termios.h>
41 #include <asm/ioctls.h>
42 #include <linux/serial.h>
43 #include <linux/poll.h>
46 * Board descriptions for two imaginary boards. Describing the
47 * boards in this way is optional, and completely driver-dependent.
48 * Some drivers use arrays such as this, other do not.
50 struct serial2002_board {
51 const char *name;
54 static const struct serial2002_board serial2002_boards[] = {
56 .name = "serial2002"}
60 * Useful for shorthand access to the particular board structure
62 #define thisboard ((const struct serial2002_board *)dev->board_ptr)
64 struct serial2002_range_table_t {
66 /* HACK... */
67 int length;
68 struct comedi_krange range;
71 struct serial2002_private {
73 int port; /* /dev/ttyS<port> */
74 int speed; /* baudrate */
75 struct file *tty;
76 unsigned int ao_readback[32];
77 unsigned char digital_in_mapping[32];
78 unsigned char digital_out_mapping[32];
79 unsigned char analog_in_mapping[32];
80 unsigned char analog_out_mapping[32];
81 unsigned char encoder_in_mapping[32];
82 struct serial2002_range_table_t in_range[32], out_range[32];
86 * most drivers define the following macro to make it easy to
87 * access the private structure.
89 #define devpriv ((struct serial2002_private *)dev->private)
91 static int serial2002_attach(struct comedi_device *dev,
92 struct comedi_devconfig *it);
93 static int serial2002_detach(struct comedi_device *dev);
94 struct comedi_driver driver_serial2002 = {
95 .driver_name = "serial2002",
96 .module = THIS_MODULE,
97 .attach = serial2002_attach,
98 .detach = serial2002_detach,
99 .board_name = &serial2002_boards[0].name,
100 .offset = sizeof(struct serial2002_board),
101 .num_names = ARRAY_SIZE(serial2002_boards),
104 static int serial2002_di_rinsn(struct comedi_device *dev,
105 struct comedi_subdevice *s,
106 struct comedi_insn *insn, unsigned int *data);
107 static int serial2002_do_winsn(struct comedi_device *dev,
108 struct comedi_subdevice *s,
109 struct comedi_insn *insn, unsigned int *data);
110 static int serial2002_ai_rinsn(struct comedi_device *dev,
111 struct comedi_subdevice *s,
112 struct comedi_insn *insn, unsigned int *data);
113 static int serial2002_ao_winsn(struct comedi_device *dev,
114 struct comedi_subdevice *s,
115 struct comedi_insn *insn, unsigned int *data);
116 static int serial2002_ao_rinsn(struct comedi_device *dev,
117 struct comedi_subdevice *s,
118 struct comedi_insn *insn, unsigned int *data);
120 struct serial_data {
121 enum { is_invalid, is_digital, is_channel } kind;
122 int index;
123 unsigned long value;
126 static long tty_ioctl(struct file *f, unsigned op, unsigned long param)
128 #ifdef HAVE_UNLOCKED_IOCTL
129 if (f->f_op->unlocked_ioctl) {
130 return f->f_op->unlocked_ioctl(f, op, param);
132 #endif
133 if (f->f_op->ioctl) {
134 return f->f_op->ioctl(f->f_dentry->d_inode, f, op, param);
136 return -ENOSYS;
139 static int tty_write(struct file *f, unsigned char *buf, int count)
141 int result;
142 mm_segment_t oldfs;
144 oldfs = get_fs();
145 set_fs(KERNEL_DS);
146 f->f_pos = 0;
147 result = f->f_op->write(f, buf, count, &f->f_pos);
148 set_fs(oldfs);
149 return result;
152 #if 0
154 * On 2.6.26.3 this occaisonally gave me page faults, worked around by
155 * settings.c_cc[VMIN] = 0; settings.c_cc[VTIME] = 0
157 static int tty_available(struct file *f)
159 long result = 0;
160 mm_segment_t oldfs;
162 oldfs = get_fs();
163 set_fs(KERNEL_DS);
164 tty_ioctl(f, FIONREAD, (unsigned long)&result);
165 set_fs(oldfs);
166 return result;
168 #endif
170 static int tty_read(struct file *f, int timeout)
172 int result;
174 result = -1;
175 if (!IS_ERR(f)) {
176 mm_segment_t oldfs;
178 oldfs = get_fs();
179 set_fs(KERNEL_DS);
180 if (f->f_op->poll) {
181 struct poll_wqueues table;
182 struct timeval start, now;
184 do_gettimeofday(&start);
185 poll_initwait(&table);
186 while (1) {
187 long elapsed;
188 int mask;
190 mask = f->f_op->poll(f, &table.pt);
191 if (mask & (POLLRDNORM | POLLRDBAND | POLLIN |
192 POLLHUP | POLLERR)) {
193 break;
195 do_gettimeofday(&now);
196 elapsed =
197 (1000000 * (now.tv_sec - start.tv_sec) +
198 now.tv_usec - start.tv_usec);
199 if (elapsed > timeout) {
200 break;
202 set_current_state(TASK_INTERRUPTIBLE);
203 schedule_timeout(((timeout -
204 elapsed) * HZ) / 10000);
206 poll_freewait(&table);
208 unsigned char ch;
210 f->f_pos = 0;
211 if (f->f_op->read(f, &ch, 1, &f->f_pos) == 1) {
212 result = ch;
215 } else {
216 /* Device does not support poll, busy wait */
217 int retries = 0;
218 while (1) {
219 unsigned char ch;
221 retries++;
222 if (retries >= timeout) {
223 break;
226 f->f_pos = 0;
227 if (f->f_op->read(f, &ch, 1, &f->f_pos) == 1) {
228 result = ch;
229 break;
231 udelay(100);
234 set_fs(oldfs);
236 return result;
239 static void tty_setspeed(struct file *f, int speed)
241 mm_segment_t oldfs;
243 oldfs = get_fs();
244 set_fs(KERNEL_DS);
246 /* Set speed */
247 struct termios settings;
249 tty_ioctl(f, TCGETS, (unsigned long)&settings);
250 /* printk("Speed: %d\n", settings.c_cflag & (CBAUD | CBAUDEX)); */
251 settings.c_iflag = 0;
252 settings.c_oflag = 0;
253 settings.c_lflag = 0;
254 settings.c_cflag = CLOCAL | CS8 | CREAD;
255 settings.c_cc[VMIN] = 0;
256 settings.c_cc[VTIME] = 0;
257 switch (speed) {
258 case 2400:{
259 settings.c_cflag |= B2400;
261 break;
262 case 4800:{
263 settings.c_cflag |= B4800;
265 break;
266 case 9600:{
267 settings.c_cflag |= B9600;
269 break;
270 case 19200:{
271 settings.c_cflag |= B19200;
273 break;
274 case 38400:{
275 settings.c_cflag |= B38400;
277 break;
278 case 57600:{
279 settings.c_cflag |= B57600;
281 break;
282 case 115200:{
283 settings.c_cflag |= B115200;
285 break;
286 default:{
287 settings.c_cflag |= B9600;
289 break;
291 tty_ioctl(f, TCSETS, (unsigned long)&settings);
292 /* printk("Speed: %d\n", settings.c_cflag & (CBAUD | CBAUDEX)); */
295 /* Set low latency */
296 struct serial_struct settings;
298 tty_ioctl(f, TIOCGSERIAL, (unsigned long)&settings);
299 settings.flags |= ASYNC_LOW_LATENCY;
300 tty_ioctl(f, TIOCSSERIAL, (unsigned long)&settings);
303 set_fs(oldfs);
306 static void poll_digital(struct file *f, int channel)
308 char cmd;
310 cmd = 0x40 | (channel & 0x1f);
311 tty_write(f, &cmd, 1);
314 static void poll_channel(struct file *f, int channel)
316 char cmd;
318 cmd = 0x60 | (channel & 0x1f);
319 tty_write(f, &cmd, 1);
322 static struct serial_data serial_read(struct file *f, int timeout)
324 struct serial_data result;
325 int length;
327 result.kind = is_invalid;
328 result.index = 0;
329 result.value = 0;
330 length = 0;
331 while (1) {
332 int data = tty_read(f, timeout);
334 length++;
335 if (data < 0) {
336 printk("serial2002 error\n");
337 break;
338 } else if (data & 0x80) {
339 result.value = (result.value << 7) | (data & 0x7f);
340 } else {
341 if (length == 1) {
342 switch ((data >> 5) & 0x03) {
343 case 0:{
344 result.value = 0;
345 result.kind = is_digital;
347 break;
348 case 1:{
349 result.value = 1;
350 result.kind = is_digital;
352 break;
354 } else {
355 result.value =
356 (result.value << 2) | ((data & 0x60) >> 5);
357 result.kind = is_channel;
359 result.index = data & 0x1f;
360 break;
363 return result;
367 static void serial_write(struct file *f, struct serial_data data)
369 if (data.kind == is_digital) {
370 unsigned char ch =
371 ((data.value << 5) & 0x20) | (data.index & 0x1f);
372 tty_write(f, &ch, 1);
373 } else {
374 unsigned char ch[6];
375 int i = 0;
376 if (data.value >= (1L << 30)) {
377 ch[i] = 0x80 | ((data.value >> 30) & 0x03);
378 i++;
380 if (data.value >= (1L << 23)) {
381 ch[i] = 0x80 | ((data.value >> 23) & 0x7f);
382 i++;
384 if (data.value >= (1L << 16)) {
385 ch[i] = 0x80 | ((data.value >> 16) & 0x7f);
386 i++;
388 if (data.value >= (1L << 9)) {
389 ch[i] = 0x80 | ((data.value >> 9) & 0x7f);
390 i++;
392 ch[i] = 0x80 | ((data.value >> 2) & 0x7f);
393 i++;
394 ch[i] = ((data.value << 5) & 0x60) | (data.index & 0x1f);
395 i++;
396 tty_write(f, ch, i);
400 static void serial_2002_open(struct comedi_device *dev)
402 char port[20];
404 sprintf(port, "/dev/ttyS%d", devpriv->port);
405 devpriv->tty = filp_open(port, 0, O_RDWR);
406 if (IS_ERR(devpriv->tty)) {
407 printk("serial_2002: file open error = %ld\n",
408 PTR_ERR(devpriv->tty));
409 } else {
410 struct config_t {
412 int kind;
413 int bits;
414 int min;
415 int max;
418 struct config_t dig_in_config[32];
419 struct config_t dig_out_config[32];
420 struct config_t chan_in_config[32];
421 struct config_t chan_out_config[32];
422 int i;
424 for (i = 0; i < 32; i++) {
425 dig_in_config[i].kind = 0;
426 dig_in_config[i].bits = 0;
427 dig_in_config[i].min = 0;
428 dig_in_config[i].max = 0;
429 dig_out_config[i].kind = 0;
430 dig_out_config[i].bits = 0;
431 dig_out_config[i].min = 0;
432 dig_out_config[i].max = 0;
433 chan_in_config[i].kind = 0;
434 chan_in_config[i].bits = 0;
435 chan_in_config[i].min = 0;
436 chan_in_config[i].max = 0;
437 chan_out_config[i].kind = 0;
438 chan_out_config[i].bits = 0;
439 chan_out_config[i].min = 0;
440 chan_out_config[i].max = 0;
443 tty_setspeed(devpriv->tty, devpriv->speed);
444 poll_channel(devpriv->tty, 31); /* Start reading configuration */
445 while (1) {
446 struct serial_data data;
448 data = serial_read(devpriv->tty, 1000);
449 if (data.kind != is_channel || data.index != 31
450 || !(data.value & 0xe0)) {
451 break;
452 } else {
453 int command, channel, kind;
454 struct config_t *cur_config = 0;
456 channel = data.value & 0x1f;
457 kind = (data.value >> 5) & 0x7;
458 command = (data.value >> 8) & 0x3;
459 switch (kind) {
460 case 1:{
461 cur_config = dig_in_config;
463 break;
464 case 2:{
465 cur_config = dig_out_config;
467 break;
468 case 3:{
469 cur_config = chan_in_config;
471 break;
472 case 4:{
473 cur_config = chan_out_config;
475 break;
476 case 5:{
477 cur_config = chan_in_config;
479 break;
482 if (cur_config) {
483 cur_config[channel].kind = kind;
484 switch (command) {
485 case 0:{
486 cur_config[channel].bits
488 (data.value >> 10) &
489 0x3f;
491 break;
492 case 1:{
493 int unit, sign, min;
494 unit =
495 (data.value >> 10) &
496 0x7;
497 sign =
498 (data.value >> 13) &
499 0x1;
500 min =
501 (data.value >> 14) &
502 0xfffff;
504 switch (unit) {
505 case 0:{
506 min =
509 1000000;
511 break;
512 case 1:{
513 min =
516 1000;
518 break;
519 case 2:{
520 min =
522 * 1;
524 break;
526 if (sign) {
527 min = -min;
529 cur_config[channel].min
530 = min;
532 break;
533 case 2:{
534 int unit, sign, max;
535 unit =
536 (data.value >> 10) &
537 0x7;
538 sign =
539 (data.value >> 13) &
540 0x1;
541 max =
542 (data.value >> 14) &
543 0xfffff;
545 switch (unit) {
546 case 0:{
547 max =
550 1000000;
552 break;
553 case 1:{
554 max =
557 1000;
559 break;
560 case 2:{
561 max =
563 * 1;
565 break;
567 if (sign) {
568 max = -max;
570 cur_config[channel].max
571 = max;
573 break;
578 for (i = 0; i <= 4; i++) {
579 /* Fill in subdev data */
580 struct config_t *c;
581 unsigned char *mapping = 0;
582 struct serial2002_range_table_t *range = 0;
583 int kind = 0;
585 switch (i) {
586 case 0:{
587 c = dig_in_config;
588 mapping = devpriv->digital_in_mapping;
589 kind = 1;
591 break;
592 case 1:{
593 c = dig_out_config;
594 mapping = devpriv->digital_out_mapping;
595 kind = 2;
597 break;
598 case 2:{
599 c = chan_in_config;
600 mapping = devpriv->analog_in_mapping;
601 range = devpriv->in_range;
602 kind = 3;
604 break;
605 case 3:{
606 c = chan_out_config;
607 mapping = devpriv->analog_out_mapping;
608 range = devpriv->out_range;
609 kind = 4;
611 break;
612 case 4:{
613 c = chan_in_config;
614 mapping = devpriv->encoder_in_mapping;
615 range = devpriv->in_range;
616 kind = 5;
618 break;
619 default:{
620 c = 0;
622 break;
624 if (c) {
625 struct comedi_subdevice *s;
626 const struct comedi_lrange **range_table_list =
627 NULL;
628 unsigned int *maxdata_list;
629 int j, chan;
631 for (chan = 0, j = 0; j < 32; j++) {
632 if (c[j].kind == kind) {
633 chan++;
636 s = &dev->subdevices[i];
637 s->n_chan = chan;
638 s->maxdata = 0;
639 if (s->maxdata_list) {
640 kfree(s->maxdata_list);
642 s->maxdata_list = maxdata_list =
643 kmalloc(sizeof(unsigned int) * s->n_chan,
644 GFP_KERNEL);
645 if (s->range_table_list) {
646 kfree(s->range_table_list);
648 if (range) {
649 s->range_table = 0;
650 s->range_table_list = range_table_list =
651 kmalloc(sizeof
652 (struct
653 serial2002_range_table_t) *
654 s->n_chan, GFP_KERNEL);
656 for (chan = 0, j = 0; j < 32; j++) {
657 if (c[j].kind == kind) {
658 if (mapping) {
659 mapping[chan] = j;
661 if (range) {
662 range[j].length = 1;
663 range[j].range.min =
664 c[j].min;
665 range[j].range.max =
666 c[j].max;
667 range_table_list[chan] =
668 (const struct
669 comedi_lrange *)
670 &range[j];
672 maxdata_list[chan] =
673 ((long long)1 << c[j].bits)
674 - 1;
675 chan++;
683 static void serial_2002_close(struct comedi_device *dev)
685 if (!IS_ERR(devpriv->tty) && (devpriv->tty != 0)) {
686 filp_close(devpriv->tty, 0);
690 static int serial2002_di_rinsn(struct comedi_device *dev,
691 struct comedi_subdevice *s,
692 struct comedi_insn *insn, unsigned int *data)
694 int n;
695 int chan;
697 chan = devpriv->digital_in_mapping[CR_CHAN(insn->chanspec)];
698 for (n = 0; n < insn->n; n++) {
699 struct serial_data read;
701 poll_digital(devpriv->tty, chan);
702 while (1) {
703 read = serial_read(devpriv->tty, 1000);
704 if (read.kind != is_digital || read.index == chan) {
705 break;
708 data[n] = read.value;
710 return n;
713 static int serial2002_do_winsn(struct comedi_device *dev,
714 struct comedi_subdevice *s,
715 struct comedi_insn *insn, unsigned int *data)
717 int n;
718 int chan;
720 chan = devpriv->digital_out_mapping[CR_CHAN(insn->chanspec)];
721 for (n = 0; n < insn->n; n++) {
722 struct serial_data write;
724 write.kind = is_digital;
725 write.index = chan;
726 write.value = data[n];
727 serial_write(devpriv->tty, write);
729 return n;
732 static int serial2002_ai_rinsn(struct comedi_device *dev,
733 struct comedi_subdevice *s,
734 struct comedi_insn *insn, unsigned int *data)
736 int n;
737 int chan;
739 chan = devpriv->analog_in_mapping[CR_CHAN(insn->chanspec)];
740 for (n = 0; n < insn->n; n++) {
741 struct serial_data read;
743 poll_channel(devpriv->tty, chan);
744 while (1) {
745 read = serial_read(devpriv->tty, 1000);
746 if (read.kind != is_channel || read.index == chan) {
747 break;
750 data[n] = read.value;
752 return n;
755 static int serial2002_ao_winsn(struct comedi_device *dev,
756 struct comedi_subdevice *s,
757 struct comedi_insn *insn, unsigned int *data)
759 int n;
760 int chan;
762 chan = devpriv->analog_out_mapping[CR_CHAN(insn->chanspec)];
763 for (n = 0; n < insn->n; n++) {
764 struct serial_data write;
766 write.kind = is_channel;
767 write.index = chan;
768 write.value = data[n];
769 serial_write(devpriv->tty, write);
770 devpriv->ao_readback[chan] = data[n];
772 return n;
775 static int serial2002_ao_rinsn(struct comedi_device *dev,
776 struct comedi_subdevice *s,
777 struct comedi_insn *insn, unsigned int *data)
779 int n;
780 int chan = CR_CHAN(insn->chanspec);
782 for (n = 0; n < insn->n; n++) {
783 data[n] = devpriv->ao_readback[chan];
786 return n;
789 static int serial2002_ei_rinsn(struct comedi_device *dev,
790 struct comedi_subdevice *s,
791 struct comedi_insn *insn, unsigned int *data)
793 int n;
794 int chan;
796 chan = devpriv->encoder_in_mapping[CR_CHAN(insn->chanspec)];
797 for (n = 0; n < insn->n; n++) {
798 struct serial_data read;
800 poll_channel(devpriv->tty, chan);
801 while (1) {
802 read = serial_read(devpriv->tty, 1000);
803 if (read.kind != is_channel || read.index == chan) {
804 break;
807 data[n] = read.value;
809 return n;
812 static int serial2002_attach(struct comedi_device *dev,
813 struct comedi_devconfig *it)
815 struct comedi_subdevice *s;
817 printk("comedi%d: serial2002: ", dev->minor);
818 dev->board_name = thisboard->name;
819 if (alloc_private(dev, sizeof(struct serial2002_private)) < 0) {
820 return -ENOMEM;
822 dev->open = serial_2002_open;
823 dev->close = serial_2002_close;
824 devpriv->port = it->options[0];
825 devpriv->speed = it->options[1];
826 printk("/dev/ttyS%d @ %d\n", devpriv->port, devpriv->speed);
828 if (alloc_subdevices(dev, 5) < 0)
829 return -ENOMEM;
831 /* digital input subdevice */
832 s = dev->subdevices + 0;
833 s->type = COMEDI_SUBD_DI;
834 s->subdev_flags = SDF_READABLE;
835 s->n_chan = 0;
836 s->maxdata = 1;
837 s->range_table = &range_digital;
838 s->insn_read = &serial2002_di_rinsn;
840 /* digital output subdevice */
841 s = dev->subdevices + 1;
842 s->type = COMEDI_SUBD_DO;
843 s->subdev_flags = SDF_WRITEABLE;
844 s->n_chan = 0;
845 s->maxdata = 1;
846 s->range_table = &range_digital;
847 s->insn_write = &serial2002_do_winsn;
849 /* analog input subdevice */
850 s = dev->subdevices + 2;
851 s->type = COMEDI_SUBD_AI;
852 s->subdev_flags = SDF_READABLE | SDF_GROUND;
853 s->n_chan = 0;
854 s->maxdata = 1;
855 s->range_table = 0;
856 s->insn_read = &serial2002_ai_rinsn;
858 /* analog output subdevice */
859 s = dev->subdevices + 3;
860 s->type = COMEDI_SUBD_AO;
861 s->subdev_flags = SDF_WRITEABLE;
862 s->n_chan = 0;
863 s->maxdata = 1;
864 s->range_table = 0;
865 s->insn_write = &serial2002_ao_winsn;
866 s->insn_read = &serial2002_ao_rinsn;
868 /* encoder input subdevice */
869 s = dev->subdevices + 4;
870 s->type = COMEDI_SUBD_COUNTER;
871 s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
872 s->n_chan = 0;
873 s->maxdata = 1;
874 s->range_table = 0;
875 s->insn_read = &serial2002_ei_rinsn;
877 return 1;
880 static int serial2002_detach(struct comedi_device *dev)
882 struct comedi_subdevice *s;
883 int i;
885 printk("comedi%d: serial2002: remove\n", dev->minor);
886 for (i = 0; i < 4; i++) {
887 s = &dev->subdevices[i];
888 if (s->maxdata_list) {
889 kfree(s->maxdata_list);
891 if (s->range_table_list) {
892 kfree(s->range_table_list);
895 return 0;
898 COMEDI_INITCLEANUP(driver_serial2002);