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