speedtch.c 23.2 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7
/******************************************************************************
 *  speedtch.c  -  Alcatel SpeedTouch USB xDSL modem driver
 *
 *  Copyright (C) 2001, Alcatel
 *  Copyright (C) 2003, Duncan Sands
 *  Copyright (C) 2004, David Woodhouse
 *
8 9
 *  Based on "modem_run.c", copyright (C) 2001, Benoit Papillault
 *
L
Linus Torvalds 已提交
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *  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.
 *
 ******************************************************************************/

26 27 28 29
#include <asm/page.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/firmware.h>
L
Linus Torvalds 已提交
30
#include <linux/gfp.h>
31
#include <linux/init.h>
L
Linus Torvalds 已提交
32
#include <linux/kernel.h>
33 34
#include <linux/module.h>
#include <linux/moduleparam.h>
L
Linus Torvalds 已提交
35
#include <linux/slab.h>
36 37 38
#include <linux/stat.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
L
Linus Torvalds 已提交
39

40
#include "usbatm.h"
L
Linus Torvalds 已提交
41 42

#define DRIVER_AUTHOR	"Johan Verrept, Duncan Sands <duncan.sands@free.fr>"
43
#define DRIVER_VERSION	"1.9"
L
Linus Torvalds 已提交
44 45 46 47
#define DRIVER_DESC	"Alcatel SpeedTouch USB driver version " DRIVER_VERSION

static const char speedtch_driver_name[] = "speedtch";

48 49
#define CTRL_TIMEOUT 2000	/* milliseconds */
#define DATA_TIMEOUT 2000	/* milliseconds */
L
Linus Torvalds 已提交
50

51 52 53 54 55 56
#define OFFSET_7	0		/* size 1 */
#define OFFSET_b	1		/* size 8 */
#define OFFSET_d	9		/* size 4 */
#define OFFSET_e	13		/* size 1 */
#define OFFSET_f	14		/* size 1 */
#define TOTAL		15
L
Linus Torvalds 已提交
57

58 59 60 61 62
#define SIZE_7		1
#define SIZE_b		8
#define SIZE_d		4
#define SIZE_e		1
#define SIZE_f		1
L
Linus Torvalds 已提交
63

64 65
#define MIN_POLL_DELAY		5000	/* milliseconds */
#define MAX_POLL_DELAY		60000	/* milliseconds */
L
Linus Torvalds 已提交
66

67
#define RESUBMIT_DELAY		1000	/* milliseconds */
L
Linus Torvalds 已提交
68

69 70 71
#define DEFAULT_ALTSETTING	1
#define DEFAULT_DL_512_FIRST	0
#define DEFAULT_SW_BUFFERING	0
L
Linus Torvalds 已提交
72

73 74 75
static int altsetting = DEFAULT_ALTSETTING;
static int dl_512_first = DEFAULT_DL_512_FIRST;
static int sw_buffering = DEFAULT_SW_BUFFERING;
L
Linus Torvalds 已提交
76

