| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * USB IR Dongle driver | 
|  | 3 | * | 
|  | 4 | *	Copyright (C) 2001-2002	Greg Kroah-Hartman (greg@kroah.com) | 
|  | 5 | *	Copyright (C) 2002	Gary Brubaker (xavyer@ix.netcom.com) | 
|  | 6 | * | 
|  | 7 | *	This program is free software; you can redistribute it and/or modify | 
|  | 8 | *	it under the terms of the GNU General Public License as published by | 
|  | 9 | *	the Free Software Foundation; either version 2 of the License, or | 
|  | 10 | *	(at your option) any later version. | 
|  | 11 | * | 
|  | 12 | * This driver allows a USB IrDA device to be used as a "dumb" serial device. | 
|  | 13 | * This can be useful if you do not have access to a full IrDA stack on the | 
|  | 14 | * other side of the connection.  If you do have an IrDA stack on both devices, | 
|  | 15 | * please use the usb-irda driver, as it contains the proper error checking and | 
|  | 16 | * other goodness of a full IrDA stack. | 
|  | 17 | * | 
|  | 18 | * Portions of this driver were taken from drivers/net/irda/irda-usb.c, which | 
|  | 19 | * was written by Roman Weissgaerber <weissg@vienna.at>, Dag Brattli | 
|  | 20 | * <dag@brattli.net>, and Jean Tourrilhes <jt@hpl.hp.com> | 
|  | 21 | * | 
|  | 22 | * See Documentation/usb/usb-serial.txt for more information on using this driver | 
|  | 23 | * | 
|  | 24 | * 2002_Mar_07	greg kh | 
|  | 25 | *	moved some needed structures and #define values from the | 
|  | 26 | *	net/irda/irda-usb.h file into our file, as we don't want to depend on | 
|  | 27 | *	that codebase compiling correctly :) | 
|  | 28 | * | 
|  | 29 | * 2002_Jan_14  gb | 
|  | 30 | *	Added module parameter to force specific number of XBOFs. | 
|  | 31 | *	Added ir_xbof_change(). | 
|  | 32 | *	Reorganized read_bulk_callback error handling. | 
|  | 33 | *	Switched from FILL_BULK_URB() to usb_fill_bulk_urb(). | 
|  | 34 | * | 
|  | 35 | * 2001_Nov_08  greg kh | 
|  | 36 | *	Changed the irda_usb_find_class_desc() function based on comments and | 
|  | 37 | *	code from Martin Diehl. | 
|  | 38 | * | 
|  | 39 | * 2001_Nov_01	greg kh | 
|  | 40 | *	Added support for more IrDA USB devices. | 
|  | 41 | *	Added support for zero packet.  Added buffer override paramater, so | 
|  | 42 | *	users can transfer larger packets at once if they wish.  Both patches | 
|  | 43 | *	came from Dag Brattli <dag@obexcode.com>. | 
|  | 44 | * | 
|  | 45 | * 2001_Oct_07	greg kh | 
|  | 46 | *	initial version released. | 
|  | 47 | */ | 
|  | 48 |  | 
|  | 49 | #include <linux/config.h> | 
|  | 50 | #include <linux/kernel.h> | 
|  | 51 | #include <linux/errno.h> | 
|  | 52 | #include <linux/init.h> | 
|  | 53 | #include <linux/slab.h> | 
|  | 54 | #include <linux/tty.h> | 
|  | 55 | #include <linux/tty_driver.h> | 
|  | 56 | #include <linux/tty_flip.h> | 
|  | 57 | #include <linux/module.h> | 
|  | 58 | #include <linux/spinlock.h> | 
|  | 59 | #include <asm/uaccess.h> | 
|  | 60 | #include <linux/usb.h> | 
|  | 61 | #include "usb-serial.h" | 
|  | 62 |  | 
|  | 63 | /* | 
|  | 64 | * Version Information | 
|  | 65 | */ | 
|  | 66 | #define DRIVER_VERSION "v0.4" | 
|  | 67 | #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>" | 
|  | 68 | #define DRIVER_DESC "USB IR Dongle driver" | 
|  | 69 |  | 
|  | 70 | /* USB IrDA class spec information */ | 
|  | 71 | #define USB_CLASS_IRDA		0x02 | 
|  | 72 | #define USB_DT_IRDA		0x21 | 
|  | 73 | #define IU_REQ_GET_CLASS_DESC	0x06 | 
|  | 74 | #define SPEED_2400		0x01 | 
|  | 75 | #define SPEED_9600		0x02 | 
|  | 76 | #define SPEED_19200		0x03 | 
|  | 77 | #define SPEED_38400		0x04 | 
|  | 78 | #define SPEED_57600		0x05 | 
|  | 79 | #define SPEED_115200		0x06 | 
|  | 80 | #define SPEED_576000		0x07 | 
|  | 81 | #define SPEED_1152000		0x08 | 
|  | 82 | #define SPEED_4000000		0x09 | 
|  | 83 |  | 
|  | 84 | struct irda_class_desc { | 
|  | 85 | u8	bLength; | 
|  | 86 | u8	bDescriptorType; | 
|  | 87 | u16	bcdSpecRevision; | 
|  | 88 | u8	bmDataSize; | 
|  | 89 | u8	bmWindowSize; | 
|  | 90 | u8	bmMinTurnaroundTime; | 
|  | 91 | u16	wBaudRate; | 
|  | 92 | u8	bmAdditionalBOFs; | 
|  | 93 | u8	bIrdaRateSniff; | 
|  | 94 | u8	bMaxUnicastList; | 
|  | 95 | } __attribute__ ((packed)); | 
|  | 96 |  | 
|  | 97 | static int debug; | 
|  | 98 |  | 
|  | 99 | /* if overridden by the user, then use their value for the size of the read and | 
|  | 100 | * write urbs */ | 
|  | 101 | static int buffer_size; | 
|  | 102 | /* if overridden by the user, then use the specified number of XBOFs */ | 
|  | 103 | static int xbof = -1; | 
|  | 104 |  | 
|  | 105 | static int  ir_startup (struct usb_serial *serial); | 
|  | 106 | static int  ir_open (struct usb_serial_port *port, struct file *filep); | 
|  | 107 | static void ir_close (struct usb_serial_port *port, struct file *filep); | 
|  | 108 | static int  ir_write (struct usb_serial_port *port, const unsigned char *buf, int count); | 
|  | 109 | static void ir_write_bulk_callback (struct urb *urb, struct pt_regs *regs); | 
|  | 110 | static void ir_read_bulk_callback (struct urb *urb, struct pt_regs *regs); | 
|  | 111 | static void ir_set_termios (struct usb_serial_port *port, struct termios *old_termios); | 
|  | 112 |  | 
|  | 113 | static u8 ir_baud = 0; | 
|  | 114 | static u8 ir_xbof = 0; | 
|  | 115 | static u8 ir_add_bof = 0; | 
|  | 116 |  | 
|  | 117 | static struct usb_device_id id_table [] = { | 
|  | 118 | { USB_DEVICE(0x050f, 0x0180) },		/* KC Technology, KC-180 */ | 
|  | 119 | { USB_DEVICE(0x08e9, 0x0100) },		/* XTNDAccess */ | 
|  | 120 | { USB_DEVICE(0x09c4, 0x0011) },		/* ACTiSys ACT-IR2000U */ | 
|  | 121 | { USB_INTERFACE_INFO (USB_CLASS_APP_SPEC, USB_CLASS_IRDA, 0) }, | 
|  | 122 | { }					/* Terminating entry */ | 
|  | 123 | }; | 
|  | 124 |  | 
|  | 125 | MODULE_DEVICE_TABLE (usb, id_table); | 
|  | 126 |  | 
|  | 127 | static struct usb_driver ir_driver = { | 
|  | 128 | .owner =	THIS_MODULE, | 
|  | 129 | .name =		"ir-usb", | 
|  | 130 | .probe =	usb_serial_probe, | 
|  | 131 | .disconnect =	usb_serial_disconnect, | 
|  | 132 | .id_table =	id_table, | 
|  | 133 | }; | 
|  | 134 |  | 
|  | 135 |  | 
| Greg Kroah-Hartman | ea65370 | 2005-06-20 21:15:16 -0700 | [diff] [blame] | 136 | static struct usb_serial_driver ir_device = { | 
| Greg Kroah-Hartman | 18fcac3 | 2005-06-20 21:15:16 -0700 | [diff] [blame] | 137 | .driver = { | 
|  | 138 | .owner =	THIS_MODULE, | 
| Greg Kroah-Hartman | 269bda1 | 2005-06-20 21:15:16 -0700 | [diff] [blame] | 139 | .name =		"ir-usb", | 
| Greg Kroah-Hartman | 18fcac3 | 2005-06-20 21:15:16 -0700 | [diff] [blame] | 140 | }, | 
| Greg Kroah-Hartman | 269bda1 | 2005-06-20 21:15:16 -0700 | [diff] [blame] | 141 | .description =		"IR Dongle", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 142 | .id_table =		id_table, | 
|  | 143 | .num_interrupt_in =	1, | 
|  | 144 | .num_bulk_in =		1, | 
|  | 145 | .num_bulk_out =		1, | 
|  | 146 | .num_ports =		1, | 
|  | 147 | .set_termios =		ir_set_termios, | 
|  | 148 | .attach =		ir_startup, | 
|  | 149 | .open =			ir_open, | 
|  | 150 | .close =		ir_close, | 
|  | 151 | .write =		ir_write, | 
|  | 152 | .write_bulk_callback =	ir_write_bulk_callback, | 
|  | 153 | .read_bulk_callback =	ir_read_bulk_callback, | 
|  | 154 | }; | 
|  | 155 |  | 
|  | 156 | static inline void irda_usb_dump_class_desc(struct irda_class_desc *desc) | 
|  | 157 | { | 
|  | 158 | dbg("bLength=%x", desc->bLength); | 
|  | 159 | dbg("bDescriptorType=%x", desc->bDescriptorType); | 
|  | 160 | dbg("bcdSpecRevision=%x", desc->bcdSpecRevision); | 
|  | 161 | dbg("bmDataSize=%x", desc->bmDataSize); | 
|  | 162 | dbg("bmWindowSize=%x", desc->bmWindowSize); | 
|  | 163 | dbg("bmMinTurnaroundTime=%d", desc->bmMinTurnaroundTime); | 
|  | 164 | dbg("wBaudRate=%x", desc->wBaudRate); | 
|  | 165 | dbg("bmAdditionalBOFs=%x", desc->bmAdditionalBOFs); | 
|  | 166 | dbg("bIrdaRateSniff=%x", desc->bIrdaRateSniff); | 
|  | 167 | dbg("bMaxUnicastList=%x", desc->bMaxUnicastList); | 
|  | 168 | } | 
|  | 169 |  | 
|  | 170 | /*------------------------------------------------------------------*/ | 
|  | 171 | /* | 
|  | 172 | * Function irda_usb_find_class_desc(dev, ifnum) | 
|  | 173 | * | 
|  | 174 | *    Returns instance of IrDA class descriptor, or NULL if not found | 
|  | 175 | * | 
|  | 176 | * The class descriptor is some extra info that IrDA USB devices will | 
|  | 177 | * offer to us, describing their IrDA characteristics. We will use that in | 
|  | 178 | * irda_usb_init_qos() | 
|  | 179 | * | 
|  | 180 | * Based on the same function in drivers/net/irda/irda-usb.c | 
|  | 181 | */ | 
|  | 182 | static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum) | 
|  | 183 | { | 
|  | 184 | struct irda_class_desc *desc; | 
|  | 185 | int ret; | 
|  | 186 |  | 
|  | 187 | desc = kmalloc(sizeof (struct irda_class_desc), GFP_KERNEL); | 
|  | 188 | if (desc == NULL) | 
|  | 189 | return NULL; | 
|  | 190 | memset(desc, 0, sizeof(struct irda_class_desc)); | 
|  | 191 |  | 
|  | 192 | ret = usb_control_msg(dev, usb_rcvctrlpipe(dev,0), | 
|  | 193 | IU_REQ_GET_CLASS_DESC, | 
|  | 194 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | 
|  | 195 | 0, ifnum, desc, sizeof(*desc), 1000); | 
|  | 196 |  | 
|  | 197 | dbg("%s -  ret=%d", __FUNCTION__, ret); | 
|  | 198 | if (ret < sizeof(*desc)) { | 
|  | 199 | dbg("%s - class descriptor read %s (%d)", | 
|  | 200 | __FUNCTION__, | 
|  | 201 | (ret<0) ? "failed" : "too short", | 
|  | 202 | ret); | 
|  | 203 | goto error; | 
|  | 204 | } | 
|  | 205 | if (desc->bDescriptorType != USB_DT_IRDA) { | 
|  | 206 | dbg("%s - bad class descriptor type", __FUNCTION__); | 
|  | 207 | goto error; | 
|  | 208 | } | 
|  | 209 |  | 
|  | 210 | irda_usb_dump_class_desc(desc); | 
|  | 211 | return desc; | 
|  | 212 | error: | 
|  | 213 | kfree(desc); | 
|  | 214 | return NULL; | 
|  | 215 | } | 
|  | 216 |  | 
|  | 217 |  | 
|  | 218 | static u8 ir_xbof_change(u8 xbof) | 
|  | 219 | { | 
|  | 220 | u8 result; | 
|  | 221 | /* reference irda-usb.c */ | 
|  | 222 | switch(xbof) { | 
|  | 223 | case 48: result = 0x10; break; | 
|  | 224 | case 28: | 
|  | 225 | case 24: result = 0x20; break; | 
|  | 226 | default: | 
|  | 227 | case 12: result = 0x30; break; | 
|  | 228 | case  5: | 
|  | 229 | case  6: result = 0x40; break; | 
|  | 230 | case  3: result = 0x50; break; | 
|  | 231 | case  2: result = 0x60; break; | 
|  | 232 | case  1: result = 0x70; break; | 
|  | 233 | case  0: result = 0x80; break; | 
|  | 234 | } | 
|  | 235 | return(result); | 
|  | 236 | } | 
|  | 237 |  | 
|  | 238 |  | 
|  | 239 | static int ir_startup (struct usb_serial *serial) | 
|  | 240 | { | 
|  | 241 | struct irda_class_desc *irda_desc; | 
|  | 242 |  | 
|  | 243 | irda_desc = irda_usb_find_class_desc (serial->dev, 0); | 
|  | 244 | if (irda_desc == NULL) { | 
|  | 245 | dev_err (&serial->dev->dev, "IRDA class descriptor not found, device not bound\n"); | 
|  | 246 | return -ENODEV; | 
|  | 247 | } | 
|  | 248 |  | 
|  | 249 | dbg ("%s - Baud rates supported:%s%s%s%s%s%s%s%s%s", | 
|  | 250 | __FUNCTION__, | 
|  | 251 | (irda_desc->wBaudRate & 0x0001) ? " 2400"    : "", | 
|  | 252 | (irda_desc->wBaudRate & 0x0002) ? " 9600"    : "", | 
|  | 253 | (irda_desc->wBaudRate & 0x0004) ? " 19200"   : "", | 
|  | 254 | (irda_desc->wBaudRate & 0x0008) ? " 38400"   : "", | 
|  | 255 | (irda_desc->wBaudRate & 0x0010) ? " 57600"   : "", | 
|  | 256 | (irda_desc->wBaudRate & 0x0020) ? " 115200"  : "", | 
|  | 257 | (irda_desc->wBaudRate & 0x0040) ? " 576000"  : "", | 
|  | 258 | (irda_desc->wBaudRate & 0x0080) ? " 1152000" : "", | 
|  | 259 | (irda_desc->wBaudRate & 0x0100) ? " 4000000" : ""); | 
|  | 260 |  | 
|  | 261 | switch( irda_desc->bmAdditionalBOFs ) { | 
|  | 262 | case 0x01: ir_add_bof = 48; break; | 
|  | 263 | case 0x02: ir_add_bof = 24; break; | 
|  | 264 | case 0x04: ir_add_bof = 12; break; | 
|  | 265 | case 0x08: ir_add_bof =  6; break; | 
|  | 266 | case 0x10: ir_add_bof =  3; break; | 
|  | 267 | case 0x20: ir_add_bof =  2; break; | 
|  | 268 | case 0x40: ir_add_bof =  1; break; | 
|  | 269 | case 0x80: ir_add_bof =  0; break; | 
|  | 270 | default:; | 
|  | 271 | } | 
|  | 272 |  | 
|  | 273 | kfree (irda_desc); | 
|  | 274 |  | 
|  | 275 | return 0; | 
|  | 276 | } | 
|  | 277 |  | 
|  | 278 | static int ir_open (struct usb_serial_port *port, struct file *filp) | 
|  | 279 | { | 
|  | 280 | char *buffer; | 
|  | 281 | int result = 0; | 
|  | 282 |  | 
|  | 283 | dbg("%s - port %d", __FUNCTION__, port->number); | 
|  | 284 |  | 
|  | 285 | if (buffer_size) { | 
|  | 286 | /* override the default buffer sizes */ | 
|  | 287 | buffer = kmalloc (buffer_size, GFP_KERNEL); | 
|  | 288 | if (!buffer) { | 
|  | 289 | dev_err (&port->dev, "%s - out of memory.\n", __FUNCTION__); | 
|  | 290 | return -ENOMEM; | 
|  | 291 | } | 
|  | 292 | kfree (port->read_urb->transfer_buffer); | 
|  | 293 | port->read_urb->transfer_buffer = buffer; | 
|  | 294 | port->read_urb->transfer_buffer_length = buffer_size; | 
|  | 295 |  | 
|  | 296 | buffer = kmalloc (buffer_size, GFP_KERNEL); | 
|  | 297 | if (!buffer) { | 
|  | 298 | dev_err (&port->dev, "%s - out of memory.\n", __FUNCTION__); | 
|  | 299 | return -ENOMEM; | 
|  | 300 | } | 
|  | 301 | kfree (port->write_urb->transfer_buffer); | 
|  | 302 | port->write_urb->transfer_buffer = buffer; | 
|  | 303 | port->write_urb->transfer_buffer_length = buffer_size; | 
|  | 304 | port->bulk_out_size = buffer_size; | 
|  | 305 | } | 
|  | 306 |  | 
|  | 307 | /* Start reading from the device */ | 
|  | 308 | usb_fill_bulk_urb ( | 
|  | 309 | port->read_urb, | 
|  | 310 | port->serial->dev, | 
|  | 311 | usb_rcvbulkpipe(port->serial->dev, port->bulk_in_endpointAddress), | 
|  | 312 | port->read_urb->transfer_buffer, | 
|  | 313 | port->read_urb->transfer_buffer_length, | 
|  | 314 | ir_read_bulk_callback, | 
|  | 315 | port); | 
|  | 316 | result = usb_submit_urb(port->read_urb, GFP_KERNEL); | 
|  | 317 | if (result) | 
|  | 318 | dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result); | 
|  | 319 |  | 
|  | 320 | return result; | 
|  | 321 | } | 
|  | 322 |  | 
|  | 323 | static void ir_close (struct usb_serial_port *port, struct file * filp) | 
|  | 324 | { | 
|  | 325 | dbg("%s - port %d", __FUNCTION__, port->number); | 
|  | 326 |  | 
|  | 327 | /* shutdown our bulk read */ | 
|  | 328 | usb_kill_urb(port->read_urb); | 
|  | 329 | } | 
|  | 330 |  | 
|  | 331 | static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int count) | 
|  | 332 | { | 
|  | 333 | unsigned char *transfer_buffer; | 
|  | 334 | int result; | 
|  | 335 | int transfer_size; | 
|  | 336 |  | 
|  | 337 | dbg("%s - port = %d, count = %d", __FUNCTION__, port->number, count); | 
|  | 338 |  | 
|  | 339 | if (!port->tty) { | 
|  | 340 | dev_err (&port->dev, "%s - no tty???\n", __FUNCTION__); | 
|  | 341 | return 0; | 
|  | 342 | } | 
|  | 343 |  | 
|  | 344 | if (count == 0) | 
|  | 345 | return 0; | 
|  | 346 |  | 
| Greg Kroah-Hartman | 507ca9b | 2005-04-23 12:49:16 -0700 | [diff] [blame] | 347 | spin_lock(&port->lock); | 
|  | 348 | if (port->write_urb_busy) { | 
|  | 349 | spin_unlock(&port->lock); | 
|  | 350 | dbg("%s - already writing", __FUNCTION__); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 351 | return 0; | 
|  | 352 | } | 
| Greg Kroah-Hartman | 507ca9b | 2005-04-23 12:49:16 -0700 | [diff] [blame] | 353 | port->write_urb_busy = 1; | 
|  | 354 | spin_unlock(&port->lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 355 |  | 
|  | 356 | transfer_buffer = port->write_urb->transfer_buffer; | 
|  | 357 | transfer_size = min(count, port->bulk_out_size - 1); | 
|  | 358 |  | 
|  | 359 | /* | 
|  | 360 | * The first byte of the packet we send to the device contains an | 
|  | 361 | * inband header which indicates an additional number of BOFs and | 
|  | 362 | * a baud rate change. | 
|  | 363 | * | 
|  | 364 | * See section 5.4.2.2 of the USB IrDA spec. | 
|  | 365 | */ | 
|  | 366 | *transfer_buffer = ir_xbof | ir_baud; | 
|  | 367 | ++transfer_buffer; | 
|  | 368 |  | 
|  | 369 | memcpy (transfer_buffer, buf, transfer_size); | 
|  | 370 |  | 
|  | 371 | usb_fill_bulk_urb ( | 
|  | 372 | port->write_urb, | 
|  | 373 | port->serial->dev, | 
|  | 374 | usb_sndbulkpipe(port->serial->dev, | 
|  | 375 | port->bulk_out_endpointAddress), | 
|  | 376 | port->write_urb->transfer_buffer, | 
|  | 377 | transfer_size + 1, | 
|  | 378 | ir_write_bulk_callback, | 
|  | 379 | port); | 
|  | 380 |  | 
|  | 381 | port->write_urb->transfer_flags = URB_ZERO_PACKET; | 
|  | 382 |  | 
|  | 383 | result = usb_submit_urb (port->write_urb, GFP_ATOMIC); | 
| Greg Kroah-Hartman | 507ca9b | 2005-04-23 12:49:16 -0700 | [diff] [blame] | 384 | if (result) { | 
|  | 385 | port->write_urb_busy = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 386 | dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result); | 
| Greg Kroah-Hartman | 507ca9b | 2005-04-23 12:49:16 -0700 | [diff] [blame] | 387 | } else | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 388 | result = transfer_size; | 
|  | 389 |  | 
|  | 390 | return result; | 
|  | 391 | } | 
|  | 392 |  | 
|  | 393 | static void ir_write_bulk_callback (struct urb *urb, struct pt_regs *regs) | 
|  | 394 | { | 
|  | 395 | struct usb_serial_port *port = (struct usb_serial_port *)urb->context; | 
|  | 396 |  | 
|  | 397 | dbg("%s - port %d", __FUNCTION__, port->number); | 
| Greg Kroah-Hartman | 507ca9b | 2005-04-23 12:49:16 -0700 | [diff] [blame] | 398 |  | 
|  | 399 | port->write_urb_busy = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 400 | if (urb->status) { | 
|  | 401 | dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); | 
|  | 402 | return; | 
|  | 403 | } | 
|  | 404 |  | 
|  | 405 | usb_serial_debug_data ( | 
|  | 406 | debug, | 
|  | 407 | &port->dev, | 
|  | 408 | __FUNCTION__, | 
|  | 409 | urb->actual_length, | 
|  | 410 | urb->transfer_buffer); | 
|  | 411 |  | 
|  | 412 | schedule_work(&port->work); | 
|  | 413 | } | 
|  | 414 |  | 
|  | 415 | static void ir_read_bulk_callback (struct urb *urb, struct pt_regs *regs) | 
|  | 416 | { | 
|  | 417 | struct usb_serial_port *port = (struct usb_serial_port *)urb->context; | 
|  | 418 | struct tty_struct *tty; | 
|  | 419 | unsigned char *data = urb->transfer_buffer; | 
|  | 420 | int result; | 
|  | 421 |  | 
|  | 422 | dbg("%s - port %d", __FUNCTION__, port->number); | 
|  | 423 |  | 
|  | 424 | if (!port->open_count) { | 
|  | 425 | dbg("%s - port closed.", __FUNCTION__); | 
|  | 426 | return; | 
|  | 427 | } | 
|  | 428 |  | 
|  | 429 | switch (urb->status) { | 
|  | 430 |  | 
|  | 431 | case 0: /* Successful */ | 
|  | 432 |  | 
|  | 433 | /* | 
|  | 434 | * The first byte of the packet we get from the device | 
|  | 435 | * contains a busy indicator and baud rate change. | 
|  | 436 | * See section 5.4.1.2 of the USB IrDA spec. | 
|  | 437 | */ | 
|  | 438 | if ((*data & 0x0f) > 0) | 
|  | 439 | ir_baud = *data & 0x0f; | 
|  | 440 |  | 
|  | 441 | usb_serial_debug_data ( | 
|  | 442 | debug, | 
|  | 443 | &port->dev, | 
|  | 444 | __FUNCTION__, | 
|  | 445 | urb->actual_length, | 
|  | 446 | data); | 
|  | 447 |  | 
|  | 448 | /* | 
|  | 449 | * Bypass flip-buffers, and feed the ldisc directly | 
|  | 450 | * due to our potentially large buffer size.  Since we | 
|  | 451 | * used to set low_latency, this is exactly what the | 
|  | 452 | * tty layer did anyway :) | 
|  | 453 | */ | 
|  | 454 | tty = port->tty; | 
|  | 455 |  | 
|  | 456 | /* | 
|  | 457 | *	FIXME: must not do this in IRQ context, | 
|  | 458 | *	must honour TTY_DONT_FLIP | 
|  | 459 | */ | 
|  | 460 | tty->ldisc.receive_buf( | 
|  | 461 | tty, | 
|  | 462 | data+1, | 
|  | 463 | NULL, | 
|  | 464 | urb->actual_length-1); | 
|  | 465 |  | 
|  | 466 | /* | 
|  | 467 | * No break here. | 
|  | 468 | * We want to resubmit the urb so we can read | 
|  | 469 | * again. | 
|  | 470 | */ | 
|  | 471 |  | 
|  | 472 | case -EPROTO: /* taking inspiration from pl2303.c */ | 
|  | 473 |  | 
|  | 474 | /* Continue trying to always read */ | 
|  | 475 | usb_fill_bulk_urb ( | 
|  | 476 | port->read_urb, | 
|  | 477 | port->serial->dev, | 
|  | 478 | usb_rcvbulkpipe(port->serial->dev, | 
|  | 479 | port->bulk_in_endpointAddress), | 
|  | 480 | port->read_urb->transfer_buffer, | 
|  | 481 | port->read_urb->transfer_buffer_length, | 
|  | 482 | ir_read_bulk_callback, | 
|  | 483 | port); | 
|  | 484 |  | 
|  | 485 | result = usb_submit_urb(port->read_urb, GFP_ATOMIC); | 
|  | 486 | if (result) | 
|  | 487 | dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", | 
|  | 488 | __FUNCTION__, result); | 
|  | 489 |  | 
|  | 490 | break ; | 
|  | 491 |  | 
|  | 492 | default: | 
|  | 493 | dbg("%s - nonzero read bulk status received: %d", | 
|  | 494 | __FUNCTION__, | 
|  | 495 | urb->status); | 
|  | 496 | break ; | 
|  | 497 |  | 
|  | 498 | } | 
|  | 499 |  | 
|  | 500 | return; | 
|  | 501 | } | 
|  | 502 |  | 
|  | 503 | static void ir_set_termios (struct usb_serial_port *port, struct termios *old_termios) | 
|  | 504 | { | 
|  | 505 | unsigned char *transfer_buffer; | 
|  | 506 | unsigned int cflag; | 
|  | 507 | int result; | 
|  | 508 |  | 
|  | 509 | dbg("%s - port %d", __FUNCTION__, port->number); | 
|  | 510 |  | 
|  | 511 | if ((!port->tty) || (!port->tty->termios)) { | 
|  | 512 | dbg("%s - no tty structures", __FUNCTION__); | 
|  | 513 | return; | 
|  | 514 | } | 
|  | 515 |  | 
|  | 516 | cflag = port->tty->termios->c_cflag; | 
|  | 517 | /* check that they really want us to change something */ | 
|  | 518 | if (old_termios) { | 
|  | 519 | if ((cflag == old_termios->c_cflag) && | 
|  | 520 | (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) { | 
|  | 521 | dbg("%s - nothing to change...", __FUNCTION__); | 
|  | 522 | return; | 
|  | 523 | } | 
|  | 524 | } | 
|  | 525 |  | 
|  | 526 | /* All we can change is the baud rate */ | 
|  | 527 | if (cflag & CBAUD) { | 
|  | 528 |  | 
|  | 529 | dbg ("%s - asking for baud %d", | 
|  | 530 | __FUNCTION__, | 
|  | 531 | tty_get_baud_rate(port->tty)); | 
|  | 532 |  | 
|  | 533 | /* | 
|  | 534 | * FIXME, we should compare the baud request against the | 
|  | 535 | * capability stated in the IR header that we got in the | 
|  | 536 | * startup function. | 
|  | 537 | */ | 
|  | 538 | switch (cflag & CBAUD) { | 
|  | 539 | case B2400:    ir_baud = SPEED_2400;    break; | 
|  | 540 | default: | 
|  | 541 | case B9600:    ir_baud = SPEED_9600;    break; | 
|  | 542 | case B19200:   ir_baud = SPEED_19200;   break; | 
|  | 543 | case B38400:   ir_baud = SPEED_38400;   break; | 
|  | 544 | case B57600:   ir_baud = SPEED_57600;   break; | 
|  | 545 | case B115200:  ir_baud = SPEED_115200;  break; | 
|  | 546 | case B576000:  ir_baud = SPEED_576000;  break; | 
|  | 547 | case B1152000: ir_baud = SPEED_1152000; break; | 
|  | 548 | #ifdef B4000000 | 
|  | 549 | case B4000000: ir_baud = SPEED_4000000; break; | 
|  | 550 | #endif | 
|  | 551 | } | 
|  | 552 |  | 
|  | 553 | if (xbof == -1) { | 
|  | 554 | ir_xbof = ir_xbof_change(ir_add_bof); | 
|  | 555 | } else { | 
|  | 556 | ir_xbof = ir_xbof_change(xbof) ; | 
|  | 557 | } | 
|  | 558 |  | 
|  | 559 | /* Notify the tty driver that the termios have changed. */ | 
|  | 560 | port->tty->ldisc.set_termios(port->tty, NULL); | 
|  | 561 |  | 
|  | 562 | /* FIXME need to check to see if our write urb is busy right | 
|  | 563 | * now, or use a urb pool. | 
|  | 564 | * | 
|  | 565 | * send the baud change out on an "empty" data packet | 
|  | 566 | */ | 
|  | 567 | transfer_buffer = port->write_urb->transfer_buffer; | 
|  | 568 | *transfer_buffer = ir_xbof | ir_baud; | 
|  | 569 |  | 
|  | 570 | usb_fill_bulk_urb ( | 
|  | 571 | port->write_urb, | 
|  | 572 | port->serial->dev, | 
|  | 573 | usb_sndbulkpipe(port->serial->dev, | 
|  | 574 | port->bulk_out_endpointAddress), | 
|  | 575 | port->write_urb->transfer_buffer, | 
|  | 576 | 1, | 
|  | 577 | ir_write_bulk_callback, | 
|  | 578 | port); | 
|  | 579 |  | 
|  | 580 | port->write_urb->transfer_flags = URB_ZERO_PACKET; | 
|  | 581 |  | 
|  | 582 | result = usb_submit_urb (port->write_urb, GFP_KERNEL); | 
|  | 583 | if (result) | 
|  | 584 | dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result); | 
|  | 585 | } | 
|  | 586 | return; | 
|  | 587 | } | 
|  | 588 |  | 
|  | 589 |  | 
|  | 590 | static int __init ir_init (void) | 
|  | 591 | { | 
|  | 592 | int retval; | 
|  | 593 | retval = usb_serial_register(&ir_device); | 
|  | 594 | if (retval) | 
|  | 595 | goto failed_usb_serial_register; | 
|  | 596 | retval = usb_register(&ir_driver); | 
|  | 597 | if (retval) | 
|  | 598 | goto failed_usb_register; | 
|  | 599 | info(DRIVER_DESC " " DRIVER_VERSION); | 
|  | 600 | return 0; | 
|  | 601 | failed_usb_register: | 
|  | 602 | usb_serial_deregister(&ir_device); | 
|  | 603 | failed_usb_serial_register: | 
|  | 604 | return retval; | 
|  | 605 | } | 
|  | 606 |  | 
|  | 607 |  | 
|  | 608 | static void __exit ir_exit (void) | 
|  | 609 | { | 
|  | 610 | usb_deregister (&ir_driver); | 
|  | 611 | usb_serial_deregister (&ir_device); | 
|  | 612 | } | 
|  | 613 |  | 
|  | 614 |  | 
|  | 615 | module_init(ir_init); | 
|  | 616 | module_exit(ir_exit); | 
|  | 617 |  | 
|  | 618 | MODULE_AUTHOR(DRIVER_AUTHOR); | 
|  | 619 | MODULE_DESCRIPTION(DRIVER_DESC); | 
|  | 620 | MODULE_LICENSE("GPL"); | 
|  | 621 |  | 
|  | 622 | module_param(debug, bool, S_IRUGO | S_IWUSR); | 
|  | 623 | MODULE_PARM_DESC(debug, "Debug enabled or not"); | 
|  | 624 | module_param(xbof, int, 0); | 
|  | 625 | MODULE_PARM_DESC(xbof, "Force specific number of XBOFs"); | 
|  | 626 | module_param(buffer_size, int, 0); | 
|  | 627 | MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers"); | 
|  | 628 |  |