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