77 78 79 80
module_param(altsetting, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(altsetting,
		 "Alternative setting for data interface (default: "
		 __MODULE_STRING(DEFAULT_ALTSETTING) ")");
L
Linus Torvalds 已提交
81

82 83 84 85
module_param(dl_512_first, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(dl_512_first,
		 "Read 512 bytes before sending firmware (default: "
		 __MODULE_STRING(DEFAULT_DL_512_FIRST) ")");
L
Linus Torvalds 已提交
86

87 88 89 90
module_param(sw_buffering, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(sw_buffering,
		 "Enable software buffering (default: "
		 __MODULE_STRING(DEFAULT_SW_BUFFERING) ")");
L
Linus Torvalds 已提交
91

92 93 94
#define ENDPOINT_INT		0x81
#define ENDPOINT_DATA		0x07
#define ENDPOINT_FIRMWARE	0x05
L
Linus Torvalds 已提交
95

96
#define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) )
L
Linus Torvalds 已提交
97 98

struct speedtch_instance_data {
99 100 101
	struct usbatm_data *usbatm;

	struct work_struct status_checker;
L
Linus Torvalds 已提交
102

103 104 105
	int poll_delay; /* milliseconds */

	struct timer_list resubmit_timer;
L
Linus Torvalds 已提交
106 107 108
	struct urb *int_urb;
	unsigned char int_data[16];

109
	unsigned char scratch_buffer[TOTAL];
L
Linus Torvalds 已提交
110 111 112 113 114 115
};

/***************
**  firmware  **
***************/

116
static void speedtch_set_swbuff(struct speedtch_instance_data *instance, int state)
L
Linus Torvalds 已提交
117
{
118 119
	struct usbatm_data *usbatm = instance->usbatm;
	struct usb_device *usb_dev = usbatm->usb_dev;
L
Linus Torvalds 已提交
120 121
	int ret;

122 123 124 125 126 127 128 129
	ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
			      0x32, 0x40, state ? 0x01 : 0x00, 0x00, NULL, 0, CTRL_TIMEOUT);
	if (ret < 0)
		usb_warn(usbatm,
			 "%sabling SW buffering: usb_control_msg returned %d\n",
			 state ? "En" : "Dis", ret);
	else
		dbg("speedtch_set_swbuff: %sbled SW buffering", state ? "En" : "Dis");
L
Linus Torvalds 已提交
130 131 132 133
}

static void speedtch_test_sequence(struct speedtch_instance_data *instance)
{
134 135 136
	struct usbatm_data *usbatm = instance->usbatm;
	struct usb_device *usb_dev = usbatm->usb_dev;
	unsigned char *buf = instance->scratch_buffer;
L
Linus Torvalds 已提交
137 138 139 140 141
	int ret;

	/* URB 147 */
	buf[0] = 0x1c;
	buf[1] = 0x50;
142 143
	ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
			      0x01, 0x40, 0x0b, 0x00, buf, 2, CTRL_TIMEOUT);
L
Linus Torvalds 已提交
144
	if (ret < 0)
145
		usb_warn(usbatm, "%s failed on URB147: %d\n", __func__, ret);
L
Linus Torvalds 已提交
146 147 148 149

	/* URB 148 */
	buf[0] = 0x32;
	buf[1] = 0x00;
150 151
	ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
			      0x01, 0x40, 0x02, 0x00, buf, 2, CTRL_TIMEOUT);
L
Linus Torvalds 已提交
152
	if (ret < 0)
153
		usb_warn(usbatm, "%s failed on URB148: %d\n", __func__, ret);
L
Linus Torvalds 已提交
154 155 156 157 158

	/* URB 149 */
	buf[0] = 0x01;
	buf[1] = 0x00;
	buf[2] = 0x01;
159 160
	ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
			      0x01, 0x40, 0x03, 0x00, buf, 3, CTRL_TIMEOUT);
L
Linus Torvalds 已提交
161
	if (ret < 0)
162
		usb_warn(usbatm, "%s failed on URB149: %d\n", __func__, ret);
L
Linus Torvalds 已提交
163 164 165 166 167

	/* URB 150 */
	buf[0] = 0x01;
	buf[1] = 0x00;
	buf[2] = 0x01;
168 169
	ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
			      0x01, 0x40, 0x04, 0x00, buf, 3, CTRL_TIMEOUT);
L
Linus Torvalds 已提交
170
	if (ret < 0)
171
		usb_warn(usbatm, "%s failed on URB150: %d\n", __func__, ret);
L
Linus Torvalds 已提交
172 173
}

174 175 176
static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
				     const struct firmware *fw1,
				     const struct firmware *fw2)
L
Linus Torvalds 已提交
177
{
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
	unsigned char *buffer;
	struct usbatm_data *usbatm = instance->usbatm;
	struct usb_interface *intf;
	struct usb_device *usb_dev = usbatm->usb_dev;
	int actual_length;
	int ret = 0;
	int offset;

	usb_dbg(usbatm, "%s entered\n", __func__);

	if (!(buffer = (unsigned char *)__get_free_page(GFP_KERNEL))) {
		ret = -ENOMEM;
		usb_dbg(usbatm, "%s: no memory for buffer!\n", __func__);
		goto out;
	}

	if (!(intf = usb_ifnum_to_if(usb_dev, 2))) {
		ret = -ENODEV;
		usb_dbg(usbatm, "%s: interface not found!\n", __func__);
		goto out_free;
	}

	/* URB 7 */
	if (dl_512_first) {	/* some modems need a read before writing the firmware */
		ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, ENDPOINT_FIRMWARE),
				   buffer, 0x200, &actual_length, 2000);

		if (ret < 0 && ret != -ETIMEDOUT)
			usb_dbg(usbatm, "%s: read BLOCK0 from modem failed (%d)!\n", __func__, ret);
		else
			usb_dbg(usbatm, "%s: BLOCK0 downloaded (%d bytes)\n", __func__, ret);
	}

	/* URB 8 : both leds are static green */
	for (offset = 0; offset < fw1->size; offset += PAGE_SIZE) {
		int thislen = min_t(int, PAGE_SIZE, fw1->size - offset);
		memcpy(buffer, fw1->data + offset, thislen);

		ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, ENDPOINT_FIRMWARE),
				   buffer, thislen, &actual_length, DATA_TIMEOUT);

		if (ret < 0) {
			usb_dbg(usbatm, "%s: write BLOCK1 to modem failed (%d)!\n", __func__, ret);
			goto out_free;
		}
		usb_dbg(usbatm, "%s: BLOCK1 uploaded (%zu bytes)\n", __func__, fw1->size);
	}

	/* USB led blinking green, ADSL led off */

	/* URB 11 */
	ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, ENDPOINT_FIRMWARE),
			   buffer, 0x200, &actual_length, DATA_TIMEOUT);
