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 9GENERAL 10======= 11 12This driver may be used if you are writing printer firmware using Linux as 13the embedded OS. This driver has nothing to do with using a printer with 14your Linux host system. 15 16You will need a USB device controller and a Linux driver for it that accepts 17a gadget / "device class" driver using the Linux USB Gadget API. After the 18USB device controller driver is loaded then load the printer gadget driver. 19This will present a printer interface to the USB Host that your USB Device 20port is connected to. 21 22This driver is structured for printer firmware that runs in user mode. The 23user mode printer firmware will read and write data from the kernel mode 24printer gadget driver using a device file. The printer returns a printer status 25byte when the USB HOST sends a device request to get the printer status. The 26user 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 32HOWTO USE THIS DRIVER 33===================== 34 35To load the USB device controller driver and the printer gadget driver. The 36following example uses the Netchip 2280 USB device controller driver: 37 38modprobe net2280 39modprobe g_printer 40 41 42The follow command line parameter can be used when loading the printer gadget 43(ex: modprobe g_printer idVendor=0x0525 idProduct=0xa4a8 ): 44 45idVendor - 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 51idProduct - 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 56bcdDevice - This is the version number of your product. It would be a good idea 57 to put your firmware version here. 58 59iManufacturer - A string containing the name of the Vendor. 60 61iProduct - A string containing the Product Name. 62 63iSerialNum - A string containing the Serial Number. This should be changed for 64 each unit of your product. 65 66iPNPstring - 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 70qlen - 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 77USING THE EXAMPLE CODE 78====================== 79 80This example code talks to stdout, instead of a print engine. 81 82To compile the test code below: 83 841) save it to a file called prn_example.c 852) compile the code with the follow command: 86 gcc prn_example.c -o prn_example 87 88 89 90To read printer data from the host to stdout: 91 92 # prn_example -read_data 93 94 95To write printer data from a file (data_file) to the host: 96 97 # cat data_file | prn_example -write_data 98 99 100To 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 110To set printer to Selected/On-line: 111 112 # prn_example -selected 113 114 115To set printer to Not Selected/Off-line: 116 117 # prn_example -not_selected 118 119 120To set paper status to paper out: 121 122 # prn_example -paper_out 123 124 125To set paper status to paper loaded: 126 127 # prn_example -paper_loaded 128 129 130To set error status to printer OK: 131 132 # prn_example -no_error 133 134 135To set error status to ERROR: 136 137 # prn_example -error 138 139 140 141 142EXAMPLE 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 161static void 162usage(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 192static int 193read_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 242static int 243write_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 301static int 302read_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 335static int 336get_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 363static int 364set_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 403static int 404display_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 435int 436main(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} 511