/drivers/staging/comedi/drivers/serial2002.c

https://bitbucket.org/cyanogenmod/android_kernel_asus_tf300t · C · 918 lines · 764 code · 93 blank · 61 comment · 95 complexity · 7e5b07272355cdb733f8e14cb66de809 MD5 · raw file

  1. /*
  2. comedi/drivers/serial2002.c
  3. Skeleton code for a Comedi driver
  4. COMEDI - Linux Control and Measurement Device Interface
  5. Copyright (C) 2002 Anders Blomdell <anders.blomdell@control.lth.se>
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18. /*
  19. Driver: serial2002
  20. Description: Driver for serial connected hardware
  21. Devices:
  22. Author: Anders Blomdell
  23. Updated: Fri, 7 Jun 2002 12:56:45 -0700
  24. Status: in development
  25. */
  26. #include "../comedidev.h"
  27. #include <linux/delay.h>
  28. #include <linux/ioport.h>
  29. #include <linux/sched.h>
  30. #include <linux/slab.h>
  31. #include <linux/termios.h>
  32. #include <asm/ioctls.h>
  33. #include <linux/serial.h>
  34. #include <linux/poll.h>
  35. /*
  36. * Board descriptions for two imaginary boards. Describing the
  37. * boards in this way is optional, and completely driver-dependent.
  38. * Some drivers use arrays such as this, other do not.
  39. */
  40. struct serial2002_board {
  41. const char *name;
  42. };
  43. static const struct serial2002_board serial2002_boards[] = {
  44. {
  45. .name = "serial2002"}
  46. };
  47. /*
  48. * Useful for shorthand access to the particular board structure
  49. */
  50. #define thisboard ((const struct serial2002_board *)dev->board_ptr)
  51. struct serial2002_range_table_t {
  52. /* HACK... */
  53. int length;
  54. struct comedi_krange range;
  55. };
  56. struct serial2002_private {
  57. int port; /* /dev/ttyS<port> */
  58. int speed; /* baudrate */
  59. struct file *tty;
  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];
  67. };
  68. /*
  69. * most drivers define the following macro to make it easy to
  70. * access the private structure.
  71. */
  72. #define devpriv ((struct serial2002_private *)dev->private)
  73. static int serial2002_attach(struct comedi_device *dev,
  74. struct comedi_devconfig *it);
  75. static int serial2002_detach(struct comedi_device *dev);
  76. struct comedi_driver driver_serial2002 = {
  77. .driver_name = "serial2002",
  78. .module = THIS_MODULE,
  79. .attach = serial2002_attach,
  80. .detach = serial2002_detach,
  81. .board_name = &serial2002_boards[0].name,
  82. .offset = sizeof(struct serial2002_board),
  83. .num_names = ARRAY_SIZE(serial2002_boards),
  84. };
  85. static int serial2002_di_rinsn(struct comedi_device *dev,
  86. struct comedi_subdevice *s,
  87. struct comedi_insn *insn, unsigned int *data);
  88. static int serial2002_do_winsn(struct comedi_device *dev,
  89. struct comedi_subdevice *s,
  90. struct comedi_insn *insn, unsigned int *data);
  91. static int serial2002_ai_rinsn(struct comedi_device *dev,
  92. struct comedi_subdevice *s,
  93. struct comedi_insn *insn, unsigned int *data);
  94. static int serial2002_ao_winsn(struct comedi_device *dev,
  95. struct comedi_subdevice *s,
  96. struct comedi_insn *insn, unsigned int *data);
  97. static int serial2002_ao_rinsn(struct comedi_device *dev,
  98. struct comedi_subdevice *s,
  99. struct comedi_insn *insn, unsigned int *data);
  100. struct serial_data {
  101. enum { is_invalid, is_digital, is_channel } kind;
  102. int index;
  103. unsigned long value;
  104. };
  105. static long tty_ioctl(struct file *f, unsigned op, unsigned long param)
  106. {
  107. if (f->f_op->unlocked_ioctl)
  108. return f->f_op->unlocked_ioctl(f, op, param);
  109. return -ENOSYS;
  110. }
  111. static int tty_write(struct file *f, unsigned char *buf, int count)
  112. {
  113. int result;
  114. mm_segment_t oldfs;
  115. oldfs = get_fs();
  116. set_fs(KERNEL_DS);
  117. f->f_pos = 0;
  118. result = f->f_op->write(f, buf, count, &f->f_pos);
  119. set_fs(oldfs);
  120. return result;
  121. }
  122. #if 0
  123. /*
  124. * On 2.6.26.3 this occaisonally gave me page faults, worked around by
  125. * settings.c_cc[VMIN] = 0; settings.c_cc[VTIME] = 0
  126. */
  127. static int tty_available(struct file *f)
  128. {
  129. long result = 0;
  130. mm_segment_t oldfs;
  131. oldfs = get_fs();
  132. set_fs(KERNEL_DS);
  133. tty_ioctl(f, FIONREAD, (unsigned long)&result);
  134. set_fs(oldfs);
  135. return result;
  136. }
  137. #endif
  138. static int tty_read(struct file *f, int timeout)
  139. {
  140. int result;
  141. result = -1;
  142. if (!IS_ERR(f)) {
  143. mm_segment_t oldfs;
  144. oldfs = get_fs();
  145. set_fs(KERNEL_DS);
  146. if (f->f_op->poll) {
  147. struct poll_wqueues table;
  148. struct timeval start, now;
  149. do_gettimeofday(&start);
  150. poll_initwait(&table);
  151. while (1) {
  152. long elapsed;
  153. int mask;
  154. mask = f->f_op->poll(f, &table.pt);
  155. if (mask & (POLLRDNORM | POLLRDBAND | POLLIN |
  156. POLLHUP | POLLERR)) {
  157. break;
  158. }
  159. do_gettimeofday(&now);
  160. elapsed =
  161. (1000000 * (now.tv_sec - start.tv_sec) +
  162. now.tv_usec - start.tv_usec);
  163. if (elapsed > timeout)
  164. break;
  165. set_current_state(TASK_INTERRUPTIBLE);
  166. schedule_timeout(((timeout -
  167. elapsed) * HZ) / 10000);
  168. }
  169. poll_freewait(&table);
  170. {
  171. unsigned char ch;
  172. f->f_pos = 0;
  173. if (f->f_op->read(f, &ch, 1, &f->f_pos) == 1)
  174. result = ch;
  175. }
  176. } else {
  177. /* Device does not support poll, busy wait */
  178. int retries = 0;
  179. while (1) {
  180. unsigned char ch;
  181. retries++;
  182. if (retries >= timeout)
  183. break;
  184. f->f_pos = 0;
  185. if (f->f_op->read(f, &ch, 1, &f->f_pos) == 1) {
  186. result = ch;
  187. break;
  188. }
  189. udelay(100);
  190. }
  191. }
  192. set_fs(oldfs);
  193. }
  194. return result;
  195. }
  196. static void tty_setspeed(struct file *f, int speed)
  197. {
  198. mm_segment_t oldfs;
  199. oldfs = get_fs();
  200. set_fs(KERNEL_DS);
  201. {
  202. /* Set speed */
  203. struct termios settings;
  204. tty_ioctl(f, TCGETS, (unsigned long)&settings);
  205. /* printk("Speed: %d\n", settings.c_cflag & (CBAUD | CBAUDEX)); */
  206. settings.c_iflag = 0;
  207. settings.c_oflag = 0;
  208. settings.c_lflag = 0;
  209. settings.c_cflag = CLOCAL | CS8 | CREAD;
  210. settings.c_cc[VMIN] = 0;
  211. settings.c_cc[VTIME] = 0;
  212. switch (speed) {
  213. case 2400:{
  214. settings.c_cflag |= B2400;
  215. }
  216. break;
  217. case 4800:{
  218. settings.c_cflag |= B4800;
  219. }
  220. break;
  221. case 9600:{
  222. settings.c_cflag |= B9600;
  223. }
  224. break;
  225. case 19200:{
  226. settings.c_cflag |= B19200;
  227. }
  228. break;
  229. case 38400:{
  230. settings.c_cflag |= B38400;
  231. }
  232. break;
  233. case 57600:{
  234. settings.c_cflag |= B57600;
  235. }
  236. break;
  237. case 115200:{
  238. settings.c_cflag |= B115200;
  239. }
  240. break;
  241. default:{
  242. settings.c_cflag |= B9600;
  243. }
  244. break;
  245. }
  246. tty_ioctl(f, TCSETS, (unsigned long)&settings);
  247. /* printk("Speed: %d\n", settings.c_cflag & (CBAUD | CBAUDEX)); */
  248. }
  249. {
  250. /* Set low latency */
  251. struct serial_struct settings;
  252. tty_ioctl(f, TIOCGSERIAL, (unsigned long)&settings);
  253. settings.flags |= ASYNC_LOW_LATENCY;
  254. tty_ioctl(f, TIOCSSERIAL, (unsigned long)&settings);
  255. }
  256. set_fs(oldfs);
  257. }
  258. static void poll_digital(struct file *f, int channel)
  259. {
  260. char cmd;
  261. cmd = 0x40 | (channel & 0x1f);
  262. tty_write(f, &cmd, 1);
  263. }
  264. static void poll_channel(struct file *f, int channel)
  265. {
  266. char cmd;
  267. cmd = 0x60 | (channel & 0x1f);
  268. tty_write(f, &cmd, 1);
  269. }
  270. static struct serial_data serial_read(struct file *f, int timeout)
  271. {
  272. struct serial_data result;
  273. int length;
  274. result.kind = is_invalid;
  275. result.index = 0;
  276. result.value = 0;
  277. length = 0;
  278. while (1) {
  279. int data = tty_read(f, timeout);
  280. length++;
  281. if (data < 0) {
  282. printk(KERN_ERR "serial2002 error\n");
  283. break;
  284. } else if (data & 0x80) {
  285. result.value = (result.value << 7) | (data & 0x7f);
  286. } else {
  287. if (length == 1) {
  288. switch ((data >> 5) & 0x03) {
  289. case 0:{
  290. result.value = 0;
  291. result.kind = is_digital;
  292. }
  293. break;
  294. case 1:{
  295. result.value = 1;
  296. result.kind = is_digital;
  297. }
  298. break;
  299. }
  300. } else {
  301. result.value =
  302. (result.value << 2) | ((data & 0x60) >> 5);
  303. result.kind = is_channel;
  304. }
  305. result.index = data & 0x1f;
  306. break;
  307. }
  308. }
  309. return result;
  310. }
  311. static void serial_write(struct file *f, struct serial_data data)
  312. {
  313. if (data.kind == is_digital) {
  314. unsigned char ch =
  315. ((data.value << 5) & 0x20) | (data.index & 0x1f);
  316. tty_write(f, &ch, 1);
  317. } else {
  318. unsigned char ch[6];
  319. int i = 0;
  320. if (data.value >= (1L << 30)) {
  321. ch[i] = 0x80 | ((data.value >> 30) & 0x03);
  322. i++;
  323. }
  324. if (data.value >= (1L << 23)) {
  325. ch[i] = 0x80 | ((data.value >> 23) & 0x7f);
  326. i++;
  327. }
  328. if (data.value >= (1L << 16)) {
  329. ch[i] = 0x80 | ((data.value >> 16) & 0x7f);
  330. i++;
  331. }
  332. if (data.value >= (1L << 9)) {
  333. ch[i] = 0x80 | ((data.value >> 9) & 0x7f);
  334. i++;
  335. }
  336. ch[i] = 0x80 | ((data.value >> 2) & 0x7f);
  337. i++;
  338. ch[i] = ((data.value << 5) & 0x60) | (data.index & 0x1f);
  339. i++;
  340. tty_write(f, ch, i);
  341. }
  342. }
  343. static int serial_2002_open(struct comedi_device *dev)
  344. {
  345. int result;
  346. char port[20];
  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. printk(KERN_ERR "serial_2002: file open error = %d\n", result);
  352. } else {
  353. struct config_t {
  354. short int kind;
  355. short int bits;
  356. int min;
  357. int max;
  358. };
  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;
  363. int i;
  364. result = 0;
  365. dig_in_config = kcalloc(32, sizeof(struct config_t),
  366. GFP_KERNEL);
  367. dig_out_config = kcalloc(32, sizeof(struct config_t),
  368. GFP_KERNEL);
  369. chan_in_config = kcalloc(32, sizeof(struct config_t),
  370. GFP_KERNEL);
  371. chan_out_config = kcalloc(32, sizeof(struct config_t),
  372. GFP_KERNEL);
  373. if (!dig_in_config || !dig_out_config
  374. || !chan_in_config || !chan_out_config) {
  375. result = -ENOMEM;
  376. goto err_alloc_configs;
  377. }
  378. tty_setspeed(devpriv->tty, devpriv->speed);
  379. poll_channel(devpriv->tty, 31); /* Start reading configuration */
  380. while (1) {
  381. struct serial_data data;
  382. data = serial_read(devpriv->tty, 1000);
  383. if (data.kind != is_channel || data.index != 31
  384. || !(data.value & 0xe0)) {
  385. break;
  386. } else {
  387. int command, channel, kind;
  388. struct config_t *cur_config = NULL;
  389. channel = data.value & 0x1f;
  390. kind = (data.value >> 5) & 0x7;
  391. command = (data.value >> 8) & 0x3;
  392. switch (kind) {
  393. case 1:{
  394. cur_config = dig_in_config;
  395. }
  396. break;
  397. case 2:{
  398. cur_config = dig_out_config;
  399. }
  400. break;
  401. case 3:{
  402. cur_config = chan_in_config;
  403. }
  404. break;
  405. case 4:{
  406. cur_config = chan_out_config;
  407. }
  408. break;
  409. case 5:{
  410. cur_config = chan_in_config;
  411. }
  412. break;
  413. }
  414. if (cur_config) {
  415. cur_config[channel].kind = kind;
  416. switch (command) {
  417. case 0:{
  418. cur_config[channel].bits
  419. =
  420. (data.value >> 10) &
  421. 0x3f;
  422. }
  423. break;
  424. case 1:{
  425. int unit, sign, min;
  426. unit =
  427. (data.value >> 10) &
  428. 0x7;
  429. sign =
  430. (data.value >> 13) &
  431. 0x1;
  432. min =
  433. (data.value >> 14) &
  434. 0xfffff;
  435. switch (unit) {
  436. case 0:{
  437. min =
  438. min
  439. *
  440. 1000000;
  441. }
  442. break;
  443. case 1:{
  444. min =
  445. min
  446. *
  447. 1000;
  448. }
  449. break;
  450. case 2:{
  451. min =
  452. min
  453. * 1;
  454. }
  455. break;
  456. }
  457. if (sign)
  458. min = -min;
  459. cur_config[channel].min
  460. = min;
  461. }
  462. break;
  463. case 2:{
  464. int unit, sign, max;
  465. unit =
  466. (data.value >> 10) &
  467. 0x7;
  468. sign =
  469. (data.value >> 13) &
  470. 0x1;
  471. max =
  472. (data.value >> 14) &
  473. 0xfffff;
  474. switch (unit) {
  475. case 0:{
  476. max =
  477. max
  478. *
  479. 1000000;
  480. }
  481. break;
  482. case 1:{
  483. max =
  484. max
  485. *
  486. 1000;
  487. }
  488. break;
  489. case 2:{
  490. max =
  491. max
  492. * 1;
  493. }
  494. break;
  495. }
  496. if (sign)
  497. max = -max;
  498. cur_config[channel].max
  499. = max;
  500. }
  501. break;
  502. }
  503. }
  504. }
  505. }
  506. for (i = 0; i <= 4; i++) {
  507. /* Fill in subdev data */
  508. struct config_t *c;
  509. unsigned char *mapping = NULL;
  510. struct serial2002_range_table_t *range = NULL;
  511. int kind = 0;
  512. switch (i) {
  513. case 0:{
  514. c = dig_in_config;
  515. mapping = devpriv->digital_in_mapping;
  516. kind = 1;
  517. }
  518. break;
  519. case 1:{
  520. c = dig_out_config;
  521. mapping = devpriv->digital_out_mapping;
  522. kind = 2;
  523. }
  524. break;
  525. case 2:{
  526. c = chan_in_config;
  527. mapping = devpriv->analog_in_mapping;
  528. range = devpriv->in_range;
  529. kind = 3;
  530. }
  531. break;
  532. case 3:{
  533. c = chan_out_config;
  534. mapping = devpriv->analog_out_mapping;
  535. range = devpriv->out_range;
  536. kind = 4;
  537. }
  538. break;
  539. case 4:{
  540. c = chan_in_config;
  541. mapping = devpriv->encoder_in_mapping;
  542. range = devpriv->in_range;
  543. kind = 5;
  544. }
  545. break;
  546. default:{
  547. c = NULL;
  548. }
  549. break;
  550. }
  551. if (c) {
  552. struct comedi_subdevice *s;
  553. const struct comedi_lrange **range_table_list =
  554. NULL;
  555. unsigned int *maxdata_list;
  556. int j, chan;
  557. for (chan = 0, j = 0; j < 32; j++) {
  558. if (c[j].kind == kind)
  559. chan++;
  560. }
  561. s = &dev->subdevices[i];
  562. s->n_chan = chan;
  563. s->maxdata = 0;
  564. kfree(s->maxdata_list);
  565. s->maxdata_list = maxdata_list =
  566. kmalloc(sizeof(unsigned int) * s->n_chan,
  567. GFP_KERNEL);
  568. if (!s->maxdata_list)
  569. break; /* error handled below */
  570. kfree(s->range_table_list);
  571. s->range_table = NULL;
  572. s->range_table_list = NULL;
  573. if (range) {
  574. s->range_table_list = range_table_list =
  575. kmalloc(sizeof
  576. (struct
  577. serial2002_range_table_t) *
  578. s->n_chan, GFP_KERNEL);
  579. if (!s->range_table_list)
  580. break; /* err handled below */
  581. }
  582. for (chan = 0, j = 0; j < 32; j++) {
  583. if (c[j].kind == kind) {
  584. if (mapping)
  585. mapping[chan] = j;
  586. if (range) {
  587. range[j].length = 1;
  588. range[j].range.min =
  589. c[j].min;
  590. range[j].range.max =
  591. c[j].max;
  592. range_table_list[chan] =
  593. (const struct
  594. comedi_lrange *)
  595. &range[j];
  596. }
  597. maxdata_list[chan] =
  598. ((long long)1 << c[j].bits)
  599. - 1;
  600. chan++;
  601. }
  602. }
  603. }
  604. }
  605. if (i <= 4) {
  606. /* Failed to allocate maxdata_list or range_table_list
  607. * for a subdevice that needed it. */
  608. result = -ENOMEM;
  609. for (i = 0; i <= 4; i++) {
  610. struct comedi_subdevice *s;
  611. s = &dev->subdevices[i];
  612. kfree(s->maxdata_list);
  613. s->maxdata_list = NULL;
  614. kfree(s->range_table_list);
  615. s->range_table_list = NULL;
  616. }
  617. }
  618. err_alloc_configs:
  619. kfree(dig_in_config);
  620. kfree(dig_out_config);
  621. kfree(chan_in_config);
  622. kfree(chan_out_config);
  623. if (result) {
  624. if (devpriv->tty) {
  625. filp_close(devpriv->tty, 0);
  626. devpriv->tty = NULL;
  627. }
  628. }
  629. }
  630. return result;
  631. }
  632. static void serial_2002_close(struct comedi_device *dev)
  633. {
  634. if (!IS_ERR(devpriv->tty) && (devpriv->tty != 0))
  635. filp_close(devpriv->tty, 0);
  636. }
  637. static int serial2002_di_rinsn(struct comedi_device *dev,
  638. struct comedi_subdevice *s,
  639. struct comedi_insn *insn, unsigned int *data)
  640. {
  641. int n;
  642. int chan;
  643. chan = devpriv->digital_in_mapping[CR_CHAN(insn->chanspec)];
  644. for (n = 0; n < insn->n; n++) {
  645. struct serial_data read;
  646. poll_digital(devpriv->tty, chan);
  647. while (1) {
  648. read = serial_read(devpriv->tty, 1000);
  649. if (read.kind != is_digital || read.index == chan)
  650. break;
  651. }
  652. data[n] = read.value;
  653. }
  654. return n;
  655. }
  656. static int serial2002_do_winsn(struct comedi_device *dev,
  657. struct comedi_subdevice *s,
  658. struct comedi_insn *insn, unsigned int *data)
  659. {
  660. int n;
  661. int chan;
  662. chan = devpriv->digital_out_mapping[CR_CHAN(insn->chanspec)];
  663. for (n = 0; n < insn->n; n++) {
  664. struct serial_data write;
  665. write.kind = is_digital;
  666. write.index = chan;
  667. write.value = data[n];
  668. serial_write(devpriv->tty, write);
  669. }
  670. return n;
  671. }
  672. static int serial2002_ai_rinsn(struct comedi_device *dev,
  673. struct comedi_subdevice *s,
  674. struct comedi_insn *insn, unsigned int *data)
  675. {
  676. int n;
  677. int chan;
  678. chan = devpriv->analog_in_mapping[CR_CHAN(insn->chanspec)];
  679. for (n = 0; n < insn->n; n++) {
  680. struct serial_data read;
  681. poll_channel(devpriv->tty, chan);
  682. while (1) {
  683. read = serial_read(devpriv->tty, 1000);
  684. if (read.kind != is_channel || read.index == chan)
  685. break;
  686. }
  687. data[n] = read.value;
  688. }
  689. return n;
  690. }
  691. static int serial2002_ao_winsn(struct comedi_device *dev,
  692. struct comedi_subdevice *s,
  693. struct comedi_insn *insn, unsigned int *data)
  694. {
  695. int n;
  696. int chan;
  697. chan = devpriv->analog_out_mapping[CR_CHAN(insn->chanspec)];
  698. for (n = 0; n < insn->n; n++) {
  699. struct serial_data write;
  700. write.kind = is_channel;
  701. write.index = chan;
  702. write.value = data[n];
  703. serial_write(devpriv->tty, write);
  704. devpriv->ao_readback[chan] = data[n];
  705. }
  706. return n;
  707. }
  708. static int serial2002_ao_rinsn(struct comedi_device *dev,
  709. struct comedi_subdevice *s,
  710. struct comedi_insn *insn, unsigned int *data)
  711. {
  712. int n;
  713. int chan = CR_CHAN(insn->chanspec);
  714. for (n = 0; n < insn->n; n++)
  715. data[n] = devpriv->ao_readback[chan];
  716. return n;
  717. }
  718. static int serial2002_ei_rinsn(struct comedi_device *dev,
  719. struct comedi_subdevice *s,
  720. struct comedi_insn *insn, unsigned int *data)
  721. {
  722. int n;
  723. int chan;
  724. chan = devpriv->encoder_in_mapping[CR_CHAN(insn->chanspec)];
  725. for (n = 0; n < insn->n; n++) {
  726. struct serial_data read;
  727. poll_channel(devpriv->tty, chan);
  728. while (1) {
  729. read = serial_read(devpriv->tty, 1000);
  730. if (read.kind != is_channel || read.index == chan)
  731. break;
  732. }
  733. data[n] = read.value;
  734. }
  735. return n;
  736. }
  737. static int serial2002_attach(struct comedi_device *dev,
  738. struct comedi_devconfig *it)
  739. {
  740. struct comedi_subdevice *s;
  741. printk("comedi%d: serial2002: ", dev->minor);
  742. dev->board_name = thisboard->name;
  743. if (alloc_private(dev, sizeof(struct serial2002_private)) < 0)
  744. return -ENOMEM;
  745. dev->open = serial_2002_open;
  746. dev->close = serial_2002_close;
  747. devpriv->port = it->options[0];
  748. devpriv->speed = it->options[1];
  749. printk("/dev/ttyS%d @ %d\n", devpriv->port, devpriv->speed);
  750. if (alloc_subdevices(dev, 5) < 0)
  751. return -ENOMEM;
  752. /* digital input subdevice */
  753. s = dev->subdevices + 0;
  754. s->type = COMEDI_SUBD_DI;
  755. s->subdev_flags = SDF_READABLE;
  756. s->n_chan = 0;
  757. s->maxdata = 1;
  758. s->range_table = &range_digital;
  759. s->insn_read = &serial2002_di_rinsn;
  760. /* digital output subdevice */
  761. s = dev->subdevices + 1;
  762. s->type = COMEDI_SUBD_DO;
  763. s->subdev_flags = SDF_WRITEABLE;
  764. s->n_chan = 0;
  765. s->maxdata = 1;
  766. s->range_table = &range_digital;
  767. s->insn_write = &serial2002_do_winsn;
  768. /* analog input subdevice */
  769. s = dev->subdevices + 2;
  770. s->type = COMEDI_SUBD_AI;
  771. s->subdev_flags = SDF_READABLE | SDF_GROUND;
  772. s->n_chan = 0;
  773. s->maxdata = 1;
  774. s->range_table = 0;
  775. s->insn_read = &serial2002_ai_rinsn;
  776. /* analog output subdevice */
  777. s = dev->subdevices + 3;
  778. s->type = COMEDI_SUBD_AO;
  779. s->subdev_flags = SDF_WRITEABLE;
  780. s->n_chan = 0;
  781. s->maxdata = 1;
  782. s->range_table = 0;
  783. s->insn_write = &serial2002_ao_winsn;
  784. s->insn_read = &serial2002_ao_rinsn;
  785. /* encoder input subdevice */
  786. s = dev->subdevices + 4;
  787. s->type = COMEDI_SUBD_COUNTER;
  788. s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
  789. s->n_chan = 0;
  790. s->maxdata = 1;
  791. s->range_table = 0;
  792. s->insn_read = &serial2002_ei_rinsn;
  793. return 1;
  794. }
  795. static int serial2002_detach(struct comedi_device *dev)
  796. {
  797. struct comedi_subdevice *s;
  798. int i;
  799. printk("comedi%d: serial2002: remove\n", dev->minor);
  800. for (i = 0; i < 5; i++) {
  801. s = &dev->subdevices[i];
  802. kfree(s->maxdata_list);
  803. kfree(s->range_table_list);
  804. }
  805. return 0;
  806. }
  807. static int __init driver_serial2002_init_module(void)
  808. {
  809. return comedi_driver_register(&driver_serial2002);
  810. }
  811. static void __exit driver_serial2002_cleanup_module(void)
  812. {
  813. comedi_driver_unregister(&driver_serial2002);
  814. }
  815. module_init(driver_serial2002_init_module);
  816. module_exit(driver_serial2002_cleanup_module);
  817. MODULE_AUTHOR("Comedi http://www.comedi.org");
  818. MODULE_DESCRIPTION("Comedi low-level driver");
  819. MODULE_LICENSE("GPL");