⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 speedtch.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************** *  speedtch.c  -  Alcatel SpeedTouch USB xDSL modem driver * *  Copyright (C) 2001, Alcatel *  Copyright (C) 2003, Duncan Sands *  Copyright (C) 2004, David Woodhouse * *  Based on "modem_run.c", copyright (C) 2001, Benoit Papillault * *  This program is free software; you can redistribute it and/or modify it *  under the terms of the GNU General Public License as published by the Free *  Software Foundation; either version 2 of the License, or (at your option) *  any later version. * *  This program is distributed in the hope that it will be useful, but WITHOUT *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for *  more details. * *  You should have received a copy of the GNU General Public License along with *  this program; if not, write to the Free Software Foundation, Inc., 59 *  Temple Place - Suite 330, Boston, MA  02111-1307, USA. * ******************************************************************************/#include <asm/page.h>#include <linux/device.h>#include <linux/errno.h>#include <linux/firmware.h>#include <linux/gfp.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/slab.h>#include <linux/stat.h>#include <linux/timer.h>#include <linux/workqueue.h>#include "usbatm.h"#define DRIVER_AUTHOR	"Johan Verrept, Duncan Sands <duncan.sands@free.fr>"#define DRIVER_VERSION	"1.9"#define DRIVER_DESC	"Alcatel SpeedTouch USB driver version " DRIVER_VERSIONstatic const char speedtch_driver_name[] = "speedtch";#define CTRL_TIMEOUT 2000	/* milliseconds */#define DATA_TIMEOUT 2000	/* milliseconds */#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#define SIZE_7		1#define SIZE_b		8#define SIZE_d		4#define SIZE_e		1#define SIZE_f		1#define MIN_POLL_DELAY		5000	/* milliseconds */#define MAX_POLL_DELAY		60000	/* milliseconds */#define RESUBMIT_DELAY		1000	/* milliseconds */#define DEFAULT_ALTSETTING	1#define DEFAULT_DL_512_FIRST	0#define DEFAULT_SW_BUFFERING	0static int altsetting = DEFAULT_ALTSETTING;static int dl_512_first = DEFAULT_DL_512_FIRST;static int sw_buffering = DEFAULT_SW_BUFFERING;module_param(altsetting, int, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(altsetting,		 "Alternative setting for data interface (default: "		 __MODULE_STRING(DEFAULT_ALTSETTING) ")");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) ")");module_param(sw_buffering, bool, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(sw_buffering,		 "Enable software buffering (default: "		 __MODULE_STRING(DEFAULT_SW_BUFFERING) ")");#define ENDPOINT_INT		0x81#define ENDPOINT_DATA		0x07#define ENDPOINT_FIRMWARE	0x05#define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) )struct speedtch_instance_data {	struct usbatm_data *usbatm;	struct work_struct status_checker;	unsigned char last_status;	int poll_delay; /* milliseconds */	struct timer_list resubmit_timer;	struct urb *int_urb;	unsigned char int_data[16];	unsigned char scratch_buffer[TOTAL];};/*****************  firmware  *****************/static void speedtch_set_swbuff(struct speedtch_instance_data *instance, int state){	struct usbatm_data *usbatm = instance->usbatm;	struct usb_device *usb_dev = usbatm->usb_dev;	int ret;	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");}static void speedtch_test_sequence(struct speedtch_instance_data *instance){	struct usbatm_data *usbatm = instance->usbatm;	struct usb_device *usb_dev = usbatm->usb_dev;	unsigned char *buf = instance->scratch_buffer;	int ret;	/* URB 147 */	buf[0] = 0x1c;	buf[1] = 0x50;	ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),			      0x01, 0x40, 0x0b, 0x00, buf, 2, CTRL_TIMEOUT);	if (ret < 0)		usb_warn(usbatm, "%s failed on URB147: %d\n", __func__, ret);	/* URB 148 */	buf[0] = 0x32;	buf[1] = 0x00;	ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),			      0x01, 0x40, 0x02, 0x00, buf, 2, CTRL_TIMEOUT);	if (ret < 0)		usb_warn(usbatm, "%s failed on URB148: %d\n", __func__, ret);	/* URB 149 */	buf[0] = 0x01;	buf[1] = 0x00;	buf[2] = 0x01;	ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),			      0x01, 0x40, 0x03, 0x00, buf, 3, CTRL_TIMEOUT);	if (ret < 0)		usb_warn(usbatm, "%s failed on URB149: %d\n", __func__, ret);	/* URB 150 */	buf[0] = 0x01;	buf[1] = 0x00;	buf[2] = 0x01;	ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),			      0x01, 0x40, 0x04, 0x00, buf, 3, CTRL_TIMEOUT);	if (ret < 0)		usb_warn(usbatm, "%s failed on URB150: %d\n", __func__, ret);}static int speedtch_upload_firmware(struct speedtch_instance_data *instance,				     const struct firmware *fw1,				     const struct firmware *fw2){	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);	if (ret < 0) {		usb_dbg(usbatm, "%s: read BLOCK2 from modem failed (%d)!\n", __func__, ret);		goto out_free;	}	usb_dbg(usbatm, "%s: BLOCK2 downloaded (%d bytes)\n", __func__, actual_length);	/* 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;}static int speedtch_find_firmware(struct usb_interface *intf, int phase,				  const struct firmware **fw_p){	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];	sprintf(buf, "speedtch-%d.bin.%x.%02x", phase, major_revision, minor_revision);	dev_dbg(dev, "%s: looking for %s\n", __func__, buf);	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);		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;			}		}	}	dev_info(dev, "found stage %d firmware %s\n", phase, buf);	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;	}	ret = speedtch_upload_firmware(instance, fw1, fw2);	release_firmware(fw2);	release_firmware(fw1);	return ret;}/************  ATM  ************/static int speedtch_read_status(struct speedtch_instance_data *instance){	struct usbatm_data *usbatm = instance->usbatm;	struct usb_device *usb_dev = usbatm->usb_dev;	unsigned char *buf = instance->scratch_buffer;	int ret;	memset(buf, 0, TOTAL);	ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),			      0x12, 0xc0, 0x07, 0x00, buf + OFFSET_7, SIZE_7,			      CTRL_TIMEOUT);	if (ret < 0) {		atm_dbg(usbatm, "%s: MSG 7 failed\n", __func__);		return ret;	}	ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),			      0x12, 0xc0, 0x0b, 0x00, buf + OFFSET_b, SIZE_b,			      CTRL_TIMEOUT);	if (ret < 0) {		atm_dbg(usbatm, "%s: MSG B failed\n", __func__);		return ret;	}	ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),			      0x12, 0xc0, 0x0d, 0x00, buf + OFFSET_d, SIZE_d,			      CTRL_TIMEOUT);	if (ret < 0) {		atm_dbg(usbatm, "%s: MSG D failed\n", __func__);		return ret;	}	ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),			      0x01, 0xc0, 0x0e, 0x00, buf + OFFSET_e, SIZE_e,			      CTRL_TIMEOUT);	if (ret < 0) {		atm_dbg(usbatm, "%s: MSG E failed\n", __func__);		return ret;	}	ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),			      0x01, 0xc0, 0x0f, 0x00, buf + OFFSET_f, SIZE_f,			      CTRL_TIMEOUT);	if (ret < 0) {		atm_dbg(usbatm, "%s: MSG F failed\n", __func__);		return ret;	}	return 0;}static int speedtch_start_synchro(struct speedtch_instance_data *instance){	struct usbatm_data *usbatm = instance->usbatm;	struct usb_device *usb_dev = usbatm->usb_dev;	unsigned char *buf = instance->scratch_buffer;	int ret;	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)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -