0001 ===============================
0002 Linux USB Printer Gadget Driver
0003 ===============================
0004
0005 06/04/2007
0006
0007 Copyright (C) 2007 Craig W. Nadler <craig@nadler.us>
0008
0009
0010
0011 General
0012 =======
0013
0014 This driver may be used if you are writing printer firmware using Linux as
0015 the embedded OS. This driver has nothing to do with using a printer with
0016 your Linux host system.
0017
0018 You will need a USB device controller and a Linux driver for it that accepts
0019 a gadget / "device class" driver using the Linux USB Gadget API. After the
0020 USB device controller driver is loaded then load the printer gadget driver.
0021 This will present a printer interface to the USB Host that your USB Device
0022 port is connected to.
0023
0024 This driver is structured for printer firmware that runs in user mode. The
0025 user mode printer firmware will read and write data from the kernel mode
0026 printer gadget driver using a device file. The printer returns a printer status
0027 byte when the USB HOST sends a device request to get the printer status. The
0028 user space firmware can read or write this status byte using a device file
0029 /dev/g_printer . Both blocking and non-blocking read/write calls are supported.
0030
0031
0032
0033
0034 Howto Use This Driver
0035 =====================
0036
0037 To load the USB device controller driver and the printer gadget driver. The
0038 following example uses the Netchip 2280 USB device controller driver::
0039
0040 modprobe net2280
0041 modprobe g_printer
0042
0043
0044 The follow command line parameter can be used when loading the printer gadget
0045 (ex: modprobe g_printer idVendor=0x0525 idProduct=0xa4a8 ):
0046
0047 idVendor
0048 This is the Vendor ID used in the device descriptor. The default is
0049 the Netchip vendor id 0x0525. YOU MUST CHANGE TO YOUR OWN VENDOR ID
0050 BEFORE RELEASING A PRODUCT. If you plan to release a product and don't
0051 already have a Vendor ID please see www.usb.org for details on how to
0052 get one.
0053
0054 idProduct
0055 This is the Product ID used in the device descriptor. The default
0056 is 0xa4a8, you should change this to an ID that's not used by any of
0057 your other USB products if you have any. It would be a good idea to
0058 start numbering your products starting with say 0x0001.
0059
0060 bcdDevice
0061 This is the version number of your product. It would be a good idea
0062 to put your firmware version here.
0063
0064 iManufacturer
0065 A string containing the name of the Vendor.
0066
0067 iProduct
0068 A string containing the Product Name.
0069
0070 iSerialNum
0071 A string containing the Serial Number. This should be changed for
0072 each unit of your product.
0073
0074 iPNPstring
0075 The PNP ID string used for this printer. You will want to set
0076 either on the command line or hard code the PNP ID string used for
0077 your printer product.
0078
0079 qlen
0080 The number of 8k buffers to use per endpoint. The default is 10, you
0081 should tune this for your product. You may also want to tune the
0082 size of each buffer for your product.
0083
0084
0085
0086
0087 Using The Example Code
0088 ======================
0089
0090 This example code talks to stdout, instead of a print engine.
0091
0092 To compile the test code below:
0093
0094 1) save it to a file called prn_example.c
0095 2) compile the code with the follow command::
0096
0097 gcc prn_example.c -o prn_example
0098
0099
0100
0101 To read printer data from the host to stdout::
0102
0103 # prn_example -read_data
0104
0105
0106 To write printer data from a file (data_file) to the host::
0107
0108 # cat data_file | prn_example -write_data
0109
0110
0111 To get the current printer status for the gadget driver:::
0112
0113 # prn_example -get_status
0114
0115 Printer status is:
0116 Printer is NOT Selected
0117 Paper is Out
0118 Printer OK
0119
0120
0121 To set printer to Selected/On-line::
0122
0123 # prn_example -selected
0124
0125
0126 To set printer to Not Selected/Off-line::
0127
0128 # prn_example -not_selected
0129
0130
0131 To set paper status to paper out::
0132
0133 # prn_example -paper_out
0134
0135
0136 To set paper status to paper loaded::
0137
0138 # prn_example -paper_loaded
0139
0140
0141 To set error status to printer OK::
0142
0143 # prn_example -no_error
0144
0145
0146 To set error status to ERROR::
0147
0148 # prn_example -error
0149
0150
0151
0152
0153 Example Code
0154 ============
0155
0156 ::
0157
0158
0159 #include <stdio.h>
0160 #include <stdlib.h>
0161 #include <fcntl.h>
0162 #include <linux/poll.h>
0163 #include <sys/ioctl.h>
0164 #include <linux/usb/g_printer.h>
0165
0166 #define PRINTER_FILE "/dev/g_printer"
0167 #define BUF_SIZE 512
0168
0169
0170 /*
0171 * 'usage()' - Show program usage.
0172 */
0173
0174 static void
0175 usage(const char *option) /* I - Option string or NULL */
0176 {
0177 if (option) {
0178 fprintf(stderr,"prn_example: Unknown option \"%s\"!\n",
0179 option);
0180 }
0181
0182 fputs("\n", stderr);
0183 fputs("Usage: prn_example -[options]\n", stderr);
0184 fputs("Options:\n", stderr);
0185 fputs("\n", stderr);
0186 fputs("-get_status Get the current printer status.\n", stderr);
0187 fputs("-selected Set the selected status to selected.\n", stderr);
0188 fputs("-not_selected Set the selected status to NOT selected.\n",
0189 stderr);
0190 fputs("-error Set the error status to error.\n", stderr);
0191 fputs("-no_error Set the error status to NO error.\n", stderr);
0192 fputs("-paper_out Set the paper status to paper out.\n", stderr);
0193 fputs("-paper_loaded Set the paper status to paper loaded.\n",
0194 stderr);
0195 fputs("-read_data Read printer data from driver.\n", stderr);
0196 fputs("-write_data Write printer sata to driver.\n", stderr);
0197 fputs("-NB_read_data (Non-Blocking) Read printer data from driver.\n",
0198 stderr);
0199 fputs("\n\n", stderr);
0200
0201 exit(1);
0202 }
0203
0204
0205 static int
0206 read_printer_data()
0207 {
0208 struct pollfd fd[1];
0209
0210 /* Open device file for printer gadget. */
0211 fd[0].fd = open(PRINTER_FILE, O_RDWR);
0212 if (fd[0].fd < 0) {
0213 printf("Error %d opening %s\n", fd[0].fd, PRINTER_FILE);
0214 close(fd[0].fd);
0215 return(-1);
0216 }
0217
0218 fd[0].events = POLLIN | POLLRDNORM;
0219
0220 while (1) {
0221 static char buf[BUF_SIZE];
0222 int bytes_read;
0223 int retval;
0224
0225 /* Wait for up to 1 second for data. */
0226 retval = poll(fd, 1, 1000);
0227
0228 if (retval && (fd[0].revents & POLLRDNORM)) {
0229
0230 /* Read data from printer gadget driver. */
0231 bytes_read = read(fd[0].fd, buf, BUF_SIZE);
0232
0233 if (bytes_read < 0) {
0234 printf("Error %d reading from %s\n",
0235 fd[0].fd, PRINTER_FILE);
0236 close(fd[0].fd);
0237 return(-1);
0238 } else if (bytes_read > 0) {
0239 /* Write data to standard OUTPUT (stdout). */
0240 fwrite(buf, 1, bytes_read, stdout);
0241 fflush(stdout);
0242 }
0243
0244 }
0245
0246 }
0247
0248 /* Close the device file. */
0249 close(fd[0].fd);
0250
0251 return 0;
0252 }
0253
0254
0255 static int
0256 write_printer_data()
0257 {
0258 struct pollfd fd[1];
0259
0260 /* Open device file for printer gadget. */
0261 fd[0].fd = open (PRINTER_FILE, O_RDWR);
0262 if (fd[0].fd < 0) {
0263 printf("Error %d opening %s\n", fd[0].fd, PRINTER_FILE);
0264 close(fd[0].fd);
0265 return(-1);
0266 }
0267
0268 fd[0].events = POLLOUT | POLLWRNORM;
0269
0270 while (1) {
0271 int retval;
0272 static char buf[BUF_SIZE];
0273 /* Read data from standard INPUT (stdin). */
0274 int bytes_read = fread(buf, 1, BUF_SIZE, stdin);
0275
0276 if (!bytes_read) {
0277 break;
0278 }
0279
0280 while (bytes_read) {
0281
0282 /* Wait for up to 1 second to sent data. */
0283 retval = poll(fd, 1, 1000);
0284
0285 /* Write data to printer gadget driver. */
0286 if (retval && (fd[0].revents & POLLWRNORM)) {
0287 retval = write(fd[0].fd, buf, bytes_read);
0288 if (retval < 0) {
0289 printf("Error %d writing to %s\n",
0290 fd[0].fd,
0291 PRINTER_FILE);
0292 close(fd[0].fd);
0293 return(-1);
0294 } else {
0295 bytes_read -= retval;
0296 }
0297
0298 }
0299
0300 }
0301
0302 }
0303
0304 /* Wait until the data has been sent. */
0305 fsync(fd[0].fd);
0306
0307 /* Close the device file. */
0308 close(fd[0].fd);
0309
0310 return 0;
0311 }
0312
0313
0314 static int
0315 read_NB_printer_data()
0316 {
0317 int fd;
0318 static char buf[BUF_SIZE];
0319 int bytes_read;
0320
0321 /* Open device file for printer gadget. */
0322 fd = open(PRINTER_FILE, O_RDWR|O_NONBLOCK);
0323 if (fd < 0) {
0324 printf("Error %d opening %s\n", fd, PRINTER_FILE);
0325 close(fd);
0326 return(-1);
0327 }
0328
0329 while (1) {
0330 /* Read data from printer gadget driver. */
0331 bytes_read = read(fd, buf, BUF_SIZE);
0332 if (bytes_read <= 0) {
0333 break;
0334 }
0335
0336 /* Write data to standard OUTPUT (stdout). */
0337 fwrite(buf, 1, bytes_read, stdout);
0338 fflush(stdout);
0339 }
0340
0341 /* Close the device file. */
0342 close(fd);
0343
0344 return 0;
0345 }
0346
0347
0348 static int
0349 get_printer_status()
0350 {
0351 int retval;
0352 int fd;
0353
0354 /* Open device file for printer gadget. */
0355 fd = open(PRINTER_FILE, O_RDWR);
0356 if (fd < 0) {
0357 printf("Error %d opening %s\n", fd, PRINTER_FILE);
0358 close(fd);
0359 return(-1);
0360 }
0361
0362 /* Make the IOCTL call. */
0363 retval = ioctl(fd, GADGET_GET_PRINTER_STATUS);
0364 if (retval < 0) {
0365 fprintf(stderr, "ERROR: Failed to set printer status\n");
0366 return(-1);
0367 }
0368
0369 /* Close the device file. */
0370 close(fd);
0371
0372 return(retval);
0373 }
0374
0375
0376 static int
0377 set_printer_status(unsigned char buf, int clear_printer_status_bit)
0378 {
0379 int retval;
0380 int fd;
0381
0382 retval = get_printer_status();
0383 if (retval < 0) {
0384 fprintf(stderr, "ERROR: Failed to get printer status\n");
0385 return(-1);
0386 }
0387
0388 /* Open device file for printer gadget. */
0389 fd = open(PRINTER_FILE, O_RDWR);
0390
0391 if (fd < 0) {
0392 printf("Error %d opening %s\n", fd, PRINTER_FILE);
0393 close(fd);
0394 return(-1);
0395 }
0396
0397 if (clear_printer_status_bit) {
0398 retval &= ~buf;
0399 } else {
0400 retval |= buf;
0401 }
0402
0403 /* Make the IOCTL call. */
0404 if (ioctl(fd, GADGET_SET_PRINTER_STATUS, (unsigned char)retval)) {
0405 fprintf(stderr, "ERROR: Failed to set printer status\n");
0406 return(-1);
0407 }
0408
0409 /* Close the device file. */
0410 close(fd);
0411
0412 return 0;
0413 }
0414
0415
0416 static int
0417 display_printer_status()
0418 {
0419 char printer_status;
0420
0421 printer_status = get_printer_status();
0422 if (printer_status < 0) {
0423 fprintf(stderr, "ERROR: Failed to get printer status\n");
0424 return(-1);
0425 }
0426
0427 printf("Printer status is:\n");
0428 if (printer_status & PRINTER_SELECTED) {
0429 printf(" Printer is Selected\n");
0430 } else {
0431 printf(" Printer is NOT Selected\n");
0432 }
0433 if (printer_status & PRINTER_PAPER_EMPTY) {
0434 printf(" Paper is Out\n");
0435 } else {
0436 printf(" Paper is Loaded\n");
0437 }
0438 if (printer_status & PRINTER_NOT_ERROR) {
0439 printf(" Printer OK\n");
0440 } else {
0441 printf(" Printer ERROR\n");
0442 }
0443
0444 return(0);
0445 }
0446
0447
0448 int
0449 main(int argc, char *argv[])
0450 {
0451 int i; /* Looping var */
0452 int retval = 0;
0453
0454 /* No Args */
0455 if (argc == 1) {
0456 usage(0);
0457 exit(0);
0458 }
0459
0460 for (i = 1; i < argc && !retval; i ++) {
0461
0462 if (argv[i][0] != '-') {
0463 continue;
0464 }
0465
0466 if (!strcmp(argv[i], "-get_status")) {
0467 if (display_printer_status()) {
0468 retval = 1;
0469 }
0470
0471 } else if (!strcmp(argv[i], "-paper_loaded")) {
0472 if (set_printer_status(PRINTER_PAPER_EMPTY, 1)) {
0473 retval = 1;
0474 }
0475
0476 } else if (!strcmp(argv[i], "-paper_out")) {
0477 if (set_printer_status(PRINTER_PAPER_EMPTY, 0)) {
0478 retval = 1;
0479 }
0480
0481 } else if (!strcmp(argv[i], "-selected")) {
0482 if (set_printer_status(PRINTER_SELECTED, 0)) {
0483 retval = 1;
0484 }
0485
0486 } else if (!strcmp(argv[i], "-not_selected")) {
0487 if (set_printer_status(PRINTER_SELECTED, 1)) {
0488 retval = 1;
0489 }
0490
0491 } else if (!strcmp(argv[i], "-error")) {
0492 if (set_printer_status(PRINTER_NOT_ERROR, 1)) {
0493 retval = 1;
0494 }
0495
0496 } else if (!strcmp(argv[i], "-no_error")) {
0497 if (set_printer_status(PRINTER_NOT_ERROR, 0)) {
0498 retval = 1;
0499 }
0500
0501 } else if (!strcmp(argv[i], "-read_data")) {
0502 if (read_printer_data()) {
0503 retval = 1;
0504 }
0505
0506 } else if (!strcmp(argv[i], "-write_data")) {
0507 if (write_printer_data()) {
0508 retval = 1;
0509 }
0510
0511 } else if (!strcmp(argv[i], "-NB_read_data")) {
0512 if (read_NB_printer_data()) {
0513 retval = 1;
0514 }
0515
0516 } else {
0517 usage(argv[i]);
0518 retval = 1;
0519 }
0520 }
0521
0522 exit(retval);
0523 }