sierra.c 21.7 KB
Newer Older
1
/*
K
Kevin Lloyd 已提交
2 3
  USB Driver for Sierra Wireless

K
Kevin Lloyd 已提交
4
  Copyright (C) 2006, 2007, 2008  Kevin Lloyd <klloyd@sierrawireless.com>
K
Kevin Lloyd 已提交
5 6 7 8 9 10 11 12 13 14 15 16

  IMPORTANT DISCLAIMER: This driver is not commercially supported by
  Sierra Wireless. Use at your own risk.

  This driver is free software; you can redistribute it and/or modify
  it under the terms of Version 2 of the GNU General Public License as
  published by the Free Software Foundation.

  Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de>
  Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
*/

K
Kevin Lloyd 已提交
17 18
#define DRIVER_VERSION "v.1.2.9c"
#define DRIVER_AUTHOR "Kevin Lloyd <klloyd@sierrawireless.com>"
K
Kevin Lloyd 已提交
19
#define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
20 21

#include <linux/kernel.h>
K
Kevin Lloyd 已提交
22 23
#include <linux/jiffies.h>
#include <linux/errno.h>
24
#include <linux/tty.h>
K
Kevin Lloyd 已提交
25
#include <linux/tty_flip.h>
26 27
#include <linux/module.h>
#include <linux/usb.h>
28
#include <linux/usb/serial.h>
29
#include <linux/usb/ch9.h>
30

31 32
#define SWIMS_USB_REQUEST_SetPower	0x00
#define SWIMS_USB_REQUEST_SetNmea	0x07
33 34 35 36 37 38 39 40 41
#define SWIMS_USB_REQUEST_SetMode	0x0B
#define SWIMS_SET_MODE_Modem		0x0001

/* per port private data */
#define N_IN_URB	4
#define N_OUT_URB	4
#define IN_BUFLEN	4096

static int debug;
42 43
static int nmea;
static int truinstall = 1;
44 45 46 47 48 49 50

enum devicetype {
	DEVICE_3_PORT =		0,
	DEVICE_1_PORT =		1,
	DEVICE_INSTALLER =	2,
};

51
static int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
52 53
{
	int result;
54
	dev_dbg(&udev->dev, "%s", "SET POWER STATE\n");
55
	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
56
			SWIMS_USB_REQUEST_SetPower,	/* __u8 request      */
K
Kevin Lloyd 已提交
57
			USB_TYPE_VENDOR,		/* __u8 request type */
58 59 60 61 62
			swiState,			/* __u16 value       */
			0,				/* __u16 index       */
			NULL,				/* void *data        */
			0,				/* __u16 size 	     */
			USB_CTRL_SET_TIMEOUT);		/* int timeout 	     */
63 64 65
	return result;
}

66
static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSWocMode)
67 68
{
	int result;
69
	dev_dbg(&udev->dev, "%s", "DEVICE MODE SWITCH\n");
70 71
	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
			SWIMS_USB_REQUEST_SetMode,	/* __u8 request      */
K
Kevin Lloyd 已提交
72
			USB_TYPE_VENDOR,		/* __u8 request type */
73 74
			eSWocMode,			/* __u16 value       */
			0x0000,				/* __u16 index       */
75 76 77 78 79 80
			NULL,				/* void *data        */
			0,				/* __u16 size 	     */
			USB_CTRL_SET_TIMEOUT);		/* int timeout       */
	return result;
}

81
static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable)
82 83
{
	int result;
84 85 86
	dev_dbg(&udev->dev, "%s", "NMEA Enable sent\n");
	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
			SWIMS_USB_REQUEST_SetNmea,	/* __u8 request      */
K
Kevin Lloyd 已提交
87
			USB_TYPE_VENDOR,		/* __u8 request type */
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
			enable,				/* __u16 value       */
			0x0000,				/* __u16 index       */
			NULL,				/* void *data        */
			0,				/* __u16 size 	     */
			USB_CTRL_SET_TIMEOUT);		/* int timeout       */
	return result;
}

static int sierra_calc_num_ports(struct usb_serial *serial)
{
	int result;
	int *num_ports = usb_get_serial_data(serial);

	result = *num_ports;

	if (result) {
		kfree(num_ports);
		usb_set_serial_data(serial, NULL);
	}

	return result;
}

