hfc_usb.c

来自「linux 内核源代码」· C语言 代码 · 共 1,609 行 · 第 1/3 页

C
1,609
字号
				fifo->hif->l1l2(fifo->hif,						PH_DEACTIVATE | INDICATION,						NULL);			}			break;		case PH_DATA | REQUEST:			if (fifo->skbuff && fifo->delete_flg) {				dev_kfree_skb_any(fifo->skbuff);				fifo->skbuff = NULL;				fifo->delete_flg = 0;			}			fifo->skbuff = arg;	/* we have a new buffer */			break;		default:			DBG(HFCUSB_DBG_STATES,			       "HFC_USB: hfc_usb_d_l2l1: unkown state : %#x", pr);			break;	}}/* initial init HFC-S USB chip registers, HiSax interface, USB URBs */static inthfc_usb_init(hfcusb_data * hfc){	usb_fifo *fifo;	int i, err;	u_char b;	struct hisax_b_if *p_b_if[2];	/* check the chip id */	if (read_usb(hfc, HFCUSB_CHIP_ID, &b) != 1) {		printk(KERN_INFO "HFC-USB: cannot read chip id\n");		return (1);	}	if (b != HFCUSB_CHIPID) {		printk(KERN_INFO "HFC-S USB: Invalid chip id 0x%02x\n", b);		return (1);	}	/* first set the needed config, interface and alternate */	err = usb_set_interface(hfc->dev, hfc->if_used, hfc->alt_used);	/* do Chip reset */	write_usb(hfc, HFCUSB_CIRM, 8);	/* aux = output, reset off */	write_usb(hfc, HFCUSB_CIRM, 0x10);	/* set USB_SIZE to match wMaxPacketSize for INT or BULK transfers */	write_usb(hfc, HFCUSB_USB_SIZE,		  (hfc->packet_size / 8) | ((hfc->packet_size / 8) << 4));	/* set USB_SIZE_I to match wMaxPacketSize for ISO transfers */	write_usb(hfc, HFCUSB_USB_SIZE_I, hfc->iso_packet_size);	/* enable PCM/GCI master mode */	write_usb(hfc, HFCUSB_MST_MODE1, 0);	/* set default values */	write_usb(hfc, HFCUSB_MST_MODE0, 1);	/* enable master mode */	/* init the fifos */	write_usb(hfc, HFCUSB_F_THRES,		  (HFCUSB_TX_THRESHOLD /		   8) | ((HFCUSB_RX_THRESHOLD / 8) << 4));	fifo = hfc->fifos;	for (i = 0; i < HFCUSB_NUM_FIFOS; i++) {		write_usb(hfc, HFCUSB_FIFO, i);	/* select the desired fifo */		fifo[i].skbuff = NULL;	/* init buffer pointer */		fifo[i].max_size =		    (i <= HFCUSB_B2_RX) ? MAX_BCH_SIZE : MAX_DFRAME_LEN;		fifo[i].last_urblen = 0;		/* set 2 bit for D- & E-channel */		write_usb(hfc, HFCUSB_HDLC_PAR,			  ((i <= HFCUSB_B2_RX) ? 0 : 2));		/* rx hdlc, enable IFF for D-channel */		write_usb(hfc, HFCUSB_CON_HDLC,			  ((i == HFCUSB_D_TX) ? 0x09 : 0x08));		write_usb(hfc, HFCUSB_INC_RES_F, 2);	/* reset the fifo */	}	write_usb(hfc, HFCUSB_CLKDEL, 0x0f);	/* clock delay value */	write_usb(hfc, HFCUSB_STATES, 3 | 0x10);	/* set deactivated mode */	write_usb(hfc, HFCUSB_STATES, 3);	/* enable state machine */	write_usb(hfc, HFCUSB_SCTRL_R, 0);	/* disable both B receivers */	write_usb(hfc, HFCUSB_SCTRL, 0x40);	/* disable B transmitters + capacitive mode */	/* set both B-channel to not connected */	hfc->b_mode[0] = L1_MODE_NULL;	hfc->b_mode[1] = L1_MODE_NULL;	hfc->l1_activated = 0;	hfc->disc_flag = 0;	hfc->led_state = 0;	hfc->old_led_state = 0;	/* init the t3 timer */	init_timer(&hfc->t3_timer);	hfc->t3_timer.data = (long) hfc;	hfc->t3_timer.function = (void *) l1_timer_expire_t3;	/* init the t4 timer */	init_timer(&hfc->t4_timer);	hfc->t4_timer.data = (long) hfc;	hfc->t4_timer.function = (void *) l1_timer_expire_t4;	/* init the background machinery for control requests */	hfc->ctrl_read.bRequestType = 0xc0;	hfc->ctrl_read.bRequest = 1;	hfc->ctrl_read.wLength = cpu_to_le16(1);	hfc->ctrl_write.bRequestType = 0x40;	hfc->ctrl_write.bRequest = 0;	hfc->ctrl_write.wLength = 0;	usb_fill_control_urb(hfc->ctrl_urb,			     hfc->dev,			     hfc->ctrl_out_pipe,			     (u_char *) & hfc->ctrl_write,			     NULL, 0, ctrl_complete, hfc);	/* Init All Fifos */	for (i = 0; i < HFCUSB_NUM_FIFOS; i++) {		hfc->fifos[i].iso[0].purb = NULL;		hfc->fifos[i].iso[1].purb = NULL;		hfc->fifos[i].active = 0;	}	/* register Modul to upper Hisax Layers */	hfc->d_if.owner = THIS_MODULE;	hfc->d_if.ifc.priv = &hfc->fifos[HFCUSB_D_TX];	hfc->d_if.ifc.l2l1 = hfc_usb_l2l1;	for (i = 0; i < 2; i++) {		hfc->b_if[i].ifc.priv = &hfc->fifos[HFCUSB_B1_TX + i * 2];		hfc->b_if[i].ifc.l2l1 = hfc_usb_l2l1;		p_b_if[i] = &hfc->b_if[i];	}	/* default Prot: EURO ISDN, should be a module_param */	hfc->protocol = 2;	i = hisax_register(&hfc->d_if, p_b_if, "hfc_usb", hfc->protocol);	if (i) {		printk(KERN_INFO "HFC-S USB: hisax_register -> %d\n", i);		return i;	}#ifdef CONFIG_HISAX_DEBUG	hfc_debug = debug;#endif	for (i = 0; i < 4; i++)		hfc->fifos[i].hif = &p_b_if[i / 2]->ifc;	for (i = 4; i < 8; i++)		hfc->fifos[i].hif = &hfc->d_if.ifc;	/* 3 (+1) INT IN + 3 ISO OUT */	if (hfc->cfg_used == CNF_3INT3ISO || hfc->cfg_used == CNF_4INT3ISO) {		start_int_fifo(hfc->fifos + HFCUSB_D_RX);		if (hfc->fifos[HFCUSB_PCM_RX].pipe)			start_int_fifo(hfc->fifos + HFCUSB_PCM_RX);		start_int_fifo(hfc->fifos + HFCUSB_B1_RX);		start_int_fifo(hfc->fifos + HFCUSB_B2_RX);	}	/* 3 (+1) ISO IN + 3 ISO OUT */	if (hfc->cfg_used == CNF_3ISO3ISO || hfc->cfg_used == CNF_4ISO3ISO) {		start_isoc_chain(hfc->fifos + HFCUSB_D_RX, ISOC_PACKETS_D,				 rx_iso_complete, 16);		if (hfc->fifos[HFCUSB_PCM_RX].pipe)			start_isoc_chain(hfc->fifos + HFCUSB_PCM_RX,					 ISOC_PACKETS_D, rx_iso_complete,					 16);		start_isoc_chain(hfc->fifos + HFCUSB_B1_RX, ISOC_PACKETS_B,				 rx_iso_complete, 16);		start_isoc_chain(hfc->fifos + HFCUSB_B2_RX, ISOC_PACKETS_B,				 rx_iso_complete, 16);	}	start_isoc_chain(hfc->fifos + HFCUSB_D_TX, ISOC_PACKETS_D,			 tx_iso_complete, 1);	start_isoc_chain(hfc->fifos + HFCUSB_B1_TX, ISOC_PACKETS_B,			 tx_iso_complete, 1);	start_isoc_chain(hfc->fifos + HFCUSB_B2_TX, ISOC_PACKETS_B,			 tx_iso_complete, 1);	handle_led(hfc, LED_POWER_ON);	return (0);}/* initial callback for each plugged USB device */static inthfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id){	struct usb_device *dev = interface_to_usbdev(intf);	hfcusb_data *context;	struct usb_host_interface *iface = intf->cur_altsetting;	struct usb_host_interface *iface_used = NULL;	struct usb_host_endpoint *ep;	int ifnum = iface->desc.bInterfaceNumber;	int i, idx, alt_idx, probe_alt_setting, vend_idx, cfg_used, *vcf,	    attr, cfg_found, cidx, ep_addr;	int cmptbl[16], small_match, iso_packet_size, packet_size,	    alt_used = 0;	hfcsusb_vdata *driver_info;	vend_idx = 0xffff;	for (i = 0; hfcusb_idtab[i].idVendor; i++) {		if ((le16_to_cpu(dev->descriptor.idVendor) == hfcusb_idtab[i].idVendor)		    && (le16_to_cpu(dev->descriptor.idProduct) == hfcusb_idtab[i].idProduct)) {			vend_idx = i;			continue;		}	}	printk(KERN_INFO	       "HFC-S USB: probing interface(%d) actalt(%d) minor(%d)\n",	       ifnum, iface->desc.bAlternateSetting, intf->minor);	if (vend_idx != 0xffff) {		/* if vendor and product ID is OK, start probing alternate settings */		alt_idx = 0;		small_match = 0xffff;		/* default settings */		iso_packet_size = 16;		packet_size = 64;		while (alt_idx < intf->num_altsetting) {			iface = intf->altsetting + alt_idx;			probe_alt_setting = iface->desc.bAlternateSetting;			cfg_used = 0;			/* check for config EOL element */			while (validconf[cfg_used][0]) {				cfg_found = 1;				vcf = validconf[cfg_used];				/* first endpoint descriptor */				ep = iface->endpoint;				memcpy(cmptbl, vcf, 16 * sizeof(int));				/* check for all endpoints in this alternate setting */				for (i = 0; i < iface->desc.bNumEndpoints;				     i++) {					ep_addr =					    ep->desc.bEndpointAddress;					/* get endpoint base */					idx = ((ep_addr & 0x7f) - 1) * 2;					if (ep_addr & 0x80)						idx++;					attr = ep->desc.bmAttributes;					if (cmptbl[idx] == EP_NUL) {						cfg_found = 0;					}					if (attr == USB_ENDPOINT_XFER_INT					    && cmptbl[idx] == EP_INT)						cmptbl[idx] = EP_NUL;					if (attr == USB_ENDPOINT_XFER_BULK					    && cmptbl[idx] == EP_BLK)						cmptbl[idx] = EP_NUL;					if (attr == USB_ENDPOINT_XFER_ISOC					    && cmptbl[idx] == EP_ISO)						cmptbl[idx] = EP_NUL;					/* check if all INT endpoints match minimum interval */					if ((attr == USB_ENDPOINT_XFER_INT)					    && (ep->desc.bInterval < vcf[17])) {						cfg_found = 0;					}					ep++;				}				for (i = 0; i < 16; i++) {					/* all entries must be EP_NOP or EP_NUL for a valid config */					if (cmptbl[i] != EP_NOP					    && cmptbl[i] != EP_NUL)						cfg_found = 0;				}				if (cfg_found) {					if (cfg_used < small_match) {						small_match = cfg_used;						alt_used =						    probe_alt_setting;						iface_used = iface;					}				}				cfg_used++;			}			alt_idx++;		} /* (alt_idx < intf->num_altsetting) */		/* found a valid USB Ta Endpint config */		if (small_match != 0xffff) {			iface = iface_used;			if (!(context = kzalloc(sizeof(hfcusb_data), GFP_KERNEL)))				return (-ENOMEM);	/* got no mem */			ep = iface->endpoint;			vcf = validconf[small_match];			for (i = 0; i < iface->desc.bNumEndpoints; i++) {				ep_addr = ep->desc.bEndpointAddress;				/* get endpoint base */				idx = ((ep_addr & 0x7f) - 1) * 2;				if (ep_addr & 0x80)					idx++;				cidx = idx & 7;				attr = ep->desc.bmAttributes;				/* init Endpoints */				if (vcf[idx] != EP_NOP				    && vcf[idx] != EP_NUL) {					switch (attr) {						case USB_ENDPOINT_XFER_INT:							context->							    fifos[cidx].							    pipe =							    usb_rcvintpipe							    (dev,							     ep->desc.							     bEndpointAddress);							context->							    fifos[cidx].							    usb_transfer_mode							    = USB_INT;							packet_size =							    le16_to_cpu(ep->desc.wMaxPacketSize);							break;						case USB_ENDPOINT_XFER_BULK:							if (ep_addr & 0x80)								context->								    fifos								    [cidx].								    pipe =								    usb_rcvbulkpipe								    (dev,								     ep->								     desc.								     bEndpointAddress);							else								context->								    fifos								    [cidx].								    pipe =								    usb_sndbulkpipe								    (dev,								     ep->								     desc.								     bEndpointAddress);							context->							    fifos[cidx].							    usb_transfer_mode							    = USB_BULK;							packet_size =							    le16_to_cpu(ep->desc.wMaxPacketSize);							break;						case USB_ENDPOINT_XFER_ISOC:							if (ep_addr & 0x80)								context->								    fifos								    [cidx].								    pipe =								    usb_rcvisocpipe								    (dev,								     ep->								     desc.								     bEndpointAddress);							else								context->								    fifos								    [cidx].								    pipe =								    usb_sndisocpipe								    (dev,								     ep->								     desc.								     bEndpointAddress);							context->							    fifos[cidx].							    usb_transfer_mode							    = USB_ISOC;							iso_packet_size =							    le16_to_cpu(ep->desc.wMaxPacketSize);							break;						default:							context->							    fifos[cidx].							    pipe = 0;					}	/* switch attribute */					if (context->fifos[cidx].pipe) {						context->fifos[cidx].						    fifonum = cidx;						context->fifos[cidx].hfc =						    context;						context->fifos[cidx].usb_packet_maxlen =						    le16_to_cpu(ep->desc.wMaxPacketSize);						context->fifos[cidx].						    intervall =						    ep->desc.bInterval;						context->fifos[cidx].						    skbuff = NULL;					}				}				ep++;			}			context->dev = dev;	/* save device */			context->if_used = ifnum;	/* save used interface */			context->alt_used = alt_used;	/* and alternate config */			context->ctrl_paksize = dev->descriptor.bMaxPacketSize0;	/* control size */			context->cfg_used = vcf[16];	/* store used config */			context->vend_idx = vend_idx;	/* store found vendor */			context->packet_size = packet_size;			context->iso_packet_size = iso_packet_size;			/* create the control pipes needed for register access */			context->ctrl_in_pipe =			    usb_rcvctrlpipe(context->dev, 0);			context->ctrl_out_pipe =			    usb_sndctrlpipe(context->dev, 0);			context->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);			driver_info =			    (hfcsusb_vdata *) hfcusb_idtab[vend_idx].			    driver_info;			printk(KERN_INFO "HFC-S USB: detected \"%s\"\n",			       driver_info->vend_name);			DBG(HFCUSB_DBG_INIT,			    "HFC-S USB: Endpoint-Config: %s (if=%d alt=%d), E-Channel(%d)",			    conf_str[small_match], context->if_used,			    context->alt_used,			    validconf[small_match][18]);			/* init the chip and register the driver */			if (hfc_usb_init(context)) {				usb_kill_urb(context->ctrl_urb);				usb_free_urb(context->ctrl_urb);				context->ctrl_urb = NULL;				kfree(context);				return (-EIO);			}			usb_set_intfdata(intf, context);			return (0);		}	} else {		printk(KERN_INFO		       "HFC-S USB: no valid vendor found in USB descriptor\n");	}	return (-EIO);}/* callback for unplugged USB device */static voidhfc_usb_disconnect(struct usb_interface *intf){	hfcusb_data *context = usb_get_intfdata(intf);	int i;	handle_led(context, LED_POWER_OFF);	schedule_timeout(HZ / 100);	printk(KERN_INFO "HFC-S USB: device disconnect\n");	context->disc_flag = 1;	usb_set_intfdata(intf, NULL);	if (timer_pending(&context->t3_timer))		del_timer(&context->t3_timer);	if (timer_pending(&context->t4_timer))		del_timer(&context->t4_timer);	/* tell all fifos to terminate */	for (i = 0; i < HFCUSB_NUM_FIFOS; i++) {		if (context->fifos[i].usb_transfer_mode == USB_ISOC) {			if (context->fifos[i].active > 0) {				stop_isoc_chain(&context->fifos[i]);				DBG(HFCUSB_DBG_INIT,				    "HFC-S USB: %s stopping ISOC chain Fifo(%i)",				    __FUNCTION__, i);			}		} else {			if (context->fifos[i].active > 0) {				context->fifos[i].active = 0;				DBG(HFCUSB_DBG_INIT,				    "HFC-S USB: %s unlinking URB for Fifo(%i)",				    __FUNCTION__, i);			}			usb_kill_urb(context->fifos[i].urb);			usb_free_urb(context->fifos[i].urb);			context->fifos[i].urb = NULL;		}		context->fifos[i].active = 0;	}	usb_kill_urb(context->ctrl_urb);	usb_free_urb(context->ctrl_urb);	context->ctrl_urb = NULL;	hisax_unregister(&context->d_if);	kfree(context);		/* free our structure again */}static struct usb_driver hfc_drv = {	.name  = "hfc_usb",	.id_table = hfcusb_idtab,	.probe = hfc_usb_probe,	.disconnect = hfc_usb_disconnect,};static void __exithfc_usb_mod_exit(void){	usb_deregister(&hfc_drv); /* release our driver */	printk(KERN_INFO "HFC-S USB: module removed\n");}static int __inithfc_usb_mod_init(void){	char revstr[30], datestr[30], dummy[30];#ifndef CONFIG_HISAX_DEBUG	hfc_debug = debug;#endif	sscanf(hfcusb_revision,	       "%s %s $ %s %s %s $ ", dummy, revstr,	       dummy, datestr, dummy);	printk(KERN_INFO	       "HFC-S USB: driver module revision %s date %s loaded, (debug=%i)\n",	       revstr, datestr, debug);	if (usb_register(&hfc_drv)) {		printk(KERN_INFO		       "HFC-S USB: Unable to register HFC-S USB module at usb stack\n");		return (-1);	/* unable to register */	}	return (0);}module_init(hfc_usb_mod_init);module_exit(hfc_usb_mod_exit);MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE("GPL");MODULE_DEVICE_TABLE(usb, hfcusb_idtab);

⌨️ 快捷键说明

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