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

📄 auerisdn.c

📁 ep9315平台下USB驱动的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
				spin_lock_irqsave(&ahp->seq_lock, flags);				ahp->txseq = 0;				ahp->rxseq = 0;				spin_unlock_irqrestore(&ahp->seq_lock,						       flags);				l2_header[l2_index++] = 0x73;	/* UA */				goto phd_answer;			case 0x53:	/* DISC */				dbg("DISC");				/* Send back a UA */				l2_header[l2_index++] = 0x73;	/* UA */				goto phd_answer;			default:				dbg("Unhandled L2 Message %X", (int) c);				break;			}			/* all done */			goto phd_free;			/* we have to generate a local answer */			/* first, confirm old message, free old skb */		      phd_answer:auerisdn_d_confirmskb(cp,					      skb);			/* allocate a new skbuff */			skb = dev_alloc_skb(l2_index);			if (!skb) {				err("no memory for new skb");				break;			}			dump("local answer to L2 is:", l2_header,			     l2_index);			memcpy(skb_put(skb, l2_index), l2_header,			       l2_index);			auerisdn_d_l1l2(&cp->isdn, PH_DATA | INDICATION,					skb);			break;			/* we have to send the L3 message out */		      phd_send:if (!len)				goto phd_free;	/* no message left */			/* get a new data buffer */			bp = auerbuf_getbuf(&cp->bufctl);			if (!bp) {				warn("no auerbuf free");				goto phd_free;			}			/* protect against too big write requests */			/* Should not happen */			if (len > cp->maxControlLength) {				err("too long D-channel paket truncated");				len = cp->maxControlLength;			}			/* Copy the data */			memcpy(bp->bufp + AUH_SIZE, sp, len);			/* set the header byte */			*(bp->bufp) =			    cp->isdn.dchannelservice.			    id | AUH_DIRECT | AUH_UNSPLIT;			/* Set the transfer Parameters */			bp->len = len + AUH_SIZE;			bp->dr->bRequestType = AUT_WREQ;			bp->dr->bRequest = AUV_WBLOCK;			bp->dr->wValue = cpu_to_le16(0);			bp->dr->wIndex =			    cpu_to_le16(cp->isdn.dchannelservice.					id | AUH_DIRECT | AUH_UNSPLIT);			bp->dr->wLength = cpu_to_le16(len + AUH_SIZE);			FILL_CONTROL_URB(bp->urbp, cp->usbdev,					 usb_sndctrlpipe(cp->usbdev, 0),					 (unsigned char *) bp->dr,					 bp->bufp, len + AUH_SIZE,					 auerisdn_dcw_complete, bp);			/* up we go */			ret =			    auerchain_submit_urb(&cp->controlchain,						 bp->urbp);			if (ret)				auerisdn_dcw_complete(bp->urbp);			else				dbg("auerisdn_dwrite: Write OK");			/* confirm message, free skb */		      phd_free:auerisdn_d_confirmskb(cp,					      skb);			break;		default:			warn("pr %#x\n", pr);			break;		}	} else {		/* hisax interface is down */		switch (pr) {		case PH_ACTIVATE | REQUEST:	/* activation request */			dbg("D channel PH_ACTIVATE | REQUEST with interface down");			/* don't answer this request! Endless... */			break;		case PH_DEACTIVATE | REQUEST:	/* deactivation request */			dbg("D channel PH_DEACTIVATE | REQUEST with interface down");			hisax_d_if->l1l2(hisax_d_if,					 PH_DEACTIVATE | INDICATION, NULL);			break;		case PH_DATA | REQUEST:	/* Transmit data request */			dbg("D channel PH_DATA | REQUEST with interface down");			skb = (struct sk_buff *) arg;			/* free data buffer */			if (skb) {				skb_pull(skb, skb->len);				dev_kfree_skb_any(skb);			}			/* send confirmation back to layer 2 */			hisax_d_if->l1l2(hisax_d_if, PH_DATA | CONFIRM,					 NULL);			break;		default:			warn("pr %#x\n", pr);			break;		}	}}/* Completion function for D channel open */static void auerisdn_dcopen_complete(struct urb *urbp){	struct auerbuf *bp = (struct auerbuf *) urbp->context;	struct auerswald *cp =	    ((struct auerswald *) ((char *) (bp->list) -				   (unsigned				    long) (&((struct auerswald *) 0)->					   bufctl)));	dbg("auerisdn_dcopen_complete called");	auerbuf_releasebuf(bp);	/* Wake up all processes waiting for a buffer */	wake_up(&cp->bufferwait);}/* Open the D-channel once more */static void auerisdn_dcopen(unsigned long data){	struct auerswald *cp = (struct auerswald *) data;	struct auerbuf *bp;	int ret;	if (cp->disconnecting)		return;	dbg("auerisdn_dcopen running");	/* get a buffer for the command */	bp = auerbuf_getbuf(&cp->bufctl);	/* if no buffer available: can't change the mode */	if (!bp) {		err("auerisdn_dcopen: no data buffer available");		return;	}	/* fill the control message */	bp->dr->bRequestType = AUT_WREQ;	bp->dr->bRequest = AUV_CHANNELCTL;	bp->dr->wValue = cpu_to_le16(1);	bp->dr->wIndex = cpu_to_le16(0);	bp->dr->wLength = cpu_to_le16(0);	FILL_CONTROL_URB(bp->urbp, cp->usbdev,			 usb_sndctrlpipe(cp->usbdev, 0),			 (unsigned char *) bp->dr, bp->bufp, 0,			 (usb_complete_t) auerisdn_dcopen_complete, bp);	/* submit the control msg */	ret = auerchain_submit_urb(&cp->controlchain, bp->urbp);	dbg("dcopen submitted");	if (ret) {		bp->urbp->status = ret;		auerisdn_dcopen_complete(bp->urbp);	}	return;}/* Initialize the isdn related items in struct auerswald */void auerisdn_init_dev(struct auerswald *cp){	unsigned int u;	cp->isdn.dchannelservice.id = AUH_UNASSIGNED;	cp->isdn.dchannelservice.dispatch = auerisdn_dispatch_dc;	cp->isdn.dchannelservice.disconnect = auerisdn_disconnect_dc;	init_timer(&cp->isdn.dcopen_timer);	cp->isdn.dcopen_timer.data = (unsigned long) cp;	cp->isdn.dcopen_timer.function = auerisdn_dcopen;	for (u = 0; u < AUISDN_BCHANNELS; u++) {		cp->isdn.bc[u].cp = cp;		cp->isdn.bc[u].mode = L1_MODE_NULL;		cp->isdn.bc[u].channel = u;		spin_lock_init(&cp->isdn.bc[u].txskb_lock);	}}/* Connect to the HISAX interface. Returns 0 if successfull */int auerisdn_probe(struct auerswald *cp){	struct hisax_b_if *b_if[AUISDN_BCHANNELS];	struct usb_endpoint_descriptor *ep;	struct auerhisax *ahp;	DECLARE_WAIT_QUEUE_HEAD(wqh);	unsigned int u;	unsigned char *ucp;	unsigned int first_time;	int ret;	/* First allocate resources, then register hisax interface */	/* Allocate RX buffers */	for (u = 0; u < AUISDN_BCHANNELS; u++) {		if (!cp->isdn.bc[u].rxbuf) {			cp->isdn.bc[u].rxbuf =			    (char *) kmalloc(AUISDN_RXSIZE, GFP_KERNEL);			if (!cp->isdn.bc[u].rxbuf) {				err("can't allocate buffer for B channel RX data");				return -1;			}		}	}	/* Read out B-Channel output fifo size */	ucp = kmalloc(32, GFP_KERNEL);	if (!ucp) {		err("Out of memory");		return -3;	}	ret = usb_control_msg(cp->usbdev,			/* pointer to device */			      usb_rcvctrlpipe(cp->usbdev, 0),	/* pipe to control endpoint */			      AUV_GETINFO,			/* USB message request value */			      AUT_RREQ,				/* USB message request type value */			      0,				/* USB message value */			      AUDI_OUTFSIZE,			/* USB message index value */			      ucp,				/* pointer to the receive buffer */			      32,				/* length of the buffer */			      HZ * 2);				/* time to wait for the message to complete before timing out */	if (ret < 4) {		kfree(ucp);		err("can't read TX Fifo sizes for B1,B2");		return -4;	}	for (u = 0; u < AUISDN_BCHANNELS; u++) {		ret = le16_to_cpup(ucp + u * 2);		cp->isdn.bc[u].ofsize = ret;		cp->isdn.bc[u].txfree = ret;	}	kfree(ucp);	for (u = 0; u < AUISDN_BCHANNELS; u++) {		dbg("B%d buffer size is %d", u, cp->isdn.bc[u].ofsize);	}	/* get the B channel output INT size */	cp->isdn.intbo_endp = AU_IRQENDPBO;	ep = usb_epnum_to_ep_desc(cp->usbdev, USB_DIR_OUT | AU_IRQENDPBO);	if (!ep) {		/* Some devices have another endpoint number here ... */		cp->isdn.intbo_endp = AU_IRQENDPBO_2;		ep = usb_epnum_to_ep_desc(cp->usbdev,					  USB_DIR_OUT | AU_IRQENDPBO_2);		if (!ep) {			err("can't get B channel OUT endpoint");			return -5;		}	}	cp->isdn.outsize = ep->wMaxPacketSize;	cp->isdn.outInterval = ep->bInterval;	cp->isdn.usbdev = cp->usbdev;	/* allocate the urb and data buffer */	if (!cp->isdn.intbo_urbp) {		cp->isdn.intbo_urbp = usb_alloc_urb(0);		if (!cp->isdn.intbo_urbp) {			err("can't allocate urb for B channel output endpoint");			return -6;		}	}	if (!cp->isdn.intbo_bufp) {		cp->isdn.intbo_bufp =		    (char *) kmalloc(cp->isdn.outsize, GFP_KERNEL);		if (!cp->isdn.intbo_bufp) {			err("can't allocate buffer for B channel output endpoint");			return -7;		}	}	/* get the B channel input INT size */	ep = usb_epnum_to_ep_desc(cp->usbdev, USB_DIR_IN | AU_IRQENDPBI);	if (!ep) {		err("can't get B channel IN endpoint");		return -8;	}	cp->isdn.insize = ep->wMaxPacketSize;	/* allocate the urb and data buffer */	if (!cp->isdn.intbi_urbp) {		cp->isdn.intbi_urbp = usb_alloc_urb(0);		if (!cp->isdn.intbi_urbp) {			err("can't allocate urb for B channel input endpoint");			return -9;		}	}	if (!cp->isdn.intbi_bufp) {		cp->isdn.intbi_bufp =		    (char *) kmalloc(cp->isdn.insize, GFP_KERNEL);		if (!cp->isdn.intbi_bufp) {			err("can't allocate buffer for B channel input endpoint");			return -10;		}	}	/* setup urb */	FILL_INT_URB(cp->isdn.intbi_urbp, cp->usbdev,		     usb_rcvintpipe(cp->usbdev, AU_IRQENDPBI),		     cp->isdn.intbi_bufp, cp->isdn.insize,		     auerisdn_intbi_complete, cp, ep->bInterval);	/* start the urb */	cp->isdn.intbi_urbp->status = 0;	/* needed! */	ret = usb_submit_urb(cp->isdn.intbi_urbp);	if (ret < 0) {		err("activation of B channel input int failed %d", ret);		usb_free_urb(cp->isdn.intbi_urbp);		cp->isdn.intbi_urbp = NULL;		return -11;	}	/* request the D-channel service now */	dbg("Requesting D channel now");	cp->isdn.dchannelservice.id = AUH_DCHANNEL;	if (auerswald_addservice(cp, &cp->isdn.dchannelservice)) {		err("can not open D-channel");		cp->isdn.dchannelservice.id = AUH_UNASSIGNED;		return -2;	}	/* Find a free hisax interface */	for (u = 0; u < AUER_MAX_DEVICES; u++) {		ahp = &auerhisax_table[u];		if (!ahp->cp) {			first_time = (u == 0);			goto ahp_found;		}	}	/* no free interface found */	return -12;	/* we found a free hisax interface */      ahp_found:	/* Wait until ipppd timeout expired. The reason behind this ugly construct:	   If we connect to a hisax device without waiting for ipppd we are not able	   to make a new IP connection. */	if (ahp->last_close) {		unsigned long timeout = jiffies - ahp->last_close;		if (timeout < AUISDN_IPTIMEOUT) {			info("waiting for ipppd to timeout");			sleep_on_timeout(&wqh, AUISDN_IPTIMEOUT - timeout);		}	}	cp->isdn.ahp = ahp;	u = ahp->hisax_registered;	ahp->hisax_registered = 1;	ahp->cp = cp;	/* now do the registration */	if (!u) {		for (u = 0; u < AUISDN_BCHANNELS; u++) {			b_if[u] = &ahp->hisax_b_if[u];		}		if (hisax_register		    (&ahp->hisax_d_if, b_if, "auerswald_usb",		     ISDN_PTYPE_EURO)) {			err("hisax registration failed");			ahp->cp = NULL;			cp->isdn.ahp = NULL;			ahp->hisax_registered = 0;			return -13;		}		dbg("hisax interface registered");	}	/* send a D channel L1 activation indication to hisax */	auerisdn_d_l1l2(&cp->isdn, PH_ACTIVATE | INDICATION, NULL);	cp->isdn.dc_activated = 1;	/* do another D channel activation for problematic devices */	cp->isdn.dcopen_timer.expires = jiffies + HZ;	dbg("add timer");	add_timer(&cp->isdn.dcopen_timer);	return 0;}/* The USB device was disconnected */void auerisdn_disconnect(struct auerswald *cp){	struct auerhisax *ahp;	DECLARE_WAIT_QUEUE_HEAD(wqh);	unsigned long flags;	unsigned int u;	int ret;	unsigned int stop_bc;	dbg("auerisdn_disconnect called");	/* stop a running timer */	del_timer_sync(&cp->isdn.dcopen_timer);	/* first, stop the B channels */	stop_bc = auerisdn_b_disconnect(cp);	/* stop the D channels */	auerisdn_d_l1l2(&cp->isdn, PH_DEACTIVATE | INDICATION, NULL);	cp->isdn.dc_activated = 0;	dbg("D-Channel disconnected");	/* Wait a moment */	sleep_on_timeout(&wqh, HZ / 10);	/* Shut the connection to the hisax interface */	ahp = cp->isdn.ahp;	if (ahp) {		dbg("closing connection to hisax interface");		ahp->cp = NULL;		cp->isdn.ahp = NULL;		/* time of last closure */		if (stop_bc)			/* if we kill a running connection ... */			ahp->last_close = jiffies;		else			ahp->last_close = 0;	}	/* Now free the memory */	if (cp->isdn.intbi_urbp) {		ret = usb_unlink_urb(cp->isdn.intbi_urbp);		if (ret)			dbg("B in: nonzero int unlink result received: %d",			    ret);		usb_free_urb(cp->isdn.intbi_urbp);		cp->isdn.intbi_urbp = NULL;	}	kfree(cp->isdn.intbi_bufp);	cp->isdn.intbi_bufp = NULL;		if (cp->isdn.intbo_urbp) {		cp->isdn.intbo_urbp->transfer_flags &= ~USB_ASYNC_UNLINK;		ret = usb_unlink_urb(cp->isdn.intbo_urbp);		if (ret)			dbg("B out: nonzero int unlink result received: %d", ret);		usb_free_urb(cp->isdn.intbo_urbp);		cp->isdn.intbo_urbp = NULL;	}	kfree(cp->isdn.intbo_bufp);	cp->isdn.intbo_bufp = NULL;	/* Remove the rx and tx buffers */	for (u = 0; u < AUISDN_BCHANNELS; u++) {		kfree(cp->isdn.bc[u].rxbuf);		cp->isdn.bc[u].rxbuf = NULL;		spin_lock_irqsave(&cp->isdn.bc[u].txskb_lock, flags);		if (cp->isdn.bc[u].txskb) {			skb_pull(cp->isdn.bc[u].txskb,				 cp->isdn.bc[u].txskb->len);			dev_kfree_skb_any(cp->isdn.bc[u].txskb);			cp->isdn.bc[u].txskb = NULL;		}		spin_unlock_irqrestore(&cp->isdn.bc[u].txskb_lock, flags);	}	/* Remove the D-channel connection */	auerswald_removeservice(cp, &cp->isdn.dchannelservice);}/*-------------------------------------------------------------------*//* Environment for long-lasting hisax interface                      *//* Wrapper for hisax B0 channel L2L1 */static void auerisdn_b0_l2l1_wrapper(struct hisax_if *ifc, int pr,				     void *arg){	auerisdn_b_l2l1(ifc, pr, arg, 0);}/* Wrapper for hisax B1 channel L2L1 */static void auerisdn_b1_l2l1_wrapper(struct hisax_if *ifc, int pr,				     void *arg){	auerisdn_b_l2l1(ifc, pr, arg, 1);}/* Init the global variables */void auerisdn_init(void){	struct auerhisax *ahp;	unsigned int u;	memset(&auerhisax_table, 0, sizeof(auerhisax_table));	for (u = 0; u < AUER_MAX_DEVICES; u++) {		ahp = &auerhisax_table[u];		spin_lock_init(&ahp->seq_lock);		ahp->hisax_d_if.ifc.priv = ahp;		ahp->hisax_d_if.ifc.l2l1 = auerisdn_d_l2l1;		ahp->hisax_b_if[0].ifc.priv = ahp;		ahp->hisax_b_if[0].ifc.l2l1 = auerisdn_b0_l2l1_wrapper;		ahp->hisax_b_if[1].ifc.priv = ahp;		ahp->hisax_b_if[1].ifc.l2l1 = auerisdn_b1_l2l1_wrapper;	}}/* Deinit the global variables */void auerisdn_cleanup(void){	struct auerhisax *ahp;	int i;	/* cleanup last allocated device first */	for (i = AUER_MAX_DEVICES - 1; i >= 0; i--) {		ahp = &auerhisax_table[i];		if (ahp->cp) {			err("hisax device %d open at cleanup", i);		}		if (ahp->hisax_registered) {			hisax_unregister(&ahp->hisax_d_if);			dbg("hisax interface %d freed", i);		}	}}

⌨️ 快捷键说明

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