]> 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/*
e1d6a774 2 * "$Id: usb-unix.c 5259 2006-03-09 19:22:36Z 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 */
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
757d2cad 85 fputs("STATE: +connecting-to-device\n", stderr);
86
ef416fc2 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
757d2cad 132 fputs("STATE: -connecting-to-device\n", stderr);
133
ef416fc2 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);
bd7854cb 253 cupsBackChannelWrite(backbuf, rbytes, 1.0);
ef416fc2 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
326void
327list_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 */
ef416fc2 377
378
379 /*
380 * Open each USB device...
381 */
382
383 for (i = 0; i < 8; i ++)
384 {
385 sprintf(device, "/dev/usb/printer%d", i);
386
387 if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
388 {
389 if (!get_device_id(fd, device_id, sizeof(device_id),
390 make_model, sizeof(make_model),
391 "usb", device_uri, sizeof(device_uri)))
392 printf("direct %s \"%s\" \"%s USB #%d\" \"%s\"\n", device_uri,
393 make_model, make_model, i + 1, device_id);
394
395 close(fd);
396 }
397 }
398#elif defined(__hpux)
399#elif defined(__osf)
b423cd4c 400#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
ef416fc2 401 int i; /* Looping var */
402 char device[255]; /* Device filename */
403
404
405 for (i = 0; i < 8; i ++)
406 {
407 sprintf(device, "/dev/ulpt%d", i);
408 if (!access(device, 0))
409 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
410
411 sprintf(device, "/dev/unlpt%d", i);
412 if (!access(device, 0))
413 printf("direct usb:%s \"Unknown\" \"USB Printer #%d (no reset)\"\n", device, i + 1);
414 }
415#endif
416}
417
418
419/*
420 * 'open_device()' - Open a USB device...
421 */
422
423int /* O - File descriptor or -1 on error */
424open_device(const char *uri) /* I - Device URI */
425{
426 /*
427 * The generic implementation just treats the URI as a device filename...
428 * Specific operating systems may also support using the device serial
429 * number and/or make/model.
430 */
431
432 if (!strncmp(uri, "usb:/dev/", 9))
433#ifdef __linux
434 return (-1); /* Do not allow direct devices anymore */
435 else if (!strncmp(uri, "usb://", 6))
436 {
437 /*
438 * For Linux, try looking up the device serial number or model...
439 */
440
441 int i; /* Looping var */
442 int busy; /* Are any ports busy? */
443 int fd; /* File descriptor */
444 char format[255], /* Format for device filename */
445 device[255], /* Device filename */
446 device_id[1024], /* Device ID string */
447 make_model[1024], /* Make and model */
448 device_uri[1024]; /* Device URI string */
449
450
451 /*
452 * First figure out which USB printer filename to use...
453 */
454
455 if (!access("/dev/usblp0", 0))
456 strcpy(format, "/dev/usblp%d");
457 else if (!access("/dev/usb/usblp0", 0))
458 strcpy(format, "/dev/usb/usblp%d");
459 else
460 strcpy(format, "/dev/usb/lp%d");
461
462 /*
463 * Then find the correct USB device...
464 */
465
466 do
467 {
468 for (busy = 0, i = 0; i < 16; i ++)
469 {
470 sprintf(device, format, i);
471
472 if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
473 {
474 get_device_id(fd, device_id, sizeof(device_id),
475 make_model, sizeof(make_model),
476 "usb", device_uri, sizeof(device_uri));
477 }
478 else
479 {
480 /*
481 * If the open failed because it was busy, flag it so we retry
482 * as needed...
483 */
484
485 if (errno == EBUSY)
486 busy = 1;
487
488 device_uri[0] = '\0';
489 }
490
491 if (!strcmp(uri, device_uri))
492 {
493 /*
494 * Yes, return this file descriptor...
495 */
496
497 fprintf(stderr, "DEBUG: Printer using device file \"%s\"...\n", device);
498
499 return (fd);
500 }
501
502 /*
503 * This wasn't the one...
504 */
505
506 if (fd >= 0)
507 close(fd);
508 }
509
510 /*
511 * If we get here and at least one of the printer ports showed up
512 * as "busy", then sleep for a bit and retry...
513 */
514
515 if (busy)
516 {
517 fputs("INFO: USB printer is busy; will retry in 5 seconds...\n",
518 stderr);
519 sleep(5);
520 }
521 }
522 while (busy);
523
524 /*
525 * Couldn't find the printer, return "no such device or address"...
526 */
527
528 errno = ENODEV;
529
530 return (-1);
531 }
532#elif defined(__sun) && defined(ECPPIOC_GETDEVID)
533 return (-1); /* Do not allow direct devices anymore */
534 else if (!strncmp(uri, "usb://", 6))
535 {
536 /*
537 * For Solaris, try looking up the device serial number or model...
538 */
539
540 int i; /* Looping var */
541 int busy; /* Are any ports busy? */
542 int fd; /* File descriptor */
543 char device[255], /* Device filename */
544 device_id[1024], /* Device ID string */
545 make_model[1024], /* Make and model */
546 device_uri[1024]; /* Device URI string */
ef416fc2 547
548
549 /*
550 * Find the correct USB device...
551 */
552
553 do
554 {
555 for (i = 0, busy = 0; i < 8; i ++)
556 {
557 sprintf(device, "/dev/usb/printer%d", i);
558
559 if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
560 get_device_id(fd, device_id, sizeof(device_id),
561 make_model, sizeof(make_model),
562 "usb", device_uri, sizeof(device_uri));
563 else
564 {
565 /*
566 * If the open failed because it was busy, flag it so we retry
567 * as needed...
568 */
569
570 if (errno == EBUSY)
571 busy = 1;
572
573 device_uri[0] = '\0';
574 }
575
576 if (!strcmp(uri, device_uri))
577 return (fd); /* Yes, return this file descriptor... */
578
579 /*
580 * This wasn't the one...
581 */
582
583 if (fd >= 0)
584 close(fd);
585 }
586
587 /*
588 * If we get here and at least one of the printer ports showed up
589 * as "busy", then sleep for a bit and retry...
590 */
591
592 if (busy)
593 {
594 fputs("INFO: USB printer is busy; will retry in 5 seconds...\n",
595 stderr);
596 sleep(5);
597 }
598 }
599 while (busy);
600
601 /*
602 * Couldn't find the printer, return "no such device or address"...
603 */
604
605 errno = ENODEV;
606
607 return (-1);
608 }
609#else
610 return (open(uri + 4, O_RDWR | O_EXCL));
611#endif /* __linux */
612 else
613 {
614 errno = ENODEV;
615 return (-1);
616 }
617}
618
619
620/*
e1d6a774 621 * End of "$Id: usb-unix.c 5259 2006-03-09 19:22:36Z mike $".
ef416fc2 622 */