111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
static int sierra_calc_interface(struct usb_serial *serial)
{
		int interface;
		struct usb_interface *p_interface;
		struct usb_host_interface *p_host_interface;

		/* Get the interface structure pointer from the serial struct */
		p_interface = serial->interface;

		/* Get a pointer to the host interface structure */
		p_host_interface = p_interface->cur_altsetting;

		/* read the interface descriptor for this active altsetting
		 * to find out the interface number we are on
		*/
		interface = p_host_interface->desc.bInterfaceNumber;

		return interface;
}

131 132 133 134
static int sierra_probe(struct usb_serial *serial,
			const struct usb_device_id *id)
{
	int result = 0;
135
	struct usb_device *udev;
136 137
	int *num_ports;
	u8 ifnum;
138

139 140 141 142 143 144
	num_ports = kmalloc(sizeof(*num_ports), GFP_KERNEL);
	if (!num_ports)
		return -ENOMEM;

	ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
	udev = serial->dev;
145

146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
		/* Figure out the interface number from the serial structure */
		ifnum = sierra_calc_interface(serial);

		/*
		 * If this interface supports more than 1 alternate
		 * select the 2nd one
		 */
		if (serial->interface->num_altsetting == 2) {
			dev_dbg(&udev->dev,
				"Selecting alt setting for interface %d\n",
				ifnum);

			/* We know the alternate setting is 1 for the MC8785 */
			usb_set_interface(udev, ifnum, 1);
		}

162
	/* Check if in installer mode */
163 164
	if (truinstall && id->driver_info == DEVICE_INSTALLER) {
		dev_dbg(&udev->dev, "%s", "FOUND TRU-INSTALL DEVICE(SW)\n");
165
		result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem);
166 167
		/* Don't bind to the device when in installer mode */
		kfree(num_ports);
168
		return -EIO;
169 170 171 172 173 174 175 176 177 178 179
	} else if (id->driver_info == DEVICE_1_PORT)
		*num_ports = 1;
	else if (ifnum == 0x99)
		*num_ports = 0;
	else
		*num_ports = 3;
	/*
	 * save off our num_ports info so that we can use it in the
	 * calc_num_ports callback
	 */
	usb_set_serial_data(serial, (void *)num_ports);
180

181
	return result;
182
}
K
Kevin Lloyd 已提交
183

184
static struct usb_device_id id_table [] = {
K
Kevin Lloyd 已提交
185
	{ USB_DEVICE(0x1199, 0x0017) },	/* Sierra Wireless EM5625 */
186
	{ USB_DEVICE(0x1199, 0x0018) },	/* Sierra Wireless MC5720 */
K
Kevin Lloyd 已提交
187
	{ USB_DEVICE(0x1199, 0x0218) },	/* Sierra Wireless MC5720 */
K
Kevin Lloyd 已提交
188
	{ USB_DEVICE(0x0f30, 0x1b1d) },	/* Sierra Wireless MC5720 */
189
	{ USB_DEVICE(0x1199, 0x0020) },	/* Sierra Wireless MC5725 */
190
	{ USB_DEVICE(0x1199, 0x0220) },	/* Sierra Wireless MC5725 */
191
	{ USB_DEVICE(0x1199, 0x0019) },	/* Sierra Wireless AirCard 595 */
K
Kevin Lloyd 已提交
192
	{ USB_DEVICE(0x1199, 0x0021) },	/* Sierra Wireless AirCard 597E */
K
Kevin Lloyd 已提交
193
	{ USB_DEVICE(0x1199, 0x0120) },	/* Sierra Wireless USB Dongle 595U */
K
Kevin Lloyd 已提交
194
	{ USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x0023, 0xFF, 0xFF, 0xFF) }, /* Sierra Wireless C597 */
K
Kevin Lloyd 已提交
195

196
	{ USB_DEVICE(0x1199, 0x6802) },	/* Sierra Wireless MC8755 */
K
Kevin Lloyd 已提交
197
	{ USB_DEVICE(0x1199, 0x6804) },	/* Sierra Wireless MC8755 */
198
	{ USB_DEVICE(0x1199, 0x6803) },	/* Sierra Wireless MC8765 */
K
Kevin Lloyd 已提交
199
	{ USB_DEVICE(0x1199, 0x6812) },	/* Sierra Wireless MC8775 & AC 875U */
K
Kevin R Page 已提交
200
	{ USB_DEVICE(0x1199, 0x6813) },	/* Sierra Wireless MC8775 (Thinkpad internal) */
