]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/ieee1284.c
Remove old files.
[thirdparty/cups.git] / backend / ieee1284.c
CommitLineData
ef416fc2 1/*
2e4ff8af 2 * "$Id: ieee1284.c 7019 2007-10-10 22:48:52Z mike $"
ef416fc2 3 *
4 * IEEE-1284 support functions for the Common UNIX Printing System (CUPS).
5 *
bc44d920 6 * Copyright 2007 by Apple Inc.
f7deaa1a 7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
ef416fc2 8 *
9 * These coded instructions, statements, and computer programs are the
bc44d920 10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
ef416fc2 12 * "LICENSE" which should have been included with this file. If this
bc44d920 13 * file is missing or damaged, see the license at "http://www.cups.org/".
ef416fc2 14 *
15 * This file is subject to the Apple OS-Developed Software exception.
16 *
17 * Contents:
18 *
ed486911 19 * backendGetDeviceID() - Get the IEEE-1284 device ID string and
20 * corresponding URI.
21 * backendGetMakeModel() - Get the make and model string from the device ID.
ef416fc2 22 */
23
24/*
25 * Include necessary headers.
26 */
27
ed486911 28#include "backend-private.h"
ef416fc2 29
ed486911 30#ifdef __linux
31# include <sys/ioctl.h>
32# include <linux/lp.h>
33# define IOCNR_GET_DEVICE_ID 1
34# define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len)
2e4ff8af
MS
35# include <linux/parport.h>
36# include <linux/ppdev.h>
37# include <unistd.h>
38# include <fcntl.h>
ed486911 39#endif /* __linux */
89d46774 40
ed486911 41#ifdef __sun
42# ifdef __sparc
43# include <sys/ecppio.h>
44# else
45# include <sys/ioccom.h>
46# include <sys/ecppsys.h>
47# endif /* __sparc */
48#endif /* __sun */
ef416fc2 49
50
51/*
ed486911 52 * 'backendGetDeviceID()' - Get the IEEE-1284 device ID string and
53 * corresponding URI.
ef416fc2 54 */
55
56int /* O - 0 on success, -1 on failure */
ed486911 57backendGetDeviceID(
ef416fc2 58 int fd, /* I - File descriptor */
59 char *device_id, /* O - 1284 device ID */
60 int device_id_size, /* I - Size of buffer */
61 char *make_model, /* O - Make/model */
62 int make_model_size, /* I - Size of buffer */
63 const char *scheme, /* I - URI scheme */
64 char *uri, /* O - Device URI */
65 int uri_size) /* I - Size of buffer */
66{
db0bd74a
MS
67#ifdef __APPLE__ /* This function is a no-op */
68 return (-1);
69
70#else /* Get the device ID from the specified file descriptor... */
ef416fc2 71 char *attr, /* 1284 attribute */
72 *delim, /* 1284 delimiter */
73 *uriptr, /* Pointer into URI */
89d46774 74 manufacturer[256], /* Manufacturer string */
ef416fc2 75 serial_number[1024]; /* Serial number string */
89d46774 76 int manulen; /* Length of manufacturer string */
db0bd74a 77# ifdef __linux
ef416fc2 78 int length; /* Length of device ID info */
2e4ff8af 79 int got_id = 0;
db0bd74a
MS
80# endif /* __linux */
81# if defined(__sun) && defined(ECPPIOC_GETDEVID)
ef416fc2 82 struct ecpp_device_id did; /* Device ID buffer */
db0bd74a 83# endif /* __sun && ECPPIOC_GETDEVID */
ef416fc2 84
89d46774 85
ed486911 86 DEBUG_printf(("backendGetDeviceID(fd=%d, device_id=%p, device_id_size=%d, "
ef416fc2 87 "make_model=%p, make_model_size=%d, scheme=\"%s\", "
88 "uri=%p, uri_size=%d)\n", fd, device_id, device_id_size,
89 make_model, make_model_size, scheme ? scheme : "(null)",
90 uri, uri_size));
91
92 /*
93 * Range check input...
94 */
95
f7deaa1a 96 if (!device_id || device_id_size < 32)
ef416fc2 97 {
ed486911 98 DEBUG_puts("backendGetDeviceID: Bad args!");
ef416fc2 99 return (-1);
100 }
101
f7deaa1a 102 if (make_model)
103 *make_model = '\0';
ef416fc2 104
f7deaa1a 105 if (fd >= 0)
ef416fc2 106 {
107 /*
f7deaa1a 108 * Get the device ID string...
ef416fc2 109 */
110
f7deaa1a 111 *device_id = '\0';
ef416fc2 112
db0bd74a 113# ifdef __linux
2e4ff8af
MS
114 if (ioctl(fd, LPIOC_GET_DEVICE_ID(device_id_size), device_id))
115 {
116 /*
117 * Linux has to implement things differently for every device it seems.
118 * Since the standard parallel port driver does not provide a simple
119 * ioctl() to get the 1284 device ID, we have to open the "raw" parallel
120 * device corresponding to this port and do some negotiation trickery
121 * to get the current device ID.
122 */
123
124 if (uri && !strncmp(uri, "parallel:/dev/", 14))
125 {
126 char devparport[16]; /* /dev/parportN */
127 int devparportfd, /* File descriptor for raw device */
2e4ff8af
MS
128 mode; /* Port mode */
129
130
131 /*
132 * Since the Linux parallel backend only supports 4 parallel port
133 * devices, just grab the trailing digit and use it to construct a
134 * /dev/parportN filename...
135 */
136
137 snprintf(devparport, sizeof(devparport), "/dev/parport%s",
138 uri + strlen(uri) - 1);
139
140 if ((devparportfd = open(devparport, O_RDWR | O_NOCTTY)) != -1)
141 {
142 /*
143 * Claim the device...
144 */
145
146 if (!ioctl(devparportfd, PPCLAIM))
147 {
0a682745 148 fcntl(devparportfd, F_SETFL, fcntl(devparportfd, F_GETFL) | O_NONBLOCK);
2e4ff8af
MS
149
150 mode = IEEE1284_MODE_COMPAT;
151
152 if (!ioctl(devparportfd, PPNEGOT, &mode))
153 {
154 /*
155 * Put the device into Device ID mode...
156 */
157
158 mode = IEEE1284_MODE_NIBBLE | IEEE1284_DEVICEID;
159
160 if (!ioctl(devparportfd, PPNEGOT, &mode))
161 {
162 /*
163 * Read the 1284 device ID...
164 */
165
166 if ((length = read(devparportfd, device_id,
167 device_id_size - 1)) >= 2)
168 {
169 device_id[length] = '\0';
170 got_id = 1;
171 }
172 }
173 }
174
175 /*
176 * Release the device...
177 */
178
179 ioctl(devparportfd, PPRELEASE);
180 }
181
182 close(devparportfd);
183 }
184 }
185 }
186 else
187 got_id = 1;
188
189 if (got_id)
f7deaa1a 190 {
191 /*
192 * Extract the length of the device ID string from the first two
193 * bytes. The 1284 spec says the length is stored MSB first...
194 */
ef416fc2 195
f7deaa1a 196 length = (((unsigned)device_id[0] & 255) << 8) +
197 ((unsigned)device_id[1] & 255);
ef416fc2 198
f7deaa1a 199 /*
200 * Check to see if the length is larger than our buffer; first
201 * assume that the vendor incorrectly implemented the 1284 spec,
202 * and then limit the length to the size of our buffer...
203 */
ef416fc2 204
f7deaa1a 205 if (length > (device_id_size - 2))
206 length = (((unsigned)device_id[1] & 255) << 8) +
207 ((unsigned)device_id[0] & 255);
ef416fc2 208
f7deaa1a 209 if (length > (device_id_size - 2))
210 length = device_id_size - 2;
211
212 /*
213 * Copy the device ID text to the beginning of the buffer and
214 * nul-terminate.
215 */
216
217 memmove(device_id, device_id + 2, length);
218 device_id[length] = '\0';
219 }
db0bd74a 220# ifdef DEBUG
f7deaa1a 221 else
222 printf("backendGetDeviceID: ioctl failed - %s\n", strerror(errno));
db0bd74a
MS
223# endif /* DEBUG */
224# endif /* __linux */
ef416fc2 225
db0bd74a 226# if defined(__sun) && defined(ECPPIOC_GETDEVID)
f7deaa1a 227 did.mode = ECPP_CENTRONICS;
228 did.len = device_id_size - 1;
229 did.rlen = 0;
230 did.addr = device_id;
ef416fc2 231
f7deaa1a 232 if (!ioctl(fd, ECPPIOC_GETDEVID, &did))
233 {
234 /*
235 * Nul-terminate the device ID text.
236 */
ef416fc2 237
f7deaa1a 238 if (did.rlen < (device_id_size - 1))
239 device_id[did.rlen] = '\0';
240 else
241 device_id[device_id_size - 1] = '\0';
242 }
db0bd74a 243# ifdef DEBUG
f7deaa1a 244 else
245 printf("backendGetDeviceID: ioctl failed - %s\n", strerror(errno));
db0bd74a
MS
246# endif /* DEBUG */
247# endif /* __sun && ECPPIOC_GETDEVID */
f7deaa1a 248 }
ef416fc2 249
ed486911 250 DEBUG_printf(("backendGetDeviceID: device_id=\"%s\"\n", device_id));
ef416fc2 251
2e4ff8af
MS
252 if (scheme && uri)
253 *uri = '\0';
254
ef416fc2 255 if (!*device_id)
256 return (-1);
257
89d46774 258 /*
259 * Get the make and model...
260 */
261
f7deaa1a 262 if (make_model)
263 backendGetMakeModel(device_id, make_model, make_model_size);
89d46774 264
265 /*
266 * Then generate a device URI...
267 */
268
269 if (scheme && uri && uri_size > 32)
270 {
271 /*
272 * Look for the serial number field...
273 */
274
275 if ((attr = strstr(device_id, "SERN:")) != NULL)
276 attr += 5;
277 else if ((attr = strstr(device_id, "SERIALNUMBER:")) != NULL)
278 attr += 13;
279 else if ((attr = strstr(device_id, ";SN:")) != NULL)
280 attr += 4;
281
282 if (attr)
283 {
284 strlcpy(serial_number, attr, sizeof(serial_number));
285
286 if ((delim = strchr(serial_number, ';')) != NULL)
287 *delim = '\0';
288 }
289 else
290 serial_number[0] = '\0';
291
292 /*
293 * Generate the device URI from the manufacturer, make_model, and
294 * serial number strings.
295 */
296
297 snprintf(uri, uri_size, "%s://", scheme);
298
299 if ((attr = strstr(device_id, "MANUFACTURER:")) != NULL)
300 attr += 13;
301 else if ((attr = strstr(device_id, "Manufacturer:")) != NULL)
302 attr += 13;
303 else if ((attr = strstr(device_id, "MFG:")) != NULL)
304 attr += 4;
305
306 if (attr)
307 {
308 strlcpy(manufacturer, attr, sizeof(manufacturer));
309
310 if ((delim = strchr(manufacturer, ';')) != NULL)
311 *delim = '\0';
312
313 if (!strcasecmp(manufacturer, "Hewlett-Packard"))
314 strcpy(manufacturer, "HP");
d09495fa 315 else if (!strcasecmp(manufacturer, "Lexmark International"))
316 strcpy(manufacturer, "Lexmark");
89d46774 317 }
318 else
319 {
320 strlcpy(manufacturer, make_model, sizeof(manufacturer));
321
322 if ((delim = strchr(manufacturer, ' ')) != NULL)
323 *delim = '\0';
324 }
325
326 manulen = strlen(manufacturer);
327
328 for (uriptr = uri + strlen(uri), delim = manufacturer;
329 *delim && uriptr < (uri + uri_size - 3);
330 delim ++)
331 if (*delim == ' ')
332 {
333 *uriptr++ = '%';
334 *uriptr++ = '2';
335 *uriptr++ = '0';
336 }
337 else
338 *uriptr++ = *delim;
339
340 *uriptr++ = '/';
341
342 if (!strncasecmp(make_model, manufacturer, manulen))
343 {
344 delim = make_model + manulen;
345
346 while (isspace(*delim & 255))
347 delim ++;
348 }
349 else
350 delim = make_model;
351
352 for (; *delim && uriptr < (uri + uri_size - 3); delim ++)
353 if (*delim == ' ')
354 {
355 *uriptr++ = '%';
356 *uriptr++ = '2';
357 *uriptr++ = '0';
358 }
359 else
360 *uriptr++ = *delim;
361
362 if (serial_number[0])
363 {
364 /*
365 * Add the serial number to the URI...
366 */
367
368 strlcpy(uriptr, "?serial=", uri_size - (uriptr - uri));
369 strlcat(uriptr, serial_number, uri_size - (uriptr - uri));
370 }
371 else
372 *uriptr = '\0';
373 }
374
375 return (0);
db0bd74a 376#endif /* __APPLE__ */
89d46774 377}
89d46774 378
379
380/*
ed486911 381 * 'backendGetMakeModel()' - Get the make and model string from the device ID.
89d46774 382 */
383
384int /* O - 0 on success, -1 on failure */
ed486911 385backendGetMakeModel(
89d46774 386 const char *device_id, /* O - 1284 device ID */
387 char *make_model, /* O - Make/model */
388 int make_model_size) /* I - Size of buffer */
389{
390 char *attr, /* 1284 attribute */
391 *delim, /* 1284 delimiter */
392 *mfg, /* Manufacturer string */
393 *mdl; /* Model string */
394
395
ed486911 396 DEBUG_printf(("backendGetMakeModel(device_id=\"%s\", "
89d46774 397 "make_model=%p, make_model_size=%d)\n", device_id,
398 make_model, make_model_size));
399
400 /*
401 * Range check input...
402 */
403
404 if (!device_id || !*device_id || !make_model || make_model_size < 32)
405 {
ed486911 406 DEBUG_puts("backendGetMakeModel: Bad args!");
89d46774 407 return (-1);
408 }
409
410 *make_model = '\0';
411
ef416fc2 412 /*
413 * Look for the description field...
414 */
415
416 if ((attr = strstr(device_id, "DES:")) != NULL)
417 attr += 4;
418 else if ((attr = strstr(device_id, "DESCRIPTION:")) != NULL)
419 attr += 12;
420
421 if (attr)
422 {
423 /*
424 * Make sure the description contains something useful, since some
425 * printer manufacturers (HP) apparently don't follow the standards
426 * they helped to define...
427 *
428 * Here we require the description to be 8 or more characters in length,
429 * containing at least one space and one letter.
430 */
431
432 if ((delim = strchr(attr, ';')) == NULL)
433 delim = attr + strlen(attr);
434
435 if ((delim - attr) < 8)
436 attr = NULL;
437 else
438 {
439 char *ptr; /* Pointer into description */
440 int letters, /* Number of letters seen */
441 spaces; /* Number of spaces seen */
442
443
444 for (ptr = attr, letters = 0, spaces = 0; ptr < delim; ptr ++)
445 {
446 if (isspace(*ptr & 255))
447 spaces ++;
448 else if (isalpha(*ptr & 255))
449 letters ++;
450
451 if (spaces && letters)
452 break;
453 }
454
455 if (!spaces || !letters)
456 attr = NULL;
457 }
458 }
459
460 if ((mfg = strstr(device_id, "MANUFACTURER:")) != NULL)
461 mfg += 13;
89d46774 462 else if ((mfg = strstr(device_id, "Manufacturer:")) != NULL)
463 mfg += 13;
ef416fc2 464 else if ((mfg = strstr(device_id, "MFG:")) != NULL)
465 mfg += 4;
466
467 if ((mdl = strstr(device_id, "MODEL:")) != NULL)
468 mdl += 6;
89d46774 469 else if ((mdl = strstr(device_id, "Model:")) != NULL)
470 mdl += 6;
ef416fc2 471 else if ((mdl = strstr(device_id, "MDL:")) != NULL)
472 mdl += 4;
473
89d46774 474 if (mdl)
ef416fc2 475 {
476 /*
89d46774 477 * Build a make-model string from the manufacturer and model attributes...
ef416fc2 478 */
479
89d46774 480 if (mfg)
ef416fc2 481 {
db0bd74a
MS
482 /*
483 * Skip leading whitespace...
484 */
485
486 while (isspace(*mfg & 255))
487 mfg ++;
488
489 /*
490 * Map common bad names to the ones we use for driver selection...
491 */
492
89d46774 493 if (!strncasecmp(mfg, "Hewlett-Packard", 15))
494 strlcpy(make_model, "HP", make_model_size);
d09495fa 495 else if (!strncasecmp(mfg, "Lexmark International", 21))
496 strlcpy(make_model, "Lexmark", make_model_size);
89d46774 497 else
db0bd74a
MS
498 {
499 /*
500 * Use the manufacturer that is supplied...
501 */
502
89d46774 503 strlcpy(make_model, mfg, make_model_size);
ef416fc2 504
db0bd74a
MS
505 if ((delim = strchr(make_model, ';')) != NULL)
506 *delim = '\0';
507
508 /*
509 * But strip trailing whitespace...
510 */
511
512 for (delim = make_model + strlen(make_model) - 1;
513 delim > make_model && *delim == ' ';
514 delim --)
515 *delim = '\0';
516 }
89d46774 517
518 if (!strncasecmp(make_model, mdl, strlen(make_model)))
519 {
520 /*
521 * Just copy model string, since it has the manufacturer...
522 */
523
524 strlcpy(make_model, mdl, make_model_size);
525 }
526 else
527 {
528 /*
529 * Concatenate the make and model...
530 */
531
db0bd74a
MS
532 while (isspace(*mdl & 255))
533 mdl ++;
534
89d46774 535 strlcat(make_model, " ", make_model_size);
536 strlcat(make_model, mdl, make_model_size);
537 }
ef416fc2 538 }
539 else
540 {
89d46774 541 /*
542 * Just copy model string, since it has the manufacturer...
543 */
544
db0bd74a
MS
545 while (isspace(*mdl & 255))
546 mdl ++;
547
89d46774 548 strlcpy(make_model, mdl, make_model_size);
ef416fc2 549 }
550 }
89d46774 551 else if (attr)
ef416fc2 552 {
553 /*
89d46774 554 * Use description...
ef416fc2 555 */
556
db0bd74a
MS
557 while (isspace(*attr & 255))
558 attr ++;
559
89d46774 560 if (!strncasecmp(attr, "Hewlett-Packard hp ", 19))
ef416fc2 561 {
562 /*
89d46774 563 * Check for a common HP bug...
ef416fc2 564 */
565
89d46774 566 strlcpy(make_model, "HP ", make_model_size);
567 strlcpy(make_model + 3, attr + 19, make_model_size - 3);
568 }
569 else if (!strncasecmp(attr, "Hewlett-Packard ", 16))
570 {
571 strlcpy(make_model, "HP ", make_model_size);
572 strlcpy(make_model + 3, attr + 16, make_model_size - 3);
ef416fc2 573 }
574 else
575 {
89d46774 576 strlcpy(make_model, attr, make_model_size);
ef416fc2 577 }
578 }
579 else
580 {
581 /*
582 * Use "Unknown" as the printer make and model...
583 */
584
585 strlcpy(make_model, "Unknown", make_model_size);
586 }
587
89d46774 588 /*
589 * Strip trailing data...
590 */
591
ef416fc2 592 if ((delim = strchr(make_model, ';')) != NULL)
593 *delim = '\0';
594
db0bd74a
MS
595 for (delim = make_model + strlen(make_model) - 1;
596 delim > make_model && *delim == ' ';
597 delim --)
598 *delim = '\0';
599
89d46774 600 /*
601 * Strip trailing whitespace...
602 */
ef416fc2 603
89d46774 604 for (delim = make_model + strlen(make_model) - 1; delim >= make_model; delim --)
605 if (isspace(*delim & 255))
606 *delim = '\0';
ef416fc2 607 else
89d46774 608 break;
ef416fc2 609
89d46774 610 /*
611 * Return...
612 */
ef416fc2 613
89d46774 614 if (make_model[0])
615 return (0);
616 else
617 return (-1);
ef416fc2 618}
619
620
621/*
2e4ff8af 622 * End of "$Id: ieee1284.c 7019 2007-10-10 22:48:52Z mike $".
ef416fc2 623 */