]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/usb-unix.c
Load cups into easysw/current.
[thirdparty/cups.git] / backend / usb-unix.c
CommitLineData
ef416fc2 1/*
f301802f 2 * "$Id: usb-unix.c 5553 2006-05-20 12:22:27Z mike $"
ef416fc2 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 *
bd7854cb 8 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
ef416fc2 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 * main() - Send a file to the specified USB port.
31 * list_devices() - List all USB devices.
32 */
33
34/*
35 * Include necessary headers.
36 */
37
38#include "ieee1284.c"
39#include <sys/select.h>
40
41
42/*
43 * Local functions...
44 */
45
46int open_device(const char *uri);
47
48
49/*
50 * 'print_device()' - Print a file to a USB device.
51 */
52
53int /* O - Exit status */
54print_device(const char *uri, /* I - Device URI */
55 const char *hostname, /* I - Hostname/manufacturer */
56 const char *resource, /* I - Resource/modelname */
57 const char *options, /* I - Device options/serial number */
58 int fp, /* I - File descriptor to print */
e53920b9 59 int copies, /* I - Copies to print */
60 int argc, /* I - Number of command-line arguments (6 or 7) */
61 char *argv[]) /* I - Command-line arguments */
ef416fc2 62{
f301802f 63 int usebc; /* Use backchannel path? */
ef416fc2 64 int fd; /* USB device */
65 int rbytes; /* Number of bytes read */
66 int wbytes; /* Number of bytes written */
67 size_t nbytes, /* Number of bytes read */
68 tbytes; /* Total number of bytes written */
69 char buffer[8192], /* Output buffer */
70 *bufptr, /* Pointer into buffer */
71 backbuf[1024]; /* Backchannel buffer */
72 struct termios opts; /* Parallel port options */
73 fd_set input, /* Input set for select() */
74 output; /* Output set for select() */
75 int paperout; /* Paper out? */
76#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
77 struct sigaction action; /* Actions for POSIX signals */
78#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
79#ifdef __linux
80 unsigned int status; /* Port status (off-line, out-of-paper, etc.) */
81#endif /* __linux */
82
e53920b9 83 (void)argc;
84 (void)argv;
ef416fc2 85
f301802f 86 /*
87 * Disable backchannel data when printing to Canon USB printers - apparently
88 * Canon printers will return the IEEE-1284 device ID over and over and over
89 * when they get a read request...
90 */
91
92 usebc = strcasecmp(hostname, "Canon") != 0;
93
ef416fc2 94 /*
95 * Open the USB port device...
96 */
97
757d2cad 98 fputs("STATE: +connecting-to-device\n", stderr);
99
ef416fc2 100 do
101 {
102 if ((fd = open_device(uri)) == -1)
103 {
104 if (getenv("CLASS") != NULL)
105 {
106 /*
107 * If the CLASS environment variable is set, the job was submitted
108 * to a class and not to a specific queue. In this case, we want
109 * to abort immediately so that the job can be requeued on the next
110 * available printer in the class.
111 */
112
113 fputs("INFO: Unable to open USB device, queuing on next printer in class...\n",
114 stderr);
115
116 /*
117 * Sleep 5 seconds to keep the job from requeuing too rapidly...
118 */
119
120 sleep(5);
121
122 return (CUPS_BACKEND_FAILED);
123 }
124
125 if (errno == EBUSY)
126 {
127 fputs("INFO: USB port busy; will retry in 30 seconds...\n", stderr);
128 sleep(30);
129 }
130 else if (errno == ENXIO || errno == EIO || errno == ENOENT || errno == ENODEV)
131 {
132 fputs("INFO: Printer not connected; will retry in 30 seconds...\n", stderr);
133 sleep(30);
134 }
135 else
136 {
137 fprintf(stderr, "ERROR: Unable to open USB device \"%s\": %s\n",
138 uri, strerror(errno));
139 return (CUPS_BACKEND_FAILED);
140 }
141 }
142 }
143 while (fd < 0);
144
757d2cad 145 fputs("STATE: -connecting-to-device\n", stderr);
146
ef416fc2 147 /*
148 * Set any options provided...
149 */
150
151 tcgetattr(fd, &opts);
152
153 opts.c_lflag &= ~(ICANON | ECHO | ISIG); /* Raw mode */
154
155 /**** No options supported yet ****/
156
157 tcsetattr(fd, TCSANOW, &opts);
158
159 /*
160 * Check printer status...
161 */
162
163 paperout = 0;
164
165#if defined(__linux) && defined(LP_POUTPA)
166 /*
167 * Show the printer status before we send the file...
168 */
169
170 while (!ioctl(fd, LPGETSTATUS, &status))
171 {
172 fprintf(stderr, "DEBUG: LPGETSTATUS returned a port status of %02X...\n", status);
173
174 if (status & LP_POUTPA)
175 {
176 fputs("WARNING: Media tray empty!\n", stderr);
177 fputs("STATUS: +media-tray-empty-error\n", stderr);
178
179 paperout = 1;
180 }
181
182 if (!(status & LP_PERRORP))
183 fputs("WARNING: Printer fault!\n", stderr);
184 else if (!(status & LP_PSELECD))
185 fputs("WARNING: Printer off-line.\n", stderr);
186 else
187 break;
188
189 sleep(5);
190 }
191#endif /* __linux && LP_POUTPA */
192
193 /*
194 * Now that we are "connected" to the port, ignore SIGTERM so that we
195 * can finish out any page data the driver sends (e.g. to eject the
196 * current page... Only ignore SIGTERM if we are printing data from
197 * stdin (otherwise you can't cancel raw jobs...)
198 */
199
200 if (!fp)
201 {
202#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
203 sigset(SIGTERM, SIG_IGN);
204#elif defined(HAVE_SIGACTION)
205 memset(&action, 0, sizeof(action));
206
207 sigemptyset(&action.sa_mask);
208 action.sa_handler = SIG_IGN;
209 sigaction(SIGTERM, &action, NULL);
210#else
211 signal(SIGTERM, SIG_IGN);
212#endif /* HAVE_SIGSET */
213 }
214
215 /*
216 * Finally, send the print file...
217 */
218
219 wbytes = 0;
220
221 while (copies > 0)
222 {
223 copies --;
224
225 if (fp != 0)
226 {
227 fputs("PAGE: 1 1\n", stderr);
228 lseek(fp, 0, SEEK_SET);
229 }
230
231 tbytes = 0;
232 while ((nbytes = read(fp, buffer, sizeof(buffer))) > 0)
233 {
234 /*
235 * Write the print data to the printer...
236 */
237
238 tbytes += nbytes;
239 bufptr = buffer;
240
241 while (nbytes > 0)
242 {
243 /*
244 * See if we are ready to read or write...
245 */
246
247 do
248 {
249 FD_ZERO(&input);
f301802f 250 if (usebc)
251 FD_SET(fd, &input);
252
ef416fc2 253 FD_ZERO(&output);
254 FD_SET(fd, &output);
255 }
256 while (select(fd + 1, &input, &output, NULL, NULL) < 0);
257
258 if (FD_ISSET(fd, &input))
259 {
260 /*
261 * Read backchannel data...
262 */
263
264 if ((rbytes = read(fd, backbuf, sizeof(backbuf))) > 0)
265 {
266 fprintf(stderr, "DEBUG: Received %d bytes of back-channel data!\n",
267 rbytes);
bd7854cb 268 cupsBackChannelWrite(backbuf, rbytes, 1.0);
ef416fc2 269 }
270 }
271
272 if (FD_ISSET(fd, &output))
273 {
274 /*
275 * Write print data...
276 */
277
278 if ((wbytes = write(fd, bufptr, nbytes)) < 0)
279 if (errno == ENOTTY)
280 wbytes = write(fd, bufptr, nbytes);
281
282 if (wbytes < 0)
283 {
284 /*
285 * Check for retryable errors...
286 */
287
288 if (errno == ENOSPC)
289 {
290 paperout = 1;
291 fputs("ERROR: Out of paper!\n", stderr);
292 fputs("STATUS: +media-tray-empty-error\n", stderr);
293 }
294 else if (errno != EAGAIN && errno != EINTR)
295 {
296 perror("ERROR: Unable to send print file to printer");
297 break;
298 }
299 }
300 else
301 {
302 /*
303 * Update count and pointer...
304 */
305
306 if (paperout)
307 {
308 fputs("STATUS: -media-tray-empty-error\n", stderr);
309 paperout = 0;
310 }
311
312 nbytes -= wbytes;
313 bufptr += wbytes;
314 }
315 }
316 }
317
318 if (wbytes < 0)
319 break;
320
321 if (fp)
322 fprintf(stderr, "INFO: Sending print file, %lu bytes...\n",
323 (unsigned long)tbytes);
324 }
325 }
326
327 /*
328 * Close the USB port and return...
329 */
330
331 close(fd);
332
333 return (wbytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK);
334}
335
336
337/*
338 * 'list_devices()' - List all USB devices.
339 */
340
341void
342list_devices(void)
343{
344#ifdef __linux
345 int i; /* Looping var */
346 int fd; /* File descriptor */
347 char format[255], /* Format for device filename */
348 device[255], /* Device filename */
349 device_id[1024], /* Device ID string */
350 device_uri[1024], /* Device URI string */
351 make_model[1024]; /* Make and model */
352
353
354 /*
355 * First figure out which USB printer filename to use...
356 */
357
358 if (!access("/dev/usblp0", 0))
359 strcpy(format, "/dev/usblp%d");
360 else if (!access("/dev/usb/usblp0", 0))
361 strcpy(format, "/dev/usb/usblp%d");
362 else
363 strcpy(format, "/dev/usb/lp%d");
364
365 /*
366 * Then open each USB device...
367 */
368
369 for (i = 0; i < 16; i ++)
370 {
371 sprintf(device, format, i);
372
373 if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
374 {
375 if (!get_device_id(fd, device_id, sizeof(device_id),
376 make_model, sizeof(make_model),
377 "usb", device_uri, sizeof(device_uri)))
378 printf("direct %s \"%s\" \"%s USB #%d\" \"%s\"\n", device_uri,
379 make_model, make_model, i + 1, device_id);
380
381 close(fd);
382 }
383 }
384#elif defined(__sgi)
385#elif defined(__sun) && defined(ECPPIOC_GETDEVID)
386 int i; /* Looping var */
387 int fd; /* File descriptor */
388 char device[255], /* Device filename */
389 device_id[1024], /* Device ID string */
390 device_uri[1024], /* Device URI string */
391 make_model[1024]; /* Make and model */
ef416fc2 392
393
394 /*
395 * Open each USB device...
396 */
397
398 for (i = 0; i < 8; i ++)
399 {
400 sprintf(device, "/dev/usb/printer%d", i);
401
402 if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
403 {
404 if (!get_device_id(fd, device_id, sizeof(device_id),
405 make_model, sizeof(make_model),
406 "usb", device_uri, sizeof(device_uri)))
407 printf("direct %s \"%s\" \"%s USB #%d\" \"%s\"\n", device_uri,
408 make_model, make_model, i + 1, device_id);
409
410 close(fd);
411 }
412 }
413#elif defined(__hpux)
414#elif defined(__osf)
b423cd4c 415#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
ef416fc2 416 int i; /* Looping var */
417 char device[255]; /* Device filename */
418
419
420 for (i = 0; i < 8; i ++)
421 {
422 sprintf(device, "/dev/ulpt%d", i);
423 if (!access(device, 0))
424 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
425
426 sprintf(device, "/dev/unlpt%d", i);
427 if (!access(device, 0))
428 printf("direct usb:%s \"Unknown\" \"USB Printer #%d (no reset)\"\n", device, i + 1);
429 }
430#endif
431}
432
433
434/*
435 * 'open_device()' - Open a USB device...
436 */
437
438int /* O - File descriptor or -1 on error */
439open_device(const char *uri) /* I - Device URI */
440{
441 /*
442 * The generic implementation just treats the URI as a device filename...
443 * Specific operating systems may also support using the device serial
444 * number and/or make/model.
445 */
446
447 if (!strncmp(uri, "usb:/dev/", 9))
448#ifdef __linux
449 return (-1); /* Do not allow direct devices anymore */
450 else if (!strncmp(uri, "usb://", 6))
451 {
452 /*
453 * For Linux, try looking up the device serial number or model...
454 */
455
456 int i; /* Looping var */
457 int busy; /* Are any ports busy? */
458 int fd; /* File descriptor */
459 char format[255], /* Format for device filename */
460 device[255], /* Device filename */
461 device_id[1024], /* Device ID string */
462 make_model[1024], /* Make and model */
463 device_uri[1024]; /* Device URI string */
464
465
466 /*
467 * First figure out which USB printer filename to use...
468 */
469
470 if (!access("/dev/usblp0", 0))
471 strcpy(format, "/dev/usblp%d");
472 else if (!access("/dev/usb/usblp0", 0))
473 strcpy(format, "/dev/usb/usblp%d");
474 else
475 strcpy(format, "/dev/usb/lp%d");
476
477 /*
478 * Then find the correct USB device...
479 */
480
481 do
482 {
483 for (busy = 0, i = 0; i < 16; i ++)
484 {
485 sprintf(device, format, i);
486
487 if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
488 {
489 get_device_id(fd, device_id, sizeof(device_id),
490 make_model, sizeof(make_model),
491 "usb", device_uri, sizeof(device_uri));
492 }
493 else
494 {
495 /*
496 * If the open failed because it was busy, flag it so we retry
497 * as needed...
498 */
499
500 if (errno == EBUSY)
501 busy = 1;
502
503 device_uri[0] = '\0';
504 }
505
506 if (!strcmp(uri, device_uri))
507 {
508 /*
509 * Yes, return this file descriptor...
510 */
511
512 fprintf(stderr, "DEBUG: Printer using device file \"%s\"...\n", device);
513
514 return (fd);
515 }
516
517 /*
518 * This wasn't the one...
519 */
520
521 if (fd >= 0)
522 close(fd);
523 }
524
525 /*
526 * If we get here and at least one of the printer ports showed up
527 * as "busy", then sleep for a bit and retry...
528 */
529
530 if (busy)
531 {
532 fputs("INFO: USB printer is busy; will retry in 5 seconds...\n",
533 stderr);
534 sleep(5);
535 }
536 }
537 while (busy);
538
539 /*
540 * Couldn't find the printer, return "no such device or address"...
541 */
542
543 errno = ENODEV;
544
545 return (-1);
546 }
547#elif defined(__sun) && defined(ECPPIOC_GETDEVID)
548 return (-1); /* Do not allow direct devices anymore */
549 else if (!strncmp(uri, "usb://", 6))
550 {
551 /*
552 * For Solaris, try looking up the device serial number or model...
553 */
554
555 int i; /* Looping var */
556 int busy; /* Are any ports busy? */
557 int fd; /* File descriptor */
558 char device[255], /* Device filename */
559 device_id[1024], /* Device ID string */
560 make_model[1024], /* Make and model */
561 device_uri[1024]; /* Device URI string */
ef416fc2 562
563
564 /*
565 * Find the correct USB device...
566 */
567
568 do
569 {
570 for (i = 0, busy = 0; i < 8; i ++)
571 {
572 sprintf(device, "/dev/usb/printer%d", i);
573
574 if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
575 get_device_id(fd, device_id, sizeof(device_id),
576 make_model, sizeof(make_model),
577 "usb", device_uri, sizeof(device_uri));
578 else
579 {
580 /*
581 * If the open failed because it was busy, flag it so we retry
582 * as needed...
583 */
584
585 if (errno == EBUSY)
586 busy = 1;
587
588 device_uri[0] = '\0';
589 }
590
591 if (!strcmp(uri, device_uri))
592 return (fd); /* Yes, return this file descriptor... */
593
594 /*
595 * This wasn't the one...
596 */
597
598 if (fd >= 0)
599 close(fd);
600 }
601
602 /*
603 * If we get here and at least one of the printer ports showed up
604 * as "busy", then sleep for a bit and retry...
605 */
606
607 if (busy)
608 {
609 fputs("INFO: USB printer is busy; will retry in 5 seconds...\n",
610 stderr);
611 sleep(5);
612 }
613 }
614 while (busy);
615
616 /*
617 * Couldn't find the printer, return "no such device or address"...
618 */
619
620 errno = ENODEV;
621
622 return (-1);
623 }
624#else
625 return (open(uri + 4, O_RDWR | O_EXCL));
626#endif /* __linux */
627 else
628 {
629 errno = ENODEV;
630 return (-1);
631 }
632}
633
634
635/*
f301802f 636 * End of "$Id: usb-unix.c 5553 2006-05-20 12:22:27Z mike $".
ef416fc2 637 */