K
Kevin Lloyd 已提交
201
	{ USB_DEVICE(0x1199, 0x6815) },	/* Sierra Wireless MC8775 */
202
	{ USB_DEVICE(0x03f0, 0x1e1d) },	/* HP hs2300 a.k.a MC8775 */
203
	{ USB_DEVICE(0x1199, 0x6820) },	/* Sierra Wireless AirCard 875 */
204
	{ USB_DEVICE(0x1199, 0x6821) },	/* Sierra Wireless AirCard 875U */
K
Kevin Lloyd 已提交
205 206
	{ USB_DEVICE(0x1199, 0x6832) },	/* Sierra Wireless MC8780*/
	{ USB_DEVICE(0x1199, 0x6833) },	/* Sierra Wireless MC8781*/
207
	{ USB_DEVICE(0x1199, 0x683B), .driver_info = DEVICE_1_PORT },	/* Sierra Wireless MC8785 Composite*/
K
Kevin Lloyd 已提交
208 209 210 211
	{ USB_DEVICE(0x1199, 0x6850) },	/* Sierra Wireless AirCard 880 */
	{ USB_DEVICE(0x1199, 0x6851) },	/* Sierra Wireless AirCard 881 */
	{ USB_DEVICE(0x1199, 0x6852) },	/* Sierra Wireless AirCard 880 E */
	{ USB_DEVICE(0x1199, 0x6853) },	/* Sierra Wireless AirCard 881 E */
K
Kevin Lloyd 已提交
212
	{ USB_DEVICE(0x1199, 0x6855) },	/* Sierra Wireless AirCard 880 U */
213
	{ USB_DEVICE(0x1199, 0x6856) },	/* Sierra Wireless AirCard 881 U */
214 215
	{ USB_DEVICE(0x1199, 0x6859), .driver_info = DEVICE_1_PORT },	/* Sierra Wireless AirCard 885 E */
	{ USB_DEVICE(0x1199, 0x685A), .driver_info = DEVICE_1_PORT },	/* Sierra Wireless AirCard 885 E */
K
Kevin Lloyd 已提交
216

K
Kevin Lloyd 已提交
217 218 219
	{ USB_DEVICE(0x1199, 0x6468) }, /* Sierra Wireless MP3G - EVDO */
	{ USB_DEVICE(0x1199, 0x6469) }, /* Sierra Wireless MP3G - UMTS/HSPA */

220 221 222 223
	{ USB_DEVICE(0x1199, 0x0112), .driver_info = DEVICE_1_PORT }, /* Sierra Wireless AirCard 580 */
	{ USB_DEVICE(0x0F3D, 0x0112), .driver_info = DEVICE_1_PORT }, /* Airprime/Sierra PC 5220 */

	{ USB_DEVICE(0x1199, 0x0FFF), .driver_info = DEVICE_INSTALLER},
K
Kevin Lloyd 已提交
224 225
	{ }
};
226
MODULE_DEVICE_TABLE(usb, id_table);
K
Kevin Lloyd 已提交
227

228
static struct usb_driver sierra_driver = {
K
Kevin Lloyd 已提交
229
	.name       = "sierra",
230
	.probe      = usb_serial_probe,
K
Kevin Lloyd 已提交
231 232
	.disconnect = usb_serial_disconnect,
	.id_table   = id_table,
233
	.no_dynamic_id = 	1,
K
Kevin Lloyd 已提交
234 235 236
};

struct sierra_port_private {
237 238 239
	spinlock_t lock;	/* lock the structure */
	int outstanding_urbs;	/* number of out urbs in flight */

O
Oliver Neukum 已提交
240
	/* Input endpoints and buffers for this port */
K
Kevin Lloyd 已提交
241
	struct urb *in_urbs[N_IN_URB];
O
Oliver Neukum 已提交
242
	char *in_buffer[N_IN_URB];
K
Kevin Lloyd 已提交
243 244 245 246 247 248 249 250 251 252

	/* Settings for the port */
	int rts_state;	/* Handshaking pins (outputs) */
	int dtr_state;
	int cts_state;	/* Handshaking pins (inputs) */
	int dsr_state;
	int dcd_state;
	int ri_state;
};

