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