| Start/ | End/ | |||
| True | False | - | Line | Source |
| 1 | /* | |||
| 2 | * usblp.c Version 0.13 | |||
| 3 | * | |||
| 4 | * Copyright (c) 1999 Michael Gee <michael@linuxspecific.com> | |||
| 5 | * Copyright (c) 1999 Pavel Machek <pavel@suse.cz> | |||
| 6 | * Copyright (c) 2000 Randy Dunlap <rdunlap@xenotime.net> | |||
| 7 | * Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz> | |||
| 8 | # Copyright (c) 2001 Pete Zaitcev <zaitcev@redhat.com> | |||
| 9 | # Copyright (c) 2001 David Paschal <paschal@rcsis.com> | |||
| 10 | * Copyright (c) 2006 Oliver Neukum <oliver@neukum.name> | |||
| 11 | * | |||
| 12 | * USB Printer Device Class driver for USB printers and printer cables | |||
| 13 | * | |||
| 14 | * Sponsored by SuSE | |||
| 15 | * | |||
| 16 | * ChangeLog: | |||
| 17 | * v0.1 - thorough cleaning, URBification, almost a rewrite | |||
| 18 | * v0.2 - some more cleanups | |||
| 19 | * v0.3 - cleaner again, waitqueue fixes | |||
| 20 | * v0.4 - fixes in unidirectional mode | |||
| 21 | * v0.5 - add DEVICE_ID string support | |||
| 22 | * v0.6 - never time out | |||
| 23 | * v0.7 - fixed bulk-IN read and poll (David Paschal) | |||
| 24 | * v0.8 - add devfs support | |||
| 25 | * v0.9 - fix unplug-while-open paths | |||
| 26 | * v0.10- remove sleep_on, fix error on oom (oliver@neukum.org) | |||
| 27 | * v0.11 - add proto_bias option (Pete Zaitcev) | |||
| 28 | * v0.12 - add hpoj.sourceforge.net ioctls (David Paschal) | |||
| 29 | * v0.13 - alloc space for statusbuf (<status> not on stack); | |||
| 30 | * use usb_buffer_alloc() for read buf & write buf; | |||
| 31 | */ | |||
| 32 | ||||
| 33 | /* | |||
| 34 | * This program is free software; you can redistribute it and/or modify | |||
| 35 | * it under the terms of the GNU General Public License as published by | |||
| 36 | * the Free Software Foundation; either version 2 of the License, or | |||
| 37 | * (at your option) any later version. | |||
| 38 | * | |||
| 39 | * This program is distributed in the hope that it will be useful, | |||
| 40 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 41 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| 42 | * GNU General Public License for more details. | |||
| 43 | * | |||
| 44 | * You should have received a copy of the GNU General Public License | |||
| 45 | * along with this program; if not, write to the Free Software | |||
| 46 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| 47 | */ | |||
| 48 | ||||
| 49 | #include <linux/module.h> | |||
| 50 | #include <linux/kernel.h> | |||
| 51 | #include <linux/sched.h> | |||
| 52 | #include <linux/smp_lock.h> | |||
| 53 | #include <linux/signal.h> | |||
| 54 | #include <linux/poll.h> | |||
| 55 | #include <linux/init.h> | |||
| 56 | #include <linux/slab.h> | |||
| 57 | #include <linux/lp.h> | |||
| 58 | #undef DEBUG | |||
| 59 | #include <linux/usb.h> | |||
| 60 | ||||
| 61 | /* | |||
| 62 | * Version Information | |||
| 63 | */ | |||
| 64 | #define DRIVER_VERSION "v0.13" | |||
| 65 | #define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap, Pete Zaitcev, David Paschal" | |||
| 66 | #define DRIVER_DESC "USB Printer Device Class driver" | |||
| 67 | ||||
| 68 | #define USBLP_BUF_SIZE 8192 | |||
| 69 | #define USBLP_DEVICE_ID_SIZE 1024 | |||
| 70 | ||||
| 71 | /* ioctls: */ | |||
| 72 | #define LPGETSTATUS 0x060b /* same as in drivers/char/lp.c */ | |||
| 73 | #define IOCNR_GET_DEVICE_ID 1 | |||
| 74 | #define IOCNR_GET_PROTOCOLS 2 | |||
| 75 | #define IOCNR_SET_PROTOCOL 3 | |||
| 76 | #define IOCNR_HP_SET_CHANNEL 4 | |||
| 77 | #define IOCNR_GET_BUS_ADDRESS 5 | |||
| 78 | #define IOCNR_GET_VID_PID 6 | |||
| 79 | #define IOCNR_SOFT_RESET 7 | |||
| 80 | /* Get device_id string: */ | |||
| 81 | #define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len) | |||
| 82 | /* The following ioctls were added for http://hpoj.sourceforge.net: */ | |||
| 83 | /* Get two-int array: | |||
| 84 | * [0]=current protocol (1=7/1/1, 2=7/1/2, 3=7/1/3), | |||
| 85 | * [1]=supported protocol mask (mask&(1<<n)!=0 means 7/1/n supported): */ | |||
| 86 | #define LPIOC_GET_PROTOCOLS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_PROTOCOLS, len) | |||
| 87 | /* Set protocol (arg: 1=7/1/1, 2=7/1/2, 3=7/1/3): */ | |||
| 88 | #define LPIOC_SET_PROTOCOL _IOC(_IOC_WRITE, 'P', IOCNR_SET_PROTOCOL, 0) | |||
| 89 | /* Set channel number (HP Vendor-specific command): */ | |||
| 90 | #define LPIOC_HP_SET_CHANNEL _IOC(_IOC_WRITE, 'P', IOCNR_HP_SET_CHANNEL, 0) | |||
| 91 | /* Get two-int array: [0]=bus number, [1]=device address: */ | |||
| 92 | #define LPIOC_GET_BUS_ADDRESS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_BUS_ADDRESS, len) | |||
| 93 | /* Get two-int array: [0]=vendor ID, [1]=product ID: */ | |||
| 94 | #define LPIOC_GET_VID_PID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_VID_PID, len) | |||
| 95 | /* Perform class specific soft reset */ | |||
| 96 | #define LPIOC_SOFT_RESET _IOC(_IOC_NONE, 'P', IOCNR_SOFT_RESET, 0); | |||
| 97 | ||||
| 98 | /* | |||
| 99 | * A DEVICE_ID string may include the printer's serial number. | |||
| 100 | * It should end with a semi-colon (';'). | |||
| 101 | * An example from an HP 970C DeskJet printer is (this is one long string, | |||
| 102 | * with the serial number changed): | |||
| 103 | 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: ; | |||
| 104 | */ | |||
| 105 | ||||
| 106 | /* | |||
| 107 | * USB Printer Requests | |||
| 108 | */ | |||
| 109 | ||||
| 110 | #define USBLP_REQ_GET_ID 0x00 | |||
| 111 | #define USBLP_REQ_GET_STATUS 0x01 | |||
| 112 | #define USBLP_REQ_RESET 0x02 | |||
| 113 | #define USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST 0x00 /* HP Vendor-specific */ | |||
| 114 | ||||
| 115 | #define USBLP_MINORS 16 | |||
| 116 | #define USBLP_MINOR_BASE 0 | |||
| 117 | ||||
| 118 | #define USBLP_WRITE_TIMEOUT (5000) /* 5 seconds */ | |||
| 119 | ||||
| 120 | #define USBLP_FIRST_PROTOCOL 1 | |||
| 121 | #define USBLP_LAST_PROTOCOL 3 | |||
| 122 | #define USBLP_MAX_PROTOCOLS (USBLP_LAST_PROTOCOL+1) | |||
| 123 | ||||
| 124 | /* | |||
| 125 | * some arbitrary status buffer size; | |||
| 126 | * need a status buffer that is allocated via kmalloc(), not on stack | |||
| 127 | */ | |||
| 128 | #define STATUS_BUF_SIZE 8 | |||
| 129 | ||||
| 130 | struct usblp { | |||
| 131 | struct usb_device *dev; /* USB device */ | |||
| 132 | struct semaphore sem; /* locks this struct, especially "dev" */ | |||
| 133 | char *writebuf; /* write transfer_buffer */ | |||
| 134 | char *readbuf; /* read transfer_buffer */ | |||
| 135 | char *statusbuf; /* status transfer_buffer */ | |||
| 136 | struct urb *readurb, *writeurb; /* The urbs */ | |||
| 137 | wait_queue_head_t wait; /* Zzzzz ... */ | |||
| 138 | int readcount; /* Counter for reads */ | |||
| 139 | int ifnum; /* Interface number */ | |||
| 140 | struct usb_interface *intf; /* The interface */ | |||
| 141 | /* Alternate-setting numbers and endpoints for each protocol | |||
| 142 | * (7/1/{index=1,2,3}) that the device supports: */ | |||
| 143 | struct { | |||
| 144 | int alt_setting; | |||
| 145 | struct usb_endpoint_descriptor *epwrite; | |||
| 146 | struct usb_endpoint_descriptor *epread; | |||
| 147 | } protocol[USBLP_MAX_PROTOCOLS]; | |||
| 148 | int current_protocol; | |||
| 149 | int minor; /* minor number of device */ | |||
| 150 | int wcomplete; /* writing is completed */ | |||
| 151 | int rcomplete; /* reading is completed */ | |||
| 152 | unsigned int quirks; /* quirks flags */ | |||
| 153 | unsigned char used; /* True if open */ | |||
| 154 | unsigned char present; /* True if not disconnected */ | |||
| 155 | unsigned char bidir; /* interface is bidirectional */ | |||
| 156 | unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */ | |||
| 157 | /* first 2 bytes are (big-endian) length */ | |||
| 158 | }; | |||
| 159 | ||||
| 160 | #ifdef DEBUG | |||
| 161 | static void usblp_dump(struct usblp *usblp) { | |||
| 162 | int p; | |||
| 163 | ||||
| 164 | dbg("usblp=0x%p", usblp); | |||
| 165 | dbg("dev=0x%p", usblp->dev); | |||
| 166 | dbg("present=%d", usblp->present); | |||
| 167 | dbg("readbuf=0x%p", usblp->readbuf); | |||
| 168 | dbg("writebuf=0x%p", usblp->writebuf); | |||
| 169 | dbg("readurb=0x%p", usblp->readurb); | |||
| 170 | dbg("writeurb=0x%p", usblp->writeurb); | |||
| 171 | dbg("readcount=%d", usblp->readcount); | |||
| 172 | dbg("ifnum=%d", usblp->ifnum); | |||
| 173 | for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) { | |||
| 174 | dbg("protocol[%d].alt_setting=%d", p, usblp->protocol[p].alt_setting); | |||
| 175 | dbg("protocol[%d].epwrite=%p", p, usblp->protocol[p].epwrite); | |||
| 176 | dbg("protocol[%d].epread=%p", p, usblp->protocol[p].epread); | |||
| 177 | } | |||
| 178 | dbg("current_protocol=%d", usblp->current_protocol); | |||
| 179 | dbg("minor=%d", usblp->minor); | |||
| 180 | dbg("wcomplete=%d", usblp->wcomplete); | |||
| 181 | dbg("rcomplete=%d", usblp->rcomplete); | |||
| 182 | dbg("quirks=%d", usblp->quirks); | |||
| 183 | dbg("used=%d", usblp->used); | |||
| 184 | dbg("bidir=%d", usblp->bidir); | |||
| 185 | dbg("device_id_string=\"%s\"", | |||
| 186 | usblp->device_id_string ? | |||
| 187 | usblp->device_id_string + 2 : | |||
| 188 | (unsigned char *)"(null)"); | |||
| 189 | } | |||
| 190 | #endif | |||
| 191 | ||||
| 192 | /* Quirks: various printer quirks are handled by this table & its flags. */ | |||
| 193 | ||||
| 194 | struct quirk_printer_struct { | |||
| 195 | __u16 vendorId; | |||
| 196 | __u16 productId; | |||
| 197 | unsigned int quirks; | |||
| 198 | }; | |||
| 199 | ||||
| 200 | #define USBLP_QUIRK_BIDIR 0x1 /* reports bidir but requires unidirectional mode (no INs/reads) */ | |||
| 201 | #define USBLP_QUIRK_USB_INIT 0x2 /* needs vendor USB init string */ | |||
| 202 | ||||
| 203 | static const struct quirk_printer_struct quirk_printers[] = { | |||
| 204 | { 0x03f0, 0x0004, USBLP_QUIRK_BIDIR }, /* HP DeskJet 895C */ | |||
| 205 | { 0x03f0, 0x0104, USBLP_QUIRK_BIDIR }, /* HP DeskJet 880C */ | |||
| 206 | { 0x03f0, 0x0204, USBLP_QUIRK_BIDIR }, /* HP DeskJet 815C */ | |||
| 207 | { 0x03f0, 0x0304, USBLP_QUIRK_BIDIR }, /* HP DeskJet 810C/812C */ | |||
| 208 | { 0x03f0, 0x0404, USBLP_QUIRK_BIDIR }, /* HP DeskJet 830C */ | |||
| 209 | { 0x03f0, 0x0504, USBLP_QUIRK_BIDIR }, /* HP DeskJet 885C */ | |||
| 210 | { 0x03f0, 0x0604, USBLP_QUIRK_BIDIR }, /* HP DeskJet 840C */ | |||
| 211 | { 0x03f0, 0x0804, USBLP_QUIRK_BIDIR }, /* HP DeskJet 816C */ | |||
| 212 | { 0x03f0, 0x1104, USBLP_QUIRK_BIDIR }, /* HP Deskjet 959C */ | |||
| 213 | { 0x0409, 0xefbe, USBLP_QUIRK_BIDIR }, /* NEC Picty900 (HP OEM) */ | |||
| 214 | { 0x0409, 0xbef4, USBLP_QUIRK_BIDIR }, /* NEC Picty760 (HP OEM) */ | |||
| 215 | { 0x0409, 0xf0be, USBLP_QUIRK_BIDIR }, /* NEC Picty920 (HP OEM) */ | |||
| 216 | { 0x0409, 0xf1be, USBLP_QUIRK_BIDIR }, /* NEC Picty800 (HP OEM) */ | |||
| 217 | { 0, 0 } | |||
| 218 | }; | |||
| 219 | ||||
| 220 | static int usblp_select_alts(struct usblp *usblp); | |||
| 221 | static int usblp_set_protocol(struct usblp *usblp, int protocol); | |||
| 222 | static int usblp_cache_device_id_string(struct usblp *usblp); | |||
| 223 | ||||
| 224 | /* forward reference to make our lives easier */ | |||
| 225 | static struct usb_driver usblp_driver; | |||
| 226 | static DECLARE_MUTEX(usblp_sem); /* locks the existence of usblp's */ | |||
| 227 | ||||
| 228 | /* | |||
| 229 | * Functions for usblp control messages. | |||
| 230 | */ | |||
| 231 | ||||
| 0 | 0 | - | 232 | static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, int recip, int value, void *buf, int len) |
| 233 | { | |||
| 234 | int retval; | |||
| 235 | int index = usblp->ifnum; | |||
| 236 | ||||
| 237 | /* High byte has the interface index. | |||
| 238 | Low byte has the alternate setting. | |||
| 239 | */ | |||
| 0 | 0 | - | 240 | if ((request == USBLP_REQ_GET_ID) && (type == USB_TYPE_CLASS)) { |
| 0 | - | 240 | (T) && (T) | |
| 0 | - | 240 | (T) && (F) | |
| 0 | - | 240 | (F) && (_) | |
| 241 | index = (usblp->ifnum<<8)|usblp->protocol[usblp->current_protocol].alt_setting; | |||
| 242 | } | |||
| 243 | ||||
| 244 | retval = usb_control_msg(usblp->dev, | |||
| 245 | dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0), | |||
| 0 | 0 | - | 245 | ternary-?: dir |
| 246 | request, type | dir | recip, value, index, buf, len, USBLP_WRITE_TIMEOUT); | |||
| 247 | dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d", | |||
| 0 | 0 | - | 247 | do-while (0) |
| 248 | request, !!dir, recip, value, index, len, retval); | |||
| 249 | return retval < 0 ? retval : 0; | |||
| 0 | 0 | - | 249 | ternary-?: retval < 0 |
| 0 | - | 249 | return retval < 0 ? retval : 0 | |
| 250 | } | |||
| 251 | ||||
| 252 | #define usblp_read_status(usblp, status)\ | |||
| 253 | usblp_ctrl_msg(usblp, USBLP_REQ_GET_STATUS, USB_TYPE_CLASS, USB_DIR_IN, USB_RECIP_INTERFACE, 0, status, 1) | |||
| 254 | #define usblp_get_id(usblp, config, id, maxlen)\ | |||
| 255 | usblp_ctrl_msg(usblp, USBLP_REQ_GET_ID, USB_TYPE_CLASS, USB_DIR_IN, USB_RECIP_INTERFACE, config, id, maxlen) | |||
| 256 | #define usblp_reset(usblp)\ | |||
| 257 | usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_TYPE_CLASS, USB_DIR_OUT, USB_RECIP_OTHER, 0, NULL, 0) | |||
| 258 | ||||
| 259 | #define usblp_hp_channel_change_request(usblp, channel, buffer) \ | |||
| 260 | usblp_ctrl_msg(usblp, USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST, USB_TYPE_VENDOR, USB_DIR_IN, USB_RECIP_INTERFACE, channel, buffer, 1) | |||
| 261 | ||||
| 262 | /* | |||
| 263 | * See the description for usblp_select_alts() below for the usage | |||
| 264 | * explanation. Look into your /proc/bus/usb/devices and dmesg in | |||
| 265 | * case of any trouble. | |||
| 266 | */ | |||
| 267 | static int proto_bias = -1; | |||
| 268 | ||||
| 269 | /* | |||
| 270 | * URB callback. | |||
| 271 | */ | |||
| 272 | ||||
| 0 | 0 | - | 273 | static void usblp_bulk_read(struct urb *urb, struct pt_regs *regs) |
| 274 | { | |||
| 275 | struct usblp *usblp = urb->context; | |||
| 276 | ||||
| 0 | 0 | - | 277 | if (unlikely(!usblp || !usblp->dev || !usblp->used)) |
| 0 | - | 278 | return; | |
| 279 | ||||
| 0 | 0 | - | 280 | if (unlikely(!usblp->present)) |
| 0 | - | 281 | goto unplug; | |
| 0 | 0 | - | 282 | if (unlikely(urb->status)) |
| 283 | warn("usblp%d: nonzero read/write bulk status received: %d", | |||
| 284 | usblp->minor, urb->status); | |||
| 285 | usblp->rcomplete = 1; | |||
| 286 | unplug: | |||
| 287 | wake_up_interruptible(&usblp->wait); | |||
| 288 | } | |||
| 289 | ||||
| 0 | 0 | - | 290 | static void usblp_bulk_write(struct urb *urb, struct pt_regs *regs) |
| 291 | { | |||
| 292 | struct usblp *usblp = urb->context; | |||
| 293 | ||||
| 0 | 0 | - | 294 | if (unlikely(!usblp || !usblp->dev || !usblp->used)) |
| 0 | - | 295 | return; | |
| 0 | 0 | - | 296 | if (unlikely(!usblp->present)) |
| 0 | - | 297 | goto unplug; | |
| 0 | 0 | - | 298 | if (unlikely(urb->status)) |
| 299 | warn("usblp%d: nonzero read/write bulk status received: %d", | |||
| 300 | usblp->minor, urb->status); | |||
| 301 | usblp->wcomplete = 1; | |||
| 302 | unplug: | |||
| 303 | wake_up_interruptible(&usblp->wait); | |||
| 304 | } | |||
| 305 | ||||
| 306 | /* | |||
| 307 | * Get and print printer errors. | |||
| 308 | */ | |||
| 309 | ||||
| 310 | static const char *usblp_messages[] = { "ok", "out of paper", "off-line", "on fire" }; | |||
| 311 | ||||
| 0 | 0 | - | 312 | static int usblp_check_status(struct usblp *usblp, int err) |
| 313 | { | |||
| 314 | unsigned char status, newerr = 0; | |||
| 315 | int error; | |||
| 316 | ||||
| 317 | error = usblp_read_status (usblp, usblp->statusbuf); | |||
| 0 | 0 | - | 318 | if (error < 0) { |
| 0 | 0 | - | 319 | if (printk_ratelimit()) |
| 320 | err("usblp%d: error %d reading printer status", | |||
| 321 | usblp->minor, error); | |||
| 0 | - | 322 | return 0; | |
| 323 | } | |||
| 324 | ||||
| 325 | status = *usblp->statusbuf; | |||
| 326 | ||||
| 0 | 0 | - | 327 | if (~status & LP_PERRORP) |
| 328 | newerr = 3; | |||
| 0 | 0 | - | 329 | if (status & LP_POUTPA) |
| 330 | newerr = 1; | |||
| 0 | 0 | - | 331 | if (~status & LP_PSELECD) |
| 332 | newerr = 2; | |||
| 333 | ||||
| 0 | 0 | - | 334 | if (newerr != err) |
| 335 | info("usblp%d: %s", usblp->minor, usblp_messages[newerr]); | |||
| 336 | ||||
| 0 | - | 337 | return newerr; | |
| 338 | } | |||
| 339 | ||||
| 340 | /* | |||
| 341 | * File op functions. | |||
| 342 | */ | |||
| 343 | ||||
| 0 | 0 | - | 344 | static int usblp_open(struct inode *inode, struct file *file) |
| 345 | { | |||
| 346 | int minor = iminor(inode); | |||
| 347 | struct usblp *usblp; | |||
| 348 | struct usb_interface *intf; | |||
| 349 | int retval; | |||
| 350 | ||||
| 0 | 0 | - | 351 | if (minor < 0) |
| 0 | - | 352 | return -ENODEV; | |
| 353 | ||||
| 354 | down (&usblp_sem); | |||
| 355 | ||||
| 356 | retval = -ENODEV; | |||
| 357 | intf = usb_find_interface(&usblp_driver, minor); | |||
| 0 | 0 | - | 358 | if (!intf) { |
| 0 | - | 359 | goto out; | |
| 360 | } | |||
| 361 | usblp = usb_get_intfdata (intf); | |||
| 0 | 0 | - | 362 | if (!usblp || !usblp->dev || !usblp->present) |
| 0 | - | 362 | T || _ || _ | |
| 0 | - | 362 | F || T || _ | |
| 0 | - | 362 | F || F || T | |
| 0 | - | 362 | F || F || F | |
| 0 | - | 363 | goto out; | |
| 364 | ||||
| 365 | retval = -EBUSY; | |||
| 0 | 0 | - | 366 | if (usblp->used) |
| 0 | - | 367 | goto out; | |
| 368 | ||||
| 369 | /* | |||
| 370 | * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ??? | |||
| 371 | * This is #if 0-ed because we *don't* want to fail an open | |||
| 372 | * just because the printer is off-line. | |||
| 373 | */ | |||
| 374 | #if 0 | |||
| 375 | if ((retval = usblp_check_status(usblp, 0))) { | |||
| 376 | retval = retval > 1 ? -EIO : -ENOSPC; | |||
| 377 | goto out; | |||
| 378 | } | |||
| 379 | #else | |||
| 380 | retval = 0; | |||
| 381 | #endif | |||
| 382 | ||||
| 383 | usblp->used = 1; | |||
| 384 | file->private_data = usblp; | |||
| 385 | ||||
| 386 | usblp->writeurb->transfer_buffer_length = 0; | |||
| 387 | usblp->wcomplete = 1; /* we begin writeable */ | |||
| 388 | usblp->rcomplete = 0; | |||
| 389 | usblp->writeurb->status = 0; | |||
| 390 | usblp->readurb->status = 0; | |||
| 391 | ||||
| 0 | 0 | - | 392 | if (usblp->bidir) { |
| 393 | usblp->readcount = 0; | |||
| 394 | usblp->readurb->dev = usblp->dev; | |||
| 0 | 0 | - | 395 | if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) { |
| 396 | retval = -EIO; | |||
| 397 | usblp->used = 0; | |||
| 398 | file->private_data = NULL; | |||
| 399 | } | |||
| 400 | } | |||
| 401 | out: | |||
| 402 | up (&usblp_sem); | |||
| 0 | - | 403 | return retval; | |
| 404 | } | |||
| 405 | ||||
| 0 | 0 | - | 406 | static void usblp_cleanup (struct usblp *usblp) |
| 407 | { | |||
| 408 | info("usblp%d: removed", usblp->minor); | |||
| 409 | ||||
| 410 | kfree (usblp->device_id_string); | |||
| 411 | kfree (usblp->statusbuf); | |||
| 412 | usb_free_urb(usblp->writeurb); | |||
| 413 | usb_free_urb(usblp->readurb); | |||
| 414 | kfree (usblp); | |||
| 415 | } | |||
| 416 | ||||
| 0 | 0 | - | 417 | static void usblp_unlink_urbs(struct usblp *usblp) |
| 418 | { | |||
| 419 | usb_kill_urb(usblp->writeurb); | |||
| 0 | 0 | - | 420 | if (usblp->bidir) |
| 421 | usb_kill_urb(usblp->readurb); | |||
| 422 | } | |||
| 423 | ||||
| 0 | 0 | - | 424 | static int usblp_release(struct inode *inode, struct file *file) |
| 425 | { | |||
| 426 | struct usblp *usblp = file->private_data; | |||
| 427 | ||||
| 428 | down (&usblp_sem); | |||
| 429 | usblp->used = 0; | |||
| 0 | 0 | - | 430 | if (usblp->present) { |
| 431 | usblp_unlink_urbs(usblp); | |||
| 432 | } else /* finish cleanup from disconnect */ | |||
| 433 | usblp_cleanup (usblp); | |||
| 434 | up (&usblp_sem); | |||
| 0 | - | 435 | return 0; | |
| 436 | } | |||
| 437 | ||||
| 438 | /* No kernel lock - fine */ | |||
| 0 | 0 | - | 439 | static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait) |
| 440 | { | |||
| 441 | struct usblp *usblp = file->private_data; | |||
| 442 | poll_wait(file, &usblp->wait, wait); | |||
| 443 | return ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN | POLLRDNORM) | |||
| 0 | 0 | - | 443 | ternary-?: ( ! usblp -> bidir || ! usblp -> rc.. |
| 444 | | (!usblp->wcomplete ? 0 : POLLOUT | POLLWRNORM); | |||
| 0 | 0 | - | 444 | ternary-?: ! usblp -> wcomplete |
| 0 | - | 444 | return ( ( ! usblp -> bidir || ! usblp -> rcom.. | |
| 445 | } | |||
| 446 | ||||
| 0 | 0 | - | 447 | static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
| 448 | { | |||
| 449 | struct usblp *usblp = file->private_data; | |||
| 450 | int length, err, i; | |||
| 451 | unsigned char newChannel; | |||
| 452 | int status; | |||
| 453 | int twoints[2]; | |||
| 454 | int retval = 0; | |||
| 455 | ||||
| 456 | down (&usblp->sem); | |||
| 0 | 0 | - | 457 | if (!usblp->present) { |
| 458 | retval = -ENODEV; | |||
| 0 | - | 459 | goto done; | |
| 460 | } | |||
| 461 | ||||
| 462 | dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd), | |||
| 0 | 0 | - | 462 | do-while (0) |
| 463 | _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd) ); | |||
| 464 | ||||
| 0 | 0 | - | 465 | if (_IOC_TYPE(cmd) == 'P') /* new-style ioctl number */ |
| 466 | ||||
| 467 | switch (_IOC_NR(cmd)) { | |||
| 468 | ||||
| 0 | - | 469 | case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */ | |
| 0 | 0 | - | 470 | if (_IOC_DIR(cmd) != _IOC_READ) { |
| 471 | retval = -EINVAL; | |||
| 0 | - | 472 | goto done; | |
| 473 | } | |||
| 474 | ||||
| 475 | length = usblp_cache_device_id_string(usblp); | |||
| 0 | 0 | - | 476 | if (length < 0) { |
| 477 | retval = length; | |||
| 0 | - | 478 | goto done; | |
| 479 | } | |||
| 0 | 0 | - | 480 | if (length > _IOC_SIZE(cmd)) |
| 481 | length = _IOC_SIZE(cmd); /* truncate */ | |||
| 482 | ||||
| 483 | if (copy_to_user((void __user *) arg, | |||
| 484 | usblp->device_id_string, | |||
| 0 | 0 | - | 485 | (unsigned long) length)) { |
| 486 | retval = -EFAULT; | |||
| 0 | - | 487 | goto done; | |
| 488 | } | |||
| 489 | ||||
| 0 | - | 490 | break; | |
| 491 | ||||
| 0 | - | 492 | case IOCNR_GET_PROTOCOLS: | |
| 493 | if (_IOC_DIR(cmd) != _IOC_READ || | |||
| 0 | 0 | - | 494 | _IOC_SIZE(cmd) < sizeof(twoints)) { |
| 0 | - | 494 | T || _ | |
| 0 | - | 494 | F || T | |
| 0 | - | 494 | F || F | |
| 495 | retval = -EINVAL; | |||
| 0 | - | 496 | goto done; | |
| 497 | } | |||
| 498 | ||||
| 499 | twoints[0] = usblp->current_protocol; | |||
| 500 | twoints[1] = 0; | |||
| 501 | for (i = USBLP_FIRST_PROTOCOL; | |||
| 0 | 0 | - | 502 | i <= USBLP_LAST_PROTOCOL; i++) { |
| 0 | 0 | - | 503 | if (usblp->protocol[i].alt_setting >= 0) |
| 504 | twoints[1] |= (1<<i); | |||
| 505 | } | |||
| 506 | ||||
| 507 | if (copy_to_user((void __user *)arg, | |||
| 508 | (unsigned char *)twoints, | |||
| 0 | 0 | - | 509 | sizeof(twoints))) { |
| 510 | retval = -EFAULT; | |||
| 0 | - | 511 | goto done; | |
| 512 | } | |||
| 513 | ||||
| 0 | - | 514 | break; | |
| 515 | ||||
| 0 | - | 516 | case IOCNR_SET_PROTOCOL: | |
| 0 | 0 | - | 517 | if (_IOC_DIR(cmd) != _IOC_WRITE) { |
| 518 | retval = -EINVAL; | |||
| 0 | - | 519 | goto done; | |
| 520 | } | |||
| 521 | ||||
| 522 | ||||