253
static int sierra_send_setup(struct usb_serial_port *port)
254
{
255 256
	struct usb_serial *serial = port->serial;
	struct sierra_port_private *portdata;
257
	__u16 interface = 0;
K
Kevin Lloyd 已提交
258

259
	dbg("%s", __func__);
K
Kevin Lloyd 已提交
260

261
	portdata = usb_get_serial_port_data(port);
K
Kevin Lloyd 已提交
262

263 264 265 266 267 268
	if (port->tty) {
		int val = 0;
		if (portdata->dtr_state)
			val |= 0x01;
		if (portdata->rts_state)
			val |= 0x02;
K
Kevin Lloyd 已提交
269

270 271 272 273 274 275 276 277
		/* Determine which port is targeted */
		if (port->bulk_out_endpointAddress == 2)
			interface = 0;
		else if (port->bulk_out_endpointAddress == 4)
			interface = 1;
		else if (port->bulk_out_endpointAddress == 5)
			interface = 2;

278 279
		return usb_control_msg(serial->dev,
				usb_rcvctrlpipe(serial->dev, 0),
280 281
				0x22, 0x21, val, interface,
				NULL, 0, USB_CTRL_SET_TIMEOUT);
282
	}
283

284
	return 0;
285 286
}

K
Kevin Lloyd 已提交
287 288
static void sierra_rx_throttle(struct usb_serial_port *port)
{
289
	dbg("%s", __func__);
K
Kevin Lloyd 已提交
290 291 292 293
}

static void sierra_rx_unthrottle(struct usb_serial_port *port)
{
294
	dbg("%s", __func__);
K
Kevin Lloyd 已提交
295 296 297 298 299
}

static void sierra_break_ctl(struct usb_serial_port *port, int break_state)
{
	/* Unfortunately, I don't know how to send a break */
300
	dbg("%s", __func__);
K
Kevin Lloyd 已提交
301 302 303
}

static void sierra_set_termios(struct usb_serial_port *port,
A
Alan Cox 已提交
304
			struct ktermios *old_termios)
K
Kevin Lloyd 已提交
305
{
306
	dbg("%s", __func__);
A
Alan Cox 已提交
307
	tty_termios_copy_hw(port->tty->termios, old_termios);
K
Kevin Lloyd 已提交
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
	sierra_send_setup(port);
}

static int sierra_tiocmget(struct usb_serial_port *port, struct file *file)
{
	unsigned int value;
	struct sierra_port_private *portdata;

	portdata = usb_get_serial_port_data(port);

	value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
		((portdata->dtr_state) ? TIOCM_DTR : 0) |
		((portdata->cts_state) ? TIOCM_CTS : 0) |
		((portdata->dsr_state) ? TIOCM_DSR : 0) |
		((portdata->dcd_state) ? TIOCM_CAR : 0) |
		((portdata->ri_state) ? TIOCM_RNG : 0);

	return value;
}

static int sierra_tiocmset(struct usb_serial_port *port, struct file *file,
			unsigned int set, unsigned int clear)
{
	struct sierra_port_private *portdata;

	portdata = usb_get_serial_port_data(port);

	if (set & TIOCM_RTS)
		portdata->rts_state = 1;
	if (set & TIOCM_DTR)
		portdata->dtr_state = 1;

	if (clear & TIOCM_RTS)
		portdata->rts_state = 0;
	if (clear & TIOCM_DTR)
		portdata->dtr_state = 0;
	return sierra_send_setup(port);
}

static int sierra_ioctl(struct usb_serial_port *port, struct file *file,
			unsigned int cmd, unsigned long arg)
{
	return -ENOIOCTLCMD;
}

353 354 355 356 357 358 359
static void sierra_outdat_callback(struct urb *urb)
{
	struct usb_serial_port *port = urb->context;
	struct sierra_port_private *portdata = usb_get_serial_port_data(port);
	int status = urb->status;
	unsigned long flags;

360
	dbg("%s - port %d", __func__, port->number);
361 362 363 364 365 366

	/* free up the transfer buffer, as usb_free_urb() does not do this */
	kfree(urb->transfer_buffer);

	if (status)
		dbg("%s - nonzero write bulk status received: %d",
367
		    __func__, status);
368 369 370 371 372 373 374 375

	spin_lock_irqsave(&portdata->lock, flags);
	--portdata->outstanding_urbs;
	spin_unlock_irqrestore(&portdata->lock, flags);

	usb_serial_port_softint(port);
}

