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