]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/usb-unix.c
Fix logic for disabling of backchannel in UNIX/Linux USB code (STR #2104)
[thirdparty/cups.git] / backend / usb-unix.c
1 /*
2 * "$Id$"
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 * print_device() - Print a file to a USB device.
31 * list_devices() - List all USB devices.
32 * open_device() - Open a USB device...
33 */
34
35 /*
36 * Include necessary headers.
37 */
38
39 #include "ieee1284.c"
40 #include <sys/select.h>
41
42
43 /*
44 * Local functions...
45 */
46
47 int open_device(const char *uri, int *use_bc);
48
49
50 /*
51 * 'print_device()' - Print a file to a USB device.
52 */
53
54 int /* O - Exit status */
55 print_device(const char *uri, /* I - Device URI */
56 const char *hostname, /* I - Hostname/manufacturer */
57 const char *resource, /* I - Resource/modelname */
58 const char *options, /* I - Device options/serial number */
59 int print_fd, /* I - File descriptor to print */
60 int copies, /* I - Copies to print */
61 int argc, /* I - Number of command-line arguments (6 or 7) */
62 char *argv[]) /* I - Command-line arguments */
63 {
64 int use_bc; /* Use backchannel path? */
65 int device_fd; /* USB device */
66 size_t tbytes; /* Total number of bytes written */
67 struct termios opts; /* Parallel port options */
68
69
70 (void)argc;
71 (void)argv;
72
73 /*
74 * Open the USB port device...
75 */
76
77 fputs("STATE: +connecting-to-device\n", stderr);
78
79 do
80 {
81 /*
82 * Disable backchannel data when printing to Canon or Minolta USB
83 * printers - apparently these printers will return the IEEE-1284
84 * device ID over and over and over when they get a read request...
85 */
86
87 use_bc = strcasecmp(hostname, "Canon") && !strstr(hostname, "Minolta");
88
89 if ((device_fd = open_device(uri, &use_bc)) == -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 ||
118 errno == ENODEV)
119 {
120 fputs("INFO: Printer not connected; will retry in 30 seconds...\n", stderr);
121 sleep(30);
122 }
123 else
124 {
125 fprintf(stderr, "ERROR: Unable to open USB device \"%s\": %s\n",
126 uri, strerror(errno));
127 return (CUPS_BACKEND_FAILED);
128 }
129 }
130 }
131 while (device_fd < 0);
132
133 fputs("STATE: -connecting-to-device\n", stderr);
134
135 /*
136 * Set any options provided...
137 */
138
139 tcgetattr(device_fd, &opts);
140
141 opts.c_lflag &= ~(ICANON | ECHO | ISIG); /* Raw mode */
142
143 /**** No options supported yet ****/
144
145 tcsetattr(device_fd, TCSANOW, &opts);
146
147 /*
148 * Finally, send the print file...
149 */
150
151 tbytes = 0;
152
153 while (copies > 0 && tbytes >= 0)
154 {
155 copies --;
156
157 if (print_fd != 0)
158 {
159 fputs("PAGE: 1 1\n", stderr);
160 lseek(print_fd, 0, SEEK_SET);
161 }
162
163 tbytes = backendRunLoop(print_fd, device_fd, use_bc);
164
165 if (print_fd != 0 && tbytes >= 0)
166 fprintf(stderr, "INFO: Sent print file, " CUPS_LLFMT " bytes...\n",
167 CUPS_LLCAST tbytes);
168 }
169
170 /*
171 * Close the USB port and return...
172 */
173
174 close(device_fd);
175
176 return (tbytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK);
177 }
178
179
180 /*
181 * 'list_devices()' - List all USB devices.
182 */
183
184 void
185 list_devices(void)
186 {
187 #ifdef __linux
188 int i; /* Looping var */
189 int fd; /* File descriptor */
190 char device[255], /* Device filename */
191 device_id[1024], /* Device ID string */
192 device_uri[1024], /* Device URI string */
193 make_model[1024]; /* Make and model */
194
195 /*
196 * Try to open each USB device...
197 */
198
199 for (i = 0; i < 16; i ++)
200 {
201 /*
202 * Linux has a long history of changing the standard filenames used
203 * for USB printer devices. We get the honor of trying them all...
204 */
205
206 sprintf(device, "/dev/usblp%d", i);
207
208 if ((fd = open(device, O_RDWR | O_EXCL)) < 0)
209 {
210 if (errno != ENOENT)
211 continue;
212
213 sprintf(device, "/dev/usb/lp%d", i);
214
215 if ((fd = open(device, O_RDWR | O_EXCL)) < 0)
216 {
217 if (errno != ENOENT)
218 continue;
219
220 sprintf(device, "/dev/usb/usblp%d", i);
221
222 if ((fd = open(device, O_RDWR | O_EXCL)) < 0)
223 continue;
224 }
225 }
226
227 if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
228 make_model, sizeof(make_model),
229 "usb", device_uri, sizeof(device_uri)))
230 printf("direct %s \"%s\" \"%s USB #%d\" \"%s\"\n", device_uri,
231 make_model, make_model, i + 1, device_id);
232
233 close(fd);
234 }
235 #elif defined(__sgi)
236 #elif defined(__sun) && defined(ECPPIOC_GETDEVID)
237 int i; /* Looping var */
238 int fd; /* File descriptor */
239 char device[255], /* Device filename */
240 device_id[1024], /* Device ID string */
241 device_uri[1024], /* Device URI string */
242 make_model[1024]; /* Make and model */
243
244
245 /*
246 * Open each USB device...
247 */
248
249 for (i = 0; i < 8; i ++)
250 {
251 sprintf(device, "/dev/usb/printer%d", i);
252
253 if ((fd = open(device, O_WRONLY | O_EXCL)) >= 0)
254 {
255 if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
256 make_model, sizeof(make_model),
257 "usb", device_uri, sizeof(device_uri)))
258 printf("direct %s \"%s\" \"%s USB #%d\" \"%s\"\n", device_uri,
259 make_model, make_model, i + 1, device_id);
260
261 close(fd);
262 }
263 }
264 #elif defined(__hpux)
265 #elif defined(__osf)
266 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
267 int i; /* Looping var */
268 char device[255]; /* Device filename */
269
270
271 for (i = 0; i < 8; i ++)
272 {
273 sprintf(device, "/dev/ulpt%d", i);
274 if (!access(device, 0))
275 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
276
277 sprintf(device, "/dev/unlpt%d", i);
278 if (!access(device, 0))
279 printf("direct usb:%s \"Unknown\" \"USB Printer #%d (no reset)\"\n", device, i + 1);
280 }
281 #endif
282 }
283
284
285 /*
286 * 'open_device()' - Open a USB device...
287 */
288
289 int /* O - File descriptor or -1 on error */
290 open_device(const char *uri, /* I - Device URI */
291 int *use_bc) /* O - Set to 0 for unidirectional */
292 {
293 int fd; /* File descriptor */
294
295
296 /*
297 * The generic implementation just treats the URI as a device filename...
298 * Specific operating systems may also support using the device serial
299 * number and/or make/model.
300 */
301
302 if (!strncmp(uri, "usb:/dev/", 9))
303 #ifdef __linux
304 {
305 /*
306 * Do not allow direct devices anymore...
307 */
308
309 errno = ENODEV;
310 return (-1);
311 }
312 else if (!strncmp(uri, "usb://", 6))
313 {
314 /*
315 * For Linux, try looking up the device serial number or model...
316 */
317
318 int i; /* Looping var */
319 int busy; /* Are any ports busy? */
320 char device[255], /* Device filename */
321 device_id[1024], /* Device ID string */
322 make_model[1024], /* Make and model */
323 device_uri[1024]; /* Device URI string */
324
325
326 /*
327 * Find the correct USB device...
328 */
329
330 do
331 {
332 for (busy = 0, i = 0; i < 16; i ++)
333 {
334 /*
335 * Linux has a long history of changing the standard filenames used
336 * for USB printer devices. We get the honor of trying them all...
337 */
338
339 sprintf(device, "/dev/usblp%d", i);
340
341 if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT)
342 {
343 sprintf(device, "/dev/usb/lp%d", i);
344
345 if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT)
346 {
347 sprintf(device, "/dev/usb/usblp%d", i);
348
349 if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT)
350 continue;
351 }
352 }
353
354 if (fd >= 0)
355 {
356 backendGetDeviceID(fd, device_id, sizeof(device_id),
357 make_model, sizeof(make_model),
358 "usb", device_uri, sizeof(device_uri));
359 }
360 else
361 {
362 /*
363 * If the open failed because it was busy, flag it so we retry
364 * as needed...
365 */
366
367 if (errno == EBUSY)
368 busy = 1;
369
370 device_uri[0] = '\0';
371 }
372
373 if (!strcmp(uri, device_uri))
374 {
375 /*
376 * Yes, return this file descriptor...
377 */
378
379 fprintf(stderr, "DEBUG: Printer using device file \"%s\"...\n", device);
380
381 return (fd);
382 }
383
384 /*
385 * This wasn't the one...
386 */
387
388 if (fd >= 0)
389 close(fd);
390 }
391
392 /*
393 * If we get here and at least one of the printer ports showed up
394 * as "busy", then sleep for a bit and retry...
395 */
396
397 if (busy)
398 {
399 fputs("INFO: USB printer is busy; will retry in 5 seconds...\n",
400 stderr);
401 sleep(5);
402 }
403 }
404 while (busy);
405
406 /*
407 * Couldn't find the printer, return "no such device or address"...
408 */
409
410 errno = ENODEV;
411
412 return (-1);
413 }
414 #elif defined(__sun) && defined(ECPPIOC_GETDEVID)
415 {
416 /*
417 * Do not allow direct devices anymore...
418 */
419
420 errno = ENODEV;
421 return (-1);
422 }
423 else if (!strncmp(uri, "usb://", 6))
424 {
425 /*
426 * For Solaris, try looking up the device serial number or model...
427 */
428
429 int i; /* Looping var */
430 int busy; /* Are any ports busy? */
431 char device[255], /* Device filename */
432 device_id[1024], /* Device ID string */
433 make_model[1024], /* Make and model */
434 device_uri[1024]; /* Device URI string */
435
436
437 /*
438 * Find the correct USB device...
439 */
440
441 do
442 {
443 for (i = 0, busy = 0; i < 8; i ++)
444 {
445 sprintf(device, "/dev/usb/printer%d", i);
446
447 if ((fd = open(device, O_WRONLY | O_EXCL)) >= 0)
448 backendGetDeviceID(fd, device_id, sizeof(device_id),
449 make_model, sizeof(make_model),
450 "usb", device_uri, sizeof(device_uri));
451 else
452 {
453 /*
454 * If the open failed because it was busy, flag it so we retry
455 * as needed...
456 */
457
458 if (errno == EBUSY)
459 busy = 1;
460
461 device_uri[0] = '\0';
462 }
463
464 if (!strcmp(uri, device_uri))
465 {
466 /*
467 * Yes, return this file descriptor...
468 */
469
470 fputs("DEBUG: Setting use_bc to 0!\n", stderr);
471
472 *use_bc = 0;
473
474 return (fd);
475 }
476
477 /*
478 * This wasn't the one...
479 */
480
481 if (fd >= 0)
482 close(fd);
483 }
484
485 /*
486 * If we get here and at least one of the printer ports showed up
487 * as "busy", then sleep for a bit and retry...
488 */
489
490 if (busy)
491 {
492 fputs("INFO: USB printer is busy; will retry in 5 seconds...\n",
493 stderr);
494 sleep(5);
495 }
496 }
497 while (busy);
498
499 /*
500 * Couldn't find the printer, return "no such device or address"...
501 */
502
503 errno = ENODEV;
504
505 return (-1);
506 }
507 #else
508 {
509 if ((fd = open(uri + 4, O_RDWR | O_EXCL)) < 0)
510 {
511 fd = open(uri + 4, O_WRONLY | O_EXCL);
512 *use_bc = 0;
513 }
514
515 return (fd);
516 }
517 #endif /* __linux */
518 else
519 {
520 errno = ENODEV;
521 return (-1);
522 }
523 }
524
525
526 /*
527 * End of "$Id$".
528 */