L
Linus Torvalds 已提交
231 232

	if (ret < 0) {
233 234
		usb_dbg(usbatm, "%s: read BLOCK2 from modem failed (%d)!\n", __func__, ret);
		goto out_free;
L
Linus Torvalds 已提交
235
	}
236
	usb_dbg(usbatm, "%s: BLOCK2 downloaded (%d bytes)\n", __func__, actual_length);
L
Linus Torvalds 已提交
237

238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
	/* URBs 12 to 139 - USB led blinking green, ADSL led off */
	for (offset = 0; offset < fw2->size; offset += PAGE_SIZE) {
		int thislen = min_t(int, PAGE_SIZE, fw2->size - offset);
		memcpy(buffer, fw2->data + offset, thislen);

		ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, ENDPOINT_FIRMWARE),
				   buffer, thislen, &actual_length, DATA_TIMEOUT);

		if (ret < 0) {
			usb_dbg(usbatm, "%s: write BLOCK3 to modem failed (%d)!\n", __func__, ret);
			goto out_free;
		}
	}
	usb_dbg(usbatm, "%s: BLOCK3 uploaded (%zu bytes)\n", __func__, fw2->size);

	/* USB led static green, ADSL led static red */

	/* URB 142 */
	ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, ENDPOINT_FIRMWARE),
			   buffer, 0x200, &actual_length, DATA_TIMEOUT);

	if (ret < 0) {
		usb_dbg(usbatm, "%s: read BLOCK4 from modem failed (%d)!\n", __func__, ret);
		goto out_free;
	}

	/* success */
	usb_dbg(usbatm, "%s: BLOCK4 downloaded (%d bytes)\n", __func__, actual_length);

	/* Delay to allow firmware to start up. We can do this here
	   because we're in our own kernel thread anyway. */
	msleep_interruptible(1000);

	/* Enable software buffering, if requested */
	if (sw_buffering)
		speedtch_set_swbuff(instance, 1);

	/* Magic spell; don't ask us what this does */
	speedtch_test_sequence(instance);

	ret = 0;

out_free:
	free_page((unsigned long)buffer);
out:
	return ret;
L
Linus Torvalds 已提交
284 285
}

286 287
static int speedtch_find_firmware(struct usb_interface *intf, int phase,
				  const struct firmware **fw_p)
L
Linus Torvalds 已提交
288
{
289 290 291 292 293
	struct device *dev = &intf->dev;
	const u16 bcdDevice = le16_to_cpu(interface_to_usbdev(intf)->descriptor.bcdDevice);
	const u8 major_revision = bcdDevice >> 8;
	const u8 minor_revision = bcdDevice & 0xff;
	char buf[24];
L
Linus Torvalds 已提交
294

295 296
	sprintf(buf, "speedtch-%d.bin.%x.%02x", phase, major_revision, minor_revision);
	dev_dbg(dev, "%s: looking for %s\n", __func__, buf);
L
Linus Torvalds 已提交
297

298 299 300
	if (request_firmware(fw_p, buf, dev)) {
		sprintf(buf, "speedtch-%d.bin.%x", phase, major_revision);
		dev_dbg(dev, "%s: looking for %s\n", __func__, buf);
L
Linus Torvalds 已提交
301

302 303 304 305 306 307 308 309 310
		if (request_firmware(fw_p, buf, dev)) {
			sprintf(buf, "speedtch-%d.bin", phase);
			dev_dbg(dev, "%s: looking for %s\n", __func__, buf);

			if (request_firmware(fw_p, buf, dev)) {
				dev_warn(dev, "no stage %d firmware found!\n", phase);
				return -ENOENT;
			}
		}
L
Linus Torvalds 已提交
311 312
	}

313
	dev_info(dev, "found stage %d firmware %s\n", phase, buf);
L
Linus Torvalds 已提交
314

315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
	return 0;
}

