4 * IEEE-1284 support functions for CUPS.
6 * Copyright 2007-2011 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * "LICENSE" which should have been included with this file. If this
13 * file is missing or damaged, see the license at "http://www.cups.org/".
15 * This file is subject to the Apple OS-Developed Software exception.
19 * backendGetDeviceID() - Get the IEEE-1284 device ID string and
21 * backendGetMakeModel() - Get the make and model string from the device
23 * get_1284_values() - Get 1284 device ID keys and values.
24 * normalize_make_and_model() - Normalize a product/make-and-model string.
28 * Include necessary headers.
31 #include "backend-private.h"
32 #include <cups/cups.h>
35 #define DEBUG_printf(x)
37 #define _cups_isspace(x) isspace((x) & 255)
38 #define _cups_strcasecmp strcasecmp
39 #define _cups_strncasecmp strncasecmp
46 static int get_1284_values(const char *device_id, cups_option_t **values);
47 static char *normalize_make_and_model(const char *make_and_model,
48 char *buffer, size_t bufsize);
52 * 'backendGetDeviceID()' - Get the IEEE-1284 device ID string and
56 int /* O - 0 on success, -1 on failure */
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 */
67 #ifdef __APPLE__ /* This function is a no-op */
72 (void)make_model_size;
79 #else /* Get the device ID from the specified file descriptor... */
81 int length; /* Length of device ID info */
84 # if defined(__sun) && defined(ECPPIOC_GETDEVID)
85 struct ecpp_device_id did; /* Device ID buffer */
86 # endif /* __sun && ECPPIOC_GETDEVID */
87 char *ptr; /* Pointer into device ID */
90 DEBUG_printf(("backendGetDeviceID(fd=%d, device_id=%p, device_id_size=%d, "
91 "make_model=%p, make_model_size=%d, scheme=\"%s\", "
92 "uri=%p, uri_size=%d)\n", fd, device_id, device_id_size,
93 make_model, make_model_size, scheme ? scheme : "(null)",
97 * Range check input...
100 if (!device_id || device_id_size < 32)
102 DEBUG_puts("backendGetDeviceID: Bad args!");
112 * Get the device ID string...
118 if (ioctl(fd, LPIOC_GET_DEVICE_ID(device_id_size), device_id))
121 * Linux has to implement things differently for every device it seems.
122 * Since the standard parallel port driver does not provide a simple
123 * ioctl() to get the 1284 device ID, we have to open the "raw" parallel
124 * device corresponding to this port and do some negotiation trickery
125 * to get the current device ID.
128 if (uri && !strncmp(uri, "parallel:/dev/", 14))
130 char devparport[16]; /* /dev/parportN */
131 int devparportfd, /* File descriptor for raw device */
132 mode; /* Port mode */
136 * Since the Linux parallel backend only supports 4 parallel port
137 * devices, just grab the trailing digit and use it to construct a
138 * /dev/parportN filename...
141 snprintf(devparport, sizeof(devparport), "/dev/parport%s",
142 uri + strlen(uri) - 1);
144 if ((devparportfd = open(devparport, O_RDWR | O_NOCTTY)) != -1)
147 * Claim the device...
150 if (!ioctl(devparportfd, PPCLAIM))
152 fcntl(devparportfd, F_SETFL, fcntl(devparportfd, F_GETFL) | O_NONBLOCK);
154 mode = IEEE1284_MODE_COMPAT;
156 if (!ioctl(devparportfd, PPNEGOT, &mode))
159 * Put the device into Device ID mode...
162 mode = IEEE1284_MODE_NIBBLE | IEEE1284_DEVICEID;
164 if (!ioctl(devparportfd, PPNEGOT, &mode))
167 * Read the 1284 device ID...
170 if ((length = read(devparportfd, device_id,
171 device_id_size - 1)) >= 2)
173 device_id[length] = '\0';
180 * Release the device...
183 ioctl(devparportfd, PPRELEASE);
196 * Extract the length of the device ID string from the first two
197 * bytes. The 1284 spec says the length is stored MSB first...
200 length = (((unsigned)device_id[0] & 255) << 8) +
201 ((unsigned)device_id[1] & 255);
204 * Check to see if the length is larger than our buffer; first
205 * assume that the vendor incorrectly implemented the 1284 spec,
206 * and then limit the length to the size of our buffer...
209 if (length > device_id_size || length < 14)
210 length = (((unsigned)device_id[1] & 255) << 8) +
211 ((unsigned)device_id[0] & 255);
213 if (length > device_id_size)
214 length = device_id_size;
217 * The length field counts the number of bytes in the string
218 * including the length field itself (2 bytes). The minimum
219 * length for a valid/usable device ID is 14 bytes:
221 * <LENGTH> MFG: <MFG> ;MDL: <MDL> ;
222 * 2 + 4 + 1 + 5 + 1 + 1
228 * Can't use this device ID, so don't try to copy it...
237 * Copy the device ID text to the beginning of the buffer and
243 memmove(device_id, device_id + 2, length);
244 device_id[length] = '\0';
249 DEBUG_printf(("backendGetDeviceID: ioctl failed - %s\n",
253 # endif /* __linux */
255 # if defined(__sun) && defined(ECPPIOC_GETDEVID)
256 did.mode = ECPP_CENTRONICS;
257 did.len = device_id_size - 1;
259 did.addr = device_id;
261 if (!ioctl(fd, ECPPIOC_GETDEVID, &did))
264 * Nul-terminate the device ID text.
267 if (did.rlen < (device_id_size - 1))
268 device_id[did.rlen] = '\0';
270 device_id[device_id_size - 1] = '\0';
274 DEBUG_printf(("backendGetDeviceID: ioctl failed - %s\n",
277 # endif /* __sun && ECPPIOC_GETDEVID */
281 * Check whether device ID is valid. Turn line breaks and tabs to spaces and
282 * reject device IDs with non-printable characters.
285 for (ptr = device_id; *ptr; ptr ++)
286 if (_cups_isspace(*ptr))
288 else if ((*ptr & 255) < ' ' || *ptr == 127)
290 DEBUG_printf(("backendGetDeviceID: Bad device_id character %d.",
296 DEBUG_printf(("backendGetDeviceID: device_id=\"%s\"\n", device_id));
305 * Get the make and model...
309 backendGetMakeModel(device_id, make_model, make_model_size);
312 * Then generate a device URI...
315 if (scheme && uri && uri_size > 32)
317 int num_values; /* Number of keys and values */
318 cups_option_t *values; /* Keys and values in device ID */
319 const char *mfg, /* Manufacturer */
321 *sern; /* Serial number */
322 char temp[256], /* Temporary manufacturer string */
323 *tempptr; /* Pointer into temp string */
327 * Get the make, model, and serial numbers...
330 num_values = get_1284_values(device_id, &values);
332 if ((sern = cupsGetOption("SERIALNUMBER", num_values, values)) == NULL)
333 if ((sern = cupsGetOption("SERN", num_values, values)) == NULL)
334 sern = cupsGetOption("SN", num_values, values);
336 if ((mfg = cupsGetOption("MANUFACTURER", num_values, values)) == NULL)
337 mfg = cupsGetOption("MFG", num_values, values);
339 if ((mdl = cupsGetOption("MODEL", num_values, values)) == NULL)
340 mdl = cupsGetOption("MDL", num_values, values);
344 if (!_cups_strcasecmp(mfg, "Hewlett-Packard"))
346 else if (!_cups_strcasecmp(mfg, "Lexmark International"))
351 strncpy(temp, make_model, sizeof(temp) - 1);
352 temp[sizeof(temp) - 1] = '\0';
354 if ((tempptr = strchr(temp, ' ')) != NULL)
363 if (!_cups_strncasecmp(mdl, mfg, strlen(mfg)))
367 while (isspace(*mdl & 255))
372 * Generate the device URI from the manufacturer, make_model, and
373 * serial number strings.
376 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, uri_size, scheme, NULL, mfg, 0,
377 "/%s%s%s", mdl, sern ? "?serial=" : "", sern ? sern : "");
379 cupsFreeOptions(num_values, values);
383 #endif /* __APPLE__ */
388 * 'backendGetMakeModel()' - Get the make and model string from the device ID.
391 int /* O - 0 on success, -1 on failure */
393 const char *device_id, /* O - 1284 device ID */
394 char *make_model, /* O - Make/model */
395 int make_model_size) /* I - Size of buffer */
397 int num_values; /* Number of keys and values */
398 cups_option_t *values; /* Keys and values */
399 const char *mfg, /* Manufacturer string */
400 *mdl, /* Model string */
401 *des; /* Description string */
404 DEBUG_printf(("backendGetMakeModel(device_id=\"%s\", "
405 "make_model=%p, make_model_size=%d)\n", device_id,
406 make_model, make_model_size));
409 * Range check input...
412 if (!device_id || !*device_id || !make_model || make_model_size < 32)
414 DEBUG_puts("backendGetMakeModel: Bad args!");
421 * Look for the description field...
424 num_values = get_1284_values(device_id, &values);
426 if ((mdl = cupsGetOption("MODEL", num_values, values)) == NULL)
427 mdl = cupsGetOption("MDL", num_values, values);
432 * Build a make-model string from the manufacturer and model attributes...
435 if ((mfg = cupsGetOption("MANUFACTURER", num_values, values)) == NULL)
436 mfg = cupsGetOption("MFG", num_values, values);
438 if (!mfg || !_cups_strncasecmp(mdl, mfg, strlen(mfg)))
441 * Just copy the model string, since it has the manufacturer...
444 normalize_make_and_model(mdl, make_model, make_model_size);
449 * Concatenate the make and model...
452 char temp[1024]; /* Temporary make and model */
454 snprintf(temp, sizeof(temp), "%s %s", mfg, mdl);
456 normalize_make_and_model(temp, make_model, make_model_size);
459 else if ((des = cupsGetOption("DESCRIPTION", num_values, values)) != NULL ||
460 (des = cupsGetOption("DES", num_values, values)) != NULL)
463 * Make sure the description contains something useful, since some
464 * printer manufacturers (HP) apparently don't follow the standards
465 * they helped to define...
467 * Here we require the description to be 8 or more characters in length,
468 * containing at least one space and one letter.
471 if (strlen(des) >= 8)
473 const char *ptr; /* Pointer into description */
474 int letters, /* Number of letters seen */
475 spaces; /* Number of spaces seen */
478 for (ptr = des, letters = 0, spaces = 0; *ptr; ptr ++)
480 if (isspace(*ptr & 255))
482 else if (isalpha(*ptr & 255))
485 if (spaces && letters)
489 if (spaces && letters)
490 normalize_make_and_model(des, make_model, make_model_size);
497 * Use "Unknown" as the printer make and model...
500 strncpy(make_model, "Unknown", make_model_size - 1);
501 make_model[make_model_size - 1] = '\0';
504 cupsFreeOptions(num_values, values);
511 * 'get_1284_values()' - Get 1284 device ID keys and values.
513 * The returned dictionary is a CUPS option array that can be queried with
514 * cupsGetOption and freed with cupsFreeOptions.
517 static int /* O - Number of key/value pairs */
519 const char *device_id, /* I - IEEE-1284 device ID string */
520 cups_option_t **values) /* O - Array of key/value pairs */
522 int num_values; /* Number of values */
523 char key[256], /* Key string */
524 value[256], /* Value string */
525 *ptr; /* Pointer into key/value */
529 * Range check input...
535 if (!device_id || !values)
539 * Parse the 1284 device ID value into keys and values. The format is
540 * repeating sequences of:
542 * [whitespace]key:value[whitespace];
548 while (_cups_isspace(*device_id))
554 for (ptr = key; *device_id && *device_id != ':'; device_id ++)
555 if (ptr < (key + sizeof(key) - 1))
561 while (ptr > key && _cups_isspace(ptr[-1]))
567 while (_cups_isspace(*device_id))
573 for (ptr = value; *device_id && *device_id != ';'; device_id ++)
574 if (ptr < (value + sizeof(value) - 1))
580 while (ptr > value && _cups_isspace(ptr[-1]))
586 num_values = cupsAddOption(key, value, num_values, values);
594 * 'normalize_make_and_model()' - Normalize a product/make-and-model string.
596 * This function tries to undo the mistakes made by many printer manufacturers
597 * to produce a clean make-and-model string we can use.
600 static char * /* O - Normalized make-and-model string or NULL on error */
601 normalize_make_and_model(
602 const char *make_and_model, /* I - Original make-and-model string */
603 char *buffer, /* I - String buffer */
604 size_t bufsize) /* I - Size of string buffer */
606 char *bufptr; /* Pointer into buffer */
609 if (!make_and_model || !buffer || bufsize < 1)
618 * Skip leading whitespace...
621 while (_cups_isspace(*make_and_model))
625 * Remove parenthesis and add manufacturers as needed...
628 if (make_and_model[0] == '(')
630 strncpy(buffer, make_and_model + 1, bufsize - 1);
631 buffer[bufsize - 1] = '\0';
633 if ((bufptr = strrchr(buffer, ')')) != NULL)
636 else if (!_cups_strncasecmp(make_and_model, "XPrint", 6))
642 snprintf(buffer, bufsize, "Xerox %s", make_and_model);
644 else if (!_cups_strncasecmp(make_and_model, "Eastman", 7))
650 snprintf(buffer, bufsize, "Kodak %s", make_and_model + 7);
652 else if (!_cups_strncasecmp(make_and_model, "laserwriter", 11))
655 * Apple LaserWriter...
658 snprintf(buffer, bufsize, "Apple LaserWriter%s", make_and_model + 11);
660 else if (!_cups_strncasecmp(make_and_model, "colorpoint", 10))
666 snprintf(buffer, bufsize, "Seiko %s", make_and_model);
668 else if (!_cups_strncasecmp(make_and_model, "fiery", 5))
674 snprintf(buffer, bufsize, "EFI %s", make_and_model);
676 else if (!_cups_strncasecmp(make_and_model, "ps ", 3) ||
677 !_cups_strncasecmp(make_and_model, "colorpass", 9))
683 snprintf(buffer, bufsize, "Canon %s", make_and_model);
685 else if (!_cups_strncasecmp(make_and_model, "primera", 7))
691 snprintf(buffer, bufsize, "Fargo %s", make_and_model);
693 else if (!_cups_strncasecmp(make_and_model, "designjet", 9) ||
694 !_cups_strncasecmp(make_and_model, "deskjet", 7))
700 snprintf(buffer, bufsize, "HP %s", make_and_model);
704 strncpy(buffer, make_and_model, bufsize - 1);
705 buffer[bufsize - 1] = '\0';
709 * Clean up the make...
712 if (!_cups_strncasecmp(buffer, "agfa", 4))
715 * Replace with AGFA (all uppercase)...
723 else if (!_cups_strncasecmp(buffer, "Hewlett-Packard hp ", 19))
726 * Just put "HP" on the front...
731 memmove(buffer + 2, buffer + 18, strlen(buffer + 18) + 1);
733 else if (!_cups_strncasecmp(buffer, "Hewlett-Packard ", 16))
736 * Just put "HP" on the front...
741 memmove(buffer + 2, buffer + 15, strlen(buffer + 15) + 1);
743 else if (!_cups_strncasecmp(buffer, "Lexmark International", 21))
746 * Strip "International"...
749 memmove(buffer + 8, buffer + 21, strlen(buffer + 21) + 1);
751 else if (!_cups_strncasecmp(buffer, "herk", 4))
754 * Replace with LHAG...
762 else if (!_cups_strncasecmp(buffer, "linotype", 8))
765 * Replace with LHAG...
772 memmove(buffer + 4, buffer + 8, strlen(buffer + 8) + 1);
776 * Remove trailing whitespace and return...
779 for (bufptr = buffer + strlen(buffer) - 1;
780 bufptr >= buffer && _cups_isspace(*bufptr);
785 return (buffer[0] ? buffer : NULL);