📄 hfc_usb.c
字号:
{ 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]; } hfc->protocol = 2; /* default EURO ISDN, should be a module_param */ hisax_register(&hfc->d_if, p_b_if, "hfc_usb", hfc->protocol); 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); // Int IN D-fifo if(hfc->fifos[HFCUSB_PCM_RX].pipe) start_int_fifo(hfc->fifos + HFCUSB_PCM_RX); // E-fifo start_int_fifo(hfc->fifos + HFCUSB_B1_RX); // Int IN B1-fifo start_int_fifo(hfc->fifos + HFCUSB_B2_RX); // Int IN B2-fifo } // 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);} /* usb_init *//****************************************//* data defining the devices to be used *//****************************************/// static __devinitdata const struct usb_device_id hfc_usb_idtab[3] = {static struct usb_device_id hfc_usb_idtab[] = { {USB_DEVICE(0x7b0, 0x0007)}, /* Billion USB TA 2 */ {USB_DEVICE(0x742, 0x2008)}, /* Stollmann USB TA */ {USB_DEVICE(0x959, 0x2bd0)}, /* Colognechip USB eval TA */ {USB_DEVICE(0x8e3, 0x0301)}, /* OliTec ISDN USB */ {USB_DEVICE(0x675, 0x1688)}, /* DrayTec ISDN USB */ {USB_DEVICE(0x7fa, 0x0846)}, /* Bewan ISDN USB TA */ {} /* end with an all-zeroes entry */};MODULE_AUTHOR("Peter Sprenger (sprenger@moving-byters.de)/Martin Bachem (info@colognechip.com)");MODULE_DESCRIPTION("HFC I4L USB driver");MODULE_DEVICE_TABLE(usb, hfc_usb_idtab);MODULE_LICENSE("GPL");#define EP_NUL 1 // Endpoint at this position not allowed#define EP_NOP 2 // all type of endpoints allowed at this position#define EP_ISO 3 // Isochron endpoint mandatory at this position#define EP_BLK 4 // Bulk endpoint mandatory at this position#define EP_INT 5 // Interrupt endpoint mandatory at this position// this array represents all endpoints possible in the HCF-USB// the last 2 entries are the configuration number and the minimum interval for Interrupt endpointsint validconf[][18]={ // INT in, ISO out config {EP_NUL,EP_INT,EP_NUL,EP_INT,EP_NUL,EP_INT,EP_NOP,EP_INT,EP_ISO,EP_NUL,EP_ISO,EP_NUL,EP_ISO,EP_NUL,EP_NUL,EP_NUL,CNF_4INT3ISO,2}, {EP_NUL,EP_INT,EP_NUL,EP_INT,EP_NUL,EP_INT,EP_NUL,EP_NUL,EP_ISO,EP_NUL,EP_ISO,EP_NUL,EP_ISO,EP_NUL,EP_NUL,EP_NUL,CNF_3INT3ISO,2}, // ISO in, ISO out config {EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_NOP,EP_ISO,CNF_4ISO3ISO,2}, {EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_NUL,EP_NUL,CNF_3ISO3ISO,2}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} // EOL element};// string description of chosen configchar *conf_str[]={ "4 Interrupt IN + 3 Isochron OUT", "3 Interrupt IN + 3 Isochron OUT", "4 Isochron IN + 3 Isochron OUT", "3 Isochron IN + 3 Isochron OUT"};/*************************************************//* function called to probe a new plugged device *//*************************************************/static int hfc_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;// usb_show_device(dev);// usb_show_device_descriptor(&dev->descriptor);// usb_show_interface_descriptor(&iface->desc); vend_idx=0xffff; for(i=0;vdata[i].vendor;i++) { if (le16_to_cpu(dev->descriptor.idVendor) == vdata[i].vendor && le16_to_cpu(dev->descriptor.idProduct) == vdata[i].prod_id) vend_idx = i; } #ifdef VERBOSE_USB_DEBUG printk(KERN_INFO "HFC-USB: probing interface(%d) actalt(%d) minor(%d)\n", ifnum, iface->desc.bAlternateSetting, intf->minor);#endif if (vend_idx != 0xffff) {#ifdef VERBOSE_USB_DEBUG printk(KERN_INFO "HFC-USB: found vendor idx:%d name:%s\n",vend_idx,vdata[vend_idx].vend_name);#endif /* if vendor and product ID is OK, start probing a matching alternate setting ... */ 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;#ifdef VERBOSE_USB_DEBUG printk(KERN_INFO "HFC-USB: test alt_setting %d\n", probe_alt_setting);#endif // check for config EOL element while (validconf[cfg_used][0]) { cfg_found=TRUE; vcf=validconf[cfg_used]; ep = iface->endpoint; /* first endpoint descriptor */#ifdef VERBOSE_USB_DEBUG printk(KERN_INFO "HFC-USB: (if=%d alt=%d cfg_used=%d)\n", ifnum, probe_alt_setting, cfg_used);#endif // copy table 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; idx = ((ep_addr & 0x7f)-1)*2; /* get endpoint base */ if (ep_addr & 0x80) idx++; attr = ep->desc.bmAttributes; if (cmptbl[idx] == EP_NUL) { printk(KERN_INFO "HFC-USB: cfg_found=FALSE in idx:%d attr:%d cmptbl[%d]:%d\n", idx, attr, idx, cmptbl[idx]); cfg_found = FALSE; } 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]) {#ifdef VERBOSE_USB_DEBUG if (cfg_found) printk(KERN_INFO "HFC-USB: Interrupt Endpoint interval < %d found - skipping config\n", vcf[17]);#endif cfg_found = FALSE; } ep++; } for (i = 0; i < 16; i++) { // printk(KERN_INFO "HFC-USB: cmptbl[%d]:%d\n", i, cmptbl[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 = FALSE; } // we check for smallest match, to provide configuration priority // configurations with smaller index have higher priority if (cfg_found) { if (cfg_used < small_match) { small_match = cfg_used; alt_used = probe_alt_setting; iface_used = iface; }#ifdef VERBOSE_USB_DEBUG printk(KERN_INFO "HFC-USB: small_match=%x %x\n", small_match, alt_used);#endif } cfg_used++; } alt_idx++; } /* (alt_idx < intf->num_altsetting) */#ifdef VERBOSE_USB_DEBUG printk(KERN_INFO "HFC-USB: final small_match=%x alt_used=%x\n",small_match, alt_used);#endif // yiipiee, we found a valid config if (small_match != 0xffff) { iface = iface_used; if (!(context = kmalloc(sizeof(hfcusb_data), GFP_KERNEL))) return(-ENOMEM); /* got no mem */ memset(context, 0, sizeof(hfcusb_data)); /* clear the structure */ ep = iface->endpoint; /* first endpoint descriptor */ vcf = validconf[small_match]; for (i = 0; i < iface->desc.bNumEndpoints; i++) { ep_addr = ep->desc.bEndpointAddress; idx = ((ep_addr & 0x7f)-1)*2; /* get endpoint base */ if (ep_addr & 0x80) idx++; cidx = idx & 7; attr = ep->desc.bmAttributes; // only initialize used 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); // remember max packet size#ifdef VERBOSE_USB_DEBUG printk (KERN_INFO "HFC-USB: Interrupt-In Endpoint found %d ms(idx:%d cidx:%d)!\n", ep->desc.bInterval, idx, cidx);#endif 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); // remember max packet size#ifdef VERBOSE_USB_DEBUG printk (KERN_INFO "HFC-USB: Bulk Endpoint found (idx:%d cidx:%d)!\n", idx, cidx);#endif 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); // remember max packet size#ifdef VERBOSE_USB_DEBUG printk (KERN_INFO "HFC-USB: ISO Endpoint found (idx:%d cidx:%d)!\n", idx, cidx);#endif break; default: context->fifos[cidx].pipe = 0; /* reset data */ } /* 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;#ifdef VERBOSE_USB_DEBUG printk (KERN_INFO "HFC-USB: fifo%d pktlen %d interval %d\n", context->fifos[cidx].fifonum, context->fifos[cidx].usb_packet_maxlen, context->fifos[cidx].intervall);#endif } } ep++; } // now share our luck 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); printk(KERN_INFO "HFC-USB: detected \"%s\" configuration: %s (if=%d alt=%d)\n", vdata[vend_idx].vend_name, conf_str[small_match], context->if_used, context->alt_used); /* init the chip and register the driver */ if (usb_init(context)) { if (context->ctrl_urb) { usb_unlink_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); } } return(-EIO);}/****************************************************//* function called when an active device is removed *//****************************************************/static void hfc_usb_disconnect(struct usb_interface *intf){ hfcusb_data *context = usb_get_intfdata(intf); int i; printk(KERN_INFO "HFC-USB: device disconnect\n"); usb_set_intfdata(intf, NULL); if (!context) return; if (timer_pending(&context->t3_timer)) del_timer(&context->t3_timer); if (timer_pending(&context->t4_timer)) del_timer(&context->t4_timer); if (timer_pending(&context->led_timer)) del_timer(&context->led_timer); hisax_unregister(&context->d_if); /* 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]);#ifdef VERBOSE_USB_DEBUG printk (KERN_INFO "HFC-USB: hfc_usb_disconnect: stopping ISOC chain Fifo no %i\n", i);#endif } } else { if(context->fifos[i].active > 0) { context->fifos[i].active = 0;#ifdef VERBOSE_USB_DEBUG printk (KERN_INFO "HFC-USB: hfc_usb_disconnect: unlinking URB for Fifo no %i\n", i);#endif } if (context->fifos[i].urb) { usb_unlink_urb(context->fifos[i].urb); usb_free_urb(context->fifos[i].urb); context->fifos[i].urb = NULL; } } context->fifos[i].active = 0; } if (context->ctrl_urb) { usb_unlink_urb(context->ctrl_urb); usb_free_urb(context->ctrl_urb); context->ctrl_urb = NULL; } kfree(context); /* free our structure again */} /* hfc_usb_disconnect *//************************************//* our driver information structure *//************************************/static struct usb_driver hfc_drv = { .owner = THIS_MODULE, .name = "hfc_usb", .id_table = hfc_usb_idtab, .probe = hfc_usb_probe, .disconnect = hfc_usb_disconnect,};static void __exit hfc_usb_exit(void){#ifdef VERBOSE_USB_DEBUG printk ("HFC-USB: calling \"hfc_usb_exit\" ...\n");#endif usb_deregister(&hfc_drv); /* release our driver */ printk(KERN_INFO "HFC-USB module removed\n");}static int __init hfc_usb_init(void){ printk ("HFC-USB: driver module revision %s loaded\n", hfcusb_revision); if(usb_register(&hfc_drv)) { printk(KERN_INFO "HFC-USB: Unable to register HFC-USB module at usb stack\n"); return(-1); /* unable to register */ } return(0);}module_init(hfc_usb_init);module_exit(hfc_usb_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -