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