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