static int speedtch_heavy_init(struct usbatm_data *usbatm, struct usb_interface *intf)
{
	const struct firmware *fw1, *fw2;
	struct speedtch_instance_data *instance = usbatm->driver_data;
	int ret;

	if ((ret = speedtch_find_firmware(intf, 1, &fw1)) < 0)
			return ret;

	if ((ret = speedtch_find_firmware(intf, 2, &fw2)) < 0) {
		release_firmware(fw1);
		return ret;
L
Linus Torvalds 已提交
330 331
	}

332 333 334 335
	ret = speedtch_upload_firmware(instance, fw1, fw2);

	release_firmware(fw2);
	release_firmware(fw1);
L
Linus Torvalds 已提交
336

337
	return ret;
L
Linus Torvalds 已提交
338 339
}

340 341 342 343 344 345

/**********
**  ATM  **
**********/

static int speedtch_read_status(struct speedtch_instance_data *instance)
L
Linus Torvalds 已提交
346
{
347 348 349
	struct usbatm_data *usbatm = instance->usbatm;
	struct usb_device *usb_dev = usbatm->usb_dev;
	unsigned char *buf = instance->scratch_buffer;
L
Linus Torvalds 已提交
350 351 352 353
	int ret;

	memset(buf, 0, TOTAL);

354
	ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
L
Linus Torvalds 已提交
355 356 357
			      0x12, 0xc0, 0x07, 0x00, buf + OFFSET_7, SIZE_7,
			      CTRL_TIMEOUT);
	if (ret < 0) {
358
		atm_dbg(usbatm, "%s: MSG 7 failed\n", __func__);
L
Linus Torvalds 已提交
359 360 361
		return ret;
	}

362
	ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
L
Linus Torvalds 已提交
363 364 365
			      0x12, 0xc0, 0x0b, 0x00, buf + OFFSET_b, SIZE_b,
			      CTRL_TIMEOUT);
	if (ret < 0) {
366
		atm_dbg(usbatm, "%s: MSG B failed\n", __func__);
L
Linus Torvalds 已提交
367 368 369
		return ret;
	}

370
	ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
L
Linus Torvalds 已提交
371 372 373
			      0x12, 0xc0, 0x0d, 0x00, buf + OFFSET_d, SIZE_d,
			      CTRL_TIMEOUT);
	if (ret < 0) {
374
		atm_dbg(usbatm, "%s: MSG D failed\n", __func__);
L
Linus Torvalds 已提交
375 376 377
		return ret;
	}

378
	ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
L
Linus Torvalds 已提交
379 380 381
			      0x01, 0xc0, 0x0e, 0x00, buf + OFFSET_e, SIZE_e,
			      CTRL_TIMEOUT);
	if (ret < 0) {
382
		atm_dbg(usbatm, "%s: MSG E failed\n", __func__);
L
Linus Torvalds 已提交
383 384 385
		return ret;
	}

386
	ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
L
Linus Torvalds 已提交
387 388 389
			      0x01, 0xc0, 0x0f, 0x00, buf + OFFSET_f, SIZE_f,
			      CTRL_TIMEOUT);
	if (ret < 0) {
390
		atm_dbg(usbatm, "%s: MSG F failed\n", __func__);
L
Linus Torvalds 已提交
391 392 393 394 395 396
		return ret;
	}

	return 0;
}

397
static int speedtch_start_synchro(struct speedtch_instance_data *instance)
L
Linus Torvalds 已提交
398
{
399 400 401
	struct usbatm_data *usbatm = instance->usbatm;
	struct usb_device *usb_dev = usbatm->usb_dev;
	unsigned char *buf = instance->scratch_buffer;
L
Linus Torvalds 已提交
402 403
	int ret;

404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
	atm_dbg(usbatm, "%s entered\n", __func__);

	memset(buf, 0, 2);

	ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
			      0x12, 0xc0, 0x04, 0x00,
			      buf, 2, CTRL_TIMEOUT);

	if (ret < 0)
		atm_warn(usbatm, "failed to start ADSL synchronisation: %d\n", ret);
	else
		atm_dbg(usbatm, "%s: modem prodded. %d bytes returned: %02x %02x\n",
			__func__, ret, buf[0], buf[1]);

	return ret;
}

static void speedtch_check_status(struct speedtch_instance_data *instance)
{
	struct usbatm_data *usbatm = instance->usbatm;
	struct atm_dev *atm_dev = usbatm->atm_dev;
	unsigned char *buf = instance->scratch_buffer;
	int ret;

	atm_dbg(usbatm, "%s entered\n", __func__);

	ret = speedtch_read_status(instance);
	if (ret < 0) {
		atm_warn(usbatm, "error %d fetching device status\n", ret);
		if (instance->poll_delay < MAX_POLL_DELAY)
			instance->poll_delay *= 2;
L
Linus Torvalds 已提交
435 436 437
		return;
	}

438 439 440 441
	if (instance->poll_delay > MIN_POLL_DELAY)
		instance->poll_delay /= 2;

	atm_dbg(usbatm, "%s: line state %02x\n", __func__, buf[OFFSET_7]);
L
Linus Torvalds 已提交
442 443 444

	switch (buf[OFFSET_7]) {
	case 0:
445 446 447 448 449
		if (atm_dev->signal != ATM_PHY_SIG_LOST) {
			atm_dev->signal = ATM_PHY_SIG_LOST;
			atm_info(usbatm, "ADSL line is down\n");
			/* It'll never resync again unless we ask it to... */
			ret = speedtch_start_synchro(instance);
L
Linus Torvalds 已提交
450 451 452 453
		}
		break;

	case 0x08:
454 455 456
		if (atm_dev->signal != ATM_PHY_SIG_UNKNOWN) {
			atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
			atm_info(usbatm, "ADSL line is blocked?\n");
L
Linus Torvalds 已提交
457 458 459 460
		}
		break;

	case 0x10:
461 462 463
		if (atm_dev->signal != ATM_PHY_SIG_LOST) {
			atm_dev->signal = ATM_PHY_SIG_LOST;
			atm_info(usbatm, "ADSL line is synchronising\n");
L
Linus Torvalds 已提交
464 465 466 467
		}
		break;

	case 0x20:
468
		if (atm_dev->signal != ATM_PHY_SIG_FOUND) {
L
Linus Torvalds 已提交
469 470 471 472 473
			int down_speed = buf[OFFSET_b] | (buf[OFFSET_b + 1] << 8)
				| (buf[OFFSET_b + 2] << 16) | (buf[OFFSET_b + 3] << 24);
			int up_speed = buf[OFFSET_b + 4] | (buf[OFFSET_b + 5] << 8)
				| (buf[OFFSET_b + 6] << 16) | (buf[OFFSET_b + 7] << 24);

474
			if (!(down_speed & 0x0000ffff) && !(up_speed & 0x0000ffff)) {
L
Linus Torvalds 已提交
475 476 477 478
				down_speed >>= 16;
				up_speed >>= 16;
			}

479 480 481 482
			atm_dev->link_rate = down_speed * 1000 / 424;
			atm_dev->signal = ATM_PHY_SIG_FOUND;

			atm_info(usbatm,
483
				 "ADSL line is up (%d kb/s down | %d kb/s up)\n",
484
				 down_speed, up_speed);
L
Linus Torvalds 已提交
485 486 487 488
		}
		break;

	default:
489 490 491
		if (atm_dev->signal != ATM_PHY_SIG_UNKNOWN) {
			atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
			atm_info(usbatm, "Unknown line state %02x\n", buf[OFFSET_7]);
L
Linus Torvalds 已提交
492 493 494 495 496
		}
		break;
	}
}

497
static void speedtch_status_poll(unsigned long data)
L
Linus Torvalds 已提交
498 499 500
{
	struct speedtch_instance_data *instance = (void *)data;

501 502 503 504 505 506 507
	schedule_work(&instance->status_checker);

	/* The following check is racy, but the race is harmless */
	if (instance->poll_delay < MAX_POLL_DELAY)
		mod_timer(&instance->status_checker.timer, jiffies + msecs_to_jiffies(instance->poll_delay));
	else
		atm_warn(instance->usbatm, "Too many failures - disabling line status polling\n");
L
Linus Torvalds 已提交
508 509
}

510
static void speedtch_resubmit_int(unsigned long data)
L
Linus Torvalds 已提交
511
{
512 513 514
	struct speedtch_instance_data *instance = (void *)data;
	struct urb *int_urb = instance->int_urb;
	int ret;
L
Linus Torvalds 已提交
515

516
	atm_dbg(instance->usbatm, "%s entered\n", __func__);
L
Linus Torvalds 已提交
517

518 519 520 521 522 523 524
	if (int_urb) {
		ret = usb_submit_urb(int_urb, GFP_ATOMIC);
		if (!ret)
			schedule_work(&instance->status_checker);
		else {
			atm_dbg(instance->usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret);
			mod_timer(&instance->resubmit_timer, jiffies + msecs_to_jiffies(RESUBMIT_DELAY));
L
Linus Torvalds 已提交
525 526
		}
	}
527
}
L
Linus Torvalds 已提交
528

529 530 531 532 533 534
static void speedtch_handle_int(struct urb *int_urb, struct pt_regs *regs)
{
	struct speedtch_instance_data *instance = int_urb->context;
	struct usbatm_data *usbatm = instance->usbatm;
	unsigned int count = int_urb->actual_length;
	int ret = int_urb->status;
L
Linus Torvalds 已提交
535

536 537 538 539 540 541
	/* The magic interrupt for "up state" */
	const static unsigned char up_int[6]   = { 0xa1, 0x00, 0x01, 0x00, 0x00, 0x00 };
	/* The magic interrupt for "down state" */
	const static unsigned char down_int[6] = { 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00 };

	atm_dbg(usbatm, "%s entered\n", __func__);
L
Linus Torvalds 已提交
542 543

	if (ret < 0) {
544 545
		atm_dbg(usbatm, "%s: nonzero urb status %d!\n", __func__, ret);
		goto fail;
L
Linus Torvalds 已提交
546 547
	}

548 549 550 551 552 553 554
	if ((count == 6) && !memcmp(up_int, instance->int_data, 6)) {
		del_timer(&instance->status_checker.timer);
		atm_info(usbatm, "DSL line goes up\n");
	} else if ((count == 6) && !memcmp(down_int, instance->int_data, 6)) {
		atm_info(usbatm, "DSL line goes down\n");
	} else {
		int i;
L
Linus Torvalds 已提交
555

556 557 558 559 560 561
		atm_dbg(usbatm, "%s: unknown interrupt packet of length %d:", __func__, count);
		for (i = 0; i < count; i++)
			printk(" %02x", instance->int_data[i]);
		printk("\n");
		goto fail;
	}
L
Linus Torvalds 已提交
562

563 564 565
	if ((int_urb = instance->int_urb)) {
		ret = usb_submit_urb(int_urb, GFP_ATOMIC);
		schedule_work(&instance->status_checker);
L
Linus Torvalds 已提交
566
		if (ret < 0) {
567 568
			atm_dbg(usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret);
			goto fail;
L
Linus Torvalds 已提交
569 570 571 572 573
		}
	}

	return;

574 575 576
fail:
	if ((int_urb = instance->int_urb))
		mod_timer(&instance->resubmit_timer, jiffies + msecs_to_jiffies(RESUBMIT_DELAY));
L
Linus Torvalds 已提交
577 578
}

579
static int speedtch_atm_start(struct usbatm_data *usbatm, struct atm_dev *atm_dev)
L
Linus Torvalds 已提交
580
{
581 582 583 584
	struct usb_device *usb_dev = usbatm->usb_dev;
	struct speedtch_instance_data *instance = usbatm->driver_data;
	int i, ret;
	unsigned char mac_str[13];
L
Linus Torvalds 已提交
585

586
	atm_dbg(usbatm, "%s entered\n", __func__);
L
Linus Torvalds 已提交
587

588 589 590
	if ((ret = usb_set_interface(usb_dev, 1, altsetting)) < 0) {
		atm_dbg(usbatm, "%s: usb_set_interface returned %d!\n", __func__, ret);
		return ret;
L
Linus Torvalds 已提交
591 592
	}

593 594 595 596 597 598
	/* Set MAC address, it is stored in the serial number */
	memset(atm_dev->esi, 0, sizeof(atm_dev->esi));
	if (usb_string(usb_dev, usb_dev->descriptor.iSerialNumber, mac_str, sizeof(mac_str)) == 12) {
		for (i = 0; i < 6; i++)
			atm_dev->esi[i] = (hex2int(mac_str[i * 2]) * 16) + (hex2int(mac_str[i * 2 + 1]));
	}
L
Linus Torvalds 已提交
599

600 601
	/* Start modem synchronisation */
	ret = speedtch_start_synchro(instance);
L
Linus Torvalds 已提交
602

603 604 605 606 607 608 609 610
	/* Set up interrupt endpoint */
	if (instance->int_urb) {
		ret = usb_submit_urb(instance->int_urb, GFP_KERNEL);
		if (ret < 0) {
			/* Doesn't matter; we'll poll anyway */
			atm_dbg(usbatm, "%s: submission of interrupt URB failed (%d)!\n", __func__, ret);
			usb_free_urb(instance->int_urb);
			instance->int_urb = NULL;
L
Linus Torvalds 已提交
611 612 613
		}
	}

614 615
	/* Start status polling */
	mod_timer(&instance->status_checker.timer, jiffies + msecs_to_jiffies(1000));
L
Linus Torvalds 已提交
616 617 618 619

	return 0;
}

620
static void speedtch_atm_stop(struct usbatm_data *usbatm, struct atm_dev *atm_dev)
L
Linus Torvalds 已提交
621
{
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
	struct speedtch_instance_data *instance = usbatm->driver_data;
	struct urb *int_urb = instance->int_urb;

	atm_dbg(usbatm, "%s entered\n", __func__);

	del_timer_sync(&instance->status_checker.timer);

	/*
	 * Since resubmit_timer and int_urb can schedule themselves and
	 * each other, shutting them down correctly takes some care
	 */
	instance->int_urb = NULL; /* signal shutdown */
	mb();
	usb_kill_urb(int_urb);
	del_timer_sync(&instance->resubmit_timer);
	/*
	 * At this point, speedtch_handle_int and speedtch_resubmit_int
	 * can run or be running, but instance->int_urb == NULL means that
	 * they will not reschedule
	 */
	usb_kill_urb(int_urb);
	del_timer_sync(&instance->resubmit_timer);
	usb_free_urb(int_urb);
L
Linus Torvalds 已提交
645

646 647
	flush_scheduled_work();
}
L
Linus Torvalds 已提交
648 649


650 651 652
/**********
**  USB  **
**********/
L
Linus Torvalds 已提交
653

654 655 656 657
static struct usb_device_id speedtch_usb_ids[] = {
	{USB_DEVICE(0x06b9, 0x4061)},
	{}
};
L
Linus Torvalds 已提交
658

659
MODULE_DEVICE_TABLE(usb, speedtch_usb_ids);
L
Linus Torvalds 已提交
660

661
static int speedtch_usb_probe(struct usb_interface *, const struct usb_device_id *);
L
Linus Torvalds 已提交
662

663 664 665 666 667 668 669
static struct usb_driver speedtch_usb_driver = {
	.owner		= THIS_MODULE,
	.name		= speedtch_driver_name,
	.probe		= speedtch_usb_probe,
	.disconnect	= usbatm_usb_disconnect,
	.id_table	= speedtch_usb_ids
};
L
Linus Torvalds 已提交
670

671 672 673
static void speedtch_release_interfaces(struct usb_device *usb_dev, int num_interfaces) {
	struct usb_interface *cur_intf;
	int i;
L
Linus Torvalds 已提交
674

675 676 677 678 679
	for(i = 0; i < num_interfaces; i++)
		if ((cur_intf = usb_ifnum_to_if(usb_dev, i))) {
			usb_set_intfdata(cur_intf, NULL);
			usb_driver_release_interface(&speedtch_usb_driver, cur_intf);
		}
L
Linus Torvalds 已提交
680 681
}

682 683 684 685
static int speedtch_bind(struct usbatm_data *usbatm,
			 struct usb_interface *intf,
			 const struct usb_device_id *id,
			 int *need_heavy_init)
L
Linus Torvalds 已提交
686
{
687 688 689 690 691 692
	struct usb_device *usb_dev = interface_to_usbdev(intf);
	struct usb_interface *cur_intf;
	struct speedtch_instance_data *instance;
	int ifnum = intf->altsetting->desc.bInterfaceNumber;
	int num_interfaces = usb_dev->actconfig->desc.bNumInterfaces;
	int i, ret;
L
Linus Torvalds 已提交
693

694
	usb_dbg(usbatm, "%s entered\n", __func__);
L
Linus Torvalds 已提交
695

696 697
	if (usb_dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) {
		usb_dbg(usbatm, "%s: wrong device class %d\n", __func__, usb_dev->descriptor.bDeviceClass);
L
Linus Torvalds 已提交
698 699 700
		return -ENODEV;
	}

701
	/* claim all interfaces */
L
Linus Torvalds 已提交
702

703 704
	for (i=0; i < num_interfaces; i++) {
		cur_intf = usb_ifnum_to_if(usb_dev, i);
L
Linus Torvalds 已提交
705

706 707
		if ((i != ifnum) && cur_intf) {
			ret = usb_driver_claim_interface(&speedtch_usb_driver, cur_intf, usbatm);
L
Linus Torvalds 已提交
708

709 710 711 712 713 714 715
			if (ret < 0) {
				usb_dbg(usbatm, "%s: failed to claim interface %d (%d)\n", __func__, i, ret);
				speedtch_release_interfaces(usb_dev, i);
				return ret;
			}
		}
	}
L
Linus Torvalds 已提交
716 717

	instance = kmalloc(sizeof(*instance), GFP_KERNEL);
718

L
Linus Torvalds 已提交
719
	if (!instance) {
720 721 722
		usb_dbg(usbatm, "%s: no memory for instance data!\n", __func__);
		ret = -ENOMEM;
		goto fail_release;
L
Linus Torvalds 已提交
723 724 725 726
	}

	memset(instance, 0, sizeof(struct speedtch_instance_data));

727
	instance->usbatm = usbatm;
L
Linus Torvalds 已提交
728

729
	INIT_WORK(&instance->status_checker, (void *)speedtch_check_status, instance);
L
Linus Torvalds 已提交
730

731 732 733
	instance->status_checker.timer.function = speedtch_status_poll;
	instance->status_checker.timer.data = (unsigned long)instance;
	instance->poll_delay = MIN_POLL_DELAY;
L
Linus Torvalds 已提交
734

735 736 737
	init_timer(&instance->resubmit_timer);
	instance->resubmit_timer.function = speedtch_resubmit_int;
	instance->resubmit_timer.data = (unsigned long)instance;
L
Linus Torvalds 已提交
738

739
	instance->int_urb = usb_alloc_urb(0, GFP_KERNEL);
L
Linus Torvalds 已提交
740

741 742 743 744 745 746 747
	if (instance->int_urb)
		usb_fill_int_urb(instance->int_urb, usb_dev,
				 usb_rcvintpipe(usb_dev, ENDPOINT_INT),
				 instance->int_data, sizeof(instance->int_data),
				 speedtch_handle_int, instance, 50);
	else
		usb_dbg(usbatm, "%s: no memory for interrupt urb!\n", __func__);
L
Linus Torvalds 已提交
748

749 750 751 752
	/* check whether the modem already seems to be alive */
	ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
			      0x12, 0xc0, 0x07, 0x00,
			      instance->scratch_buffer + OFFSET_7, SIZE_7, 500);
