]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/usb-unix.c
41a56062ada3b5b342f42ea762027ab58a8d05a1
[thirdparty/cups.git] / backend / usb-unix.c
1 /*
2 * USB port backend for CUPS.
3 *
4 * This file is included from "usb.c" when compiled on UNIX/Linux.
5 *
6 * Copyright 2007-2013 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
8 *
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/".
14 *
15 * This file is subject to the Apple OS-Developed Software exception.
16 */
17
18 /*
19 * Include necessary headers.
20 */
21
22 #include <sys/select.h>
23
24
25 /*
26 * Local functions...
27 */
28
29 static int open_device(const char *uri, int *use_bc);
30 static int side_cb(int print_fd, int device_fd, int snmp_fd,
31 http_addr_t *addr, int use_bc);
32
33
34 /*
35 * 'print_device()' - Print a file to a USB device.
36 */
37
38 int /* O - Exit status */
39 print_device(const char *uri, /* I - Device URI */
40 const char *hostname, /* I - Hostname/manufacturer */
41 const char *resource, /* I - Resource/modelname */
42 char *options, /* I - Device options/serial number */
43 int print_fd, /* I - File descriptor to print */
44 int copies, /* I - Copies to print */
45 int argc, /* I - Number of command-line arguments (6 or 7) */
46 char *argv[]) /* I - Command-line arguments */
47 {
48 int use_bc; /* Use backchannel path? */
49 int device_fd; /* USB device */
50 ssize_t tbytes; /* Total number of bytes written */
51 struct termios opts; /* Parallel port options */
52
53
54 (void)argc;
55 (void)argv;
56
57 /*
58 * Open the USB port device...
59 */
60
61 fputs("STATE: +connecting-to-device\n", stderr);
62
63 do
64 {
65 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
66 /*
67 * *BSD's ulpt driver currently does not support the
68 * back-channel, incorrectly returns data ready on a select(),
69 * and locks up on read()...
70 */
71
72 use_bc = 0;
73
74 #elif defined(__sun)
75 /*
76 * CUPS STR #3028: Solaris' usbprn driver apparently does not support
77 * select() or poll(), so we can't support backchannel...
78 */
79
80 use_bc = 0;
81
82 #else
83 /*
84 * Disable backchannel data when printing to Brother, Canon, or
85 * Minolta USB printers - apparently these printers will return
86 * the IEEE-1284 device ID over and over and over when they get
87 * a read request...
88 */
89
90 use_bc = _cups_strcasecmp(hostname, "Brother") &&
91 _cups_strcasecmp(hostname, "Canon") &&
92 _cups_strncasecmp(hostname, "Konica", 6) &&
93 _cups_strncasecmp(hostname, "Minolta", 7);
94 #endif /* __FreeBSD__ || __NetBSD__ || __OpenBSD__ || __DragonFly__ */
95
96 if ((device_fd = open_device(uri, &use_bc)) == -1)
97 {
98 if (getenv("CLASS") != NULL)
99 {
100 /*
101 * If the CLASS environment variable is set, the job was submitted
102 * to a class and not to a specific queue. In this case, we want
103 * to abort immediately so that the job can be requeued on the next
104 * available printer in the class.
105 */
106
107 _cupsLangPrintFilter(stderr, "INFO",
108 _("Unable to contact printer, queuing on next "
109 "printer in class."));
110
111 /*
112 * Sleep 5 seconds to keep the job from requeuing too rapidly...
113 */
114
115 sleep(5);
116
117 return (CUPS_BACKEND_FAILED);
118 }
119
120 if (errno == EBUSY)
121 {
122 _cupsLangPrintFilter(stderr, "INFO", _("The printer is in use."));
123 sleep(10);
124 }
125 else if (errno == ENXIO || errno == EIO || errno == ENOENT ||
126 errno == ENODEV)
127 {
128 sleep(30);
129 }
130 else
131 {
132 _cupsLangPrintError("ERROR", _("Unable to open device file"));
133 return (CUPS_BACKEND_FAILED);
134 }
135 }
136 }
137 while (device_fd < 0);
138
139 fputs("STATE: -connecting-to-device\n", stderr);
140
141 /*
142 * Set any options provided...
143 */
144
145 tcgetattr(device_fd, &opts);
146
147 opts.c_lflag &= ~(unsigned)(ICANON | ECHO | ISIG); /* Raw mode */
148
149 /**** No options supported yet ****/
150
151 tcsetattr(device_fd, TCSANOW, &opts);
152
153 /*
154 * Finally, send the print file...
155 */
156
157 tbytes = 0;
158
159 while (copies > 0 && tbytes >= 0)
160 {
161 copies --;
162
163 if (print_fd != 0)
164 {
165 fputs("PAGE: 1 1\n", stderr);
166 lseek(print_fd, 0, SEEK_SET);
167 }
168
169 #ifdef __sun
170 /*
171 * CUPS STR #3028: Solaris' usbprn driver apparently does not support
172 * select() or poll(), so we can't support the sidechannel either...
173 */
174
175 tbytes = backendRunLoop(print_fd, device_fd, -1, NULL, use_bc, 1, NULL);
176
177 #else
178 tbytes = backendRunLoop(print_fd, device_fd, -1, NULL, use_bc, 1, side_cb);
179 #endif /* __sun */
180
181 if (print_fd != 0 && tbytes >= 0)
182 _cupsLangPrintFilter(stderr, "INFO", _("Print file sent."));
183 }
184
185 /*
186 * Close the USB port and return...
187 */
188
189 close(device_fd);
190
191 return (CUPS_BACKEND_OK);
192 }
193
194
195 /*
196 * 'list_devices()' - List all USB devices.
197 */
198
199 void
200 list_devices(void)
201 {
202 #ifdef __linux
203 int i; /* Looping var */
204 int fd; /* File descriptor */
205 char device[255], /* Device filename */
206 device_id[1024], /* Device ID string */
207 device_uri[1024], /* Device URI string */
208 make_model[1024]; /* Make and model */
209
210
211 /*
212 * Try to open each USB device...
213 */
214
215 for (i = 0; i < 16; i ++)
216 {
217 /*
218 * Linux has a long history of changing the standard filenames used
219 * for USB printer devices. We get the honor of trying them all...
220 */
221
222 sprintf(device, "/dev/usblp%d", i);
223
224 if ((fd = open(device, O_RDWR | O_EXCL)) < 0)
225 {
226 if (errno != ENOENT)
227 continue;
228
229 sprintf(device, "/dev/usb/lp%d", i);
230
231 if ((fd = open(device, O_RDWR | O_EXCL)) < 0)
232 {
233 if (errno != ENOENT)
234 continue;
235
236 sprintf(device, "/dev/usb/usblp%d", i);
237
238 if ((fd = open(device, O_RDWR | O_EXCL)) < 0)
239 continue;
240 }
241 }
242
243 if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
244 make_model, sizeof(make_model),
245 "usb", device_uri, sizeof(device_uri)))
246 cupsBackendReport("direct", device_uri, make_model, make_model,
247 device_id, NULL);
248
249 close(fd);
250 }
251 #elif defined(__sun) && defined(ECPPIOC_GETDEVID)
252 int i; /* Looping var */
253 int fd; /* File descriptor */
254 char device[255], /* Device filename */
255 device_id[1024], /* Device ID string */
256 device_uri[1024], /* Device URI string */
257 make_model[1024]; /* Make and model */
258
259
260 /*
261 * Open each USB device...
262 */
263
264 for (i = 0; i < 8; i ++)
265 {
266 sprintf(device, "/dev/usb/printer%d", i);
267
268 if ((fd = open(device, O_WRONLY | O_EXCL)) >= 0)
269 {
270 if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
271 make_model, sizeof(make_model),
272 "usb", device_uri, sizeof(device_uri)))
273 cupsBackendReport("direct", device_uri, make_model, make_model,
274 device_id, NULL);
275
276 close(fd);
277 }
278 }
279 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
280 int i; /* Looping var */
281 char device[255]; /* Device filename */
282
283
284 for (i = 0; i < 8; i ++)
285 {
286 sprintf(device, "/dev/ulpt%d", i);
287 if (!access(device, 0))
288 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
289
290 sprintf(device, "/dev/unlpt%d", i);
291 if (!access(device, 0))
292 printf("direct usb:%s \"Unknown\" \"USB Printer #%d (no reset)\"\n", device, i + 1);
293 }
294 #endif
295 }
296
297
298 /*
299 * 'open_device()' - Open a USB device...
300 */
301
302 static int /* O - File descriptor or -1 on error */
303 open_device(const char *uri, /* I - Device URI */
304 int *use_bc) /* O - Set to 0 for unidirectional */
305 {
306 int fd; /* File descriptor */
307
308
309 /*
310 * The generic implementation just treats the URI as a device filename...
311 * Specific operating systems may also support using the device serial
312 * number and/or make/model.
313 */
314
315 if (!strncmp(uri, "usb:/dev/", 9))
316 #ifdef __linux
317 {
318 /*
319 * Do not allow direct devices anymore...
320 */
321
322 errno = ENODEV;
323 return (-1);
324 }
325 else if (!strncmp(uri, "usb://", 6))
326 {
327 /*
328 * For Linux, try looking up the device serial number or model...
329 */
330
331 int i; /* Looping var */
332 int busy; /* Are any ports busy? */
333 char device[255], /* Device filename */
334 device_id[1024], /* Device ID string */
335 make_model[1024], /* Make and model */
336 device_uri[1024]; /* Device URI string */
337
338
339 /*
340 * Find the correct USB device...
341 */
342
343 for (;;)
344 {
345 for (busy = 0, i = 0; i < 16; i ++)
346 {
347 /*
348 * Linux has a long history of changing the standard filenames used
349 * for USB printer devices. We get the honor of trying them all...
350 */
351
352 sprintf(device, "/dev/usblp%d", i);
353
354 if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT)
355 {
356 sprintf(device, "/dev/usb/lp%d", i);
357
358 if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT)
359 {
360 sprintf(device, "/dev/usb/usblp%d", i);
361
362 if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT)
363 continue;
364 }
365 }
366
367 if (fd >= 0)
368 {
369 backendGetDeviceID(fd, device_id, sizeof(device_id),
370 make_model, sizeof(make_model),
371 "usb", device_uri, sizeof(device_uri));
372 }
373 else
374 {
375 /*
376 * If the open failed because it was busy, flag it so we retry
377 * as needed...
378 */
379
380 if (errno == EBUSY)
381 busy = 1;
382
383 device_uri[0] = '\0';
384 }
385
386 if (!strcmp(uri, device_uri))
387 {
388 /*
389 * Yes, return this file descriptor...
390 */
391
392 fprintf(stderr, "DEBUG: Printer using device file \"%s\"...\n",
393 device);
394
395 return (fd);
396 }
397
398 /*
399 * This wasn't the one...
400 */
401
402 if (fd >= 0)
403 close(fd);
404 }
405
406 /*
407 * If we get here and at least one of the printer ports showed up
408 * as "busy", then sleep for a bit and retry...
409 */
410
411 if (busy)
412 _cupsLangPrintFilter(stderr, "INFO", _("The printer is in use."));
413
414 sleep(5);
415 }
416 }
417 #elif defined(__sun) && defined(ECPPIOC_GETDEVID)
418 {
419 /*
420 * Do not allow direct devices anymore...
421 */
422
423 errno = ENODEV;
424 return (-1);
425 }
426 else if (!strncmp(uri, "usb://", 6))
427 {
428 /*
429 * For Solaris, try looking up the device serial number or model...
430 */
431
432 int i; /* Looping var */
433 int busy; /* Are any ports busy? */
434 char device[255], /* Device filename */
435 device_id[1024], /* Device ID string */
436 make_model[1024], /* Make and model */
437 device_uri[1024]; /* Device URI string */
438
439
440 /*
441 * Find the correct USB device...
442 */
443
444 do
445 {
446 for (i = 0, busy = 0; i < 8; i ++)
447 {
448 sprintf(device, "/dev/usb/printer%d", i);
449
450 if ((fd = open(device, O_WRONLY | O_EXCL)) >= 0)
451 backendGetDeviceID(fd, device_id, sizeof(device_id),
452 make_model, sizeof(make_model),
453 "usb", device_uri, sizeof(device_uri));
454 else
455 {
456 /*
457 * If the open failed because it was busy, flag it so we retry
458 * as needed...
459 */
460
461 if (errno == EBUSY)
462 busy = 1;
463
464 device_uri[0] = '\0';
465 }
466
467 if (!strcmp(uri, device_uri))
468 {
469 /*
470 * Yes, return this file descriptor...
471 */
472
473 fputs("DEBUG: Setting use_bc to 0!\n", stderr);
474
475 *use_bc = 0;
476
477 return (fd);
478 }
479
480 /*
481 * This wasn't the one...
482 */
483
484 if (fd >= 0)
485 close(fd);
486 }
487
488 /*
489 * If we get here and at least one of the printer ports showed up
490 * as "busy", then sleep for a bit and retry...
491 */
492
493 if (busy)
494 {
495 _cupsLangPrintFilter(stderr, "INFO", _("The printer is in use."));
496 sleep(5);
497 }
498 }
499 while (busy);
500
501 /*
502 * Couldn't find the printer, return "no such device or address"...
503 */
504
505 errno = ENODEV;
506
507 return (-1);
508 }
509 #else
510 {
511 if (*use_bc)
512 fd = open(uri + 4, O_RDWR | O_EXCL);
513 else
514 fd = -1;
515
516 if (fd < 0)
517 {
518 fd = open(uri + 4, O_WRONLY | O_EXCL);
519 *use_bc = 0;
520 }
521
522 return (fd);
523 }
524 #endif /* __linux */
525 else
526 {
527 errno = ENODEV;
528 return (-1);
529 }
530 }
531
532
533 /*
534 * 'side_cb()' - Handle side-channel requests...
535 */
536
537 static int /* O - 0 on success, -1 on error */
538 side_cb(int print_fd, /* I - Print file */
539 int device_fd, /* I - Device file */
540 int snmp_fd, /* I - SNMP socket (unused) */
541 http_addr_t *addr, /* I - Device address (unused) */
542 int use_bc) /* I - Using back-channel? */
543 {
544 cups_sc_command_t command; /* Request command */
545 cups_sc_status_t status; /* Request/response status */
546 char data[2048]; /* Request/response data */
547 int datalen; /* Request/response data size */
548
549
550 (void)snmp_fd;
551 (void)addr;
552
553 datalen = sizeof(data);
554
555 if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
556 return (-1);
557
558 switch (command)
559 {
560 case CUPS_SC_CMD_DRAIN_OUTPUT :
561 if (backendDrainOutput(print_fd, device_fd))
562 status = CUPS_SC_STATUS_IO_ERROR;
563 else if (tcdrain(device_fd))
564 status = CUPS_SC_STATUS_IO_ERROR;
565 else
566 status = CUPS_SC_STATUS_OK;
567
568 datalen = 0;
569 break;
570
571 case CUPS_SC_CMD_GET_BIDI :
572 status = CUPS_SC_STATUS_OK;
573 data[0] = use_bc;
574 datalen = 1;
575 break;
576
577 case CUPS_SC_CMD_GET_DEVICE_ID :
578 memset(data, 0, sizeof(data));
579
580 if (backendGetDeviceID(device_fd, data, sizeof(data) - 1,
581 NULL, 0, NULL, NULL, 0))
582 {
583 status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
584 datalen = 0;
585 }
586 else
587 {
588 status = CUPS_SC_STATUS_OK;
589 datalen = strlen(data);
590 }
591 break;
592
593 default :
594 status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
595 datalen = 0;
596 break;
597 }
598
599 return (cupsSideChannelWrite(command, status, data, datalen, 1.0));
600 }