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

📄 speedtch.c

📁 usb driver for 2.6.17
💻 C
📖 第 1 页 / 共 2 页
字号:
#ifdef VERBOSE_DEBUG	atm_dbg(usbatm, "%s entered\n", __func__);#endif	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];	if ((status != instance->last_status) || !status) {		atm_dbg(usbatm, "%s: line state 0x%02x\n", __func__, 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" */	static const unsigned char up_int[6]   = { 0xa1, 0x00, 0x01, 0x00, 0x00, 0x00 };	/* The magic interrupt for "down state" */	static const 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__);	/* 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 = {	.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){	struct usb_device *usb_dev = interface_to_usbdev(intf);	struct usb_interface *cur_intf, *data_intf;	struct speedtch_instance_data *instance;	int ifnum = intf->altsetting->desc.bInterfaceNumber;	int num_interfaces = usb_dev->actconfig->desc.bNumInterfaces;	int i, ret;	int use_isoc;	usb_dbg(usbatm, "%s entered\n", __func__);	/* sanity checks */	if (usb_dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) {		usb_err(usbatm, "%s: wrong device class %d\n", __func__, usb_dev->descriptor.bDeviceClass);		return -ENODEV;	}	if (!(data_intf = usb_ifnum_to_if(usb_dev, INTERFACE_DATA))) {		usb_err(usbatm, "%s: data interface not found!\n", __func__);		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_err(usbatm, "%s: failed to claim interface %2d (%d)!\n", __func__, i, ret);				speedtch_release_interfaces(usb_dev, i);				return ret;			}		}	}	instance = kzalloc(sizeof(*instance), GFP_KERNEL);	if (!instance) {		usb_err(usbatm, "%s: no memory for instance data!\n", __func__);		ret = -ENOMEM;		goto fail_release;	}	instance->usbatm = usbatm;	/* altsetting and enable_isoc may change at any moment, so take a snapshot */	instance->altsetting = altsetting;	use_isoc = enable_isoc;	if (instance->altsetting)		if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->altsetting)) < 0) {			usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, instance->altsetting, ret);			instance->altsetting = 0; /* fall back to default */		}	if (!instance->altsetting && use_isoc)		if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_ISOC_ALTSETTING)) < 0) {			usb_dbg(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_ISOC_ALTSETTING, ret);			use_isoc = 0; /* fall back to bulk */		}	if (use_isoc) {		const struct usb_host_interface *desc = data_intf->cur_altsetting;		const __u8 target_address = USB_DIR_IN | usbatm->driver->isoc_in;		int i;		use_isoc = 0; /* fall back to bulk if endpoint not found */		for (i=0; i<desc->desc.bNumEndpoints; i++) {			const struct usb_endpoint_descriptor *endpoint_desc = &desc->endpoint[i].desc;			if ((endpoint_desc->bEndpointAddress == target_address)) {				use_isoc = (endpoint_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==					USB_ENDPOINT_XFER_ISOC;				break;			}		}		if (!use_isoc)			usb_info(usbatm, "isochronous transfer not supported - using bulk\n");	}	if (!use_isoc && !instance->altsetting)		if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_BULK_ALTSETTING)) < 0) {			usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_BULK_ALTSETTING, ret);			goto fail_free;		}	if (!instance->altsetting)		instance->altsetting = use_isoc ? DEFAULT_ISOC_ALTSETTING : DEFAULT_BULK_ALTSETTING;	usbatm->flags |= (use_isoc ? UDSL_USE_ISOC : 0);	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);	usbatm->flags |= (ret == SIZE_7 ? UDSL_SKIP_HEAVY_INIT : 0);	usb_dbg(usbatm, "%s: firmware %s loaded\n", __func__, usbatm->flags & UDSL_SKIP_HEAVY_INIT ? "already" : "not");	if (!(usbatm->flags & UDSL_SKIP_HEAVY_INIT))		if ((ret = usb_reset_device(usb_dev)) < 0) {			usb_err(usbatm, "%s: device reset failed (%d)!\n", __func__, ret);			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 = {	.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,	.bulk_in	= ENDPOINT_BULK_DATA,	.bulk_out	= ENDPOINT_BULK_DATA,	.isoc_in	= ENDPOINT_ISOC_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 + -