2 * USB port backend for CUPS.
4 * This file is included from "usb.c" when compiled on UNIX/Linux.
6 * Copyright © 2020-2024 by OpenPrinting.
7 * Copyright © 2007-2013 by Apple Inc.
8 * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
10 * Licensed under Apache License v2.0. See the file "LICENSE" for more
15 * Include necessary headers.
18 #include <sys/select.h>
25 static int open_device(const char *uri
, int *use_bc
);
26 static int side_cb(int print_fd
, int device_fd
, int snmp_fd
,
27 http_addr_t
*addr
, int use_bc
);
31 * 'print_device()' - Print a file to a USB device.
34 int /* O - Exit status */
35 print_device(const char *uri
, /* I - Device URI */
36 const char *hostname
, /* I - Hostname/manufacturer */
37 const char *resource
, /* I - Resource/modelname */
38 char *options
, /* I - Device options/serial number */
39 int print_fd
, /* I - File descriptor to print */
40 int copies
, /* I - Copies to print */
41 int argc
, /* I - Number of command-line arguments (6 or 7) */
42 char *argv
[]) /* I - Command-line arguments */
44 int use_bc
; /* Use backchannel path? */
45 int device_fd
; /* USB device */
46 ssize_t tbytes
; /* Total number of bytes written */
47 struct termios opts
; /* Parallel port options */
54 * Open the USB port device...
57 fputs("STATE: +connecting-to-device\n", stderr
);
61 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
63 * *BSD's ulpt driver currently does not support the
64 * back-channel, incorrectly returns data ready on a select(),
65 * and locks up on read()...
72 * CUPS STR #3028: Solaris' usbprn driver apparently does not support
73 * select() or poll(), so we can't support backchannel...
80 * Disable backchannel data when printing to Brother, Canon, or
81 * Minolta USB printers - apparently these printers will return
82 * the IEEE-1284 device ID over and over and over when they get
86 use_bc
= _cups_strcasecmp(hostname
, "Brother") &&
87 _cups_strcasecmp(hostname
, "Canon") &&
88 _cups_strncasecmp(hostname
, "Konica", 6) &&
89 _cups_strncasecmp(hostname
, "Minolta", 7);
90 #endif /* __FreeBSD__ || __NetBSD__ || __OpenBSD__ || __DragonFly__ */
92 if ((device_fd
= open_device(uri
, &use_bc
)) == -1)
94 if (getenv("CLASS") != NULL
)
97 * If the CLASS environment variable is set, the job was submitted
98 * to a class and not to a specific queue. In this case, we want
99 * to abort immediately so that the job can be requeued on the next
100 * available printer in the class.
103 _cupsLangPrintFilter(stderr
, "INFO",
104 _("Unable to contact printer, queuing on next "
105 "printer in class."));
108 * Sleep 5 seconds to keep the job from requeuing too rapidly...
113 return (CUPS_BACKEND_FAILED
);
118 _cupsLangPrintFilter(stderr
, "INFO", _("The printer is in use."));
121 else if (errno
== ENXIO
|| errno
== EIO
|| errno
== ENOENT
||
128 _cupsLangPrintError("ERROR", _("Unable to open device file"));
129 return (CUPS_BACKEND_FAILED
);
133 while (device_fd
< 0);
135 fputs("STATE: -connecting-to-device\n", stderr
);
138 * Set any options provided...
141 tcgetattr(device_fd
, &opts
);
143 opts
.c_lflag
&= ~(unsigned)(ICANON
| ECHO
| ISIG
); /* Raw mode */
145 /**** No options supported yet ****/
147 tcsetattr(device_fd
, TCSANOW
, &opts
);
150 * Finally, send the print file...
155 while (copies
> 0 && tbytes
>= 0)
161 fputs("PAGE: 1 1\n", stderr
);
162 lseek(print_fd
, 0, SEEK_SET
);
167 * CUPS STR #3028: Solaris' usbprn driver apparently does not support
168 * select() or poll(), so we can't support the sidechannel either...
171 tbytes
= backendRunLoop(print_fd
, device_fd
, -1, NULL
, use_bc
, 1, NULL
);
174 tbytes
= backendRunLoop(print_fd
, device_fd
, -1, NULL
, use_bc
, 1, side_cb
);
177 if (print_fd
!= 0 && tbytes
>= 0)
178 _cupsLangPrintFilter(stderr
, "INFO", _("Print file sent."));
182 * Close the USB port and return...
187 return (CUPS_BACKEND_OK
);
192 * 'list_devices()' - List all USB devices.
199 int i
; /* Looping var */
200 int fd
; /* File descriptor */
201 char device
[255], /* Device filename */
202 device_id
[1024], /* Device ID string */
203 device_uri
[1024], /* Device URI string */
204 make_model
[1024]; /* Make and model */
208 * Try to open each USB device...
211 for (i
= 0; i
< 16; i
++)
214 * Linux has a long history of changing the standard filenames used
215 * for USB printer devices. We get the honor of trying them all...
218 snprintf(device
, sizeof(device
), "/dev/usblp%d", i
);
220 if ((fd
= open(device
, O_RDWR
| O_EXCL
)) < 0)
225 snprintf(device
, sizeof(device
), "/dev/usb/lp%d", i
);
227 if ((fd
= open(device
, O_RDWR
| O_EXCL
)) < 0)
232 snprintf(device
, sizeof(device
), "/dev/usb/usblp%d", i
);
234 if ((fd
= open(device
, O_RDWR
| O_EXCL
)) < 0)
239 if (!backendGetDeviceID(fd
, device_id
, sizeof(device_id
),
240 make_model
, sizeof(make_model
),
241 "usb", device_uri
, sizeof(device_uri
)))
242 cupsBackendReport("direct", device_uri
, make_model
, make_model
,
247 #elif defined(__sun) && defined(ECPPIOC_GETDEVID)
248 int i
; /* Looping var */
249 int fd
; /* File descriptor */
250 char device
[255], /* Device filename */
251 device_id
[1024], /* Device ID string */
252 device_uri
[1024], /* Device URI string */
253 make_model
[1024]; /* Make and model */
257 * Open each USB device...
260 for (i
= 0; i
< 8; i
++)
262 snprintf(device
, sizeof(device
), "/dev/usb/printer%d", i
);
264 if ((fd
= open(device
, O_WRONLY
| O_EXCL
)) >= 0)
266 if (!backendGetDeviceID(fd
, device_id
, sizeof(device_id
),
267 make_model
, sizeof(make_model
),
268 "usb", device_uri
, sizeof(device_uri
)))
269 cupsBackendReport("direct", device_uri
, make_model
, make_model
,
275 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
276 int i
; /* Looping var */
277 char device
[255]; /* Device filename */
280 for (i
= 0; i
< 8; i
++)
282 snprintf(device
, sizeof(device
), "/dev/ulpt%d", i
);
283 if (!access(device
, 0))
284 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device
, i
+ 1);
286 snprintf(device
, sizeof(device
), "/dev/unlpt%d", i
);
287 if (!access(device
, 0))
288 printf("direct usb:%s \"Unknown\" \"USB Printer #%d (no reset)\"\n", device
, i
+ 1);
295 * 'open_device()' - Open a USB device...
298 static int /* O - File descriptor or -1 on error */
299 open_device(const char *uri
, /* I - Device URI */
300 int *use_bc
) /* O - Set to 0 for unidirectional */
302 int fd
; /* File descriptor */
306 * The generic implementation just treats the URI as a device filename...
307 * Specific operating systems may also support using the device serial
308 * number and/or make/model.
311 if (!strncmp(uri
, "usb:/dev/", 9))
315 * Do not allow direct devices anymore...
321 else if (!strncmp(uri
, "usb://", 6))
324 * For Linux, try looking up the device serial number or model...
327 int i
; /* Looping var */
328 int busy
; /* Are any ports busy? */
329 char device
[255], /* Device filename */
330 device_id
[1024], /* Device ID string */
331 make_model
[1024], /* Make and model */
332 device_uri
[1024]; /* Device URI string */
336 * Find the correct USB device...
341 for (busy
= 0, i
= 0; i
< 16; i
++)
344 * Linux has a long history of changing the standard filenames used
345 * for USB printer devices. We get the honor of trying them all...
348 snprintf(device
, sizeof(device
), "/dev/usblp%d", i
);
350 if ((fd
= open(device
, O_RDWR
| O_EXCL
)) < 0 && errno
== ENOENT
)
352 snprintf(device
, sizeof(device
), "/dev/usb/lp%d", i
);
354 if ((fd
= open(device
, O_RDWR
| O_EXCL
)) < 0 && errno
== ENOENT
)
356 snprintf(device
, sizeof(device
), "/dev/usb/usblp%d", i
);
358 if ((fd
= open(device
, O_RDWR
| O_EXCL
)) < 0 && errno
== ENOENT
)
365 backendGetDeviceID(fd
, device_id
, sizeof(device_id
),
366 make_model
, sizeof(make_model
),
367 "usb", device_uri
, sizeof(device_uri
));
372 * If the open failed because it was busy, flag it so we retry
379 device_uri
[0] = '\0';
382 if (!strcmp(uri
, device_uri
))
385 * Yes, return this file descriptor...
388 fprintf(stderr
, "DEBUG: Printer using device file \"%s\"...\n",
395 * This wasn't the one...
403 * If we get here and at least one of the printer ports showed up
404 * as "busy", then sleep for a bit and retry...
408 _cupsLangPrintFilter(stderr
, "INFO", _("The printer is in use."));
413 #elif defined(__sun) && defined(ECPPIOC_GETDEVID)
416 * Do not allow direct devices anymore...
422 else if (!strncmp(uri
, "usb://", 6))
425 * For Solaris, try looking up the device serial number or model...
428 int i
; /* Looping var */
429 int busy
; /* Are any ports busy? */
430 char device
[255], /* Device filename */
431 device_id
[1024], /* Device ID string */
432 make_model
[1024], /* Make and model */
433 device_uri
[1024]; /* Device URI string */
437 * Find the correct USB device...
442 for (i
= 0, busy
= 0; i
< 8; i
++)
444 snprintf(device
, sizeof(device
), "/dev/usb/printer%d", i
);
446 if ((fd
= open(device
, O_WRONLY
| O_EXCL
)) >= 0)
447 backendGetDeviceID(fd
, device_id
, sizeof(device_id
),
448 make_model
, sizeof(make_model
),
449 "usb", device_uri
, sizeof(device_uri
));
453 * If the open failed because it was busy, flag it so we retry
460 device_uri
[0] = '\0';
463 if (!strcmp(uri
, device_uri
))
466 * Yes, return this file descriptor...
469 fputs("DEBUG: Setting use_bc to 0!\n", stderr
);
477 * This wasn't the one...
485 * If we get here and at least one of the printer ports showed up
486 * as "busy", then sleep for a bit and retry...
491 _cupsLangPrintFilter(stderr
, "INFO", _("The printer is in use."));
498 * Couldn't find the printer, return "no such device or address"...
508 fd
= open(uri
+ 4, O_RDWR
| O_EXCL
);
514 fd
= open(uri
+ 4, O_WRONLY
| O_EXCL
);
530 * 'side_cb()' - Handle side-channel requests...
533 static int /* O - 0 on success, -1 on error */
534 side_cb(int print_fd
, /* I - Print file */
535 int device_fd
, /* I - Device file */
536 int snmp_fd
, /* I - SNMP socket (unused) */
537 http_addr_t
*addr
, /* I - Device address (unused) */
538 int use_bc
) /* I - Using back-channel? */
540 cups_sc_command_t command
; /* Request command */
541 cups_sc_status_t status
; /* Request/response status */
542 char data
[2048]; /* Request/response data */
543 int datalen
; /* Request/response data size */
549 datalen
= sizeof(data
);
551 if (cupsSideChannelRead(&command
, &status
, data
, &datalen
, 1.0))
556 case CUPS_SC_CMD_DRAIN_OUTPUT
:
557 if (backendDrainOutput(print_fd
, device_fd
))
558 status
= CUPS_SC_STATUS_IO_ERROR
;
559 else if (tcdrain(device_fd
))
560 status
= CUPS_SC_STATUS_IO_ERROR
;
562 status
= CUPS_SC_STATUS_OK
;
567 case CUPS_SC_CMD_GET_BIDI
:
568 status
= CUPS_SC_STATUS_OK
;
573 case CUPS_SC_CMD_GET_DEVICE_ID
:
574 memset(data
, 0, sizeof(data
));
576 if (backendGetDeviceID(device_fd
, data
, sizeof(data
) - 1,
577 NULL
, 0, NULL
, NULL
, 0))
579 status
= CUPS_SC_STATUS_NOT_IMPLEMENTED
;
584 status
= CUPS_SC_STATUS_OK
;
585 datalen
= strlen(data
);
590 status
= CUPS_SC_STATUS_NOT_IMPLEMENTED
;
595 return (cupsSideChannelWrite(command
, status
, data
, datalen
, 1.0));