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

📄 usb-uhci.c

📁 Usb1.1驱动c语言源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	uhci_desc_t *qh, *td;		dbg("init_skel");		s->framelist = (__u32 *) get_free_page (GFP_KERNEL);	if (!s->framelist)		return -ENOMEM;	memset (s->framelist, 0, 4096);	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		ret = alloc_td (&td, 0);		if (ret)			goto init_skel_cleanup;		s->iso_td[n] = td;		s->framelist[n] = ((__u32) virt_to_bus (td));	}	dbg("allocating qh: chain_end");	ret = alloc_qh (&qh);		if (ret)		goto init_skel_cleanup;					s->chain_end = qh;	ret = alloc_td (&td, 0);	if (ret)		goto init_skel_cleanup;		fill_td (td, TD_CTRL_IOC, 0, 0); // generate 1ms interrupt	insert_td (s, qh, td, 0);	dbg("allocating qh: bulk_chain");	ret = alloc_qh (&qh);	if (ret)		goto init_skel_cleanup;		insert_qh (s, s->chain_end, qh, 0);	s->bulk_chain = qh;	dbg("allocating qh: control_chain");	ret = alloc_qh (&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	s->chain_end->hw.qh.head=virt_to_bus(s->control_chain) | UHCI_PTR_QH | UHCI_PTR_TERM;#endif	dbg("allocating qh: ls_control_chain");	ret = alloc_qh (&qh);	if (ret)		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;		alloc_td (&td, 0);		if (!td)			goto init_skel_cleanup;		s->int_chain[n] = td;		if (n == 0) {			s->int_chain[0]->hw.td.link = virt_to_bus (s->ls_control_chain) | UHCI_PTR_QH;		}		else {			s->int_chain[n]->hw.td.link = virt_to_bus (s->int_chain[0]);		}	}	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,s->framelist[n]);		if ((n&127)==127) 			((uhci_desc_t*) s->iso_td[n])->hw.td.link = virt_to_bus(s->int_chain[0]);		else 			for (o = 1, m = 2; m <= 128; o++, m += m)				if ((n & (m - 1)) == ((m - 1) / 2))					((uhci_desc_t*) s->iso_td[n])->hw.td.link = virt_to_bus (s->int_chain[o]);	}	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 (urb_t *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	if (!maxsze) {		err("uhci_submit_control_urb: pipesize for pipe %x is zero", urb->pipe);		return -EINVAL;	}	dbg("uhci_submit_control start");	alloc_qh (&qh);		// alloc qh for this request	if (!qh)		return -ENOMEM;	alloc_td (&td, UHCI_PTR_DEPTH * depth_first);		// get td for setup stage	if (!td) {		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), virt_to_bus (urb->setup_packet));	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;		alloc_td (&td, UHCI_PTR_DEPTH * depth_first);		if (!td) {			delete_qh (s, qh);			return -ENOMEM;		}		if (pktsze > maxsze)			pktsze = maxsze;		destination ^= 1 << TD_TOKEN_TOGGLE;	// toggle DATA0/1		fill_td (td, status, destination | ((pktsze - 1) << 21),			 virt_to_bus (data));	// Status, pktsze bytes of data		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 */	alloc_td (&td, UHCI_PTR_DEPTH);		if (!td) {		delete_qh (s, qh);		return -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);	urb->status = -EINPROGRESS;	queue_urb (s, urb);	// queue before inserting in desc chain	qh->hw.qh.element &= ~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;}/*-------------------------------------------------------------------*/// 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 (urb_t *urb, urb_t *bulk_urb){	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;	urb_priv_t *urb_priv = urb->hcpriv;	uhci_desc_t *qh, *td, *nqh, *bqh;	unsigned long destination, status;	char *data;	unsigned int pipe = urb->pipe;	int maxsze = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));	int info, len;	int depth_first=USE_BULK_DEPTH_FIRST;  // UHCI descriptor chasing method	urb_priv_t *upriv, *bpriv;	if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)))		return -EPIPE;	if (urb->transfer_buffer_length < 0) {		err("Negative transfer length in submit_bulk");		return -EINVAL;	}		if (!maxsze)		return -EMSGSIZE;		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) {		alloc_qh (&qh);		// get qh for this request				if (!qh)			return -ENOMEM;		if (urb->transfer_flags & USB_QUEUE_BULK) {			alloc_qh(&nqh); // placeholder for clean unlink			if (!nqh) {				delete_desc (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;		bpriv->next_queued_urb=urb;		upriv->prev_queued_urb=bulk_urb;	}	queue_dbg("uhci_submit_bulk: qh=%p, nqh=%p\n",bqh,nqh);	if (urb->transfer_flags & USB_QUEUE_BULK) {		alloc_qh (&bqh); // "bottom" QH,				if (!bqh) {			if (!bulk_urb) { 				delete_desc(qh);				delete_desc(nqh);			}			return -ENOMEM;		}		bqh->hw.qh.element = UHCI_PTR_TERM;		bqh->hw.qh.element = virt_to_bus(nqh)|UHCI_PTR_QH;		upriv->bottom_qh = bqh;		queue_dbg("uhci_submit_bulk: new bqh %p\n",bqh);	}		/* 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;		alloc_td (&td, UHCI_PTR_DEPTH * depth_first);		if (!td) {			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, virt_to_bus (data));		data += pktsze;		len -= pktsze;		if (!len)			td->hw.td.status |= TD_CTRL_IOC;	// last one generates INT		insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first);		usb_dotoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));	} while (len > 0);	list_add (&qh->desc_list, &urb_priv->desc_list);	if (urb->transfer_flags & USB_QUEUE_BULK) {		qh->hw.qh.element&=~UHCI_PTR_TERM;		append_qh(s, td, bqh, UHCI_PTR_DEPTH * depth_first);	}	urb->status = -EINPROGRESS;	queue_urb_unlocked (s, urb);		qh->hw.qh.element  &= ~UHCI_PTR_TERM;	if (!bulk_urb) { 		if (urb->transfer_flags & USB_QUEUE_BULK) {			spin_lock (&s->td_lock);			// both QHs in one go			insert_qh (s, s->chain_end, qh, 0);	// Main QH			insert_qh (s, s->chain_end, nqh, 0);	// Helper QH			spin_unlock (&s->td_lock);		}		else			insert_qh (s, s->chain_end, qh, 0);	}		//uhci_show_queue(s->bulk_chain);	//dbg("uhci_submit_bulk_urb: exit\n");	return 0;}/*-------------------------------------------------------------------*/_static void uhci_clean_iso_step1(uhci_t *s, urb_priv_t *urb_priv){	struct list_head *p;	uhci_desc_t *td;	for (p = urb_priv->desc_list.next; p != &urb_priv->desc_list; p = p->next) {				td = list_entry (p, uhci_desc_t, desc_list);				unlink_td (s, td, 1);	}}/*-------------------------------------------------------------------*/_static void uhci_clean_iso_step2(uhci_t *s, urb_priv_t *urb_priv){	struct list_head *p;	uhci_desc_t *td;	while ((p = urb_priv->desc_list.next) != &urb_priv->desc_list) {				td = list_entry (p, uhci_desc_t, desc_list);				list_del (p);				delete_desc (td);	}}/*-------------------------------------------------------------------*/// mode: 0: unlink + no deletion mark, 1: regular (unlink/delete-mark), 2: don't unlink// looks a bit complicated because of all the bulk queueing goodies_static void uhci_clean_transfer (uhci_t *s, urb_t *urb, uhci_desc_t *qh, int mode){	uhci_desc_t *bqh, *nqh, *prevqh;	int now;	urb_priv_t *priv=(urb_priv_t*)urb->hcpriv;	now=UHCI_GET_CURRENT_FRAME(s);	dbg("clean transfer urb %p, qh %p, mode %i",urb,qh,mode);	bqh=priv->bottom_qh;		if (!priv->next_queued_urb)  { // no more appended bulk queues		if (mode != 2) 			unlink_qh (s, qh);			if (priv->prev_queued_urb) {			urb_priv_t* ppriv=(urb_priv_t*)priv->prev_queued_urb->hcpriv;			ppriv->bottom_qh = priv->bottom_qh;			ppriv->next_queued_urb = NULL;		}		else if (bqh) {  // queue dead			nqh=priv->next_qh;						if (mode != 2)				unlink_qh(s, nqh);			if (mode) {				nqh->last_used = bqh->last_used = now;				list_add_tail (&nqh->horizontal, &s->free_desc);				list_add_tail (&bqh->horizontal, &s->free_desc);			}					}	}	else { // there are queued urbs following		urb_t *nurb;		unsigned long flags;		       		nurb=priv->next_queued_urb;		spin_lock_irqsave (&s->qh_lock, flags);				if (!priv->prev_queued_urb) { // top			if (mode !=2) {				prevqh = list_entry (qh->horizontal.prev, uhci_desc_t, horizontal);				prevqh->hw.qh.head = virt_to_bus(bqh) | UHCI_PTR_QH;				queue_dbg ("TOP relink of %p to %p-%p",qh,prevqh,bqh);								list_del (&qh->horizontal);				list_add (&bqh->horizontal, &prevqh->horizontal);			}			}		else {		//intermediate			urb_priv_t* ppriv=(urb_priv_t*)priv->prev_queued_urb->hcpriv;			uhci_desc_t * bnqh;						bnqh=list_entry (&((urb_priv_t*)(nurb->hcpriv))->desc_list.next, uhci_desc_t, desc_list);			ppriv->bottom_qh=bnqh;			ppriv->next_queued_urb=nurb;						if (mode!=2) {				prevqh = list_entry (ppriv->desc_list.next, uhci_desc_t, desc_list);				prevqh->hw.qh.head = virt_to_bus(bqh) | UHCI_PTR_QH;				queue_dbg ("IM relink of %p to %p-%p",qh,prevqh,bqh);				}		}		mb();		spin_unlock_irqrestore (&s->qh_lock, flags);		((urb_priv_t*)nurb->hcpriv)->prev_queued_urb=priv->prev_queued_urb;	

⌨️ 快捷键说明

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