K
Kevin Lloyd 已提交
376 377 378 379
/* Write */
static int sierra_write(struct usb_serial_port *port,
			const unsigned char *buf, int count)
{
380 381 382 383 384 385
	struct sierra_port_private *portdata = usb_get_serial_port_data(port);
	struct usb_serial *serial = port->serial;
	unsigned long flags;
	unsigned char *buffer;
	struct urb *urb;
	int status;
K
Kevin Lloyd 已提交
386 387 388

	portdata = usb_get_serial_port_data(port);

389
	dbg("%s: write (%d chars)", __func__, count);
K
Kevin Lloyd 已提交
390

391 392 393
	spin_lock_irqsave(&portdata->lock, flags);
	if (portdata->outstanding_urbs > N_OUT_URB) {
		spin_unlock_irqrestore(&portdata->lock, flags);
394
		dbg("%s - write limit hit\n", __func__);
395 396 397 398 399 400 401 402 403 404 405
		return 0;
	}
	portdata->outstanding_urbs++;
	spin_unlock_irqrestore(&portdata->lock, flags);

	buffer = kmalloc(count, GFP_ATOMIC);
	if (!buffer) {
		dev_err(&port->dev, "out of memory\n");
		count = -ENOMEM;
		goto error_no_buffer;
	}
K
Kevin Lloyd 已提交
406

407 408 409 410 411 412
	urb = usb_alloc_urb(0, GFP_ATOMIC);
	if (!urb) {
		dev_err(&port->dev, "no more free urbs\n");
		count = -ENOMEM;
		goto error_no_urb;
	}
K
Kevin Lloyd 已提交
413

414
	memcpy(buffer, buf, count);
K
Kevin Lloyd 已提交
415

416
	usb_serial_debug_data(debug, &port->dev, __func__, count, buffer);
417 418 419 420 421 422 423 424 425 426

	usb_fill_bulk_urb(urb, serial->dev,
			  usb_sndbulkpipe(serial->dev,
					  port->bulk_out_endpointAddress),
			  buffer, count, sierra_outdat_callback, port);

	/* send it down the pipe */
	status = usb_submit_urb(urb, GFP_ATOMIC);
	if (status) {
		dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed "
427
			"with status = %d\n", __func__, status);
428 429
		count = status;
		goto error;
K
Kevin Lloyd 已提交
430 431
	}

432 433 434 435 436 437 438 439 440 441 442 443 444
	/* we are done with this urb, so let the host driver
	 * really free it when it is finished with it */
	usb_free_urb(urb);

	return count;
error:
	usb_free_urb(urb);
error_no_urb:
	kfree(buffer);
error_no_buffer:
	spin_lock_irqsave(&portdata->lock, flags);
	--portdata->outstanding_urbs;
	spin_unlock_irqrestore(&portdata->lock, flags);
K
Kevin Lloyd 已提交
445 446 447 448 449 450 451 452 453 454
	return count;
}

static void sierra_indat_callback(struct urb *urb)
{
	int err;
	int endpoint;
	struct usb_serial_port *port;
	struct tty_struct *tty;
	unsigned char *data = urb->transfer_buffer;
455
	int status = urb->status;
K
Kevin Lloyd 已提交
456

457
	dbg("%s: %p", __func__, urb);
K
Kevin Lloyd 已提交
458 459 460 461

	endpoint = usb_pipeendpoint(urb->pipe);
	port = (struct usb_serial_port *) urb->context;

462
	if (status) {
K
Kevin Lloyd 已提交
463
		dbg("%s: nonzero status: %d on endpoint %02x.",
464
		    __func__, status, endpoint);
K
Kevin Lloyd 已提交
465 466 467 468 469 470 471
	} else {
		tty = port->tty;
		if (urb->actual_length) {
			tty_buffer_request_room(tty, urb->actual_length);
			tty_insert_flip_string(tty, data, urb->actual_length);
			tty_flip_buffer_push(tty);
		} else {
472
			dbg("%s: empty read urb received", __func__);
K
Kevin Lloyd 已提交
473 474 475
		}

		/* Resubmit urb so we continue receiving */
476
		if (port->open_count && status != -ESHUTDOWN) {
K
Kevin Lloyd 已提交
477 478
			err = usb_submit_urb(urb, GFP_ATOMIC);
			if (err)
479
				dev_err(&port->dev, "resubmit read urb failed."
480
					"(%d)\n", err);
K
Kevin Lloyd 已提交
481 482 483 484 485 486 487 488
		}
	}
	return;
}

