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

📄 uhci.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 4 页
字号:
	tmp = head->next;	while (tmp != head) {		u = list_entry(tmp, struct urb, urb_list);		tmp = tmp->next;		if (u->dev == urb->dev &&		    u->pipe == urb->pipe)			goto found;	}	u = NULL;found:	nested_unlock(&uhci->urblist_lock, flags);	return u;}static int uhci_submit_urb(struct urb *urb){	int ret = -EINVAL;	struct uhci *uhci;	unsigned long flags;	struct urb *u;	int bustime;	if (!urb)		return -EINVAL;	if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv)		return -ENODEV;	uhci = (struct uhci *)urb->dev->bus->hcpriv;	/* Short circuit the virtual root hub */	if (usb_pipedevice(urb->pipe) == uhci->rh.devnum)		return rh_submit_urb(urb);	u = uhci_find_urb_ep(uhci, urb);	if (u && !(urb->transfer_flags & USB_QUEUE_BULK))		return -ENXIO;	usb_inc_dev_use(urb->dev);	spin_lock_irqsave(&urb->lock, flags);	if (!uhci_alloc_urb_priv(urb)) {		spin_unlock_irqrestore(&urb->lock, flags);		usb_dec_dev_use(urb->dev);		return -ENOMEM;	}	switch (usb_pipetype(urb->pipe)) {	case PIPE_CONTROL:		ret = uhci_submit_control(urb);		break;	case PIPE_INTERRUPT:		if (urb->bandwidth == 0) {	/* not yet checked/allocated */			bustime = usb_check_bandwidth(urb->dev, urb);			if (bustime < 0)				ret = bustime;			else {				ret = uhci_submit_interrupt(urb);				if (ret == -EINPROGRESS)					usb_claim_bandwidth(urb->dev, urb, bustime, 0);			}		} else		/* bandwidth is already set */			ret = uhci_submit_interrupt(urb);		break;	case PIPE_BULK:		ret = uhci_submit_bulk(urb, u);		break;	case PIPE_ISOCHRONOUS:		if (urb->bandwidth == 0) {	/* not yet checked/allocated */			if (urb->number_of_packets <= 0) {				ret = -EINVAL;				break;			}			bustime = usb_check_bandwidth(urb->dev, urb);			if (bustime < 0) {				ret = bustime;				break;			}			ret = uhci_submit_isochronous(urb);			if (ret == -EINPROGRESS)				usb_claim_bandwidth(urb->dev, urb, bustime, 1);		} else		/* bandwidth is already set */			ret = uhci_submit_isochronous(urb);		break;	}	urb->status = ret;	spin_unlock_irqrestore(&urb->lock, flags);	if (ret == -EINPROGRESS)		ret = 0;	else {		uhci_unlink_generic(urb);		usb_dec_dev_use(urb->dev);	}	return ret;}/* * Return the result of a transfer * * Must be called with urblist_lock acquired */static void uhci_transfer_result(struct urb *urb){	struct usb_device *dev = urb->dev;	struct urb *turb;	int proceed = 0, is_ring = 0;	int ret = -EINVAL;	unsigned long flags;	spin_lock_irqsave(&urb->lock, flags);	switch (usb_pipetype(urb->pipe)) {	case PIPE_CONTROL:		ret = uhci_result_control(urb);		break;	case PIPE_INTERRUPT:		ret = uhci_result_interrupt(urb);		break;	case PIPE_BULK:		ret = uhci_result_bulk(urb);		break;	case PIPE_ISOCHRONOUS:		ret = uhci_result_isochronous(urb);		break;	}	urb->status = ret;	spin_unlock_irqrestore(&urb->lock, flags);	if (ret == -EINPROGRESS)		return;	switch (usb_pipetype(urb->pipe)) {	case PIPE_CONTROL:	case PIPE_BULK:	case PIPE_ISOCHRONOUS:		/* Release bandwidth for Interrupt or Isoc. transfers */		/* Spinlock needed ? */		if (urb->bandwidth)			usb_release_bandwidth(urb->dev, urb, 1);		uhci_unlink_generic(urb);		break;	case PIPE_INTERRUPT:		/* Interrupts are an exception */		if (urb->interval) {			urb->complete(urb);			uhci_reset_interrupt(urb);			return;		}		/* Release bandwidth for Interrupt or Isoc. transfers */		/* Spinlock needed ? */		if (urb->bandwidth)			usb_release_bandwidth(urb->dev, urb, 0);		uhci_unlink_generic(urb);		break;	}	if (urb->next) {		turb = urb->next;		do {			if (turb->status != -EINPROGRESS) {				proceed = 1;				break;			}			turb = turb->next;		} while (turb && turb != urb && turb != urb->next);		if (turb == urb || turb == urb->next)			is_ring = 1;	}	if (urb->complete && !proceed) {		urb->complete(urb);		if (!proceed && is_ring)			uhci_submit_urb(urb);	}	if (proceed && urb->next) {		turb = urb->next;		do {			if (turb->status != -EINPROGRESS &&			    uhci_submit_urb(turb) != 0)			turb = turb->next;		} while (turb && turb != urb->next);		if (urb->complete)			urb->complete(urb);	}	/* We decrement the usage count after we're done with everything */	usb_dec_dev_use(dev);}static int uhci_unlink_generic(struct urb *urb){	struct urb_priv *urbp = urb->hcpriv;	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;	if (!urbp)		return -EINVAL;	uhci_dec_fsbr(uhci, urb);	/* Safe since it checks */	uhci_remove_urb_list(uhci, urb);	if (urbp->qh)		/* The interrupt loop will reclaim the QH's */		uhci_remove_qh(uhci, urbp->qh);	if (!list_empty(&urbp->urb_queue_list))		uhci_delete_queued_urb(uhci, urb);	uhci_destroy_urb_priv(urb);	urb->dev = NULL;	return 0;}static int uhci_unlink_urb(struct urb *urb){	struct uhci *uhci;	int ret = 0;	unsigned long flags;	if (!urb)		return -EINVAL;	if (!urb->dev || !urb->dev->bus)		return -ENODEV;	uhci = (struct uhci *)urb->dev->bus->hcpriv;	/* Short circuit the virtual root hub */	if (usb_pipedevice(urb->pipe) == uhci->rh.devnum)		return rh_unlink_urb(urb);	/* Release bandwidth for Interrupt or Isoc. transfers */	/* Spinlock needed ? */	if (urb->bandwidth) {		switch (usb_pipetype(urb->pipe)) {		case PIPE_INTERRUPT:			usb_release_bandwidth(urb->dev, urb, 0);			break;		case PIPE_ISOCHRONOUS:			usb_release_bandwidth(urb->dev, urb, 1);			break;		default:			break;		}	}	if (urb->status == -EINPROGRESS) {		uhci_unlink_generic(urb);		if (urb->transfer_flags & USB_ASYNC_UNLINK) {			urb->status = -ECONNABORTED;			spin_lock_irqsave(&uhci->urb_remove_lock, flags);			/* Check to see if the remove list is empty */			if (list_empty(&uhci->urb_remove_list))				uhci_set_next_interrupt(uhci);						list_add(&urb->urb_list, &uhci->urb_remove_list);			spin_unlock_irqrestore(&uhci->urb_remove_lock, flags);		} else {			urb->status = -ENOENT;			if (in_interrupt()) {	/* wait at least 1 frame */				static int errorcount = 10;				if (errorcount--)					dbg("uhci_unlink_urb called from interrupt for urb %p", urb);				udelay(1000);			} else				schedule_timeout(1+1*HZ/1000); 			if (urb->complete)				urb->complete(urb);		}	}	return ret;}static int uhci_fsbr_timeout(struct uhci *uhci, struct urb *urb){	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;	struct list_head *head, *tmp;	uhci_dec_fsbr(uhci, urb);	/* There is a race with updating IOC in here, but it's not worth */	/*  trying to fix since this is merely an optimization. The only */	/*  time we'd lose is if the status of the packet got updated */	/*  and we'd be turning on FSBR next frame anyway, so it's a wash */	urbp->fsbr_timeout = 1;	head = &urbp->list;	tmp = head->next;	while (tmp != head) {		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);		tmp = tmp->next;		if (td->status & TD_CTRL_ACTIVE) {			td->status |= TD_CTRL_IOC;			break;		}	}	return 0;}/* * uhci_get_current_frame_number() * * returns the current frame number for a USB bus/controller. */static int uhci_get_current_frame_number(struct usb_device *dev){	struct uhci *uhci = (struct uhci *)dev->bus->hcpriv;	return inw(uhci->io_addr + USBFRNUM);}struct usb_operations uhci_device_operations = {	uhci_alloc_dev,	uhci_free_dev,	uhci_get_current_frame_number,	uhci_submit_urb,	uhci_unlink_urb};/* -------------------------------------------------------------------   Virtual Root Hub   ------------------------------------------------------------------- */static __u8 root_hub_dev_des[] ={ 	0x12,			/*  __u8  bLength; */	0x01,			/*  __u8  bDescriptorType; Device */	0x00,			/*  __u16 bcdUSB; v1.0 */	0x01,	0x09,			/*  __u8  bDeviceClass; HUB_CLASSCODE */	0x00,			/*  __u8  bDeviceSubClass; */	0x00,			/*  __u8  bDeviceProtocol; */	0x08,			/*  __u8  bMaxPacketSize0; 8 Bytes */	0x00,			/*  __u16 idVendor; */	0x00,	0x00,			/*  __u16 idProduct; */	0x00,	0x00,			/*  __u16 bcdDevice; */	0x00,	0x00,			/*  __u8  iManufacturer; */	0x02,			/*  __u8  iProduct; */	0x01,			/*  __u8  iSerialNumber; */	0x01			/*  __u8  bNumConfigurations; */};/* Configuration descriptor */static __u8 root_hub_config_des[] ={	0x09,			/*  __u8  bLength; */	0x02,			/*  __u8  bDescriptorType; Configuration */	0x19,			/*  __u16 wTotalLength; */	0x00,	0x01,			/*  __u8  bNumInterfaces; */	0x01,			/*  __u8  bConfigurationValue; */	0x00,			/*  __u8  iConfiguration; */	0x40,			/*  __u8  bmAttributes;					Bit 7: Bus-powered, 6: Self-powered,					Bit 5 Remote-wakeup, 4..0: resvd */	0x00,			/*  __u8  MaxPower; */	/* interface */	0x09,			/*  __u8  if_bLength; */	0x04,			/*  __u8  if_bDescriptorType; Interface */	0x00,			/*  __u8  if_bInterfaceNumber; */	0x00,			/*  __u8  if_bAlternateSetting; */	0x01,			/*  __u8  if_bNumEndpoints; */	0x09,			/*  __u8  if_bInterfaceClass; HUB_CLASSCODE */	0x00,			/*  __u8  if_bInterfaceSubClass; */	0x00,			/*  __u8  if_bInterfaceProtocol; */	0x00,			/*  __u8  if_iInterface; */	/* endpoint */	0x07,			/*  __u8  ep_bLength; */	0x05,			/*  __u8  ep_bDescriptorType; Endpoint */	0x81,			/*  __u8  ep_bEndpointAddress; IN Endpoint 1 */	0x03,			/*  __u8  ep_bmAttributes; Interrupt */	0x08,			/*  __u16 ep_wMaxPacketSize; 8 Bytes */	0x00,	0xff			/*  __u8  ep_bInterval; 255 ms */};static __u8 root_hub_hub_des[] ={	0x09,			/*  __u8  bLength; */	0x29,			/*  __u8  bDescriptorType; Hub-descriptor */	0x02,			/*  __u8  bNbrPorts; */	0x00,			/* __u16  wHubCharacteristics; */	0x00,	0x01,			/*  __u8  bPwrOn2pwrGood; 2ms */	0x00,			/*  __u8  bHubContrCurrent; 0 mA */	0x00,			/*  __u8  DeviceRemovable; *** 7 Ports max *** */	0xff			/*  __u8  PortPwrCtrlMask; *** 7 ports max *** */};/*-------------------------------------------------------------------------*//* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */static int rh_send_irq(struct urb *urb){	int i, len = 1;	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;	unsigned int io_addr = uhci->io_addr;	__u16 data = 0;	for (i = 0; i < uhci->rh.numports; i++) {		data |= ((inw(io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0);		len = (i + 1) / 8 + 1;	}	*(__u16 *) urb->transfer_buffer = cpu_to_le16(data);	urb->actual_length = len;	urb->status = USB_ST_NOERROR;	if ((data > 0) && (uhci->rh.send != 0)) {		dbg("root-hub INT complete: port1: %x port2: %x data: %x",			inw(io_addr + USBPORTSC1), inw(io_addr + USBPORTSC2), data);		urb->complete(urb);	}	return USB_ST_NOERROR;}/*-------------------------------------------------------------------------*//* Virtual Root Hub INTs are polled by this timer every "interval" ms */static int rh_init_int_timer(struct urb *urb);static void rh_int_timer_do(unsigned long ptr){	struct urb *urb = (struct urb *)ptr;	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;	struct list_head *tmp, *head = &uhci->urb_list;	struct urb_priv *urbp;	int len;	unsigned long flags;	if (uhci->rh.send) {		len = rh_send_irq(urb);		if (len > 0) {			urb->actual_length = len;			if (urb->complete)				urb->complete(urb);		}	}	nested_lock(&uhci->urblist_lock, flags);	tmp = head->next;	while (tmp != head) {		struct urb *u = list_entry(tmp, urb_t, urb_list);		tmp = tmp->next;		urbp = (struct urb_priv *)u->hcpriv;		if (urbp) {			/* Check if the FSBR timed out */			if (urbp->fsbr && time_after_eq(jiffies, urbp->inserttime + IDLE_TIMEOUT))				uhci_fsbr_timeout(uhci, u);			/* Check if the URB timed out */			if (u->timeout && time_after_eq(jiffies, u->timeout)) {				u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED;				uhci_unlink_urb(u);			}		}	}	nested_unlock(&uhci->urblist_lock, flags);	rh_init_int_timer(urb);}/*-------------------------------------------------------------------------*//* Root Hub INTs are polled by this timer */static int rh_init_int_timer(struct urb *urb){	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;	uhci->rh.interval = urb->interval;	init_timer(&uhci->rh.rh_int_timer);	uhci->rh.rh_int_timer.function = rh_int_timer_do;	uhci->rh.rh_int_timer.data = (unsigned long)urb;	uhci->rh.rh_int_timer.expires = jiffies + (HZ * (urb->interval < 30 ? 30 : urb->interval)) / 1000;	add_timer(&uhci->rh.rh_int_timer);	return 0;}/*-------------------------------------------------------------------------*/#define OK(x)			len = (x); break#define CLR_RH_PORTSTAT(x) \	status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \	status = (status & 0xfff5) & ~(x); \	outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))#define SET_RH_PORTSTAT(x) \	status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \	status = (status & 0xfff5) | (x); \	outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))/*-------------------------------------------------------------------------*//************************* ** Root Hub Control Pipe *************************/static int rh_submit_urb(struct urb *urb){	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;	unsigned int pipe = urb->pipe;	devrequest *cmd = (devrequest *)urb->setup_packet;	void *data = urb->transfer_buffer;	int leni = urb->transfer_buffer_length;	int len = 0;	int status = 0;	int stat = USB_ST_NOERROR;	int i;	unsigned int io_addr = uhci->io_addr;	__u16 cstatus;	__u16 bmRType_bReq;	__u16 wValue;	__u16 wIndex;	__u16 wLength;	if (usb_pipetype(pipe) == PIPE_INTERRUPT) {		uhci->rh.urb = urb;		uhci->rh.send = 1;		uhci->rh.interval = urb->interval;		rh_init_int_timer(urb);		return USB_ST_NOERROR;	}	bmRType_bReq = cmd->requesttype | cmd->request << 8;	wValue = le16_to_cpu(cmd->value);	wIndex = le16_to_cpu(cmd->index);	wLength = le16_to_cpu(cmd->length);	for (i = 0; i < 8; i++)		uhci->rh.c_p_r[i] = 0;	switch (bmRType_bReq) {		/* Request Destination:		   without flags: Device,		   RH_INTERFACE: interface,		   RH_ENDPOINT: endpoint,		   RH_CLASS means HUB here,		   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here		*/	case RH_GET_STATUS:		*(__u16 *)data = cpu_to_le16(1);		OK(2);	case RH_GET_STATUS | RH_INTERFACE:		*(__u16 *)data = cpu_to_le16(0);		OK(2);	case RH_GET_STATUS | RH_ENDPOINT:		*(__u16 *)data = cpu_to_le16(0);		OK(2);	case RH_GET_STATUS | RH_CLASS:		*(__u32 *)data = cpu_to_le32(0);		OK(4);		/* hub power */	case RH_GET_STATUS | RH_OTHER | RH_CLASS:		status = inw(io_addr + USBPORTSC1 + 2 * (wIndex - 1));		cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |			((status & USBPORTSC_PEC) >> (3 - 1)) |			(uhci->rh.c_p_r[wIndex - 1] << (0 + 4));			status = (status & USBPORTSC_CCS) |			((status & USBPORTSC_PE) >> (2 - 1)) |			((status & USBPORTSC_SUSP) >> (12 - 2)) |			((status & USBPORTSC_PR) >> (9 - 4)) |			(1 << 8) |      /* power on */			((status & USBPORTSC_LSDA) << (-8 + 9));		*(__u16 *)data = cpu_to_le16(status);		*(__u16 *)(data + 2) = cpu_to_le16(cstatus);		OK(4);	case RH_CLEAR_FEATURE | RH_ENDPOINT:		switch (wValue) {		case RH_ENDPOINT_STALL:			OK(0);		}		break;	case RH_CLEAR_FEATURE | RH_CLASS:		switch (wValue) {		case RH_C_HUB_OVER_CURRENT:			OK(0);	/* hub power over current */		}		break;	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:		switch (wValue) {		case RH_PORT_ENABLE:			CLR_RH_PORTSTAT(USBPORTSC_PE);			OK(0);		case RH_PORT_SUSPEND:			CLR_RH_PORTSTAT(USBPORTSC_SUSP);			OK(0);		case RH_PORT_POWER:			OK(0);	/* port power */		case RH_C_PORT_CONNECTION:			SET_RH_PORTSTAT(USBPORTSC_CSC);			OK(0);		case RH_C_PORT_ENABLE:			SET_RH_PORTSTAT(USBPORTSC_PEC);			OK(0);		case RH_C_PORT_SUSPEND:			/*** WR_RH_PORTSTAT(RH_PS_PSSC); */

⌨️ 快捷键说明

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