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

📄 uhci-hcd.c

📁 h内核
💻 C
📖 第 1 页 / 共 5 页
字号:
		uhci->td_pool = NULL;	}	if (uhci->fl) {		dma_free_coherent(uhci_dev(uhci), sizeof(*uhci->fl),				uhci->fl, uhci->fl->dma_handle);		uhci->fl = NULL;	}	if (uhci->dentry) {		debugfs_remove(uhci->dentry);		uhci->dentry = NULL;	}}static int uhci_reset(struct usb_hcd *hcd){	struct uhci_hcd *uhci = hcd_to_uhci(hcd);	uhci->io_addr = (unsigned long) hcd->regs;	/* Kick BIOS off this hardware and reset, so we won't get	 * interrupts from any previous setup.	 */	reset_hc(uhci);	return 0;}/* * Allocate a frame list, and then setup the skeleton * * The hardware doesn't really know any difference * in the queues, but the order does matter for the * protocols higher up. The order is: * *  - any isochronous events handled before any *    of the queues. We don't do that here, because *    we'll create the actual TD entries on demand. *  - The first queue is the interrupt queue. *  - The second queue is the control queue, split into low- and full-speed *  - The third queue is bulk queue. *  - The fourth queue is the bandwidth reclamation queue, which loops back *    to the full-speed control queue. */static int uhci_start(struct usb_hcd *hcd){	struct uhci_hcd *uhci = hcd_to_uhci(hcd);	int retval = -EBUSY;	int i, port;	unsigned io_size;	dma_addr_t dma_handle;	struct usb_device *udev;	struct dentry *dentry;	io_size = pci_resource_len(to_pci_dev(uhci_dev(uhci)), hcd->region);	dentry = debugfs_create_file(hcd->self.bus_name, S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, uhci, &uhci_debug_operations);	if (!dentry) {		dev_err(uhci_dev(uhci), "couldn't create uhci debugfs entry\n");		retval = -ENOMEM;		goto err_create_debug_entry;	}	uhci->dentry = dentry;	uhci->fsbr = 0;	uhci->fsbrtimeout = 0;	spin_lock_init(&uhci->schedule_lock);	INIT_LIST_HEAD(&uhci->qh_remove_list);	INIT_LIST_HEAD(&uhci->td_remove_list);	INIT_LIST_HEAD(&uhci->urb_remove_list);	INIT_LIST_HEAD(&uhci->urb_list);	INIT_LIST_HEAD(&uhci->complete_list);	init_waitqueue_head(&uhci->waitqh);	uhci->fl = dma_alloc_coherent(uhci_dev(uhci), sizeof(*uhci->fl),			&dma_handle, 0);	if (!uhci->fl) {		dev_err(uhci_dev(uhci), "unable to allocate "				"consistent memory for frame list\n");		goto err_alloc_fl;	}	memset((void *)uhci->fl, 0, sizeof(*uhci->fl));	uhci->fl->dma_handle = dma_handle;	uhci->td_pool = dma_pool_create("uhci_td", uhci_dev(uhci),			sizeof(struct uhci_td), 16, 0);	if (!uhci->td_pool) {		dev_err(uhci_dev(uhci), "unable to create td dma_pool\n");		goto err_create_td_pool;	}	uhci->qh_pool = dma_pool_create("uhci_qh", uhci_dev(uhci),			sizeof(struct uhci_qh), 16, 0);	if (!uhci->qh_pool) {		dev_err(uhci_dev(uhci), "unable to create qh dma_pool\n");		goto err_create_qh_pool;	}	/* Initialize the root hub */	/* UHCI specs says devices must have 2 ports, but goes on to say */	/*  they may have more but give no way to determine how many they */	/*  have. However, according to the UHCI spec, Bit 7 is always set */	/*  to 1. So we try to use this to our advantage */	for (port = 0; port < (io_size - 0x10) / 2; port++) {		unsigned int portstatus;		portstatus = inw(uhci->io_addr + 0x10 + (port * 2));		if (!(portstatus & 0x0080))			break;	}	if (debug)		dev_info(uhci_dev(uhci), "detected %d ports\n", port);	/* This is experimental so anything less than 2 or greater than 8 is */	/*  something weird and we'll ignore it */	if (port < 2 || port > UHCI_RH_MAXCHILD) {		dev_info(uhci_dev(uhci), "port count misdetected? "				"forcing to 2 ports\n");		port = 2;	}	uhci->rh_numports = port;	udev = usb_alloc_dev(NULL, &hcd->self, 0);	if (!udev) {		dev_err(uhci_dev(uhci), "unable to allocate root hub\n");		goto err_alloc_root_hub;	}	uhci->term_td = uhci_alloc_td(uhci, udev);	if (!uhci->term_td) {		dev_err(uhci_dev(uhci), "unable to allocate terminating TD\n");		goto err_alloc_term_td;	}	for (i = 0; i < UHCI_NUM_SKELQH; i++) {		uhci->skelqh[i] = uhci_alloc_qh(uhci, udev);		if (!uhci->skelqh[i]) {			dev_err(uhci_dev(uhci), "unable to allocate QH\n");			goto err_alloc_skelqh;		}	}	/*	 * 8 Interrupt queues; link all higher int queues to int1,	 * then link int1 to control and control to bulk	 */	uhci->skel_int128_qh->link =			uhci->skel_int64_qh->link =			uhci->skel_int32_qh->link =			uhci->skel_int16_qh->link =			uhci->skel_int8_qh->link =			uhci->skel_int4_qh->link =			uhci->skel_int2_qh->link =			cpu_to_le32(uhci->skel_int1_qh->dma_handle) | UHCI_PTR_QH;	uhci->skel_int1_qh->link = cpu_to_le32(uhci->skel_ls_control_qh->dma_handle) | UHCI_PTR_QH;	uhci->skel_ls_control_qh->link = cpu_to_le32(uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH;	uhci->skel_fs_control_qh->link = cpu_to_le32(uhci->skel_bulk_qh->dma_handle) | UHCI_PTR_QH;	uhci->skel_bulk_qh->link = cpu_to_le32(uhci->skel_term_qh->dma_handle) | UHCI_PTR_QH;	/* This dummy TD is to work around a bug in Intel PIIX controllers */	uhci_fill_td(uhci->term_td, 0, (UHCI_NULL_DATA_SIZE << 21) |		(0x7f << TD_TOKEN_DEVADDR_SHIFT) | USB_PID_IN, 0);	uhci->term_td->link = cpu_to_le32(uhci->term_td->dma_handle);	uhci->skel_term_qh->link = UHCI_PTR_TERM;	uhci->skel_term_qh->element = cpu_to_le32(uhci->term_td->dma_handle);	/*	 * Fill the frame list: make all entries point to the proper	 * interrupt queue.	 *	 * The interrupt queues will be interleaved as evenly as possible.	 * There's not much to be done about period-1 interrupts; they have	 * to occur in every frame.  But we can schedule period-2 interrupts	 * in odd-numbered frames, period-4 interrupts in frames congruent	 * to 2 (mod 4), and so on.  This way each frame only has two	 * interrupt QHs, which will help spread out bandwidth utilization.	 */	for (i = 0; i < UHCI_NUMFRAMES; i++) {		int irq;		/*		 * ffs (Find First bit Set) does exactly what we need:		 * 1,3,5,...  => ffs = 0 => use skel_int2_qh = skelqh[6],		 * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[5], etc.		 * ffs > 6 => not on any high-period queue, so use		 *	skel_int1_qh = skelqh[7].		 * Add UHCI_NUMFRAMES to insure at least one bit is set.		 */		irq = 6 - (int) __ffs(i + UHCI_NUMFRAMES);		if (irq < 0)			irq = 7;		/* Only place we don't use the frame list routines */		uhci->fl->frame[i] = UHCI_PTR_QH |				cpu_to_le32(uhci->skelqh[irq]->dma_handle);	}	/*	 * Some architectures require a full mb() to enforce completion of	 * the memory writes above before the I/O transfers in start_hc().	 */	mb();	if ((retval = start_hc(uhci)) != 0)		goto err_alloc_skelqh;	init_stall_timer(hcd);	udev->speed = USB_SPEED_FULL;	if (hcd_register_root(udev, hcd) != 0) {		dev_err(uhci_dev(uhci), "unable to start root hub\n");		retval = -ENOMEM;		goto err_start_root_hub;	}	return 0;/* * error exits: */err_start_root_hub:	reset_hc(uhci);	del_timer_sync(&uhci->stall_timer);err_alloc_skelqh:	for (i = 0; i < UHCI_NUM_SKELQH; i++)		if (uhci->skelqh[i]) {			uhci_free_qh(uhci, uhci->skelqh[i]);			uhci->skelqh[i] = NULL;		}	uhci_free_td(uhci, uhci->term_td);	uhci->term_td = NULL;err_alloc_term_td:	usb_put_dev(udev);err_alloc_root_hub:	dma_pool_destroy(uhci->qh_pool);	uhci->qh_pool = NULL;err_create_qh_pool:	dma_pool_destroy(uhci->td_pool);	uhci->td_pool = NULL;err_create_td_pool:	dma_free_coherent(uhci_dev(uhci), sizeof(*uhci->fl),			uhci->fl, uhci->fl->dma_handle);	uhci->fl = NULL;err_alloc_fl:	debugfs_remove(uhci->dentry);	uhci->dentry = NULL;err_create_debug_entry:	return retval;}static void uhci_stop(struct usb_hcd *hcd){	struct uhci_hcd *uhci = hcd_to_uhci(hcd);	del_timer_sync(&uhci->stall_timer);	/*	 * At this point, we're guaranteed that no new connects can be made	 * to this bus since there are no more parents	 */	reset_hc(uhci);	spin_lock_irq(&uhci->schedule_lock);	uhci_free_pending_qhs(uhci);	uhci_free_pending_tds(uhci);	uhci_remove_pending_urbps(uhci);	uhci_finish_completion(hcd, NULL);	uhci_free_pending_qhs(uhci);	uhci_free_pending_tds(uhci);	spin_unlock_irq(&uhci->schedule_lock);	/* Wake up anyone waiting for an URB to complete */	wake_up_all(&uhci->waitqh);		release_uhci(uhci);}#ifdef CONFIG_PMstatic int uhci_suspend(struct usb_hcd *hcd, u32 state){	struct uhci_hcd *uhci = hcd_to_uhci(hcd);	/* Don't try to suspend broken motherboards, reset instead */	if (suspend_allowed(uhci)) {		suspend_hc(uhci);		uhci->saved_framenumber =				inw(uhci->io_addr + USBFRNUM) & 0x3ff;	} else		reset_hc(uhci);	return 0;}static int uhci_resume(struct usb_hcd *hcd){	struct uhci_hcd *uhci = hcd_to_uhci(hcd);	int rc;	pci_set_master(to_pci_dev(uhci_dev(uhci)));	if (uhci->state == UHCI_SUSPENDED) {		/*		 * Some systems don't maintain the UHCI register values		 * during a PM suspend/resume cycle, so reinitialize		 * the Frame Number, Framelist Base Address, Interrupt		 * Enable, and Legacy Support registers.		 */		pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,				0);		outw(uhci->saved_framenumber, uhci->io_addr + USBFRNUM);		outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD);		outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC |				USBINTR_SP, uhci->io_addr + USBINTR);		uhci->resume_detect = 1;		pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,				USBLEGSUP_DEFAULT);	} else {		reset_hc(uhci);		if ((rc = start_hc(uhci)) != 0)			return rc;	}	hcd->state = USB_STATE_RUNNING;	return 0;}#endif/* Wait until all the URBs for a particular device/endpoint are gone */static void uhci_hcd_endpoint_disable(struct usb_hcd *hcd,		struct usb_host_endpoint *ep){	struct uhci_hcd *uhci = hcd_to_uhci(hcd);	wait_event_interruptible(uhci->waitqh, list_empty(&ep->urb_list));}static int uhci_hcd_get_frame_number(struct usb_hcd *hcd){	return uhci_get_current_frame_number(hcd_to_uhci(hcd));}static const char hcd_name[] = "uhci_hcd";static const struct hc_driver uhci_driver = {	.description =		hcd_name,	.product_desc =		"UHCI Host Controller",	.hcd_priv_size =	sizeof(struct uhci_hcd),	/* Generic hardware linkage */	.irq =			uhci_irq,	.flags =		HCD_USB11,	/* Basic lifecycle operations */	.reset =		uhci_reset,	.start =		uhci_start,#ifdef CONFIG_PM	.suspend =		uhci_suspend,	.resume =		uhci_resume,#endif	.stop =			uhci_stop,	.urb_enqueue =		uhci_urb_enqueue,	.urb_dequeue =		uhci_urb_dequeue,	.endpoint_disable =	uhci_hcd_endpoint_disable,	.get_frame_number =	uhci_hcd_get_frame_number,	.hub_status_data =	uhci_hub_status_data,	.hub_control =		uhci_hub_control,};static const struct pci_device_id uhci_pci_ids[] = { {	/* handle any USB UHCI controller */	PCI_DEVICE_CLASS(((PCI_CLASS_SERIAL_USB << 8) | 0x00), ~0),	.driver_data =	(unsigned long) &uhci_driver,	}, { /* end: all zeroes */ }};MODULE_DEVICE_TABLE(pci, uhci_pci_ids);static struct pci_driver uhci_pci_driver = {	.name =		(char *)hcd_name,	.id_table =	uhci_pci_ids,	.probe =	usb_hcd_pci_probe,	.remove =	usb_hcd_pci_remove,#ifdef	CONFIG_PM	.suspend =	usb_hcd_pci_suspend,	.resume =	usb_hcd_pci_resume,#endif	/* PM */}; static int __init uhci_hcd_init(void){	int retval = -ENOMEM;	printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION "\n");	if (usb_disabled())		return -ENODEV;	if (debug) {		errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);		if (!errbuf)			goto errbuf_failed;	}	uhci_debugfs_root = debugfs_create_dir("uhci", NULL);	if (!uhci_debugfs_root)		goto debug_failed;	uhci_up_cachep = kmem_cache_create("uhci_urb_priv",		sizeof(struct urb_priv), 0, 0, NULL, NULL);	if (!uhci_up_cachep)		goto up_failed;	retval = pci_register_driver(&uhci_pci_driver);	if (retval)		goto init_failed;	return 0;init_failed:	if (kmem_cache_destroy(uhci_up_cachep))		warn("not all urb_priv's were freed!");up_failed:	debugfs_remove(uhci_debugfs_root);debug_failed:	if (errbuf)		kfree(errbuf);errbuf_failed:	return retval;}static void __exit uhci_hcd_cleanup(void) {	pci_unregister_driver(&uhci_pci_driver);		if (kmem_cache_destroy(uhci_up_cachep))		warn("not all urb_priv's were freed!");	debugfs_remove(uhci_debugfs_root);	if (errbuf)		kfree(errbuf);}module_init(uhci_hcd_init);module_exit(uhci_hcd_cleanup);MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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