static void sierra_instat_callback(struct urb *urb)
{
	int err;
489
	int status = urb->status;
K
Kevin Lloyd 已提交
490 491 492 493
	struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
	struct sierra_port_private *portdata = usb_get_serial_port_data(port);
	struct usb_serial *serial = port->serial;

494 495
	dbg("%s", __func__);
	dbg("%s: urb %p port %p has data %p", __func__, urb, port, portdata);
K
Kevin Lloyd 已提交
496

497
	if (status == 0) {
K
Kevin Lloyd 已提交
498 499 500 501
		struct usb_ctrlrequest *req_pkt =
				(struct usb_ctrlrequest *)urb->transfer_buffer;

		if (!req_pkt) {
502
			dbg("%s: NULL req_pkt\n", __func__);
K
Kevin Lloyd 已提交
503 504 505 506 507 508 509 510 511
			return;
		}
		if ((req_pkt->bRequestType == 0xA1) &&
				(req_pkt->bRequest == 0x20)) {
			int old_dcd_state;
			unsigned char signals = *((unsigned char *)
					urb->transfer_buffer +
					sizeof(struct usb_ctrlrequest));

512
			dbg("%s: signal x%x", __func__, signals);
K
Kevin Lloyd 已提交
513 514 515 516 517 518 519 520 521 522 523

			old_dcd_state = portdata->dcd_state;
			portdata->cts_state = 1;
			portdata->dcd_state = ((signals & 0x01) ? 1 : 0);
			portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
			portdata->ri_state = ((signals & 0x08) ? 1 : 0);

			if (port->tty && !C_CLOCAL(port->tty) &&
					old_dcd_state && !portdata->dcd_state)
				tty_hangup(port->tty);
		} else {
524
			dbg("%s: type %x req %x", __func__,
K
Kevin Lloyd 已提交
525
				req_pkt->bRequestType, req_pkt->bRequest);
K
Kevin Lloyd 已提交
526 527
		}
	} else
528
		dbg("%s: error %d", __func__, status);
K
Kevin Lloyd 已提交
529 530

	/* Resubmit urb so we continue receiving IRQ data */
531
	if (status != -ESHUTDOWN) {
K
Kevin Lloyd 已提交
532 533 534 535
		urb->dev = serial->dev;
		err = usb_submit_urb(urb, GFP_ATOMIC);
		if (err)
			dbg("%s: resubmit intr urb failed. (%d)",
536
				__func__, err);
K
Kevin Lloyd 已提交
537 538 539 540 541
	}
}

static int sierra_write_room(struct usb_serial_port *port)
{
542 543
	struct sierra_port_private *portdata = usb_get_serial_port_data(port);
	unsigned long flags;
K
Kevin Lloyd 已提交
544

545
	dbg("%s - port %d", __func__, port->number);
K
Kevin Lloyd 已提交
546

547 548 549 550 551
	/* try to give a good number back based on if we have any free urbs at
	 * this point in time */
	spin_lock_irqsave(&portdata->lock, flags);
	if (portdata->outstanding_urbs > N_OUT_URB * 2 / 3) {
		spin_unlock_irqrestore(&portdata->lock, flags);
552
		dbg("%s - write limit hit\n", __func__);
553
		return 0;
K
Kevin Lloyd 已提交
554
	}
555
	spin_unlock_irqrestore(&portdata->lock, flags);
K
Kevin Lloyd 已提交
556

557
	return 2048;
K
Kevin Lloyd 已提交
558 559 560 561
}

static int sierra_chars_in_buffer(struct usb_serial_port *port)
{
562
	dbg("%s - port %d", __func__, port->number);
563 564 565 566 567 568

	/*
	 * We can't really account for how much data we
	 * have sent out, but hasn't made it through to the
	 * device as we can't see the backend here, so just
	 * tell the tty layer that everything is flushed.
569 570
	 *
	 * FIXME: should walk the outstanding urbs info
571 572
	 */
	return 0;
K
Kevin Lloyd 已提交
573 574 575 576 577 578
}

