⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hfc_usb.c

📁 h内核
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * hfc_usb.c * * modular HiSax ISDN driver for Colognechip HFC-USB chip * * Authors : Peter Sprenger  (sprenger@moving-byters.de) *           Martin Bachem   (info@colognechip.com) *           based on the first hfc_usb driver of Werner Cornelius (werner@isdn-development.de) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. **/#include <linux/types.h>#include <linux/stddef.h>#include <linux/timer.h>#include <linux/config.h>#include <linux/init.h>#include "hisax.h"#include <linux/module.h>#include <linux/kernel_stat.h>#include <linux/usb.h>#include <linux/kernel.h>#include <linux/smp_lock.h>#include <linux/sched.h>#include "hisax_if.h"static const char *hfcusb_revision = "4.0";/*	to enable much mire debug messages in this driver, define			VERBOSE_USB_DEBUG and VERBOSE_ISDN_DEBUG	below*/#define VERBOSE_USB_DEBUG#define VERBOSE_ISDN_DEBUG#define INCLUDE_INLINE_FUNCS#define TRUE  1#define FALSE 0/***********//* defines *//***********/#define HFC_CTRL_TIMEOUT	20  //(HZ * USB_CTRL_GET_TIMEOUT)/* 5ms timeout writing/reading regs */#define HFC_TIMER_T3     8000      /* timeout for l1 activation timer */#define HFC_TIMER_T4     500       /* time for state change interval */#define HFCUSB_L1_STATECHANGE   0  /* L1 state changed */#define HFCUSB_L1_DRX           1  /* D-frame received */#define HFCUSB_L1_ERX           2  /* E-frame received */#define HFCUSB_L1_DTX           4  /* D-frames completed */#define MAX_BCH_SIZE        2048   /* allowed B-channel packet size */#define HFCUSB_RX_THRESHOLD 64     /* threshold for fifo report bit rx */#define HFCUSB_TX_THRESHOLD 64     /* threshold for fifo report bit tx */#define HFCUSB_CHIP_ID    0x16     /* Chip ID register index */#define HFCUSB_CIRM       0x00     /* cirm register index */#define HFCUSB_USB_SIZE   0x07     /* int length register */#define HFCUSB_USB_SIZE_I 0x06     /* iso length register */#define HFCUSB_F_CROSS    0x0b     /* bit order register */#define HFCUSB_CLKDEL     0x37     /* bit delay register */#define HFCUSB_CON_HDLC   0xfa     /* channel connect register */#define HFCUSB_HDLC_PAR   0xfb#define HFCUSB_SCTRL      0x31     /* S-bus control register (tx) */#define HFCUSB_SCTRL_E    0x32     /* same for E and special funcs */#define HFCUSB_SCTRL_R    0x33     /* S-bus control register (rx) */#define HFCUSB_F_THRES    0x0c     /* threshold register */#define HFCUSB_FIFO       0x0f     /* fifo select register */#define HFCUSB_F_USAGE    0x1a     /* fifo usage register */#define HFCUSB_MST_MODE0  0x14#define HFCUSB_MST_MODE1  0x15#define HFCUSB_P_DATA     0x1f#define HFCUSB_INC_RES_F  0x0e#define HFCUSB_STATES     0x30#define HFCUSB_CHIPID 0x40         /* ID value of HFC-USB *//******************//* fifo registers *//******************/#define HFCUSB_NUM_FIFOS   8       /* maximum number of fifos */#define HFCUSB_B1_TX       0       /* index for B1 transmit bulk/int */#define HFCUSB_B1_RX       1       /* index for B1 receive bulk/int */#define HFCUSB_B2_TX       2#define HFCUSB_B2_RX       3#define HFCUSB_D_TX        4#define HFCUSB_D_RX        5#define HFCUSB_PCM_TX      6#define HFCUSB_PCM_RX      7/** used to switch snd_transfer_mode for different TA modes e.g. the Billion USB TA just* supports ISO out, while the Cologne Chip EVAL TA just supports BULK out*/#define USB_INT		0#define USB_BULK	1#define USB_ISOC	2#define ISOC_PACKETS_D	8#define ISOC_PACKETS_B	8#define ISO_BUFFER_SIZE	128// ISO send definitions#define SINK_MAX	68#define SINK_MIN	48#define SINK_DMIN	12#define SINK_DMAX	18#define BITLINE_INF	(-64*8)/**********//* macros *//**********/#define write_usb(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_out_pipe,0,0x40,(c),(b),NULL,0,HFC_CTRL_TIMEOUT)#define read_usb(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_in_pipe,1,0xC0,0,(b),(c),1,HFC_CTRL_TIMEOUT)/*************************************************//* entry and size of output/input control buffer *//*************************************************/#define HFC_CTRL_BUFSIZE 32typedef struct{	__u8 hfc_reg;		/* register number */	__u8 reg_val;		/* value to be written (or read) */	int action;         /* data for action handler */} ctrl_buft;typedef struct{	int vendor;         // vendor id	int prod_id;	    // product id	char *vend_name;    // vendor string	__u8 led_scheme;    // led display scheme	__u8 led_invert;    // invert led aux port settings	__u8 led_bits[8];   // array of 8 possible LED bitmask settings} vendor_data;/***************************************************************//* structure defining input+output fifos (interrupt/bulk mode) *//***************************************************************/struct usb_fifo;			/* forward definition */typedef struct iso_urb_struct{	struct urb *purb;	__u8 buffer[ISO_BUFFER_SIZE];	/* buffer incoming/outgoing data */	struct usb_fifo *owner_fifo;	// pointer to owner fifo} iso_urb_struct;struct hfcusb_data;			/* forward definition */typedef struct usb_fifo{	int fifonum;			/* fifo index attached to this structure */	int active;			/* fifo is currently active */	struct hfcusb_data *hfc;	/* pointer to main structure */	int pipe;			/* address of endpoint */	__u8 usb_packet_maxlen;		/* maximum length for usb transfer */	unsigned int max_size;		/* maximum size of receive/send packet */	__u8 intervall;			/* interrupt interval */	struct sk_buff *skbuff; 	/* actual used buffer */	struct urb *urb;		/* transfer structure for usb routines */	__u8 buffer[128];		/* buffer incoming/outgoing data */	int bit_line;			/* how much bits are in the fifo? */	volatile __u8 usb_transfer_mode;/* switched between ISO and INT */	iso_urb_struct iso[2];		/* need two urbs to have one always for pending */	struct hisax_if *hif;		/* hisax interface */	int delete_flg;			/* only delete skbuff once */	int last_urblen;		/* remember length of last packet */} usb_fifo;/*********************************************//* structure holding all data for one device *//*********************************************/typedef struct hfcusb_data{	// HiSax Interface for loadable Layer1 drivers	struct hisax_d_if d_if;			/* see hisax_if.h */	struct hisax_b_if b_if[2];		/* see hisax_if.h */	int protocol;		struct usb_device *dev;			/* our device */	int if_used;				/* used interface number */	int alt_used;				/* used alternate config */	int ctrl_paksize;			/* control pipe packet size */	int ctrl_in_pipe, ctrl_out_pipe;	/* handles for control pipe */	int cfg_used;				/* configuration index used */	int vend_idx;				// vendor found	int b_mode[2];				// B-channel mode	int l1_activated;			// layer 1 activated	int packet_size,iso_packet_size;		/* control pipe background handling */	ctrl_buft ctrl_buff[HFC_CTRL_BUFSIZE];	/* buffer holding queued data */	volatile int ctrl_in_idx, ctrl_out_idx,		ctrl_cnt;			/* input/output pointer + count */	struct urb *ctrl_urb;			/* transfer structure for control channel */	struct usb_ctrlrequest ctrl_write;	/* buffer for control write request */	struct usb_ctrlrequest ctrl_read;	/* same for read request */	__u8 led_state,led_new_data,led_b_active;	volatile __u8 threshold_mask;		/* threshold actually reported */	volatile __u8 bch_enables;		/* or mask for sctrl_r and sctrl register values */	usb_fifo fifos[HFCUSB_NUM_FIFOS];	/* structure holding all fifo data */	volatile __u8 l1_state;			/* actual l1 state */	struct timer_list t3_timer;		/* timer 3 for activation/deactivation */	struct timer_list t4_timer;		/* timer 4 for activation/deactivation */	struct timer_list led_timer;		/* timer flashing leds */} hfcusb_data;static void collect_rx_frame(usb_fifo *fifo,__u8 *data,int len,int finish);/******************************************************//* start next background transfer for control channel *//******************************************************/static void ctrl_start_transfer(hfcusb_data * hfc){	int err;	if(hfc->ctrl_cnt)	{		hfc->ctrl_urb->pipe = hfc->ctrl_out_pipe;		hfc->ctrl_urb->setup_packet = (u_char *) & hfc->ctrl_write;		hfc->ctrl_urb->transfer_buffer = NULL;		hfc->ctrl_urb->transfer_buffer_length = 0;		hfc->ctrl_write.wIndex = hfc->ctrl_buff[hfc->ctrl_out_idx].hfc_reg;		hfc->ctrl_write.wValue = hfc->ctrl_buff[hfc->ctrl_out_idx].reg_val;		err = usb_submit_urb(hfc->ctrl_urb, GFP_ATOMIC);	/* start transfer */		printk(KERN_DEBUG "ctrl_start_transfer: submit %d\n", err);	}}				/* ctrl_start_transfer *//************************************//* queue a control transfer request *//* return 0 on success.             *//************************************/static int queue_control_request(hfcusb_data * hfc, __u8 reg, __u8 val,int action){	ctrl_buft *buf;#ifdef VERBOSE_USB_DEBUG	printk ("HFC_USB: queue_control_request reg: %x, val: %x\n", reg, val);#endif	if(hfc->ctrl_cnt >= HFC_CTRL_BUFSIZE)  return(1);	   /* no space left */	buf = &hfc->ctrl_buff[hfc->ctrl_in_idx];	/* pointer to new index */	buf->hfc_reg = reg;	buf->reg_val = val;	buf->action=action;	if (++hfc->ctrl_in_idx >= HFC_CTRL_BUFSIZE)		hfc->ctrl_in_idx = 0;	/* pointer wrap */	if (++hfc->ctrl_cnt == 1)		ctrl_start_transfer(hfc);	return(0);}		/* queue_control_request */static int control_action_handler(hfcusb_data *hfc,int reg,int val,int action){	if(!action) return(1);  // no action defined	return(0);}/***************************************************************//* control completion routine handling background control cmds *//***************************************************************/static void ctrl_complete(struct urb *urb, struct pt_regs *regs){	hfcusb_data *hfc = (hfcusb_data *) urb->context;	ctrl_buft *buf;	printk(KERN_DEBUG "ctrl_complete cnt %d\n", hfc->ctrl_cnt);	urb->dev = hfc->dev;	if(hfc->ctrl_cnt)	{		buf=&hfc->ctrl_buff[hfc->ctrl_out_idx];		control_action_handler(hfc,buf->hfc_reg,buf->reg_val,buf->action);		hfc->ctrl_cnt--;	/* decrement actual count */		if(++hfc->ctrl_out_idx >= HFC_CTRL_BUFSIZE) hfc->ctrl_out_idx = 0;	/* pointer wrap */		ctrl_start_transfer(hfc);	/* start next transfer */	}}				/* ctrl_complete */#define LED_OFF      0   // no LED support#define LED_SCHEME1  1	 // LED standard scheme#define LED_SCHEME2  2	 // not used yet...#define LED_POWER_ON	1#define LED_POWER_OFF	2#define LED_S0_ON		3#define LED_S0_OFF		4#define LED_B1_ON		5#define LED_B1_OFF		6#define LED_B1_DATA		7#define LED_B2_ON		8#define LED_B2_OFF		9#define LED_B2_DATA	   10#define LED_NORMAL   0	 // LEDs are normal#define LED_INVERTED 1   // LEDs are inverted// time for LED flashing#define LED_TIME      250vendor_data vdata[]={    {0x959, 0x2bd0, "ISDN USB TA (Cologne Chip HFC-S USB based)", LED_OFF,LED_NORMAL,{4,0,2,1}},     /* CologneChip Eval TA */	{0x7b0, 0x0007, "Billion tiny USB ISDN TA 128", LED_SCHEME1,  LED_INVERTED, {8,0x40,0x20,0x10}},  /* Billion TA */	{0x742, 0x2008, "Stollmann USB TA",             LED_SCHEME1,  LED_NORMAL,   {4,0,2,1}},           /* Stollmann TA */	{0x8e3, 0x0301, "Olitec USB RNIS",              LED_SCHEME1,  LED_NORMAL,   {2,0,1,4}},           /* Olitec TA  */	{0x675, 0x1688, "DrayTec USB ISDN TA",          LED_SCHEME1,  LED_NORMAL,   {4,0,2,1}},           /* Draytec TA */	{0x7fa, 0x0846, "Bewan Modem RNIS USB",         LED_SCHEME1,  LED_INVERTED, {8,0x40,0x20,0x10}},  /* Bewan TA   */	{0}			   // EOL element};										/***************************************************//* write led data to auxport & invert if necessary *//***************************************************/static void write_led(hfcusb_data * hfc,__u8 led_state){	if(led_state!=hfc->led_state)	{		hfc->led_state=led_state;		queue_control_request(hfc, HFCUSB_P_DATA,(vdata[hfc->vend_idx].led_invert) ? ~led_state : led_state,1);	}}/******************************************//* invert B-channel LEDs if data is sent  *//******************************************/static void led_timer(hfcusb_data * hfc){   	static int cnt=0;	__u8 led_state=hfc->led_state;	if(cnt)	{		if(hfc->led_b_active&1) led_state|=vdata[hfc->vend_idx].led_bits[2];		if(hfc->led_b_active&2) led_state|=vdata[hfc->vend_idx].led_bits[3];	}	else	{		if(!(hfc->led_b_active&1) || hfc->led_new_data&1) led_state&=~vdata[hfc->vend_idx].led_bits[2];		if(!(hfc->led_b_active&2) || hfc->led_new_data&2) led_state&=~vdata[hfc->vend_idx].led_bits[3];	}	write_led(hfc,led_state);	hfc->led_new_data=0;	cnt=!cnt;	// restart 4 hz timer	hfc->led_timer.expires = jiffies + (LED_TIME * HZ) / 1000;	if(!timer_pending(&hfc->led_timer)) add_timer(&hfc->led_timer);}/**************************//* handle LED requests    *//**************************/static void handle_led(hfcusb_data * hfc,int event){	__u8 led_state=hfc->led_state;	// if no scheme -> no LED action   	if(vdata[hfc->vend_idx].led_scheme==LED_OFF) return;	switch(event)	{		case LED_POWER_ON:				   led_state|=vdata[hfc->vend_idx].led_bits[0];				break;		case LED_POWER_OFF: // no Power off handling				break;		case LED_S0_ON:				   led_state|=vdata[hfc->vend_idx].led_bits[1];				break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -