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

📄 usb-uhci.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
}/*-------------------------------------------------------------------*/_static void clean_td_chain (uhci_t *s, uhci_desc_t *td){	struct list_head *p;	uhci_desc_t *td1;	if (!td)		return;		while ((p = td->horizontal.next) != &td->horizontal) {		td1 = list_entry (p, uhci_desc_t, horizontal);		delete_desc (s, td1);	}		delete_desc (s, td);}/*-------------------------------------------------------------------*/_static void fill_td (uhci_desc_t *td, int status, int info, __u32 buffer){	td->hw.td.status = cpu_to_le32(status);	td->hw.td.info = cpu_to_le32(info);	td->hw.td.buffer = cpu_to_le32(buffer);}/*-------------------------------------------------------------------*/// Removes ALL qhs in chain (paranoia!)_static void cleanup_skel (uhci_t *s){	unsigned int n;	uhci_desc_t *td;	dbg("cleanup_skel");	clean_descs(s,1);		if (s->td32ms) {			unlink_td(s,s->td32ms,1);		delete_desc(s, s->td32ms);	}	for (n = 0; n < 8; n++) {		td = s->int_chain[n];		clean_td_chain (s, td);	}	if (s->iso_td) {		for (n = 0; n < 1024; n++) {			td = s->iso_td[n];			clean_td_chain (s, td);		}		kfree (s->iso_td);	}	if (s->framelist)		pci_free_consistent(s->uhci_pci, PAGE_SIZE,				    s->framelist, s->framelist_dma);	if (s->control_chain) {		// completed init_skel?		struct list_head *p;		uhci_desc_t *qh, *qh1;		qh = s->control_chain;		while ((p = qh->horizontal.next) != &qh->horizontal) {			qh1 = list_entry (p, uhci_desc_t, horizontal);			delete_qh (s, qh1);		}		delete_qh (s, qh);	}	else {		if (s->ls_control_chain)			delete_desc (s, s->ls_control_chain);		if (s->control_chain)			delete_desc (s, s->control_chain);		if (s->bulk_chain)			delete_desc (s, s->bulk_chain);		if (s->chain_end)			delete_desc (s, s->chain_end);	}	if (s->desc_pool) {		pci_pool_destroy(s->desc_pool);		s->desc_pool = NULL;	}	dbg("cleanup_skel finished");	}/*-------------------------------------------------------------------*/// allocates framelist and qh-skeletons// only HW-links provide continous linking, SW-links stay in their domain (ISO/INT)_static int init_skel (uhci_t *s){	int n, ret;	uhci_desc_t *qh, *td;		dbg("init_skel");		s->framelist = pci_alloc_consistent(s->uhci_pci, PAGE_SIZE,					    &s->framelist_dma);	if (!s->framelist)		return -ENOMEM;	memset (s->framelist, 0, 4096);	dbg("creating descriptor pci_pool");	s->desc_pool = pci_pool_create("uhci_desc", s->uhci_pci,				       sizeof(uhci_desc_t), 16, 0,				       GFP_DMA | GFP_ATOMIC);		if (!s->desc_pool)		goto init_skel_cleanup;	dbg("allocating iso desc pointer list");	s->iso_td = (uhci_desc_t **) kmalloc (1024 * sizeof (uhci_desc_t*), GFP_KERNEL);		if (!s->iso_td)		goto init_skel_cleanup;	s->ls_control_chain = NULL;	s->control_chain = NULL;	s->bulk_chain = NULL;	s->chain_end = NULL;	dbg("allocating iso descs");	for (n = 0; n < 1024; n++) {	 	// allocate skeleton iso/irq-tds		if (alloc_td (s, &td, 0))			goto init_skel_cleanup;		s->iso_td[n] = td;		s->framelist[n] = cpu_to_le32((__u32) td->dma_addr);	}	dbg("allocating qh: chain_end");	if (alloc_qh (s, &qh))			goto init_skel_cleanup;					s->chain_end = qh;	if (alloc_td (s, &td, 0))		goto init_skel_cleanup;		fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 1ms interrupt (enabled on demand)	insert_td (s, qh, td, 0);	qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM); // remove TERM bit	s->td1ms=td;	dbg("allocating qh: bulk_chain");	if (alloc_qh (s, &qh))		goto init_skel_cleanup;		insert_qh (s, s->chain_end, qh, 0);	s->bulk_chain = qh;	dbg("allocating qh: control_chain");	ret = alloc_qh (s, &qh);	if (ret)		goto init_skel_cleanup;		insert_qh (s, s->bulk_chain, qh, 0);	s->control_chain = qh;#ifdef	CONFIG_USB_UHCI_HIGH_BANDWIDTH	// disabled reclamation loop	set_qh_head(s->chain_end, s->control_chain->dma_addr | UHCI_PTR_QH | UHCI_PTR_TERM);#endif	dbg("allocating qh: ls_control_chain");	if (alloc_qh (s, &qh))		goto init_skel_cleanup;		insert_qh (s, s->control_chain, qh, 0);	s->ls_control_chain = qh;	for (n = 0; n < 8; n++)		s->int_chain[n] = 0;	dbg("allocating skeleton INT-TDs");		for (n = 0; n < 8; n++) {		uhci_desc_t *td;		if (alloc_td (s, &td, 0))			goto init_skel_cleanup;		s->int_chain[n] = td;		if (n == 0) {			set_td_link(s->int_chain[0], s->ls_control_chain->dma_addr | UHCI_PTR_QH);		}		else {			set_td_link(s->int_chain[n], s->int_chain[0]->dma_addr);		}	}	dbg("Linking skeleton INT-TDs");		for (n = 0; n < 1024; n++) {		// link all iso-tds to the interrupt chains		int m, o;		dbg("framelist[%i]=%x",n,le32_to_cpu(s->framelist[n]));		if ((n&127)==127) 			((uhci_desc_t*) s->iso_td[n])->hw.td.link = cpu_to_le32(s->int_chain[0]->dma_addr);		else 			for (o = 1, m = 2; m <= 128; o++, m += m)				if ((n & (m - 1)) == ((m - 1) / 2))					set_td_link(((uhci_desc_t*) s->iso_td[n]), s->int_chain[o]->dma_addr);	}	if (alloc_td (s, &td, 0))		goto init_skel_cleanup;		fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 32ms interrupt (activated later)	s->td32ms=td;	insert_td_horizontal (s, s->int_chain[5], td);	mb();	//uhci_show_queue(s->control_chain);   	dbg("init_skel exit");	return 0;      init_skel_cleanup:	cleanup_skel (s);	return -ENOMEM;}/*-------------------------------------------------------------------*///                         LOW LEVEL STUFF//          assembles QHs und TDs for control, bulk and iso/*-------------------------------------------------------------------*/_static int uhci_submit_control_urb (struct urb *urb){	uhci_desc_t *qh, *td;	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;	urb_priv_t *urb_priv = urb->hcpriv;	unsigned long destination, status;	int maxsze = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));	unsigned long len;	char *data;	int depth_first=USE_CTRL_DEPTH_FIRST;  // UHCI descriptor chasing method	dbg("uhci_submit_control start");	if (alloc_qh (s, &qh))		// alloc qh for this request		return -ENOMEM;	if (alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first))		// get td for setup stage	{		delete_qh (s, qh);		return -ENOMEM;	}	/* The "pipe" thing contains the destination in bits 8--18 */	destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;	/* 3 errors */	status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE |		(urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);	/*  Build the TD for the control request, try forever, 8 bytes of data */	fill_td (td, status, destination | (7 << 21), urb_priv->setup_packet_dma);	insert_td (s, qh, td, 0);	// queue 'setup stage'-td in qh#if 0	{		char *sp=urb->setup_packet;		dbg("SETUP to pipe %x: %x %x %x %x %x %x %x %x", urb->pipe,		    sp[0],sp[1],sp[2],sp[3],sp[4],sp[5],sp[6],sp[7]);	}	//uhci_show_td(td);#endif	len = urb->transfer_buffer_length;	data = urb->transfer_buffer;	/* If direction is "send", change the frame from SETUP (0x2D)	   to OUT (0xE1). Else change it from SETUP to IN (0x69). */	destination = (urb->pipe & PIPE_DEVEP_MASK) | (usb_pipeout (urb->pipe)?USB_PID_OUT:USB_PID_IN);	while (len > 0) {		int pktsze = len;		if (alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first))			goto fail_unmap_enomem;		if (pktsze > maxsze)			pktsze = maxsze;		destination ^= 1 << TD_TOKEN_TOGGLE;	// toggle DATA0/1		// Status, pktsze bytes of data		fill_td (td, status, destination | ((pktsze - 1) << 21),			 urb_priv->transfer_buffer_dma + (data - (char *)urb->transfer_buffer));		insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first);	// queue 'data stage'-td in qh		data += pktsze;		len -= pktsze;	}	/* Build the final TD for control status */	/* It's only IN if the pipe is out AND we aren't expecting data */	destination &= ~UHCI_PID;	if (usb_pipeout (urb->pipe) || (urb->transfer_buffer_length == 0))		destination |= USB_PID_IN;	else		destination |= USB_PID_OUT;	destination |= 1 << TD_TOKEN_TOGGLE;	/* End in Data1 */	if (alloc_td (s, &td, UHCI_PTR_DEPTH))		goto fail_unmap_enomem;	status &=~TD_CTRL_SPD;	/* no limit on errors on final packet , 0 bytes of data */	fill_td (td, status | TD_CTRL_IOC, destination | (UHCI_NULL_DATA_SIZE << 21),		 0);	insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first);	// queue status td	list_add (&qh->desc_list, &urb_priv->desc_list);	queue_urb (s, urb);	// queue before inserting in desc chain	qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM);	//uhci_show_queue(qh);	/* Start it up... put low speed first */	if (urb->pipe & TD_CTRL_LS)		insert_qh (s, s->control_chain, qh, 0);	else		insert_qh (s, s->bulk_chain, qh, 0);	dbg("uhci_submit_control end");	return 0;fail_unmap_enomem:	delete_qh(s, qh);	return -ENOMEM;}/*-------------------------------------------------------------------*/// For queued bulk transfers, two additional QH helpers are allocated (nqh, bqh)// Due to the linking with other bulk urbs, it has to be locked with urb_list_lock!_static int uhci_submit_bulk_urb (struct urb *urb, struct urb *bulk_urb){	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;	urb_priv_t *urb_priv = urb->hcpriv, *upriv, *bpriv=NULL;	uhci_desc_t *qh, *td, *nqh=NULL, *bqh=NULL, *first_td=NULL;	unsigned long destination, status;	char *data;	unsigned int pipe = urb->pipe;	int maxsze = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));	int info, len, last;	int depth_first=USE_BULK_DEPTH_FIRST;  // UHCI descriptor chasing method	if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)))		return -EPIPE;	queue_dbg("uhci_submit_bulk_urb: urb %p, old %p, pipe %08x, len %i",		  urb,bulk_urb,urb->pipe,urb->transfer_buffer_length);	upriv = (urb_priv_t*)urb->hcpriv;	if (!bulk_urb) {		if (alloc_qh (s, &qh))		// get qh for this request			return -ENOMEM;		if (urb->transfer_flags & USB_QUEUE_BULK) {			if (alloc_qh(s, &nqh)) // placeholder for clean unlink			{				delete_desc (s, qh);				return -ENOMEM;			}			upriv->next_qh = nqh;			queue_dbg("new next qh %p",nqh);		}	}	else { 		bpriv = (urb_priv_t*)bulk_urb->hcpriv;		qh = bpriv->bottom_qh;  // re-use bottom qh and next qh		nqh = bpriv->next_qh;		upriv->next_qh=nqh;			upriv->prev_queued_urb=bulk_urb;	}	if (urb->transfer_flags & USB_QUEUE_BULK) {		if (alloc_qh (s, &bqh))  // "bottom" QH		{			if (!bulk_urb) { 				delete_desc(s, qh);				delete_desc(s, nqh);			}			return -ENOMEM;		}		set_qh_element(bqh, UHCI_PTR_TERM);		set_qh_head(bqh, nqh->dma_addr | UHCI_PTR_QH); // element		upriv->bottom_qh = bqh;	}	queue_dbg("uhci_submit_bulk: qh %p bqh %p nqh %p",qh, bqh, nqh);	/* The "pipe" thing contains the destination in bits 8--18. */	destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe);	/* 3 errors */	status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE |		((urb->transfer_flags & USB_DISABLE_SPD) ? 0 : TD_CTRL_SPD) | (3 << 27);	/* Build the TDs for the bulk request */	len = urb->transfer_buffer_length;	data = urb->transfer_buffer;		do {					// TBD: Really allow zero-length packets?		int pktsze = len;		if (alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first))		{			delete_qh (s, qh);			return -ENOMEM;		}		if (pktsze > maxsze)			pktsze = maxsze;		// pktsze bytes of data 		info = destination | (((pktsze - 1)&UHCI_NULL_DATA_SIZE) << 21) |			(usb_gettoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE);		fill_td (td, status, info,			 urb_priv->transfer_buffer_dma + (data - (char *)urb->transfer_buffer));		data += pktsze;		len -= pktsze;		// Use USB_ZERO_PACKET to finish bulk OUTs always with a zero length packet		last = (len == 0 && (usb_pipein(pipe) || pktsze < maxsze || !(urb->transfer_flags & USB_ZERO_PACKET)));		if (last)			set_td_ioc(td);	// last one generates INT		insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first);		if (!first_td)			first_td=td;		usb_dotoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));	} while (!last);	if (bulk_urb && bpriv)   // everything went OK, link with old bulk URB		bpriv->next_queued_urb=urb;	list_add (&qh->desc_list, &urb_priv->desc_list);	if (urb->transfer_flags & USB_QUEUE_BULK)		append_qh(s, td, bqh, UHCI_PTR_DEPTH * depth_first);	queue_urb_unlocked (s, urb);		if (urb->transfer_flags & USB_QUEUE_BULK)		set_qh_element(qh, first_td->dma_addr);	else

⌨️ 快捷键说明

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