]>
git.ipfire.org Git - ipfire-2.x.git/blob - src/hwinfo/src/hd/modem.c
11 #include <sys/ioctl.h>
18 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
22 * Note: what about modem speed?
24 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
29 static struct speeds_s
{
42 #if !defined(__sparc__)
46 ,{ 1000000, B1000000
}
47 ,{ 2000000, B2000000
}
48 ,{ 4000000, B4000000
}
52 #define MAX_SPEED (sizeof speeds / sizeof *speeds)
54 static char *init_strings
[] = {
62 #define MAX_INIT_STRING (sizeof init_strings / sizeof *init_strings)
64 static void get_serial_modem(hd_data_t
* hd_data
);
65 static void add_serial_modem(hd_data_t
* hd_data
);
66 static int dev_name_duplicate(hd_data_t
*hd_data
, char *dev_name
);
67 static void guess_modem_name(hd_data_t
*hd_data
, ser_device_t
*sm
);
68 static void at_cmd(hd_data_t
*hd_data
, char *at
, int raw
, int log_it
);
69 static void write_modem(hd_data_t
*hd_data
, char *msg
);
70 static void read_modem(hd_data_t
*hd_data
);
71 static ser_device_t
*add_ser_modem_entry(ser_device_t
**sm
, ser_device_t
*new_sm
);
72 static int set_modem_speed(ser_device_t
*sm
, unsigned baud
);
73 static int init_modem(ser_device_t
*mi
);
74 static unsigned chk4id(ser_device_t
*mi
);
75 static void dump_ser_modem_data(hd_data_t
*hd_data
);
77 void hd_scan_modem(hd_data_t
*hd_data
)
79 ser_device_t
*sm
, *sm_next
;
81 if(!hd_probe_feature(hd_data
, pr_modem
)) return;
83 hd_data
->module
= mod_modem
;
86 remove_hd_entries(hd_data
);
87 hd_data
->ser_modem
= NULL
;
89 PROGRESS(1, 0, "serial");
91 hd_fork(hd_data
, 15, 120);
93 if(hd_data
->flags
.forked
) {
94 get_serial_modem(hd_data
);
95 hd_move_to_shm(hd_data
);
96 if((hd_data
->debug
& HD_DEB_MODEM
)) dump_ser_modem_data(hd_data
);
99 /* take data from shm */
100 hd_data
->ser_modem
= ((hd_data_t
*) (hd_data
->shm
.data
))->ser_modem
;
101 if((hd_data
->debug
& HD_DEB_MODEM
)) dump_ser_modem_data(hd_data
);
104 hd_fork_done(hd_data
);
106 add_serial_modem(hd_data
);
108 hd_shm_clean(hd_data
);
110 for(sm
= hd_data
->ser_modem
; sm
; sm
= sm_next
) {
113 free_str_list(sm
->at_resp
);
115 free_mem(sm
->dev_name
);
116 free_mem(sm
->serial
);
117 free_mem(sm
->class_name
);
118 free_mem(sm
->dev_id
);
119 free_mem(sm
->user_name
);
121 free_mem(sm
->init_string1
);
122 free_mem(sm
->init_string2
);
126 hd_data
->ser_modem
= NULL
;
130 int check_for_responce(str_list_t
*str_list
, char *str
, int len
)
132 for(; str_list
!= NULL
; str_list
= str_list
->next
) {
133 if(!strncmp(str_list
->str
, str
, len
)) return 1;
139 str_list_t
*str_list_dup(str_list_t
*orig
)
141 str_list_t
*dup
= NULL
;
143 for(; orig
!= NULL
; orig
= orig
->next
) {
144 add_str_list(&dup
, orig
->str
);
150 void get_serial_modem(hd_data_t
*hd_data
)
154 unsigned modem_info
, baud
;
157 int chk_usb
= hd_probe_feature(hd_data
, pr_modem_usb
);
159 /* serial modems & usb modems */
160 for(hd
= hd_data
->hd
; hd
; hd
= hd
->next
) {
164 hd
->base_class
.id
== bc_comm
&&
165 hd
->sub_class
.id
== sc_com_ser
&&
167 hd
->tag
.ser_device
!= 2 && /* cf. serial.c */
168 !has_something_attached(hd_data
, hd
)
172 hd
->bus
.id
== bus_usb
&&
173 hd
->base_class
.id
== bc_modem
175 ) && hd
->unix_dev_name
177 if(dev_name_duplicate(hd_data
, hd
->unix_dev_name
)) continue;
178 if((fd
= open(hd
->unix_dev_name
, O_RDWR
| O_NONBLOCK
)) >= 0) {
179 sm
= add_ser_modem_entry(&hd_data
->ser_modem
, new_mem(sizeof *sm
));
180 sm
->dev_name
= new_str(hd
->unix_dev_name
);
182 sm
->hd_idx
= hd
->idx
;
189 if(!hd_data
->ser_modem
) return;
191 PROGRESS(2, 0, "init");
193 usleep(300000); /* PnP protocol; 200ms seems to be too fast */
195 for(sm
= hd_data
->ser_modem
; sm
; sm
= sm
->next
) {
196 modem_info
= TIOCM_DTR
| TIOCM_RTS
;
197 ioctl(sm
->fd
, TIOCMBIS
, &modem_info
);
198 ioctl(sm
->fd
, TIOCMGET
, &modem_info
);
199 if(!(modem_info
& (TIOCM_DSR
| TIOCM_CD
))) {
204 /* just a quick test if we get a response to an AT command */
206 for(i
= 0; i
< 4; i
++) {
207 PROGRESS(3, i
+ 1, "at test");
209 for(sm
= hd_data
->ser_modem
; sm
; sm
= sm
->next
) {
211 set_modem_speed(sm
, i
== 0 ? 115200 : i
== 1 ? 38400 : i
== 2 ? 9600 : 1200);
214 at_cmd(hd_data
, "AT\r", 1, 1);
216 for(sm
= hd_data
->ser_modem
; sm
; sm
= sm
->next
) {
217 if(strstr(sm
->buf
, "OK") || strstr(sm
->buf
, "0")) {
221 sm
->buf_len
= 0; /* clear buffer */
225 for(sm
= hd_data
->ser_modem
; sm
; sm
= sm
->next
) {
226 if((sm
->do_io
= sm
->is_modem
)) {
227 sm
->max_baud
= sm
->cur_baud
;
231 /* check for init string */
232 PROGRESS(4, 0, "init string");
235 for(i
= 0; (unsigned) i
< MAX_INIT_STRING
; i
++) {
236 str_printf(&command
, 0, "AT %s\r", init_strings
[i
]);
237 at_cmd(hd_data
, command
, 1, 1);
239 for(sm
= hd_data
->ser_modem
; sm
; sm
= sm
->next
) {
240 if(strstr(sm
->buf
, "OK") || strstr(sm
->buf
, "0")) {
241 str_printf(&sm
->init_string2
, -1,
242 "%s %s", sm
->init_string2
? "" : "AT", init_strings
[i
]
247 command
= free_mem(command
);
249 for(sm
= hd_data
->ser_modem
; sm
; sm
= sm
->next
)
251 str_printf(&sm
->init_string1
, -1, "ATZ");
254 int cmds
[] = { 1, 3, 4, 5, 6 };
256 int i
, j
, ModemsCount
= 0;
257 str_list_t
**responces
= NULL
;
258 for(sm
= hd_data
->ser_modem
; sm
; sm
= sm
->next
)
261 responces
= new_mem(ModemsCount
* sizeof *responces
);
263 at_cmd(hd_data
, "ATI\r", 0, 1);
264 for(j
= 0, sm
= hd_data
->ser_modem
; sm
; sm
= sm
->next
) {
266 responces
[j
++] = str_list_dup(sm
->at_resp
);
269 for(i
= 0; (unsigned) i
< sizeof cmds
/ sizeof *cmds
; i
++) {
271 sprintf(at
, "ATI%d\r", atx
);
272 at_cmd(hd_data
, at
, 0, 1);
273 for(j
= 0, sm
= hd_data
->ser_modem
; sm
; sm
= sm
->next
) {
275 if(atx
== 1 && check_for_responce(responces
[j
], "Hagenuk", 7) &&
276 (check_for_responce(sm
->at_resp
, "Speed Dragon", 12) ||
277 check_for_responce(sm
->at_resp
, "Power Dragon", 12))) {
278 free_mem(sm
->init_string1
);
279 free_mem(sm
->init_string2
);
280 sm
->init_string1
= new_str("AT&F");
281 sm
->init_string2
= new_str("ATB8");
283 if(atx
== 3 && check_for_responce(responces
[j
], "346900", 6) &&
284 check_for_responce(sm
->at_resp
, "3Com U.S. Robotics ISDN", 23)) {
285 free_mem(sm
->init_string1
);
286 free_mem(sm
->init_string2
);
287 sm
->init_string1
= new_str("AT&F");
288 sm
->init_string2
= new_str("AT*PPP=1");
290 if(atx
== 4 && check_for_responce(responces
[j
], "SP ISDN", 7) &&
291 check_for_responce(sm
->at_resp
, "Sportster ISDN TA", 17)) {
292 free_mem(sm
->init_string1
);
293 free_mem(sm
->init_string2
);
294 sm
->init_string1
= new_str("AT&F");
295 sm
->init_string2
= new_str("ATB3");
297 if(atx
== 6 && check_for_responce(responces
[j
], "644", 3) &&
298 check_for_responce(sm
->at_resp
, "ELSA MicroLink ISDN", 19)) {
299 free_mem(sm
->init_string1
);
300 free_mem(sm
->init_string2
);
301 sm
->init_string1
= new_str("AT&F");
302 sm
->init_string2
= new_str("AT$IBP=HDLCP");
303 free_mem(sm
->pppd_option
);
304 sm
->pppd_option
= new_str("default-asyncmap");
306 if(atx
== 6 && check_for_responce(responces
[j
], "643", 3) &&
307 check_for_responce(sm
->at_resp
, "MicroLink ISDN/TLV.34", 21)) {
308 free_mem(sm
->init_string1
);
309 free_mem(sm
->init_string2
);
310 sm
->init_string1
= new_str("AT&F");
311 sm
->init_string2
= new_str("AT\\N10%P1");
313 if(atx
== 5 && check_for_responce(responces
[j
], "ISDN TA", 6) &&
314 check_for_responce(sm
->at_resp
, "ISDN TA;ASU", 4)) {
316 sm
->vend
= new_str("ASUS");
317 free_mem(sm
->user_name
);
318 sm
->user_name
= new_str("ISDNLink TA");
319 free_mem(sm
->init_string1
);
320 free_mem(sm
->init_string2
);
321 sm
->init_string1
= new_str("AT&F");
322 sm
->init_string2
= new_str("ATB40");
324 if(atx
==3 && check_for_responce(responces
[j
], "128000", 6) &&
325 check_for_responce(sm
->at_resp
, "Lasat Speed", 11)) {
326 free_mem(sm
->init_string1
);
327 free_mem(sm
->init_string2
);
328 sm
->init_string1
= new_str("AT&F");
329 sm
->init_string2
= new_str("AT\\P1&B2X3");
332 (check_for_responce(responces
[j
], "28642", 5) ||
333 check_for_responce(responces
[j
], "1281", 4) ||
334 check_for_responce(responces
[j
], "1282", 4) ||
335 check_for_responce(responces
[j
], "1283", 4) ||
336 check_for_responce(responces
[j
], "1291", 4) ||
337 check_for_responce(responces
[j
], "1292", 4) ||
338 check_for_responce(responces
[j
], "1293", 4)) &&
339 (check_for_responce(sm
->at_resp
, "Elite 2864I", 11) ||
340 check_for_responce(sm
->at_resp
, "ZyXEL omni", 10))) {
341 free_mem(sm
->init_string1
);
342 free_mem(sm
->init_string2
);
343 sm
->init_string1
= new_str("AT&F");
344 sm
->init_string2
= new_str("AT&O2B40");
351 for(i
= 0; i
< ModemsCount
; i
++) free_str_list(responces
[i
]);
355 /* now, go for the maximum speed... */
356 PROGRESS(5, 0, "speed");
358 for(i
= MAX_SPEED
- 1; i
>= 0; i
--) {
359 baud
= speeds
[i
].baud
;
360 for(j
= 0, sm
= hd_data
->ser_modem
; sm
; sm
= sm
->next
) {
362 if(baud
> sm
->max_baud
) {
363 sm
->do_io
= set_modem_speed(sm
, baud
) ? 0 : 1;
372 at_cmd(hd_data
, "AT\r", 1, 0);
374 for(sm
= hd_data
->ser_modem
; sm
; sm
= sm
->next
) {
375 if(strstr(sm
->buf
, "OK") || strstr(sm
->buf
, "0")) {
376 sm
->max_baud
= sm
->cur_baud
;
381 sm
->buf_len
= 0; /* clear buffer */
385 /* now, fix it all up... */
386 for(sm
= hd_data
->ser_modem
; sm
; sm
= sm
->next
) {
388 set_modem_speed(sm
, sm
->max_baud
);
394 /* just for testing */
395 if((hd_data
->debug
& HD_DEB_MODEM
)) {
397 int cmds
[] = { 0, 1, 2, 3, 6 };
400 PROGRESS(8, 0, "testing");
402 at_cmd(hd_data
, "ATI\r", 0, 1);
403 for(i
= 0; (unsigned) i
< sizeof cmds
/ sizeof *cmds
; i
++) {
404 sprintf(at
, "ATI%d\r", cmds
[i
]);
405 at_cmd(hd_data
, at
, 0, 1);
407 at_cmd(hd_data
, "AT\r", 0, 1);
411 PROGRESS(5, 0, "pnp id");
413 at_cmd(hd_data
, "ATI9\r", 1, 1);
415 for(sm
= hd_data
->ser_modem
; sm
; sm
= sm
->next
) {
419 if(!sm
->user_name
) guess_modem_name(hd_data
, sm
);
422 /* reset serial lines */
423 tcflush(sm
->fd
, TCIOFLUSH
);
424 tcsetattr(sm
->fd
, TCSAFLUSH
, &sm
->tio
);
430 void add_serial_modem(hd_data_t
*hd_data
)
437 for(sm
= hd_data
->ser_modem
; sm
; sm
= sm
->next
) {
438 if(!sm
->is_modem
) continue;
440 hd
= hd_get_device_by_idx(hd_data
, sm
->hd_idx
);
441 if(hd
&& hd
->base_class
.id
== bc_modem
) {
442 /* just *add* info */
446 hd
= add_hd_entry(hd_data
, __LINE__
, 0);
447 hd
->base_class
.id
= bc_modem
;
448 hd
->bus
.id
= bus_serial
;
449 hd
->unix_dev_name
= new_str(sm
->dev_name
);
450 hd
->attached_to
= sm
->hd_idx
;
451 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
452 res
->baud
.type
= res_baud
;
453 res
->baud
.speed
= sm
->max_baud
;
454 if(sm
->pppd_option
) {
455 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
456 res
->pppd_option
.type
= res_pppd_option
;
457 res
->pppd_option
.option
= new_str(sm
->pppd_option
);
460 strncpy(buf
, sm
->pnp_id
, 3);
462 hd
->vendor
.id
= name2eisa_id(buf
);
463 hd
->device
.id
= MAKE_ID(TAG_EISA
, strtol(sm
->pnp_id
+ 3, NULL
, 16));
465 hd
->serial
= new_str(sm
->serial
);
466 if(sm
->user_name
) hd
->device
.name
= new_str(sm
->user_name
);
467 if(sm
->vend
) hd
->vendor
.name
= new_str(sm
->vend
);
469 if(sm
->dev_id
&& strlen(sm
->dev_id
) >= 7) {
473 u1
= name2eisa_id(sm
->dev_id
);
475 strncpy(buf
, sm
->dev_id
+ 3, 4);
477 u2
= strtol(sm
->dev_id
+ 3, &s
, 16);
479 hd
->compat_vendor
.id
= u1
;
480 hd
->compat_device
.id
= MAKE_ID(TAG_EISA
, u2
);
485 if(!(hd
->device
.id
|| hd
->device
.name
|| hd
->vendor
.id
|| hd
->vendor
.name
)) {
486 hd
->vendor
.id
= MAKE_ID(TAG_SPECIAL
, 0x2000);
487 hd
->device
.id
= MAKE_ID(TAG_SPECIAL
, 0x0001);
490 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
491 res
->init_strings
.type
= res_init_strings
;
492 res
->init_strings
.init1
= new_str(sm
->init_string1
);
493 res
->init_strings
.init2
= new_str(sm
->init_string2
);
498 int dev_name_duplicate(hd_data_t
*hd_data
, char *dev_name
)
502 for(sm
= hd_data
->ser_modem
; sm
; sm
= sm
->next
) {
503 if(!strcmp(sm
->dev_name
, dev_name
)) return 1;
509 void guess_modem_name(hd_data_t
*hd_data
, ser_device_t
*modem
)
519 for(sm
= hd_data
->ser_modem
; sm
; sm
= sm
->next
) sm
->do_io
= 0;
521 (sm
= modem
)->do_io
= 1;
524 at_cmd(hd_data
, "ATI0\r", 0, 1);
526 if(sl
&& !strcmp(sl
->str
, "ATI0")) sl
= sl
->next
; /* skip AT cmd echo */
530 if(strstr(sl
->str
, "PowerBook")) {
531 sm
->vend
= new_str("Apple");
532 sm
->user_name
= new_str(sl
->str
);
536 s1
= new_str(sl
->str
);
539 at_cmd(hd_data
, "ATI1\r", 0, 1);
541 if(sl
&& !strcmp(sl
->str
, "ATI1")) sl
= sl
->next
; /* skip AT cmd echo */
544 if(strstr(sl
->str
, "APPLE")) {
545 sm
->vend
= new_str("Apple");
546 str_printf(&sm
->user_name
, 0, "AT Modem");
548 u
= strtoul(s1
, &s2
, 10);
549 if(u
&& !*s2
&& !(u
% 1000)) {
550 str_printf(&sm
->user_name
, 0, "%uk AT Modem", u
/ 1000);
563 at_cmd(hd_data
, "ATI3\r", 0, 1);
565 if(sl
&& !strcmp(sl
->str
, "ATI3")) sl
= sl
->next
; /* skip AT cmd echo */
568 if(*sl
->str
== 'U' && strstr(sl
->str
, "Robotics ")) {
569 /* looks like an U.S. Robotics... */
571 sm
->vend
= new_str("U.S. Robotics, Inc.");
572 /* strip revision code */
573 if((s
= strstr(sl
->str
, " Rev. "))) *s
= 0;
574 sm
->user_name
= canon_str(sl
->str
, strlen(sl
->str
));
579 if(strstr(sl
->str
, "3Com U.S. Robotics ") == sl
->str
) {
580 /* looks like an 3Com U.S. Robotics... */
582 sm
->vend
= new_str("3Com U.S. Robotics, Inc.");
583 sm
->user_name
= canon_str(sl
->str
, strlen(sl
->str
));
588 if(strstr(sl
->str
, "-V34_DS -d Z201 2836")) {
589 /* looks like a Zoom V34X */
591 sm
->vend
= new_str("Zoom Telephonics, Inc.");
592 sm
->user_name
= new_str("Zoom FaxModem V.34X Plus Model 2836");
597 if(strstr(sl
->str
, "FM560 VER 3.01 V.90")) {
598 /* looks like a Microcom DeskPorte 56K Voice ... */
600 sm
->vend
= new_str("Microcom");
601 sm
->user_name
= new_str("TravelCard 56K");
606 if(strstr(sl
->str
, "Compaq Microcom 550 56K Modem")) {
607 /* looks like a Microcom DeskPorte Pocket ... */
609 sm
->vend
= new_str("Compaq");
610 sm
->user_name
= new_str("Microcom 550 56K Modem");
617 at_cmd(hd_data
, "ATI0\r", 0, 1);
619 if(sl
&& !strcmp(sl
->str
, "ATI0")) sl
= sl
->next
; /* skip AT cmd echo */
622 if(strstr(sl
->str
, "DP Pocket")) {
623 /* looks like a Microcom DeskPorte Pocket ... */
625 sm
->vend
= new_str("Microcom");
626 sm
->user_name
= new_str("DeskPorte Pocket");
633 at_cmd(hd_data
, "ATI6\r", 0, 1);
635 if(sl
&& !strcmp(sl
->str
, "ATI6")) sl
= sl
->next
; /* skip AT cmd echo */
638 if(strstr(sl
->str
, "RCV56DPF-PLL L8571A")) {
639 /* looks like a Microcom DeskPorte 56K Voice ... */
641 sm
->vend
= new_str("Microcom");
642 sm
->user_name
= new_str("DeskPorte 56K Voice");
649 at_cmd(hd_data
, "ATI2\r", 0, 1);
651 if(sl
&& !strcmp(sl
->str
, "ATI2")) sl
= sl
->next
; /* skip AT cmd echo */
654 if(strstr(sl
->str
, "ZyXEL ")) {
655 /* looks like a ZyXEL... */
657 sm
->vend
= new_str("ZyXEL");
659 at_cmd(hd_data
, "ATI1\r", 0, 1);
661 if(sl
&& !strcmp(sl
->str
, "ATI1")) sl
= sl
->next
;
665 if((s
= strstr(sl
->str
, " V "))) *s
= 0;
666 sm
->user_name
= canon_str(sl
->str
, strlen(sl
->str
));
675 void at_cmd(hd_data_t
*hd_data
, char *at
, int raw
, int log_it
)
677 static unsigned u
= 1;
683 for(sm
= hd_data
->ser_modem
; sm
; sm
= sm
->next
) {
690 if(modems
== 0) return;
692 PROGRESS(9, u
, "write at cmd");
693 write_modem(hd_data
, at
);
694 PROGRESS(9, u
, "read at resp");
697 PROGRESS(9, u
, "read ok");
700 for(sm
= hd_data
->ser_modem
; sm
; sm
= sm
->next
) {
702 sm
->at_resp
= free_str_list(sm
->at_resp
);
703 if(sm
->buf_len
== 0 || raw
) continue;
705 while((s
= strsep(&s0
, "\r\n"))) {
706 if(*s
) add_str_list(&sm
->at_resp
, s
);
711 if(!(hd_data
->debug
& HD_DEB_MODEM
) || !log_it
) return;
713 for(sm
= hd_data
->ser_modem
; sm
; sm
= sm
->next
) {
715 ADD2LOG("%s@%u: %s\n", sm
->dev_name
, sm
->cur_baud
, at
);
718 hexdump(&hd_data
->log
, 1, sm
->buf_len
, sm
->buf
);
722 for(sl
= sm
->at_resp
; sl
; sl
= sl
->next
) ADD2LOG(" %s\n", sl
->str
);
729 void write_modem(hd_data_t
*hd_data
, char *msg
)
732 int i
, len
= strlen(msg
);
734 for(sm
= hd_data
->ser_modem
; sm
; sm
= sm
->next
) {
736 i
= write(sm
->fd
, msg
, len
);
738 ADD2LOG("%s write oops: %d/%d (\"%s\")\n", sm
->dev_name
, i
, len
, msg
);
744 void read_modem(hd_data_t
*hd_data
)
746 int i
, sel
, fd_max
= -1;
753 for(i
= 0, sm
= hd_data
->ser_modem
; sm
; sm
= sm
->next
) {
755 FD_SET(sm
->fd
, &set0
);
756 if(sm
->fd
> fd_max
) fd_max
= sm
->fd
;
761 if(!i
) return; /* nothing selected */
764 to
.tv_sec
= 0; to
.tv_usec
= 1000000;
766 if((sel
= select(fd_max
+ 1, &set
, NULL
, NULL
, &to
)) > 0) {
767 // fprintf(stderr, "sel: %d\n", sel);
768 for(sm
= hd_data
->ser_modem
; sm
; sm
= sm
->next
) {
769 if(FD_ISSET(sm
->fd
, &set
)) {
770 if((i
= read(sm
->fd
, sm
->buf
+ sm
->buf_len
, sizeof sm
->buf
- sm
->buf_len
)) > 0)
772 // fprintf(stderr, "%s: got %d\n", sm->dev_name, i);
773 if(i
<= 0) FD_CLR(sm
->fd
, &set0
);
782 /* make the strings \000 terminated */
783 for(sm
= hd_data
->ser_modem
; sm
; sm
= sm
->next
) {
784 if(sm
->buf_len
== sizeof sm
->buf
) sm
->buf_len
--;
785 sm
->buf
[sm
->buf_len
] = 0;
789 int set_modem_speed(ser_device_t
*sm
, unsigned baud
)
795 for(i
= 0; (unsigned) i
< MAX_SPEED
; i
++) if(speeds
[i
].baud
== baud
) break;
797 if(i
== MAX_SPEED
) return 1;
799 if(tcgetattr(sm
->fd
, &tio
)) return errno
;
801 cfsetospeed(&tio
, speeds
[i
].mask
);
802 cfsetispeed(&tio
, speeds
[i
].mask
);
804 if(tcsetattr(sm
->fd
, TCSAFLUSH
, &tio
)) return errno
;
806 /* tcsetattr() returns ok even if it couldn't set the speed... */
808 if(tcgetattr(sm
->fd
, &tio
)) return errno
;
810 st
= cfgetospeed(&tio
);
812 for(i
= 0; (unsigned) i
< MAX_SPEED
; i
++) if(speeds
[i
].mask
== st
) break;
814 if(i
== MAX_SPEED
) return 2;
816 sm
->cur_baud
= speeds
[i
].baud
;
818 return baud
== speeds
[i
].baud
? 0 : 3;
822 int init_modem(ser_device_t
*sm
)
826 if(tcgetattr(sm
->fd
, &tio
)) return errno
;
830 tio
.c_iflag
= IGNBRK
| IGNPAR
;
837 tio
.c_cflag
= CREAD
| CLOCAL
| HUPCL
| B1200
| CS8
;
839 if(tcsetattr(sm
->fd
, TCSAFLUSH
, &tio
)) return errno
;
846 * Check for a PnP info field starting at ofs;
847 * returns either the length of the field or 0 if none was found.
849 * the minfo_t struct is updated with the PnP data
851 int is_pnpinfo(ser_device_t
*mi
, int ofs
)
854 unsigned char c
, *s
= mi
->buf
+ ofs
, *t
;
855 int len
= mi
->buf_len
- ofs
;
856 unsigned serial
, class_name
, dev_id
, user_name
;
858 if(len
<= 0) return 0;
869 if(len
< 11) return 0;
874 if((s
[i
] & ~0x3f) || (s
[i
+ 1] & ~0x3f)) return 0;
875 mi
->pnp_rev
= (s
[i
] << 6) + s
[i
+ 1];
877 /* pnp_rev may *optionally* be given as a string!!! (e.g. "1.0")*/
882 if(s
[i
+ 3] < 'A') j
++;
885 if(s
[i
] < '0' || s
[i
] > '9') return 0;
886 if(s
[i
+ 1] != '.') return 0;
887 for(k
= 0; k
< j
; k
++)
888 if(s
[i
+ 2 + k
] < '0' || s
[i
+ 2 + k
] > '9') return 0;
889 mi
->pnp_rev
= (s
[i
] - '0') * 100;
890 mi
->pnp_rev
+= s
[i
+ 2] * 10;
891 if(j
== 2) mi
->pnp_rev
+= s
[i
+ 3];
899 for(j
= 0; j
< 7; j
++) {
900 mi
->pnp_id
[j
] = s
[i
+ j
];
901 if(mi
->bits
== 6) mi
->pnp_id
[j
] += 0x20;
907 /* now check the id */
908 for(j
= 0; j
< 3; j
++) {
910 /* numbers are not really allowed, but... */
911 (mi
->pnp_id
[j
] < '0' || mi
->pnp_id
[j
] > '9') &&
912 (mi
->pnp_id
[j
] < 'A' || mi
->pnp_id
[j
] > 'Z') &&
917 for(j
= 3; j
< 7; j
++) {
919 (mi
->pnp_id
[j
] < '0' || mi
->pnp_id
[j
] > '9') &&
920 (mi
->pnp_id
[j
] < 'A' || mi
->pnp_id
[j
] > 'F')
925 if((mi
->bits
== 6 && s
[i
] == 0x09) || (mi
->bits
== 7 && s
[i
] == 0x29)) {
929 if((mi
->bits
!= 6 || s
[i
] != 0x3c) && (mi
->bits
!= 7 || s
[i
] != 0x5c)) {
933 /* parse extended info */
934 serial
= class_name
= dev_id
= user_name
= 0;
935 for(j
= 0; i
< len
; i
++) {
936 if((mi
->bits
== 6 && s
[i
] == 0x09) || (mi
->bits
== 7 && s
[i
] == 0x29)) {
938 if(serial
) for(k
= serial
; k
< len
; k
++) {
940 if(mi
->bits
== 6) c
+= 0x20;
942 str_printf(&mi
->serial
, -1, "%c", c
);
945 if(class_name
) for(k
= class_name
; k
< len
; k
++) {
947 if(mi
->bits
== 6) c
+= 0x20;
949 str_printf(&mi
->class_name
, -1, "%c", c
);
952 if(dev_id
) for(k
= dev_id
; k
< len
; k
++) {
954 if(mi
->bits
== 6) c
+= 0x20;
956 str_printf(&mi
->dev_id
, -1, "%c", c
);
960 for(k
= user_name
; k
< len
; k
++) {
962 if(mi
->bits
== 6) c
+= 0x20;
963 if(c
== '\\' || c
== ')') break;
964 str_printf(&mi
->user_name
, -1, "%c", c
);
966 if(mi
->user_name
&& (l
= strlen(mi
->user_name
)) >= 2) {
967 /* skip *optional*(!!!) 2 char checksum */
968 t
= mi
->user_name
+ l
- 2;
970 ((t
[0] >= '0' && t
[0] <= '9') || (t
[0] >= 'A' && t
[0] <= 'F')) &&
971 ((t
[1] >= '0' && t
[1] <= '9') || (t
[1] >= 'A' && t
[1] <= 'F'))
973 /* OK, *might* be a hex number... */
974 mi
->user_name
[l
- 2] = 0;
977 * A better check would be to look for the complete name string
978 * in the output from another AT command, e.g AT3, AT6 or AT11.
979 * If it's there -> no checksum field.
988 if(((mi
->bits
== 6 && s
[i
] == 0x3c) || (mi
->bits
== 7 && s
[i
] == 0x5c)) && i
< len
- 1) {
991 serial
= i
+ 1; j
++; break;
993 class_name
= i
+ 1; j
++; break;
995 dev_id
= i
+ 1; j
++; break;
997 user_name
= i
+ 1; j
++; break;
999 fprintf(stderr
, "PnP-ID oops\n");
1004 /* no end token... */
1010 unsigned chk4id(ser_device_t
*mi
)
1014 if(!mi
->buf_len
) return 0;
1016 for(i
= 0; i
< mi
->buf_len
; i
++) {
1017 if((mi
->pnp
= is_pnpinfo(mi
, i
))) break;
1019 if(i
== mi
->buf_len
) return 0;
1026 ser_device_t
*add_ser_modem_entry(ser_device_t
**sm
, ser_device_t
*new_sm
)
1028 while(*sm
) sm
= &(*sm
)->next
;
1029 return *sm
= new_sm
;
1032 void dump_ser_modem_data(hd_data_t
*hd_data
)
1037 if(!(sm
= hd_data
->ser_modem
)) return;
1039 ADD2LOG("----- serial modems -----\n");
1041 for(; sm
; sm
= sm
->next
) {
1042 ADD2LOG("%s\n", sm
->dev_name
);
1043 if(sm
->serial
) ADD2LOG("serial: \"%s\"\n", sm
->serial
);
1044 if(sm
->class_name
) ADD2LOG("class_name: \"%s\"\n", sm
->class_name
);
1045 if(sm
->dev_id
) ADD2LOG("dev_id: \"%s\"\n", sm
->dev_id
);
1046 if(sm
->user_name
) ADD2LOG("user_name: \"%s\"\n", sm
->user_name
);
1049 ADD2LOG(" pre_garbage[%u]: ", sm
->garbage
);
1050 hexdump(&hd_data
->log
, 1, sm
->garbage
, sm
->buf
);
1055 ADD2LOG(" pnp[%u]: ", sm
->pnp
);
1056 hexdump(&hd_data
->log
, 1, sm
->pnp
, sm
->buf
+ sm
->garbage
);
1060 if((j
= sm
->buf_len
- (sm
->garbage
+ sm
->pnp
))) {
1061 ADD2LOG(" post_garbage[%u]: ", j
);
1062 hexdump(&hd_data
->log
, 1, j
, sm
->buf
+ sm
->garbage
+ sm
->pnp
);
1067 ADD2LOG(" is modem\n");
1069 ADD2LOG(" not a modem\n");
1072 ADD2LOG(" bits: %u\n", sm
->bits
);
1073 ADD2LOG(" PnP Rev: %u.%02u\n", sm
->pnp_rev
/ 100, sm
->pnp_rev
% 100);
1074 ADD2LOG(" PnP ID: \"%s\"\n", sm
->pnp_id
);
1077 if(sm
->next
) ADD2LOG("\n");
1080 ADD2LOG("----- serial modems end -----\n");
1083 #endif /* ifndef LIBHD_TINY */