Viewing file: st5481.h (14.34 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/* * 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. * */
#ifndef _ST5481_H_ #define _ST5481_H_
#include <linux/config.h>
// USB IDs, the Product Id is in the range 0x4810-0x481F
#define ST_VENDOR_ID 0x0483 #define ST5481_PRODUCT_ID 0x4810 #define ST5481_PRODUCT_ID_MASK 0xFFF0
// ST5481 endpoints when using alternative setting 3 (2B+D). // To get the endpoint address, OR with 0x80 for IN endpoints.
#define EP_CTRL 0x00U /* Control endpoint */ #define EP_INT 0x01U /* Interrupt endpoint */ #define EP_B1_OUT 0x02U /* B1 channel out */ #define EP_B1_IN 0x03U /* B1 channel in */ #define EP_B2_OUT 0x04U /* B2 channel out */ #define EP_B2_IN 0x05U /* B2 channel in */ #define EP_D_OUT 0x06U /* D channel out */ #define EP_D_IN 0x07U /* D channel in */ // Number of isochronous packets. With 20 packets we get // 50 interrupts/sec for each endpoint.
#define NUM_ISO_PACKETS_D 20 #define NUM_ISO_PACKETS_B 20
// Size of each isochronous packet. // In outgoing direction we need to match ISDN data rates: // D: 2 bytes / msec -> 16 kbit / s // B: 16 bytes / msec -> 64 kbit / s #define SIZE_ISO_PACKETS_D_IN 16 #define SIZE_ISO_PACKETS_D_OUT 2 #define SIZE_ISO_PACKETS_B_IN 32 #define SIZE_ISO_PACKETS_B_OUT 8
// If we overrun/underrun, we send one packet with +/- 2 bytes #define B_FLOW_ADJUST 2
// Registers that are written using vendor specific device request // on endpoint 0.
#define LBA 0x02 /* S loopback */ #define SET_DEFAULT 0x06 /* Soft reset */ #define LBB 0x1D /* S maintenance loopback */ #define STT 0x1e /* S force transmission signals */ #define SDA_MIN 0x20 /* SDA-sin minimal value */ #define SDA_MAX 0x21 /* SDA-sin maximal value */ #define SDELAY_VALUE 0x22 /* Delay between Tx and Rx clock */ #define IN_D_COUNTER 0x36 /* D receive channel fifo counter */ #define OUT_D_COUNTER 0x37 /* D transmit channel fifo counter */ #define IN_B1_COUNTER 0x38 /* B1 receive channel fifo counter */ #define OUT_B1_COUNTER 0x39 /* B1 transmit channel fifo counter */ #define IN_B2_COUNTER 0x3a /* B2 receive channel fifo counter */ #define OUT_B2_COUNTER 0x3b /* B2 transmit channel fifo counter */ #define FFCTRL_IN_D 0x3C /* D receive channel fifo threshold low */ #define FFCTRH_IN_D 0x3D /* D receive channel fifo threshold high */ #define FFCTRL_OUT_D 0x3E /* D transmit channel fifo threshold low */ #define FFCTRH_OUT_D 0x3F /* D transmit channel fifo threshold high */ #define FFCTRL_IN_B1 0x40 /* B1 receive channel fifo threshold low */ #define FFCTRH_IN_B1 0x41 /* B1 receive channel fifo threshold high */ #define FFCTRL_OUT_B1 0x42 /* B1 transmit channel fifo threshold low */ #define FFCTRH_OUT_B1 0x43 /* B1 transmit channel fifo threshold high */ #define FFCTRL_IN_B2 0x44 /* B2 receive channel fifo threshold low */ #define FFCTRH_IN_B2 0x45 /* B2 receive channel fifo threshold high */ #define FFCTRL_OUT_B2 0x46 /* B2 transmit channel fifo threshold low */ #define FFCTRH_OUT_B2 0x47 /* B2 transmit channel fifo threshold high */ #define MPMSK 0x4A /* Multi purpose interrupt MASK register */ #define FFMSK_D 0x4c /* D fifo interrupt MASK register */ #define FFMSK_B1 0x4e /* B1 fifo interrupt MASK register */ #define FFMSK_B2 0x50 /* B2 fifo interrupt MASK register */ #define GPIO_DIR 0x52 /* GPIO pins direction registers */ #define GPIO_OUT 0x53 /* GPIO pins output register */ #define GPIO_IN 0x54 /* GPIO pins input register */ #define TXCI 0x56 /* CI command to be transmitted */
// Format of the interrupt packet received on endpoint 1: // // +--------+--------+--------+--------+--------+--------+ // !MPINT !FFINT_D !FFINT_B1!FFINT_B2!CCIST !GPIO_INT! // +--------+--------+--------+--------+--------+--------+
// Offsets in the interrupt packet
#define MPINT 0 #define FFINT_D 1 #define FFINT_B1 2 #define FFINT_B2 3 #define CCIST 4 #define GPIO_INT 5 #define INT_PKT_SIZE 6
// MPINT #define LSD_INT 0x80 /* S line activity detected */ #define RXCI_INT 0x40 /* Indicate primitive arrived */ #define DEN_INT 0x20 /* Signal enabling data out of D Tx fifo */ #define DCOLL_INT 0x10 /* D channel collision */ #define AMIVN_INT 0x04 /* AMI violation number reached 2 */ #define INFOI_INT 0x04 /* INFOi changed */ #define DRXON_INT 0x02 /* Reception channel active */ #define GPCHG_INT 0x01 /* GPIO pin value changed */
// FFINT_x #define IN_OVERRUN 0x80 /* In fifo overrun */ #define OUT_UNDERRUN 0x40 /* Out fifo underrun */ #define IN_UP 0x20 /* In fifo thresholdh up-crossed */ #define IN_DOWN 0x10 /* In fifo thresholdl down-crossed */ #define OUT_UP 0x08 /* Out fifo thresholdh up-crossed */ #define OUT_DOWN 0x04 /* Out fifo thresholdl down-crossed */ #define IN_COUNTER_ZEROED 0x02 /* In down-counter reached 0 */ #define OUT_COUNTER_ZEROED 0x01 /* Out down-counter reached 0 */
#define ANY_REC_INT (IN_OVERRUN+IN_UP+IN_DOWN+IN_COUNTER_ZEROED) #define ANY_XMIT_INT (OUT_UNDERRUN+OUT_UP+OUT_DOWN+OUT_COUNTER_ZEROED)
// Level 1 commands that are sent using the TXCI device request #define ST5481_CMD_DR 0x0 /* Deactivation Request */ #define ST5481_CMD_RES 0x1 /* state machine RESet */ #define ST5481_CMD_TM1 0x2 /* Test Mode 1 */ #define ST5481_CMD_TM2 0x3 /* Test Mode 2 */ #define ST5481_CMD_PUP 0x7 /* Power UP */ #define ST5481_CMD_AR8 0x8 /* Activation Request class 1 */ #define ST5481_CMD_AR10 0x9 /* Activation Request class 2 */ #define ST5481_CMD_ARL 0xA /* Activation Request Loopback */ #define ST5481_CMD_PDN 0xF /* Power DoWn */
// Turn on/off the LEDs using the GPIO device request. // To use the B LEDs, number_of_leds must be set to 4 #define B1_LED 0x10U #define B2_LED 0x20U #define GREEN_LED 0x40U #define RED_LED 0x80U
// D channel out states enum { 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, };
#define DOUT_STATE_COUNT (ST_DOUT_WAIT_FOR_RESET + 1)
// D channel out events enum { EV_DOUT_START_XMIT, EV_DOUT_COMPLETE, EV_DOUT_DEN, EV_DOUT_RESETED, EV_DOUT_STOPPED, EV_DOUT_COLL, EV_DOUT_UNDERRUN, };
#define DOUT_EVENT_COUNT (EV_DOUT_UNDERRUN + 1)
// ----------------------------------------------------------------------
enum { ST_L1_F3, ST_L1_F4, ST_L1_F6, ST_L1_F7, ST_L1_F8, };
#define L1_STATE_COUNT (ST_L1_F8+1)
// The first 16 entries match the Level 1 indications that // are found at offset 4 (CCIST) in the interrupt packet
enum { EV_IND_DP, // 0000 Deactivation Pending EV_IND_1, // 0001 EV_IND_2, // 0010 EV_IND_3, // 0011 EV_IND_RSY, // 0100 ReSYnchronizing EV_IND_5, // 0101 EV_IND_6, // 0110 EV_IND_7, // 0111 EV_IND_AP, // 1000 Activation Pending EV_IND_9, // 1001 EV_IND_10, // 1010 EV_IND_11, // 1011 EV_IND_AI8, // 1100 Activation Indication class 8 EV_IND_AI10,// 1101 Activation Indication class 10 EV_IND_AIL, // 1110 Activation Indication Loopback EV_IND_DI, // 1111 Deactivation Indication EV_PH_ACTIVATE_REQ, EV_PH_DEACTIVATE_REQ, EV_TIMER3, };
#define L1_EVENT_COUNT (EV_TIMER3 + 1)
#define ERR(format, arg...) \ printk(KERN_ERR __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg)
#define WARN(format, arg...) \ printk(KERN_WARNING __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg)
#define INFO(format, arg...) \ printk(KERN_INFO __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg)
#include "st5481_hdlc.h" #include "fsm.h" #include "hisax_if.h" #include <linux/skbuff.h>
/* ====================================================================== * FIFO handling */
/* Generic FIFO structure */ struct fifo { u_char r,w,count,size; spinlock_t lock; };
/* * Init an FIFO */ static inline void fifo_init(struct fifo *fifo, int size) { fifo->r = fifo->w = fifo->count = 0; fifo->size = size; spin_lock_init(&fifo->lock); }
/* * Add an entry to the FIFO */ static inline int fifo_add(struct fifo *fifo) { unsigned long flags; int index;
if (!fifo) { return -1; }
spin_lock_irqsave(&fifo->lock, flags); if (fifo->count == fifo->size) { // FIFO full index = -1; } else { // Return index where to get the next data to add to the FIFO index = fifo->w++ & (fifo->size-1); fifo->count++; } spin_unlock_irqrestore(&fifo->lock, flags); return index; }
/* * Remove an entry from the FIFO with the index returned. */ static inline int fifo_remove(struct fifo *fifo) { unsigned long flags; int index;
if (!fifo) { return -1; }
spin_lock_irqsave(&fifo->lock, flags); if (!fifo->count) { // FIFO empty index = -1; } else { // Return index where to get the next data from the FIFO index = fifo->r++ & (fifo->size-1); fifo->count--; } spin_unlock_irqrestore(&fifo->lock, flags);
return index; }
/* ====================================================================== * control pipe */ typedef void (*ctrl_complete_t)(void *);
typedef struct ctrl_msg { devrequest dr; ctrl_complete_t complete; void *context; } ctrl_msg;
/* FIFO of ctrl messages waiting to be sent */ #define MAX_EP0_MSG 16 struct ctrl_msg_fifo { struct fifo f; struct ctrl_msg data[MAX_EP0_MSG]; };
#define MAX_DFRAME_LEN_L1 300 #define HSCX_BUFMAX 4096
struct st5481_ctrl { struct ctrl_msg_fifo msg_fifo; unsigned long busy; struct urb *urb; };
struct st5481_intr { // struct evt_fifo evt_fifo; struct urb *urb; };
struct st5481_d_out { struct hdlc_vars hdlc_state; struct urb *urb[2]; /* double buffering */ unsigned long busy; struct sk_buff *tx_skb; struct FsmInst fsm; };
struct st5481_b_out { struct hdlc_vars hdlc_state; struct urb *urb[2]; /* double buffering */ u_char flow_event; u_long busy; struct sk_buff *tx_skb; };
struct st5481_in { struct hdlc_vars hdlc_state; struct urb *urb[2]; /* double buffering */ int mode; int bufsize; unsigned int num_packets; unsigned int packet_size; unsigned char ep, counter; unsigned char *rcvbuf; struct st5481_adapter *adapter; struct hisax_if *hisax_if; };
int st5481_setup_in(struct st5481_in *in); void st5481_release_in(struct st5481_in *in); void st5481_in_mode(struct st5481_in *in, int mode);
struct st5481_bcs { struct hisax_b_if b_if; struct st5481_adapter *adapter; struct st5481_in b_in; struct st5481_b_out b_out; int channel; int mode; };
struct st5481_adapter { struct list_head list; int number_of_leds; struct usb_device *usb_dev; struct hisax_d_if hisax_d_if;
struct st5481_ctrl ctrl; struct st5481_intr intr; struct st5481_in d_in; struct st5481_d_out d_out;
unsigned char leds; unsigned int led_counter;
unsigned long event;
struct FsmInst l1m; struct FsmTimer timer;
struct st5481_bcs bcs[2]; };
#define TIMER3_VALUE 7000
/* ====================================================================== * */
/* * Submit an URB with error reporting. This is a macro so * the __FUNCTION__ returns the caller function name. */ #define SUBMIT_URB(urb) \ ({ \ int status; \ if ((status = usb_submit_urb(urb)) < 0) { \ WARN("usb_submit_urb failed,status=%d", status); \ } \ status; \ })
/* * USB double buffering, return the URB index (0 or 1). */ static inline int get_buf_nr(struct urb *urbs[], struct urb *urb) { return (urbs[0]==urb ? 0 : 1); }
/* ---------------------------------------------------------------------- */
/* B Channel */
int st5481_setup_b(struct st5481_bcs *bcs); void st5481_release_b(struct st5481_bcs *bcs); void st5481_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg);
/* D Channel */
int st5481_setup_d(struct st5481_adapter *adapter); void st5481_release_d(struct st5481_adapter *adapter); void st5481_b_l2l1(struct hisax_if *b_if, int pr, void *arg); int st5481_d_init(void); void st5481_d_exit(void);
/* USB */ void st5481_ph_command(struct st5481_adapter *adapter, unsigned int command); int st5481_setup_isocpipes(struct urb* urb[2], struct usb_device *dev, unsigned int pipe, int num_packets, int packet_size, int buf_size, usb_complete_t complete, void *context); void st5481_release_isocpipes(struct urb* urb[2]);
int st5481_isoc_flatten(struct urb *urb); void st5481_usb_pipe_reset(struct st5481_adapter *adapter, u_char pipe, ctrl_complete_t complete, void *context); void st5481_usb_ctrl_msg(struct st5481_adapter *adapter, u8 request, u8 requesttype, u16 value, u16 index, ctrl_complete_t complete, void *context); void st5481_usb_device_ctrl_msg(struct st5481_adapter *adapter, u8 request, u16 value, ctrl_complete_t complete, void *context); int st5481_setup_usb(struct st5481_adapter *adapter); void st5481_release_usb(struct st5481_adapter *adapter); void st5481_start(struct st5481_adapter *adapter); void st5481_stop(struct st5481_adapter *adapter);
// ---------------------------------------------------------------------- // debugging macros
#define __debug_variable st5481_debug #include "hisax_debug.h"
#ifdef CONFIG_HISAX_DEBUG
extern int st5481_debug;
#define DBG_ISO_PACKET(level,urb) \ if (level & __debug_variable) dump_iso_packet(__FUNCTION__,urb)
static void __attribute__((unused)) dump_iso_packet(const char *name,urb_t *urb) { int i,j; int len,ofs; u_char *data;
printk(KERN_DEBUG "%s: packets=%d,errors=%d\n", name,urb->number_of_packets,urb->error_count); for (i = 0; i < urb->number_of_packets; ++i) { if (urb->pipe & USB_DIR_IN) { len = urb->iso_frame_desc[i].actual_length; } else { len = urb->iso_frame_desc[i].length; } ofs = urb->iso_frame_desc[i].offset; printk(KERN_DEBUG "len=%.2d,ofs=%.3d ",len,ofs); if (len) { data = urb->transfer_buffer+ofs; for (j=0; j < len; j++) { printk ("%.2x", data[j]); } } printk("\n"); } }
static inline const char *ST5481_CMD_string(int evt) { static char s[16];
switch (evt) { case ST5481_CMD_DR: return "DR"; case ST5481_CMD_RES: return "RES"; case ST5481_CMD_TM1: return "TM1"; case ST5481_CMD_TM2: return "TM2"; case ST5481_CMD_PUP: return "PUP"; case ST5481_CMD_AR8: return "AR8"; case ST5481_CMD_AR10: return "AR10"; case ST5481_CMD_ARL: return "ARL"; case ST5481_CMD_PDN: return "PDN"; }; sprintf(s,"0x%x",evt); return s; }
#else
#define DBG_ISO_PACKET(level,urb) do {} while (0)
#endif
#endif
|