- braille: ht detection needs longer timeouts
[opensuse:hwinfo.git] / src / hd / braille.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <fcntl.h>
6 #include <termios.h>
7 #include <sys/ioctl.h>
8
9 #include "hd.h"
10 #include "hd_int.h"
11 #include "braille.h"
12
13 /**
14  * @defgroup BRAILLEint Braille devices
15  * @ingroup  libhdDEVint
16  * @brief Braille displays functions
17  *
18  * @{
19  */
20
21 #if !defined(LIBHD_TINY) && !defined(__sparc__)
22
23 static unsigned do_alva(hd_data_t *hd_data, char *dev_name, int cnt);
24 static unsigned do_fhp(hd_data_t *hd_data, char *dev_name, unsigned baud, int cnt);
25 static unsigned do_fhp_new(hd_data_t *hd_data, char *dev_name, int cnt);
26 static unsigned do_ht(hd_data_t *hd_data, char *dev_name, int cnt);
27 static unsigned do_baum(hd_data_t *hd_data, char *dev_name, int cnt);
28
29 void hd_scan_braille(hd_data_t *hd_data)
30 {
31   hd_t *hd, *hd_tmp;
32   int cnt = 0;
33   unsigned *dev, *vend;
34
35   if(!hd_probe_feature(hd_data, pr_braille)) return;
36
37   hd_data->module = mod_braille;
38
39   /* some clean-up */
40   remove_hd_entries(hd_data);
41
42   dev = hd_shm_add(hd_data, NULL, sizeof *dev);
43   vend = hd_shm_add(hd_data, NULL, sizeof *vend);
44
45   if(!dev || !vend) return;
46
47   for(hd = hd_data->hd; hd; hd = hd->next) {
48     if(
49       hd->base_class.id == bc_comm &&
50       hd->sub_class.id == sc_com_ser &&
51       hd->unix_dev_name &&
52       !hd->tag.ser_skip &&
53       !has_something_attached(hd_data, hd)
54     ) {
55       cnt++;
56       *dev = *vend = 0;
57
58       hd_fork(hd_data, 10, 10);
59
60       if(hd_data->flags.forked) {
61
62         if(hd_probe_feature(hd_data, pr_braille_alva)) {
63           PROGRESS(1, cnt, "alva");
64           *vend = MAKE_ID(TAG_SPECIAL, 0x5001);
65           *dev = do_alva(hd_data, hd->unix_dev_name, cnt);
66         }
67
68         if(!*dev && hd_probe_feature(hd_data, pr_braille_fhp)) {
69           PROGRESS(1, cnt, "fhp_old");
70           *vend = MAKE_ID(TAG_SPECIAL, 0x5002);
71           *dev = do_fhp(hd_data, hd->unix_dev_name, B19200, cnt);
72           if(!*dev) {
73             PROGRESS(1, cnt, "fhp_el");
74             *dev = do_fhp(hd_data, hd->unix_dev_name, B38400, cnt);
75           }
76         }
77
78         if(!*dev && hd_probe_feature(hd_data, pr_braille_ht)) {
79           PROGRESS(1, cnt, "ht");
80           *vend = MAKE_ID(TAG_SPECIAL, 0x5003);
81           *dev = do_ht(hd_data, hd->unix_dev_name, cnt);
82         }
83
84         if(!*dev && hd_probe_feature(hd_data, pr_braille_baum)) {
85           PROGRESS(1, cnt, "baum");
86           *vend = MAKE_ID(TAG_SPECIAL, 0x5004);
87           *dev = do_baum(hd_data, hd->unix_dev_name, cnt);
88         }
89
90         if(!*dev && hd_probe_feature(hd_data, pr_braille_fhp)) {
91           PROGRESS(1, cnt, "fhp new");
92           *vend = MAKE_ID(TAG_SPECIAL, 0x5002);
93           *dev = do_fhp_new(hd_data, hd->unix_dev_name, cnt);
94         }
95
96       }
97
98       hd_fork_done(hd_data);
99
100       if(*dev && *vend) {
101         hd_tmp = add_hd_entry(hd_data, __LINE__, 0);
102         hd_tmp->base_class.id = bc_braille;
103         hd_tmp->bus.id = bus_serial;
104         hd_tmp->unix_dev_name = new_str(hd->unix_dev_name);
105         hd_tmp->attached_to = hd->idx;
106         hd_tmp->vendor.id = *vend;
107         hd_tmp->device.id = *dev;
108       }
109     }
110   }
111
112   hd_shm_clean(hd_data);
113 }
114
115
116 /*
117  * autodetect for Alva Braille-displays
118  * Author: marco Skambraks <marco@suse.de>
119  * Suse GmbH Nuernberg
120  *
121  * This is free software, placed under the terms of the
122  * GNU General Public License, as published by the Free Software
123  * Foundation.  Please see the file COPYING for details.
124 */
125
126 /* Communication codes */
127 #define BRL_ID  "\033ID="
128
129
130 #define WAIT_DTR        700000
131 #define WAIT_FLUSH      200
132
133 unsigned do_alva(hd_data_t *hd_data, char *dev_name, int cnt)
134 {
135   int fd, i, timeout = 100;
136   struct termios oldtio, newtio;                /* old & new terminal settings */
137   int model = -1;
138   unsigned char buffer[sizeof BRL_ID];
139   unsigned dev = 0;
140
141   PROGRESS(2, cnt, "alva open");
142
143   /* Open the Braille display device for random access */
144   fd = open(dev_name, O_RDWR | O_NOCTTY);
145   if(fd < 0) return 0;
146
147   tcgetattr(fd, &oldtio);       /* save current settings */
148
149   /* Set flow control and 8n1, enable reading */
150   memset(&newtio, 0, sizeof newtio);
151   newtio.c_cflag = CRTSCTS | CS8 | CLOCAL | CREAD;
152   /* Ignore bytes with parity errors and make terminal raw and dumb */
153   newtio.c_iflag = IGNPAR;
154   newtio.c_oflag = 0;           /* raw output */
155   newtio.c_lflag = 0;           /* don't echo or generate signals */
156   newtio.c_cc[VMIN] = 0;        /* set nonblocking read */
157   newtio.c_cc[VTIME] = 0;
158
159   PROGRESS(3, cnt, "alva init ok");
160
161   PROGRESS(4, cnt, "alva read data");
162
163   /* autodetecting ABT model */
164   /* to force DTR off */
165   cfsetispeed(&newtio, B0);
166   cfsetospeed(&newtio, B0);
167   tcsetattr(fd, TCSANOW, &newtio);      /* activate new settings */
168   usleep(WAIT_DTR);
169
170   tcflush(fd, TCIOFLUSH);               /* clean line */
171   usleep(WAIT_FLUSH);
172
173   /* DTR back on */
174   cfsetispeed(&newtio, B9600);
175   cfsetospeed(&newtio, B9600);
176   tcsetattr(fd, TCSANOW, &newtio);      /* activate new settings */
177   usleep(WAIT_DTR);                     /* give time to send ID string */
178
179   if((i = read(fd, buffer, sizeof buffer)) == sizeof buffer) {
180     if(!strncmp(buffer, BRL_ID, sizeof BRL_ID - 1)) {
181       /* Find out which model we are connected to... */
182       switch(model = buffer[sizeof buffer - 1])
183       {
184         case    1:
185         case    2:
186         case    3:
187         case    4:
188         case 0x0b:
189         case 0x0d:
190         case 0x0e:
191          dev = MAKE_ID(TAG_SPECIAL, model);
192          break;
193       }
194     }
195   }
196   ADD2LOG("alva.%d@%s[%d]: ", timeout, dev_name, i);
197   if(i > 0) hexdump(&hd_data->log, 1, i, buffer);
198   ADD2LOG("\n");
199
200   PROGRESS(5, cnt, "alva read done");
201
202   /* reset serial lines */
203   tcflush(fd, TCIOFLUSH);
204   tcsetattr(fd, TCSAFLUSH, &oldtio);
205   close(fd);
206
207   return dev;
208 }
209
210
211 /*
212  * autodetect for Papenmeier Braille-displays
213  * Author: marco Skambraks <marco@suse.de>
214  * Suse GmbH Nuernberg
215  *
216  * This is free software, placed under the terms of the
217  * GNU General Public License, as published by the Free Software
218  * Foundation.  Please see the file COPYING for details.
219  */
220
221 unsigned do_fhp(hd_data_t *hd_data, char *dev_name, unsigned baud, int cnt)
222 {
223   int fd, i;
224   char crash[] = { 2, 'S', 0, 0, 0, 0 };
225   unsigned char buf[10];
226   struct termios oldtio, newtio;        /* old & new terminal settings */
227   unsigned dev;
228
229   PROGRESS(2, cnt, "fhp open");
230
231   /* Now open the Braille display device for random access */
232   fd = open(dev_name, O_RDWR | O_NOCTTY);
233   if(fd < 0) return 0;
234
235   tcgetattr(fd, &oldtio);       /* save current settings */
236
237   /* Set bps, flow control and 8n1, enable reading */
238   memset(&newtio, 0, sizeof newtio);
239   newtio.c_cflag = baud | CS8 | CLOCAL | CREAD;
240
241   /* Ignore bytes with parity errors and make terminal raw and dumb */
242   newtio.c_iflag = IGNPAR;
243   newtio.c_oflag = 0;                           /* raw output */
244   newtio.c_lflag = 0;                           /* don't echo or generate signals */
245   newtio.c_cc[VMIN] = 0;                        /* set nonblocking read */
246   newtio.c_cc[VTIME] = 0;
247   tcflush(fd, TCIFLUSH);                        /* clean line */
248   tcsetattr(fd, TCSANOW, &newtio);              /* activate new settings */
249
250   PROGRESS(3, cnt, "fhp init ok");
251
252   crash[2] = 0x200 >> 8;
253   crash[3] = 0x200 & 0xff;
254   crash[5] = (7+10) & 0xff;
255
256   write(fd, crash, sizeof crash);
257   write(fd, "1111111111",10);
258   write(fd, "\03", 1);
259
260   crash[2] = 0x0 >> 8;
261   crash[3] = 0x0 & 0xff;
262   crash[5] = 5 & 0xff;
263
264   write(fd, crash, sizeof crash);
265   write(fd, "1111111111", 10);
266   write(fd, "\03", 1);
267
268   usleep(500000);               /* 100000 should be enough */
269
270   PROGRESS(4, cnt, "fhp write ok");
271
272   i = read(fd, &buf, 10);
273
274   PROGRESS(5, cnt, "fhp read done");
275
276   ADD2LOG("fhp@%s[%d]: ", dev_name, i);
277   if(i > 0) hexdump(&hd_data->log, 1, i, buf);
278   ADD2LOG("\n");
279
280   dev = 0;
281   if(i == 10 && buf[0] == 0x02 && buf[1] == 0x49) {
282     switch(buf[2]) {
283       case  1:
284       case  2:
285       case  3:
286       case 64:
287       case 65:
288       case 66:
289       case 67:
290       case 68:
291         dev = buf[2];
292         dev = MAKE_ID(TAG_SPECIAL, dev);
293         break;
294     }
295   }
296   if(!dev) ADD2LOG("no fhp display: 0x%02x\n", i >= 2 ? buf[2] : 0);
297
298   /* reset serial lines */
299   tcflush(fd, TCIOFLUSH);
300   tcsetattr(fd, TCSAFLUSH, &oldtio);
301   close(fd);
302
303   return dev;
304 }
305
306
307 /*
308  * autodetect for Handy Tech  Braille-displays
309  * Author: marco Skambraks <marco@suse.de>
310  * Suse GmbH Nuernberg
311  *
312  * This is free software, placed under the terms of the
313  * GNU General Public License, as published by the Free Software
314  * Foundation.  Please see the file COPYING for details.
315 */
316
317 unsigned do_ht(hd_data_t *hd_data, char *dev_name, int cnt)
318 {
319   int fd, i;
320   unsigned char code = 0xff, buf[2] = { 0, 0 };
321   struct termios oldtio, newtio;
322   unsigned dev = 0;
323
324   PROGRESS(2, cnt, "ht open");
325
326   fd = open(dev_name, O_RDWR | O_NOCTTY);
327   if(fd < 0) return 0;
328
329   tcgetattr(fd, &oldtio);
330
331   newtio = oldtio;
332   newtio.c_cflag = CLOCAL | PARODD | PARENB | CREAD | CS8;
333   newtio.c_iflag = IGNPAR;
334   newtio.c_oflag = 0;
335   newtio.c_lflag = 0;
336   newtio.c_cc[VMIN] = 0;
337   newtio.c_cc[VTIME] = 0;
338
339   i = 0;
340   /*
341    * Force down DTR, flush any pending data and then the port to what we
342    * want it to be
343    */
344   if(
345     !(
346       cfsetispeed(&newtio, B0) ||
347       cfsetospeed(&newtio, B0) ||
348       tcsetattr(fd, TCSANOW, &newtio) ||
349       tcflush(fd, TCIOFLUSH) ||
350       cfsetispeed(&newtio, B19200) ||
351       cfsetospeed(&newtio, B19200) ||
352       tcsetattr(fd, TCSANOW, &newtio)
353     )
354   ) {
355     /* Pause 20ms to let them take effect */
356     usleep(20 * 1000);
357
358     PROGRESS(3, cnt, "ht init ok");
359
360     write(fd, &code, 1);        /* reset brl */
361     usleep(40 * 1000);          /* wait for reset */
362
363     PROGRESS(4, cnt, "ht write ok");
364
365     read(fd, buf, 1);
366     i = 1;
367
368     PROGRESS(5, cnt, "ht read done");
369
370     if(buf[0] == 0xfe) {        /* resetok now read id */
371       usleep(80 * 1000);
372       read(fd, buf + 1, 1);
373       i = 2;
374
375       PROGRESS(6, cnt, "ht read done");
376
377       switch(buf[1]) {
378         case 0x05:
379         case 0x09:
380         case 0x36:
381         case 0x38:
382         case 0x44:
383         case 0x72:
384         case 0x74:
385         case 0x78:
386         case 0x80:
387         case 0x84:
388         case 0x88:
389         case 0x89:
390           dev = buf[1];
391           dev = MAKE_ID(TAG_SPECIAL, dev);
392           break;
393       }
394     }
395   }
396
397   ADD2LOG("ht@%s[%d]: ", dev_name, i);
398   if(i > 0) hexdump(&hd_data->log, 1, i, buf);
399   ADD2LOG("\n");
400
401   if(!dev) ADD2LOG("no ht display: 0x%02x\n", buf[1]);
402
403   /* reset serial lines */
404   tcflush(fd, TCIOFLUSH);
405   tcsetattr(fd, TCSAFLUSH, &oldtio);
406   close(fd);
407
408   return dev;
409 }
410
411
412 /*
413  * autodetect for Baum Braille-displays
414  * Author: marco Skambraks <marco@suse.de>
415  * Suse GmbH Nuernberg
416  *
417  * This is free software, placed under the terms of the
418  * GNU General Public License, as published by the Free Software
419  * Foundation.  Please see the file COPYING for details.
420 */
421
422 #define BAUDRATE        B19200          /* But both run at 19k2 */
423 #define MAXREAD         18
424
425 unsigned do_baum(hd_data_t *hd_data, char *dev_name, int cnt)
426 {
427   static char device_id[] = { 0x1b, 0x84 };
428   int fd;
429   struct termios oldtio, curtio;
430   unsigned char buf[MAXREAD + 1];
431   int i;
432
433   PROGRESS(2, cnt, "baum open");
434
435   fd = open(dev_name, O_RDWR | O_NOCTTY);
436   if(fd < 0) return 0;
437
438   tcgetattr(fd, &curtio);
439
440   oldtio = curtio;
441   cfmakeraw(&curtio);
442
443   /* no SIGTTOU to backgrounded processes */
444   curtio.c_lflag &= ~TOSTOP;
445   curtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;
446   /* no input parity check, no XON/XOFF */
447   curtio.c_iflag &= ~(INPCK | ~IXOFF);
448
449   curtio.c_cc[VTIME] = 2;       /* 0.1s timeout between chars on input */
450   curtio.c_cc[VMIN] = 0;        /* no minimum input */
451
452   tcsetattr(fd, TCSAFLUSH, &curtio);
453
454   /* write ID-request */
455   write(fd, device_id, sizeof device_id);
456
457   /* wait for response */
458   usleep(250000);
459
460   PROGRESS(3, cnt, "baum write ok");
461
462   i = read(fd, buf, sizeof buf - 1);
463   buf[sizeof buf - 1] = 0;
464
465   PROGRESS(4, cnt, "baum read done");
466
467   ADD2LOG("baum@%s[%d]: ", dev_name, i);
468   if(i > 0) hexdump(&hd_data->log, 1, i, buf);
469   ADD2LOG("\n");
470
471   /* reset serial lines */
472   tcflush(fd, TCIOFLUSH);
473   tcsetattr(fd, TCSAFLUSH, &oldtio);
474   close(fd);
475
476   if(!strcmp(buf + 2, "Baum Vario40")) return MAKE_ID(TAG_SPECIAL, 1);
477   if(!strcmp(buf + 2, "Baum Vario80")) return MAKE_ID(TAG_SPECIAL, 2);
478
479   return 0;
480 }
481
482
483 unsigned do_fhp_new(hd_data_t *hd_data, char *dev_name, int cnt)
484 {
485   int i, fd, status = 0;
486   unsigned id;
487   unsigned char retstr[50] = "";
488   unsigned char brlauto[] = { 2, 0x42, 0x50, 0x50, 3 };
489   struct termios oldtio, tiodata = { };
490
491   PROGRESS(2, cnt, "fhp2 open");
492
493   fd = open(dev_name, O_RDWR | O_NONBLOCK | O_NOCTTY);
494   if(fd < 0) return 0;
495
496   fcntl(fd, F_SETFL, 0);        // remove O_NONBLOCK
497
498   tcgetattr(fd, &oldtio);
499
500   /* Set bps, and 8n1, enable reading */
501   tiodata.c_cflag = (CLOCAL | CREAD | CS8);
502   tiodata.c_iflag = IGNPAR;
503   tiodata.c_lflag = 0;
504   tiodata.c_cc[VMIN] = 0;
505   tiodata.c_cc[VTIME] = 0;
506
507   if(
508     cfsetispeed(&tiodata, B0) ||
509     cfsetospeed(&tiodata, B0) ||
510     tcsetattr(fd, TCSANOW, &tiodata) ||
511     tcflush(fd, TCIOFLUSH) ||
512     cfsetispeed(&tiodata, B57600) ||
513     cfsetospeed(&tiodata, B57600) ||
514     tcsetattr(fd, TCSANOW, &tiodata)
515   ) {
516      /* init error */
517
518     tcflush(fd, TCIOFLUSH);
519     tcsetattr(fd, TCSAFLUSH, &oldtio);
520     close(fd);
521
522     return 0;
523   }
524
525   tcflush(fd, TCIOFLUSH);
526   usleep(100 * 1000);
527
528   /* get status of inteface */
529   ioctl(fd, TIOCMGET, &status);
530
531   /* clear dtr-line */
532   status &= ~TIOCM_DTR;
533
534   /* set new status */
535   ioctl(fd, TIOCMSET, &status);
536
537   usleep(100 * 1000);
538
539   write(fd, brlauto, sizeof brlauto);
540
541   PROGRESS(3, cnt, "fhp2 write ok");
542
543   usleep(100 * 1000);
544
545   i = read(fd, retstr, 20);
546
547   PROGRESS(4, cnt, "fhp2 read done");
548
549   ADD2LOG("fhp2@%s[%d]: ", dev_name, i);
550   if(i > 0) hexdump(&hd_data->log, 1, i, retstr);
551   ADD2LOG("\n");
552
553   id = 0;
554
555   if(i == 10 && retstr[1] == 'J') {
556     id = retstr[3];
557
558     /* papenmeir new serial and usb device IDs */
559     switch(id) {
560       case 0x55:
561       case 0x57:
562       case 0x58:
563         id = MAKE_ID(TAG_SPECIAL, id);
564         break;
565
566       default:
567         ADD2LOG("unknown id %d\n", id);
568         id = 0;
569     }
570   }
571
572   /* reset serial lines */
573   tcflush(fd, TCIOFLUSH);
574   tcsetattr(fd, TCSAFLUSH, &oldtio);
575   close(fd);
576
577   return id;
578 }
579
580
581 #endif  /* !defined(LIBHD_TINY) && !defined(__sparc__) */
582
583 /** @} */
584