]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/usb-libusb.c
Merge changes from CUPS 1.4.0 (r8756)
[thirdparty/cups.git] / backend / usb-libusb.c
CommitLineData
75bd9771
MS
1/*
2 * "$Id$"
3 *
4 * Libusb interface code for the Common UNIX Printing System (CUPS).
5 *
d2354e63 6 * Copyright 2007-2009 by Apple Inc.
75bd9771
MS
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Apple Inc. and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
11 * which should have been included with this file. If this file is
12 * file is missing or damaged, see the license at "http://www.cups.org/".
13 *
14 * Contents:
15 *
005dd1eb
MS
16 * list_devices() - List the available printers.
17 * print_device() - Print a file to a USB device.
18 * close_device() - Close the connection to the USB printer.
19 * find_device() - Find or enumerate USB printers.
20 * get_device_id() - Get the IEEE-1284 device ID for the printer.
21 * list_cb() - List USB printers for discovery.
22 * make_device_uri() - Create a device URI for a USB printer.
23 * open_device() - Open a connection to the USB printer.
24 * print_cb() - Find a USB printer for printing.
25 * side_cb() - Handle side-channel requests.
75bd9771
MS
26 */
27
28/*
29 * Include necessary headers...
30 */
31
32#include <usb.h>
005dd1eb 33#include <poll.h>
75bd9771
MS
34
35
36/*
37 * Local types...
38 */
39
40typedef struct usb_printer_s /**** USB Printer Data ****/
41{
42 struct usb_device *device; /* Device info */
43 int conf, /* Configuration */
44 iface, /* Interface */
45 altset, /* Alternate setting */
46 write_endp, /* Write endpoint */
47 read_endp; /* Read endpoint */
48 struct usb_dev_handle *handle; /* Open handle to device */
49} usb_printer_t;
50
51typedef int (*usb_cb_t)(usb_printer_t *, const char *, const char *,
52 const void *);
53
54
55/*
56 * Local functions...
57 */
58
59static int close_device(usb_printer_t *printer);
60static usb_printer_t *find_device(usb_cb_t cb, const void *data);
61static int get_device_id(usb_printer_t *printer, char *buffer,
62 size_t bufsize);
63static int list_cb(usb_printer_t *printer, const char *device_uri,
64 const char *device_id, const void *data);
65static char *make_device_uri(usb_printer_t *printer,
66 const char *device_id,
67 char *uri, size_t uri_size);
68static int open_device(usb_printer_t *printer, int verbose);
69static int print_cb(usb_printer_t *printer, const char *device_uri,
70 const char *device_id, const void *data);
005dd1eb 71static ssize_t side_cb(usb_printer_t *printer, int print_fd);
75bd9771
MS
72
73
74/*
75 * 'list_devices()' - List the available printers.
76 */
77
78void
79list_devices(void)
80{
81 fputs("DEBUG: list_devices\n", stderr);
82 find_device(list_cb, NULL);
83}
84
85
86/*
87 * 'print_device()' - Print a file to a USB device.
88 */
89
90int /* O - Exit status */
91print_device(const char *uri, /* I - Device URI */
92 const char *hostname, /* I - Hostname/manufacturer */
93 const char *resource, /* I - Resource/modelname */
94 char *options, /* I - Device options/serial number */
95 int print_fd, /* I - File descriptor to print */
96 int copies, /* I - Copies to print */
97 int argc, /* I - Number of command-line arguments (6 or 7) */
98 char *argv[]) /* I - Command-line arguments */
99{
100 usb_printer_t *printer; /* Printer */
101 ssize_t bytes, /* Bytes read/written */
102 tbytes; /* Total bytes written */
103 char buffer[8192]; /* Print data buffer */
104 struct sigaction action; /* Actions for POSIX signals */
005dd1eb 105 struct pollfd pfds[2]; /* Poll descriptors */
75bd9771
MS
106
107
108 fputs("DEBUG: print_device\n", stderr);
109
110 /*
111 * Connect to the printer...
112 */
113
114 while ((printer = find_device(print_cb, uri)) == NULL)
115 {
116 _cupsLangPuts(stderr,
117 _("INFO: Waiting for printer to become available...\n"));
118 sleep(5);
119 }
120
75bd9771
MS
121
122 /*
123 * If we are printing data from a print driver on stdin, ignore SIGTERM
124 * so that the driver can finish out any page data, e.g. to eject the
125 * current page. We only do this for stdin printing as otherwise there
126 * is no way to cancel a raw print job...
127 */
128
129 if (!print_fd)
130 {
131 memset(&action, 0, sizeof(action));
132
133 sigemptyset(&action.sa_mask);
134 action.sa_handler = SIG_IGN;
135 sigaction(SIGTERM, &action, NULL);
136 }
137
138 tbytes = 0;
139
005dd1eb
MS
140 pfds[0].fd = print_fd;
141 pfds[0].events = POLLIN;
142 pfds[1].fd = CUPS_SC_FD;
143 pfds[1].events = POLLIN;
144
75bd9771
MS
145 while (copies > 0 && tbytes >= 0)
146 {
147 copies --;
148
149 if (print_fd != 0)
150 {
151 fputs("PAGE: 1 1\n", stderr);
152 lseek(print_fd, 0, SEEK_SET);
153 }
154
155 /*
005dd1eb 156 * TODO: Add back-channel support, along with better write error handling.
75bd9771
MS
157 */
158
d2354e63 159 while (poll(pfds, 2, -1) > 0)
75bd9771 160 {
005dd1eb 161 if (pfds[0].revents & POLLIN)
75bd9771 162 {
005dd1eb
MS
163 if ((bytes = read(print_fd, buffer, sizeof(buffer))) > 0)
164 {
d2354e63 165 if (usb_bulk_write(printer->handle, printer->write_endp, buffer,
557dde9f 166 bytes, 45000) < 0)
005dd1eb
MS
167 {
168 _cupsLangPrintf(stderr,
169 _("ERROR: Unable to write %d bytes to printer!\n"),
170 (int)bytes);
171 tbytes = -1;
172 break;
173 }
174
175 tbytes += bytes;
176 }
d2354e63 177 else if (bytes == 0 || (bytes < 0 && errno != EAGAIN && errno != EINTR))
005dd1eb 178 break;
75bd9771
MS
179 }
180
005dd1eb
MS
181 if (pfds[1].revents & POLLIN)
182 tbytes += side_cb(printer, print_fd);
75bd9771
MS
183 }
184 }
185
186 /*
187 * Close our connection and return...
188 */
189
190 close_device(printer);
191
192 return (CUPS_BACKEND_OK);
193}
194
195
196/*
197 * 'close_device()' - Close the connection to the USB printer.
198 */
199
200static int /* I - 0 on success, -1 on failure */
201close_device(usb_printer_t *printer) /* I - Printer */
202{
203 if (printer->handle)
204 {
557dde9f
MS
205 /*
206 * Release interfaces before closing so that we know all data is written
207 * to the device...
208 */
209
210 int number = printer->device->config[printer->conf].
211 interface[printer->iface].
212 altsetting[printer->altset].bInterfaceNumber;
213 usb_release_interface(printer->handle, number);
214
215 if (number != 0)
216 usb_release_interface(printer->handle, 0);
217
218 /*
219 * Close the interface and return...
220 */
221
75bd9771
MS
222 usb_close(printer->handle);
223 printer->handle = NULL;
224 }
225
226 return (0);
227}
228
229
230/*
231 * 'find_device()' - Find or enumerate USB printers.
232 */
233
234static usb_printer_t * /* O - Found printer */
235find_device(usb_cb_t cb, /* I - Callback function */
236 const void *data) /* I - User data for callback */
237{
238 struct usb_bus *bus; /* Current bus */
239 struct usb_device *device; /* Current device */
240 struct usb_config_descriptor *confptr;/* Pointer to current configuration */
241 struct usb_interface *ifaceptr; /* Pointer to current interface */
242 struct usb_interface_descriptor *altptr;
243 /* Pointer to current alternate setting */
244 struct usb_endpoint_descriptor *endpptr;
245 /* Pointer to current endpoint */
246 int conf, /* Current configuration */
247 iface, /* Current interface */
248 altset, /* Current alternate setting */
249 protocol, /* Current protocol */
250 endp, /* Current endpoint */
251 read_endp, /* Current read endpoint */
252 write_endp; /* Current write endpoint */
253 char device_id[1024],/* IEEE-1284 device ID */
254 device_uri[1024];
255 /* Device URI */
256 static usb_printer_t printer; /* Current printer */
257
258
259 /*
260 * Initialize libusb...
261 */
262
263 usb_init();
264 fprintf(stderr, "DEBUG: usb_find_busses=%d\n", usb_find_busses());
265 fprintf(stderr, "DEBUG: usb_find_devices=%d\n", usb_find_devices());
266
267 /*
268 * Then loop through the devices it found...
269 */
270
271 for (bus = usb_get_busses(); bus; bus = bus->next)
272 for (device = bus->devices; device; device = device->next)
273 {
274 /*
275 * Ignore devices with no configuration data and anything that is not
276 * a printer...
277 */
278
279 if (!device->config || !device->descriptor.idVendor ||
280 !device->descriptor.idProduct)
281 continue;
282
283 for (conf = 0, confptr = device->config;
284 conf < device->descriptor.bNumConfigurations;
285 conf ++, confptr ++)
286 for (iface = 0, ifaceptr = confptr->interface;
287 iface < confptr->bNumInterfaces;
288 iface ++, ifaceptr ++)
289 {
290 /*
291 * Some printers offer multiple interfaces...
292 */
293
294 protocol = 0;
295
296 for (altset = 0, altptr = ifaceptr->altsetting;
297 altset < ifaceptr->num_altsetting;
298 altset ++, altptr ++)
299 {
300 /*
301 * Currently we only support unidirectional and bidirectional
302 * printers. Future versions of this code will support the
303 * 1284.4 (packet mode) protocol as well.
304 */
305
306 if (altptr->bInterfaceClass != USB_CLASS_PRINTER ||
307 altptr->bInterfaceSubClass != 1 ||
308 (altptr->bInterfaceProtocol != 1 && /* Unidirectional */
309 altptr->bInterfaceProtocol != 2) || /* Bidirectional */
310 altptr->bInterfaceProtocol < protocol)
311 continue;
312
313 read_endp = -1;
314 write_endp = -1;
315
316 for (endp = 0, endpptr = altptr->endpoint;
317 endp < altptr->bNumEndpoints;
318 endp ++, endpptr ++)
319 if ((endpptr->bmAttributes & USB_ENDPOINT_TYPE_MASK) ==
320 USB_ENDPOINT_TYPE_BULK)
321 {
322 if (endpptr->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
323 read_endp = endp;
324 else
325 write_endp = endp;
326 }
327
328 if (write_endp >= 0)
329 {
330 /*
331 * Save the best match so far...
332 */
333
334 protocol = altptr->bInterfaceProtocol;
335 printer.altset = altset;
336 printer.write_endp = write_endp;
337 printer.read_endp = read_endp;
338 }
339 }
340
341 if (protocol > 0)
342 {
343 printer.device = device;
344 printer.conf = conf;
345 printer.iface = iface;
346 printer.handle = NULL;
347
348 if (!open_device(&printer, data != NULL))
349 {
350 if (!get_device_id(&printer, device_id, sizeof(device_id)))
351 {
352 make_device_uri(&printer, device_id, device_uri,
353 sizeof(device_uri));
354
355 if ((*cb)(&printer, device_uri, device_id, data))
005dd1eb
MS
356 {
357 printer.read_endp = printer.device->config[printer.conf].
358 interface[printer.iface].
359 altsetting[printer.altset].
360 endpoint[printer.read_endp].
361 bEndpointAddress;
362 printer.write_endp = printer.device->config[printer.conf].
363 interface[printer.iface].
364 altsetting[printer.altset].
365 endpoint[printer.write_endp].
366 bEndpointAddress;
75bd9771 367 return (&printer);
005dd1eb 368 }
75bd9771
MS
369 }
370
371 close_device(&printer);
372 }
373 }
374 }
375 }
376
377 /*
378 * If we get this far without returning, then we haven't found a printer
379 * to print to...
380 */
381
382 return (NULL);
383}
384
385
386/*
387 * 'get_device_id()' - Get the IEEE-1284 device ID for the printer.
388 */
389
390static int /* O - 0 on success, -1 on error */
391get_device_id(usb_printer_t *printer, /* I - Printer */
392 char *buffer, /* I - String buffer */
393 size_t bufsize) /* I - Number of bytes in buffer */
394{
395 int length; /* Length of device ID */
396
397
398 if (usb_control_msg(printer->handle,
399 USB_TYPE_CLASS | USB_ENDPOINT_IN | USB_RECIP_INTERFACE,
e4572d57 400 0, printer->conf, printer->iface,
75bd9771
MS
401 buffer, bufsize, 5000) < 0)
402 {
403 *buffer = '\0';
404 return (-1);
405 }
406
407 /*
408 * Extract the length of the device ID string from the first two
409 * bytes. The 1284 spec says the length is stored MSB first...
410 */
411
412 length = (((unsigned)buffer[0] & 255) << 8) +
413 ((unsigned)buffer[1] & 255);
414
415 /*
416 * Check to see if the length is larger than our buffer; first
417 * assume that the vendor incorrectly implemented the 1284 spec,
418 * and then limit the length to the size of our buffer...
419 */
420
421 if (length > (bufsize - 2))
422 length = (((unsigned)buffer[1] & 255) << 8) +
423 ((unsigned)buffer[0] & 255);
424
425 if (length > (bufsize - 2))
426 length = bufsize - 2;
427
428 /*
429 * Copy the device ID text to the beginning of the buffer and
430 * nul-terminate.
431 */
432
433 memmove(buffer, buffer + 2, length);
434 buffer[length] = '\0';
435
436 return (0);
437}
438
439
440/*
441 * 'list_cb()' - List USB printers for discovery.
442 */
443
444static int /* O - 0 to continue, 1 to stop */
445list_cb(usb_printer_t *printer, /* I - Printer */
446 const char *device_uri, /* I - Device URI */
447 const char *device_id, /* I - IEEE-1284 device ID */
448 const void *data) /* I - User data (not used) */
449{
450 char make_model[1024]; /* Make and model */
451
452
453 /*
454 * Get the device URI and make/model strings...
455 */
456
457 backendGetMakeModel(device_id, make_model, sizeof(make_model));
458
459 /*
460 * Report the printer...
461 */
462
749b1e90
MS
463 cupsBackendReport("direct", device_uri, make_model, make_model, device_id,
464 NULL);
75bd9771
MS
465
466 /*
467 * Keep going...
468 */
469
470 return (0);
471}
472
473
474/*
475 * 'make_device_uri()' - Create a device URI for a USB printer.
476 */
477
478static char * /* O - Device URI */
479make_device_uri(
480 usb_printer_t *printer, /* I - Printer */
481 const char *device_id, /* I - IEEE-1284 device ID */
482 char *uri, /* I - Device URI buffer */
483 size_t uri_size) /* I - Size of device URI buffer */
484{
485 char options[1024]; /* Device URI options */
486 int num_values; /* Number of 1284 parameters */
487 cups_option_t *values; /* 1284 parameters */
488 const char *mfg, /* Manufacturer */
489 *mdl, /* Model */
490 *des, /* Description */
491 *sern; /* Serial number */
492 char tempmfg[256], /* Temporary manufacturer string */
493 tempsern[256], /* Temporary serial number string */
494 *tempptr; /* Pointer into temp string */
495
496
497 /*
498 * Get the make, model, and serial numbers...
499 */
500
501 num_values = _ppdGet1284Values(device_id, &values);
502
503 if ((sern = cupsGetOption("SERIALNUMBER", num_values, values)) == NULL)
504 if ((sern = cupsGetOption("SERN", num_values, values)) == NULL)
505 if ((sern = cupsGetOption("SN", num_values, values)) == NULL)
506 {
507 /*
508 * Try getting the serial number from the device itself...
509 */
510
511 int length = usb_get_string_simple(printer->handle,
512 printer->device->descriptor.
513 iSerialNumber,
514 tempsern, sizeof(tempsern) - 1);
515 if (length > 0)
516 {
517 tempsern[length] = '\0';
518 sern = tempsern;
519 }
520 }
521
522 if ((mfg = cupsGetOption("MANUFACTURER", num_values, values)) == NULL)
523 mfg = cupsGetOption("MFG", num_values, values);
524
525 if ((mdl = cupsGetOption("MODEL", num_values, values)) == NULL)
526 mdl = cupsGetOption("MDL", num_values, values);
527
528#ifdef __APPLE__
529 /*
530 * To maintain compatibility with the original IOKit-based backend on Mac OS X,
531 * don't map manufacturer names...
532 */
533
534 if (!mfg)
535
536#else
537 /*
538 * To maintain compatibility with the original character device backend on
539 * Linux and *BSD, map manufacturer names...
540 */
541
542 if (mfg)
543 {
544 if (!strcasecmp(mfg, "Hewlett-Packard"))
545 mfg = "HP";
546 else if (!strcasecmp(mfg, "Lexmark International"))
547 mfg = "Lexmark";
548 }
549 else
550#endif /* __APPLE__ */
551 {
552 /*
553 * No manufacturer? Use the model string or description...
554 */
555
556 if (mdl)
557 _ppdNormalizeMakeAndModel(mdl, tempmfg, sizeof(tempmfg));
558 else if ((des = cupsGetOption("DESCRIPTION", num_values, values)) != NULL ||
559 (des = cupsGetOption("DES", num_values, values)) != NULL)
560 _ppdNormalizeMakeAndModel(des, tempmfg, sizeof(tempmfg));
561 else
562 strlcpy(tempmfg, "Unknown", sizeof(tempmfg));
563
564 if ((tempptr = strchr(tempmfg, ' ')) != NULL)
565 *tempptr = '\0';
566
567 mfg = tempmfg;
568 }
569
570 /*
571 * Generate the device URI from the manufacturer, model, serial number,
572 * and interface number...
573 */
574
575 if (sern)
576 {
577 if (printer->iface > 0)
578 snprintf(options, sizeof(options), "?serial=%s&interface=%d", sern,
579 printer->iface);
580 else
581 snprintf(options, sizeof(options), "?serial=%s", sern);
582 }
583 else if (printer->iface > 0)
584 snprintf(options, sizeof(options), "?interface=%d", printer->iface);
585 else
586 options[0] = '\0';
587
588 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, uri_size, "usb", NULL, mfg, 0,
589 "/%s%s", mdl, options);
590
591 cupsFreeOptions(num_values, values);
592
593 return (uri);
594}
595
596
597/*
598 * 'open_device()' - Open a connection to the USB printer.
599 */
600
601static int /* O - 0 on success, -1 on error */
602open_device(usb_printer_t *printer, /* I - Printer */
603 int verbose) /* I - Update connecting-to-device state? */
604{
605 int number; /* Configuration/interface/altset numbers */
606
607
608 /*
609 * Return immediately if we are already connected...
610 */
611
612 if (printer->handle)
613 return (0);
614
615 /*
616 * Try opening the printer...
617 */
618
619 if ((printer->handle = usb_open(printer->device)) == NULL)
620 return (-1);
621
622 /*
623 * Then set the desired configuration...
624 */
625
626 if (verbose)
627 fputs("STATE: +connecting-to-device\n", stderr);
628
629 number = printer->device->config[printer->conf].bConfigurationValue;
e4572d57
MS
630
631 if (usb_set_configuration(printer->handle, number) < 0)
75bd9771 632 {
e4572d57
MS
633 /*
634 * If the set fails, chances are that the printer only supports a
635 * single configuration. Technically these printers don't conform to
636 * the USB printer specification, but otherwise they'll work...
637 */
638
75bd9771
MS
639 if (errno != EBUSY)
640 fprintf(stderr, "DEBUG: Failed to set configuration %d for %04x:%04x\n",
641 number, printer->device->descriptor.idVendor,
642 printer->device->descriptor.idProduct);
75bd9771
MS
643 }
644
645 /*
646 * Claim interfaces as needed...
647 */
648
649 number = printer->device->config[printer->conf].interface[printer->iface].
650 altsetting[printer->altset].bInterfaceNumber;
651 while (usb_claim_interface(printer->handle, number) < 0)
652 {
653 if (errno != EBUSY)
e4572d57 654 fprintf(stderr, "DEBUG: Failed to claim interface %d for %04x:%04x: %s\n",
75bd9771 655 number, printer->device->descriptor.idVendor,
e4572d57 656 printer->device->descriptor.idProduct, strerror(errno));
75bd9771
MS
657
658 goto error;
659 }
660
661 if (number != 0)
662 while (usb_claim_interface(printer->handle, 0) < 0)
663 {
664 if (errno != EBUSY)
e4572d57 665 fprintf(stderr, "DEBUG: Failed to claim interface 0 for %04x:%04x: %s\n",
75bd9771 666 printer->device->descriptor.idVendor,
e4572d57 667 printer->device->descriptor.idProduct, strerror(errno));
75bd9771
MS
668
669 goto error;
670 }
671
672 /*
673 * Set alternate setting...
674 */
675
676 number = printer->device->config[printer->conf].interface[printer->iface].
677 altsetting[printer->altset].bAlternateSetting;
678 while (usb_set_altinterface(printer->handle, number) < 0)
679 {
680 if (errno != EBUSY)
681 fprintf(stderr,
e4572d57 682 "DEBUG: Failed to set alternate interface %d for %04x:%04x: %s\n",
75bd9771 683 number, printer->device->descriptor.idVendor,
e4572d57 684 printer->device->descriptor.idProduct, strerror(errno));
75bd9771
MS
685
686 goto error;
687 }
688
689 if (verbose)
690 fputs("STATE: -connecting-to-device\n", stderr);
691
692 return (0);
693
694 /*
695 * If we get here, there was a hard error...
696 */
697
698 error:
699
700 if (verbose)
701 fputs("STATE: -connecting-to-device\n", stderr);
702
703 usb_close(printer->handle);
704 printer->handle = NULL;
705
706 return (-1);
707}
708
709
710/*
711 * 'print_cb()' - Find a USB printer for printing.
712 */
713
714static int /* O - 0 to continue, 1 to stop (found) */
715print_cb(usb_printer_t *printer, /* I - Printer */
716 const char *device_uri, /* I - Device URI */
717 const char *device_id, /* I - IEEE-1284 device ID */
718 const void *data) /* I - User data (make, model, S/N) */
719{
720 return (!strcmp((char *)data, device_uri));
721}
722
723
005dd1eb
MS
724/*
725 * 'side_cb()' - Handle side-channel requests.
726 */
727
728static ssize_t /* O - Number of bytes written */
729side_cb(usb_printer_t *printer, /* I - Printer */
730 int print_fd) /* I - File to print */
731{
732 ssize_t bytes, /* Bytes read/written */
733 tbytes; /* Total bytes written */
734 char buffer[8192]; /* Print data buffer */
735 struct pollfd pfd; /* Poll descriptor */
736 cups_sc_command_t command; /* Request command */
737 cups_sc_status_t status; /* Request/response status */
738 char data[2048]; /* Request/response data */
739 int datalen; /* Request/response data size */
740
741
742 tbytes = 0;
743 datalen = sizeof(data);
744
745 if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
746 {
747 _cupsLangPuts(stderr, _("WARNING: Failed to read side-channel request!\n"));
748 return (0);
749 }
750
751 switch (command)
752 {
753 case CUPS_SC_CMD_DRAIN_OUTPUT :
754 pfd.fd = print_fd;
755 pfd.events = POLLIN;
756
757 while (poll(&pfd, 1, 1000) > 0)
758 {
759 if ((bytes = read(print_fd, buffer, sizeof(buffer))) > 0)
760 {
761 while (usb_bulk_write(printer->handle, printer->write_endp, buffer,
762 bytes, 5000) < 0)
763 {
764 _cupsLangPrintf(stderr,
765 _("ERROR: Unable to write %d bytes to printer!\n"),
766 (int)bytes);
767 tbytes = -1;
768 break;
769 }
770
771 tbytes += bytes;
772 }
773 else if (bytes < 0 && errno != EAGAIN && errno != EINTR)
774 break;
775 }
776
777 if (tbytes < 0)
778 status = CUPS_SC_STATUS_IO_ERROR;
779 else
780 status = CUPS_SC_STATUS_OK;
781
782 datalen = 0;
783 break;
784
785 case CUPS_SC_CMD_GET_BIDI :
8b450588 786 status = CUPS_SC_STATUS_OK;
005dd1eb
MS
787 data[0] = 0; /* TODO: Change to 1 when read supported */
788 datalen = 1;
789 break;
790
791 case CUPS_SC_CMD_GET_DEVICE_ID :
792 if (get_device_id(printer, data, sizeof(data)))
793 {
794 status = CUPS_SC_STATUS_IO_ERROR;
795 datalen = 0;
796 }
797 else
798 {
799 status = CUPS_SC_STATUS_OK;
800 datalen = strlen(data);
801 }
802 break;
803
804 default :
805 status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
806 datalen = 0;
807 break;
808 }
809
810 cupsSideChannelWrite(command, status, data, datalen, 1.0);
811
812 return (tbytes);
813}
814
815
75bd9771
MS
816/*
817 * End of "$Id$".
818 */
819