📄 st5481_d.c
字号:
/* * Driver for ST5481 USB ISDN modem * * Author Frode Isaksen * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com> * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de> * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * */#include <linux/init.h>#include <linux/usb.h>#include <linux/slab.h>#include <linux/netdevice.h>#include "st5481.h"static void ph_connect(struct st5481_adapter *adapter);static void ph_disconnect(struct st5481_adapter *adapter);static struct Fsm l1fsm;static char *strL1State[] ={ "ST_L1_F3", "ST_L1_F4", "ST_L1_F6", "ST_L1_F7", "ST_L1_F8",};static char *strL1Event[] ={ "EV_IND_DP", "EV_IND_1", "EV_IND_2", "EV_IND_3", "EV_IND_RSY", "EV_IND_5", "EV_IND_6", "EV_IND_7", "EV_IND_AP", "EV_IND_9", "EV_IND_10", "EV_IND_11", "EV_IND_AI8", "EV_IND_AI10", "EV_IND_AIL", "EV_IND_DI", "EV_PH_ACTIVATE_REQ", "EV_PH_DEACTIVATE_REQ", "EV_TIMER3",};static inline void D_L1L2(struct st5481_adapter *adapter, int pr, void *arg){ struct hisax_if *ifc = (struct hisax_if *) &adapter->hisax_d_if; ifc->l1l2(ifc, pr, arg);}static voidl1_go_f3(struct FsmInst *fi, int event, void *arg){ struct st5481_adapter *adapter = fi->userdata; if (fi->state == ST_L1_F7) ph_disconnect(adapter); FsmChangeState(fi, ST_L1_F3); D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL);}static voidl1_go_f6(struct FsmInst *fi, int event, void *arg){ struct st5481_adapter *adapter = fi->userdata; if (fi->state == ST_L1_F7) ph_disconnect(adapter); FsmChangeState(fi, ST_L1_F6);}static voidl1_go_f7(struct FsmInst *fi, int event, void *arg){ struct st5481_adapter *adapter = fi->userdata; FsmDelTimer(&adapter->timer, 0); ph_connect(adapter); FsmChangeState(fi, ST_L1_F7); D_L1L2(adapter, PH_ACTIVATE | INDICATION, NULL);}static voidl1_go_f8(struct FsmInst *fi, int event, void *arg){ struct st5481_adapter *adapter = fi->userdata; if (fi->state == ST_L1_F7) ph_disconnect(adapter); FsmChangeState(fi, ST_L1_F8);}static voidl1_timer3(struct FsmInst *fi, int event, void *arg){ struct st5481_adapter *adapter = fi->userdata; st5481_ph_command(adapter, ST5481_CMD_DR); FsmChangeState(fi, ST_L1_F3); D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL);}static voidl1_ignore(struct FsmInst *fi, int event, void *arg){}static voidl1_activate(struct FsmInst *fi, int event, void *arg){ struct st5481_adapter *adapter = fi->userdata; st5481_ph_command(adapter, ST5481_CMD_DR); st5481_ph_command(adapter, ST5481_CMD_PUP); FsmRestartTimer(&adapter->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); st5481_ph_command(adapter, ST5481_CMD_AR8); FsmChangeState(fi, ST_L1_F4);}static struct FsmNode L1FnList[] __initdata ={ {ST_L1_F3, EV_IND_DP, l1_ignore}, {ST_L1_F3, EV_IND_AP, l1_go_f6}, {ST_L1_F3, EV_IND_AI8, l1_go_f7}, {ST_L1_F3, EV_IND_AI10, l1_go_f7}, {ST_L1_F3, EV_PH_ACTIVATE_REQ, l1_activate}, {ST_L1_F4, EV_TIMER3, l1_timer3}, {ST_L1_F4, EV_IND_DP, l1_go_f3}, {ST_L1_F4, EV_IND_AP, l1_go_f6}, {ST_L1_F4, EV_IND_AI8, l1_go_f7}, {ST_L1_F4, EV_IND_AI10, l1_go_f7}, {ST_L1_F6, EV_TIMER3, l1_timer3}, {ST_L1_F6, EV_IND_DP, l1_go_f3}, {ST_L1_F6, EV_IND_AP, l1_ignore}, {ST_L1_F6, EV_IND_AI8, l1_go_f7}, {ST_L1_F6, EV_IND_AI10, l1_go_f7}, {ST_L1_F7, EV_IND_RSY, l1_go_f8}, {ST_L1_F7, EV_IND_DP, l1_go_f3}, {ST_L1_F7, EV_IND_AP, l1_go_f6}, {ST_L1_F7, EV_IND_AI8, l1_ignore}, {ST_L1_F7, EV_IND_AI10, l1_ignore}, {ST_L1_F7, EV_IND_RSY, l1_go_f8}, {ST_L1_F8, EV_TIMER3, l1_timer3}, {ST_L1_F8, EV_IND_DP, l1_go_f3}, {ST_L1_F8, EV_IND_AP, l1_go_f6}, {ST_L1_F8, EV_IND_AI8, l1_go_f8}, {ST_L1_F8, EV_IND_AI10, l1_go_f8}, {ST_L1_F8, EV_IND_RSY, l1_ignore},};static void l1m_debug(struct FsmInst *fi, char *fmt, ...){ va_list args; char buf[256]; va_start(args, fmt); vsprintf(buf, fmt, args); DBG(8, "%s", buf); va_end(args);}/* ====================================================================== * D-Channel out *//* D OUT state machine: ==================== Transmit short frame (< 16 bytes of encoded data): L1 FRAME D_OUT_STATE USB D CHANNEL -------- ----------- --- --------- FIXME -> [xx..xx] SHORT_INIT -> [7Exx..xxC1C27EFF] SHORT_WAIT_DEN <> OUT_D_COUNTER=16 END_OF_SHORT <- DEN_EVENT -> 7Exx xxxx xxxx xxxx xxxx xxxx C1C1 7EFF WAIT_FOR_RESET_IDLE <- D_UNDERRUN <- (8ms) IDLE <> Reset pipe Transmit long frame (>= 16 bytes of encoded data): L1 FRAME D_OUT_STATE USB D CHANNEL -------- ----------- --- --------- -> [xx...xx] IDLE WAIT_FOR_STOP <> OUT_D_COUNTER=0 WAIT_FOR_RESET <> Reset pipe STOP INIT_LONG_FRAME -> [7Exx..xx] WAIT_DEN <> OUT_D_COUNTER=16 OUT_NORMAL <- DEN_EVENT -> 7Exx END_OF_FRAME_BUSY -> [xxxx] xxxx END_OF_FRAME_NOT_BUSY -> [xxxx] xxxx -> [xxxx] xxxx -> [C1C2] xxxx -> [7EFF] xxxx xxxx xxxx .... xxxx C1C2 7EFF <- D_UNDERRUN <- (> 8ms) WAIT_FOR_STOP <> OUT_D_COUNTER=0 WAIT_FOR_RESET <> Reset pipe STOP*/ static struct Fsm dout_fsm;static char *strDoutState[] ={ "ST_DOUT_NONE", "ST_DOUT_SHORT_INIT", "ST_DOUT_SHORT_WAIT_DEN", "ST_DOUT_LONG_INIT", "ST_DOUT_LONG_WAIT_DEN", "ST_DOUT_NORMAL", "ST_DOUT_WAIT_FOR_UNDERRUN", "ST_DOUT_WAIT_FOR_NOT_BUSY", "ST_DOUT_WAIT_FOR_STOP", "ST_DOUT_WAIT_FOR_RESET",};static char *strDoutEvent[] ={ "EV_DOUT_START_XMIT", "EV_DOUT_COMPLETE", "EV_DOUT_DEN", "EV_DOUT_RESETED", "EV_DOUT_STOPPED", "EV_DOUT_COLL", "EV_DOUT_UNDERRUN",};static void dout_debug(struct FsmInst *fi, char *fmt, ...){ va_list args; char buf[256]; va_start(args, fmt); vsprintf(buf, fmt, args); DBG(0x2, "%s", buf); va_end(args);}static void dout_stop_event(void *context){ struct st5481_adapter *adapter = context; FsmEvent(&adapter->d_out.fsm, EV_DOUT_STOPPED, NULL);}/* * Start the transfer of a D channel frame. */static void usb_d_out(struct st5481_adapter *adapter, int buf_nr){ struct st5481_d_out *d_out = &adapter->d_out; struct urb *urb; unsigned int num_packets, packet_offset; int len, buf_size, bytes_sent; struct sk_buff *skb; struct usb_iso_packet_descriptor *desc; if (d_out->fsm.state != ST_DOUT_NORMAL) return; if (test_and_set_bit(buf_nr, &d_out->busy)) { DBG(2, "ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy); return; } urb = d_out->urb[buf_nr]; skb = d_out->tx_skb; buf_size = NUM_ISO_PACKETS_D * SIZE_ISO_PACKETS_D_OUT; if (skb) { len = isdnhdlc_encode(&d_out->hdlc_state, skb->data, skb->len, &bytes_sent, urb->transfer_buffer, buf_size); skb_pull(skb,bytes_sent); } else { // Send flags or idle len = isdnhdlc_encode(&d_out->hdlc_state, NULL, 0, &bytes_sent, urb->transfer_buffer, buf_size); } if (len < buf_size) { FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_UNDERRUN); } if (skb && !skb->len) { d_out->tx_skb = NULL; D_L1L2(adapter, PH_DATA | CONFIRM, NULL); dev_kfree_skb_any(skb); } // Prepare the URB urb->transfer_buffer_length = len; num_packets = 0; packet_offset = 0; while (packet_offset < len) { desc = &urb->iso_frame_desc[num_packets]; desc->offset = packet_offset; desc->length = SIZE_ISO_PACKETS_D_OUT; if (len - packet_offset < desc->length) desc->length = len - packet_offset; num_packets++; packet_offset += desc->length; } urb->number_of_packets = num_packets; // Prepare the URB urb->dev = adapter->usb_dev; // Need to transmit the next buffer 2ms after the DEN_EVENT urb->transfer_flags = 0; urb->start_frame = usb_get_current_frame_number(adapter->usb_dev)+2; DBG_ISO_PACKET(0x20,urb); if (usb_submit_urb(urb, GFP_KERNEL) < 0) { // There is another URB queued up urb->transfer_flags = URB_ISO_ASAP; SUBMIT_URB(urb, GFP_KERNEL); } }static void fifo_reseted(void *context){ struct st5481_adapter *adapter = context; FsmEvent(&adapter->d_out.fsm, EV_DOUT_RESETED, NULL);}static void usb_d_out_complete(struct urb *urb, struct pt_regs *regs){ struct st5481_adapter *adapter = urb->context; struct st5481_d_out *d_out = &adapter->d_out; int buf_nr; DBG(2, ""); buf_nr = get_buf_nr(d_out->urb, urb); test_and_clear_bit(buf_nr, &d_out->busy); if (unlikely(urb->status < 0)) { switch (urb->status) { case -ENOENT: case -ESHUTDOWN: case -ECONNRESET: DBG(1,"urb killed status %d", urb->status); break; default:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -