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

📄 speedtch.c

📁 h内核
💻 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 * *  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 <linux/module.h>#include <linux/moduleparam.h>#include <linux/gfp.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/errno.h>#include <linux/proc_fs.h>#include <linux/slab.h>#include <linux/wait.h>#include <linux/list.h>#include <asm/processor.h>#include <asm/uaccess.h>#include <linux/smp_lock.h>#include <linux/interrupt.h>#include <linux/atm.h>#include <linux/atmdev.h>#include <linux/crc32.h>#include <linux/init.h>#include <linux/firmware.h>#include "usb_atm.h"#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)#	define USE_FW_LOADER#endif#define DRIVER_AUTHOR	"Johan Verrept, Duncan Sands <duncan.sands@free.fr>"#define DRIVER_VERSION	"1.8"#define DRIVER_DESC	"Alcatel SpeedTouch USB driver version " DRIVER_VERSIONstatic const char speedtch_driver_name[] = "speedtch";#define SPEEDTOUCH_VENDORID		0x06b9#define SPEEDTOUCH_PRODUCTID		0x4061/* Timeout in jiffies */#define CTRL_TIMEOUT (2*HZ)#define DATA_TIMEOUT (2*HZ)#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 1static int dl_512_first = 0;static int sw_buffering = 0;module_param(dl_512_first, bool, 0444);MODULE_PARM_DESC(dl_512_first, "Read 512 bytes before sending firmware");module_param(sw_buffering, uint, 0444);MODULE_PARM_DESC(sw_buffering, "Enable software buffering");#define UDSL_IOCTL_LINE_UP		1#define UDSL_IOCTL_LINE_DOWN		2#define SPEEDTCH_ENDPOINT_INT		0x81#define SPEEDTCH_ENDPOINT_DATA		0x07#define SPEEDTCH_ENDPOINT_FIRMWARE	0x05#define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) )static struct usb_device_id speedtch_usb_ids[] = {	{USB_DEVICE(SPEEDTOUCH_VENDORID, SPEEDTOUCH_PRODUCTID)},	{}};MODULE_DEVICE_TABLE(usb, speedtch_usb_ids);struct speedtch_instance_data {	struct udsl_instance_data u;	/* Status */	struct urb *int_urb;	unsigned char int_data[16];	struct work_struct poll_work;	struct timer_list poll_timer;};/* USB */static int speedtch_usb_probe(struct usb_interface *intf,			      const struct usb_device_id *id);static void speedtch_usb_disconnect(struct usb_interface *intf);static int speedtch_usb_ioctl(struct usb_interface *intf, unsigned int code,			      void *user_data);static void speedtch_handle_int(struct urb *urb, struct pt_regs *regs);static void speedtch_poll_status(struct speedtch_instance_data *instance);static struct usb_driver speedtch_usb_driver = {	.owner		= THIS_MODULE,	.name		= speedtch_driver_name,	.probe		= speedtch_usb_probe,	.disconnect	= speedtch_usb_disconnect,	.ioctl		= speedtch_usb_ioctl,	.id_table	= speedtch_usb_ids,};/*****************  firmware  *****************/static void speedtch_got_firmware(struct speedtch_instance_data *instance,				  int got_it){	int err;	struct usb_interface *intf;	down(&instance->u.serialize);	/* vs self, speedtch_firmware_start */	if (instance->u.status == UDSL_LOADED_FIRMWARE)		goto out;	if (!got_it) {		instance->u.status = UDSL_NO_FIRMWARE;		goto out;	}	if ((err = usb_set_interface(instance->u.usb_dev, 1, 1)) < 0) {		dbg("speedtch_got_firmware: usb_set_interface returned %d!", err);		instance->u.status = UDSL_NO_FIRMWARE;		goto out;	}	/* Set up interrupt endpoint */	intf = usb_ifnum_to_if(instance->u.usb_dev, 0);	if (intf && !usb_driver_claim_interface(&speedtch_usb_driver, intf, NULL)) {		instance->int_urb = usb_alloc_urb(0, GFP_KERNEL);		if (instance->int_urb) {			usb_fill_int_urb(instance->int_urb, instance->u.usb_dev,					 usb_rcvintpipe(instance->u.usb_dev, SPEEDTCH_ENDPOINT_INT),					 instance->int_data,					 sizeof(instance->int_data),					 speedtch_handle_int, instance, 50);			err = usb_submit_urb(instance->int_urb, GFP_KERNEL);			if (err) {				/* Doesn't matter; we'll poll anyway */				dbg("speedtch_got_firmware: Submission of interrupt URB failed %d", err);				usb_free_urb(instance->int_urb);				instance->int_urb = NULL;				usb_driver_release_interface(&speedtch_usb_driver, intf);			}		}	}	/* Start status polling */	mod_timer(&instance->poll_timer, jiffies + (1 * HZ));	instance->u.status = UDSL_LOADED_FIRMWARE;	tasklet_schedule(&instance->u.receive_tasklet); out:	up(&instance->u.serialize);	wake_up_interruptible(&instance->u.firmware_waiters);}static int speedtch_set_swbuff(struct speedtch_instance_data *instance,			       int state){	struct usb_device *dev = instance->u.usb_dev;	int ret;	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),			      0x32, 0x40, state ? 0x01 : 0x00,			      0x00, NULL, 0, 100);	if (ret < 0) {		printk("Warning: %sabling SW buffering: usb_control_msg returned %d\n",		     state ? "En" : "Dis", ret);		return ret;	}	dbg("speedtch_set_swbuff: %sbled SW buffering", state ? "En" : "Dis");	return 0;}static void speedtch_test_sequence(struct speedtch_instance_data *instance){	struct usb_device *dev = instance->u.usb_dev;	unsigned char buf[10];	int ret;	/* URB 147 */	buf[0] = 0x1c;	buf[1] = 0x50;	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),			      0x01, 0x40, 0x0b, 0x00, buf, 2, 100);	if (ret < 0)		printk(KERN_WARNING "%s failed on URB147: %d\n", __func__, ret);	/* URB 148 */	buf[0] = 0x32;	buf[1] = 0x00;	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),			      0x01, 0x40, 0x02, 0x00, buf, 2, 100);	if (ret < 0)		printk(KERN_WARNING "%s failed on URB148: %d\n", __func__, ret);	/* URB 149 */	buf[0] = 0x01;	buf[1] = 0x00;	buf[2] = 0x01;	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),			      0x01, 0x40, 0x03, 0x00, buf, 3, 100);	if (ret < 0)		printk(KERN_WARNING "%s failed on URB149: %d\n", __func__, ret);	/* URB 150 */	buf[0] = 0x01;	buf[1] = 0x00;	buf[2] = 0x01;	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),			      0x01, 0x40, 0x04, 0x00, buf, 3, 100);	if (ret < 0)		printk(KERN_WARNING "%s failed on URB150: %d\n", __func__, ret);}static int speedtch_start_synchro(struct speedtch_instance_data *instance){	struct usb_device *dev = instance->u.usb_dev;	unsigned char buf[2];	int ret;	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),			      0x12, 0xc0, 0x04, 0x00,			      buf, sizeof(buf), CTRL_TIMEOUT);	if (ret < 0) {		printk(KERN_WARNING "SpeedTouch: Failed to start ADSL synchronisation: %d\n", ret);		return ret;	}	dbg("speedtch_start_synchro: modem prodded. %d Bytes returned: %02x %02x", ret, buf[0], buf[1]);	return 0;}static void speedtch_handle_int(struct urb *urb, struct pt_regs *regs){	struct speedtch_instance_data *instance = urb->context;	unsigned int count = urb->actual_length;	int ret;	/* 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 };	switch (urb->status) {	case 0:		/* success */		break;	case -ECONNRESET:	case -ENOENT:	case -ESHUTDOWN:		/* this urb is terminated; clean up */		dbg("%s - urb shutting down with status: %d", __func__, urb->status);		return;	default:		dbg("%s - nonzero urb status received: %d", __func__, urb->status);		goto exit;	}	if (count < 6) {		dbg("%s - int packet too short", __func__);		goto exit;	}	if (!memcmp(up_int, instance->int_data, 6)) {		del_timer(&instance->poll_timer);		printk(KERN_NOTICE "DSL line goes up\n");	} else if (!memcmp(down_int, instance->int_data, 6)) {		printk(KERN_NOTICE "DSL line goes down\n");	} else {		int i;		printk(KERN_DEBUG "Unknown interrupt packet of %d bytes:", count);		for (i = 0; i < count; i++)			printk(" %02x", instance->int_data[i]);		printk("\n");	}	schedule_work(&instance->poll_work); exit:	rmb();	if (!instance->int_urb)		return;	ret = usb_submit_urb(urb, GFP_ATOMIC);	if (ret)		err("%s - usb_submit_urb failed with result %d", __func__, ret);}static int speedtch_get_status(struct speedtch_instance_data *instance,			       unsigned char *buf){	struct usb_device *dev = instance->u.usb_dev;	int ret;	memset(buf, 0, TOTAL);	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),			      0x12, 0xc0, 0x07, 0x00, buf + OFFSET_7, SIZE_7,			      CTRL_TIMEOUT);	if (ret < 0) {		dbg("MSG 7 failed");		return ret;	}	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),			      0x12, 0xc0, 0x0b, 0x00, buf + OFFSET_b, SIZE_b,			      CTRL_TIMEOUT);	if (ret < 0) {		dbg("MSG B failed");		return ret;	}	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),			      0x12, 0xc0, 0x0d, 0x00, buf + OFFSET_d, SIZE_d,			      CTRL_TIMEOUT);	if (ret < 0) {		dbg("MSG D failed");		return ret;	}	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),			      0x01, 0xc0, 0x0e, 0x00, buf + OFFSET_e, SIZE_e,			      CTRL_TIMEOUT);	if (ret < 0) {		dbg("MSG E failed");		return ret;	}	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),			      0x01, 0xc0, 0x0f, 0x00, buf + OFFSET_f, SIZE_f,			      CTRL_TIMEOUT);	if (ret < 0) {		dbg("MSG F failed");		return ret;	}	return 0;}static void speedtch_poll_status(struct speedtch_instance_data *instance){	unsigned char buf[TOTAL];	int ret;	ret = speedtch_get_status(instance, buf);	if (ret) {		printk(KERN_WARNING		       "SpeedTouch: Error %d fetching device status\n", ret);		return;	}	dbg("Line state %02x", buf[OFFSET_7]);	switch (buf[OFFSET_7]) {	case 0:		if (instance->u.atm_dev->signal != ATM_PHY_SIG_LOST) {			instance->u.atm_dev->signal = ATM_PHY_SIG_LOST;			printk(KERN_NOTICE "ADSL line is down\n");		}		break;	case 0x08:		if (instance->u.atm_dev->signal != ATM_PHY_SIG_UNKNOWN) {			instance->u.atm_dev->signal = ATM_PHY_SIG_UNKNOWN;			printk(KERN_NOTICE "ADSL line is blocked?\n");		}		break;	case 0x10:		if (instance->u.atm_dev->signal != ATM_PHY_SIG_LOST) {			instance->u.atm_dev->signal = ATM_PHY_SIG_LOST;			printk(KERN_NOTICE "ADSL line is synchronising\n");		}		break;	case 0x20:		if (instance->u.atm_dev->signal != ATM_PHY_SIG_FOUND) {			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);			if (!(down_speed & 0x0000ffff) &&			    !(up_speed & 0x0000ffff)) {				down_speed >>= 16;				up_speed >>= 16;			}			instance->u.atm_dev->link_rate = down_speed * 1000 / 424;			instance->u.atm_dev->signal = ATM_PHY_SIG_FOUND;			printk(KERN_NOTICE			       "ADSL line is up (%d Kib/s down | %d Kib/s up)\n",			       down_speed, up_speed);		}

⌨️ 快捷键说明

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