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

📄 speedtch.c

📁 h内核
💻 C
📖 第 1 页 / 共 2 页
字号:
		break;	default:		if (instance->u.atm_dev->signal != ATM_PHY_SIG_UNKNOWN) {			instance->u.atm_dev->signal = ATM_PHY_SIG_UNKNOWN;			printk(KERN_NOTICE "Unknown line state %02x\n", buf[OFFSET_7]);		}		break;	}}static void speedtch_timer_poll(unsigned long data){	struct speedtch_instance_data *instance = (void *)data;	schedule_work(&instance->poll_work);	mod_timer(&instance->poll_timer, jiffies + (5 * HZ));}#ifdef USE_FW_LOADERstatic void speedtch_upload_firmware(struct speedtch_instance_data *instance,				     const struct firmware *fw1,				     const struct firmware *fw2){	unsigned char *buffer;	struct usb_device *usb_dev = instance->u.usb_dev;	struct usb_interface *intf;	int actual_length, ret;	int offset;	dbg("speedtch_upload_firmware");	if (!(intf = usb_ifnum_to_if(usb_dev, 2))) {		dbg("speedtch_upload_firmware: interface not found!");		goto fail;	}	if (!(buffer = (unsigned char *)__get_free_page(GFP_KERNEL))) {		dbg("speedtch_upload_firmware: no memory for buffer!");		goto fail;	}	/* A user-space firmware loader may already have claimed interface #2 */	if ((ret =	     usb_driver_claim_interface(&speedtch_usb_driver, intf, NULL)) < 0) {		dbg("speedtch_upload_firmware: interface in use (%d)!", ret);		goto fail_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, SPEEDTCH_ENDPOINT_FIRMWARE),				   buffer, 0x200, &actual_length, 2 * HZ);		if (ret < 0 && ret != -ETIMEDOUT)			dbg("speedtch_upload_firmware: read BLOCK0 from modem failed (%d)!", ret);		else			dbg("speedtch_upload_firmware: BLOCK0 downloaded (%d bytes)", 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, SPEEDTCH_ENDPOINT_FIRMWARE),				   buffer, thislen, &actual_length, DATA_TIMEOUT);		if (ret < 0) {			dbg("speedtch_upload_firmware: write BLOCK1 to modem failed (%d)!", ret);			goto fail_release;		}		dbg("speedtch_upload_firmware: BLOCK1 uploaded (%zu bytes)", fw1->size);	}	/* USB led blinking green, ADSL led off */	/* URB 11 */	ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE),			   buffer, 0x200, &actual_length, DATA_TIMEOUT);	if (ret < 0) {		dbg("speedtch_upload_firmware: read BLOCK2 from modem failed (%d)!", ret);		goto fail_release;	}	dbg("speedtch_upload_firmware: BLOCK2 downloaded (%d bytes)", 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, SPEEDTCH_ENDPOINT_FIRMWARE),				   buffer, thislen, &actual_length, DATA_TIMEOUT);		if (ret < 0) {			dbg("speedtch_upload_firmware: write BLOCK3 to modem failed (%d)!", ret);			goto fail_release;		}	}	dbg("speedtch_upload_firmware: BLOCK3 uploaded (%zu bytes)", fw2->size);	/* USB led static green, ADSL led static red */	/* URB 142 */	ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE),			   buffer, 0x200, &actual_length, DATA_TIMEOUT);	if (ret < 0) {		dbg("speedtch_upload_firmware: read BLOCK4 from modem failed (%d)!", ret);		goto fail_release;	}	/* success */	dbg("speedtch_upload_firmware: BLOCK4 downloaded (%d bytes)", actual_length);	/* Delay to allow firmware to start up. We can do this here	   because we're in our own kernel thread anyway. */	msleep(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);	/* Start modem synchronisation */	if (speedtch_start_synchro(instance))		dbg("speedtch_start_synchro: failed");	speedtch_got_firmware(instance, 1);	free_page((unsigned long)buffer);	return; fail_release:	/* Only release interface #2 if uploading failed; we don't release it	   we succeeded.  This prevents the userspace tools from trying to load	   the firmware themselves */	usb_driver_release_interface(&speedtch_usb_driver, intf); fail_free:	free_page((unsigned long)buffer); fail:	speedtch_got_firmware(instance, 0);}static int speedtch_find_firmware(struct speedtch_instance_data				  *instance, int phase,				  const struct firmware **fw_p){	char buf[24];	const u16 bcdDevice = le16_to_cpu(instance->u.usb_dev->descriptor.bcdDevice);	const u8 major_revision = bcdDevice >> 8;	const u8 minor_revision = bcdDevice & 0xff;	sprintf(buf, "speedtch-%d.bin.%x.%02x", phase, major_revision, minor_revision);	dbg("speedtch_find_firmware: looking for %s", buf);	if (request_firmware(fw_p, buf, &instance->u.usb_dev->dev)) {		sprintf(buf, "speedtch-%d.bin.%x", phase, major_revision);		dbg("speedtch_find_firmware: looking for %s", buf);		if (request_firmware(fw_p, buf, &instance->u.usb_dev->dev)) {			sprintf(buf, "speedtch-%d.bin", phase);			dbg("speedtch_find_firmware: looking for %s", buf);			if (request_firmware(fw_p, buf, &instance->u.usb_dev->dev)) {				dev_warn(&instance->u.usb_dev->dev, "no stage %d firmware found!", phase);				return -ENOENT;			}		}	}	dev_info(&instance->u.usb_dev->dev, "found stage %d firmware %s\n", phase, buf);	return 0;}static int speedtch_load_firmware(void *arg){	const struct firmware *fw1, *fw2;	struct speedtch_instance_data *instance = arg;	BUG_ON(!instance);	daemonize("firmware/speedtch");	if (!speedtch_find_firmware(instance, 1, &fw1)) {		if (!speedtch_find_firmware(instance, 2, &fw2)) {			speedtch_upload_firmware(instance, fw1, fw2);			release_firmware(fw2);		}		release_firmware(fw1);	}	/* In case we failed, set state back to NO_FIRMWARE so that	   another later attempt may work. Otherwise, we never actually	   manage to recover if, for example, the firmware is on /usr and	   we look for it too early. */	speedtch_got_firmware(instance, 0);	module_put(THIS_MODULE);	udsl_put_instance(&instance->u);	return 0;}#endif /* USE_FW_LOADER */static void speedtch_firmware_start(struct speedtch_instance_data *instance){#ifdef USE_FW_LOADER	int ret;#endif	dbg("speedtch_firmware_start");	down(&instance->u.serialize);	/* vs self, speedtch_got_firmware */	if (instance->u.status >= UDSL_LOADING_FIRMWARE) {		up(&instance->u.serialize);		return;	}	instance->u.status = UDSL_LOADING_FIRMWARE;	up(&instance->u.serialize);#ifdef USE_FW_LOADER	udsl_get_instance(&instance->u);	try_module_get(THIS_MODULE);	ret = kernel_thread(speedtch_load_firmware, instance,			    CLONE_FS | CLONE_FILES);	if (ret >= 0)		return;		/* OK */	dbg("speedtch_firmware_start: kernel_thread failed (%d)!", ret);	module_put(THIS_MODULE);	udsl_put_instance(&instance->u);	/* Just pretend it never happened... hope modem_run happens */#endif				/* USE_FW_LOADER */	speedtch_got_firmware(instance, 0);}static int speedtch_firmware_wait(struct udsl_instance_data *instance){	speedtch_firmware_start((void *)instance);	if (wait_event_interruptible(instance->firmware_waiters, instance->status != UDSL_LOADING_FIRMWARE) < 0)		return -ERESTARTSYS;	return (instance->status == UDSL_LOADED_FIRMWARE) ? 0 : -EAGAIN;}/************  USB  ************/static int speedtch_usb_ioctl(struct usb_interface *intf, unsigned int code,			      void *user_data){	struct speedtch_instance_data *instance = usb_get_intfdata(intf);	dbg("speedtch_usb_ioctl entered");	if (!instance) {		dbg("speedtch_usb_ioctl: NULL instance!");		return -ENODEV;	}	switch (code) {	case UDSL_IOCTL_LINE_UP:		instance->u.atm_dev->signal = ATM_PHY_SIG_FOUND;		speedtch_got_firmware(instance, 1);		return (instance->u.status == UDSL_LOADED_FIRMWARE) ? 0 : -EIO;	case UDSL_IOCTL_LINE_DOWN:		instance->u.atm_dev->signal = ATM_PHY_SIG_LOST;		return 0;	default:		return -ENOTTY;	}}static int speedtch_usb_probe(struct usb_interface *intf,			      const struct usb_device_id *id){	struct usb_device *dev = interface_to_usbdev(intf);	int ifnum = intf->altsetting->desc.bInterfaceNumber;	struct speedtch_instance_data *instance;	unsigned char mac_str[13];	int ret, i;	char buf7[SIZE_7];	dbg("speedtch_usb_probe: trying device with vendor=0x%x, product=0x%x, ifnum %d",	    le16_to_cpu(dev->descriptor.idVendor),	    le16_to_cpu(dev->descriptor.idProduct), ifnum);	if ((dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) || 	    (ifnum != 1))		return -ENODEV;	dbg("speedtch_usb_probe: device accepted");	/* instance init */	instance = kmalloc(sizeof(*instance), GFP_KERNEL);	if (!instance) {		dbg("speedtch_usb_probe: no memory for instance data!");		return -ENOMEM;	}	memset(instance, 0, sizeof(struct speedtch_instance_data));	if ((ret = usb_set_interface(dev, 0, 0)) < 0)		goto fail;	if ((ret = usb_set_interface(dev, 2, 0)) < 0)		goto fail;	instance->u.data_endpoint = SPEEDTCH_ENDPOINT_DATA;	instance->u.firmware_wait = speedtch_firmware_wait;	instance->u.driver_name = speedtch_driver_name;	ret = udsl_instance_setup(dev, &instance->u);	if (ret)		goto fail;	init_timer(&instance->poll_timer);	instance->poll_timer.function = speedtch_timer_poll;	instance->poll_timer.data = (unsigned long)instance;	INIT_WORK(&instance->poll_work, (void *)speedtch_poll_status, instance);	/* set MAC address, it is stored in the serial number */	memset(instance->u.atm_dev->esi, 0, sizeof(instance->u.atm_dev->esi));	if (usb_string(dev, dev->descriptor.iSerialNumber, mac_str, sizeof(mac_str)) == 12) {		for (i = 0; i < 6; i++)			instance->u.atm_dev->esi[i] =				(hex2int(mac_str[i * 2]) * 16) + (hex2int(mac_str[i * 2 + 1]));	}	/* First check whether the modem already seems to be alive */	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),			      0x12, 0xc0, 0x07, 0x00, buf7, SIZE_7, HZ / 2);	if (ret == SIZE_7) {		dbg("firmware appears to be already loaded");		speedtch_got_firmware(instance, 1);		speedtch_poll_status(instance);	} else {		speedtch_firmware_start(instance);	}	usb_set_intfdata(intf, instance);	return 0; fail:	kfree(instance);	return -ENOMEM;}static void speedtch_usb_disconnect(struct usb_interface *intf){	struct speedtch_instance_data *instance = usb_get_intfdata(intf);	dbg("speedtch_usb_disconnect entered");	if (!instance) {		dbg("speedtch_usb_disconnect: NULL instance!");		return;	}/*QQ need to handle disconnects on interface #2 while uploading firmware *//*QQ and what about interface #1? */	if (instance->int_urb) {		struct urb *int_urb = instance->int_urb;		instance->int_urb = NULL;		wmb();		usb_unlink_urb(int_urb);		usb_free_urb(int_urb);	}	instance->int_data[0] = 1;	del_timer_sync(&instance->poll_timer);	wmb();	flush_scheduled_work();	udsl_instance_disconnect(&instance->u);	/* clean up */	usb_set_intfdata(intf, NULL);	udsl_put_instance(&instance->u);}/*************  init  *************/static int __init speedtch_usb_init(void){	dbg("speedtch_usb_init: driver version " DRIVER_VERSION);	return usb_register(&speedtch_usb_driver);}static void __exit speedtch_usb_cleanup(void){	dbg("speedtch_usb_cleanup entered");	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 + -