Merge git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
[pandora-kernel.git] / Documentation / usb / gadget_printer.txt
1
2                        Linux USB Printer Gadget Driver
3                                  06/04/2007
4
5               Copyright (C) 2007 Craig W. Nadler <craig@nadler.us>
6
7
8
9 GENERAL
10 =======
11
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.
15
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.
21
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.
28
29
30
31
32 HOWTO USE THIS DRIVER
33 =====================
34
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:
37
38 modprobe net2280
39 modprobe g_printer
40
41
42 The follow command line parameter can be used when loading the printer gadget
43 (ex: modprobe g_printer idVendor=0x0525 idProduct=0xa4a8 ):
44
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.
50
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.
55
56 bcdDevice - This is the version number of your product. It would be a good idea
57         to put your firmware version here.
58
59 iManufacturer - A string containing the name of the Vendor.
60
61 iProduct - A string containing the Product Name.
62
63 iSerialNum - A string containing the Serial Number. This should be changed for
64         each unit of your product.
65
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.
69
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.
73
74
75
76
77 USING THE EXAMPLE CODE
78 ======================
79
80 This example code talks to stdout, instead of a print engine.
81
82 To compile the test code below:
83
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
87
88
89
90 To read printer data from the host to stdout:
91
92         # prn_example -read_data
93
94
95 To write printer data from a file (data_file) to the host:
96
97         # cat data_file | prn_example -write_data
98
99
100 To get the current printer status for the gadget driver:
101
102         # prn_example -get_status
103
104         Printer status is:
105              Printer is NOT Selected
106              Paper is Out
107              Printer OK
108
109
110 To set printer to Selected/On-line:
111
112         # prn_example -selected
113
114
115 To set printer to Not Selected/Off-line:
116
117         # prn_example -not_selected
118
119
120 To set paper status to paper out:
121
122         # prn_example -paper_out
123
124
125 To set paper status to paper loaded:
126
127         # prn_example -paper_loaded
128
129
130 To set error status to printer OK:
131
132         # prn_example -no_error
133
134
135 To set error status to ERROR:
136
137         # prn_example -error
138
139
140
141
142 EXAMPLE CODE
143 ============
144
145
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>
152
153 #define PRINTER_FILE                    "/dev/g_printer"
154 #define BUF_SIZE                        512
155
156
157 /*
158  * 'usage()' - Show program usage.
159  */
160
161 static void
162 usage(const char *option)               /* I - Option string or NULL */
163 {
164         if (option) {
165                 fprintf(stderr,"prn_example: Unknown option \"%s\"!\n",
166                                 option);
167         }
168
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);
187
188         exit(1);
189 }
190
191
192 static int
193 read_printer_data()
194 {
195         struct pollfd   fd[1];
196
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         }
204
205         fd[0].events = POLLIN | POLLRDNORM;
206
207         while (1) {
208                 static char buf[BUF_SIZE];
209                 int bytes_read;
210                 int retval;
211
212                 /* Wait for up to 1 second for data. */
213                 retval = poll(fd, 1, 1000);
214
215                 if (retval && (fd[0].revents & POLLRDNORM)) {
216
217                         /* Read data from printer gadget driver. */
218                         bytes_read = read(fd[0].fd, buf, BUF_SIZE);
219
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                         }
230
231                 }
232
233         }
234
235         /* Close the device file. */
236         close(fd[0].fd);
237
238         return 0;
239 }
240
241
242 static int
243 write_printer_data()
244 {
245         struct pollfd   fd[1];
246
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         }
254
255         fd[0].events = POLLOUT | POLLWRNORM;
256
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);
262
263                 if (!bytes_read) {
264                         break;
265                 }
266
267                 while (bytes_read) {
268
269                         /* Wait for up to 1 second to sent data. */
270                         retval = poll(fd, 1, 1000);
271
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                                 }
284
285                         }
286
287                 }
288
289         }
290
291         /* Wait until the data has been sent. */
292         fsync(fd[0].fd);
293
294         /* Close the device file. */
295         close(fd[0].fd);
296
297         return 0;
298 }
299
300
301 static int
302 read_NB_printer_data()
303 {
304         int             fd;
305         static char     buf[BUF_SIZE];
306         int             bytes_read;
307
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         }
315
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                 }
322
323                 /* Write data to standard OUTPUT (stdout). */
324                 fwrite(buf, 1, bytes_read, stdout);
325                 fflush(stdout);
326         }
327
328         /* Close the device file. */
329         close(fd);
330
331         return 0;
332 }
333
334
335 static int
336 get_printer_status()
337 {
338         int     retval;
339         int     fd;
340
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         }
348
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         }
355
356         /* Close the device file. */
357         close(fd);
358
359         return(retval);
360 }
361
362
363 static int
364 set_printer_status(unsigned char buf, int clear_printer_status_bit)
365 {
366         int     retval;
367         int     fd;
368
369         retval = get_printer_status();
370         if (retval < 0) {
371                 fprintf(stderr, "ERROR: Failed to get printer status\n");
372                 return(-1);
373         }
374
375         /* Open device file for printer gadget. */
376         fd = open(PRINTER_FILE, O_RDWR);
377
378         if (fd < 0) {
379                 printf("Error %d opening %s\n", fd, PRINTER_FILE);
380                 close(fd);
381                 return(-1);
382         }
383
384         if (clear_printer_status_bit) {
385                 retval &= ~buf;
386         } else {
387                 retval |= buf;
388         }
389
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         }
395
396         /* Close the device file. */
397         close(fd);
398
399         return 0;
400 }
401
402
403 static int
404 display_printer_status()
405 {
406         char    printer_status;
407
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         }
413
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         }
430
431         return(0);
432 }
433
434
435 int
436 main(int  argc, char *argv[])
437 {
438         int     i;              /* Looping var */
439         int     retval = 0;
440
441         /* No Args */
442         if (argc == 1) {
443                 usage(0);
444                 exit(0);
445         }
446
447         for (i = 1; i < argc && !retval; i ++) {
448
449                 if (argv[i][0] != '-') {
450                         continue;
451                 }
452
453                 if (!strcmp(argv[i], "-get_status")) {
454                         if (display_printer_status()) {
455                                 retval = 1;
456                         }
457
458                 } else if (!strcmp(argv[i], "-paper_loaded")) {
459                         if (set_printer_status(PRINTER_PAPER_EMPTY, 1)) {
460                                 retval = 1;
461                         }
462
463                 } else if (!strcmp(argv[i], "-paper_out")) {
464                         if (set_printer_status(PRINTER_PAPER_EMPTY, 0)) {
465                                 retval = 1;
466                         }
467
468                 } else if (!strcmp(argv[i], "-selected")) {
469                         if (set_printer_status(PRINTER_SELECTED, 0)) {
470                                 retval = 1;
471                         }
472
473                 } else if (!strcmp(argv[i], "-not_selected")) {
474                         if (set_printer_status(PRINTER_SELECTED, 1)) {
475                                 retval = 1;
476                         }
477
478                 } else if (!strcmp(argv[i], "-error")) {
479                         if (set_printer_status(PRINTER_NOT_ERROR, 1)) {
480                                 retval = 1;
481                         }
482
483                 } else if (!strcmp(argv[i], "-no_error")) {
484                         if (set_printer_status(PRINTER_NOT_ERROR, 0)) {
485                                 retval = 1;
486                         }
487
488                 } else if (!strcmp(argv[i], "-read_data")) {
489                         if (read_printer_data()) {
490                                 retval = 1;
491                         }
492
493                 } else if (!strcmp(argv[i], "-write_data")) {
494                         if (write_printer_data()) {
495                                 retval = 1;
496                         }
497
498                 } else if (!strcmp(argv[i], "-NB_read_data")) {
499                         if (read_NB_printer_data()) {
500                                 retval = 1;
501                         }
502
503                 } else {
504                         usage(argv[i]);
505                         retval = 1;
506                 }
507         }
508
509         exit(retval);
510 }