]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/usb-libusb.c
Merge changes from CUPS 1.5svn-r8849.
[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 {
18ecb428
MS
161 /*
162 * CUPS STR #3318: USB process hangs on end-of-file, making further
163 * printing impossible
164 *
165 * From a strict interpretation of POSIX poll(), POLLHUP should never be
166 * set without POLLIN, since POLLIN is the event you request. That said,
167 * it appears that some versions of Linux break this.
168 */
169
170 if (pfds[0].revents & (POLLIN | POLLHUP))
75bd9771 171 {
005dd1eb
MS
172 if ((bytes = read(print_fd, buffer, sizeof(buffer))) > 0)
173 {
d2354e63 174 if (usb_bulk_write(printer->handle, printer->write_endp, buffer,
557dde9f 175 bytes, 45000) < 0)
005dd1eb
MS
176 {
177 _cupsLangPrintf(stderr,
4d301e69 178 _("ERROR: Unable to write %d bytes to printer\n"),
005dd1eb
MS
179 (int)bytes);
180 tbytes = -1;
181 break;
182 }
183
184 tbytes += bytes;
185 }
d2354e63 186 else if (bytes == 0 || (bytes < 0 && errno != EAGAIN && errno != EINTR))
005dd1eb 187 break;
75bd9771
MS
188 }
189
18ecb428
MS
190 if (pfds[1].revents & (POLLIN | POLLHUP))
191 {
192 if ((bytes = side_cb(printer, print_fd)) < 0)
193 pfds[1].events = 0; /* Filter has gone away... */
194 else
195 tbytes += bytes;
196 }
75bd9771
MS
197 }
198 }
199
200 /*
201 * Close our connection and return...
202 */
203
204 close_device(printer);
205
206 return (CUPS_BACKEND_OK);
207}
208
209
210/*
211 * 'close_device()' - Close the connection to the USB printer.
212 */
213
214static int /* I - 0 on success, -1 on failure */
215close_device(usb_printer_t *printer) /* I - Printer */
216{
217 if (printer->handle)
218 {
557dde9f
MS
219 /*
220 * Release interfaces before closing so that we know all data is written
221 * to the device...
222 */
223
224 int number = printer->device->config[printer->conf].
225 interface[printer->iface].
226 altsetting[printer->altset].bInterfaceNumber;
227 usb_release_interface(printer->handle, number);
228
229 if (number != 0)
230 usb_release_interface(printer->handle, 0);
231
232 /*
233 * Close the interface and return...
234 */
235
75bd9771
MS
236 usb_close(printer->handle);
237 printer->handle = NULL;
238 }
239
240 return (0);
241}
242
243
244/*
245 * 'find_device()' - Find or enumerate USB printers.
246 */
247
248static usb_printer_t * /* O - Found printer */
249find_device(usb_cb_t cb, /* I - Callback function */
250 const void *data) /* I - User data for callback */
251{
252 struct usb_bus *bus; /* Current bus */
253 struct usb_device *device; /* Current device */
254 struct usb_config_descriptor *confptr;/* Pointer to current configuration */
255 struct usb_interface *ifaceptr; /* Pointer to current interface */
256 struct usb_interface_descriptor *altptr;
257 /* Pointer to current alternate setting */
258 struct usb_endpoint_descriptor *endpptr;
259 /* Pointer to current endpoint */
260 int conf, /* Current configuration */
261 iface, /* Current interface */
262 altset, /* Current alternate setting */
263 protocol, /* Current protocol */
264 endp, /* Current endpoint */
265 read_endp, /* Current read endpoint */
266 write_endp; /* Current write endpoint */
267 char device_id[1024],/* IEEE-1284 device ID */
268 device_uri[1024];
269 /* Device URI */
270 static usb_printer_t printer; /* Current printer */
271
272
273 /*
274 * Initialize libusb...
275 */
276
277 usb_init();
278 fprintf(stderr, "DEBUG: usb_find_busses=%d\n", usb_find_busses());
279 fprintf(stderr, "DEBUG: usb_find_devices=%d\n", usb_find_devices());
280
281 /*
282 * Then loop through the devices it found...
283 */
284
285 for (bus = usb_get_busses(); bus; bus = bus->next)
286 for (device = bus->devices; device; device = device->next)
287 {
288 /*
289 * Ignore devices with no configuration data and anything that is not
290 * a printer...
291 */
292
293 if (!device->config || !device->descriptor.idVendor ||
294 !device->descriptor.idProduct)
295 continue;
296
297 for (conf = 0, confptr = device->config;
298 conf < device->descriptor.bNumConfigurations;
299 conf ++, confptr ++)
300 for (iface = 0, ifaceptr = confptr->interface;
301 iface < confptr->bNumInterfaces;
302 iface ++, ifaceptr ++)
303 {
304 /*
305 * Some printers offer multiple interfaces...
306 */
307
308 protocol = 0;
309
310 for (altset = 0, altptr = ifaceptr->altsetting;
311 altset < ifaceptr->num_altsetting;
312 altset ++, altptr ++)
313 {
314 /*
315 * Currently we only support unidirectional and bidirectional
316 * printers. Future versions of this code will support the
317 * 1284.4 (packet mode) protocol as well.
318 */
319
320 if (altptr->bInterfaceClass != USB_CLASS_PRINTER ||
321 altptr->bInterfaceSubClass != 1 ||
322 (altptr->bInterfaceProtocol != 1 && /* Unidirectional */
323 altptr->bInterfaceProtocol != 2) || /* Bidirectional */
324 altptr->bInterfaceProtocol < protocol)
325 continue;
326
327 read_endp = -1;
328 write_endp = -1;
329
330 for (endp = 0, endpptr = altptr->endpoint;
331 endp < altptr->bNumEndpoints;
332 endp ++, endpptr ++)
333 if ((endpptr->bmAttributes & USB_ENDPOINT_TYPE_MASK) ==
334 USB_ENDPOINT_TYPE_BULK)
335 {
336 if (endpptr->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
337 read_endp = endp;
338 else
339 write_endp = endp;
340 }
341
342 if (write_endp >= 0)
343 {
344 /*
345 * Save the best match so far...
346 */
347
348 protocol = altptr->bInterfaceProtocol;
349 printer.altset = altset;
350 printer.write_endp = write_endp;
351 printer.read_endp = read_endp;
352 }
353 }
354
355 if (protocol > 0)
356 {
357 printer.device = device;
358 printer.conf = conf;
359 printer.iface = iface;
360 printer.handle = NULL;
361
362 if (!open_device(&printer, data != NULL))
363 {
364 if (!get_device_id(&printer, device_id, sizeof(device_id)))
365 {
366 make_device_uri(&printer, device_id, device_uri,
367 sizeof(device_uri));
368
369 if ((*cb)(&printer, device_uri, device_id, data))
005dd1eb
MS
370 {
371 printer.read_endp = printer.device->config[printer.conf].
372 interface[printer.iface].
373 altsetting[printer.altset].
374 endpoint[printer.read_endp].
375 bEndpointAddress;
376 printer.write_endp = printer.device->config[printer.conf].
377 interface[printer.iface].
378 altsetting[printer.altset].
379 endpoint[printer.write_endp].
380 bEndpointAddress;
75bd9771 381 return (&printer);
005dd1eb 382 }
75bd9771
MS
383 }
384
385 close_device(&printer);
386 }
387 }
388 }
389 }
390
391 /*
392 * If we get this far without returning, then we haven't found a printer
393 * to print to...
394 */
395
396 return (NULL);
397}
398
399
400/*
401 * 'get_device_id()' - Get the IEEE-1284 device ID for the printer.
402 */
403
404static int /* O - 0 on success, -1 on error */
405get_device_id(usb_printer_t *printer, /* I - Printer */
406 char *buffer, /* I - String buffer */
407 size_t bufsize) /* I - Number of bytes in buffer */
408{
409 int length; /* Length of device ID */
410
411
412 if (usb_control_msg(printer->handle,
413 USB_TYPE_CLASS | USB_ENDPOINT_IN | USB_RECIP_INTERFACE,
e4572d57 414 0, printer->conf, printer->iface,
75bd9771
MS
415 buffer, bufsize, 5000) < 0)
416 {
417 *buffer = '\0';
418 return (-1);
419 }
420
421 /*
422 * Extract the length of the device ID string from the first two
423 * bytes. The 1284 spec says the length is stored MSB first...
424 */
425
426 length = (((unsigned)buffer[0] & 255) << 8) +
427 ((unsigned)buffer[1] & 255);
428
429 /*
430 * Check to see if the length is larger than our buffer; first
431 * assume that the vendor incorrectly implemented the 1284 spec,
432 * and then limit the length to the size of our buffer...
433 */
434
ee6ddad2 435 if (length > bufsize)
75bd9771
MS
436 length = (((unsigned)buffer[1] & 255) << 8) +
437 ((unsigned)buffer[0] & 255);
438
ee6ddad2
MS
439 if (length > bufsize)
440 length = bufsize;
441
442 length -= 2;
75bd9771
MS
443
444 /*
445 * Copy the device ID text to the beginning of the buffer and
446 * nul-terminate.
447 */
448
449 memmove(buffer, buffer + 2, length);
450 buffer[length] = '\0';
451
452 return (0);
453}
454
455
456/*
457 * 'list_cb()' - List USB printers for discovery.
458 */
459
460static int /* O - 0 to continue, 1 to stop */
461list_cb(usb_printer_t *printer, /* I - Printer */
462 const char *device_uri, /* I - Device URI */
463 const char *device_id, /* I - IEEE-1284 device ID */
464 const void *data) /* I - User data (not used) */
465{
466 char make_model[1024]; /* Make and model */
467
468
469 /*
470 * Get the device URI and make/model strings...
471 */
472
473 backendGetMakeModel(device_id, make_model, sizeof(make_model));
474
475 /*
476 * Report the printer...
477 */
478
749b1e90
MS
479 cupsBackendReport("direct", device_uri, make_model, make_model, device_id,
480 NULL);
75bd9771
MS
481
482 /*
483 * Keep going...
484 */
485
486 return (0);
487}
488
489
490/*
491 * 'make_device_uri()' - Create a device URI for a USB printer.
492 */
493
494static char * /* O - Device URI */
495make_device_uri(
496 usb_printer_t *printer, /* I - Printer */
497 const char *device_id, /* I - IEEE-1284 device ID */
498 char *uri, /* I - Device URI buffer */
499 size_t uri_size) /* I - Size of device URI buffer */
500{
501 char options[1024]; /* Device URI options */
502 int num_values; /* Number of 1284 parameters */
503 cups_option_t *values; /* 1284 parameters */
504 const char *mfg, /* Manufacturer */
505 *mdl, /* Model */
506 *des, /* Description */
507 *sern; /* Serial number */
508 char tempmfg[256], /* Temporary manufacturer string */
509 tempsern[256], /* Temporary serial number string */
510 *tempptr; /* Pointer into temp string */
511
512
513 /*
514 * Get the make, model, and serial numbers...
515 */
516
517 num_values = _ppdGet1284Values(device_id, &values);
518
519 if ((sern = cupsGetOption("SERIALNUMBER", num_values, values)) == NULL)
520 if ((sern = cupsGetOption("SERN", num_values, values)) == NULL)
521 if ((sern = cupsGetOption("SN", num_values, values)) == NULL)
522 {
523 /*
524 * Try getting the serial number from the device itself...
525 */
526
527 int length = usb_get_string_simple(printer->handle,
528 printer->device->descriptor.
529 iSerialNumber,
530 tempsern, sizeof(tempsern) - 1);
531 if (length > 0)
532 {
533 tempsern[length] = '\0';
534 sern = tempsern;
535 }
536 }
537
538 if ((mfg = cupsGetOption("MANUFACTURER", num_values, values)) == NULL)
539 mfg = cupsGetOption("MFG", num_values, values);
540
541 if ((mdl = cupsGetOption("MODEL", num_values, values)) == NULL)
542 mdl = cupsGetOption("MDL", num_values, values);
543
544#ifdef __APPLE__
545 /*
546 * To maintain compatibility with the original IOKit-based backend on Mac OS X,
547 * don't map manufacturer names...
548 */
549
550 if (!mfg)
551
552#else
553 /*
554 * To maintain compatibility with the original character device backend on
555 * Linux and *BSD, map manufacturer names...
556 */
557
558 if (mfg)
559 {
560 if (!strcasecmp(mfg, "Hewlett-Packard"))
561 mfg = "HP";
562 else if (!strcasecmp(mfg, "Lexmark International"))
563 mfg = "Lexmark";
564 }
565 else
566#endif /* __APPLE__ */
567 {
568 /*
569 * No manufacturer? Use the model string or description...
570 */
571
572 if (mdl)
573 _ppdNormalizeMakeAndModel(mdl, tempmfg, sizeof(tempmfg));
574 else if ((des = cupsGetOption("DESCRIPTION", num_values, values)) != NULL ||
575 (des = cupsGetOption("DES", num_values, values)) != NULL)
576 _ppdNormalizeMakeAndModel(des, tempmfg, sizeof(tempmfg));
577 else
578 strlcpy(tempmfg, "Unknown", sizeof(tempmfg));
579
580 if ((tempptr = strchr(tempmfg, ' ')) != NULL)
581 *tempptr = '\0';
582
583 mfg = tempmfg;
584 }
585
586 /*
587 * Generate the device URI from the manufacturer, model, serial number,
588 * and interface number...
589 */
590
591 if (sern)
592 {
593 if (printer->iface > 0)
594 snprintf(options, sizeof(options), "?serial=%s&interface=%d", sern,
595 printer->iface);
596 else
597 snprintf(options, sizeof(options), "?serial=%s", sern);
598 }
599 else if (printer->iface > 0)
600 snprintf(options, sizeof(options), "?interface=%d", printer->iface);
601 else
602 options[0] = '\0';
603
604 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, uri_size, "usb", NULL, mfg, 0,
605 "/%s%s", mdl, options);
606
607 cupsFreeOptions(num_values, values);
608
609 return (uri);
610}
611
612
613/*
614 * 'open_device()' - Open a connection to the USB printer.
615 */
616
617static int /* O - 0 on success, -1 on error */
618open_device(usb_printer_t *printer, /* I - Printer */
619 int verbose) /* I - Update connecting-to-device state? */
620{
621 int number; /* Configuration/interface/altset numbers */
622
623
624 /*
625 * Return immediately if we are already connected...
626 */
627
628 if (printer->handle)
629 return (0);
630
631 /*
632 * Try opening the printer...
633 */
634
635 if ((printer->handle = usb_open(printer->device)) == NULL)
636 return (-1);
637
638 /*
639 * Then set the desired configuration...
640 */
641
642 if (verbose)
643 fputs("STATE: +connecting-to-device\n", stderr);
644
645 number = printer->device->config[printer->conf].bConfigurationValue;
e4572d57
MS
646
647 if (usb_set_configuration(printer->handle, number) < 0)
75bd9771 648 {
e4572d57
MS
649 /*
650 * If the set fails, chances are that the printer only supports a
651 * single configuration. Technically these printers don't conform to
652 * the USB printer specification, but otherwise they'll work...
653 */
654
75bd9771
MS
655 if (errno != EBUSY)
656 fprintf(stderr, "DEBUG: Failed to set configuration %d for %04x:%04x\n",
657 number, printer->device->descriptor.idVendor,
658 printer->device->descriptor.idProduct);
75bd9771
MS
659 }
660
661 /*
662 * Claim interfaces as needed...
663 */
664
665 number = printer->device->config[printer->conf].interface[printer->iface].
666 altsetting[printer->altset].bInterfaceNumber;
667 while (usb_claim_interface(printer->handle, number) < 0)
668 {
669 if (errno != EBUSY)
e4572d57 670 fprintf(stderr, "DEBUG: Failed to claim interface %d for %04x:%04x: %s\n",
75bd9771 671 number, printer->device->descriptor.idVendor,
e4572d57 672 printer->device->descriptor.idProduct, strerror(errno));
75bd9771
MS
673
674 goto error;
675 }
676
677 if (number != 0)
678 while (usb_claim_interface(printer->handle, 0) < 0)
679 {
680 if (errno != EBUSY)
e4572d57 681 fprintf(stderr, "DEBUG: Failed to claim interface 0 for %04x:%04x: %s\n",
75bd9771 682 printer->device->descriptor.idVendor,
e4572d57 683 printer->device->descriptor.idProduct, strerror(errno));
75bd9771
MS
684
685 goto error;
686 }
687
688 /*
689 * Set alternate setting...
690 */
691
692 number = printer->device->config[printer->conf].interface[printer->iface].
693 altsetting[printer->altset].bAlternateSetting;
694 while (usb_set_altinterface(printer->handle, number) < 0)
695 {
696 if (errno != EBUSY)
697 fprintf(stderr,
e4572d57 698 "DEBUG: Failed to set alternate interface %d for %04x:%04x: %s\n",
75bd9771 699 number, printer->device->descriptor.idVendor,
e4572d57 700 printer->device->descriptor.idProduct, strerror(errno));
75bd9771
MS
701
702 goto error;
703 }
704
705 if (verbose)
706 fputs("STATE: -connecting-to-device\n", stderr);
707
708 return (0);
709
710 /*
711 * If we get here, there was a hard error...
712 */
713
714 error:
715
716 if (verbose)
717 fputs("STATE: -connecting-to-device\n", stderr);
718
719 usb_close(printer->handle);
720 printer->handle = NULL;
721
722 return (-1);
723}
724
725
726/*
727 * 'print_cb()' - Find a USB printer for printing.
728 */
729
730static int /* O - 0 to continue, 1 to stop (found) */
731print_cb(usb_printer_t *printer, /* I - Printer */
732 const char *device_uri, /* I - Device URI */
733 const char *device_id, /* I - IEEE-1284 device ID */
734 const void *data) /* I - User data (make, model, S/N) */
735{
736 return (!strcmp((char *)data, device_uri));
737}
738
739
005dd1eb
MS
740/*
741 * 'side_cb()' - Handle side-channel requests.
742 */
743
744static ssize_t /* O - Number of bytes written */
745side_cb(usb_printer_t *printer, /* I - Printer */
746 int print_fd) /* I - File to print */
747{
748 ssize_t bytes, /* Bytes read/written */
749 tbytes; /* Total bytes written */
750 char buffer[8192]; /* Print data buffer */
751 struct pollfd pfd; /* Poll descriptor */
752 cups_sc_command_t command; /* Request command */
753 cups_sc_status_t status; /* Request/response status */
754 char data[2048]; /* Request/response data */
755 int datalen; /* Request/response data size */
756
757
758 tbytes = 0;
759 datalen = sizeof(data);
760
761 if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
18ecb428 762 return (-1);
005dd1eb
MS
763
764 switch (command)
765 {
766 case CUPS_SC_CMD_DRAIN_OUTPUT :
767 pfd.fd = print_fd;
768 pfd.events = POLLIN;
769
770 while (poll(&pfd, 1, 1000) > 0)
771 {
772 if ((bytes = read(print_fd, buffer, sizeof(buffer))) > 0)
773 {
774 while (usb_bulk_write(printer->handle, printer->write_endp, buffer,
775 bytes, 5000) < 0)
776 {
777 _cupsLangPrintf(stderr,
4d301e69 778 _("ERROR: Unable to write %d bytes to printer\n"),
005dd1eb
MS
779 (int)bytes);
780 tbytes = -1;
781 break;
782 }
783
784 tbytes += bytes;
785 }
786 else if (bytes < 0 && errno != EAGAIN && errno != EINTR)
787 break;
788 }
789
790 if (tbytes < 0)
791 status = CUPS_SC_STATUS_IO_ERROR;
792 else
793 status = CUPS_SC_STATUS_OK;
794
795 datalen = 0;
796 break;
797
798 case CUPS_SC_CMD_GET_BIDI :
8b450588 799 status = CUPS_SC_STATUS_OK;
005dd1eb
MS
800 data[0] = 0; /* TODO: Change to 1 when read supported */
801 datalen = 1;
802 break;
803
804 case CUPS_SC_CMD_GET_DEVICE_ID :
805 if (get_device_id(printer, data, sizeof(data)))
806 {
807 status = CUPS_SC_STATUS_IO_ERROR;
808 datalen = 0;
809 }
810 else
811 {
812 status = CUPS_SC_STATUS_OK;
813 datalen = strlen(data);
814 }
815 break;
816
817 default :
818 status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
819 datalen = 0;
820 break;
821 }
822
823 cupsSideChannelWrite(command, status, data, datalen, 1.0);
824
825 return (tbytes);
826}
827
828
75bd9771
MS
829/*
830 * End of "$Id$".
831 */
832