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.
26 Description: Driver for serial connected hardware
28 Author: Anders Blomdell
29 Updated: Fri, 7 Jun 2002 12:56:45 -0700
30 Status: in development
34 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
36 #include "../comedidev.h"
38 #include <linux/delay.h>
39 #include <linux/ioport.h>
40 #include <linux/sched.h>
41 #include <linux/slab.h>
43 #include <linux/termios.h>
44 #include <asm/ioctls.h>
45 #include <linux/serial.h>
46 #include <linux/poll.h>
48 struct serial2002_range_table_t {
52 struct comedi_krange range;
55 struct serial2002_private {
57 int port; /* /dev/ttyS<port> */
58 int speed; /* baudrate */
60 unsigned int ao_readback[32];
61 unsigned char digital_in_mapping[32];
62 unsigned char digital_out_mapping[32];
63 unsigned char analog_in_mapping[32];
64 unsigned char analog_out_mapping[32];
65 unsigned char encoder_in_mapping[32];
66 struct serial2002_range_table_t in_range[32], out_range[32];
70 enum { is_invalid, is_digital, is_channel } kind;
75 static long tty_ioctl(struct file *f, unsigned op, unsigned long param)
77 if (f->f_op->unlocked_ioctl)
78 return f->f_op->unlocked_ioctl(f, op, param);
83 static int tty_write(struct file *f, unsigned char *buf, int count)
91 result = f->f_op->write(f, buf, count, &f->f_pos);
98 * On 2.6.26.3 this occaisonally gave me page faults, worked around by
99 * settings.c_cc[VMIN] = 0; settings.c_cc[VTIME] = 0
101 static int tty_available(struct file *f)
108 tty_ioctl(f, FIONREAD, (unsigned long)&result);
114 static int tty_read(struct file *f, int timeout)
125 struct poll_wqueues table;
126 struct timeval start, now;
128 do_gettimeofday(&start);
129 poll_initwait(&table);
134 mask = f->f_op->poll(f, &table.pt);
135 if (mask & (POLLRDNORM | POLLRDBAND | POLLIN |
136 POLLHUP | POLLERR)) {
139 do_gettimeofday(&now);
141 (1000000 * (now.tv_sec - start.tv_sec) +
142 now.tv_usec - start.tv_usec);
143 if (elapsed > timeout)
145 set_current_state(TASK_INTERRUPTIBLE);
146 schedule_timeout(((timeout -
147 elapsed) * HZ) / 10000);
149 poll_freewait(&table);
154 if (f->f_op->read(f, &ch, 1, &f->f_pos) == 1)
158 /* Device does not support poll, busy wait */
164 if (retries >= timeout)
168 if (f->f_op->read(f, &ch, 1, &f->f_pos) == 1) {
180 static void tty_setspeed(struct file *f, int speed)
188 struct termios settings;
190 tty_ioctl(f, TCGETS, (unsigned long)&settings);
191 /* printk("Speed: %d\n", settings.c_cflag & (CBAUD | CBAUDEX)); */
192 settings.c_iflag = 0;
193 settings.c_oflag = 0;
194 settings.c_lflag = 0;
195 settings.c_cflag = CLOCAL | CS8 | CREAD;
196 settings.c_cc[VMIN] = 0;
197 settings.c_cc[VTIME] = 0;
200 settings.c_cflag |= B2400;
204 settings.c_cflag |= B4800;
208 settings.c_cflag |= B9600;
212 settings.c_cflag |= B19200;
216 settings.c_cflag |= B38400;
220 settings.c_cflag |= B57600;
224 settings.c_cflag |= B115200;
228 settings.c_cflag |= B9600;
232 tty_ioctl(f, TCSETS, (unsigned long)&settings);
233 /* printk("Speed: %d\n", settings.c_cflag & (CBAUD | CBAUDEX)); */
236 /* Set low latency */
237 struct serial_struct settings;
239 tty_ioctl(f, TIOCGSERIAL, (unsigned long)&settings);
240 settings.flags |= ASYNC_LOW_LATENCY;
241 tty_ioctl(f, TIOCSSERIAL, (unsigned long)&settings);
247 static void poll_digital(struct file *f, int channel)
251 cmd = 0x40 | (channel & 0x1f);
252 tty_write(f, &cmd, 1);
255 static void poll_channel(struct file *f, int channel)
259 cmd = 0x60 | (channel & 0x1f);
260 tty_write(f, &cmd, 1);
263 static struct serial_data serial_read(struct file *f, int timeout)
265 struct serial_data result;
268 result.kind = is_invalid;
273 int data = tty_read(f, timeout);
277 pr_err("Failed to read serial.\n");
279 } else if (data & 0x80) {
280 result.value = (result.value << 7) | (data & 0x7f);
283 switch ((data >> 5) & 0x03) {
286 result.kind = is_digital;
291 result.kind = is_digital;
297 (result.value << 2) | ((data & 0x60) >> 5);
298 result.kind = is_channel;
300 result.index = data & 0x1f;
308 static void serial_write(struct file *f, struct serial_data data)
310 if (data.kind == is_digital) {
312 ((data.value << 5) & 0x20) | (data.index & 0x1f);
313 tty_write(f, &ch, 1);
317 if (data.value >= (1L << 30)) {
318 ch[i] = 0x80 | ((data.value >> 30) & 0x03);
321 if (data.value >= (1L << 23)) {
322 ch[i] = 0x80 | ((data.value >> 23) & 0x7f);
325 if (data.value >= (1L << 16)) {
326 ch[i] = 0x80 | ((data.value >> 16) & 0x7f);
329 if (data.value >= (1L << 9)) {
330 ch[i] = 0x80 | ((data.value >> 9) & 0x7f);
333 ch[i] = 0x80 | ((data.value >> 2) & 0x7f);
335 ch[i] = ((data.value << 5) & 0x60) | (data.index & 0x1f);
341 static int serial_2002_open(struct comedi_device *dev)
343 struct serial2002_private *devpriv = dev->private;
347 sprintf(port, "/dev/ttyS%d", devpriv->port);
348 devpriv->tty = filp_open(port, O_RDWR, 0);
349 if (IS_ERR(devpriv->tty)) {
350 result = (int)PTR_ERR(devpriv->tty);
351 dev_err(dev->class_dev, "file open error = %d\n", result);
361 struct config_t *dig_in_config;
362 struct config_t *dig_out_config;
363 struct config_t *chan_in_config;
364 struct config_t *chan_out_config;
368 dig_in_config = kcalloc(32, sizeof(struct config_t),
370 dig_out_config = kcalloc(32, sizeof(struct config_t),
372 chan_in_config = kcalloc(32, sizeof(struct config_t),
374 chan_out_config = kcalloc(32, sizeof(struct config_t),
376 if (!dig_in_config || !dig_out_config
377 || !chan_in_config || !chan_out_config) {
379 goto err_alloc_configs;
382 tty_setspeed(devpriv->tty, devpriv->speed);
383 poll_channel(devpriv->tty, 31); /* Start reading configuration */
385 struct serial_data data;
387 data = serial_read(devpriv->tty, 1000);
388 if (data.kind != is_channel || data.index != 31
389 || !(data.value & 0xe0)) {
392 int command, channel, kind;
393 struct config_t *cur_config = NULL;
395 channel = data.value & 0x1f;
396 kind = (data.value >> 5) & 0x7;
397 command = (data.value >> 8) & 0x3;
400 cur_config = dig_in_config;
404 cur_config = dig_out_config;
408 cur_config = chan_in_config;
412 cur_config = chan_out_config;
416 cur_config = chan_in_config;
422 cur_config[channel].kind = kind;
425 cur_config[channel].bits
467 cur_config[channel].min
507 cur_config[channel].max
515 for (i = 0; i <= 4; i++) {
516 /* Fill in subdev data */
518 unsigned char *mapping = NULL;
519 struct serial2002_range_table_t *range = NULL;
525 mapping = devpriv->digital_in_mapping;
531 mapping = devpriv->digital_out_mapping;
537 mapping = devpriv->analog_in_mapping;
538 range = devpriv->in_range;
544 mapping = devpriv->analog_out_mapping;
545 range = devpriv->out_range;
551 mapping = devpriv->encoder_in_mapping;
552 range = devpriv->in_range;
562 struct comedi_subdevice *s;
563 const struct comedi_lrange **range_table_list =
565 unsigned int *maxdata_list;
568 for (chan = 0, j = 0; j < 32; j++) {
569 if (c[j].kind == kind)
572 s = &dev->subdevices[i];
575 kfree(s->maxdata_list);
576 s->maxdata_list = maxdata_list =
577 kmalloc(sizeof(unsigned int) * s->n_chan,
579 if (!s->maxdata_list)
580 break; /* error handled below */
581 kfree(s->range_table_list);
582 s->range_table = NULL;
583 s->range_table_list = NULL;
584 if (kind == 1 || kind == 2) {
585 s->range_table = &range_digital;
587 s->range_table_list = range_table_list =
590 serial2002_range_table_t) *
591 s->n_chan, GFP_KERNEL);
592 if (!s->range_table_list)
593 break; /* err handled below */
595 for (chan = 0, j = 0; j < 32; j++) {
596 if (c[j].kind == kind) {
605 range_table_list[chan] =
611 ((long long)1 << c[j].bits)
619 /* Failed to allocate maxdata_list or range_table_list
620 * for a subdevice that needed it. */
622 for (i = 0; i <= 4; i++) {
623 struct comedi_subdevice *s;
625 s = &dev->subdevices[i];
626 kfree(s->maxdata_list);
627 s->maxdata_list = NULL;
628 kfree(s->range_table_list);
629 s->range_table_list = NULL;
634 kfree(dig_in_config);
635 kfree(dig_out_config);
636 kfree(chan_in_config);
637 kfree(chan_out_config);
641 filp_close(devpriv->tty, NULL);
649 static void serial_2002_close(struct comedi_device *dev)
651 struct serial2002_private *devpriv = dev->private;
653 if (!IS_ERR(devpriv->tty) && devpriv->tty)
654 filp_close(devpriv->tty, NULL);
657 static int serial2002_di_rinsn(struct comedi_device *dev,
658 struct comedi_subdevice *s,
659 struct comedi_insn *insn, unsigned int *data)
661 struct serial2002_private *devpriv = dev->private;
665 chan = devpriv->digital_in_mapping[CR_CHAN(insn->chanspec)];
666 for (n = 0; n < insn->n; n++) {
667 struct serial_data read;
669 poll_digital(devpriv->tty, chan);
671 read = serial_read(devpriv->tty, 1000);
672 if (read.kind != is_digital || read.index == chan)
675 data[n] = read.value;
680 static int serial2002_do_winsn(struct comedi_device *dev,
681 struct comedi_subdevice *s,
682 struct comedi_insn *insn, unsigned int *data)
684 struct serial2002_private *devpriv = dev->private;
688 chan = devpriv->digital_out_mapping[CR_CHAN(insn->chanspec)];
689 for (n = 0; n < insn->n; n++) {
690 struct serial_data write;
692 write.kind = is_digital;
694 write.value = data[n];
695 serial_write(devpriv->tty, write);
700 static int serial2002_ai_rinsn(struct comedi_device *dev,
701 struct comedi_subdevice *s,
702 struct comedi_insn *insn, unsigned int *data)
704 struct serial2002_private *devpriv = dev->private;
708 chan = devpriv->analog_in_mapping[CR_CHAN(insn->chanspec)];
709 for (n = 0; n < insn->n; n++) {
710 struct serial_data read;
712 poll_channel(devpriv->tty, chan);
714 read = serial_read(devpriv->tty, 1000);
715 if (read.kind != is_channel || read.index == chan)
718 data[n] = read.value;
723 static int serial2002_ao_winsn(struct comedi_device *dev,
724 struct comedi_subdevice *s,
725 struct comedi_insn *insn, unsigned int *data)
727 struct serial2002_private *devpriv = dev->private;
731 chan = devpriv->analog_out_mapping[CR_CHAN(insn->chanspec)];
732 for (n = 0; n < insn->n; n++) {
733 struct serial_data write;
735 write.kind = is_channel;
737 write.value = data[n];
738 serial_write(devpriv->tty, write);
739 devpriv->ao_readback[chan] = data[n];
744 static int serial2002_ao_rinsn(struct comedi_device *dev,
745 struct comedi_subdevice *s,
746 struct comedi_insn *insn, unsigned int *data)
748 struct serial2002_private *devpriv = dev->private;
750 int chan = CR_CHAN(insn->chanspec);
752 for (n = 0; n < insn->n; n++)
753 data[n] = devpriv->ao_readback[chan];
758 static int serial2002_ei_rinsn(struct comedi_device *dev,
759 struct comedi_subdevice *s,
760 struct comedi_insn *insn, unsigned int *data)
762 struct serial2002_private *devpriv = dev->private;
766 chan = devpriv->encoder_in_mapping[CR_CHAN(insn->chanspec)];
767 for (n = 0; n < insn->n; n++) {
768 struct serial_data read;
770 poll_channel(devpriv->tty, chan);
772 read = serial_read(devpriv->tty, 1000);
773 if (read.kind != is_channel || read.index == chan)
776 data[n] = read.value;
781 static int serial2002_attach(struct comedi_device *dev,
782 struct comedi_devconfig *it)
784 struct serial2002_private *devpriv;
785 struct comedi_subdevice *s;
788 dev_dbg(dev->class_dev, "serial2002: attach\n");
789 dev->board_name = dev->driver->driver_name;
791 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
794 dev->private = devpriv;
796 dev->open = serial_2002_open;
797 dev->close = serial_2002_close;
798 devpriv->port = it->options[0];
799 devpriv->speed = it->options[1];
800 dev_dbg(dev->class_dev, "/dev/ttyS%d @ %d\n", devpriv->port,
803 ret = comedi_alloc_subdevices(dev, 5);
807 /* digital input subdevice */
808 s = &dev->subdevices[0];
809 s->type = COMEDI_SUBD_DI;
810 s->subdev_flags = SDF_READABLE;
813 s->range_table = &range_digital;
814 s->insn_read = &serial2002_di_rinsn;
816 /* digital output subdevice */
817 s = &dev->subdevices[1];
818 s->type = COMEDI_SUBD_DO;
819 s->subdev_flags = SDF_WRITEABLE;
822 s->range_table = &range_digital;
823 s->insn_write = &serial2002_do_winsn;
825 /* analog input subdevice */
826 s = &dev->subdevices[2];
827 s->type = COMEDI_SUBD_AI;
828 s->subdev_flags = SDF_READABLE | SDF_GROUND;
831 s->range_table = NULL;
832 s->insn_read = &serial2002_ai_rinsn;
834 /* analog output subdevice */
835 s = &dev->subdevices[3];
836 s->type = COMEDI_SUBD_AO;
837 s->subdev_flags = SDF_WRITEABLE;
840 s->range_table = NULL;
841 s->insn_write = &serial2002_ao_winsn;
842 s->insn_read = &serial2002_ao_rinsn;
844 /* encoder input subdevice */
845 s = &dev->subdevices[4];
846 s->type = COMEDI_SUBD_COUNTER;
847 s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
850 s->range_table = NULL;
851 s->insn_read = &serial2002_ei_rinsn;
856 static void serial2002_detach(struct comedi_device *dev)
858 struct comedi_subdevice *s;
861 for (i = 0; i < 5; i++) {
862 s = &dev->subdevices[i];
863 kfree(s->maxdata_list);
864 kfree(s->range_table_list);
868 static struct comedi_driver serial2002_driver = {
869 .driver_name = "serial2002",
870 .module = THIS_MODULE,
871 .attach = serial2002_attach,
872 .detach = serial2002_detach,
874 module_comedi_driver(serial2002_driver);
876 MODULE_AUTHOR("Comedi http://www.comedi.org");
877 MODULE_DESCRIPTION("Comedi low-level driver");
878 MODULE_LICENSE("GPL");