blob: 5e5516c69075f323cfbe3ba2600296ab9e3e4da6 [file] [log] [blame]
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -03001===============================
2Linux USB Printer Gadget Driver
3===============================
Craig W. Nadler25a010c2007-11-11 15:00:15 -08004
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300506/04/2007
Craig W. Nadler25a010c2007-11-11 15:00:15 -08006
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -03007Copyright (C) 2007 Craig W. Nadler <craig@nadler.us>
Craig W. Nadler25a010c2007-11-11 15:00:15 -08008
9
10
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -030011General
Craig W. Nadler25a010c2007-11-11 15:00:15 -080012=======
13
14This driver may be used if you are writing printer firmware using Linux as
15the embedded OS. This driver has nothing to do with using a printer with
16your Linux host system.
17
18You will need a USB device controller and a Linux driver for it that accepts
19a gadget / "device class" driver using the Linux USB Gadget API. After the
20USB device controller driver is loaded then load the printer gadget driver.
21This will present a printer interface to the USB Host that your USB Device
22port is connected to.
23
24This driver is structured for printer firmware that runs in user mode. The
25user mode printer firmware will read and write data from the kernel mode
26printer gadget driver using a device file. The printer returns a printer status
27byte when the USB HOST sends a device request to get the printer status. The
28user space firmware can read or write this status byte using a device file
29/dev/g_printer . Both blocking and non-blocking read/write calls are supported.
30
31
32
33
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -030034Howto Use This Driver
Craig W. Nadler25a010c2007-11-11 15:00:15 -080035=====================
36
37To load the USB device controller driver and the printer gadget driver. The
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -030038following example uses the Netchip 2280 USB device controller driver::
Craig W. Nadler25a010c2007-11-11 15:00:15 -080039
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -030040 modprobe net2280
41 modprobe g_printer
Craig W. Nadler25a010c2007-11-11 15:00:15 -080042
43
44The follow command line parameter can be used when loading the printer gadget
45(ex: modprobe g_printer idVendor=0x0525 idProduct=0xa4a8 ):
46
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -030047idVendor
48 This is the Vendor ID used in the device descriptor. The default is
Craig W. Nadler25a010c2007-11-11 15:00:15 -080049 the Netchip vendor id 0x0525. YOU MUST CHANGE TO YOUR OWN VENDOR ID
50 BEFORE RELEASING A PRODUCT. If you plan to release a product and don't
51 already have a Vendor ID please see www.usb.org for details on how to
52 get one.
53
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -030054idProduct
55 This is the Product ID used in the device descriptor. The default
Craig W. Nadler25a010c2007-11-11 15:00:15 -080056 is 0xa4a8, you should change this to an ID that's not used by any of
57 your other USB products if you have any. It would be a good idea to
58 start numbering your products starting with say 0x0001.
59
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -030060bcdDevice
61 This is the version number of your product. It would be a good idea
Craig W. Nadler25a010c2007-11-11 15:00:15 -080062 to put your firmware version here.
63
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -030064iManufacturer
65 A string containing the name of the Vendor.
Craig W. Nadler25a010c2007-11-11 15:00:15 -080066
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -030067iProduct
68 A string containing the Product Name.
Craig W. Nadler25a010c2007-11-11 15:00:15 -080069
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -030070iSerialNum
71 A string containing the Serial Number. This should be changed for
Craig W. Nadler25a010c2007-11-11 15:00:15 -080072 each unit of your product.
73
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -030074iPNPstring
75 The PNP ID string used for this printer. You will want to set
Craig W. Nadler25a010c2007-11-11 15:00:15 -080076 either on the command line or hard code the PNP ID string used for
77 your printer product.
78
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -030079qlen
80 The number of 8k buffers to use per endpoint. The default is 10, you
Craig W. Nadler25a010c2007-11-11 15:00:15 -080081 should tune this for your product. You may also want to tune the
82 size of each buffer for your product.
83
84
85
86
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -030087Using The Example Code
Craig W. Nadler25a010c2007-11-11 15:00:15 -080088======================
89
90This example code talks to stdout, instead of a print engine.
91
92To compile the test code below:
93
941) save it to a file called prn_example.c
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300952) compile the code with the follow command::
96
Craig W. Nadler25a010c2007-11-11 15:00:15 -080097 gcc prn_example.c -o prn_example
98
99
100
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300101To read printer data from the host to stdout::
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800102
103 # prn_example -read_data
104
105
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300106To write printer data from a file (data_file) to the host::
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800107
108 # cat data_file | prn_example -write_data
109
110
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300111To get the current printer status for the gadget driver:::
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800112
113 # prn_example -get_status
114
115 Printer status is:
116 Printer is NOT Selected
117 Paper is Out
118 Printer OK
119
120
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300121To set printer to Selected/On-line::
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800122
123 # prn_example -selected
124
125
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300126To set printer to Not Selected/Off-line::
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800127
128 # prn_example -not_selected
129
130
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300131To set paper status to paper out::
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800132
133 # prn_example -paper_out
134
135
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300136To set paper status to paper loaded::
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800137
138 # prn_example -paper_loaded
139
140
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300141To set error status to printer OK::
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800142
143 # prn_example -no_error
144
145
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300146To set error status to ERROR::
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800147
148 # prn_example -error
149
150
151
152
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300153Example Code
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800154============
155
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300156::
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800157
158
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300159 #include <stdio.h>
160 #include <stdlib.h>
161 #include <fcntl.h>
162 #include <linux/poll.h>
163 #include <sys/ioctl.h>
164 #include <linux/usb/g_printer.h>
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800165
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300166 #define PRINTER_FILE "/dev/g_printer"
167 #define BUF_SIZE 512
168
169
170 /*
171 * 'usage()' - Show program usage.
172 */
173
174 static void
175 usage(const char *option) /* I - Option string or NULL */
176 {
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800177 if (option) {
178 fprintf(stderr,"prn_example: Unknown option \"%s\"!\n",
179 option);
180 }
181
182 fputs("\n", stderr);
183 fputs("Usage: prn_example -[options]\n", stderr);
184 fputs("Options:\n", stderr);
185 fputs("\n", stderr);
186 fputs("-get_status Get the current printer status.\n", stderr);
187 fputs("-selected Set the selected status to selected.\n", stderr);
188 fputs("-not_selected Set the selected status to NOT selected.\n",
189 stderr);
190 fputs("-error Set the error status to error.\n", stderr);
191 fputs("-no_error Set the error status to NO error.\n", stderr);
192 fputs("-paper_out Set the paper status to paper out.\n", stderr);
193 fputs("-paper_loaded Set the paper status to paper loaded.\n",
194 stderr);
195 fputs("-read_data Read printer data from driver.\n", stderr);
196 fputs("-write_data Write printer sata to driver.\n", stderr);
197 fputs("-NB_read_data (Non-Blocking) Read printer data from driver.\n",
198 stderr);
199 fputs("\n\n", stderr);
200
201 exit(1);
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300202 }
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800203
204
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300205 static int
206 read_printer_data()
207 {
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800208 struct pollfd fd[1];
209
210 /* Open device file for printer gadget. */
211 fd[0].fd = open(PRINTER_FILE, O_RDWR);
212 if (fd[0].fd < 0) {
213 printf("Error %d opening %s\n", fd[0].fd, PRINTER_FILE);
214 close(fd[0].fd);
215 return(-1);
216 }
217
218 fd[0].events = POLLIN | POLLRDNORM;
219
220 while (1) {
221 static char buf[BUF_SIZE];
222 int bytes_read;
223 int retval;
224
225 /* Wait for up to 1 second for data. */
226 retval = poll(fd, 1, 1000);
227
228 if (retval && (fd[0].revents & POLLRDNORM)) {
229
230 /* Read data from printer gadget driver. */
231 bytes_read = read(fd[0].fd, buf, BUF_SIZE);
232
233 if (bytes_read < 0) {
234 printf("Error %d reading from %s\n",
235 fd[0].fd, PRINTER_FILE);
236 close(fd[0].fd);
237 return(-1);
238 } else if (bytes_read > 0) {
239 /* Write data to standard OUTPUT (stdout). */
240 fwrite(buf, 1, bytes_read, stdout);
241 fflush(stdout);
242 }
243
244 }
245
246 }
247
248 /* Close the device file. */
249 close(fd[0].fd);
250
251 return 0;
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300252 }
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800253
254
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300255 static int
256 write_printer_data()
257 {
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800258 struct pollfd fd[1];
259
260 /* Open device file for printer gadget. */
261 fd[0].fd = open (PRINTER_FILE, O_RDWR);
262 if (fd[0].fd < 0) {
263 printf("Error %d opening %s\n", fd[0].fd, PRINTER_FILE);
264 close(fd[0].fd);
265 return(-1);
266 }
267
268 fd[0].events = POLLOUT | POLLWRNORM;
269
270 while (1) {
271 int retval;
272 static char buf[BUF_SIZE];
273 /* Read data from standard INPUT (stdin). */
274 int bytes_read = fread(buf, 1, BUF_SIZE, stdin);
275
276 if (!bytes_read) {
277 break;
278 }
279
280 while (bytes_read) {
281
282 /* Wait for up to 1 second to sent data. */
283 retval = poll(fd, 1, 1000);
284
285 /* Write data to printer gadget driver. */
286 if (retval && (fd[0].revents & POLLWRNORM)) {
287 retval = write(fd[0].fd, buf, bytes_read);
288 if (retval < 0) {
289 printf("Error %d writing to %s\n",
290 fd[0].fd,
291 PRINTER_FILE);
292 close(fd[0].fd);
293 return(-1);
294 } else {
295 bytes_read -= retval;
296 }
297
298 }
299
300 }
301
302 }
303
304 /* Wait until the data has been sent. */
305 fsync(fd[0].fd);
306
307 /* Close the device file. */
308 close(fd[0].fd);
309
310 return 0;
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300311 }
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800312
313
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300314 static int
315 read_NB_printer_data()
316 {
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800317 int fd;
318 static char buf[BUF_SIZE];
319 int bytes_read;
320
321 /* Open device file for printer gadget. */
322 fd = open(PRINTER_FILE, O_RDWR|O_NONBLOCK);
323 if (fd < 0) {
324 printf("Error %d opening %s\n", fd, PRINTER_FILE);
325 close(fd);
326 return(-1);
327 }
328
329 while (1) {
330 /* Read data from printer gadget driver. */
331 bytes_read = read(fd, buf, BUF_SIZE);
332 if (bytes_read <= 0) {
333 break;
334 }
335
336 /* Write data to standard OUTPUT (stdout). */
337 fwrite(buf, 1, bytes_read, stdout);
338 fflush(stdout);
339 }
340
341 /* Close the device file. */
342 close(fd);
343
344 return 0;
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300345 }
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800346
347
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300348 static int
349 get_printer_status()
350 {
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800351 int retval;
352 int fd;
353
354 /* Open device file for printer gadget. */
355 fd = open(PRINTER_FILE, O_RDWR);
356 if (fd < 0) {
357 printf("Error %d opening %s\n", fd, PRINTER_FILE);
358 close(fd);
359 return(-1);
360 }
361
362 /* Make the IOCTL call. */
363 retval = ioctl(fd, GADGET_GET_PRINTER_STATUS);
364 if (retval < 0) {
365 fprintf(stderr, "ERROR: Failed to set printer status\n");
366 return(-1);
367 }
368
369 /* Close the device file. */
370 close(fd);
371
372 return(retval);
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300373 }
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800374
375
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300376 static int
377 set_printer_status(unsigned char buf, int clear_printer_status_bit)
378 {
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800379 int retval;
380 int fd;
381
382 retval = get_printer_status();
383 if (retval < 0) {
384 fprintf(stderr, "ERROR: Failed to get printer status\n");
385 return(-1);
386 }
387
388 /* Open device file for printer gadget. */
389 fd = open(PRINTER_FILE, O_RDWR);
390
391 if (fd < 0) {
392 printf("Error %d opening %s\n", fd, PRINTER_FILE);
393 close(fd);
394 return(-1);
395 }
396
397 if (clear_printer_status_bit) {
398 retval &= ~buf;
399 } else {
400 retval |= buf;
401 }
402
403 /* Make the IOCTL call. */
404 if (ioctl(fd, GADGET_SET_PRINTER_STATUS, (unsigned char)retval)) {
405 fprintf(stderr, "ERROR: Failed to set printer status\n");
406 return(-1);
407 }
408
409 /* Close the device file. */
410 close(fd);
411
412 return 0;
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300413 }
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800414
415
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300416 static int
417 display_printer_status()
418 {
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800419 char printer_status;
420
421 printer_status = get_printer_status();
422 if (printer_status < 0) {
423 fprintf(stderr, "ERROR: Failed to get printer status\n");
424 return(-1);
425 }
426
427 printf("Printer status is:\n");
428 if (printer_status & PRINTER_SELECTED) {
429 printf(" Printer is Selected\n");
430 } else {
431 printf(" Printer is NOT Selected\n");
432 }
433 if (printer_status & PRINTER_PAPER_EMPTY) {
434 printf(" Paper is Out\n");
435 } else {
436 printf(" Paper is Loaded\n");
437 }
438 if (printer_status & PRINTER_NOT_ERROR) {
439 printf(" Printer OK\n");
440 } else {
441 printf(" Printer ERROR\n");
442 }
443
444 return(0);
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300445 }
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800446
447
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300448 int
449 main(int argc, char *argv[])
450 {
Craig W. Nadler25a010c2007-11-11 15:00:15 -0800451 int i; /* Looping var */
452 int retval = 0;
453
454 /* No Args */
455 if (argc == 1) {
456 usage(0);
457 exit(0);
458 }
459
460 for (i = 1; i < argc && !retval; i ++) {
461
462 if (argv[i][0] != '-') {
463 continue;
464 }
465
466 if (!strcmp(argv[i], "-get_status")) {
467 if (display_printer_status()) {
468 retval = 1;
469 }
470
471 } else if (!strcmp(argv[i], "-paper_loaded")) {
472 if (set_printer_status(PRINTER_PAPER_EMPTY, 1)) {
473 retval = 1;
474 }
475
476 } else if (!strcmp(argv[i], "-paper_out")) {
477 if (set_printer_status(PRINTER_PAPER_EMPTY, 0)) {
478 retval = 1;
479 }
480
481 } else if (!strcmp(argv[i], "-selected")) {
482 if (set_printer_status(PRINTER_SELECTED, 0)) {
483 retval = 1;
484 }
485
486 } else if (!strcmp(argv[i], "-not_selected")) {
487 if (set_printer_status(PRINTER_SELECTED, 1)) {
488 retval = 1;
489 }
490
491 } else if (!strcmp(argv[i], "-error")) {
492 if (set_printer_status(PRINTER_NOT_ERROR, 1)) {
493 retval = 1;
494 }
495
496 } else if (!strcmp(argv[i], "-no_error")) {
497 if (set_printer_status(PRINTER_NOT_ERROR, 0)) {
498 retval = 1;
499 }
500
501 } else if (!strcmp(argv[i], "-read_data")) {
502 if (read_printer_data()) {
503 retval = 1;
504 }
505
506 } else if (!strcmp(argv[i], "-write_data")) {
507 if (write_printer_data()) {
508 retval = 1;
509 }
510
511 } else if (!strcmp(argv[i], "-NB_read_data")) {
512 if (read_NB_printer_data()) {
513 retval = 1;
514 }
515
516 } else {
517 usage(argv[i]);
518 retval = 1;
519 }
520 }
521
522 exit(retval);
Mauro Carvalho Chehabd80b5002019-04-15 23:56:01 -0300523 }