/*
* usblp.c Version 0.13
*
* Copyright (c) 1999 Michael Gee <michael@linuxspecific.com>
* Copyright (c) 1999 Pavel Machek <pavel@suse.cz>
* Copyright (c) 2000 Randy Dunlap <rddunlap@osdl.org>
* Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz>
# Copyright (c) 2001 Pete Zaitcev <zaitcev@redhat.com>
# Copyright (c) 2001 David Paschal <paschal@rcsis.com>
*
* USB Printer Device Class driver for USB printers and printer cables
*
* Sponsored by SuSE
*
* ChangeLog:
* v0.1 - thorough cleaning, URBification, almost a rewrite
* v0.2 - some more cleanups
* v0.3 - cleaner again, waitqueue fixes
* v0.4 - fixes in unidirectional mode
* v0.5 - add DEVICE_ID string support
* v0.6 - never time out
* v0.7 - fixed bulk-IN read and poll (David Paschal)
* v0.8 - add devfs support
* v0.9 - fix unplug-while-open paths
* v0.10- remove sleep_on, fix error on oom (oliver@neukum.org)
* v0.11 - add proto_bias option (Pete Zaitcev)
* v0.12 - add hpoj.sourceforge.net ioctls (David Paschal)
* v0.13 - alloc space for statusbuf (<status> not on stack);
* use usb_buffer_alloc() for read buf & write buf;
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/signal.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/lp.h>
#undef DEBUG
#include <linux/usb.h>
/*
* Version Information
*/
#define DRIVER_VERSION "v0.13"
#define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap, Pete Zaitcev, David Paschal"
#define DRIVER_DESC "USB Printer Device Class driver"
#define USBLP_BUF_SIZE 8192
#define USBLP_DEVICE_ID_SIZE 1024
/* ioctls: */
#define LPGETSTATUS 0x060b /* same as in drivers/char/lp.c */
#define IOCNR_GET_DEVICE_ID 1
#define IOCNR_GET_PROTOCOLS 2
#define IOCNR_SET_PROTOCOL 3
#define IOCNR_HP_SET_CHANNEL 4
#define IOCNR_GET_BUS_ADDRESS 5
#define IOCNR_GET_VID_PID 6
#define IOCNR_SOFT_RESET 7
/* Get device_id string: */
#define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len)
/* The following ioctls were added for http://hpoj.sourceforge.net: */
/* Get two-int array:
* [0]=current protocol (1=7/1/1, 2=7/1/2, 3=7/1/3),
* [1]=supported protocol mask (mask&(1<<n)!=0 means 7/1/n supported): */
#define LPIOC_GET_PROTOCOLS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_PROTOCOLS, len)
/* Set protocol (arg: 1=7/1/1, 2=7/1/2, 3=7/1/3): */
#define LPIOC_SET_PROTOCOL _IOC(_IOC_WRITE, 'P', IOCNR_SET_PROTOCOL, 0)
/* Set channel number (HP Vendor-specific command): */
#define LPIOC_HP_SET_CHANNEL _IOC(_IOC_WRITE, 'P', IOCNR_HP_SET_CHANNEL, 0)
/* Get two-int array: [0]=bus number, [1]=device address: */
#define LPIOC_GET_BUS_ADDRESS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_BUS_ADDRESS, len)
/* Get two-int array: [0]=vendor ID, [1]=product ID: */
#define LPIOC_GET_VID_PID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_VID_PID, len)
/* Perform class specific soft reset */
#define LPIOC_SOFT_RESET _IOC(_IOC_NONE, 'P', IOCNR_SOFT_RESET, 0);
/*
* A DEVICE_ID string may include the printer's serial number.
* It should end with a semi-colon (';').
* An example from an HP 970C DeskJet printer is (this is one long string,
* with the serial number changed):
MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:Hewlett-Packard DeskJet 970C;SERN:US970CSEPROF;VSTATUS:$HB0$NC0,ff,DN,IDLE,CUT,K1,C0,DP,NR,KP000,CP027;VP:0800,FL,B0;VJ: ;
*/
/*
* USB Printer Requests
*/
#define USBLP_REQ_GET_ID 0x00
#define USBLP_REQ_GET_STATUS 0x01
#define USBLP_REQ_RESET 0x02
#define USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST 0x00 /* HP Vendor-specific */
#define USBLP_MINORS 16
#define USBLP_MINOR_BASE 0
#define USBLP_WRITE_TIMEOUT (5000) /* 5 seconds */
#define USBLP_FIRST_PROTOCOL 1
#define USBLP_LAST_PROTOCOL 3
#define USBLP_MAX_PROTOCOLS (USBLP_LAST_PROTOCOL+1)
/*
* some arbitrary status buffer size;
* need a status buffer that is allocated via kmalloc(), not on stack
*/
#define STATUS_BUF_SIZE 8
struct usblp {
struct usb_device *dev; /* USB device */
struct semaphore sem; /* locks this struct, especially "dev" */
char *writebuf; /* write transfer_buffer */
char *readbuf; /* read transfer_buffer */
char *statusbuf; /* status transfer_buffer */
struct urb *readurb, *writeurb; /* The urbs */
wait_queue_head_t wait; /* Zzzzz ... */
int readcount; /* Counter for reads */
int ifnum; /* Interface number */
struct usb_interface *intf; /* The interface */
/* Alternate-setting numbers and endpoints for each protocol
* (7/1/{index=1,2,3}) that the device supports: */
struct {
int alt_setting;
struct usb_endpoint_descriptor *epwrite;
struct usb_endpoint_descriptor *epread;
} protocol[USBLP_MAX_PROTOCOLS];
int current_protocol;
int minor; /* minor number of device */
int wcomplete; /* writing is completed */
int rcomplete; /* reading is completed */
unsigned int quirks; /* quirks flags */
unsigned char used; /* True if open */
unsigned char present; /* True if not disconnected */
unsigned char bidir; /* interface is bidirectional */
unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */
/* first 2 bytes are (big-endian) length */
};
#ifdef DEBUG
static void usblp_dump(struct usblp *usblp) {
int p;
dbg("usblp=0x%p", usblp