L
Linus Torvalds 已提交
753

754
	*need_heavy_init = (ret != SIZE_7);
L
Linus Torvalds 已提交
755

756 757 758 759 760
	usb_dbg(usbatm, "%s: firmware %s loaded\n", __func__, need_heavy_init ? "not" : "already");

	if (*need_heavy_init)
		if ((ret = usb_reset_device(usb_dev)) < 0)
			goto fail_free;
L
Linus Torvalds 已提交
761

762
        usbatm->driver_data = instance;
L
Linus Torvalds 已提交
763 764 765

	return 0;

766 767
fail_free:
	usb_free_urb(instance->int_urb);
L
Linus Torvalds 已提交
768
	kfree(instance);
769 770 771
fail_release:
	speedtch_release_interfaces(usb_dev, num_interfaces);
	return ret;
L
Linus Torvalds 已提交
772 773
}

774
static void speedtch_unbind(struct usbatm_data *usbatm, struct usb_interface *intf)
L
Linus Torvalds 已提交
775
{
776 777
	struct usb_device *usb_dev = interface_to_usbdev(intf);
	struct speedtch_instance_data *instance = usbatm->driver_data;
L
Linus Torvalds 已提交
778

779
	usb_dbg(usbatm, "%s entered\n", __func__);
L
Linus Torvalds 已提交
780

781 782 783
	speedtch_release_interfaces(usb_dev, usb_dev->actconfig->desc.bNumInterfaces);
	usb_free_urb(instance->int_urb);
	kfree(instance);
L
Linus Torvalds 已提交
784 785
}

786

L
Linus Torvalds 已提交
787 788 789 790
/***********
**  init  **
***********/

791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807
static struct usbatm_driver speedtch_usbatm_driver = {
	.owner		= THIS_MODULE,
	.driver_name	= speedtch_driver_name,
	.bind		= speedtch_bind,
	.heavy_init	= speedtch_heavy_init,
	.unbind		= speedtch_unbind,
	.atm_start	= speedtch_atm_start,
	.atm_stop	= speedtch_atm_stop,
	.in		= ENDPOINT_DATA,
	.out		= ENDPOINT_DATA
};

static int speedtch_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
	return usbatm_usb_probe(intf, id, &speedtch_usbatm_driver);
}

L
Linus Torvalds 已提交
808 809
static int __init speedtch_usb_init(void)
{
810
	dbg("%s: driver version %s", __func__, DRIVER_VERSION);
L
Linus Torvalds 已提交
811 812 813 814 815 816

	return usb_register(&speedtch_usb_driver);
}

static void __exit speedtch_usb_cleanup(void)
{
817
	dbg("%s", __func__);
L
Linus Torvalds 已提交
818 819 820 821 822 823 824 825 826 827 828

	usb_deregister(&speedtch_usb_driver);
}

module_init(speedtch_usb_init);
module_exit(speedtch_usb_cleanup);

MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
MODULE_VERSION(DRIVER_VERSION);