Linux 4.14.5
[linux/fpc-iii.git] / Documentation / usb / gadget_printer.txt
blobad995bf0db4176153ff3b37769a8c47e6e445438
2                        Linux USB Printer Gadget Driver
3                                  06/04/2007
5               Copyright (C) 2007 Craig W. Nadler <craig@nadler.us>
9 GENERAL
10 =======
12 This driver may be used if you are writing printer firmware using Linux as
13 the embedded OS. This driver has nothing to do with using a printer with
14 your Linux host system.
16 You will need a USB device controller and a Linux driver for it that accepts
17 a gadget / "device class" driver using the Linux USB Gadget API. After the
18 USB device controller driver is loaded then load the printer gadget driver.
19 This will present a printer interface to the USB Host that your USB Device
20 port is connected to.
22 This driver is structured for printer firmware that runs in user mode. The
23 user mode printer firmware will read and write data from the kernel mode
24 printer gadget driver using a device file. The printer returns a printer status
25 byte when the USB HOST sends a device request to get the printer status.  The
26 user space firmware can read or write this status byte using a device file
27 /dev/g_printer . Both blocking and non-blocking read/write calls are supported.
32 HOWTO USE THIS DRIVER
33 =====================
35 To load the USB device controller driver and the printer gadget driver. The
36 following example uses the Netchip 2280 USB device controller driver:
38 modprobe net2280
39 modprobe g_printer
42 The follow command line parameter can be used when loading the printer gadget
43 (ex: modprobe g_printer idVendor=0x0525 idProduct=0xa4a8 ):
45 idVendor - This is the Vendor ID used in the device descriptor. The default is
46         the Netchip vendor id 0x0525. YOU MUST CHANGE TO YOUR OWN VENDOR ID
47         BEFORE RELEASING A PRODUCT. If you plan to release a product and don't
48         already have a Vendor ID please see www.usb.org for details on how to
49         get one.
51 idProduct - This is the Product ID used in the device descriptor. The default
52         is 0xa4a8, you should change this to an ID that's not used by any of
53         your other USB products if you have any. It would be a good idea to
54         start numbering your products starting with say 0x0001.
56 bcdDevice - This is the version number of your product. It would be a good idea
57         to put your firmware version here.
59 iManufacturer - A string containing the name of the Vendor.
61 iProduct - A string containing the Product Name.
63 iSerialNum - A string containing the Serial Number. This should be changed for
64         each unit of your product.
66 iPNPstring -  The PNP ID string used for this printer. You will want to set
67         either on the command line or hard code the PNP ID string used for
68         your printer product.
70 qlen - The number of 8k buffers to use per endpoint. The default is 10, you
71         should tune this for your product. You may also want to tune the
72         size of each buffer for your product.
77 USING THE EXAMPLE CODE
78 ======================
80 This example code talks to stdout, instead of a print engine.
82 To compile the test code below:
84 1) save it to a file called prn_example.c
85 2) compile the code with the follow command:
86          gcc prn_example.c -o prn_example
90 To read printer data from the host to stdout:
92         # prn_example -read_data
95 To write printer data from a file (data_file) to the host:
97         # cat data_file | prn_example -write_data
100 To get the current printer status for the gadget driver:
102         # prn_example -get_status
104         Printer status is:
105              Printer is NOT Selected
106              Paper is Out
107              Printer OK
110 To set printer to Selected/On-line:
112         # prn_example -selected
115 To set printer to Not Selected/Off-line:
117         # prn_example -not_selected
120 To set paper status to paper out:
122         # prn_example -paper_out
125 To set paper status to paper loaded:
127         # prn_example -paper_loaded
130 To set error status to printer OK:
132         # prn_example -no_error
135 To set error status to ERROR:
137         # prn_example -error
142 EXAMPLE CODE
143 ============
146 #include <stdio.h>
147 #include <stdlib.h>
148 #include <fcntl.h>
149 #include <linux/poll.h>
150 #include <sys/ioctl.h>
151 #include <linux/usb/g_printer.h>
153 #define PRINTER_FILE                    "/dev/g_printer"
154 #define BUF_SIZE                        512
158  * 'usage()' - Show program usage.
159  */
161 static void
162 usage(const char *option)               /* I - Option string or NULL */
164         if (option) {
165                 fprintf(stderr,"prn_example: Unknown option \"%s\"!\n",
166                                 option);
167         }
169         fputs("\n", stderr);
170         fputs("Usage: prn_example -[options]\n", stderr);
171         fputs("Options:\n", stderr);
172         fputs("\n", stderr);
173         fputs("-get_status    Get the current printer status.\n", stderr);
174         fputs("-selected      Set the selected status to selected.\n", stderr);
175         fputs("-not_selected  Set the selected status to NOT selected.\n",
176                         stderr);
177         fputs("-error         Set the error status to error.\n", stderr);
178         fputs("-no_error      Set the error status to NO error.\n", stderr);
179         fputs("-paper_out     Set the paper status to paper out.\n", stderr);
180         fputs("-paper_loaded  Set the paper status to paper loaded.\n",
181                         stderr);
182         fputs("-read_data     Read printer data from driver.\n", stderr);
183         fputs("-write_data    Write printer sata to driver.\n", stderr);
184         fputs("-NB_read_data  (Non-Blocking) Read printer data from driver.\n",
185                         stderr);
186         fputs("\n\n", stderr);
188         exit(1);
192 static int
193 read_printer_data()
195         struct pollfd   fd[1];
197         /* Open device file for printer gadget. */
198         fd[0].fd = open(PRINTER_FILE, O_RDWR);
199         if (fd[0].fd < 0) {
200                 printf("Error %d opening %s\n", fd[0].fd, PRINTER_FILE);
201                 close(fd[0].fd);
202                 return(-1);
203         }
205         fd[0].events = POLLIN | POLLRDNORM;
207         while (1) {
208                 static char buf[BUF_SIZE];
209                 int bytes_read;
210                 int retval;
212                 /* Wait for up to 1 second for data. */
213                 retval = poll(fd, 1, 1000);
215                 if (retval && (fd[0].revents & POLLRDNORM)) {
217                         /* Read data from printer gadget driver. */
218                         bytes_read = read(fd[0].fd, buf, BUF_SIZE);
220                         if (bytes_read < 0) {
221                                 printf("Error %d reading from %s\n",
222                                                 fd[0].fd, PRINTER_FILE);
223                                 close(fd[0].fd);
224                                 return(-1);
225                         } else if (bytes_read > 0) {
226                                 /* Write data to standard OUTPUT (stdout). */
227                                 fwrite(buf, 1, bytes_read, stdout);
228                                 fflush(stdout);
229                         }
231                 }
233         }
235         /* Close the device file. */
236         close(fd[0].fd);
238         return 0;
242 static int
243 write_printer_data()
245         struct pollfd   fd[1];
247         /* Open device file for printer gadget. */
248         fd[0].fd = open (PRINTER_FILE, O_RDWR);
249         if (fd[0].fd < 0) {
250                 printf("Error %d opening %s\n", fd[0].fd, PRINTER_FILE);
251                 close(fd[0].fd);
252                 return(-1);
253         }
255         fd[0].events = POLLOUT | POLLWRNORM;
257         while (1) {
258                 int retval;
259                 static char buf[BUF_SIZE];
260                 /* Read data from standard INPUT (stdin). */
261                 int bytes_read = fread(buf, 1, BUF_SIZE, stdin);
263                 if (!bytes_read) {
264                         break;
265                 }
267                 while (bytes_read) {
269                         /* Wait for up to 1 second to sent data. */
270                         retval = poll(fd, 1, 1000);
272                         /* Write data to printer gadget driver. */
273                         if (retval && (fd[0].revents & POLLWRNORM)) {
274                                 retval = write(fd[0].fd, buf, bytes_read);
275                                 if (retval < 0) {
276                                         printf("Error %d writing to %s\n",
277                                                         fd[0].fd,
278                                                         PRINTER_FILE);
279                                         close(fd[0].fd);
280                                         return(-1);
281                                 } else {
282                                         bytes_read -= retval;
283                                 }
285                         }
287                 }
289         }
291         /* Wait until the data has been sent. */
292         fsync(fd[0].fd);
294         /* Close the device file. */
295         close(fd[0].fd);
297         return 0;
301 static int
302 read_NB_printer_data()
304         int             fd;
305         static char     buf[BUF_SIZE];
306         int             bytes_read;
308         /* Open device file for printer gadget. */
309         fd = open(PRINTER_FILE, O_RDWR|O_NONBLOCK);
310         if (fd < 0) {
311                 printf("Error %d opening %s\n", fd, PRINTER_FILE);
312                 close(fd);
313                 return(-1);
314         }
316         while (1) {
317                 /* Read data from printer gadget driver. */
318                 bytes_read = read(fd, buf, BUF_SIZE);
319                 if (bytes_read <= 0) {
320                         break;
321                 }
323                 /* Write data to standard OUTPUT (stdout). */
324                 fwrite(buf, 1, bytes_read, stdout);
325                 fflush(stdout);
326         }
328         /* Close the device file. */
329         close(fd);
331         return 0;
335 static int
336 get_printer_status()
338         int     retval;
339         int     fd;
341         /* Open device file for printer gadget. */
342         fd = open(PRINTER_FILE, O_RDWR);
343         if (fd < 0) {
344                 printf("Error %d opening %s\n", fd, PRINTER_FILE);
345                 close(fd);
346                 return(-1);
347         }
349         /* Make the IOCTL call. */
350         retval = ioctl(fd, GADGET_GET_PRINTER_STATUS);
351         if (retval < 0) {
352                 fprintf(stderr, "ERROR: Failed to set printer status\n");
353                 return(-1);
354         }
356         /* Close the device file. */
357         close(fd);
359         return(retval);
363 static int
364 set_printer_status(unsigned char buf, int clear_printer_status_bit)
366         int     retval;
367         int     fd;
369         retval = get_printer_status();
370         if (retval < 0) {
371                 fprintf(stderr, "ERROR: Failed to get printer status\n");
372                 return(-1);
373         }
375         /* Open device file for printer gadget. */
376         fd = open(PRINTER_FILE, O_RDWR);
378         if (fd < 0) {
379                 printf("Error %d opening %s\n", fd, PRINTER_FILE);
380                 close(fd);
381                 return(-1);
382         }
384         if (clear_printer_status_bit) {
385                 retval &= ~buf;
386         } else {
387                 retval |= buf;
388         }
390         /* Make the IOCTL call. */
391         if (ioctl(fd, GADGET_SET_PRINTER_STATUS, (unsigned char)retval)) {
392                 fprintf(stderr, "ERROR: Failed to set printer status\n");
393                 return(-1);
394         }
396         /* Close the device file. */
397         close(fd);
399         return 0;
403 static int
404 display_printer_status()
406         char    printer_status;
408         printer_status = get_printer_status();
409         if (printer_status < 0) {
410                 fprintf(stderr, "ERROR: Failed to get printer status\n");
411                 return(-1);
412         }
414         printf("Printer status is:\n");
415         if (printer_status & PRINTER_SELECTED) {
416                 printf("     Printer is Selected\n");
417         } else {
418                 printf("     Printer is NOT Selected\n");
419         }
420         if (printer_status & PRINTER_PAPER_EMPTY) {
421                 printf("     Paper is Out\n");
422         } else {
423                 printf("     Paper is Loaded\n");
424         }
425         if (printer_status & PRINTER_NOT_ERROR) {
426                 printf("     Printer OK\n");
427         } else {
428                 printf("     Printer ERROR\n");
429         }
431         return(0);
436 main(int  argc, char *argv[])
438         int     i;              /* Looping var */
439         int     retval = 0;
441         /* No Args */
442         if (argc == 1) {
443                 usage(0);
444                 exit(0);
445         }
447         for (i = 1; i < argc && !retval; i ++) {
449                 if (argv[i][0] != '-') {
450                         continue;
451                 }
453                 if (!strcmp(argv[i], "-get_status")) {
454                         if (display_printer_status()) {
455                                 retval = 1;
456                         }
458                 } else if (!strcmp(argv[i], "-paper_loaded")) {
459                         if (set_printer_status(PRINTER_PAPER_EMPTY, 1)) {
460                                 retval = 1;
461                         }
463                 } else if (!strcmp(argv[i], "-paper_out")) {
464                         if (set_printer_status(PRINTER_PAPER_EMPTY, 0)) {
465                                 retval = 1;
466                         }
468                 } else if (!strcmp(argv[i], "-selected")) {
469                         if (set_printer_status(PRINTER_SELECTED, 0)) {
470                                 retval = 1;
471                         }
473                 } else if (!strcmp(argv[i], "-not_selected")) {
474                         if (set_printer_status(PRINTER_SELECTED, 1)) {
475                                 retval = 1;
476                         }
478                 } else if (!strcmp(argv[i], "-error")) {
479                         if (set_printer_status(PRINTER_NOT_ERROR, 1)) {
480                                 retval = 1;
481                         }
483                 } else if (!strcmp(argv[i], "-no_error")) {
484                         if (set_printer_status(PRINTER_NOT_ERROR, 0)) {
485                                 retval = 1;
486                         }
488                 } else if (!strcmp(argv[i], "-read_data")) {
489                         if (read_printer_data()) {
490                                 retval = 1;
491                         }
493                 } else if (!strcmp(argv[i], "-write_data")) {
494                         if (write_printer_data()) {
495                                 retval = 1;
496                         }
498                 } else if (!strcmp(argv[i], "-NB_read_data")) {
499                         if (read_NB_printer_data()) {
500                                 retval = 1;
501                         }
503                 } else {
504                         usage(argv[i]);
505                         retval = 1;
506                 }
507         }
509         exit(retval);