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