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