]> 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 6234 2007-02-05 20:25:50Z 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 * 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") &&
88 strcasecmp(hostname, "Konica Minolta") &&
89 strcasecmp(hostname, "Minolta");
90
91 if ((device_fd = open_device(uri, &use_bc)) == -1)
92 {
93 if (getenv("CLASS") != NULL)
94 {
95 /*
96 * If the CLASS environment variable is set, the job was submitted
97 * to a class and not to a specific queue. In this case, we want
98 * to abort immediately so that the job can be requeued on the next
99 * available printer in the class.
100 */
101
102 fputs("INFO: Unable to open USB device, queuing on next printer in class...\n",
103 stderr);
104
105 /*
106 * Sleep 5 seconds to keep the job from requeuing too rapidly...
107 */
108
109 sleep(5);
110
111 return (CUPS_BACKEND_FAILED);
112 }
113
114 if (errno == EBUSY)
115 {
116 fputs("INFO: USB port busy; will retry in 30 seconds...\n", stderr);
117 sleep(30);
118 }
119 else if (errno == ENXIO || errno == EIO || errno == ENOENT ||
120 errno == ENODEV)
121 {
122 fputs("INFO: Printer not connected; will retry in 30 seconds...\n", stderr);
123 sleep(30);
124 }
125 else
126 {
127 fprintf(stderr, "ERROR: Unable to open USB device \"%s\": %s\n",
128 uri, strerror(errno));
129 return (CUPS_BACKEND_FAILED);
130 }
131 }
132 }
133 while (device_fd < 0);
134
135 fputs("STATE: -connecting-to-device\n", stderr);
136
137 /*
138 * Set any options provided...
139 */
140
141 tcgetattr(device_fd, &opts);
142
143 opts.c_lflag &= ~(ICANON | ECHO | ISIG); /* Raw mode */
144
145 /**** No options supported yet ****/
146
147 tcsetattr(device_fd, TCSANOW, &opts);
148
149 /*
150 * Finally, send the print file...
151 */
152
153 tbytes = 0;
154
155 while (copies > 0 && tbytes >= 0)
156 {
157 copies --;
158
159 if (print_fd != 0)
160 {
161 fputs("PAGE: 1 1\n", stderr);
162 lseek(print_fd, 0, SEEK_SET);
163 }
164
165 tbytes = backendRunLoop(print_fd, device_fd, use_bc);
166
167 if (print_fd != 0 && tbytes >= 0)
168 fprintf(stderr, "INFO: Sent print file, " CUPS_LLFMT " bytes...\n",
169 CUPS_LLCAST tbytes);
170 }
171
172 /*
173 * Close the USB port and return...
174 */
175
176 close(device_fd);
177
178 return (tbytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK);
179 }
180
181
182 /*
183 * 'list_devices()' - List all USB devices.
184 */
185
186 void
187 list_devices(void)
188 {
189 #ifdef __linux
190 int i; /* Looping var */
191 int fd; /* File descriptor */
192 char device[255], /* Device filename */
193 device_id[1024], /* Device ID string */
194 device_uri[1024], /* Device URI string */
195 make_model[1024]; /* Make and model */
196
197 /*
198 * Try to open each USB device...
199 */
200
201 for (i = 0; i < 16; i ++)
202 {
203 /*
204 * Linux has a long history of changing the standard filenames used
205 * for USB printer devices. We get the honor of trying them all...
206 */
207
208 sprintf(device, "/dev/usblp%d", i);
209
210 if ((fd = open(device, O_RDWR | O_EXCL)) < 0)
211 {
212 if (errno != ENOENT)
213 continue;
214
215 sprintf(device, "/dev/usb/lp%d", i);
216
217 if ((fd = open(device, O_RDWR | O_EXCL)) < 0)
218 {
219 if (errno != ENOENT)
220 continue;
221
222 sprintf(device, "/dev/usb/usblp%d", i);
223
224 if ((fd = open(device, O_RDWR | O_EXCL)) < 0)
225 continue;
226 }
227 }
228
229 if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
230 make_model, sizeof(make_model),
231 "usb", device_uri, sizeof(device_uri)))
232 printf("direct %s \"%s\" \"%s USB #%d\" \"%s\"\n", device_uri,
233 make_model, make_model, i + 1, device_id);
234
235 close(fd);
236 }
237 #elif defined(__sgi)
238 #elif defined(__sun) && defined(ECPPIOC_GETDEVID)
239 int i; /* Looping var */
240 int fd; /* File descriptor */
241 char device[255], /* Device filename */
242 device_id[1024], /* Device ID string */
243 device_uri[1024], /* Device URI string */
244 make_model[1024]; /* Make and model */
245
246
247 /*
248 * Open each USB device...
249 */
250
251 for (i = 0; i < 8; i ++)
252 {
253 sprintf(device, "/dev/usb/printer%d", i);
254
255 if ((fd = open(device, O_WRONLY | O_EXCL)) >= 0)
256 {
257 if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
258 make_model, sizeof(make_model),
259 "usb", device_uri, sizeof(device_uri)))
260 printf("direct %s \"%s\" \"%s USB #%d\" \"%s\"\n", device_uri,
261 make_model, make_model, i + 1, device_id);
262
263 close(fd);
264 }
265 }
266 #elif defined(__hpux)
267 #elif defined(__osf)
268 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
269 int i; /* Looping var */
270 char device[255]; /* Device filename */
271
272
273 for (i = 0; i < 8; i ++)
274 {
275 sprintf(device, "/dev/ulpt%d", i);
276 if (!access(device, 0))
277 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
278
279 sprintf(device, "/dev/unlpt%d", i);
280 if (!access(device, 0))
281 printf("direct usb:%s \"Unknown\" \"USB Printer #%d (no reset)\"\n", device, i + 1);
282 }
283 #endif
284 }
285
286
287 /*
288 * 'open_device()' - Open a USB device...
289 */
290
291 int /* O - File descriptor or -1 on error */
292 open_device(const char *uri, /* I - Device URI */
293 int *use_bc) /* O - Set to 0 for unidirectional */
294 {
295 int fd; /* File descriptor */
296
297
298 /*
299 * The generic implementation just treats the URI as a device filename...
300 * Specific operating systems may also support using the device serial
301 * number and/or make/model.
302 */
303
304 if (!strncmp(uri, "usb:/dev/", 9))
305 #ifdef __linux
306 {
307 /*
308 * Do not allow direct devices anymore...
309 */
310
311 errno = ENODEV;
312 return (-1);
313 }
314 else if (!strncmp(uri, "usb://", 6))
315 {
316 /*
317 * For Linux, try looking up the device serial number or model...
318 */
319
320 int i; /* Looping var */
321 int busy; /* Are any ports busy? */
322 char device[255], /* Device filename */
323 device_id[1024], /* Device ID string */
324 make_model[1024], /* Make and model */
325 device_uri[1024]; /* Device URI string */
326
327
328 /*
329 * Find the correct USB device...
330 */
331
332 do
333 {
334 for (busy = 0, i = 0; i < 16; i ++)
335 {
336 /*
337 * Linux has a long history of changing the standard filenames used
338 * for USB printer devices. We get the honor of trying them all...
339 */
340
341 sprintf(device, "/dev/usblp%d", i);
342
343 if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT)
344 {
345 sprintf(device, "/dev/usb/lp%d", i);
346
347 if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT)
348 {
349 sprintf(device, "/dev/usb/usblp%d", i);
350
351 if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT)
352 continue;
353 }
354 }
355
356 if (fd >= 0)
357 {
358 backendGetDeviceID(fd, device_id, sizeof(device_id),
359 make_model, sizeof(make_model),
360 "usb", device_uri, sizeof(device_uri));
361 }
362 else
363 {
364 /*
365 * If the open failed because it was busy, flag it so we retry
366 * as needed...
367 */
368
369 if (errno == EBUSY)
370 busy = 1;
371
372 device_uri[0] = '\0';
373 }
374
375 if (!strcmp(uri, device_uri))
376 {
377 /*
378 * Yes, return this file descriptor...
379 */
380
381 fprintf(stderr, "DEBUG: Printer using device file \"%s\"...\n", device);
382
383 return (fd);
384 }
385
386 /*
387 * This wasn't the one...
388 */
389
390 if (fd >= 0)
391 close(fd);
392 }
393
394 /*
395 * If we get here and at least one of the printer ports showed up
396 * as "busy", then sleep for a bit and retry...
397 */
398
399 if (busy)
400 {
401 fputs("INFO: USB printer is busy; will retry in 5 seconds...\n",
402 stderr);
403 sleep(5);
404 }
405 }
406 while (busy);
407
408 /*
409 * Couldn't find the printer, return "no such device or address"...
410 */
411
412 errno = ENODEV;
413
414 return (-1);
415 }
416 #elif defined(__sun) && defined(ECPPIOC_GETDEVID)
417 {
418 /*
419 * Do not allow direct devices anymore...
420 */
421
422 errno = ENODEV;
423 return (-1);
424 }
425 else if (!strncmp(uri, "usb://", 6))
426 {
427 /*
428 * For Solaris, try looking up the device serial number or model...
429 */
430
431 int i; /* Looping var */
432 int busy; /* Are any ports busy? */
433 char device[255], /* Device filename */
434 device_id[1024], /* Device ID string */
435 make_model[1024], /* Make and model */
436 device_uri[1024]; /* Device URI string */
437
438
439 /*
440 * Find the correct USB device...
441 */
442
443 do
444 {
445 for (i = 0, busy = 0; i < 8; i ++)
446 {
447 sprintf(device, "/dev/usb/printer%d", i);
448
449 if ((fd = open(device, O_WRONLY | O_EXCL)) >= 0)
450 backendGetDeviceID(fd, device_id, sizeof(device_id),
451 make_model, sizeof(make_model),
452 "usb", device_uri, sizeof(device_uri));
453 else
454 {
455 /*
456 * If the open failed because it was busy, flag it so we retry
457 * as needed...
458 */
459
460 if (errno == EBUSY)
461 busy = 1;
462
463 device_uri[0] = '\0';
464 }
465
466 if (!strcmp(uri, device_uri))
467 {
468 /*
469 * Yes, return this file descriptor...
470 */
471
472 fputs("DEBUG: Setting use_bc to 0!\n", stderr);
473
474 *use_bc = 0;
475
476 return (fd);
477 }
478
479 /*
480 * This wasn't the one...
481 */
482
483 if (fd >= 0)
484 close(fd);
485 }
486
487 /*
488 * If we get here and at least one of the printer ports showed up
489 * as "busy", then sleep for a bit and retry...
490 */
491
492 if (busy)
493 {
494 fputs("INFO: USB printer is busy; will retry in 5 seconds...\n",
495 stderr);
496 sleep(5);
497 }
498 }
499 while (busy);
500
501 /*
502 * Couldn't find the printer, return "no such device or address"...
503 */
504
505 errno = ENODEV;
506
507 return (-1);
508 }
509 #else
510 {
511 if ((fd = open(uri + 4, O_RDWR | O_EXCL)) < 0)
512 {
513 fd = open(uri + 4, O_WRONLY | O_EXCL);
514 *use_bc = 0;
515 }
516
517 return (fd);
518 }
519 #endif /* __linux */
520 else
521 {
522 errno = ENODEV;
523 return (-1);
524 }
525 }
526
527
528 /*
529 * End of "$Id: usb-unix.c 6234 2007-02-05 20:25:50Z mike $".
530 */