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 + -
显示快捷键?