/* $Id: parport_probe.c,v 1.1.2.9 1997/03/29 21:08:16 phil Exp $ * Parallel port device probing code * * Authors: Carsten Gross, carsten@sol.wohnheim.uni-ulm.de * Philip Blundell */ #include #include #include #include #include #include #include #include #include #include #include #include #include #undef DEBUG_PROBE static inline int read_nibble(struct parport *port) { unsigned char i; i = parport_r_status(port)>>3; i&=~8; if ( ( i & 0x10) == 0) i|=8; return(i & 0x0f); } static void read_terminate(struct parport *port) { parport_w_ctrl(port, (parport_r_ctrl(port) & ~2) | 8); /* SelectIN high, AutoFeed low */ if (parport_wait_peripheral(port, 0x80, 0)) /* timeout, SelectIN high, Autofeed low */ return; parport_w_ctrl(port, parport_r_ctrl(port) | 2); /* AutoFeed high */ parport_wait_peripheral(port, 0x80, 0x80); /* no timeout possible, Autofeed low, SelectIN high */ parport_w_ctrl(port, (parport_r_ctrl(port) & ~2) | 8); return; } static long read_polled(struct parport *port, char *buf, unsigned long length) { int i; char *temp=buf; int count = 0; unsigned char z=0; unsigned char Byte=0; for (i=0; ; i++) { parport_w_ctrl(port, parport_r_ctrl(port) | 2); /* AutoFeed high */ if (parport_wait_peripheral(port, 0x40, 0)) { printk("%s: read1 timeout.\n", port->name); parport_w_ctrl(port, parport_r_ctrl(port) & ~2); break; } z = read_nibble(port); parport_w_ctrl(port, parport_r_ctrl(port) & ~2); /* AutoFeed low */ if (parport_wait_peripheral(port, 0x40, 0x40)) { printk("%s: read2 timeout.\n", port->name); break; } if (( i & 1) != 0) { Byte= (Byte | z<<4); if (temp) *(temp++) = Byte; if (count++ == length) temp = NULL; /* Does the error line indicate end of data? */ if ((parport_r_status(port) & LP_PERRORP) == LP_PERRORP) break; } else Byte=z; } read_terminate(port); return count; } static struct wait_queue *wait_q = NULL; static int wakeup(void *ref) { struct ppd **dev = (struct ppd **)ref; if (!wait_q || parport_claim(*dev)) return 1; wake_up(&wait_q); return 0; } int parport_probe(struct parport *port, char *buffer, int len) { struct ppd *dev = parport_register_device(port, "IEEE 1284 probe", NULL, wakeup, NULL, PARPORT_DEV_TRAN, &dev); int result = 0; if (!dev) { printk("%s: unable to register for probe.\n", port->name); return -EINVAL; } if (parport_claim(dev)) { sleep_on(&wait_q); wait_q = NULL; } switch (parport_ieee1284_nibble_mode_ok(port, 4)) { case 1: current->state=TASK_INTERRUPTIBLE; current->timeout=jiffies+1; schedule(); /* HACK: wait 10ms because printer seems to * ack wrong */ result = read_polled(port, buffer, len); break; case 0: result = -EIO; break; } parport_release(dev); parport_unregister_device(dev); return result; } static struct { char *token; char *descr; } classes[] = { { "", "Legacy device" }, { "PRINTER", "Printer" }, { "MODEM", "Modem" }, { "NET", "Network device" }, { "HDC", "Hard disk" }, { "PCMCIA", "PCMCIA" }, { "MEDIA", "Multimedia device" }, { "FDC", "Floppy disk" }, { "PORTS", "Ports" }, { "SCANNER", "Scanner" }, { "DIGICAM", "Digital camera" }, { "", "Unknown device" }, { "", "Unspecified" }, { NULL, NULL } }; static char *strdup(char *str) { int n = strlen(str)+1; char *s = kmalloc(n, GFP_KERNEL); if (!s) return NULL; return strcpy(s, str); } static void parse_data(struct parport *port, char *str) { char *txt = kmalloc(strlen(str)+1, GFP_KERNEL); char *p = txt, *q; int guessed_class = PARPORT_CLASS_UNSPEC; if (!txt) { printk("%s probe: memory squeeze\n", port->name); return; } strcpy(txt, str); while (p) { char *sep; q = strchr(p, ';'); if (q) *q = 0; sep = strchr(p, ':'); if (sep) { char *u = p; *(sep++) = 0; while (*u) { *u = toupper(*u); u++; } if (!strcmp(p, "MFG") || !strcmp(p, "MANUFACTURER")) { port->probe_info.mfr = strdup(sep); } else if (!strcmp(p, "MDL") || !strcmp(p, "MODEL")) { port->probe_info.model = strdup(sep); } else if (!strcmp(p, "CLS") || !strcmp(p, "CLASS")) { int i; for (u = sep; *u; u++) *u = toupper(*u); for (i = 0; classes[i].token; i++) { if (!strcmp(classes[i].token, sep)) { port->probe_info.class = i; goto rock_on; } } printk(KERN_WARNING "%s probe: warning, class '%s' not understood.\n", port->name, sep); port->probe_info.class = PARPORT_CLASS_OTHER; } else if (!strcmp(p, "CMD") || !strcmp(p, "COMMAND SET")) { /* if it speaks printer language, it's probably a printer */ if (strstr(sep, "PJL") || strstr(sep, "PCL")) guessed_class = PARPORT_CLASS_PRINTER; } else if (!strcmp(p, "DES") || !strcmp(p, "DESCRIPTION")) { port->probe_info.description = strdup(sep); } } rock_on: if (q) p = q+1; else p=NULL; } /* If the device didn't tell us its class, maybe we have managed to guess one from the things it did say. */ if (port->probe_info.class == PARPORT_CLASS_UNSPEC) port->probe_info.class = guessed_class; kfree(txt); } static void pretty_print(struct parport *port) { printk(KERN_INFO "%s: %s", port->name, classes[port->probe_info.class].descr); if (port->probe_info.class) { printk(", %s (%s)", port->probe_info.model, port->probe_info.mfr); } printk("\n"); } void parport_probe_one(struct parport *port) { char *buffer = kmalloc(2048, GFP_KERNEL); int r; port->probe_info.model = "Unknown device"; port->probe_info.mfr = "Unknown vendor"; port->probe_info.description = NULL; port->probe_info.class = PARPORT_CLASS_UNSPEC; if (!buffer) { printk(KERN_ERR "%s probe: Memory squeeze.\n", port->name); return; } r = parport_probe(port, buffer, 2047); if (r < 0) { printk(KERN_INFO "%s: no IEEE-1284 device present.\n", port->name); port->probe_info.class = PARPORT_CLASS_LEGACY; } else if (r == 0) { printk(KERN_INFO "%s: no ID data returned by device.\n", port->name); } else { buffer[r] = 0; #ifdef DEBUG_PROBE printk("%s id: %s\n", port->name, buffer+2); #endif parse_data(port, buffer+2); pretty_print(port); } kfree(buffer); }