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