]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/usb-unix.c
94544df5eff9134751180f126932e67f1d1ca883
[thirdparty/cups.git] / backend / usb-unix.c
1 /*
2 * "$Id: usb-unix.c 5726 2006-07-12 20:00:11Z 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 USB printers - apparently
83 * Canon printers will return the IEEE-1284 device ID over and over and over
84 * when they get a read request...
85 */
86
87 use_bc = strcasecmp(hostname, "Canon") != 0;
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 format[255], /* Format for device filename */
191 device[255], /* Device filename */
192 device_id[1024], /* Device ID string */
193 device_uri[1024], /* Device URI string */
194 make_model[1024]; /* Make and model */
195
196
197 /*
198 * First figure out which USB printer filename to use...
199 */
200
201 if (!access("/dev/usblp0", 0))
202 strcpy(format, "/dev/usblp%d");
203 else if (!access("/dev/usb/usblp0", 0))
204 strcpy(format, "/dev/usb/usblp%d");
205 else
206 strcpy(format, "/dev/usb/lp%d");
207
208 /*
209 * Then open each USB device...
210 */
211
212 for (i = 0; i < 16; i ++)
213 {
214 sprintf(device, format, i);
215
216 if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
217 {
218 if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
219 make_model, sizeof(make_model),
220 "usb", device_uri, sizeof(device_uri)))
221 printf("direct %s \"%s\" \"%s USB #%d\" \"%s\"\n", device_uri,
222 make_model, make_model, i + 1, device_id);
223
224 close(fd);
225 }
226 }
227 #elif defined(__sgi)
228 #elif defined(__sun) && defined(ECPPIOC_GETDEVID)
229 int i; /* Looping var */
230 int fd; /* File descriptor */
231 char device[255], /* Device filename */
232 device_id[1024], /* Device ID string */
233 device_uri[1024], /* Device URI string */
234 make_model[1024]; /* Make and model */
235
236
237 /*
238 * Open each USB device...
239 */
240
241 for (i = 0; i < 8; i ++)
242 {
243 sprintf(device, "/dev/usb/printer%d", i);
244
245 if ((fd = open(device, O_WRONLY | O_EXCL)) >= 0)
246 {
247 if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
248 make_model, sizeof(make_model),
249 "usb", device_uri, sizeof(device_uri)))
250 printf("direct %s \"%s\" \"%s USB #%d\" \"%s\"\n", device_uri,
251 make_model, make_model, i + 1, device_id);
252
253 close(fd);
254 }
255 }
256 #elif defined(__hpux)
257 #elif defined(__osf)
258 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
259 int i; /* Looping var */
260 char device[255]; /* Device filename */
261
262
263 for (i = 0; i < 8; i ++)
264 {
265 sprintf(device, "/dev/ulpt%d", i);
266 if (!access(device, 0))
267 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
268
269 sprintf(device, "/dev/unlpt%d", i);
270 if (!access(device, 0))
271 printf("direct usb:%s \"Unknown\" \"USB Printer #%d (no reset)\"\n", device, i + 1);
272 }
273 #endif
274 }
275
276
277 /*
278 * 'open_device()' - Open a USB device...
279 */
280
281 int /* O - File descriptor or -1 on error */
282 open_device(const char *uri, /* I - Device URI */
283 int *use_bc) /* O - Set to 0 for unidirectional */
284 {
285 int fd; /* File descriptor */
286
287
288 /*
289 * The generic implementation just treats the URI as a device filename...
290 * Specific operating systems may also support using the device serial
291 * number and/or make/model.
292 */
293
294 if (!strncmp(uri, "usb:/dev/", 9))
295 #ifdef __linux
296 {
297 /*
298 * Do not allow direct devices anymore...
299 */
300
301 errno = ENODEV;
302 return (-1);
303 }
304 else if (!strncmp(uri, "usb://", 6))
305 {
306 /*
307 * For Linux, try looking up the device serial number or model...
308 */
309
310 int i; /* Looping var */
311 int busy; /* Are any ports busy? */
312 char format[255], /* Format for device filename */
313 device[255], /* Device filename */
314 device_id[1024], /* Device ID string */
315 make_model[1024], /* Make and model */
316 device_uri[1024]; /* Device URI string */
317
318
319 /*
320 * First figure out which USB printer filename to use...
321 */
322
323 if (!access("/dev/usblp0", 0))
324 strcpy(format, "/dev/usblp%d");
325 else if (!access("/dev/usb/usblp0", 0))
326 strcpy(format, "/dev/usb/usblp%d");
327 else
328 strcpy(format, "/dev/usb/lp%d");
329
330 /*
331 * Then find the correct USB device...
332 */
333
334 do
335 {
336 for (busy = 0, i = 0; i < 16; i ++)
337 {
338 sprintf(device, format, i);
339
340 if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
341 {
342 backendGetDeviceID(fd, device_id, sizeof(device_id),
343 make_model, sizeof(make_model),
344 "usb", device_uri, sizeof(device_uri));
345 }
346 else
347 {
348 /*
349 * If the open failed because it was busy, flag it so we retry
350 * as needed...
351 */
352
353 if (errno == EBUSY)
354 busy = 1;
355
356 device_uri[0] = '\0';
357 }
358
359 if (!strcmp(uri, device_uri))
360 {
361 /*
362 * Yes, return this file descriptor...
363 */
364
365 fprintf(stderr, "DEBUG: Printer using device file \"%s\"...\n", device);
366
367 return (fd);
368 }
369
370 /*
371 * This wasn't the one...
372 */
373
374 if (fd >= 0)
375 close(fd);
376 }
377
378 /*
379 * If we get here and at least one of the printer ports showed up
380 * as "busy", then sleep for a bit and retry...
381 */
382
383 if (busy)
384 {
385 fputs("INFO: USB printer is busy; will retry in 5 seconds...\n",
386 stderr);
387 sleep(5);
388 }
389 }
390 while (busy);
391
392 /*
393 * Couldn't find the printer, return "no such device or address"...
394 */
395
396 errno = ENODEV;
397
398 return (-1);
399 }
400 #elif defined(__sun) && defined(ECPPIOC_GETDEVID)
401 {
402 /*
403 * Do not allow direct devices anymore...
404 */
405
406 errno = ENODEV;
407 return (-1);
408 }
409 else if (!strncmp(uri, "usb://", 6))
410 {
411 /*
412 * For Solaris, try looking up the device serial number or model...
413 */
414
415 int i; /* Looping var */
416 int busy; /* Are any ports busy? */
417 char device[255], /* Device filename */
418 device_id[1024], /* Device ID string */
419 make_model[1024], /* Make and model */
420 device_uri[1024]; /* Device URI string */
421
422
423 /*
424 * Find the correct USB device...
425 */
426
427 do
428 {
429 for (i = 0, busy = 0; i < 8; i ++)
430 {
431 sprintf(device, "/dev/usb/printer%d", i);
432
433 if ((fd = open(device, O_WRONLY | O_EXCL)) >= 0)
434 backendGetDeviceID(fd, device_id, sizeof(device_id),
435 make_model, sizeof(make_model),
436 "usb", device_uri, sizeof(device_uri));
437 else
438 {
439 /*
440 * If the open failed because it was busy, flag it so we retry
441 * as needed...
442 */
443
444 if (errno == EBUSY)
445 busy = 1;
446
447 device_uri[0] = '\0';
448 }
449
450 if (!strcmp(uri, device_uri))
451 {
452 /*
453 * Yes, return this file descriptor...
454 */
455
456 fputs("DEBUG: Setting use_bc to 0!\n", stderr);
457
458 *use_bc = 0;
459
460 return (fd);
461 }
462
463 /*
464 * This wasn't the one...
465 */
466
467 if (fd >= 0)
468 close(fd);
469 }
470
471 /*
472 * If we get here and at least one of the printer ports showed up
473 * as "busy", then sleep for a bit and retry...
474 */
475
476 if (busy)
477 {
478 fputs("INFO: USB printer is busy; will retry in 5 seconds...\n",
479 stderr);
480 sleep(5);
481 }
482 }
483 while (busy);
484
485 /*
486 * Couldn't find the printer, return "no such device or address"...
487 */
488
489 errno = ENODEV;
490
491 return (-1);
492 }
493 #else
494 {
495 if ((fd = open(uri + 4, O_RDWR | O_EXCL)) < 0)
496 {
497 fd = open(uri + 4, O_WRONLY | O_EXCL);
498 *use_bc = 0;
499 }
500
501 return (fd);
502 }
503 #endif /* __linux */
504 else
505 {
506 errno = ENODEV;
507 return (-1);
508 }
509 }
510
511
512 /*
513 * End of "$Id: usb-unix.c 5726 2006-07-12 20:00:11Z mike $".
514 */