]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/usb-unix.c
More localization stuff + cleanup to only use fputs and fprintf since we
[thirdparty/cups.git] / backend / usb-unix.c
CommitLineData
8e3807e7 1/*
c9d3f842 2 * "$Id$"
8e3807e7 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 *
761a542e 8 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
8e3807e7 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
c9d3f842 20 * Hollywood, Maryland 20636 USA
8e3807e7 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 *
74584961 30 * print_device() - Print a file to a USB device.
8e3807e7 31 * list_devices() - List all USB devices.
74584961 32 * open_device() - Open a USB device...
761a542e 33 * side_cb() - Handle side-channel requests...
8e3807e7 34 */
35
36/*
37 * Include necessary headers.
38 */
39
9ef960f1 40#include "ieee1284.c"
5baa731f 41#include <sys/select.h>
42
8e3807e7 43
44/*
45 * Local functions...
46 */
47
761a542e 48static int open_device(const char *uri, int *use_bc);
49static void side_cb(int print_fd, int device_fd, int use_bc);
8e3807e7 50
51
52/*
53 * 'print_device()' - Print a file to a USB device.
54 */
55
56int /* O - Exit status */
57print_device(const char *uri, /* I - Device URI */
58 const char *hostname, /* I - Hostname/manufacturer */
59 const char *resource, /* I - Resource/modelname */
60 const char *options, /* I - Device options/serial number */
43b5ad0d 61 int print_fd, /* I - File descriptor to print */
7e826c4a 62 int copies, /* I - Copies to print */
63 int argc, /* I - Number of command-line arguments (6 or 7) */
64 char *argv[]) /* I - Command-line arguments */
8e3807e7 65{
43b5ad0d 66 int use_bc; /* Use backchannel path? */
67 int device_fd; /* USB device */
68 size_t tbytes; /* Total number of bytes written */
8e3807e7 69 struct termios opts; /* Parallel port options */
43b5ad0d 70
8e3807e7 71
7e826c4a 72 (void)argc;
73 (void)argv;
8e3807e7 74
75 /*
76 * Open the USB port device...
77 */
78
22a980cc 79 fputs("STATE: +connecting-to-device\n", stderr);
80
8e3807e7 81 do
82 {
acc0a9db 83 /*
e4b02d8f 84 * Disable backchannel data when printing to Brother, Canon, or
85 * Minolta USB printers - apparently these printers will return
86 * the IEEE-1284 device ID over and over and over when they get
87 * a read request...
acc0a9db 88 */
89
e4b02d8f 90 use_bc = strcasecmp(hostname, "Brother") &&
91 strcasecmp(hostname, "Canon") &&
c740586e 92 strcasecmp(hostname, "Konica Minolta") &&
e6b5af05 93 strcasecmp(hostname, "Minolta");
acc0a9db 94
95 if ((device_fd = open_device(uri, &use_bc)) == -1)
8e3807e7 96 {
b7b63780 97 if (getenv("CLASS") != NULL)
98 {
99 /*
100 * If the CLASS environment variable is set, the job was submitted
101 * to a class and not to a specific queue. In this case, we want
102 * to abort immediately so that the job can be requeued on the next
103 * available printer in the class.
104 */
105
ff0295f0 106 fputs(_("INFO: Unable to contact printer, queuing on next "
107 "printer in class...\n"), stderr);
b7b63780 108
109 /*
110 * Sleep 5 seconds to keep the job from requeuing too rapidly...
111 */
112
113 sleep(5);
114
6248387b 115 return (CUPS_BACKEND_FAILED);
b7b63780 116 }
117
8e3807e7 118 if (errno == EBUSY)
119 {
ff0295f0 120 fputs(_("INFO: Printer busy; will retry in 10 seconds...\n"), stderr);
121 sleep(10);
8e3807e7 122 }
43b5ad0d 123 else if (errno == ENXIO || errno == EIO || errno == ENOENT ||
124 errno == ENODEV)
8e3807e7 125 {
ff0295f0 126 fputs(_("INFO: Printer not connected; will retry in 30 seconds...\n"),
127 stderr);
8e3807e7 128 sleep(30);
129 }
130 else
131 {
ff0295f0 132 fprintf(stderr, _("ERROR: Unable to open device file \"%s\": %s\n"),
133 resource, strerror(errno));
6248387b 134 return (CUPS_BACKEND_FAILED);
8e3807e7 135 }
136 }
137 }
43b5ad0d 138 while (device_fd < 0);
8e3807e7 139
22a980cc 140 fputs("STATE: -connecting-to-device\n", stderr);
141
8e3807e7 142 /*
143 * Set any options provided...
144 */
145
43b5ad0d 146 tcgetattr(device_fd, &opts);
8e3807e7 147
148 opts.c_lflag &= ~(ICANON | ECHO | ISIG); /* Raw mode */
149
150 /**** No options supported yet ****/
151
43b5ad0d 152 tcsetattr(device_fd, TCSANOW, &opts);
9ef960f1 153
8e3807e7 154 /*
155 * Finally, send the print file...
156 */
157
43b5ad0d 158 tbytes = 0;
897922a9 159
43b5ad0d 160 while (copies > 0 && tbytes >= 0)
8e3807e7 161 {
162 copies --;
163
43b5ad0d 164 if (print_fd != 0)
8e3807e7 165 {
166 fputs("PAGE: 1 1\n", stderr);
43b5ad0d 167 lseek(print_fd, 0, SEEK_SET);
8e3807e7 168 }
169
761a542e 170 tbytes = backendRunLoop(print_fd, device_fd, use_bc, side_cb);
8e3807e7 171
43b5ad0d 172 if (print_fd != 0 && tbytes >= 0)
ff0295f0 173 fprintf(stderr,
174#ifdef HAVE_LONG_LONG
175 _("INFO: Sent print file, %lld bytes...\n"),
176#else
177 _("INFO: Sent print file, %ld bytes...\n"),
178#endif /* HAVE_LONG_LONG */
179 CUPS_LLCAST tbytes);
8e3807e7 180 }
181
182 /*
183 * Close the USB port and return...
184 */
185
43b5ad0d 186 close(device_fd);
8e3807e7 187
43b5ad0d 188 return (tbytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK);
8e3807e7 189}
190
191
8e3807e7 192/*
193 * 'list_devices()' - List all USB devices.
194 */
195
196void
197list_devices(void)
198{
199#ifdef __linux
7c76593b 200 int i; /* Looping var */
201 int fd; /* File descriptor */
202 char device[255], /* Device filename */
203 device_id[1024], /* Device ID string */
204 device_uri[1024], /* Device URI string */
205 make_model[1024]; /* Make and model */
8e3807e7 206
207 /*
7c76593b 208 * Try to open each USB device...
8e3807e7 209 */
210
211 for (i = 0; i < 16; i ++)
212 {
7c76593b 213 /*
214 * Linux has a long history of changing the standard filenames used
215 * for USB printer devices. We get the honor of trying them all...
216 */
8e3807e7 217
7c76593b 218 sprintf(device, "/dev/usblp%d", i);
219
220 if ((fd = open(device, O_RDWR | O_EXCL)) < 0)
8e3807e7 221 {
7c76593b 222 if (errno != ENOENT)
223 continue;
8e3807e7 224
7c76593b 225 sprintf(device, "/dev/usb/lp%d", i);
226
227 if ((fd = open(device, O_RDWR | O_EXCL)) < 0)
228 {
229 if (errno != ENOENT)
230 continue;
231
232 sprintf(device, "/dev/usb/usblp%d", i);
233
234 if ((fd = open(device, O_RDWR | O_EXCL)) < 0)
235 continue;
236 }
8e3807e7 237 }
7c76593b 238
239 if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
240 make_model, sizeof(make_model),
241 "usb", device_uri, sizeof(device_uri)))
242 printf("direct %s \"%s\" \"%s USB #%d\" \"%s\"\n", device_uri,
243 make_model, make_model, i + 1, device_id);
244
245 close(fd);
8e3807e7 246 }
247#elif defined(__sgi)
74ef1ffb 248#elif defined(__sun) && defined(ECPPIOC_GETDEVID)
8e3807e7 249 int i; /* Looping var */
250 int fd; /* File descriptor */
251 char device[255], /* Device filename */
252 device_id[1024], /* Device ID string */
253 device_uri[1024], /* Device URI string */
254 make_model[1024]; /* Make and model */
8e3807e7 255
256
257 /*
258 * Open each USB device...
259 */
260
261 for (i = 0; i < 8; i ++)
262 {
263 sprintf(device, "/dev/usb/printer%d", i);
264
acc0a9db 265 if ((fd = open(device, O_WRONLY | O_EXCL)) >= 0)
8e3807e7 266 {
43b5ad0d 267 if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
268 make_model, sizeof(make_model),
269 "usb", device_uri, sizeof(device_uri)))
9ef960f1 270 printf("direct %s \"%s\" \"%s USB #%d\" \"%s\"\n", device_uri,
271 make_model, make_model, i + 1, device_id);
8e3807e7 272
273 close(fd);
274 }
8e3807e7 275 }
276#elif defined(__hpux)
277#elif defined(__osf)
fe688a06 278#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
8e3807e7 279 int i; /* Looping var */
280 char device[255]; /* Device filename */
281
282
283 for (i = 0; i < 8; i ++)
284 {
285 sprintf(device, "/dev/ulpt%d", i);
286 if (!access(device, 0))
287 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
288
289 sprintf(device, "/dev/unlpt%d", i);
290 if (!access(device, 0))
291 printf("direct usb:%s \"Unknown\" \"USB Printer #%d (no reset)\"\n", device, i + 1);
292 }
293#endif
294}
295
296
297/*
298 * 'open_device()' - Open a USB device...
299 */
300
761a542e 301static int /* O - File descriptor or -1 on error */
acc0a9db 302open_device(const char *uri, /* I - Device URI */
303 int *use_bc) /* O - Set to 0 for unidirectional */
8e3807e7 304{
acc0a9db 305 int fd; /* File descriptor */
306
307
8e3807e7 308 /*
309 * The generic implementation just treats the URI as a device filename...
310 * Specific operating systems may also support using the device serial
311 * number and/or make/model.
312 */
313
9ef960f1 314 if (!strncmp(uri, "usb:/dev/", 9))
8e3807e7 315#ifdef __linux
74584961 316 {
317 /*
318 * Do not allow direct devices anymore...
319 */
320
321 errno = ENODEV;
322 return (-1);
323 }
9ef960f1 324 else if (!strncmp(uri, "usb://", 6))
8e3807e7 325 {
326 /*
327 * For Linux, try looking up the device serial number or model...
328 */
329
330 int i; /* Looping var */
331 int busy; /* Are any ports busy? */
7c76593b 332 char device[255], /* Device filename */
8e3807e7 333 device_id[1024], /* Device ID string */
334 make_model[1024], /* Make and model */
335 device_uri[1024]; /* Device URI string */
336
337
338 /*
7c76593b 339 * Find the correct USB device...
8e3807e7 340 */
341
342 do
343 {
344 for (busy = 0, i = 0; i < 16; i ++)
345 {
7c76593b 346 /*
347 * Linux has a long history of changing the standard filenames used
348 * for USB printer devices. We get the honor of trying them all...
349 */
350
351 sprintf(device, "/dev/usblp%d", i);
352
353 if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT)
354 {
355 sprintf(device, "/dev/usb/lp%d", i);
356
357 if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT)
358 {
359 sprintf(device, "/dev/usb/usblp%d", i);
360
361 if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT)
362 continue;
363 }
364 }
8e3807e7 365
7c76593b 366 if (fd >= 0)
8e3807e7 367 {
43b5ad0d 368 backendGetDeviceID(fd, device_id, sizeof(device_id),
369 make_model, sizeof(make_model),
370 "usb", device_uri, sizeof(device_uri));
8e3807e7 371 }
372 else
373 {
374 /*
375 * If the open failed because it was busy, flag it so we retry
376 * as needed...
377 */
378
379 if (errno == EBUSY)
380 busy = 1;
381
9ef960f1 382 device_uri[0] = '\0';
8e3807e7 383 }
384
9ef960f1 385 if (!strcmp(uri, device_uri))
8e3807e7 386 {
387 /*
9ef960f1 388 * Yes, return this file descriptor...
8e3807e7 389 */
390
ff0295f0 391 fprintf(stderr, "DEBUG: Printer using device file \"%s\"...\n",
392 device);
8e3807e7 393
9ef960f1 394 return (fd);
8e3807e7 395 }
396
397 /*
398 * This wasn't the one...
399 */
400
401 if (fd >= 0)
402 close(fd);
403 }
404
405 /*
406 * If we get here and at least one of the printer ports showed up
407 * as "busy", then sleep for a bit and retry...
408 */
409
410 if (busy)
411 {
ff0295f0 412 fputs(_("INFO: Printer is busy; will retry in 5 seconds...\n"),
413 stderr);
8e3807e7 414 sleep(5);
415 }
416 }
417 while (busy);
418
419 /*
420 * Couldn't find the printer, return "no such device or address"...
421 */
422
423 errno = ENODEV;
424
425 return (-1);
426 }
427#elif defined(__sun) && defined(ECPPIOC_GETDEVID)
74584961 428 {
429 /*
430 * Do not allow direct devices anymore...
431 */
432
433 errno = ENODEV;
434 return (-1);
435 }
9ef960f1 436 else if (!strncmp(uri, "usb://", 6))
8e3807e7 437 {
438 /*
439 * For Solaris, try looking up the device serial number or model...
440 */
441
442 int i; /* Looping var */
443 int busy; /* Are any ports busy? */
8e3807e7 444 char device[255], /* Device filename */
445 device_id[1024], /* Device ID string */
446 make_model[1024], /* Make and model */
447 device_uri[1024]; /* Device URI string */
8e3807e7 448
449
450 /*
451 * Find the correct USB device...
452 */
453
454 do
455 {
63412dfd 456 for (i = 0, busy = 0; i < 8; i ++)
8e3807e7 457 {
458 sprintf(device, "/dev/usb/printer%d", i);
459
acc0a9db 460 if ((fd = open(device, O_WRONLY | O_EXCL)) >= 0)
43b5ad0d 461 backendGetDeviceID(fd, device_id, sizeof(device_id),
462 make_model, sizeof(make_model),
463 "usb", device_uri, sizeof(device_uri));
8e3807e7 464 else
465 {
466 /*
467 * If the open failed because it was busy, flag it so we retry
468 * as needed...
469 */
470
471 if (errno == EBUSY)
472 busy = 1;
473
9ef960f1 474 device_uri[0] = '\0';
8e3807e7 475 }
476
9ef960f1 477 if (!strcmp(uri, device_uri))
acc0a9db 478 {
479 /*
480 * Yes, return this file descriptor...
481 */
482
483 fputs("DEBUG: Setting use_bc to 0!\n", stderr);
484
485 *use_bc = 0;
486
487 return (fd);
488 }
8e3807e7 489
490 /*
491 * This wasn't the one...
492 */
493
494 if (fd >= 0)
495 close(fd);
496 }
497
498 /*
499 * If we get here and at least one of the printer ports showed up
500 * as "busy", then sleep for a bit and retry...
501 */
502
503 if (busy)
504 {
ff0295f0 505 fputs(_("INFO: Printer is busy; will retry in 5 seconds...\n"),
506 stderr);
8e3807e7 507 sleep(5);
508 }
509 }
510 while (busy);
511
512 /*
513 * Couldn't find the printer, return "no such device or address"...
514 */
515
516 errno = ENODEV;
517
518 return (-1);
519 }
d4102150 520#else
acc0a9db 521 {
522 if ((fd = open(uri + 4, O_RDWR | O_EXCL)) < 0)
523 {
524 fd = open(uri + 4, O_WRONLY | O_EXCL);
525 *use_bc = 0;
526 }
527
528 return (fd);
529 }
d4102150 530#endif /* __linux */
8e3807e7 531 else
532 {
533 errno = ENODEV;
534 return (-1);
535 }
536}
537
538
761a542e 539/*
540 * 'side_cb()' - Handle side-channel requests...
541 */
542
543static void
544side_cb(int print_fd, /* I - Print file */
545 int device_fd, /* I - Device file */
546 int use_bc) /* I - Using back-channel? */
547{
548 cups_sc_command_t command; /* Request command */
549 cups_sc_status_t status; /* Request/response status */
550 char data[2048]; /* Request/response data */
551 int datalen; /* Request/response data size */
552
553
554 datalen = sizeof(data);
555
556 if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
557 {
ff0295f0 558 fputs(_("WARNING: Failed to read side-channel request!\n"), stderr);
761a542e 559 return;
560 }
561
562 switch (command)
563 {
564 case CUPS_SC_CMD_DRAIN_OUTPUT :
565 if (tcdrain(device_fd))
566 status = CUPS_SC_STATUS_IO_ERROR;
567 else
568 status = CUPS_SC_STATUS_OK;
569
570 datalen = 0;
571 break;
572
573 case CUPS_SC_CMD_GET_BIDI :
574 data[0] = use_bc;
575 datalen = 1;
576 break;
577
578 case CUPS_SC_CMD_GET_DEVICE_ID :
579 memset(data, 0, sizeof(data));
580
581 if (backendGetDeviceID(device_fd, data, sizeof(data) - 1,
582 NULL, 0, NULL, NULL, 0))
583 {
584 status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
585 datalen = 0;
586 }
587 else
588 {
589 status = CUPS_SC_STATUS_OK;
590 datalen = strlen(data);
591 }
592 break;
593
594 default :
595 status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
596 datalen = 0;
597 break;
598 }
599
600 cupsSideChannelWrite(command, status, data, datalen, 1.0);
601}
602
603
8e3807e7 604/*
c9d3f842 605 * End of "$Id$".
8e3807e7 606 */