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

📄 speedtch.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
		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 down_speed, up_speed, ret;	unsigned char status;	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);		instance->poll_delay = min(2 * instance->poll_delay, MAX_POLL_DELAY);		return;	}	instance->poll_delay = max(instance->poll_delay / 2, MIN_POLL_DELAY);	status = buf[OFFSET_7];	atm_dbg(usbatm, "%s: line state %02x\n", __func__, status);	if ((status != instance->last_status) || !status) {		switch (status) {		case 0:			atm_dev->signal = ATM_PHY_SIG_LOST;			if (instance->last_status)				atm_info(usbatm, "ADSL line is down\n");			/* It may never resync again unless we ask it to... */			ret = speedtch_start_synchro(instance);			break;		case 0x08:			atm_dev->signal = ATM_PHY_SIG_UNKNOWN;			atm_info(usbatm, "ADSL line is blocked?\n");			break;		case 0x10:			atm_dev->signal = ATM_PHY_SIG_LOST;			atm_info(usbatm, "ADSL line is synchronising\n");			break;		case 0x20:			down_speed = buf[OFFSET_b] | (buf[OFFSET_b + 1] << 8)				| (buf[OFFSET_b + 2] << 16) | (buf[OFFSET_b + 3] << 24);			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;			}			atm_dev->link_rate = down_speed * 1000 / 424;			atm_dev->signal = ATM_PHY_SIG_FOUND;			atm_info(usbatm,				 "ADSL line is up (%d kb/s down | %d kb/s up)\n",				 down_speed, up_speed);			break;		default:			atm_dev->signal = ATM_PHY_SIG_UNKNOWN;			atm_info(usbatm, "Unknown line state %02x\n", status);			break;		}		instance->last_status = status;	}}static void speedtch_status_poll(unsigned long data){	struct speedtch_instance_data *instance = (void *)data;	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");}static void speedtch_resubmit_int(unsigned long data){	struct speedtch_instance_data *instance = (void *)data;	struct urb *int_urb = instance->int_urb;	int ret;	atm_dbg(instance->usbatm, "%s entered\n", __func__);	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));		}	}}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;	/* 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__);	if (ret < 0) {		atm_dbg(usbatm, "%s: nonzero urb status %d!\n", __func__, ret);		goto fail;	}	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;		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;	}	if ((int_urb = instance->int_urb)) {		ret = usb_submit_urb(int_urb, GFP_ATOMIC);		schedule_work(&instance->status_checker);		if (ret < 0) {			atm_dbg(usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret);			goto fail;		}	}	return;fail:	if ((int_urb = instance->int_urb))		mod_timer(&instance->resubmit_timer, jiffies + msecs_to_jiffies(RESUBMIT_DELAY));}static int speedtch_atm_start(struct usbatm_data *usbatm, struct atm_dev *atm_dev){	struct usb_device *usb_dev = usbatm->usb_dev;	struct speedtch_instance_data *instance = usbatm->driver_data;	int i, ret;	unsigned char mac_str[13];	atm_dbg(usbatm, "%s entered\n", __func__);	if ((ret = usb_set_interface(usb_dev, 1, altsetting)) < 0) {		atm_dbg(usbatm, "%s: usb_set_interface returned %d!\n", __func__, ret);		return ret;	}	/* 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]));	}	/* Start modem synchronisation */	ret = speedtch_start_synchro(instance);	/* 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;		}	}	/* Start status polling */	mod_timer(&instance->status_checker.timer, jiffies + msecs_to_jiffies(1000));	return 0;}static void speedtch_atm_stop(struct usbatm_data *usbatm, struct atm_dev *atm_dev){	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);	flush_scheduled_work();}/************  USB  ************/static struct usb_device_id speedtch_usb_ids[] = {	{USB_DEVICE(0x06b9, 0x4061)},	{}};MODULE_DEVICE_TABLE(usb, speedtch_usb_ids);static int speedtch_usb_probe(struct usb_interface *, const struct usb_device_id *);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};static void speedtch_release_interfaces(struct usb_device *usb_dev, int num_interfaces) {	struct usb_interface *cur_intf;	int i;	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);		}}static int speedtch_bind(struct usbatm_data *usbatm,			 struct usb_interface *intf,			 const struct usb_device_id *id,			 int *need_heavy_init){	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;	usb_dbg(usbatm, "%s entered\n", __func__);	if (usb_dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) {		usb_dbg(usbatm, "%s: wrong device class %d\n", __func__, usb_dev->descriptor.bDeviceClass);		return -ENODEV;	}	/* claim all interfaces */	for (i=0; i < num_interfaces; i++) {		cur_intf = usb_ifnum_to_if(usb_dev, i);		if ((i != ifnum) && cur_intf) {			ret = usb_driver_claim_interface(&speedtch_usb_driver, cur_intf, usbatm);			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;			}		}	}	instance = kmalloc(sizeof(*instance), GFP_KERNEL);	if (!instance) {		usb_dbg(usbatm, "%s: no memory for instance data!\n", __func__);		ret = -ENOMEM;		goto fail_release;	}	memset(instance, 0, sizeof(struct speedtch_instance_data));	instance->usbatm = usbatm;	INIT_WORK(&instance->status_checker, (void *)speedtch_check_status, instance);	instance->status_checker.timer.function = speedtch_status_poll;	instance->status_checker.timer.data = (unsigned long)instance;	instance->last_status = 0xff;	instance->poll_delay = MIN_POLL_DELAY;	init_timer(&instance->resubmit_timer);	instance->resubmit_timer.function = speedtch_resubmit_int;	instance->resubmit_timer.data = (unsigned long)instance;	instance->int_urb = usb_alloc_urb(0, GFP_KERNEL);	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__);	/* 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);	*need_heavy_init = (ret != SIZE_7);	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;        usbatm->driver_data = instance;	return 0;fail_free:	usb_free_urb(instance->int_urb);	kfree(instance);fail_release:	speedtch_release_interfaces(usb_dev, num_interfaces);	return ret;}static void speedtch_unbind(struct usbatm_data *usbatm, struct usb_interface *intf){	struct usb_device *usb_dev = interface_to_usbdev(intf);	struct speedtch_instance_data *instance = usbatm->driver_data;	usb_dbg(usbatm, "%s entered\n", __func__);	speedtch_release_interfaces(usb_dev, usb_dev->actconfig->desc.bNumInterfaces);	usb_free_urb(instance->int_urb);	kfree(instance);}/*************  init  *************/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);}static int __init speedtch_usb_init(void){	dbg("%s: driver version %s", __func__, DRIVER_VERSION);	return usb_register(&speedtch_usb_driver);}static void __exit speedtch_usb_cleanup(void){	dbg("%s", __func__);	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);

⌨️ 快捷键说明

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