📄 hfc_usb.c
字号:
} /* rx_iso_complete *//*****************************************************//* collect data from interrupt or isochron in *//*****************************************************/static void collect_rx_frame(usb_fifo *fifo,__u8 *data,int len,int finish){ hfcusb_data *hfc = fifo->hfc; int transp_mode,fifon; fifon=fifo->fifonum; transp_mode=0; if(fifon<4 && hfc->b_mode[fifon/2]==L1_MODE_TRANS) transp_mode=TRUE; //printk(KERN_INFO "HFC-USB: got %d bytes finish:%d max_size:%d fifo:%d\n",len,finish,fifo->max_size,fifon); if(!fifo->skbuff) { // allocate sk buffer fifo->skbuff=dev_alloc_skb(fifo->max_size + 3); if(!fifo->skbuff) { printk(KERN_INFO "HFC-USB: cannot allocate buffer (dev_alloc_skb) fifo:%d\n",fifon); return; } } if(len && fifo->skbuff->len+len<fifo->max_size) { memcpy(skb_put(fifo->skbuff,len),data,len); } else printk(KERN_INFO "HCF-USB: got frame exceeded fifo->max_size:%d\n",fifo->max_size); // give transparent data up, when 128 byte are available if(transp_mode && fifo->skbuff->len>=128) { fifo->hif->l1l2(fifo->hif,PH_DATA | INDICATION,fifo->skbuff); fifo->skbuff = NULL; // buffer was freed from upper layer return; } // we have a complete hdlc packet if(finish) { if(!fifo->skbuff->data[fifo->skbuff->len-1]) { skb_trim(fifo->skbuff,fifo->skbuff->len-3); // remove CRC & status //printk(KERN_INFO "HFC-USB: got frame %d bytes on fifo:%d\n",fifo->skbuff->len,fifon); if(fifon==HFCUSB_PCM_RX) fifo->hif->l1l2(fifo->hif,PH_DATA_E | INDICATION,fifo->skbuff); else fifo->hif->l1l2(fifo->hif,PH_DATA | INDICATION,fifo->skbuff); fifo->skbuff = NULL; // buffer was freed from upper layer } else { printk(KERN_INFO "HFC-USB: got frame %d bytes but CRC ERROR!!!\n",fifo->skbuff->len); skb_trim(fifo->skbuff,0); // clear whole buffer } } // LED flashing only in HDLC mode if(!transp_mode) { if(fifon==HFCUSB_B1_RX) handle_led(hfc,LED_B1_DATA); if(fifon==HFCUSB_B2_RX) handle_led(hfc,LED_B2_DATA); }}/***********************************************//* receive completion routine for all rx fifos *//***********************************************/static void rx_complete(struct urb *urb, struct pt_regs *regs){ int len; __u8 *buf; usb_fifo *fifo = (usb_fifo *) urb->context; /* pointer to our fifo */ hfcusb_data *hfc = fifo->hfc; urb->dev = hfc->dev; /* security init */ if((!fifo->active) || (urb->status)) {#ifdef VERBOSE_USB_DEBUG printk(KERN_INFO "HFC-USB: RX-Fifo %i is going down (%i)\n", fifo->fifonum, urb->status);#endif fifo->urb->interval = 0; /* cancel automatic rescheduling */ if(fifo->skbuff) { dev_kfree_skb_any(fifo->skbuff); fifo->skbuff = NULL; } return; } len=urb->actual_length; buf=fifo->buffer; if(fifo->last_urblen!=fifo->usb_packet_maxlen) { // the threshold mask is in the 2nd status byte hfc->threshold_mask=buf[1]; // the S0 state is in the upper half of the 1st status byte state_handler(hfc,buf[0] >> 4); // if we have more than the 2 status bytes -> collect data if(len>2) collect_rx_frame(fifo,buf+2,urb->actual_length-2,buf[0]&1); } else collect_rx_frame(fifo,buf,urb->actual_length,0); fifo->last_urblen=urb->actual_length;} /* rx_complete *//***************************************************//* start the interrupt transfer for the given fifo *//***************************************************/static void start_int_fifo(usb_fifo * fifo){ int errcode;#ifdef VERBOSE_USB_DEBUG printk(KERN_INFO "HFC-USB: starting intr IN fifo:%d\n", fifo->fifonum);#endif if (!fifo->urb) { fifo->urb = usb_alloc_urb(0, GFP_KERNEL); if (!fifo->urb) return; } usb_fill_int_urb(fifo->urb, fifo->hfc->dev, fifo->pipe, fifo->buffer, fifo->usb_packet_maxlen, rx_complete, fifo, fifo->intervall); fifo->active = 1; /* must be marked active */ errcode = usb_submit_urb(fifo->urb, GFP_KERNEL); if(errcode) { printk(KERN_INFO "HFC-USB: submit URB error(start_int_info): status:%i\n", errcode); fifo->active = 0; fifo->skbuff = NULL; }} /* start_int_fifo *//*****************************//* set the B-channel mode *//*****************************/static void set_hfcmode(hfcusb_data *hfc,int channel,int mode){ __u8 val,idx_table[2]={0,2};#ifdef VERBOSE_ISDN_DEBUG printk (KERN_INFO "HFC-USB: setting channel %d to mode %d\n",channel,mode);#endif hfc->b_mode[channel]=mode; // setup CON_HDLC val=0; if(mode!=L1_MODE_NULL) val=8; // enable fifo? if(mode==L1_MODE_TRANS) val|=2; // set transparent bit queue_control_request(hfc,HFCUSB_FIFO,idx_table[channel],1); // set FIFO to transmit register queue_control_request(hfc,HFCUSB_CON_HDLC,val,1); queue_control_request(hfc,HFCUSB_INC_RES_F,2,1); // reset fifo queue_control_request(hfc,HFCUSB_FIFO,idx_table[channel]+1,1); // set FIFO to receive register queue_control_request(hfc,HFCUSB_CON_HDLC,val,1); queue_control_request(hfc,HFCUSB_INC_RES_F,2,1); // reset fifo val=0x40; if(hfc->b_mode[0]) val|=1; if(hfc->b_mode[1]) val|=2; queue_control_request(hfc,HFCUSB_SCTRL,val,1); val=0; if(hfc->b_mode[0]) val|=1; if(hfc->b_mode[1]) val|=2; queue_control_request(hfc,HFCUSB_SCTRL_R,val,1); if(mode==L1_MODE_NULL) { if(channel) handle_led(hfc,LED_B2_OFF); else handle_led(hfc,LED_B1_OFF); } else { if(channel) handle_led(hfc,LED_B2_ON); else handle_led(hfc,LED_B1_ON); }}/* -------------------------------------------------------------------------------------- from here : hisax_if callback routines : - void hfc_usb_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg) { l1 to l2 routines : - static void hfc_usb_l1l2(hfcusb_data * hfc)*/void hfc_usb_l2l1(struct hisax_if *my_hisax_if, int pr, void *arg){ usb_fifo *fifo = my_hisax_if->priv; hfcusb_data *hfc = fifo->hfc; switch (pr) { case PH_ACTIVATE | REQUEST: if(fifo->fifonum==HFCUSB_D_TX) {#ifdef VERBOSE_ISDN_DEBUG printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_ACTIVATE | REQUEST\n");#endif queue_control_request(hfc, HFCUSB_STATES,0x60,1); /* make activation */ hfc->t3_timer.expires = jiffies + (HFC_TIMER_T3 * HZ) / 1000; if(!timer_pending(&hfc->t3_timer)) add_timer(&hfc->t3_timer); } else {#ifdef VERBOSE_ISDN_DEBUG printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_ACTIVATE | REQUEST\n");#endif set_hfcmode(hfc,(fifo->fifonum==HFCUSB_B1_TX) ? 0 : 1 ,(int)arg); fifo->hif->l1l2(fifo->hif,PH_ACTIVATE | INDICATION, NULL); } break; case PH_DEACTIVATE | REQUEST: if(fifo->fifonum==HFCUSB_D_TX) {#ifdef VERBOSE_ISDN_DEBUG printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_DEACTIVATE | REQUEST\n");#endif printk (KERN_INFO "HFC-USB: ISDN TE device should not deativate...\n"); } else {#ifdef VERBOSE_ISDN_DEBUG printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_DEACTIVATE | REQUEST\n");#endif set_hfcmode(hfc,(fifo->fifonum==HFCUSB_B1_TX) ? 0 : 1 ,(int)L1_MODE_NULL); 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); //printk(KERN_INFO "skbuff=NULL on fifo:%d\n",fifo->fifonum); fifo->skbuff = NULL; fifo->delete_flg=FALSE; } fifo->skbuff=arg; // we have a new buffer //if(fifo->fifonum==HFCUSB_D_TX) printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_DATA | REQUEST\n"); //else printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_DATA | REQUEST\n"); break; default: printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1: unkown state : %#x\n", pr); break; }}// valid configurations#define CNF_4INT3ISO 1 // 4 INT IN, 3 ISO OUT#define CNF_3INT3ISO 2 // 3 INT IN, 3 ISO OUT#define CNF_4ISO3ISO 3 // 4 ISO IN, 3 ISO OUT#define CNF_3ISO3ISO 4 // 3 ISO IN, 3 ISO OUT/* -------------------------------------------------------------------------------------- From here on USB initialization and deactivation related routines are implemented : - hfc_usb_init : is the main Entry Point for the USB Subsystem when the device get plugged in. This function calls usb_register with usb_driver as parameter. Here, further entry points for probing (hfc_usb_probe) and disconnecting the device (hfc_usb_disconnect) are published, as the id_table - hfc_usb_probe this function is called by the usb subsystem, and steps through the alternate settings of the currently plugged in device to detect all Endpoints needed to run an ISDN TA. Needed EndPoints are 3 (+1) IntIn EndPoints (D-in, E-in, B1-in, B2-in, (E-in)) or 3 (+1) Isochron In Endpoints (D-out, B1-out, B2-out) and 3 IsoOut Endpoints The currently used transfer mode of on the Out-Endpoints will be stored in hfc->usb_transfer_mode and is either USB_INT or USB_ISO When a valid alternate setting could be found, the usb_init (see blow) function is called - usb_init Here, the HFC_USB Chip itself gets initialized and the USB framework to send/receive Data to/from the several EndPoints are initialized: The E- and D-Channel Int-In chain gets started The IsoChain for the Iso-Out traffic get started - hfc_usb_disconnect this function is called by the usb subsystem and has to free all resources and stop all usb traffic to allow a proper hotplugging disconnect.*//***************************************************************************//* usb_init is called once when a new matching device is detected to setup *//* main parameters. It registers the driver at the main hisax module. *//* on success 0 is returned. *//***************************************************************************/static int 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 */ printk(KERN_INFO "HFCUSB_CHIP_ID begin\n"); if (read_usb(hfc, HFCUSB_CHIP_ID, &b) != 1) { printk(KERN_INFO "HFC-USB: cannot read chip id\n"); return(1); } printk(KERN_INFO "HFCUSB_CHIP_ID %x\n", b); if (b != HFCUSB_CHIPID) { printk(KERN_INFO "HFC-USB: Invalid chip id 0x%02x\n", b); return(1); } /* first set the needed config, interface and alternate */ printk(KERN_INFO "usb_init 1\n");// usb_set_configuration(hfc->dev, 1); printk(KERN_INFO "usb_init 2\n"); err = usb_set_interface(hfc->dev, hfc->if_used, hfc->alt_used); printk(KERN_INFO "usb_init usb_set_interface return %d\n", err); /* now we initialize the chip */ write_usb(hfc, HFCUSB_CIRM, 8); // do reset write_usb(hfc, HFCUSB_CIRM, 0x10); // aux = output, reset off // set USB_SIZE to match the the 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 the the 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; write_usb(hfc, HFCUSB_HDLC_PAR, ((i <= HFCUSB_B2_RX) ? 0 : 2)); // set 2 bit for D- & E-channel write_usb(hfc, HFCUSB_CON_HDLC, ((i==HFCUSB_D_TX) ? 0x09 : 0x08)); // rx hdlc, enable IFF for D-channel 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=FALSE; hfc->led_state=0; hfc->led_new_data=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 led timer */ init_timer(&hfc->led_timer); hfc->led_timer.data = (long) hfc; hfc->led_timer.function = (void *) led_timer; // trigger 4 hz led timer hfc->led_timer.expires = jiffies + (LED_TIME * HZ) / 1000; if(!timer_pending(&hfc->led_timer)) add_timer(&hfc->led_timer); // init the background machinery for control requests hfc->ctrl_read.bRequestType = 0xc0; hfc->ctrl_read.bRequest = 1; hfc->ctrl_read.wLength = 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 like Germaschewski : 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++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -