]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/usb-unix.c
Remove all of the Subversion keywords from various source files.
[thirdparty/cups.git] / backend / usb-unix.c
CommitLineData
ef416fc2 1/*
5a1d7a17 2 * USB port backend for CUPS.
ef416fc2 3 *
5a1d7a17 4 * This file is included from "usb.c" when compiled on UNIX/Linux.
ef416fc2 5 *
5a1d7a17
MS
6 * Copyright 2007-2013 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
ef416fc2 8 *
5a1d7a17
MS
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/".
ef416fc2 14 *
5a1d7a17 15 * This file is subject to the Apple OS-Developed Software exception.
ef416fc2 16 */
17
18/*
19 * Include necessary headers.
20 */
21
ef416fc2 22#include <sys/select.h>
23
24
25/*
26 * Local functions...
27 */
28
f7deaa1a 29static int open_device(const char *uri, int *use_bc);
18ecb428 30static int side_cb(int print_fd, int device_fd, int snmp_fd,
568fa3fa 31 http_addr_t *addr, int use_bc);
ef416fc2 32
33
34/*
35 * 'print_device()' - Print a file to a USB device.
36 */
37
38int /* O - Exit status */
39print_device(const char *uri, /* I - Device URI */
40 const char *hostname, /* I - Hostname/manufacturer */
41 const char *resource, /* I - Resource/modelname */
db1f069b 42 char *options, /* I - Device options/serial number */
ed486911 43 int print_fd, /* I - File descriptor to print */
e53920b9 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 */
ef416fc2 47{
ed486911 48 int use_bc; /* Use backchannel path? */
49 int device_fd; /* USB device */
321d8d57 50 ssize_t tbytes; /* Total number of bytes written */
ef416fc2 51 struct termios opts; /* Parallel port options */
ed486911 52
ef416fc2 53
e53920b9 54 (void)argc;
55 (void)argv;
ef416fc2 56
57 /*
58 * Open the USB port device...
59 */
60
757d2cad 61 fputs("STATE: +connecting-to-device\n", stderr);
62
ef416fc2 63 do
64 {
b94498cf 65#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
323c5de1 66 /*
b94498cf 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()...
323c5de1 70 */
71
72 use_bc = 0;
73
ed6e7faf
MS
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
323c5de1 82#else
8ca02f3c 83 /*
f7deaa1a 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...
8ca02f3c 88 */
89
88f9aafc
MS
90 use_bc = _cups_strcasecmp(hostname, "Brother") &&
91 _cups_strcasecmp(hostname, "Canon") &&
92 _cups_strncasecmp(hostname, "Konica", 6) &&
93 _cups_strncasecmp(hostname, "Minolta", 7);
b94498cf 94#endif /* __FreeBSD__ || __NetBSD__ || __OpenBSD__ || __DragonFly__ */
8ca02f3c 95
96 if ((device_fd = open_device(uri, &use_bc)) == -1)
ef416fc2 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
0837b7e8
MS
107 _cupsLangPrintFilter(stderr, "INFO",
108 _("Unable to contact printer, queuing on next "
109 "printer in class."));
ef416fc2 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 {
f3c17241 122 _cupsLangPrintFilter(stderr, "INFO", _("The printer is in use."));
c0e1af83 123 sleep(10);
ef416fc2 124 }
ed486911 125 else if (errno == ENXIO || errno == EIO || errno == ENOENT ||
126 errno == ENODEV)
ef416fc2 127 {
ef416fc2 128 sleep(30);
129 }
130 else
131 {
c779abb0 132 _cupsLangPrintError("ERROR", _("Unable to open device file"));
ef416fc2 133 return (CUPS_BACKEND_FAILED);
134 }
135 }
136 }
ed486911 137 while (device_fd < 0);
ef416fc2 138
757d2cad 139 fputs("STATE: -connecting-to-device\n", stderr);
140
ef416fc2 141 /*
142 * Set any options provided...
143 */
144
ed486911 145 tcgetattr(device_fd, &opts);
ef416fc2 146
7d5824d6 147 opts.c_lflag &= ~(unsigned)(ICANON | ECHO | ISIG); /* Raw mode */
ef416fc2 148
149 /**** No options supported yet ****/
150
ed486911 151 tcsetattr(device_fd, TCSANOW, &opts);
ef416fc2 152
ef416fc2 153 /*
154 * Finally, send the print file...
155 */
156
ed486911 157 tbytes = 0;
ef416fc2 158
ed486911 159 while (copies > 0 && tbytes >= 0)
ef416fc2 160 {
161 copies --;
162
ed486911 163 if (print_fd != 0)
ef416fc2 164 {
165 fputs("PAGE: 1 1\n", stderr);
ed486911 166 lseek(print_fd, 0, SEEK_SET);
ef416fc2 167 }
168
ed6e7faf
MS
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
ef55b745 175 tbytes = backendRunLoop(print_fd, device_fd, -1, NULL, use_bc, 1, NULL);
ed6e7faf
MS
176
177#else
ef55b745 178 tbytes = backendRunLoop(print_fd, device_fd, -1, NULL, use_bc, 1, side_cb);
ed6e7faf 179#endif /* __sun */
ef416fc2 180
ed486911 181 if (print_fd != 0 && tbytes >= 0)
0837b7e8 182 _cupsLangPrintFilter(stderr, "INFO", _("Print file sent."));
ef416fc2 183 }
184
185 /*
186 * Close the USB port and return...
187 */
188
ed486911 189 close(device_fd);
ef416fc2 190
c8fef167 191 return (CUPS_BACKEND_OK);
ef416fc2 192}
193
194
195/*
196 * 'list_devices()' - List all USB devices.
197 */
198
199void
200list_devices(void)
201{
202#ifdef __linux
2abf387c 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 */
ef416fc2 209
749b1e90 210
ef416fc2 211 /*
2abf387c 212 * Try to open each USB device...
ef416fc2 213 */
214
215 for (i = 0; i < 16; i ++)
216 {
2abf387c 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 */
ef416fc2 221
2abf387c 222 sprintf(device, "/dev/usblp%d", i);
223
224 if ((fd = open(device, O_RDWR | O_EXCL)) < 0)
ef416fc2 225 {
2abf387c 226 if (errno != ENOENT)
227 continue;
ef416fc2 228
2abf387c 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 }
ef416fc2 241 }
2abf387c 242
243 if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
244 make_model, sizeof(make_model),
245 "usb", device_uri, sizeof(device_uri)))
749b1e90
MS
246 cupsBackendReport("direct", device_uri, make_model, make_model,
247 device_id, NULL);
2abf387c 248
249 close(fd);
ef416fc2 250 }
ef416fc2 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 */
ef416fc2 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
8ca02f3c 268 if ((fd = open(device, O_WRONLY | O_EXCL)) >= 0)
ef416fc2 269 {
ed486911 270 if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
271 make_model, sizeof(make_model),
272 "usb", device_uri, sizeof(device_uri)))
749b1e90
MS
273 cupsBackendReport("direct", device_uri, make_model, make_model,
274 device_id, NULL);
ef416fc2 275
276 close(fd);
277 }
278 }
2e4ff8af 279#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
ef416fc2 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
f7deaa1a 302static int /* O - File descriptor or -1 on error */
8ca02f3c 303open_device(const char *uri, /* I - Device URI */
304 int *use_bc) /* O - Set to 0 for unidirectional */
ef416fc2 305{
8ca02f3c 306 int fd; /* File descriptor */
307
308
ef416fc2 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
ed486911 317 {
318 /*
319 * Do not allow direct devices anymore...
320 */
321
322 errno = ENODEV;
323 return (-1);
324 }
ef416fc2 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? */
2abf387c 333 char device[255], /* Device filename */
ef416fc2 334 device_id[1024], /* Device ID string */
335 make_model[1024], /* Make and model */
336 device_uri[1024]; /* Device URI string */
337
338
339 /*
2abf387c 340 * Find the correct USB device...
ef416fc2 341 */
342
0a682745 343 for (;;)
ef416fc2 344 {
345 for (busy = 0, i = 0; i < 16; i ++)
346 {
2abf387c 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 }
ef416fc2 366
2abf387c 367 if (fd >= 0)
ef416fc2 368 {
ed486911 369 backendGetDeviceID(fd, device_id, sizeof(device_id),
370 make_model, sizeof(make_model),
371 "usb", device_uri, sizeof(device_uri));
ef416fc2 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
c0e1af83 392 fprintf(stderr, "DEBUG: Printer using device file \"%s\"...\n",
393 device);
ef416fc2 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)
f3c17241 412 _cupsLangPrintFilter(stderr, "INFO", _("The printer is in use."));
839a51c8
MS
413
414 sleep(5);
ef416fc2 415 }
ef416fc2 416 }
417#elif defined(__sun) && defined(ECPPIOC_GETDEVID)
ed486911 418 {
419 /*
420 * Do not allow direct devices anymore...
421 */
422
423 errno = ENODEV;
424 return (-1);
425 }
ef416fc2 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? */
ef416fc2 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 */
ef416fc2 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
8ca02f3c 450 if ((fd = open(device, O_WRONLY | O_EXCL)) >= 0)
ed486911 451 backendGetDeviceID(fd, device_id, sizeof(device_id),
452 make_model, sizeof(make_model),
453 "usb", device_uri, sizeof(device_uri));
ef416fc2 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))
8ca02f3c 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 }
ef416fc2 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 {
f3c17241 495 _cupsLangPrintFilter(stderr, "INFO", _("The printer is in use."));
ef416fc2 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
8ca02f3c 510 {
91c84a35 511 if (*use_bc)
323c5de1 512 fd = open(uri + 4, O_RDWR | O_EXCL);
513 else
514 fd = -1;
515
516 if (fd < 0)
8ca02f3c 517 {
518 fd = open(uri + 4, O_WRONLY | O_EXCL);
519 *use_bc = 0;
520 }
521
522 return (fd);
523 }
ef416fc2 524#endif /* __linux */
525 else
526 {
527 errno = ENODEV;
528 return (-1);
529 }
530}
531
532
533/*
f7deaa1a 534 * 'side_cb()' - Handle side-channel requests...
535 */
536
18ecb428 537static int /* O - 0 on success, -1 on error */
568fa3fa
MS
538side_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? */
f7deaa1a 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
568fa3fa
MS
550 (void)snmp_fd;
551 (void)addr;
552
f7deaa1a 553 datalen = sizeof(data);
554
555 if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
18ecb428 556 return (-1);
f7deaa1a 557
558 switch (command)
559 {
560 case CUPS_SC_CMD_DRAIN_OUTPUT :
09a101d6 561 if (backendDrainOutput(print_fd, device_fd))
562 status = CUPS_SC_STATUS_IO_ERROR;
563 else if (tcdrain(device_fd))
f7deaa1a 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 :
8b450588 572 status = CUPS_SC_STATUS_OK;
f7deaa1a 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
18ecb428 599 return (cupsSideChannelWrite(command, status, data, datalen, 1.0));
f7deaa1a 600}