diff options
author | nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2005-05-28 09:17:29 +0000 |
---|---|---|
committer | nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2005-05-28 09:17:29 +0000 |
commit | 76ed58d705e7f3892a1259abcd92882a527e7b53 (patch) | |
tree | 80dfa6ecb493ee8cb9ca1436f1b37ee89f320a55 /target/linux/linux-2.4/patches/201-hfc_usb_backport.patch | |
parent | e285af3e184318b0fefeab597ae5ee4a2628422d (diff) |
move package/linux into target/linux, use wbx' new kernel code. support building images with more than one kernel, split kernel module parts off of packages that use their own kernel modules (fuse, shfs, openswan). some cleanup in the image building process in target/. image builder is disabled for now, needs some fixing.
git-svn-id: svn://svn.openwrt.org/openwrt/trunk/openwrt@1085 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/linux-2.4/patches/201-hfc_usb_backport.patch')
-rw-r--r-- | target/linux/linux-2.4/patches/201-hfc_usb_backport.patch | 2663 |
1 files changed, 2663 insertions, 0 deletions
diff --git a/target/linux/linux-2.4/patches/201-hfc_usb_backport.patch b/target/linux/linux-2.4/patches/201-hfc_usb_backport.patch new file mode 100644 index 000000000..4ef20fa8b --- /dev/null +++ b/target/linux/linux-2.4/patches/201-hfc_usb_backport.patch @@ -0,0 +1,2663 @@ +diff -rNu linux-2.4.29.old/drivers/Makefile linux-2.4.29/drivers/Makefile +--- linux-2.4.29.old/drivers/Makefile 2005-03-22 14:47:41.000000000 +0100 ++++ linux-2.4.29/drivers/Makefile 2005-03-22 15:15:20.012957872 +0100 +@@ -38,7 +38,7 @@ + subdir-$(CONFIG_MD) += md + subdir-$(CONFIG_IEEE1394) += ieee1394 + subdir-$(CONFIG_PNP) += pnp +-subdir-$(CONFIG_ISDN_BOOL) += isdn ++subdir-$(CONFIG_ISDN) += isdn + subdir-$(CONFIG_ATM) += atm + subdir-$(CONFIG_FC4) += fc4 + +diff -rNu linux-2.4.29.old/drivers/isdn/hisax/hfc_usb.c linux-2.4.29/drivers/isdn/hisax/hfc_usb.c +--- linux-2.4.29.old/drivers/isdn/hisax/hfc_usb.c 2005-03-22 15:13:58.233390256 +0100 ++++ linux-2.4.29/drivers/isdn/hisax/hfc_usb.c 2005-03-22 15:14:57.475384104 +0100 +@@ -1,13 +1,11 @@ +-/* $Id: hfc_usb.c,v 2.3 2001/07/06 21:30:11 werner Exp $ ++/* ++ * hfc_usb.c + * ++ * modular HiSax ISDN driver for Colognechip HFC-USB chip + * +- * +- * Author (C) 2001 Werner Cornelius (werner@isdn-development.de) +- * modular driver for Colognechip HFC-USB chip +- * as plugin for HiSax isdn driver +- * type approval valid for HFC-S USB based TAs +- * +- * Copyright 2001 by Werner Cornelius (werner@isdn-development.de) ++ * 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 +@@ -23,70 +21,90 @@ + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * +- */ ++ * 2005_Mar_16 grsch ++ * ported 2.6.8 hfc_usb.c to 2.4.20 format ++ * Gregor Schaffrath <gschaff@ran-dom.org> ++*/ ++ + + #include <linux/types.h> + #include <linux/stddef.h> + #include <linux/timer.h> + #include <linux/config.h> +-#include <linux/isdn_compat.h> + #include <linux/init.h> + #include "hisax.h" + #include <linux/module.h> + #include <linux/kernel_stat.h> +-#include <linux/tqueue.h> + #include <linux/usb.h> + #include <linux/kernel.h> + #include <linux/smp_lock.h> + #include <linux/sched.h> ++#include "hisax_if.h" + #include "hisax_loadable.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 5 /* 5ms timeout writing/reading regs */ +-#define HFC_TIMER_T3 7000 /* timeout for l1 activation timer */ +- +-#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 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_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 */ ++#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_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 +@@ -94,198 +112,162 @@ + #define HFCUSB_PCM_TX 6 + #define HFCUSB_PCM_RX 7 + +-/************/ +-/* LED mask */ +-/************/ +-#define LED_DRIVER 0x1 +-#define LED_L1 0x2 +-#define LED_BCH 0x4 ++/* ++* 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_hfc(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_out_pipe,0,0x40,(c),(b),0,0,HFC_CTRL_TIMEOUT) +-#define Read_hfc(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_in_pipe,1,0xC0,0,(b),(c),1,HFC_CTRL_TIMEOUT) +- +-#ifdef COMPAT_HAS_USB_IDTAB +-/****************************************/ +-/* data defining the devices to be used */ +-/****************************************/ +-static __devinitdata const struct usb_device_id hfc_usb_idtab[3] = { +- {USB_DEVICE(0x959, 0x2bd0)}, /* Colognechip ROM */ +- {USB_DEVICE(0x7b0, 0x0006)}, /* USB TA 128 */ +- {} /* end with an all-zeroes entry */ +-}; +-#endif ++#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 32 +-typedef struct { ++typedef 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 hfcusb_data; /* forward definition */ +-typedef struct { +- int fifonum; /* fifo index attached to this structure */ +- __u8 fifo_mask; /* mask for this fifo */ +- int active; /* fifo is currently active */ ++ ++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_maxlen; /* maximum length for usb transfer */ +- int max_size; /* maximum size of receive/send packet */ +- int transmode; /* transparent mode selected */ +- int framenum; /* number of frame when last tx completed */ +- int rx_offset; /* offset inside rx buffer */ +- int next_complete; /* complete marker */ +- __u8 *act_ptr; /* pointer to next data */ +- __u8 intervall; /* interrupt interval */ +- struct sk_buff *buff; /* actual used buffer */ +- urb_t urb; /* transfer structure for usb routines */ +- __u8 buffer[128]; /* buffer incoming/outgoing data */ ++ 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 { +- struct hisax_drvreg regd; /* register data and callbacks */ +- 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 */ ++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 */ +- urb_t ctrl_urb; /* transfer structure for control channel */ +- devrequest ctrl_write; /* buffer for control write request */ +- devrequest ctrl_read; /* same for read request */ +- +- volatile __u8 dfifo_fill; /* value read from tx d-fifo */ +- volatile __u8 active_fifos; /* fifos currently active as bit mask */ +- volatile __u8 threshold_mask; /* threshold actually reported */ +- volatile __u8 service_request; /* fifo needs service from task */ +- volatile __u8 ctrl_fifo; /* last selected fifo */ +- volatile __u8 bch_enables; /* or mask for sctrl_r and sctrl register values */ +- volatile __u8 led_req; /* request status of adapters leds */ +- volatile __u8 led_act; /* active status of adapters leds */ ++ 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 */ + +- /* layer 1 activation/deactivation handling */ +- volatile __u8 l1_state; /* actual l1 state */ +- volatile ulong l1_event; /* event mask */ +- struct tq_struct l1_tq; /* l1 bh structure */ +- struct timer_list t3_timer; /* timer for activation/deactivation */ +- struct timer_list t4_timer; /* timer for activation/deactivation */ ++ 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; + +-#if 0 +-static void +-usb_dump_urb(purb_t purb) +-{ +- printk("urb :%p\n", purb); +- printk("next :%p\n", purb->next); +- printk("dev :%p\n", purb->dev); +- printk("pipe :%08X\n", purb->pipe); +- printk("status :%d\n", purb->status); +- printk("transfer_flags :%08X\n", purb->transfer_flags); +- printk("transfer_buffer :%p\n", purb->transfer_buffer); +- printk("transfer_buffer_length:%d\n", +- purb->transfer_buffer_length); +- printk("actual_length :%d\n", purb->actual_length); +- printk("setup_packet :%p\n", purb->setup_packet); +- printk("start_frame :%d\n", purb->start_frame); +- printk("number_of_packets :%d\n", purb->number_of_packets); +- printk("interval :%d\n", purb->interval); +- printk("error_count :%d\n", purb->error_count); +- printk("context :%p\n", purb->context); +- printk("complete :%p\n", purb->complete); +-} +-#endif + +-/*************************************************************************/ +-/* bottom half handler for L1 activation/deactiavtaion + D-chan + E-chan */ +-/*************************************************************************/ +-static void +-usb_l1d_bh(hfcusb_data * hfc) +-{ ++static void collect_rx_frame(usb_fifo *fifo,__u8 *data,int len,int finish); ++ + +- while (hfc->l1_event) { +- if (test_and_clear_bit +- (HFCUSB_L1_STATECHANGE, &hfc->l1_event)) { +- if (hfc->l1_state == 7) +- hfc->led_req |= LED_L1; +- else +- hfc->led_req &= ~LED_L1; +- if ((hfc->l1_state == 7) || +- (hfc->l1_state == 3)) +- hfc->regd.dch_l1l2(hfc->regd.arg_hisax, +- (hfc->l1_state == +- 7) ? (PH_ACTIVATE | +- INDICATION) +- : (PH_DEACTIVATE | INDICATION), +- NULL); +- } +- if (test_and_clear_bit(HFCUSB_L1_DRX, &hfc->l1_event)) { +- hfc->regd.dch_l1l2(hfc->regd.arg_hisax, +- PH_DATA | INDICATION, +- (void *) 0); +- } +- if (test_and_clear_bit(HFCUSB_L1_ERX, &hfc->l1_event)) { +- hfc->regd.dch_l1l2(hfc->regd.arg_hisax, +- PH_DATA | INDICATION, +- (void *) 1); +- } +- if (test_and_clear_bit(HFCUSB_L1_DTX, &hfc->l1_event)) { +- hfc->regd.dch_l1l2(hfc->regd.arg_hisax, +- PH_DATA | CONFIRM, NULL); +- } +- } /* while */ +-} /* usb_l1d_bh */ + + /******************************************************/ + /* start next background transfer for control channel */ + /******************************************************/ +-static void +-ctrl_start_transfer(hfcusb_data * hfc) ++static void ctrl_start_transfer(hfcusb_data * hfc) + { +- +- if (hfc->ctrl_cnt) { +- switch (hfc->ctrl_buff[hfc->ctrl_out_idx].hfc_reg) { +- case HFCUSB_F_USAGE: +- hfc->ctrl_urb.pipe = hfc->ctrl_in_pipe; +- hfc->ctrl_urb.setup_packet = +- (u_char *) & hfc->ctrl_read; +- hfc->ctrl_urb.transfer_buffer_length = 1; +- hfc->ctrl_read.index = +- hfc->ctrl_buff[hfc->ctrl_out_idx]. +- hfc_reg; +- hfc->ctrl_urb.transfer_buffer = +- (char *) &hfc->dfifo_fill; +- break; +- +- default: /* write register */ +- 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.index = +- hfc->ctrl_buff[hfc->ctrl_out_idx]. +- hfc_reg; +- hfc->ctrl_write.value = +- hfc->ctrl_buff[hfc->ctrl_out_idx]. +- reg_val; +- break; +- } +- usb_submit_urb(&hfc->ctrl_urb); /* start transfer */ ++ 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); /* start transfer */ ++ printk(KERN_DEBUG "ctrl_start_transfer: submit %d\n", err); + } + } /* ctrl_start_transfer */ + +@@ -293,897 +275,1418 @@ + /* queue a control transfer request */ + /* return 0 on success. */ + /************************************/ +-static int +-queue_control_request(hfcusb_data * hfc, __u8 reg, __u8 val) ++static int queue_control_request(hfcusb_data * hfc, __u8 reg, __u8 val,int action) + { + ctrl_buft *buf; + +- if (hfc->ctrl_cnt >= HFC_CTRL_BUFSIZE) +- return (1); /* no space left */ +- buf = hfc->ctrl_buff + hfc->ctrl_in_idx; /* pointer to new index */ ++#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 */ ++ return(0); ++} /* queue_control_request */ + +-/**************************************/ +-/* called when timer t3 or t4 expires */ +-/**************************************/ +-static void +-l1_timer_expire(hfcusb_data * hfc) +-{ +- if (timer_pending(&hfc->t4_timer)) +- del_timer(&hfc->t4_timer); +- queue_control_request(hfc, HFCUSB_STATES, 0x40); +- test_and_set_bit(HFCUSB_L1_STATECHANGE, +- &hfc->l1_event); +- queue_task(&hfc->l1_tq, &tq_immediate); +- mark_bh(IMMEDIATE_BH); +-} /* l1_timer_expire */ +- +-/**************************************************/ +-/* (re)fills a tx-fifo urb. Queuing is done later */ +-/**************************************************/ +-static void +-fill_tx_urb(usb_fifo * fifo) +-{ +- struct sk_buff *skb; +- long flags; +- int i, ii = 0; +- +- fifo->urb.dev = fifo->hfc->dev; +- if ((fifo->buff) +- && (fifo->urb.transfer_buffer_length < fifo->usb_maxlen)) { +- switch (fifo->fifonum) { +- case HFCUSB_B1_TX: +- case HFCUSB_B2_TX: +- skb = fifo->buff; +- fifo->buff = NULL; +- fifo->hfc->regd.bch_l1l2(fifo->hfc->regd. +- arg_hisax, +- (fifo->fifonum == +- HFCUSB_B1_TX) ? 0 +- : 1, +- (PH_DATA | +- CONFIRM), +- (void *) skb); +- fifo->hfc->service_request |= +- fifo->fifo_mask; +- return; +- case HFCUSB_D_TX: +- dev_kfree_skb_any(fifo->buff); +- fifo->buff = NULL; +- save_flags(flags); +- cli(); +- fifo->hfc->dfifo_fill = 0xff; /* currently invalid data */ +- queue_control_request(fifo->hfc, +- HFCUSB_FIFO, +- HFCUSB_D_TX); +- queue_control_request(fifo->hfc, +- HFCUSB_F_USAGE, 0); +- restore_flags(flags); +- return; +- default: +- return; /* error, invalid fifo */ +- } ++ ++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) ++{ ++ 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 250 ++ ++vendor_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]; + } + +- /* check if new buffer needed */ +- if (!fifo->buff) { +- switch (fifo->fifonum) { +- case HFCUSB_B1_TX: +- if (fifo->hfc->regd.bsk[0]) +- fifo->buff = *fifo->hfc->regd.bsk[0]; /* B1-channel tx buffer */ ++ 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; ++ case LED_S0_OFF: ++ led_state&=~vdata[hfc->vend_idx].led_bits[1]; + break; +- case HFCUSB_B2_TX: +- if (fifo->hfc->regd.bsk[1]) +- fifo->buff = *fifo->hfc->regd.bsk[1]; /* B2-channel tx buffer */ ++ case LED_B1_ON: ++ hfc->led_b_active|=1; + break; +- case HFCUSB_D_TX: +- if (fifo->hfc->regd.dsq) +- fifo->buff = skb_dequeue(fifo->hfc->regd.dsq); /* D-channel tx queue */ ++ case LED_B1_OFF: ++ hfc->led_b_active&=~1; + break; +- default: +- return; /* error, invalid fifo */ ++ case LED_B1_DATA: ++ hfc->led_new_data|=1; ++ break; ++ case LED_B2_ON: ++ hfc->led_b_active|=2; ++ break; ++ case LED_B2_OFF: ++ hfc->led_b_active&=~2; ++ break; ++ case LED_B2_DATA: ++ hfc->led_new_data|=2; ++ break; ++ } ++ ++ write_led(hfc,led_state); ++} ++ ++/********************************/ ++/* called when timer t3 expires */ ++/********************************/ ++static void l1_timer_expire_t3(hfcusb_data * hfc) ++{ ++ //printk (KERN_INFO "HFC-USB: l1_timer_expire_t3\n"); ++ ++ hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,PH_DEACTIVATE | INDICATION,NULL); ++#ifdef VERBOSE_USB_DEBUG ++ printk(KERN_INFO "PH_DEACTIVATE | INDICATION sent\n"); ++#endif ++ hfc->l1_activated=FALSE; ++ handle_led(hfc,LED_S0_OFF); ++} ++ ++/********************************/ ++/* called when timer t4 expires */ ++/********************************/ ++static void l1_timer_expire_t4(hfcusb_data * hfc) ++{ ++ //printk (KERN_INFO "HFC-USB: l1_timer_expire_t4\n"); ++ ++ hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,PH_DEACTIVATE | INDICATION,NULL); ++#ifdef VERBOSE_USB_DEBUG ++ printk(KERN_INFO "PH_DEACTIVATE | INDICATION sent\n"); ++#endif ++ hfc->l1_activated=FALSE; ++ handle_led(hfc,LED_S0_OFF); ++} ++ ++/*****************************/ ++/* handle S0 state changes */ ++/*****************************/ ++static void state_handler(hfcusb_data * hfc,__u8 state) ++{ ++ __u8 old_state; ++ ++ old_state=hfc->l1_state; ++ ++ // range check ++ if(state==old_state || state<1 || state>8) return; ++ ++#ifdef VERBOSE_ISDN_DEBUG ++ printk(KERN_INFO "HFC-USB: new S0 state:%d old_state:%d\n",state,old_state); ++#endif ++ ++ if(state<4 || state==7 || state==8) ++ { ++ if(timer_pending(&hfc->t3_timer)) del_timer(&hfc->t3_timer); ++ //printk(KERN_INFO "HFC-USB: T3 deactivated\n"); ++ } ++ ++ if(state>=7) ++ { ++ if(timer_pending(&hfc->t4_timer)) del_timer(&hfc->t4_timer); ++ //printk(KERN_INFO "HFC-USB: T4 deactivated\n"); ++ } ++ ++ if(state==7 && !hfc->l1_activated) ++ { ++ hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,PH_ACTIVATE | INDICATION,NULL); ++ //printk(KERN_INFO "HFC-USB: PH_ACTIVATE | INDICATION sent\n"); ++ hfc->l1_activated=TRUE; ++ handle_led(hfc,LED_S0_ON); ++ } ++ else ++ if(state<=3 /* && activated*/) ++ { ++ if(old_state==7 || old_state==8) ++ { ++ //printk(KERN_INFO "HFC-USB: T4 activated\n"); ++ hfc->t4_timer.expires = jiffies + (HFC_TIMER_T4 * HZ) / 1000; ++ if(!timer_pending(&hfc->t4_timer)) add_timer(&hfc->t4_timer); + } +- if (!fifo->buff) { +- fifo->active = 0; /* we are inactive now */ +- fifo->hfc->active_fifos &= ~fifo->fifo_mask; +- if (fifo->fifonum == HFCUSB_D_TX) { +- test_and_set_bit(HFCUSB_L1_DTX, +- &fifo->hfc->l1_event); +- queue_task(&fifo->hfc->l1_tq, +- &tq_immediate); +- mark_bh(IMMEDIATE_BH); +- } +- return; ++ else ++ { ++ hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,PH_DEACTIVATE | INDICATION,NULL); ++ //printk(KERN_INFO "HFC-USB: PH_DEACTIVATE | INDICATION sent\n"); ++ hfc->l1_activated=FALSE; ++ handle_led(hfc,LED_S0_OFF); + } +- fifo->act_ptr = fifo->buff->data; /* start of data */ +- fifo->active = 1; +- ii = 1; +- fifo->hfc->active_fifos |= fifo->fifo_mask; +- fifo->hfc->service_request &= ~fifo->fifo_mask; +- } +- /* fillup the send buffer */ +- i = fifo->buff->len - (fifo->act_ptr - fifo->buff->data); /* remaining length */ +- fifo->buffer[0] = !fifo->transmode; /* not eof */ +- if (i > (fifo->usb_maxlen - ii)) { +- i = fifo->usb_maxlen - ii; +- } +- if (i) +- memcpy(fifo->buffer + ii, fifo->act_ptr, i); +- fifo->urb.transfer_buffer_length = i + ii; +- fifo->rx_offset = ii; +-} /* fill_tx_urb */ +- +-/************************************************/ +-/* transmit completion routine for all tx fifos */ +-/************************************************/ +-static void +-tx_complete(purb_t urb) ++ } ++ ++ hfc->l1_state=state; ++} ++ ++ ++/* prepare iso urb */ ++static void fill_isoc_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, void *buf, ++ int num_packets, int packet_size, int interval, usb_complete_t complete, void *context) + { +- usb_fifo *fifo = (usb_fifo *) urb->context; /* pointer to our fifo */ ++ int k; + +- fifo->hfc->service_request &= ~fifo->fifo_mask; /* no further handling */ +- fifo->framenum = usb_get_current_frame_number(fifo->hfc->dev); ++ spin_lock_init(&urb->lock); // do we really need spin_lock_init ? ++ urb->dev = dev; ++ urb->pipe = pipe; ++ urb->complete = complete; ++ urb->number_of_packets = num_packets; ++ urb->transfer_buffer_length = packet_size * num_packets; ++ urb->context = context; ++ urb->transfer_buffer = buf; ++ urb->transfer_flags = 0; ++ urb->transfer_flags = USB_ISO_ASAP; ++ urb->actual_length = 0; ++ urb->interval = interval; ++ for (k = 0; k < num_packets; k++) { ++ urb->iso_frame_desc[k].offset = packet_size * k; ++ urb->iso_frame_desc[k].length = packet_size; ++ urb->iso_frame_desc[k].actual_length = 0; ++ } ++} + +- /* check for deactivation or error */ +- if ((!fifo->active) || (urb->status)) { +- fifo->hfc->active_fifos &= ~fifo->fifo_mask; /* we are inactive */ +- fifo->active = 0; +- if ((fifo->buff) && (fifo->fifonum == HFCUSB_D_TX)) { +- dev_kfree_skb_any(fifo->buff); ++/* allocs urbs and start isoc transfer with two pending urbs to avoid gaps in the transfer chain */ ++static int start_isoc_chain(usb_fifo * fifo, int num_packets_per_urb,usb_complete_t complete,int packet_size) ++{ ++ int i, k, errcode; ++ ++#ifdef VERBOSE_USB_DEBUG ++ printk(KERN_INFO "HFC-USB: starting ISO-chain for Fifo %i\n", fifo->fifonum); ++#endif ++ ++ ++ // allocate Memory for Iso out Urbs ++ for (i = 0; i < 2; i++) { ++ if (!(fifo->iso[i].purb)) { ++ fifo->iso[i].purb = usb_alloc_urb(num_packets_per_urb); ++ fifo->iso[i].owner_fifo = (struct usb_fifo *) fifo; ++ ++ // Init the first iso ++ if (ISO_BUFFER_SIZE >= (fifo->usb_packet_maxlen * num_packets_per_urb)) ++ { ++ ++ fill_isoc_urb(fifo->iso[i].purb, fifo->hfc->dev, fifo->pipe, fifo->iso[i].buffer, ++ num_packets_per_urb, fifo->usb_packet_maxlen, fifo->intervall, ++ complete, &fifo->iso[i]); ++ ++ memset(fifo->iso[i].buffer, 0, sizeof(fifo->iso[i].buffer)); ++ ++ // defining packet delimeters in fifo->buffer ++ for(k = 0; k < num_packets_per_urb; k++) ++ { ++ fifo->iso[i].purb->iso_frame_desc[k].offset = k*packet_size; ++ fifo->iso[i].purb->iso_frame_desc[k].length = packet_size; ++ } ++ } + } +- fifo->buff = NULL; +- return; ++ ++ fifo->bit_line = BITLINE_INF; ++ ++ errcode = usb_submit_urb(fifo->iso[i].purb); ++ fifo->active = (errcode >= 0) ? 1 : 0; ++ if(errcode < 0) ++ { ++ printk(KERN_INFO "HFC-USB: error submitting ISO URB: %i.%i \n", errcode, i); ++ }; ++ + } +- fifo->act_ptr += (urb->transfer_buffer_length - fifo->rx_offset); /* adjust pointer */ +- fill_tx_urb(fifo); /* refill the urb */ +- fifo->hfc->threshold_mask |= fifo->fifo_mask; /* assume threshold reached */ +- if (fifo->buff) +- fifo->hfc->service_request |= fifo->fifo_mask; /* need to restart */ +-} /* tx_complete */ + +-/***********************************************/ +-/* receive completion routine for all rx fifos */ +-/***********************************************/ +-static void +-rx_complete(purb_t urb) ++ // errcode = (usb_submit_urb(fifo->iso[0].purb, GFP_KERNEL)); ++ return(fifo->active); ++} ++ ++/* stops running iso chain and frees their pending urbs */ ++static void stop_isoc_chain(usb_fifo * fifo) + { +- usb_fifo *fifo = (usb_fifo *) urb->context; /* pointer to our fifo */ +- hfcusb_data *hfc = fifo->hfc; +- usb_fifo *txfifo; +- __u8 last_state; +- int i, ii, currcnt, hdlci; +- struct sk_buff *skb; +- +- urb->dev = hfc->dev; /* security init */ +- if ((!fifo->active) || (urb->status)) { +- hfc->service_request &= ~fifo->fifo_mask; /* no further handling */ +- hfc->active_fifos &= ~fifo->fifo_mask; /* we are inactive */ +- fifo->urb.interval = 0; /* cancel automatic rescheduling */ +- if (fifo->buff) { +- dev_kfree_skb_any(fifo->buff); +- fifo->buff = NULL; ++ int i; ++ ++ for(i = 0; i < 2; i++) ++ { ++ if(fifo->iso[i].purb) ++ { ++#ifdef VERBOSE_USB_DEBUG ++ printk(KERN_INFO "HFC-USB: Stopping iso chain for fifo %i.%i\n", fifo->fifonum, i); ++#endif ++ usb_unlink_urb(fifo->iso[i].purb); ++ usb_free_urb(fifo->iso[i].purb); ++ fifo->iso[i].purb = NULL; + } +- return; + } ++ if (fifo->urb) { ++ usb_unlink_urb(fifo->urb); ++ usb_free_urb(fifo->urb); ++ fifo->urb = NULL; ++ } ++ fifo->active = 0; ++} + +- /* first check for any status changes */ +- if ((urb->actual_length < fifo->rx_offset) +- || (urb->actual_length > fifo->usb_maxlen)) +- return; /* error condition */ +- +- if (fifo->rx_offset) { +- hfc->threshold_mask = fifo->buffer[1]; /* update threshold status */ +- fifo->next_complete = fifo->buffer[0] & 1; +- if ((fifo->fifonum == HFCUSB_D_RX) && +- (hfc->led_req != hfc->led_act)) +- queue_control_request(hfc, HFCUSB_P_DATA, hfc->led_req); +- +- /* check if rescheduling needed */ +- if ((i = +- hfc->service_request & hfc->active_fifos & ~hfc-> +- threshold_mask)) { +- currcnt = +- usb_get_current_frame_number(hfc->dev); +- txfifo = hfc->fifos + HFCUSB_B1_TX; +- ii = 3; +- while (ii--) { +- if ((i & txfifo->fifo_mask) +- && (currcnt != txfifo->framenum)) { +- hfc->service_request &= +- ~txfifo->fifo_mask; +- if (!txfifo->buff) +- fill_tx_urb(txfifo); +- if (txfifo->buff) +- usb_submit_urb(&txfifo-> +- urb); ++// defines how much ISO packets are handled in one URB ++static int iso_packets[8]={ISOC_PACKETS_B,ISOC_PACKETS_B,ISOC_PACKETS_B,ISOC_PACKETS_B, ++ ISOC_PACKETS_D,ISOC_PACKETS_D,ISOC_PACKETS_D,ISOC_PACKETS_D}; ++ ++/*****************************************************/ ++/* transmit completion routine for all ISO tx fifos */ ++/*****************************************************/ ++static void tx_iso_complete(struct urb *urb) ++{ ++ iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context; ++ usb_fifo *fifo = context_iso_urb->owner_fifo; ++ hfcusb_data *hfc = fifo->hfc; ++ int k, tx_offset, num_isoc_packets, sink, len, current_len,errcode,frame_complete,transp_mode,fifon; ++ __u8 threshbit; ++ __u8 threshtable[8] = { 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80}; ++ ++ fifon=fifo->fifonum; ++ tx_offset=0; ++ // very weird error code when using ohci drivers, for now : ignore this error ... (MB) ++ if(urb->status == -EOVERFLOW) ++ { ++ urb->status = 0; ++#ifdef VERBOSE_USB_DEBUG ++ printk(KERN_INFO "HFC-USB: ignoring USB DATAOVERRUN for fifo %i \n",fifon); ++#endif ++ } ++ ++ if(fifo->active && !urb->status) ++ { ++ transp_mode=0; ++ if(fifon<4 && hfc->b_mode[fifon/2]==L1_MODE_TRANS) transp_mode=TRUE; ++ ++ threshbit = threshtable[fifon] & hfc->threshold_mask; // is threshold set for our channel? ++ num_isoc_packets=iso_packets[fifon]; ++ ++ if(fifon >= HFCUSB_D_TX) ++ { ++ sink = (threshbit) ? SINK_DMIN : SINK_DMAX; // how much bit go to the sink for D-channel? ++ } ++ else ++ { ++ sink = (threshbit) ? SINK_MIN : SINK_MAX; // how much bit go to the sink for B-channel? ++ } ++ ++ // prepare ISO Urb ++ fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe,context_iso_urb->buffer, num_isoc_packets, ++ fifo->usb_packet_maxlen, fifo->intervall, tx_iso_complete, urb->context); ++ memset(context_iso_urb->buffer, 0, sizeof(context_iso_urb->buffer)); ++ ++ frame_complete=FALSE; ++ ++ // Generate Iso Packets ++ for(k = 0; k < num_isoc_packets; ++k) ++ { ++ if(fifo->skbuff) ++ { ++ len = fifo->skbuff->len; // remaining length ++ ++ fifo->bit_line -= sink; // we lower data margin every msec ++ current_len = (0 - fifo->bit_line) / 8; ++ if(current_len > 14) current_len = 14; // maximum 15 byte for every ISO packet makes our life easier ++ current_len = (len <= current_len) ? len : current_len; ++ fifo->bit_line += current_len * 8; // how much bit do we put on the line? ++ ++ context_iso_urb->buffer[tx_offset] = 0; ++ if(current_len == len) ++ { ++ if(!transp_mode) ++ { ++ context_iso_urb->buffer[tx_offset] = 1; // here frame completion ++ fifo->bit_line += 32; // add 2 byte flags and 16bit CRC at end of ISDN frame ++ } ++ frame_complete = TRUE; ++ } ++ ++ // copy bytes from buffer into ISO_URB ++ memcpy(context_iso_urb->buffer+tx_offset+1,fifo->skbuff->data,current_len); ++ skb_pull(fifo->skbuff,current_len); ++ ++ // define packet delimeters within the URB buffer ++ urb->iso_frame_desc[k].offset = tx_offset; ++ urb->iso_frame_desc[k].length = current_len + 1; ++ ++ tx_offset += (current_len + 1); ++ // printk(KERN_INFO "HFC-USB: fifonum:%d,%d bytes to send, %d bytes ISO packet,bitline:%d,sink:%d,threshbit:%d,threshmask:%x\n",fifon,len,current_len,fifo->bit_line,sink,threshbit,hfc->threshold_mask); ++ if(!transp_mode) ++ { ++ if(fifon==HFCUSB_B1_TX) handle_led(hfc,LED_B1_DATA); ++ if(fifon==HFCUSB_B2_TX) handle_led(hfc,LED_B2_DATA); ++ } ++ } ++ else ++ { ++ // we have no more data - generate 1 byte ISO packets ++ urb->iso_frame_desc[k].offset = tx_offset++; ++ ++ urb->iso_frame_desc[k].length = 1; ++ fifo->bit_line -= sink; // we lower data margin every msec ++ ++ if(fifo->bit_line < BITLINE_INF) ++ { ++ fifo->bit_line = BITLINE_INF; ++ //printk (KERN_INFO "HFC-USB: BITLINE_INF underrun\n"); + } +- txfifo += 2; + } +- } + +- /* handle l1 events */ +- if ((fifo->buffer[0] >> 4) != hfc->l1_state) { +- last_state = hfc->l1_state; +- hfc->l1_state = fifo->buffer[0] >> 4; /* update status */ +- if (timer_pending(&hfc->t4_timer)) +- del_timer(&hfc->t4_timer); +- if (((hfc->l1_state == 3) && +- ((last_state == 7) || +- (last_state == 8))) || +- ((timer_pending(&hfc->t3_timer) && +- (hfc->l1_state == 8)))) { +- hfc->t4_timer.expires = jiffies + 2; +- add_timer(&hfc->t4_timer); +- } else { +- if (timer_pending(&hfc->t3_timer) +- && (hfc->l1_state == 7)) +- del_timer(&hfc->t3_timer); /* no longer needed */ +- test_and_set_bit(HFCUSB_L1_STATECHANGE, +- &hfc->l1_event); +- queue_task(&hfc->l1_tq, &tq_immediate); +- mark_bh(IMMEDIATE_BH); ++ if(frame_complete) ++ { ++ // delete the buffer only once, here or in hfc_usb_l2l1() in a PH_DATA|REQUEST ++ fifo->delete_flg=TRUE; ++ ++ fifo->hif->l1l2(fifo->hif,PH_DATA|CONFIRM,(void*)fifo->skbuff->truesize); ++ ++ if(fifo->skbuff && fifo->delete_flg) ++ { ++ dev_kfree_skb_any(fifo->skbuff); ++ //printk(KERN_INFO "HFC-USB: skbuff=NULL on fifo:%d\n",fifo->fifonum); ++ fifo->skbuff = NULL; ++ fifo->delete_flg=FALSE; ++ } ++ ++ frame_complete=FALSE; + } ++ } ++ ++ errcode = usb_submit_urb(urb); ++ if(errcode < 0) ++ { ++ printk(KERN_INFO "HFC-USB: error submitting ISO URB: %i \n", errcode); ++ } ++ } ++ else ++ { ++ if(urb->status) ++ { ++ printk(KERN_INFO "HFC-USB: tx_iso_complete : urb->status %i, fifonum %i\n", urb->status,fifon); + } + } + +- /* check the length for data and move if present */ +- if (fifo->next_complete || (urb->actual_length > fifo->rx_offset)) { +- i = fifo->buff->len + urb->actual_length - fifo->rx_offset; /* new total length */ +- hdlci = (fifo->transmode) ? 0 : 3; +- if (i <= (fifo->max_size + hdlci)) { +- memcpy(fifo->act_ptr, +- fifo->buffer + fifo->rx_offset, +- urb->actual_length - fifo->rx_offset); +- fifo->act_ptr += +- (urb->actual_length - fifo->rx_offset); +- fifo->buff->len += +- (urb->actual_length - fifo->rx_offset); +- } else +- fifo->buff->len = fifo->max_size + 4; /* mark frame as to long */ +- if (fifo->next_complete && (urb->actual_length < fifo->usb_maxlen)) { +- /* the frame is complete */ +- fifo->next_complete = 0; +- if (((!*(fifo->act_ptr - 1)) || fifo->transmode) && +- (fifo->buff->len >= (hdlci + 1)) +- && (fifo->buff->len <= +- (fifo->max_size + hdlci)) && +- ((skb = dev_alloc_skb(fifo->max_size + hdlci)) != NULL)) { +- fifo->buff->len -= hdlci; /* adjust size */ +- switch (fifo->fifonum) { +- case HFCUSB_D_RX: +- skb_queue_tail(hfc->regd. +- drq, +- fifo->buff); +- test_and_set_bit +- (HFCUSB_L1_DRX, +- &hfc->l1_event); +- queue_task(&hfc->l1_tq, +- &tq_immediate); +- mark_bh(IMMEDIATE_BH); +- break; ++} /* tx_iso_complete */ + +- case HFCUSB_B1_RX: +- if (hfc->regd.brq[0]) { +- skb_queue_tail +- (hfc->regd. +- brq[0], +- fifo->buff); +- hfc->regd. +- bch_l1l2(hfc-> +- regd. +- arg_hisax, +- 0, +- PH_DATA +- | +- INDICATION, +- (void *) +- fifo-> +- buff); +- } else +- dev_kfree_skb_any +- (fifo->buff); +- break; +- +- case HFCUSB_B2_RX: +- if (hfc->regd.brq[1]) { +- skb_queue_tail +- (hfc->regd. +- brq[1], +- fifo->buff); +- hfc->regd. +- bch_l1l2(hfc-> +- regd. +- arg_hisax, +- 1, +- PH_DATA +- | +- INDICATION, +- (void +- *) +- fifo-> +- buff); +- } else +- dev_kfree_skb_any +- (fifo->buff); +- break; ++/*****************************************************/ ++/* receive completion routine for all ISO tx fifos */ ++/*****************************************************/ ++static void rx_iso_complete(struct urb *urb) ++{ ++ iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context; ++ usb_fifo *fifo = context_iso_urb->owner_fifo; ++ hfcusb_data *hfc = fifo->hfc; ++ int k, len, errcode, offset, num_isoc_packets,fifon; ++ __u8 *buf; + +- case HFCUSB_PCM_RX: +- skb_queue_tail(&hfc->regd. +- erq, +- fifo->buff); +- test_and_set_bit +- (HFCUSB_L1_ERX, +- &hfc->l1_event); +- queue_task(&hfc->l1_tq, +- &tq_immediate); +- mark_bh(IMMEDIATE_BH); +- break; ++ fifon=fifo->fifonum; ++ // very weird error code when using ohci drivers, for now : ignore this error ... (MB) ++ if(urb->status == -EOVERFLOW) ++ { ++ urb->status = 0; ++#ifdef VERBOSE_USB_DEBUG ++ printk(KERN_INFO "HFC-USB: ignoring USB DATAOVERRUN for fifo %i \n",fifon); ++#endif ++ } + +- default: +- dev_kfree_skb_any(fifo-> +- buff); +- break; ++ if(fifo->active && !urb->status) ++ { ++ num_isoc_packets=iso_packets[fifon]; ++ ++ // Generate D-Channel Iso Packets ++ for(k = 0; k < num_isoc_packets; ++k) ++ { ++ len=urb->iso_frame_desc[k].actual_length; ++ offset=urb->iso_frame_desc[k].offset; ++ buf=context_iso_urb->buffer+offset; ++ ++ 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,len-2,buf[0]&1); + } +- fifo->buff = skb; +- } +- fifo->buff->len = 0; /* reset counter */ +- fifo->act_ptr = fifo->buff->data; /* and pointer */ ++ else collect_rx_frame(fifo,buf,len,0); ++ ++ fifo->last_urblen=len; ++ ++ } ++ ++ // prepare ISO Urb ++ fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe,context_iso_urb->buffer, num_isoc_packets, ++ fifo->usb_packet_maxlen, fifo->intervall, rx_iso_complete, urb->context); ++ ++ errcode = usb_submit_urb(urb); ++ if(errcode < 0) ++ { ++ printk(KERN_INFO "HFC-USB: error submitting ISO URB: %i \n", errcode); ++ } ++ } ++ else ++ { ++ if(urb->status) ++ { ++ printk(KERN_INFO "HFC-USB: rx_iso_complete : urb->status %i, fifonum %i\n", urb->status,fifon); ++ } ++ } ++} /* 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) ++{ ++ 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; + } +- fifo->rx_offset = (urb->actual_length < fifo->usb_maxlen) ? 2 : 0; +-} /* rx_complete */ ++ ++ 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_rx_fifo(usb_fifo * fifo) ++static void start_int_fifo(usb_fifo * fifo) + { +- if (fifo->buff) +- return; /* still active */ +- if (! +- (fifo->buff = +- dev_alloc_skb(fifo->max_size + (fifo->transmode ? 0 : 3)))) +- return; +- fifo->act_ptr = fifo->buff->data; +- FILL_INT_URB(&fifo->urb, fifo->hfc->dev, fifo->pipe, fifo->buffer, +- fifo->usb_maxlen, rx_complete, fifo, fifo->intervall); +- fifo->next_complete = 0; +- fifo->rx_offset = 2; +- fifo->active = 1; /* must be marked active */ +- fifo->hfc->active_fifos |= fifo->fifo_mask; +- if (usb_submit_urb(&fifo->urb)) { ++ 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); ++ 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); ++ ++ if(errcode) ++ { ++ printk(KERN_INFO "HFC-USB: submit URB error(start_int_info): status:%i\n", errcode); + fifo->active = 0; +- fifo->hfc->active_fifos &= ~fifo->fifo_mask; +- dev_kfree_skb_any(fifo->buff); +- fifo->buff = NULL; ++ fifo->skbuff = NULL; + } +-} /* start_rx_fifo */ ++} /* start_int_fifo */ + +-/***************************************************************/ +-/* control completion routine handling background control cmds */ +-/***************************************************************/ +-static void +-ctrl_complete(purb_t urb) ++/*****************************/ ++/* set the B-channel mode */ ++/*****************************/ ++static void set_hfcmode(hfcusb_data *hfc,int channel,int mode) + { +- hfcusb_data *hfc = (hfcusb_data *) urb->context; ++ __u8 val,idx_table[2]={0,2}; + +- urb->dev = hfc->dev; +- if (hfc->ctrl_cnt) { +- switch (hfc->ctrl_buff[hfc->ctrl_out_idx].hfc_reg) { +- case HFCUSB_FIFO: +- hfc->ctrl_fifo = +- hfc->ctrl_buff[hfc->ctrl_out_idx]. +- reg_val; +- break; +- case HFCUSB_F_USAGE: +- if (!hfc->dfifo_fill) { +- fill_tx_urb(hfc->fifos + +- HFCUSB_D_TX); +- if (hfc->fifos[HFCUSB_D_TX].buff) +- usb_submit_urb(&hfc-> +- fifos +- [HFCUSB_D_TX]. +- urb); +- } else { +- queue_control_request(hfc, +- HFCUSB_FIFO, +- HFCUSB_D_TX); +- queue_control_request(hfc, +- HFCUSB_F_USAGE, +- 0); +- } +- break; +- case HFCUSB_SCTRL_R: +- switch (hfc->ctrl_fifo) { +- case HFCUSB_B1_RX: +- if (hfc->bch_enables & 1) +- start_rx_fifo(hfc-> +- fifos +- + +- HFCUSB_B1_RX); +- break; +- case HFCUSB_B2_RX: +- if (hfc->bch_enables & 2) +- start_rx_fifo(hfc-> +- fifos +- + +- HFCUSB_B2_RX); +- break; +- } +- if (hfc->bch_enables & 3) +- hfc->led_req |= LED_BCH; +- else +- hfc->led_req &= ~LED_BCH; +- break; +- case HFCUSB_P_DATA: +- hfc->led_act = +- hfc->ctrl_buff[hfc->ctrl_out_idx]. +- reg_val; +- break; +- } +- 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 */ ++#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); + } +-} /* ctrl_complete */ ++ else ++ { ++ if(channel) handle_led(hfc,LED_B2_ON); ++ else handle_led(hfc,LED_B1_ON); ++ } ++} + +-/*****************************************/ +-/* Layer 1 + D channel access from HiSax */ +-/*****************************************/ +-static void +-hfcusb_l1_access(void *drvarg, int pr, void *arg) +-{ +- hfcusb_data *hfc = (hfcusb_data *) drvarg; +- +- switch (pr) { +- case (PH_DATA | REQUEST): +- case (PH_PULL | INDICATION): +- skb_queue_tail(hfc->regd.dsq, +- (struct sk_buff *) arg); +- if (!hfc->fifos[HFCUSB_D_TX].active +- && !hfc->dfifo_fill) { +- fill_tx_urb(hfc->fifos + HFCUSB_D_TX); +- hfc->active_fifos |= +- hfc->fifos[HFCUSB_D_TX].fifo_mask; +- usb_submit_urb(&hfc->fifos[HFCUSB_D_TX]. +- urb); +- } +- break; +- case (PH_ACTIVATE | REQUEST): +- switch (hfc->l1_state) { +- case 6: +- case 8: +- hfc->regd.dch_l1l2(hfc->regd.arg_hisax, +- (PH_DEACTIVATE | +- INDICATION), NULL); ++/* ++ -------------------------------------------------------------------------------------- ++ from here : hisax_if callback routines : ++ - void hfc_usb_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg) { + +- break; +- case 7: +- hfc->regd.dch_l1l2(hfc->regd.arg_hisax, +- (PH_ACTIVATE | +- INDICATION), NULL); ++ l1 to l2 routines : ++ - static void hfc_usb_l1l2(hfcusb_data * hfc) + +- break; +- default: +- queue_control_request(hfc, HFCUSB_STATES, 0x60); /* start activation */ +- hfc->t3_timer.expires = +- jiffies + (HFC_TIMER_T3 * HZ) / 1000; +- if (!timer_pending(&hfc->t3_timer)) +- add_timer(&hfc->t3_timer); +- break; +- } +- break; ++*/ + +- case (PH_DEACTIVATE | REQUEST): +- queue_control_request(hfc, HFCUSB_STATES, 0x40); /* start deactivation */ +- break; +- default: +- printk(KERN_INFO "unknown hfcusb l1_access 0x%x\n", +- pr); +- break; +- } +-} /* hfcusb_l1_access */ +- +-/*******************************/ +-/* B channel access from HiSax */ +-/*******************************/ +-static void +-hfcusb_bch_access(void *drvarg, int chan, int pr, void *arg) +-{ +- hfcusb_data *hfc = (hfcusb_data *) drvarg; +- usb_fifo *fifo = hfc->fifos + (chan ? HFCUSB_B2_TX : HFCUSB_B1_TX); +- long flags; +- +- switch (pr) { +- case (PH_DATA | REQUEST): +- case (PH_PULL | INDICATION): +- save_flags(flags); +- cli(); +- if (!fifo->active) { +- fill_tx_urb(fifo); +- hfc->active_fifos |= fifo->fifo_mask; +- usb_submit_urb(&fifo->urb); +- } +- restore_flags(flags); +- break; +- case (PH_ACTIVATE | REQUEST): +- if (!((int) arg)) { +- hfc->bch_enables &= ~(1 << chan); +- if (fifo->active) { +- fifo->active = 0; +- usb_unlink_urb(&fifo->urb); ++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); + } +- save_flags(flags); +- cli(); +- queue_control_request(hfc, HFCUSB_FIFO, +- fifo->fifonum); +- queue_control_request(hfc, +- HFCUSB_INC_RES_F, 2); +- queue_control_request(hfc, HFCUSB_CON_HDLC, +- 9); +- queue_control_request(hfc, HFCUSB_SCTRL, +- 0x40 + +- hfc->bch_enables); +- queue_control_request(hfc, HFCUSB_SCTRL_R, +- hfc->bch_enables); +- restore_flags(flags); +- fifo++; +- if (fifo->active) { +- fifo->active = 0; +- usb_unlink_urb(&fifo->urb); ++ 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); + } +- return; /* fifo deactivated */ +- } +- fifo->transmode = ((int) arg == L1_MODE_TRANS); +- fifo->max_size = +- ((fifo->transmode) ? fifo-> +- usb_maxlen : MAX_BCH_SIZE); +- (fifo + 1)->transmode = fifo->transmode; +- (fifo + 1)->max_size = fifo->max_size; +- hfc->bch_enables |= (1 << chan); +- save_flags(flags); +- cli(); +- queue_control_request(hfc, HFCUSB_FIFO, +- fifo->fifonum); +- queue_control_request(hfc, HFCUSB_CON_HDLC, +- ((!fifo-> +- transmode) ? 9 : 11)); +- queue_control_request(hfc, HFCUSB_INC_RES_F, 2); +- queue_control_request(hfc, HFCUSB_SCTRL, +- 0x40 + hfc->bch_enables); +- if ((int) arg == L1_MODE_HDLC) +- queue_control_request(hfc, HFCUSB_CON_HDLC, +- 8); +- queue_control_request(hfc, HFCUSB_FIFO, +- fifo->fifonum + 1); +- queue_control_request(hfc, HFCUSB_CON_HDLC, +- ((!fifo-> +- transmode) ? 8 : 10)); +- queue_control_request(hfc, HFCUSB_INC_RES_F, 2); +- queue_control_request(hfc, HFCUSB_SCTRL_R, +- hfc->bch_enables); +- restore_flags(flags); +- +- break; +- +- default: +- printk(KERN_INFO +- "unknown hfcusb bch_access chan %d 0x%x\n", +- chan, pr); +- break; +- } +-} /* hfcusb_bch_access */ ++ 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 parmeters. It registers the driver at the main hisax module. */ ++/* main parameters. It registers the driver at the main hisax module. */ + /* on success 0 is returned. */ + /***************************************************************************/ +-static int +-usb_init(hfcusb_data * hfc) ++static int usb_init(hfcusb_data * hfc) + { + usb_fifo *fifo; +- int i; ++ int i, err; + u_char b; +- ++ struct hisax_b_if *p_b_if[2]; ++ + /* check the chip id */ +- if ((Read_hfc(hfc, HFCUSB_CHIP_ID, &b) != 1) || +- (b != HFCUSB_CHIPID)) { ++ 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); ++ return(1); + } + + /* first set the needed config, interface and alternate */ +- usb_set_configuration(hfc->dev, 1); +- usb_set_interface(hfc->dev, hfc->if_used, hfc->alt_used); ++ 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 + +- /* init the led state request */ +- hfc->led_req = LED_DRIVER; ++ // 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)); + +- /* now we initialise the chip */ +- Write_hfc(hfc, HFCUSB_CIRM, 0x10); /* aux = output, reset off */ +- Write_hfc(hfc, HFCUSB_P_DATA, 0); /* leds = off */ +- Write_hfc(hfc, HFCUSB_USB_SIZE, +- (hfc->fifos[HFCUSB_B1_TX].usb_maxlen >> 3) | +- ((hfc->fifos[HFCUSB_B1_RX].usb_maxlen >> 3) << 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_hfc(hfc, HFCUSB_MST_MODE1, 0); /* set default values */ +- Write_hfc(hfc, HFCUSB_MST_MODE0, 1); /* enable 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_hfc(hfc, HFCUSB_F_THRES, (HFCUSB_TX_THRESHOLD >> 3) | +- ((HFCUSB_RX_THRESHOLD >> 3) << 4)); ++ write_usb(hfc, HFCUSB_F_THRES, (HFCUSB_TX_THRESHOLD/8) |((HFCUSB_RX_THRESHOLD/8) << 4)); + +- for (i = 0, fifo = hfc->fifos + i; i < HFCUSB_NUM_FIFOS; +- i++, fifo++) { +- Write_hfc(hfc, HFCUSB_FIFO, i); /* select the desired fifo */ +- +- fifo->transmode = 0; /* hdlc mode selected */ +- fifo->buff = NULL; /* init buffer pointer */ +- fifo->max_size = +- (i <= HFCUSB_B2_RX) ? MAX_BCH_SIZE : MAX_DFRAME_LEN; +- Write_hfc(hfc, HFCUSB_HDLC_PAR, ((i <= HFCUSB_B2_RX) ? 0 : 2)); /* data length */ +- Write_hfc(hfc, HFCUSB_CON_HDLC, ((i & 1) ? 0x08 : 0x09)); /* rx hdlc, tx fill 1 */ +- Write_hfc(hfc, HFCUSB_INC_RES_F, 2); /* reset the fifo */ +- } +- +- Write_hfc(hfc, HFCUSB_CLKDEL, 0x0f); /* clock delay value */ +- Write_hfc(hfc, HFCUSB_STATES, 3 | 0x10); /* set deactivated mode */ +- Write_hfc(hfc, HFCUSB_STATES, 3); /* enable state machine */ ++ 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_hfc(hfc, HFCUSB_SCTRL_R, 0); /* disable both B receivers */ +- Write_hfc(hfc, HFCUSB_SCTRL, 0x40); /* disable B transmitters + cap mode */ ++ 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 l1 timer */ ++ /* init the t3 timer */ + init_timer(&hfc->t3_timer); + hfc->t3_timer.data = (long) hfc; +- hfc->t3_timer.function = (void *) l1_timer_expire; ++ 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; +- hfc->l1_tq.routine = (void *) (void *) usb_l1d_bh; +- hfc->l1_tq.sync = 0; +- hfc->l1_tq.data = hfc; +- +- /* init the background control machinery */ +- hfc->ctrl_read.requesttype = 0xc0; +- hfc->ctrl_read.request = 1; +- hfc->ctrl_read.length = 1; +- hfc->ctrl_write.requesttype = 0x40; +- hfc->ctrl_write.request = 0; +- hfc->ctrl_write.length = 0; +- FILL_CONTROL_URB(&hfc->ctrl_urb, hfc->dev, hfc->ctrl_out_pipe, +- (u_char *) & hfc->ctrl_write, NULL, 0, +- ctrl_complete, hfc); +- +- /* init the TX-urbs */ +- fifo = hfc->fifos + HFCUSB_D_TX; +- FILL_BULK_URB(&fifo->urb, hfc->dev, fifo->pipe, +- (u_char *) fifo->buffer, 0, tx_complete, fifo); +- fifo = hfc->fifos + HFCUSB_B1_TX; +- FILL_BULK_URB(&fifo->urb, hfc->dev, fifo->pipe, +- (u_char *) fifo->buffer, 0, tx_complete, fifo); +- fifo = hfc->fifos + HFCUSB_B2_TX; +- FILL_BULK_URB(&fifo->urb, hfc->dev, fifo->pipe, +- (u_char *) fifo->buffer, 0, tx_complete, fifo); +- +- /* init the E-buffer */ +- skb_queue_head_init(&hfc->regd.erq); +- +- /* now register ourself at hisax */ +- hfc->regd.version = HISAX_LOAD_VERSION; /* set our version */ +- hfc->regd.cmd = HISAX_LOAD_REGISTER; /* register command */ +- hfc->regd.argl1 = (void *) hfc; /* argument for our local routine */ +- hfc->regd.dch_l2l1 = hfcusb_l1_access; +- hfc->regd.bch_l2l1 = hfcusb_bch_access; +- hfc->regd.drvname = "hfc_usb"; +- if (hisax_register_hfcusb(&hfc->regd)) { +- printk(KERN_INFO "HFC-USB failed to register at hisax\n"); +- Write_hfc(hfc, HFCUSB_CIRM, 0x08); /* aux = input, reset on */ +- return (1); +- } +- +- /* startup the D- and E-channel fifos */ +- start_rx_fifo(hfc->fifos + HFCUSB_D_RX); /* D-fifo */ +- if (hfc->fifos[HFCUSB_PCM_RX].pipe) +- start_rx_fifo(hfc->fifos + HFCUSB_PCM_RX); /* E-fifo */ ++ 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++) ++ { ++ 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]; ++ } ++ ++ hfc->protocol = 2; /* default EURO ISDN, should be a module_param */ ++ hisax_register(&hfc->d_if, p_b_if, "hfc_usb", hfc->protocol); ++ ++ 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); // Int IN D-fifo ++ if(hfc->fifos[HFCUSB_PCM_RX].pipe) start_int_fifo(hfc->fifos + HFCUSB_PCM_RX); // E-fifo ++ start_int_fifo(hfc->fifos + HFCUSB_B1_RX); // Int IN B1-fifo ++ start_int_fifo(hfc->fifos + HFCUSB_B2_RX); // Int IN B2-fifo ++ } ++ ++ // 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); ++} /* usb_init */ ++ ++ ++/****************************************/ ++/* data defining the devices to be used */ ++/****************************************/ ++// static __devinitdata const struct usb_device_id hfc_usb_idtab[3] = { ++static struct usb_device_id hfc_usb_idtab[] = { ++ {USB_DEVICE(0x7b0, 0x0007)}, /* Billion USB TA 2 */ ++ {USB_DEVICE(0x742, 0x2008)}, /* Stollmann USB TA */ ++ {USB_DEVICE(0x959, 0x2bd0)}, /* Colognechip USB eval TA */ ++ {USB_DEVICE(0x8e3, 0x0301)}, /* OliTec ISDN USB */ ++ {USB_DEVICE(0x675, 0x1688)}, /* DrayTec ISDN USB */ ++ {USB_DEVICE(0x7fa, 0x0846)}, /* Bewan ISDN USB TA */ ++ {} /* end with an all-zeroes entry */ ++}; ++ ++MODULE_AUTHOR("Peter Sprenger (sprenger@moving-byters.de)/Martin Bachem (info@colognechip.com)"); ++MODULE_DESCRIPTION("HFC I4L USB driver"); ++MODULE_DEVICE_TABLE(usb, hfc_usb_idtab); ++MODULE_LICENSE("GPL"); ++ ++#define EP_NUL 1 // Endpoint at this position not allowed ++#define EP_NOP 2 // all type of endpoints allowed at this position ++#define EP_ISO 3 // Isochron endpoint mandatory at this position ++#define EP_BLK 4 // Bulk endpoint mandatory at this position ++#define EP_INT 5 // Interrupt endpoint mandatory at this position ++ ++// this array represents all endpoints possible in the HCF-USB ++// the last 2 entries are the configuration number and the minimum interval for Interrupt endpoints ++int validconf[][18]= ++{ ++ // INT in, ISO out config ++ {EP_NUL,EP_INT,EP_NUL,EP_INT,EP_NUL,EP_INT,EP_NOP,EP_INT,EP_ISO,EP_NUL,EP_ISO,EP_NUL,EP_ISO,EP_NUL,EP_NUL,EP_NUL,CNF_4INT3ISO,2}, ++ {EP_NUL,EP_INT,EP_NUL,EP_INT,EP_NUL,EP_INT,EP_NUL,EP_NUL,EP_ISO,EP_NUL,EP_ISO,EP_NUL,EP_ISO,EP_NUL,EP_NUL,EP_NUL,CNF_3INT3ISO,2}, ++ // ISO in, ISO out config ++ {EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_NOP,EP_ISO,CNF_4ISO3ISO,2}, ++ {EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_NUL,EP_NUL,CNF_3ISO3ISO,2}, ++ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} // EOL element ++}; ++ ++// string description of chosen config ++char *conf_str[]= ++{ ++ "4 Interrupt IN + 3 Isochron OUT", ++ "3 Interrupt IN + 3 Isochron OUT", ++ "4 Isochron IN + 3 Isochron OUT", ++ "3 Isochron IN + 3 Isochron OUT" ++}; + +- return (0); +-} /* usb_init */ + + /*************************************************/ + /* function called to probe a new plugged device */ + /*************************************************/ +-static void * +-hfc_usb_probe(struct usb_device *dev, unsigned int interface +-#ifdef COMPAT_HAS_USB_IDTAB +- , const struct usb_device_id *id_table) +-#else +- ) +-#endif ++//static int hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) ++static void* hfc_usb_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id) + { ++ //struct usb_device *dev= interface_to_usbdev(intf); ++ struct usb_interface* intf = dev->actconfig->interface + ifnum; + hfcusb_data *context; +- struct usb_interface *ifp = dev->actconfig->interface + interface; +- struct usb_interface_descriptor *ifdp = +- ifp->altsetting + ifp->act_altsetting; +- struct usb_endpoint_descriptor *epd; +- int i, idx, ep_msk; +- +-#ifdef COMPAT_HAS_USB_IDTAB +- if (id_table && (dev->descriptor.idVendor == id_table->idVendor) && +- (dev->descriptor.idProduct == id_table->idProduct) && +-#else +- if ((((dev->descriptor.idVendor == 0x959) && +- (dev->descriptor.idProduct == 0x2bd0)) || +- ((dev->descriptor.idVendor == 0x7b0) && +- (dev->descriptor.idProduct == 0x0006))) && +-#endif +- (ifdp->bNumEndpoints >= 6) && (ifdp->bNumEndpoints <= 16)) { +- if (!(context = kmalloc(sizeof(hfcusb_data), GFP_KERNEL))) { +- return (NULL); /* got no mem */ +- }; +- memset(context, 0, sizeof(hfcusb_data)); /* clear the structure */ +- i = ifdp->bNumEndpoints; /* get number of endpoints */ +- ep_msk = 0; /* none found */ +- epd = ifdp->endpoint; /* first endpoint descriptor */ +- while (i-- && ((ep_msk & 0xcf) != 0xcf)) { +- +- idx = (((epd->bEndpointAddress & 0x7f) - 1) << 1); /* get endpoint base */ +- if (idx < 7) { +- switch (epd->bmAttributes) { +- case USB_ENDPOINT_XFER_INT: +- if (! +- (epd-> +- bEndpointAddress & +- 0x80)) +- break; /* only interrupt in allowed */ +- idx++; /* input index is odd */ +- context->fifos[idx].pipe = +- usb_rcvintpipe(dev, +- epd-> +- bEndpointAddress); +- break; +- +- case USB_ENDPOINT_XFER_BULK: +- if (epd-> +- bEndpointAddress & +- 0x80) +- break; /* only bulk out allowed */ +- context->fifos[idx].pipe = +- usb_sndbulkpipe(dev, +- epd-> +- bEndpointAddress); +- break; +- default: +- context->fifos[idx].pipe = 0; /* reset data */ +- } /* switch attribute */ +- +- if (context->fifos[idx].pipe) { +- context->fifos[idx].fifonum = idx; +- context->fifos[idx].fifo_mask = +- 1 << idx; +- context->fifos[idx].hfc = context; +- context->fifos[idx].usb_maxlen = +- epd->wMaxPacketSize; +- context->fifos[idx].intervall = +- epd->bInterval; +- ep_msk |= (1 << idx); +- } else +- ep_msk &= ~(1 << idx); +- } /* idx < 7 */ +- epd++; +- } ++ //struct usb_host_interface *iface = intf->cur_altsetting; ++ //struct usb_host_interface *iface_used = NULL; ++ //struct usb_host_endpoint *ep; ++ struct usb_endpoint_descriptor* ep; ++ //int ifnum = iface->desc.bInterfaceNumber; ++ struct usb_interface_descriptor* intfdesc = intf->altsetting + intf->act_altsetting; ++ struct usb_interface_descriptor* intfdesc_used = NULL; ++ 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; ++ ++// usb_show_device(dev); ++// usb_show_device_descriptor(&dev->descriptor); ++// usb_show_interface_descriptor(&iface->desc); ++ vend_idx=0xffff; ++ for(i=0;vdata[i].vendor;i++) ++ { ++ if(dev->descriptor.idVendor==vdata[i].vendor && dev->descriptor.idProduct==vdata[i].prod_id) vend_idx=i; ++ } ++ + +- if ((ep_msk & 0x3f) != 0x3f) { +- kfree(context); +- return (NULL); +- } +- MOD_INC_USE_COUNT; /* lock our module */ +- context->dev = dev; /* save device */ +- context->if_used = interface; /* save used interface */ +- context->alt_used = ifp->act_altsetting; /* and alternate config */ +- context->ctrl_paksize = dev->descriptor.bMaxPacketSize0; /* control 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); +- +- /* init the chip and register the driver */ +- if (usb_init(context)) { +- kfree(context); +- MOD_DEC_USE_COUNT; +- return (NULL); +- } ++#ifdef VERBOSE_USB_DEBUG ++ printk(KERN_INFO "HFC-USB: probing interface(%d) actalt(%d)\n", ++ ifnum, intfdesc->bAlternateSetting); ++ /* printk(KERN_INFO "HFC-USB: probing interface(%d) actalt(%d) minor(%d)\n", ++ ifnum, intfdesc->bAlternateSetting, intf->driver->minor); */ ++#endif + +- printk(KERN_INFO +- "HFC-USB: New device if=%d alt=%d registered\n", +- context->if_used, context->alt_used); +- return (context); +- } ++ if (vend_idx != 0xffff) { ++#ifdef VERBOSE_USB_DEBUG ++ printk(KERN_INFO "HFC-USB: found vendor idx:%d name:%s\n",vend_idx,vdata[vend_idx].vend_name); ++#endif ++ /* if vendor and product ID is OK, start probing a matching alternate setting ... */ ++ 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; ++ intfdesc = intf->altsetting + alt_idx; ++ probe_alt_setting = intfdesc->bAlternateSetting; ++ cfg_used=0; + +- return (NULL); /* no matching entry */ +-} /* hfc_usb_probe */ ++#ifdef VERBOSE_USB_DEBUG ++ printk(KERN_INFO "HFC-USB: test alt_setting %d\n", probe_alt_setting); ++#endif ++ // check for config EOL element ++ while (validconf[cfg_used][0]) { ++ cfg_found=TRUE; ++ vcf=validconf[cfg_used]; ++ ep = intfdesc->endpoint; /* first endpoint descriptor */ ++ ++#ifdef VERBOSE_USB_DEBUG ++ printk(KERN_INFO "HFC-USB: (if=%d alt=%d cfg_used=%d)\n", ++ ifnum, probe_alt_setting, cfg_used); ++#endif ++ // copy table ++ memcpy(cmptbl,vcf,16*sizeof(int)); ++ ++ // check for all endpoints in this alternate setting ++ for (i=0; i < intfdesc->bNumEndpoints; i++) { ++ ep_addr = ep->bEndpointAddress; ++ idx = ((ep_addr & 0x7f)-1)*2; /* get endpoint base */ ++ if (ep_addr & 0x80) ++ idx++; ++ attr = ep->bmAttributes; ++ ++ if (cmptbl[idx] == EP_NUL) { ++ printk(KERN_INFO "HFC-USB: cfg_found=FALSE in idx:%d attr:%d cmptbl[%d]:%d\n", ++ idx, attr, idx, cmptbl[idx]); ++ cfg_found = FALSE; ++ } ++ ++ 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->bInterval < vcf[17]) { ++#ifdef VERBOSE_USB_DEBUG ++ if (cfg_found) ++ printk(KERN_INFO "HFC-USB: Interrupt Endpoint interval < %d found - skipping config\n", ++ vcf[17]); ++#endif ++ cfg_found = FALSE; ++ } ++ ++ ep++; ++ } ++ ++ for (i = 0; i < 16; i++) { ++ // printk(KERN_INFO "HFC-USB: cmptbl[%d]:%d\n", i, cmptbl[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 = FALSE; ++ } ++ ++ // we check for smallest match, to provide configuration priority ++ // configurations with smaller index have higher priority ++ if (cfg_found) { ++ if (cfg_used < small_match) { ++ small_match = cfg_used; ++ alt_used = probe_alt_setting; ++ //iface_used = iface; ++ intfdesc_used = intfdesc; ++ } ++#ifdef VERBOSE_USB_DEBUG ++ printk(KERN_INFO "HFC-USB: small_match=%x %x\n", small_match, alt_used); ++#endif ++ } ++ ++ cfg_used++; ++ } ++ ++ alt_idx++; ++ } /* (alt_idx < intf->num_altsetting) */ ++#ifdef VERBOSE_USB_DEBUG ++ printk(KERN_INFO "HFC-USB: final small_match=%x alt_used=%x\n",small_match, alt_used); ++#endif ++ // yiipiee, we found a valid config ++ if (small_match != 0xffff) { ++ //iface = iface_used; ++ intfdesc = intfdesc_used; ++ ++ if (!(context = kmalloc(sizeof(hfcusb_data), GFP_KERNEL))) ++ return(NULL); /* got no mem */ ++ memset(context, 0, sizeof(hfcusb_data)); /* clear the structure */ ++ ++ ep = intfdesc->endpoint; /* first endpoint descriptor */ ++ vcf = validconf[small_match]; ++ ++ for (i = 0; i < intfdesc->bNumEndpoints; i++) { ++ ep_addr = ep->bEndpointAddress; ++ idx = ((ep_addr & 0x7f)-1)*2; /* get endpoint base */ ++ if (ep_addr & 0x80) ++ idx++; ++ cidx = idx & 7; ++ attr = ep->bmAttributes; ++ ++ // only initialize used 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->bEndpointAddress); ++ context->fifos[cidx].usb_transfer_mode = USB_INT; ++ packet_size = ep->wMaxPacketSize; // remember max packet size ++#ifdef VERBOSE_USB_DEBUG ++ printk (KERN_INFO "HFC-USB: Interrupt-In Endpoint found %d ms(idx:%d cidx:%d)!\n", ++ ep->bInterval, idx, cidx); ++#endif ++ break; ++ case USB_ENDPOINT_XFER_BULK: ++ if (ep_addr & 0x80) ++ context->fifos[cidx].pipe = usb_rcvbulkpipe(dev, ep->bEndpointAddress); ++ else ++ context->fifos[cidx].pipe = usb_sndbulkpipe(dev, ep->bEndpointAddress); ++ context->fifos[cidx].usb_transfer_mode = USB_BULK; ++ packet_size = ep->wMaxPacketSize; // remember max packet size ++#ifdef VERBOSE_USB_DEBUG ++ printk (KERN_INFO "HFC-USB: Bulk Endpoint found (idx:%d cidx:%d)!\n", ++ idx, cidx); ++#endif ++ break; ++ case USB_ENDPOINT_XFER_ISOC: ++ if (ep_addr & 0x80) ++ context->fifos[cidx].pipe = usb_rcvisocpipe(dev, ep->bEndpointAddress); ++ else ++ context->fifos[cidx].pipe = usb_sndisocpipe(dev, ep->bEndpointAddress); ++ context->fifos[cidx].usb_transfer_mode = USB_ISOC; ++ iso_packet_size = ep->wMaxPacketSize; // remember max packet size ++#ifdef VERBOSE_USB_DEBUG ++ printk (KERN_INFO "HFC-USB: ISO Endpoint found (idx:%d cidx:%d)!\n", ++ idx, cidx); ++#endif ++ break; ++ default: ++ context->fifos[cidx].pipe = 0; /* reset data */ ++ } /* switch attribute */ ++ ++ if (context->fifos[cidx].pipe) { ++ context->fifos[cidx].fifonum = cidx; ++ context->fifos[cidx].hfc = context; ++ context->fifos[cidx].usb_packet_maxlen = ep->wMaxPacketSize; ++ context->fifos[cidx].intervall = ep->bInterval; ++ context->fifos[cidx].skbuff = NULL; ++#ifdef VERBOSE_USB_DEBUG ++ printk (KERN_INFO "HFC-USB: fifo%d pktlen %d interval %d\n", ++ context->fifos[cidx].fifonum, ++ context->fifos[cidx].usb_packet_maxlen, ++ context->fifos[cidx].intervall); ++#endif ++ } ++ } ++ ++ ep++; ++ } ++ ++ // now share our luck ++ 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); ++ ++ printk(KERN_INFO "HFC-USB: detected \"%s\" configuration: %s (if=%d alt=%d)\n", ++ vdata[vend_idx].vend_name, conf_str[small_match], context->if_used, context->alt_used); ++ ++ /* init the chip and register the driver */ ++ if (usb_init(context)) ++ { ++ if (context->ctrl_urb) { ++ usb_unlink_urb(context->ctrl_urb); ++ usb_free_urb(context->ctrl_urb); ++ context->ctrl_urb = NULL; ++ } ++ kfree(context); ++ return(NULL); ++ } ++ //usb_set_intfdata(intf, context); ++ //intf->private_data = context; ++ return(context); ++ } ++ } ++ return(NULL); ++} + + /****************************************************/ + /* function called when an active device is removed */ + /****************************************************/ +-static void +-hfc_usb_disconnect(struct usb_device *usbdev, void *drv_context) ++//static void hfc_usb_disconnect(struct usb_interface *intf) ++static void hfc_usb_disconnect(struct usb_device *usbdev, void* drv_context) + { +- hfcusb_data *context = drv_context; ++ //hfcusb_data *context = intf->private_data; ++ hfcusb_data* context = drv_context; + int i; +- struct sk_buff *skb; + +- /* tell all fifos to terminate */ +- for (i = 0; i < HFCUSB_NUM_FIFOS; i++) +- if (context->fifos[i].active) { +- context->fifos[i].active = 0; +- usb_unlink_urb(&context->fifos[i].urb); +- } +- while (context->active_fifos) { +- set_current_state(TASK_INTERRUPTIBLE); +- /* Timeout 10ms */ +- schedule_timeout((10 * HZ) / 1000); +- } ++ printk(KERN_INFO "HFC-USB: device disconnect\n"); ++ ++ //intf->private_data = NULL; ++ if (!context) ++ return; + if (timer_pending(&context->t3_timer)) + del_timer(&context->t3_timer); +- context->regd.release_driver(context->regd.arg_hisax); +- while ((skb = skb_dequeue(&context->regd.erq)) != NULL) +- dev_kfree_skb_any(skb); ++ if (timer_pending(&context->t4_timer)) ++ del_timer(&context->t4_timer); ++ if (timer_pending(&context->led_timer)) ++ del_timer(&context->led_timer); ++ ++ hisax_unregister(&context->d_if); + ++ /* 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]); ++#ifdef VERBOSE_USB_DEBUG ++ printk (KERN_INFO "HFC-USB: hfc_usb_disconnect: stopping ISOC chain Fifo no %i\n", i); ++#endif ++ } ++ } else { ++ if(context->fifos[i].active > 0) { ++ context->fifos[i].active = 0; ++#ifdef VERBOSE_USB_DEBUG ++ printk (KERN_INFO "HFC-USB: hfc_usb_disconnect: unlinking URB for Fifo no %i\n", i); ++#endif ++ } ++ if (context->fifos[i].urb) { ++ usb_unlink_urb(context->fifos[i].urb); ++ usb_free_urb(context->fifos[i].urb); ++ context->fifos[i].urb = NULL; ++ } ++ } ++ context->fifos[i].active = 0; ++ } ++ if (context->ctrl_urb) { ++ usb_unlink_urb(context->ctrl_urb); ++ usb_free_urb(context->ctrl_urb); ++ context->ctrl_urb = NULL; ++ } + kfree(context); /* free our structure again */ +- MOD_DEC_USE_COUNT; /* and decrement the usage counter */ + } /* hfc_usb_disconnect */ + ++ + /************************************/ + /* our driver information structure */ + /************************************/ + static struct usb_driver hfc_drv = { + name:"hfc_usb", +-#ifdef COMPAT_HAS_USB_IDTAB + id_table:hfc_usb_idtab, +-#endif + probe:hfc_usb_probe, + disconnect:hfc_usb_disconnect, + }; + +-static void __exit +-hfc_usb_exit(void) +-{ + ++static void __exit hfc_usb_exit(void) ++{ ++#ifdef VERBOSE_USB_DEBUG ++ printk ("HFC-USB: calling \"hfc_usb_exit\" ...\n"); ++#endif + usb_deregister(&hfc_drv); /* release our driver */ + printk(KERN_INFO "HFC-USB module removed\n"); + } + +-static int __init +-hfc_usb_init(void) ++static int __init hfc_usb_init(void) + { +- struct hisax_drvreg drv; ++ printk ("HFC-USB: driver module revision %s loaded\n", hfcusb_revision); + +- drv.version = HISAX_LOAD_VERSION; /* set our version */ +- drv.cmd = HISAX_LOAD_CHKVER; /* check command only */ +- if (hisax_register_hfcusb(&drv)) { +- printk(KERN_INFO "HFC-USB <-> hisax version conflict\n"); +- return (-1); /* unable to register */ +- } +- if (usb_register(&hfc_drv)) { +- printk(KERN_INFO +- "Unable to register HFC-USB module at usb stack\n"); +- return (-1); /* unable to register */ ++ if(usb_register(&hfc_drv)) ++ { ++ printk(KERN_INFO "HFC-USB: Unable to register HFC-USB module at usb stack\n"); ++ return(-1); /* unable to register */ + } +- +- printk(KERN_INFO "HFC-USB module loaded\n"); +- return (0); ++ return(0); + } + ++ ++ ++ ++ + module_init(hfc_usb_init); + module_exit(hfc_usb_exit); ++ |