static int sierra_open(struct usb_serial_port *port, struct file *filp)
{
	struct sierra_port_private *portdata;
	struct usb_serial *serial = port->serial;
579
	int i;
K
Kevin Lloyd 已提交
580
	struct urb *urb;
K
Kevin Lloyd 已提交
581
	int result;
K
Kevin Lloyd 已提交
582 583 584

	portdata = usb_get_serial_port_data(port);

585
	dbg("%s", __func__);
K
Kevin Lloyd 已提交
586 587 588 589 590 591 592 593

	/* Set some sane defaults */
	portdata->rts_state = 1;
	portdata->dtr_state = 1;

	/* Reset low level data toggle and start reading from endpoints */
	for (i = 0; i < N_IN_URB; i++) {
		urb = portdata->in_urbs[i];
594
		if (!urb)
K
Kevin Lloyd 已提交
595 596
			continue;
		if (urb->dev != serial->dev) {
597
			dbg("%s: dev %p != %p", __func__,
K
Kevin Lloyd 已提交
598 599 600 601 602 603 604 605 606 607
				urb->dev, serial->dev);
			continue;
		}

		/*
		 * make sure endpoint data toggle is synchronized with the
		 * device
		 */
		usb_clear_halt(urb->dev, urb->pipe);

608 609
		result = usb_submit_urb(urb, GFP_KERNEL);
		if (result) {
610
			dev_err(&port->dev, "submit urb %d failed (%d) %d\n",
611
				i, result, urb->transfer_buffer_length);
K
Kevin Lloyd 已提交
612 613 614 615 616 617 618
		}
	}

	port->tty->low_latency = 1;

	sierra_send_setup(port);

619 620 621 622
	/* start up the interrupt endpoint if we have one */
	if (port->interrupt_in_urb) {
		result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
		if (result)
623
			dev_err(&port->dev, "submit irq_in urb failed %d\n",
624 625 626
				result);
	}
	return 0;
K
Kevin Lloyd 已提交
627 628 629 630 631 632 633 634
}

static void sierra_close(struct usb_serial_port *port, struct file *filp)
{
	int i;
	struct usb_serial *serial = port->serial;
	struct sierra_port_private *portdata;

635
	dbg("%s", __func__);
K
Kevin Lloyd 已提交
636 637 638 639 640 641
	portdata = usb_get_serial_port_data(port);

	portdata->rts_state = 0;
	portdata->dtr_state = 0;

	if (serial->dev) {
642 643 644 645
		mutex_lock(&serial->disc_mutex);
		if (!serial->disconnected)
			sierra_send_setup(port);
		mutex_unlock(&serial->disc_mutex);
K
Kevin Lloyd 已提交
646 647 648

		/* Stop reading/writing urbs */
		for (i = 0; i < N_IN_URB; i++)
649
			usb_kill_urb(portdata->in_urbs[i]);
K
Kevin Lloyd 已提交
650 651
	}

652
	usb_kill_urb(port->interrupt_in_urb);
K
Kevin Lloyd 已提交
653

654
	port->tty = NULL;
K
Kevin Lloyd 已提交
655 656 657 658 659 660
}

static int sierra_startup(struct usb_serial *serial)
{
	struct usb_serial_port *port;
	struct sierra_port_private *portdata;
661 662 663
	struct urb *urb;
	int i;
	int j;
K
Kevin Lloyd 已提交
664

665
	dbg("%s", __func__);
K
Kevin Lloyd 已提交
666

667
	/* Set Device mode to D0 */
668 669
	sierra_set_power_state(serial->dev, 0x0000);

670 671 672 673
	/* Check NMEA and set */
	if (nmea)
		sierra_vsc_set_nmea(serial->dev, 1);

K
Kevin Lloyd 已提交
674 675 676 677 678 679
	/* Now setup per port private data */
	for (i = 0; i < serial->num_ports; i++) {
		port = serial->port[i];
		portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
		if (!portdata) {
			dbg("%s: kmalloc for sierra_port_private (%d) failed!.",
680
					__func__, i);
681
			return -ENOMEM;
K
Kevin Lloyd 已提交
682
		}
683
		spin_lock_init(&portdata->lock);
O
Oliver Neukum 已提交
684 685 686 687 688 689 690 691 692
		for (j = 0; j < N_IN_URB; j++) {
			portdata->in_buffer[j] = kmalloc(IN_BUFLEN, GFP_KERNEL);
			if (!portdata->in_buffer[j]) {
				for (--j; j >= 0; j--)
					kfree(portdata->in_buffer[j]);
				kfree(portdata);
				return -ENOMEM;
			}
		}
K
Kevin Lloyd 已提交
693 694 695

		usb_set_serial_port_data(port, portdata);

696 697 698 699 700
		/* initialize the in urbs */
		for (j = 0; j < N_IN_URB; ++j) {
			urb = usb_alloc_urb(0, GFP_KERNEL);
			if (urb == NULL) {
				dbg("%s: alloc for in port failed.",
701
				    __func__);
702 703 704 705 706 707 708 709 710 711
				continue;
			}
			/* Fill URB using supplied data. */
			usb_fill_bulk_urb(urb, serial->dev,
					  usb_rcvbulkpipe(serial->dev,
						port->bulk_in_endpointAddress),
					  portdata->in_buffer[j], IN_BUFLEN,
					  sierra_indat_callback, port);
			portdata->in_urbs[j] = urb;
		}
K
Kevin Lloyd 已提交
712 713
	}

714
	return 0;
K
Kevin Lloyd 已提交
715 716 717 718 719 720 721 722
}

