]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/usb.c
Mirror 1.1.x changes.
[thirdparty/cups.git] / backend / usb.c
1 /*
2 * "$Id: usb.c,v 1.18.2.19 2002/10/15 16:40:33 mike Exp $"
3 *
4 * USB port backend for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2002 by Easy Software Products, all rights reserved.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636-3111 USA
19 *
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
28 * main() - Send a file to the specified USB port.
29 * list_devices() - List all USB devices.
30 */
31
32 /*
33 * Include necessary headers.
34 */
35
36 #include <cups/cups.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <errno.h>
40 #include <cups/string.h>
41 #include <signal.h>
42
43 #ifdef WIN32
44 # include <io.h>
45 #else
46 # include <unistd.h>
47 # include <fcntl.h>
48 # include <termios.h>
49 #endif /* WIN32 */
50
51 #ifdef __linux
52 # include <sys/ioctl.h>
53 # include <linux/lp.h>
54 # define IOCNR_GET_DEVICE_ID 1
55
56 /*
57 * Get device_id string
58 */
59 # define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len)
60 #endif /* __linux */
61
62
63 /*
64 * Local functions...
65 */
66
67 void decode_device_id(int port, const char *device_id,
68 char *make_model, int mmsize,
69 char *uri, int urisize);
70 void list_devices(void);
71 int open_device(const char *uri);
72
73
74 /*
75 * 'main()' - Send a file to the specified USB port.
76 *
77 * Usage:
78 *
79 * printer-uri job-id user title copies options [file]
80 */
81
82 int /* O - Exit status */
83 main(int argc, /* I - Number of command-line arguments (6 or 7) */
84 char *argv[]) /* I - Command-line arguments */
85 {
86 int fp; /* Print file */
87 int copies; /* Number of copies to print */
88 int fd; /* Parallel device */
89 int wbytes; /* Number of bytes written */
90 size_t nbytes, /* Number of bytes read */
91 tbytes; /* Total number of bytes written */
92 char buffer[8192], /* Output buffer */
93 *bufptr; /* Pointer into buffer */
94 struct termios opts; /* Parallel port options */
95 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
96 struct sigaction action; /* Actions for POSIX signals */
97 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
98 #ifdef __linux
99 unsigned char status; /* Port status (off-line, out-of-paper, etc.) */
100 #endif /* __linux */
101
102
103 /*
104 * Make sure status messages are not buffered...
105 */
106
107 setbuf(stderr, NULL);
108
109 /*
110 * Ignore SIGPIPE signals...
111 */
112
113 #ifdef HAVE_SIGSET
114 sigset(SIGPIPE, SIG_IGN);
115 #elif defined(HAVE_SIGACTION)
116 memset(&action, 0, sizeof(action));
117 action.sa_handler = SIG_IGN;
118 sigaction(SIGPIPE, &action, NULL);
119 #else
120 signal(SIGPIPE, SIG_IGN);
121 #endif /* HAVE_SIGSET */
122
123 /*
124 * Check command-line...
125 */
126
127 if (argc == 1)
128 {
129 list_devices();
130 return (0);
131 }
132 else if (argc < 6 || argc > 7)
133 {
134 fputs("Usage: USB job-id user title copies options [file]\n", stderr);
135 return (1);
136 }
137
138 /*
139 * If we have 7 arguments, print the file named on the command-line.
140 * Otherwise, send stdin instead...
141 */
142
143 if (argc == 6)
144 {
145 fp = 0;
146 copies = 1;
147 }
148 else
149 {
150 /*
151 * Try to open the print file...
152 */
153
154 if ((fp = open(argv[6], O_RDONLY)) < 0)
155 {
156 perror("ERROR: unable to open print file");
157 return (1);
158 }
159
160 copies = atoi(argv[4]);
161 }
162
163 /*
164 * Open the USB port device...
165 */
166
167 do
168 {
169 if ((fd = open_device(argv[0])) == -1)
170 {
171 if (errno == EBUSY)
172 {
173 fputs("INFO: USB port busy; will retry in 30 seconds...\n", stderr);
174 sleep(30);
175 }
176 else if (errno == ENXIO || errno == EIO || errno == ENOENT)
177 {
178 fputs("INFO: Printer not connected; will retry in 30 seconds...\n", stderr);
179 sleep(30);
180 }
181 else
182 {
183 fprintf(stderr, "ERROR: Unable to open USB device \"%s\": %s\n",
184 argv[0], strerror(errno));
185 return (1);
186 }
187 }
188 }
189 while (fd < 0);
190
191 /*
192 * Set any options provided...
193 */
194
195 tcgetattr(fd, &opts);
196
197 opts.c_lflag &= ~(ICANON | ECHO | ISIG); /* Raw mode */
198
199 /**** No options supported yet ****/
200
201 tcsetattr(fd, TCSANOW, &opts);
202
203 /*
204 * Now that we are "connected" to the port, ignore SIGTERM so that we
205 * can finish out any page data the driver sends (e.g. to eject the
206 * current page...
207 */
208
209 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
210 sigset(SIGTERM, SIG_IGN);
211 #elif defined(HAVE_SIGACTION)
212 memset(&action, 0, sizeof(action));
213
214 sigemptyset(&action.sa_mask);
215 action.sa_handler = SIG_IGN;
216 sigaction(SIGTERM, &action, NULL);
217 #else
218 signal(SIGTERM, SIG_IGN);
219 #endif /* HAVE_SIGSET */
220
221 /*
222 * Finally, send the print file...
223 */
224
225 while (copies > 0)
226 {
227 copies --;
228
229 if (fp != 0)
230 {
231 fputs("PAGE: 1 1\n", stderr);
232 lseek(fp, 0, SEEK_SET);
233 }
234
235 tbytes = 0;
236 while ((nbytes = read(fp, buffer, sizeof(buffer))) > 0)
237 {
238 /*
239 * Write the print data to the printer...
240 */
241
242 tbytes += nbytes;
243 bufptr = buffer;
244
245 while (nbytes > 0)
246 {
247 #ifdef __linux
248 if (ioctl(fd, LPGETSTATUS, &status) == 0)
249 {
250 fprintf(stderr, "DEBUG: LPGETSTATUS returned %02X...\n", status);
251
252 if (status & LP_NOPA)
253 fputs("INFO: Media tray empty!\n", stderr);
254 else if (status & LP_ERR)
255 fputs("INFO: Printer fault!\n", stderr);
256 else if (status & LP_OFFL)
257 fputs("INFO: Printer off-line.\n", stderr);
258 }
259 #endif /* __linux */
260
261 if ((wbytes = write(fd, bufptr, nbytes)) < 0)
262 if (errno == ENOTTY)
263 wbytes = write(fd, bufptr, nbytes);
264
265 if (wbytes < 0)
266 {
267 perror("ERROR: Unable to send print file to printer");
268 break;
269 }
270
271 nbytes -= wbytes;
272 bufptr += wbytes;
273 }
274
275 if (argc > 6)
276 fprintf(stderr, "INFO: Sending print file, %lu bytes...\n",
277 (unsigned long)tbytes);
278 }
279 }
280
281 /*
282 * Close the socket connection and input file and return...
283 */
284
285 close(fd);
286 if (fp != 0)
287 close(fp);
288
289 fputs("INFO: Ready to print.\n", stderr);
290
291 return (0);
292 }
293
294
295 /*
296 * 'decode_device_id()' - Decode the IEEE-1284 device ID string.
297 */
298
299 void
300 decode_device_id(int port, /* I - Port number */
301 const char *device_id, /* I - 1284 device ID string */
302 char *make_model, /* O - Make/model */
303 int mmsize, /* I - Size of buffer */
304 char *uri, /* O - Device URI */
305 int urisize) /* I - Size of buffer */
306 {
307 char *attr, /* 1284 attribute */
308 *delim, /* 1284 delimiter */
309 *uriptr, /* Pointer into URI */
310 line[1024]; /* Line from devices file */
311 FILE *fp; /* /proc/bus/usb/devices file */
312 int current; /* Current printer port */
313 char serial_number[1024], /* Serial number string */
314 temp[1024]; /* Temporary string */
315
316
317 /*
318 * Look for the description field...
319 */
320
321 if ((attr = strstr(device_id, "DES:")) != NULL)
322 attr += 4;
323 else if ((attr = strstr(device_id, "DESCRIPTION:")) != NULL)
324 attr += 12;
325
326 if (attr)
327 {
328 if (strncasecmp(attr, "Hewlett-Packard ", 16) == 0)
329 {
330 strlcpy(make_model, "HP ", mmsize);
331 strlcpy(make_model + 3, attr + 16, mmsize - 3);
332 }
333 else
334 {
335 strlcpy(make_model, attr, mmsize);
336 }
337
338 if ((delim = strchr(make_model, ';')) != NULL)
339 *delim = '\0';
340 }
341 else
342 strlcpy(make_model, "Unknown", mmsize);
343
344 /*
345 * Look for the serial number field...
346 */
347
348 if ((attr = strstr(device_id, "SERN:")) != NULL)
349 attr += 5;
350 else if ((attr = strstr(device_id, "SERIALNUMBER:")) != NULL)
351 attr += 13;
352
353 if (attr)
354 {
355 strlcpy(serial_number, attr, sizeof(serial_number));
356
357 if ((delim = strchr(serial_number, ';')) != NULL)
358 *delim = '\0';
359 }
360 else if ((fp = fopen("/proc/bus/usb/devices", "r")) != NULL)
361 {
362 serial_number[0] = '\0';
363
364 for (current = 0; fgets(line, sizeof(line), fp) != NULL;)
365 {
366 if (line[0] == 'S' && (attr = strstr(line, "SerialNumber=")) != NULL)
367 {
368 /*
369 * Copy serial number from line...
370 */
371
372 strlcpy(temp, attr + 13, sizeof(temp));
373 if ((delim = strchr(temp, '\n')) != NULL)
374 *delim = '\0';
375 }
376 else if (line[0] == 'I' && strstr(line, "Driver=usblp") != NULL &&
377 strstr(line, "Prot=02") != NULL)
378 {
379 /*
380 * Found printer device; if current == port, then use it!
381 */
382
383 if (current == port)
384 {
385 strlcpy(serial_number, temp, sizeof(serial_number));
386 break;
387 }
388
389 current ++;
390 }
391 }
392
393 fclose(fp);
394 }
395
396 /*
397 * Generate the device URI from the make_model and serial number strings.
398 */
399
400 strlcpy(uri, "usb://", urisize);
401 for (uriptr = uri + 6, delim = make_model;
402 *delim && uriptr < (uri + urisize - 1);
403 delim ++)
404 if (*delim == ' ')
405 {
406 delim ++;
407 *uriptr++ = '/';
408 break;
409 }
410 else
411 *uriptr++ = *delim;
412
413 for (; *delim && uriptr < (uri + urisize - 3); delim ++)
414 if (*delim == ' ')
415 {
416 *uriptr++ = '%';
417 *uriptr++ = '2';
418 *uriptr++ = '0';
419 }
420 else
421 *uriptr++ = *delim;
422
423 *uriptr = '\0';
424
425 if (serial_number[0])
426 {
427 /*
428 * Add the serial number to the URI...
429 */
430
431 strlcat(uri, "?serial=", urisize);
432 strlcat(uri, serial_number, urisize);
433 }
434 }
435
436
437 /*
438 * 'list_devices()' - List all USB devices.
439 */
440
441 void
442 list_devices(void)
443 {
444 #ifdef __linux
445 int i; /* Looping var */
446 int length; /* Length of device ID info */
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 device_uri[1024], /* Device URI string */
452 make_model[1024]; /* Make and model */
453
454
455 /*
456 * First figure out which USB printer filename to use...
457 */
458
459 if (access("/dev/usb/lp0", 0) == 0)
460 strcpy(format, "/dev/usb/lp%d");
461 else if (access("/dev/usb/usblp0", 0) == 0)
462 strcpy(format, "/dev/usb/usblp%d");
463 else
464 strcpy(format, "/dev/usblp%d");
465
466 /*
467 * Then open each USB device...
468 */
469
470 for (i = 0; i < 16; i ++)
471 {
472 sprintf(device, format, i);
473
474 if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
475 {
476 if (ioctl(fd, LPIOC_GET_DEVICE_ID(sizeof(device_id)), device_id) == 0)
477 {
478 length = (((unsigned)device_id[0] & 255) << 8) +
479 ((unsigned)device_id[1] & 255);
480 memcpy(device_id, device_id + 2, length);
481 device_id[length] = '\0';
482 }
483 else
484 device_id[0] = '\0';
485
486 close(fd);
487 }
488 else
489 device_id[0] = '\0';
490
491 if (device_id[0])
492 {
493 decode_device_id(i, device_id, make_model, sizeof(make_model),
494 device_uri, sizeof(device_uri));
495
496 printf("direct %s \"%s\" \"USB Printer #%d\"\n", device_uri,
497 make_model, i + 1);
498 }
499 else
500 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
501 }
502 #elif defined(__sgi)
503 #elif defined(__sun)
504 int i; /* Looping var */
505 char device[255]; /* Device filename */
506
507
508 for (i = 0; i < 8; i ++)
509 {
510 sprintf(device, "/dev/usb/printer%d", i);
511 if (!access(device, 0))
512 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
513 }
514 #elif defined(__hpux)
515 #elif defined(__osf)
516 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
517 int i; /* Looping var */
518 char device[255]; /* Device filename */
519
520
521 for (i = 0; i < 8; i ++)
522 {
523 sprintf(device, "/dev/ulpt%d", i);
524 if (!access(device, 0))
525 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
526
527 sprintf(device, "/dev/unlpt%d", i);
528 if (!access(device, 0))
529 printf("direct usb:%s \"Unknown\" \"USB Printer #%d (no reset)\"\n", device, i + 1);
530 }
531 #endif
532 }
533
534
535 /*
536 * 'open_device()' - Open a USB device...
537 */
538
539 int /* O - File descriptor or -1 on error */
540 open_device(const char *uri) /* I - Device URI */
541 {
542 /*
543 * The generic implementation just treats the URI as a device filename...
544 * Specific operating systems may also support using the device serial
545 * number and/or make/model.
546 */
547
548 if (strncmp(uri, "usb:/dev/", 9) == 0)
549 return (open(uri + 4, O_RDWR | O_EXCL));
550 #ifdef __linux
551 else if (strncmp(uri, "usb://", 6) == 0)
552 {
553 /*
554 * For Linux, try looking up the device serial number or model...
555 */
556
557 int i; /* Looping var */
558 int length; /* Length of device ID info */
559 int fd; /* File descriptor */
560 char format[255], /* Format for device filename */
561 device[255], /* Device filename */
562 device_id[1024], /* Device ID string */
563 make_model[1024], /* Make and model */
564 device_uri[1024]; /* Device URI string */
565
566
567 /*
568 * First figure out which USB printer filename to use...
569 */
570
571 if (access("/dev/usb/lp0", 0) == 0)
572 strcpy(format, "/dev/usb/lp%d");
573 else if (access("/dev/usb/usblp0", 0) == 0)
574 strcpy(format, "/dev/usb/usblp%d");
575 else
576 strcpy(format, "/dev/usblp%d");
577
578 /*
579 * Then find the correct USB device...
580 */
581
582 for (i = 0; i < 16; i ++)
583 {
584 sprintf(device, format, i);
585
586 if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
587 {
588 if (ioctl(fd, LPIOC_GET_DEVICE_ID(sizeof(device_id)), device_id) == 0)
589 {
590 length = (((unsigned)device_id[0] & 255) << 8) +
591 ((unsigned)device_id[1] & 255);
592 memcpy(device_id, device_id + 2, length);
593 device_id[length] = '\0';
594 }
595 else
596 device_id[0] = '\0';
597 }
598 else
599 device_id[0] = '\0';
600
601 if (device_id[0])
602 {
603 /*
604 * Got the device ID - is this the one?
605 */
606
607 decode_device_id(i, device_id, make_model, sizeof(make_model),
608 device_uri, sizeof(device_uri));
609
610 if (strcmp(uri, device_uri) == 0)
611 return (fd); /* Yes, return this file descriptor... */
612 }
613
614 /*
615 * This wasn't the one...
616 */
617
618 close(fd);
619 }
620
621 /*
622 * Couldn't find the printer, return "no such device or address"...
623 */
624
625 errno = ENODEV;
626
627 return (-1);
628 }
629 #endif /* __linux */
630 else
631 {
632 errno = ENODEV;
633 return (-1);
634 }
635 }
636
637
638 /*
639 * End of "$Id: usb.c,v 1.18.2.19 2002/10/15 16:40:33 mike Exp $".
640 */