Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | /* $Id: parport_probe.c,v 1.1 1999/07/03 08:56:17 davem Exp $ * Parallel port device probing code * * Authors: Carsten Gross, carsten@sol.wohnheim.uni-ulm.de * Philip Blundell <Philip.Blundell@pobox.com> */ #include <linux/parport.h> #include <linux/ctype.h> #include <asm/uaccess.h> 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" }, { "SCSIADAPTER", "SCSI adapter" }, { NULL, NULL } }; static void pretty_print(struct parport *port, int device) { struct parport_device_info *info = &port->probe_info[device + 1]; printk(KERN_INFO "%s", port->name); if (device >= 0) printk (" (addr %d)", device); printk (": %s", classes[info->class].descr); if (info->class) printk(", %s %s", info->mfr, info->model); printk("\n"); } 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, int device, char *str) { char *txt = kmalloc(strlen(str)+1, GFP_KERNEL); char *p = txt, *q; int guessed_class = PARPORT_CLASS_UNSPEC; struct parport_device_info *info = &port->probe_info[device + 1]; if (!txt) { printk(KERN_WARNING "%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; *(sep++) = 0; /* Get rid of trailing blanks */ u = sep + strlen (sep) - 1; while (u >= p && *u == ' ') *u-- = '\0'; u = p; while (*u) { *u = toupper(*u); u++; } if (!strcmp(p, "MFG") || !strcmp(p, "MANUFACTURER")) { if (info->mfr) kfree (info->mfr); info->mfr = strdup(sep); } else if (!strcmp(p, "MDL") || !strcmp(p, "MODEL")) { if (info->model) kfree (info->model); info->model = strdup(sep); } else if (!strcmp(p, "CLS") || !strcmp(p, "CLASS")) { int i; if (info->class_name) kfree (info->class_name); info->class_name = strdup(sep); for (u = sep; *u; u++) *u = toupper(*u); for (i = 0; classes[i].token; i++) { if (!strcmp(classes[i].token, sep)) { info->class = i; goto rock_on; } } printk(KERN_WARNING "%s probe: warning, class '%s' not understood.\n", port->name, sep); info->class = PARPORT_CLASS_OTHER; } else if (!strcmp(p, "CMD") || !strcmp(p, "COMMAND SET")) { if (info->cmdset) kfree (info->cmdset); info->cmdset = strdup(sep); /* 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")) { if (info->description) kfree (info->description); 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 (info->class == PARPORT_CLASS_UNSPEC) info->class = guessed_class; pretty_print (port, device); kfree(txt); } /* Get Std 1284 Device ID. */ ssize_t parport_device_id (int devnum, char *buffer, size_t len) { ssize_t retval = -ENXIO; struct pardevice *dev = parport_open (devnum, "Device ID probe", NULL, NULL, NULL, 0, NULL); if (!dev) return -ENXIO; parport_claim_or_block (dev); /* Negotiate to compatibility mode, and then to device ID mode. * (This is in case we are already in device ID mode.) */ parport_negotiate (dev->port, IEEE1284_MODE_COMPAT); retval = parport_negotiate (dev->port, IEEE1284_MODE_NIBBLE | IEEE1284_DEVICEID); if (!retval) { int idlen; unsigned char length[2]; /* First two bytes are MSB,LSB of inclusive length. */ retval = parport_read (dev->port, length, 2); if (retval != 2) goto end_id; idlen = (length[0] << 8) + length[1] - 2; if (idlen < len) len = idlen; retval = parport_read (dev->port, buffer, len); if (retval != len) printk (KERN_DEBUG "%s: only read %Zd of %Zd ID bytes\n", dev->port->name, retval, len); /* Some printer manufacturers mistakenly believe that the length field is supposed to be _exclusive_. In addition, there are broken devices out there that don't even finish off with a semi-colon. */ if (buffer[len - 1] != ';') { ssize_t diff; diff = parport_read (dev->port, buffer + len, 2); retval += diff; if (diff) printk (KERN_DEBUG "%s: device reported incorrect " "length field (%d, should be %Zd)\n", dev->port->name, idlen, retval); else { /* One semi-colon short of a device ID. */ buffer[len++] = ';'; printk (KERN_DEBUG "%s: faking semi-colon\n", dev->port->name); /* If we get here, I don't think we need to worry about the possible standard violation of having read more than we were told to. The device is non-compliant anyhow. */ } } end_id: buffer[len] = '\0'; parport_negotiate (dev->port, IEEE1284_MODE_COMPAT); } parport_release (dev); if (retval > 2) parse_data (dev->port, dev->daisy, buffer); parport_close (dev); return retval; } |