static void sierra_shutdown(struct usb_serial *serial)
{
	int i, j;
	struct usb_serial_port *port;
	struct sierra_port_private *portdata;

723
	dbg("%s", __func__);
K
Kevin Lloyd 已提交
724 725 726

	for (i = 0; i < serial->num_ports; ++i) {
		port = serial->port[i];
727 728
		if (!port)
			continue;
K
Kevin Lloyd 已提交
729
		portdata = usb_get_serial_port_data(port);
730 731
		if (!portdata)
			continue;
K
Kevin Lloyd 已提交
732 733

		for (j = 0; j < N_IN_URB; j++) {
734 735
			usb_kill_urb(portdata->in_urbs[j]);
			usb_free_urb(portdata->in_urbs[j]);
O
Oliver Neukum 已提交
736
			kfree(portdata->in_buffer[j]);
K
Kevin Lloyd 已提交
737
		}
738 739
		kfree(portdata);
		usb_set_serial_port_data(port, NULL);
K
Kevin Lloyd 已提交
740 741 742
	}
}

743
static struct usb_serial_driver sierra_device = {
744 745 746 747
	.driver = {
		.owner =	THIS_MODULE,
		.name =		"sierra1",
	},
748 749
	.description       = "Sierra USB modem",
	.id_table          = id_table,
750
	.usb_driver        = &sierra_driver,
751 752
	.calc_num_ports	   = sierra_calc_num_ports,
	.probe		   = sierra_probe,
753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773
	.open              = sierra_open,
	.close             = sierra_close,
	.write             = sierra_write,
	.write_room        = sierra_write_room,
	.chars_in_buffer   = sierra_chars_in_buffer,
	.throttle          = sierra_rx_throttle,
	.unthrottle        = sierra_rx_unthrottle,
	.ioctl             = sierra_ioctl,
	.set_termios       = sierra_set_termios,
	.break_ctl         = sierra_break_ctl,
	.tiocmget          = sierra_tiocmget,
	.tiocmset          = sierra_tiocmset,
	.attach            = sierra_startup,
	.shutdown          = sierra_shutdown,
	.read_int_callback = sierra_instat_callback,
};

/* Functions used by new usb-serial code. */
static int __init sierra_init(void)
{
	int retval;
774
	retval = usb_serial_register(&sierra_device);
775
	if (retval)
776
		goto failed_device_register;
777 778 779 780 781 782 783 784 785 786 787


	retval = usb_register(&sierra_driver);
	if (retval)
		goto failed_driver_register;

	info(DRIVER_DESC ": " DRIVER_VERSION);

	return 0;

failed_driver_register:
788 789
	usb_serial_deregister(&sierra_device);
failed_device_register:
790 791 792 793 794 795
	return retval;
}

static void __exit sierra_exit(void)
{
	usb_deregister (&sierra_driver);
796
	usb_serial_deregister(&sierra_device);
797 798 799 800 801
}

module_init(sierra_init);
module_exit(sierra_exit);

K
Kevin Lloyd 已提交
802 803 804
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION);
805
MODULE_LICENSE("GPL");
K
Kevin Lloyd 已提交
806

807 808 809 810 811 812
module_param(truinstall, bool, 0);
MODULE_PARM_DESC(truinstall, "TRU-Install support");

module_param(nmea, bool, 0);
MODULE_PARM_DESC(nmea, "NMEA streaming");

K
Kevin Lloyd 已提交
813 814 815 816 817
#ifdef CONFIG_USB_DEBUG
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug messages");
#endif