11
#include <sys/ioctl.h>
19
* @defgroup MODEMint Modem devices
20
* @ingroup libhdDEVint
21
* @brief Modem detection functions
23
* Note: what about modem speed?
30
static struct speeds_s {
43
#if !defined(__sparc__)
47
,{ 1000000, B1000000 }
48
,{ 2000000, B2000000 }
49
,{ 4000000, B4000000 }
53
#define MAX_SPEED (sizeof speeds / sizeof *speeds)
55
static char *init_strings[] = {
63
#define MAX_INIT_STRING (sizeof init_strings / sizeof *init_strings)
65
static void get_serial_modem(hd_data_t* hd_data);
66
static void add_serial_modem(hd_data_t* hd_data);
67
static int dev_name_duplicate(hd_data_t *hd_data, char *dev_name);
68
static void guess_modem_name(hd_data_t *hd_data, ser_device_t *sm);
69
static void at_cmd(hd_data_t *hd_data, char *at, int raw, int log_it);
70
static void write_modem(hd_data_t *hd_data, char *msg);
71
static void read_modem(hd_data_t *hd_data);
72
static ser_device_t *add_ser_modem_entry(ser_device_t **sm, ser_device_t *new_sm);
73
static int set_modem_speed(ser_device_t *sm, unsigned baud);
74
static int init_modem(ser_device_t *mi);
75
static unsigned chk4id(ser_device_t *mi);
76
static void dump_ser_modem_data(hd_data_t *hd_data);
78
void hd_scan_modem(hd_data_t *hd_data)
80
ser_device_t *sm, *sm_next;
82
if(!hd_probe_feature(hd_data, pr_modem)) return;
84
hd_data->module = mod_modem;
87
remove_hd_entries(hd_data);
88
hd_data->ser_modem = NULL;
90
PROGRESS(1, 0, "serial");
92
hd_fork(hd_data, 15, 120);
94
if(hd_data->flags.forked) {
95
get_serial_modem(hd_data);
96
hd_move_to_shm(hd_data);
97
if((hd_data->debug & HD_DEB_MODEM)) dump_ser_modem_data(hd_data);
100
/* take data from shm */
101
hd_data->ser_modem = ((hd_data_t *) (hd_data->shm.data))->ser_modem;
102
if((hd_data->debug & HD_DEB_MODEM)) dump_ser_modem_data(hd_data);
105
hd_fork_done(hd_data);
107
add_serial_modem(hd_data);
109
hd_shm_clean(hd_data);
111
for(sm = hd_data->ser_modem; sm; sm = sm_next) {
114
free_str_list(sm->at_resp);
116
free_mem(sm->dev_name);
117
free_mem(sm->serial);
118
free_mem(sm->class_name);
119
free_mem(sm->dev_id);
120
free_mem(sm->user_name);
122
free_mem(sm->init_string1);
123
free_mem(sm->init_string2);
127
hd_data->ser_modem = NULL;
131
int check_for_responce(str_list_t *str_list, char *str, int len)
133
for(; str_list != NULL; str_list = str_list->next) {
134
if(!strncmp(str_list->str, str, len)) return 1;
140
str_list_t *str_list_dup(str_list_t *orig)
142
str_list_t *dup = NULL;
144
for(; orig != NULL; orig = orig->next) {
145
add_str_list(&dup, orig->str);
151
void get_serial_modem(hd_data_t *hd_data)
155
unsigned modem_info, baud;
158
int chk_usb = hd_probe_feature(hd_data, pr_modem_usb);
160
/* serial modems & usb modems */
161
for(hd = hd_data->hd; hd; hd = hd->next) {
165
hd->base_class.id == bc_comm &&
166
hd->sub_class.id == sc_com_ser &&
168
hd->tag.ser_device != 2 && /* cf. serial.c */
169
!has_something_attached(hd_data, hd)
173
hd->bus.id == bus_usb &&
174
hd->base_class.id == bc_modem
176
) && hd->unix_dev_name
178
if(dev_name_duplicate(hd_data, hd->unix_dev_name)) continue;
179
if((fd = open(hd->unix_dev_name, O_RDWR | O_NONBLOCK)) >= 0) {
180
sm = add_ser_modem_entry(&hd_data->ser_modem, new_mem(sizeof *sm));
181
sm->dev_name = new_str(hd->unix_dev_name);
183
sm->hd_idx = hd->idx;
190
if(!hd_data->ser_modem) return;
192
PROGRESS(2, 0, "init");
194
usleep(300000); /* PnP protocol; 200ms seems to be too fast */
196
for(sm = hd_data->ser_modem; sm; sm = sm->next) {
197
modem_info = TIOCM_DTR | TIOCM_RTS;
198
ioctl(sm->fd, TIOCMBIS, &modem_info);
199
ioctl(sm->fd, TIOCMGET, &modem_info);
200
if(!(modem_info & (TIOCM_DSR | TIOCM_CD))) {
205
/* just a quick test if we get a response to an AT command */
207
for(i = 0; i < 4; i++) {
208
PROGRESS(3, i + 1, "at test");
210
for(sm = hd_data->ser_modem; sm; sm = sm->next) {
212
set_modem_speed(sm, i == 0 ? 115200 : i == 1 ? 38400 : i == 2 ? 9600 : 1200);
215
at_cmd(hd_data, "AT\r", 1, 1);
217
for(sm = hd_data->ser_modem; sm; sm = sm->next) {
218
if(strstr(sm->buf, "OK") || strstr(sm->buf, "0")) {
222
sm->buf_len = 0; /* clear buffer */
226
for(sm = hd_data->ser_modem; sm; sm = sm->next) {
227
if((sm->do_io = sm->is_modem)) {
228
sm->max_baud = sm->cur_baud;
232
/* check for init string */
233
PROGRESS(4, 0, "init string");
236
for(i = 0; (unsigned) i < MAX_INIT_STRING; i++) {
237
str_printf(&command, 0, "AT %s\r", init_strings[i]);
238
at_cmd(hd_data, command, 1, 1);
240
for(sm = hd_data->ser_modem; sm; sm = sm->next) {
241
if(strstr(sm->buf, "OK") || strstr(sm->buf, "0")) {
242
str_printf(&sm->init_string2, -1,
243
"%s %s", sm->init_string2 ? "" : "AT", init_strings[i]
248
command = free_mem(command);
250
for(sm = hd_data->ser_modem; sm; sm = sm->next)
252
str_printf(&sm->init_string1, -1, "ATZ");
255
int cmds[] = { 1, 3, 4, 5, 6 };
257
int i, j, ModemsCount = 0;
258
str_list_t **responces = NULL;
259
for(sm = hd_data->ser_modem; sm; sm = sm->next)
262
responces = new_mem(ModemsCount * sizeof *responces);
264
at_cmd(hd_data, "ATI\r", 0, 1);
265
for(j = 0, sm = hd_data->ser_modem; sm; sm = sm->next) {
267
responces[j++] = str_list_dup(sm->at_resp);
270
for(i = 0; (unsigned) i < sizeof cmds / sizeof *cmds; i++) {
272
sprintf(at, "ATI%d\r", atx);
273
at_cmd(hd_data, at, 0, 1);
274
for(j = 0, sm = hd_data->ser_modem; sm; sm = sm->next) {
276
if(atx == 1 && check_for_responce(responces[j], "Hagenuk", 7) &&
277
(check_for_responce(sm->at_resp, "Speed Dragon", 12) ||
278
check_for_responce(sm->at_resp, "Power Dragon", 12))) {
279
free_mem(sm->init_string1);
280
free_mem(sm->init_string2);
281
sm->init_string1 = new_str("AT&F");
282
sm->init_string2 = new_str("ATB8");
284
if(atx == 3 && check_for_responce(responces[j], "346900", 6) &&
285
check_for_responce(sm->at_resp, "3Com U.S. Robotics ISDN", 23)) {
286
free_mem(sm->init_string1);
287
free_mem(sm->init_string2);
288
sm->init_string1 = new_str("AT&F");
289
sm->init_string2 = new_str("AT*PPP=1");
291
if(atx == 4 && check_for_responce(responces[j], "SP ISDN", 7) &&
292
check_for_responce(sm->at_resp, "Sportster ISDN TA", 17)) {
293
free_mem(sm->init_string1);
294
free_mem(sm->init_string2);
295
sm->init_string1 = new_str("AT&F");
296
sm->init_string2 = new_str("ATB3");
298
if(atx == 6 && check_for_responce(responces[j], "644", 3) &&
299
check_for_responce(sm->at_resp, "ELSA MicroLink ISDN", 19)) {
300
free_mem(sm->init_string1);
301
free_mem(sm->init_string2);
302
sm->init_string1 = new_str("AT&F");
303
sm->init_string2 = new_str("AT$IBP=HDLCP");
304
free_mem(sm->pppd_option);
305
sm->pppd_option = new_str("default-asyncmap");
307
if(atx == 6 && check_for_responce(responces[j], "643", 3) &&
308
check_for_responce(sm->at_resp, "MicroLink ISDN/TLV.34", 21)) {
309
free_mem(sm->init_string1);
310
free_mem(sm->init_string2);
311
sm->init_string1 = new_str("AT&F");
312
sm->init_string2 = new_str("AT\\N10%P1");
314
if(atx == 5 && check_for_responce(responces[j], "ISDN TA", 6) &&
315
check_for_responce(sm->at_resp, "ISDN TA;ASU", 4)) {
317
sm->vend = new_str("ASUS");
318
free_mem(sm->user_name);
319
sm->user_name = new_str("ISDNLink TA");
320
free_mem(sm->init_string1);
321
free_mem(sm->init_string2);
322
sm->init_string1 = new_str("AT&F");
323
sm->init_string2 = new_str("ATB40");
325
if(atx==3 && check_for_responce(responces[j], "128000", 6) &&
326
check_for_responce(sm->at_resp, "Lasat Speed", 11)) {
327
free_mem(sm->init_string1);
328
free_mem(sm->init_string2);
329
sm->init_string1 = new_str("AT&F");
330
sm->init_string2 = new_str("AT\\P1&B2X3");
333
(check_for_responce(responces[j], "28642", 5) ||
334
check_for_responce(responces[j], "1281", 4) ||
335
check_for_responce(responces[j], "1282", 4) ||
336
check_for_responce(responces[j], "1283", 4) ||
337
check_for_responce(responces[j], "1291", 4) ||
338
check_for_responce(responces[j], "1292", 4) ||
339
check_for_responce(responces[j], "1293", 4)) &&
340
(check_for_responce(sm->at_resp, "Elite 2864I", 11) ||
341
check_for_responce(sm->at_resp, "ZyXEL omni", 10))) {
342
free_mem(sm->init_string1);
343
free_mem(sm->init_string2);
344
sm->init_string1 = new_str("AT&F");
345
sm->init_string2 = new_str("AT&O2B40");
352
for(i = 0; i < ModemsCount; i++) free_str_list(responces[i]);
356
/* now, go for the maximum speed... */
357
PROGRESS(5, 0, "speed");
359
for(i = MAX_SPEED - 1; i >= 0; i--) {
360
baud = speeds[i].baud;
361
for(j = 0, sm = hd_data->ser_modem; sm; sm = sm->next) {
363
if(baud > sm->max_baud) {
364
sm->do_io = set_modem_speed(sm, baud) ? 0 : 1;
373
at_cmd(hd_data, "AT\r", 1, 0);
375
for(sm = hd_data->ser_modem; sm; sm = sm->next) {
376
if(strstr(sm->buf, "OK") || strstr(sm->buf, "0")) {
377
sm->max_baud = sm->cur_baud;
382
sm->buf_len = 0; /* clear buffer */
386
/* now, fix it all up... */
387
for(sm = hd_data->ser_modem; sm; sm = sm->next) {
389
set_modem_speed(sm, sm->max_baud);
395
/* just for testing */
396
if((hd_data->debug & HD_DEB_MODEM)) {
398
int cmds[] = { 0, 1, 2, 3, 6 };
401
PROGRESS(8, 0, "testing");
403
at_cmd(hd_data, "ATI\r", 0, 1);
404
for(i = 0; (unsigned) i < sizeof cmds / sizeof *cmds; i++) {
405
sprintf(at, "ATI%d\r", cmds[i]);
406
at_cmd(hd_data, at, 0, 1);
408
at_cmd(hd_data, "AT\r", 0, 1);
412
PROGRESS(5, 0, "pnp id");
414
at_cmd(hd_data, "ATI9\r", 1, 1);
416
for(sm = hd_data->ser_modem; sm; sm = sm->next) {
420
if(!sm->user_name) guess_modem_name(hd_data, sm);
423
/* reset serial lines */
424
tcflush(sm->fd, TCIOFLUSH);
425
tcsetattr(sm->fd, TCSAFLUSH, &sm->tio);
431
void add_serial_modem(hd_data_t *hd_data)
438
for(sm = hd_data->ser_modem; sm; sm = sm->next) {
439
if(!sm->is_modem) continue;
441
hd = hd_get_device_by_idx(hd_data, sm->hd_idx);
442
if(hd && hd->base_class.id == bc_modem) {
443
/* just *add* info */
447
hd = add_hd_entry(hd_data, __LINE__, 0);
448
hd->base_class.id = bc_modem;
449
hd->bus.id = bus_serial;
450
hd->unix_dev_name = new_str(sm->dev_name);
451
hd->attached_to = sm->hd_idx;
452
res = add_res_entry(&hd->res, new_mem(sizeof *res));
453
res->baud.type = res_baud;
454
res->baud.speed = sm->max_baud;
455
if(sm->pppd_option) {
456
res = add_res_entry(&hd->res, new_mem(sizeof *res));
457
res->pppd_option.type = res_pppd_option;
458
res->pppd_option.option = new_str(sm->pppd_option);
461
strncpy(buf, sm->pnp_id, 3);
463
hd->vendor.id = name2eisa_id(buf);
464
hd->device.id = MAKE_ID(TAG_EISA, strtol(sm->pnp_id + 3, NULL, 16));
466
hd->serial = new_str(sm->serial);
467
if(sm->user_name) hd->device.name = new_str(sm->user_name);
468
if(sm->vend) hd->vendor.name = new_str(sm->vend);
470
if(sm->dev_id && strlen(sm->dev_id) >= 7) {
474
u1 = name2eisa_id(sm->dev_id);
476
strncpy(buf, sm->dev_id + 3, 4);
478
u2 = strtol(sm->dev_id + 3, &s, 16);
480
hd->compat_vendor.id = u1;
481
hd->compat_device.id = MAKE_ID(TAG_EISA, u2);
486
if(!(hd->device.id || hd->device.name || hd->vendor.id || hd->vendor.name)) {
487
hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x2000);
488
hd->device.id = MAKE_ID(TAG_SPECIAL, 0x0001);
491
res = add_res_entry(&hd->res, new_mem(sizeof *res));
492
res->init_strings.type = res_init_strings;
493
res->init_strings.init1 = new_str(sm->init_string1);
494
res->init_strings.init2 = new_str(sm->init_string2);
499
int dev_name_duplicate(hd_data_t *hd_data, char *dev_name)
503
for(sm = hd_data->ser_modem; sm; sm = sm->next) {
504
if(!strcmp(sm->dev_name, dev_name)) return 1;
510
void guess_modem_name(hd_data_t *hd_data, ser_device_t *modem)
520
for(sm = hd_data->ser_modem; sm; sm = sm->next) sm->do_io = 0;
522
(sm = modem)->do_io = 1;
525
at_cmd(hd_data, "ATI0\r", 0, 1);
527
if(sl && !strcmp(sl->str, "ATI0")) sl = sl->next; /* skip AT cmd echo */
531
if(strstr(sl->str, "PowerBook")) {
532
sm->vend = new_str("Apple");
533
sm->user_name = new_str(sl->str);
537
s1 = new_str(sl->str);
540
at_cmd(hd_data, "ATI1\r", 0, 1);
542
if(sl && !strcmp(sl->str, "ATI1")) sl = sl->next; /* skip AT cmd echo */
545
if(strstr(sl->str, "APPLE")) {
546
sm->vend = new_str("Apple");
547
str_printf(&sm->user_name, 0, "AT Modem");
549
u = strtoul(s1, &s2, 10);
550
if(u && !*s2 && !(u % 1000)) {
551
str_printf(&sm->user_name, 0, "%uk AT Modem", u / 1000);
564
at_cmd(hd_data, "ATI3\r", 0, 1);
566
if(sl && !strcmp(sl->str, "ATI3")) sl = sl->next; /* skip AT cmd echo */
569
if(*sl->str == 'U' && strstr(sl->str, "Robotics ")) {
570
/* looks like an U.S. Robotics... */
572
sm->vend = new_str("U.S. Robotics, Inc.");
573
/* strip revision code */
574
if((s = strstr(sl->str, " Rev. "))) *s = 0;
575
sm->user_name = canon_str(sl->str, strlen(sl->str));
580
if(strstr(sl->str, "3Com U.S. Robotics ") == sl->str) {
581
/* looks like an 3Com U.S. Robotics... */
583
sm->vend = new_str("3Com U.S. Robotics, Inc.");
584
sm->user_name = canon_str(sl->str, strlen(sl->str));
589
if(strstr(sl->str, "-V34_DS -d Z201 2836")) {
590
/* looks like a Zoom V34X */
592
sm->vend = new_str("Zoom Telephonics, Inc.");
593
sm->user_name = new_str("Zoom FaxModem V.34X Plus Model 2836");
598
if(strstr(sl->str, "FM560 VER 3.01 V.90")) {
599
/* looks like a Microcom DeskPorte 56K Voice ... */
601
sm->vend = new_str("Microcom");
602
sm->user_name = new_str("TravelCard 56K");
607
if(strstr(sl->str, "Compaq Microcom 550 56K Modem")) {
608
/* looks like a Microcom DeskPorte Pocket ... */
610
sm->vend = new_str("Compaq");
611
sm->user_name = new_str("Microcom 550 56K Modem");
618
at_cmd(hd_data, "ATI0\r", 0, 1);
620
if(sl && !strcmp(sl->str, "ATI0")) sl = sl->next; /* skip AT cmd echo */
623
if(strstr(sl->str, "DP Pocket")) {
624
/* looks like a Microcom DeskPorte Pocket ... */
626
sm->vend = new_str("Microcom");
627
sm->user_name = new_str("DeskPorte Pocket");
634
at_cmd(hd_data, "ATI6\r", 0, 1);
636
if(sl && !strcmp(sl->str, "ATI6")) sl = sl->next; /* skip AT cmd echo */
639
if(strstr(sl->str, "RCV56DPF-PLL L8571A")) {
640
/* looks like a Microcom DeskPorte 56K Voice ... */
642
sm->vend = new_str("Microcom");
643
sm->user_name = new_str("DeskPorte 56K Voice");
650
at_cmd(hd_data, "ATI2\r", 0, 1);
652
if(sl && !strcmp(sl->str, "ATI2")) sl = sl->next; /* skip AT cmd echo */
655
if(strstr(sl->str, "ZyXEL ")) {
656
/* looks like a ZyXEL... */
658
sm->vend = new_str("ZyXEL");
660
at_cmd(hd_data, "ATI1\r", 0, 1);
662
if(sl && !strcmp(sl->str, "ATI1")) sl = sl->next;
666
if((s = strstr(sl->str, " V "))) *s = 0;
667
sm->user_name = canon_str(sl->str, strlen(sl->str));
676
void at_cmd(hd_data_t *hd_data, char *at, int raw, int log_it)
678
static unsigned u = 1;
684
for(sm = hd_data->ser_modem; sm; sm = sm->next) {
691
if(modems == 0) return;
693
PROGRESS(9, u, "write at cmd");
694
write_modem(hd_data, at);
695
PROGRESS(9, u, "read at resp");
698
PROGRESS(9, u, "read ok");
701
for(sm = hd_data->ser_modem; sm; sm = sm->next) {
703
sm->at_resp = free_str_list(sm->at_resp);
704
if(sm->buf_len == 0 || raw) continue;
706
while((s = strsep(&s0, "\r\n"))) {
707
if(*s) add_str_list(&sm->at_resp, s);
712
if(!(hd_data->debug & HD_DEB_MODEM) || !log_it) return;
714
for(sm = hd_data->ser_modem; sm; sm = sm->next) {
716
ADD2LOG("%s@%u: %s\n", sm->dev_name, sm->cur_baud, at);
719
hexdump(&hd_data->log, 1, sm->buf_len, sm->buf);
723
for(sl = sm->at_resp; sl; sl = sl->next) ADD2LOG(" %s\n", sl->str);
730
void write_modem(hd_data_t *hd_data, char *msg)
733
int i, len = strlen(msg);
735
for(sm = hd_data->ser_modem; sm; sm = sm->next) {
737
i = write(sm->fd, msg, len);
739
ADD2LOG("%s write oops: %d/%d (\"%s\")\n", sm->dev_name, i, len, msg);
745
void read_modem(hd_data_t *hd_data)
747
int i, sel, fd_max = -1;
754
for(i = 0, sm = hd_data->ser_modem; sm; sm = sm->next) {
756
FD_SET(sm->fd, &set0);
757
if(sm->fd > fd_max) fd_max = sm->fd;
762
if(!i) return; /* nothing selected */
765
to.tv_sec = 0; to.tv_usec = 1000000;
767
if((sel = select(fd_max + 1, &set, NULL, NULL, &to)) > 0) {
768
// fprintf(stderr, "sel: %d\n", sel);
769
for(sm = hd_data->ser_modem; sm; sm = sm->next) {
770
if(FD_ISSET(sm->fd, &set)) {
771
if((i = read(sm->fd, sm->buf + sm->buf_len, sizeof sm->buf - sm->buf_len)) > 0)
773
// fprintf(stderr, "%s: got %d\n", sm->dev_name, i);
774
if(i <= 0) FD_CLR(sm->fd, &set0);
783
/* make the strings \000 terminated */
784
for(sm = hd_data->ser_modem; sm; sm = sm->next) {
785
if(sm->buf_len == sizeof sm->buf) sm->buf_len--;
786
sm->buf[sm->buf_len] = 0;
790
int set_modem_speed(ser_device_t *sm, unsigned baud)
796
for(i = 0; (unsigned) i < MAX_SPEED; i++) if(speeds[i].baud == baud) break;
798
if(i == MAX_SPEED) return 1;
800
if(tcgetattr(sm->fd, &tio)) return errno;
802
cfsetospeed(&tio, speeds[i].mask);
803
cfsetispeed(&tio, speeds[i].mask);
805
if(tcsetattr(sm->fd, TCSAFLUSH, &tio)) return errno;
807
/* tcsetattr() returns ok even if it couldn't set the speed... */
809
if(tcgetattr(sm->fd, &tio)) return errno;
811
st = cfgetospeed(&tio);
813
for(i = 0; (unsigned) i < MAX_SPEED; i++) if(speeds[i].mask == st) break;
815
if(i == MAX_SPEED) return 2;
817
sm->cur_baud = speeds[i].baud;
819
return baud == speeds[i].baud ? 0 : 3;
823
int init_modem(ser_device_t *sm)
827
if(tcgetattr(sm->fd, &tio)) return errno;
831
tio.c_iflag = IGNBRK | IGNPAR;
838
tio.c_cflag = CREAD | CLOCAL | HUPCL | B1200 | CS8;
840
if(tcsetattr(sm->fd, TCSAFLUSH, &tio)) return errno;
847
* Check for a PnP info field starting at ofs;
848
* returns either the length of the field or 0 if none was found.
850
* the minfo_t struct is updated with the PnP data
852
int is_pnpinfo(ser_device_t *mi, int ofs)
855
unsigned char c, *s = mi->buf + ofs, *t;
856
int len = mi->buf_len - ofs;
857
unsigned serial, class_name, dev_id, user_name;
859
if(len <= 0) return 0;
870
if(len < 11) return 0;
875
if((s[i] & ~0x3f) || (s[i + 1] & ~0x3f)) return 0;
876
mi->pnp_rev = (s[i] << 6) + s[i + 1];
878
/* pnp_rev may *optionally* be given as a string!!! (e.g. "1.0")*/
883
if(s[i + 3] < 'A') j++;
886
if(s[i] < '0' || s[i] > '9') return 0;
887
if(s[i + 1] != '.') return 0;
888
for(k = 0; k < j; k++)
889
if(s[i + 2 + k] < '0' || s[i + 2 + k] > '9') return 0;
890
mi->pnp_rev = (s[i] - '0') * 100;
891
mi->pnp_rev += s[i + 2] * 10;
892
if(j == 2) mi->pnp_rev += s[i + 3];
900
for(j = 0; j < 7; j++) {
901
mi->pnp_id[j] = s[i + j];
902
if(mi->bits == 6) mi->pnp_id[j] += 0x20;
908
/* now check the id */
909
for(j = 0; j < 3; j++) {
911
/* numbers are not really allowed, but... */
912
(mi->pnp_id[j] < '0' || mi->pnp_id[j] > '9') &&
913
(mi->pnp_id[j] < 'A' || mi->pnp_id[j] > 'Z') &&
918
for(j = 3; j < 7; j++) {
920
(mi->pnp_id[j] < '0' || mi->pnp_id[j] > '9') &&
921
(mi->pnp_id[j] < 'A' || mi->pnp_id[j] > 'F')
926
if((mi->bits == 6 && s[i] == 0x09) || (mi->bits == 7 && s[i] == 0x29)) {
930
if((mi->bits != 6 || s[i] != 0x3c) && (mi->bits != 7 || s[i] != 0x5c)) {
934
/* parse extended info */
935
serial = class_name = dev_id = user_name = 0;
936
for(j = 0; i < len; i++) {
937
if((mi->bits == 6 && s[i] == 0x09) || (mi->bits == 7 && s[i] == 0x29)) {
939
if(serial) for(k = serial; k < len; k++) {
941
if(mi->bits == 6) c += 0x20;
943
str_printf(&mi->serial, -1, "%c", c);
946
if(class_name) for(k = class_name; k < len; k++) {
948
if(mi->bits == 6) c += 0x20;
950
str_printf(&mi->class_name, -1, "%c", c);
953
if(dev_id) for(k = dev_id; k < len; k++) {
955
if(mi->bits == 6) c += 0x20;
957
str_printf(&mi->dev_id, -1, "%c", c);
961
for(k = user_name; k < len; k++) {
963
if(mi->bits == 6) c += 0x20;
964
if(c == '\\' || c == ')') break;
965
str_printf(&mi->user_name, -1, "%c", c);
967
if(mi->user_name && (l = strlen(mi->user_name)) >= 2) {
968
/* skip *optional*(!!!) 2 char checksum */
969
t = mi->user_name + l - 2;
971
((t[0] >= '0' && t[0] <= '9') || (t[0] >= 'A' && t[0] <= 'F')) &&
972
((t[1] >= '0' && t[1] <= '9') || (t[1] >= 'A' && t[1] <= 'F'))
974
/* OK, *might* be a hex number... */
975
mi->user_name[l - 2] = 0;
978
* A better check would be to look for the complete name string
979
* in the output from another AT command, e.g AT3, AT6 or AT11.
980
* If it's there -> no checksum field.
989
if(((mi->bits == 6 && s[i] == 0x3c) || (mi->bits == 7 && s[i] == 0x5c)) && i < len - 1) {
992
serial = i + 1; j++; break;
994
class_name = i + 1; j++; break;
996
dev_id = i + 1; j++; break;
998
user_name = i + 1; j++; break;
1000
fprintf(stderr, "PnP-ID oops\n");
1005
/* no end token... */
1011
unsigned chk4id(ser_device_t *mi)
1015
if(!mi->buf_len) return 0;
1017
for(i = 0; i < mi->buf_len; i++) {
1018
if((mi->pnp = is_pnpinfo(mi, i))) break;
1020
if(i == mi->buf_len) return 0;
1027
ser_device_t *add_ser_modem_entry(ser_device_t **sm, ser_device_t *new_sm)
1029
while(*sm) sm = &(*sm)->next;
1030
return *sm = new_sm;
1033
void dump_ser_modem_data(hd_data_t *hd_data)
1038
if(!(sm = hd_data->ser_modem)) return;
1040
ADD2LOG("----- serial modems -----\n");
1042
for(; sm; sm = sm->next) {
1043
ADD2LOG("%s\n", sm->dev_name);
1044
if(sm->serial) ADD2LOG("serial: \"%s\"\n", sm->serial);
1045
if(sm->class_name) ADD2LOG("class_name: \"%s\"\n", sm->class_name);
1046
if(sm->dev_id) ADD2LOG("dev_id: \"%s\"\n", sm->dev_id);
1047
if(sm->user_name) ADD2LOG("user_name: \"%s\"\n", sm->user_name);
1050
ADD2LOG(" pre_garbage[%u]: ", sm->garbage);
1051
hexdump(&hd_data->log, 1, sm->garbage, sm->buf);
1056
ADD2LOG(" pnp[%u]: ", sm->pnp);
1057
hexdump(&hd_data->log, 1, sm->pnp, sm->buf + sm->garbage);
1061
if((j = sm->buf_len - (sm->garbage + sm->pnp))) {
1062
ADD2LOG(" post_garbage[%u]: ", j);
1063
hexdump(&hd_data->log, 1, j, sm->buf + sm->garbage + sm->pnp);
1068
ADD2LOG(" is modem\n");
1070
ADD2LOG(" not a modem\n");
1073
ADD2LOG(" bits: %u\n", sm->bits);
1074
ADD2LOG(" PnP Rev: %u.%02u\n", sm->pnp_rev / 100, sm->pnp_rev % 100);
1075
ADD2LOG(" PnP ID: \"%s\"\n", sm->pnp_id);
1078
if(sm->next) ADD2LOG("\n");
1081
ADD2LOG("----- serial modems end -----\n");
1084
#endif /* ifndef LIBHD_TINY */