Hi,
It seems this ML is quite dead :-( so that we may finally switch to
english more easily than expected ;-)
We had in mind to get a version 2.0 out very soon now, unfortunately (?)
we have all this remaining to be achieved :
- test new eagle-usb.conf (better for new bnm), mostly for Fast 800
E2L / E2T, no tester so far...
- check that Oops are correctly handled with sl33p3r proposal (no answer
to previous mail)
- obtain updates for translations
I'm not sure it will be ready for Christmas at this rate :-( when we
expected to ship the 2.0 version last thursday... well to get involved :
0. Get the latest CVS version :
cvs -d:pserver:[EMAIL PROTECTED] co eagleusb # press
enter as you are logging as anonymous
1. to test new eagle-usb.conf for pots, see attached file (change your
VPI/VCI/encapsulation/ISP according to your ISP as defined in
eagleconfig), unplug/plug your modem to take into account new
configuration (you _must_ use latest bnm included in cvs & 1.9.9.1
version)
Please provide the following results :
- eaglediag -sc
- estimated time to synchronize (longer than before, the same,
faster...)
- any error in /var/log/messages (except warning about unknown
option...)
For ISDN, see fileW.2.0.31_fr/L1/CMV/cmvei.txt from
http://www.sagem.com/support/site/driver/w_2_0_31_fr.zip
If anyone finds *any* documentation, (s)he's welcome.
Who had a look at this new driver for linux ?
http://www.sagem.com/support/site/driver/Fast8x0_2_0_32.tgz
available from here :
http://www.sagem.com/support/site/modele_fax.php?page=driver
2. check sl33p3r message :
https://mail.gna.org/public/eagleusb-dev/2004-09/msg00113.html
to make it short : once cvs version downloaded, compile/install then
eaglectrl -x 0xFFFFFFFF
eaglectrl -d
rmmod eagle-usb
you can do it many times (if not getting any Oops...) with an added depmod -a
or insmod eagle-usb
Please report :
- kernel / gcc / distribution used
- messages obtained
- anything I've forgotten to ask you
3. For translation, see
http://dev.eagle-usb.org/wakka.php?wiki=LocalizationScriptsUs
and compare your eagleusb/utils/scripts/lang/en with the file in your language
(Tux has added new messages)
Thanks for your participation, it will help make it work better.
@++
Ben'. aka baud123
<eaglectrl>
# Options are set whith the following syntax:
#
# Name = Value
#
# where "Name" is the option name, and
# "Value" is the option value, specified
# in hexadecimal (without any prefix).
# Option names are case sensitive.
# Options that are commented out are specified
# with their default values.
#
# Other than VPI, VCI and Encapsulation,
# I really don't known what these options mean.
#POTS FOR EAGLE
OPTN0=80008066
OPTN0=00000994
OPTN2=63600000
OPTN3=00000028
OPTN4=00600000
OPTN5=00000500
# OPTN6=00000000
# OPTN7=02CD8044
# OPTN15=09090909
OPTN18=820200ff
OPTN19=80000000
OPTN20=11900002
OPTN70=218280aa
OPTN72=006f06eb
OPTN73=00010060
# NON TR-48 => interoperability ???
#OPTN0=80008066
#OPTN18=820200ff
#OPTN19=00000000
# ignored, how to implement ???
#cw diag 0 0x26870030
#cw flag 0 0x00000820
#CW cntl 0 2
VPI=00000008
VCI=00000023
#The following values are valid for encapsulation :
#MPOA_MODE_BRIDGED_ETH_LLC ----> 1
#MPOA_MODE_BRIDGED_ETH_VC ----> 2
#MPOA_MODE_ROUTED_IP_LLC ----> 3
#MPOA_MODE_ROUTED_IP_VC ----> 4
#MPOA_MODE_PPPOA_LLC ----> 5
#MPOA_MODE_PPPOA_VC ----> 6
Encapsulation=00000006
Linetype=00000001
RatePollFreq=00000009
</eaglectrl>
/*
*
* Copyright (c) 2003, Frederick Ros ([EMAIL PROTECTED])
*
* eu_types.h - Types Declarations.
*
* This file is part of the eagle-usb driver package.
*
* eagle-usb driver package 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 of the License,
* or (at your option) any later version.
*
* "eagle-usb driver package" 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 "ADI USB ADSL Driver for Linux"; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: eu_types.h,v 1.4 2004/07/13 19:01:48 sleeper Exp $
*/
#ifndef __EU_TYPES_H__
#define __EU_TYPES_H__
#include <linux/if_ether.h>
#include <asm/bitops.h>
#include <linux/types.h>
/**
* eu_ioctl_info - Used to exchange data between kernl and user space via
* ioctls
*
*/
struct eu_ioctl_info
{
uint32_t idma_start;
uint32_t buffer_size;
uint8_t *buffer;
};
/*
* ioctl commands
*/
#define EU_IO_OPTIONS _IOW('U', 101, struct eu_ioctl_info)
#define EU_IO_DSP _IOW('U', 102, struct eu_ioctl_info)
#define EU_IO_GETITF _IOWR('U', 103, struct eu_ioctl_info)
#define EU_IO_SYNC _IO('U', 104)
#define EU_IO_GETDBG _IOWR('U', 105, struct eu_ioctl_info)
#define EU_IO_SETDBG _IOWR('U', 106, struct eu_ioctl_info)
#if 0
#define EU_IO_CMVS _IOW('U', 107, struct eu_ioctl_info)
#endif
/*
* Options description structure
*/
#define MAX_OPTION_NAME_LENGTH 64
typedef struct
{
char name[MAX_OPTION_NAME_LENGTH];
uint32_t value;
} eu_opt_t;
enum
{
CFG_OPT_0 = 0,
CFG_OPT_2,
CFG_OPT_3,
CFG_OPT_4,
CFG_OPT_5,
CFG_OPT_6,
CFG_OPT_7,
CFG_OPT_15,
CFG_VPI,
CFG_VCI,
CFG_ENCAPS,
CFG_LINE,
CFG_RATE_POLL_FREQ,
CFG_OPT_COUNT
};
#define NUM_DRV_OPTIONS CFG_OPT_COUNT
typedef eu_opt_t eu_options_t[NUM_DRV_OPTIONS];
#ifdef __KERNEL__
#define TRANSMIT_TIMEOUT (HZ*5) /* 5 seconds */
#define ETHERTYPE_IP 0x0008
#define ETHERTYPE_IPV6 0xdd86
#define ETHERTYPE_ARP 0x0608
/*
* Custom ADI vendor control commands
*/
#define EU_CMD_GET_BLOCK 0x00
#define EU_CMD_SET_BLOCK 0x01
#define EU_CMD_GET_STAT 0x02
#define EU_CMD_SET_MODE 0x03
#define EU_CMD_SET_2183_DATA 0x04
#define EU_CMD_GET_2183_DATA 0x05
#define EU_CMD_GET_STAT_VAR 0x06
#define EU_CMD_GET_INTERRUPT 0x07
#define EU_CMD_SET_FPGA_DATA 0x0E
#define EU_CMD_SET_TIMEOUT 0x11
/*
* Modes for EU_CMD_SET_MODE
*/
#define MODE_LOOPBACK_OFF 0x02
#define MODE_LOOPBACK_ON 0x03
#define MODE_BOOTMODE_IDMA 0x06
#define MODE_START_RESET 0x07
#define MODE_END_RESET 0x08
/*
* Mailbox addrs
*/
#define DSP_MP_TX_MAILBOX 0x3FD6
#define DSP_MP_TX_START 0x3FCE
#define DSP_MP_RX_MAILBOX 0x3FDF
#define DSP_SWAP_MAILBOX 0x3FCD
/*
* Mailbox states
*/
#define MAILBOX_EMPTY 0
#define MAILBOX_FULL 1
/*
* Maximums
*/
#define MAX_DSP_ALLOCS 128
/*
* MPOA Encapsulations
*/
#define MPOA_MODE_PPPOA_LLC 5
#define MPOA_MODE_PPPOA_VC 6
/**
* eu_cdc_t - Comm Device Class notification buffer
*
* @req: request as defined but USB standard
* @data: 20 bytes array used to pass data to the modem
*
* This is an extended version of the USB standard CDC, as ADI modem
* use this to pass data.
*/
typedef struct
{
uint8_t bRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
uint8_t data[20];
} eu_cdc_t __attribute__ ((packed));
/**
* eu_devint_t - returned by the modem on interrupt
*/
#define CMV_DATA_WORDS 8
typedef struct
{
uint16_t intr;
union
{
uint16_t swap_data;
uint16_t cmv_data[CMV_DATA_WORDS];
} intr_info ;
uint16_t data_size;
} eu_devint_t;
/**
* ISO Frame
*
* @status - Status of this received frame
* @length - Actual Data Buffer Length (how much data we received)
* @data - Received Data
*/
#define FASTEST_ISO_RATE 1007
typedef struct eu_iso_frame
{
int status;
int length;
char data[FASTEST_ISO_RATE];
} eu_iso_frame_t;
/**
* ISO Receive Buffer
*
* @next - To link buffers in completed receive list
* @frames - Frames for this receive buffer
*
*/
#define FRAMES_PER_ISO_URB 16
typedef struct eu_iso_rb
{
struct list_head next;
eu_iso_frame_t frames[FRAMES_PER_ISO_URB];
} eu_iso_rb_t;
/************************************************************************************/
/* This will be the receiver buffer for incoming network data. We will queue */
/* up a bunch of reads with USB with these buffers, then process them into */
/* real ethernet packets as they come in. This enables us to support situations */
/* where the entire ethernet packet does not come in in one USBBulkRead. We */
/* do require that the data received into these buffers is an exact number */
/* of ATM cells */
/* LINUX NOTE : */
/* In kernel 2.4.7-10 (the stock kernel with RedHat 7.2), the usb-uhci module */
/* has a problem queuing multiple read bulk urbs). Therefore, we set this to one so */
/* we'll work with uhci or ohci. However, higher performance can be seen on ohci */
/* if you allow multiple read urbs. So, if you're on an ohci-based machine, */
/* set INCOMING_Q_SIZE to > 1 to achieve greater performance. */
/************************************************************************************/
/* FIXME */
#ifdef USEBULK
#define INCOMING_Q_SIZE 1
#else
/*We'll set it to 6 when we're dealing with ISOCHRONOUS data.*/
#define INCOMING_Q_SIZE 6
#endif
#define OUTGOING_Q_SIZE 64
#define OUTGOING_DATA_SIZE 1802 /* same logic as for INCOMING_DATA_SIZE */
/************************************************************************************/
/* Here's how I got this - Max ethernet = 1500 bytes + */
/* possible Ethernet FCS = 4 bytes + */
/* possible MPOA encapsulation = 10 bytes + */
/* CPCS PDU trailer = 8 bytes + */
/* at most 2 ATM payloads of pad = 96 bytes */
/* ---------- */
/* 1618 bytes */
/* Divided among ATM cells = 34 ATM cells * 53 bytes */
/* Grand total = 1802 */
/* NOTE NOTE NOTE NOTE */
/* This logic all makes sense IF the device received data in ATM cell sized chunks, */
/* however, it doesn't. The USB pipes receive 64bytes at a time, so we have */
/* to have space for a size that is the LCM of 64 and 53, which is 64*53 */
/************************************************************************************/
/* FIXME */
#define INCOMING_DATA_SIZE (64 * 53)
/**
* BULK Receive Buffer
*
* @next - To link buffers in completed receive list
* length - Received Data Length
* data - Received Data
*/
typedef struct eu_bulk_rb
{
struct list_head next;
int length;
char data[INCOMING_DATA_SIZE];
} eu_bulk_rb_t;
/*
* To ease code ...
*/
#ifdef USEBULK
typedef eu_bulk_rb_t eu_rb_t;
#else
typedef eu_iso_rb_t eu_rb_t;
#endif /* USEBULK */
/*
* Queued Control Urb
*/
#define CTRL_URB_Q_SIZE 16
typedef struct
{
struct list_head list;
struct urb *urb;
void *dev;
} queued_urb_t;
/**
* eu_msg_t - Decoded modem messages
*
* @preamble Message preamble
* @type Function type
* @subtype Function Sub Type
* @sender_id ID of the Sender (unused)
* @receiver_id ID of the receiver (unused)
* @index message index (unused)
* @symb_addr Symbolic addr (unused)
* @offset_addr Offset (unused)
* @data Data from modem
*
* Field marked with (unused) tag are only used to check message is not
* corrupted
*/
typedef struct
{
uint16_t preamble;
uint16_t type;
uint16_t subtype;
uint16_t sender_id;
uint16_t receiver_id;
uint16_t index;
uint8_t saddr[4];
uint32_t offset_addr;
uint32_t data;
} eu_msg_t;
typedef struct
{
uint16_t preamble;
uint16_t function;
uint16_t idx;
uint8_t saddr_hihi;
uint8_t saddr_hilo;
uint8_t saddr_lohi;
uint8_t saddr_lolo;
uint16_t offset;
uint32_t data;
} eu_cmv_msg_t;
/* FIXME */
#define MAX_CMV_MESSAGES 20
typedef struct
{
union
{
eu_cmv_msg_t *Msgs[ MAX_CMV_MESSAGES ];
uint16_t *RawCmd[ MAX_CMV_MESSAGES ];
} MsgMax;
uint32_t MsgCount;
} MsgSequence;
/* State machine control structure*/
/* FIXME */
typedef struct
{
/* state machine flags and options*/
uint32_t ADPT0;
uint32_t ADPT1;
uint32_t ADPT2;
uint32_t INFO9;
uint32_t CNTL0;
uint32_t OPTN0;
uint32_t OPTN2;
uint32_t OPTN4;
uint32_t OPTN7;
uint32_t OPTN3;
uint32_t OPTN5;
uint32_t OPTN6;
uint32_t OPTN15;
uint32_t PFCL1;
uint32_t MASK8;
uint32_t MASK9;
uint32_t INFO8;
uint32_t PSDM0;
uint32_t UNH;
uint32_t ISDN;
uint32_t FLAG0;
/* OPERATIONAL values*/
uint32_t sw_status;
uint32_t crc_status;
uint32_t flags;
/* statistics*/
uint32_t stats_ES_count;
uint32_t stats_Cur_Atten;
uint32_t stats_Cur_SNR;
uint32_t stats_Rx_Blks;
uint32_t stats_Tx_Blks;
uint32_t stats_Corr_Blks;
uint32_t stats_Uncorr_Blks;
uint32_t stats_Rx_Blks_Delta;
uint32_t stats_Corr_Blks_Delta;
uint32_t stats_Uncorr_Blks_Delta;
/* transfer rate*/
uint32_t XferRate0;
uint32_t DownRate;
uint32_t UpRate;
uint32_t FwRxTimeout;
/* miscell*/
uint32_t DIAG03;
uint32_t DIAG47;
uint32_t DIAG49;
uint32_t INFO10;
uint32_t PSDM01;
uint32_t INFO08;
uint32_t INFO14;
/* following counters work in single digits before reset is tridgerred*/
uint8_t LOS_count;
uint8_t CRC_count;
uint8_t Block_CRC90;
uint8_t Block_CRC97;
uint32_t stats_Ne_Fast_Lod_Failure;
uint32_t stats_Ne_Fast_Hec_Failure;
/* -------- status variables ------------------------*/
uint8_t LineType;
uint16_t ModemReplyExpected;
uint16_t CurrentAdiState;
uint16_t PrevAdiState;
uint16_t MsgStage;
uint16_t ReTrain;
uint16_t RetryCount;
uint32_t HeartbeatCounter;
/* pre-composed messages used for fast retrain sequence*/
MsgSequence MsgSeq_Retrainer;
MsgSequence MsgSeq_SoftReset;
MsgSequence MsgSeq_OpStat;
MsgSequence MsgSeq_Stat;
MsgSequence MsgSeq_ModemEna;
MsgSequence MsgSeq_EnaFR;
struct timer_list timerSM;
/* flags and handles*/
uint32_t CurrentExpirationTime;
uint32_t SwapPageRequiredTime;
uint32_t OutboundPending;
uint32_t InboundAsyncPending;
uint32_t InboundSyncPending;
uint32_t watchBadBlocks;
} AdiMSM;
/*
* Boot states: they are copied over the value of the modem internal states
*/
typedef enum {
PRE_BOOT = 0,
STAGE_1 = 1,
STAGE_2 = 2,
STAGE_3 = 3,
REBOOT = 4,
UPLOAD_P = 5,
STATE_MAX
} boot_state_t;
/* Represents a block of IDMA memory, either Program or Data Memory (PM or DM)*/
/* FIXME */
typedef struct
{
uint8_t *MemOffset;
uint32_t DSPAddr;
uint32_t DSPSize;
uint32_t DSPExtendedSize;
} IDMABlock;
/* Represents a page of IDMA memory, either a Main page or a Swap page*/
/* FIXME */
typedef struct
{
uint32_t BlockCount;
uint32_t PageOffset;
IDMABlock *Blocks;
} IDMAPage;
/**
* eu_sar_r_t - Sar Reassembly structure
*
* @skb - Pointer to the used skb
* @pdu_len_from_trailer - Length as reported by cell trailer
* @running_crc - CRC in the process to be calculated
* @cell_count - Number of prcessed cells for this frame.
*/
typedef struct
{
struct sk_buff *skb;
uint32_t pdu_len_from_trailer;
uint32_t running_crc;
uint32_t cell_count;
} eu_sar_r_t;
/**
* eu_sar_s_t - Sar Segmentation structure
*
* @out_buff - Buffer used to segemnt data
* @size -
*
*/
typedef struct
{
uint8_t *out_buff;
uint32_t size;
uint8_t *cell_hdr;
uint32_t raw_pdu_length;
uint32_t padding_len;
uint32_t bytes_left_in_curr_cell;
uint32_t cell_count;
uint32_t running_crc;
} eu_sar_s_t;
/**
* eu_aal5_trailer_t - AAL5 Trailer
*
* @cpcs_uu -
* @cpi -
* @pdu_len - PDU Length for this frame
* @crc - CRC for this frame
*
*/
typedef struct
{
uint8_t cpcs_uu;
uint8_t cpi;
uint16_t pdu_len;
uint32_t crc;
}
eu_aal5_trailer_t;
/**
* eu_atm_vc_t - ATM Virtual Channel descriptor
*
* @reassembler - SAR Reassembler
* @vpi - Virtual Path Identifier
* @vci - Virtual Channel Identifier
* @vpi_vci - Agregated VPI/VCI
* @max_sdu_size - Maximum Data User Size
* @reassembly_ipg - uint32_t : Is a Reassembly I ProGress ?
* @encaps_size - Encapsulation size on segmentation ( RFC 2684 )
* @encaps_hdr - Encapsulation Header
* @cell_hdr - Header of current cell
* @cpcs_uu -
* @cpi -
*
*/
#define ATM_CELL_HEADER_SIZE 5
typedef struct
{
eu_sar_r_t reassembler;
eu_sar_s_t segmenter;
uint32_t vpi;
uint32_t vci;
uint32_t vpi_vci;
uint32_t max_sdu_size;
uint32_t reassembly_ipg;
uint32_t encaps_size;
uint8_t *encaps_hdr;
uint8_t cell_hdr[ATM_CELL_HEADER_SIZE];
uint8_t cpcs_uu;
uint8_t cpi;
} eu_atm_vc_t;
/*
* Encapsulation modes
*/
#define MPOA_MODE_BRIDGED_ETH_LLC 1
#define MPOA_MODE_BRIDGED_ETH_VC 2
#define MPOA_MODE_ROUTED_IP_LLC 3
#define MPOA_MODE_ROUTED_IP_VC 4
/**
* Instance flags
*/
#define EU_OPEN 0
#define EU_WRITING 1
#define EU_HAS_INT 2
#define EU_READING 3
#define EU_MSG_INITIALIZED 4
#define EU_UNPLUG 5
#define EU_LOW_RATE 6
#define EU_DSP_IPG 7
#define EU_DSP_LOADED 8
#define EU_ETH_REGISTERED 9 /* Successfully registered */
#define EU_ETH_REGISTERING 10 /* Registration in progress */
#define EU_SET_FLAG(i,f) set_bit((f), &(i)->flags)
#define EU_CLEAR_FLAG(i,f) clear_bit((f),&(i)->flags)
#define EU_TEST_FLAG(i,f) test_bit((f),&(i)->flags)
#define STAT_COUNT 0x0015
#define ATM_CELL_SIZE 53
/* ---------------------------- Stats Counters ----------------------------- */
/*
* Received ATM Cells
*/
#define STAT_CELLS_RX 0x0000
/*
* Transmited ATM Cells
*/
#define STAT_CELLS_TX 0x0001
/*
* Number of cells drop because of CRC error
*/
#define STAT_CELLS_LOST_CRC 0x0002
/*
* Stats Lost because of invalid VPI/VCI
*/
#define STAT_CELLS_LOST_VPIVCI 0x0003
/*
* Number of cells lost because reassembly buffer is to short
*/
#define STAT_CELLS_LOST_OTHER 0x0004
/*
* Received Ethernet/IP Packets
*/
#define STAT_PAKTS_RX 0x0005
/*
* Transmited Ethernet/IP Packets
*/
#define STAT_PAKTS_TX 0x0006
/*
* Packets lost because over-sized
*/
#define STAT_PAKTS_LOST_OSIZE 0x0007
/*
* Nb Packets droped after filter
*/
#define STAT_PAKTS_FILTERED 0x0008
#define STAT_ATMVCI 0x0009
#define STAT_ATMVPI 0x000A
#define STAT_ATMHEC 0x000B
#define STAT_ATMDELIN 0x000C
#define STAT_DSLMARGIN 0x000D
#define STAT_DSLATTEN 0x000E
#define STAT_DSLFEC 0x000F
#define STAT_DSLVIDCPE 0x0010
#define STAT_DSLVIDCO 0x0011
#define STAT_DSLTXRATE 0x0012
#define STAT_DSLRXRATE 0x0013
/*
* Number of OAM cells received
*/
#define STAT_CELLS_OAM_RCVD 0x0014
typedef struct eu_instance_s
{
/*
* To count the number of interfaces linked to this structure ...
*/
uint32_t users;
/*
* To protect accesses to this structure.
*/
spinlock_t lock;
/*
* To link all of our instances
*/
struct list_head list;
/*
* Holds USB device information (dev, interfaces, pipes, etc.)
*/
struct usb_device *usbdev;
/*
* URBs allocated for this device
*/
struct urb *urb_int;
struct urb *urb_write;
struct urb *urb_oam_write;
struct urb *read_urb[INCOMING_Q_SIZE]; /* Array of receive urbs */
/*
* Device's endpoints
*/
uint32_t pipe_int_in;
uint32_t pipe_bulk_idma_out;
uint32_t pipe_bulk_data_out;
uint32_t pipe_bulk_data_in;
uint32_t pipe_iso_data_in;
/*
* Data returned on interrupt by modem
*/
eu_cdc_t *intr_data;
/*
* Cache used to allocate read buffers
*/
kmem_cache_t *rb_cache;
/*
* Maximum Receive Unit - depends on the encapsulation
*/
unsigned int mru;
/*
* Size of the header to prepend in front of inbound data
*/
unsigned int eth_hdr;
/*
* To hold outbound data
*/
uint8_t *segmentation_buffer;
/*
* Modem state machine info
*/
AdiMSM AdiModemSm;
wait_queue_head_t sync_q;
eu_cmv_msg_t *pDriverCMVs;
/*DSP code info*/
IDMAPage MainPage;
IDMAPage *pSwapPages;
uint32_t SwapPageCount;
/*URB queues*/
struct list_head ctrl_urb_free_q; /* Free queued_urb_t queue */
struct list_head ctrl_urb_ipg_q; /* In-progress control urb queue */
struct urb *ctrl_urb_failed;
spinlock_t ctrl_q_lock;
/*Kernel timer(s)*/
struct timer_list ctrl_urb_q_timer;
struct timer_list ctrl_urb_retry;
/*
* Tasklets
*/
struct tasklet_struct rcv_complete_tasklet;
#ifdef LINUX_2_6
/*
* Work queue for eth creation
*/
struct work_struct create_eth;
#endif
/*
* Boot queue / task
*/
#ifdef LINUX_2_6
struct work_struct boot_sm;
#elif defined(LINUX_2_4)
struct tq_struct boot_sm;
#endif
boot_state_t boot_state;
uint16_t swap_data;
/*
* Wait Queue
*/
wait_queue_head_t thr_wait;
/*
* Completed Read Queue: data to be treated by kernel
*/
struct list_head comp_read_q;
/*
* Associated spinlock
*/
spinlock_t comp_read_q_lock;
/*
* Misc data
*/
volatile unsigned long flags;
#ifdef DELAY_ISO_STARTUP
uint32_t IsReadPipeStarted;
#endif
uint32_t MpoaMode;
uint8_t mac[ETH_ALEN];
/*
* Ethernet interface data
*/
uint32_t out_pkt_size;
struct net_device *eth;
struct net_device_stats LinuxStats;
char if_name[IFNAMSIZ];
/*
* Statistics
*/
uint32_t Statistics[STAT_COUNT];
/*
* ATM data
*/
eu_atm_vc_t Vc;
/*
* State variables used for OAM stuff
*/
uint32_t OAMState_TimerOn;
uint32_t OAMState_SendingCC;
uint32_t OAMState_ReceiveCC;
uint32_t OAMState_AIS;
uint32_t OAMState_CCSink;
uint8_t OAMCell[ATM_CELL_SIZE*2];
uint8_t *pOAMCell;
uint8_t OAMCellHeader[ATM_CELL_HEADER_SIZE*2];
struct timer_list OAMTimer;
} eu_instance_t;
#endif /* __KERNEL__ */
#endif /* __EU_TYPES_H__ */
/*
*
* Copyright (c) 2003, Frederick Ros ([EMAIL PROTECTED])
* Forked from ADI Linux driver from Analog Devices Inc.,
* User space interface rewritten by C.Casteyde ([EMAIL PROTECTED])
* Multi-modem support added by Renaud Guerin ([EMAIL PROTECTED])
* Other stuff : Frederick Ros ([EMAIL PROTECTED])
*
* eagle-usb.c
*
* ----------------------------------------------------------------------------
*
* This file is part of the eagle-usb driver package.
*
* "eagle-usb driver package" 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 of the License,
* or (at your option) any later version.
*
* "eagle-usb driver package" 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 "eagle-usb driver package"; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* $Id: eu_main.c,v 1.15 2004/08/26 20:06:34 sleeper Exp $
*/
#include "Adiutil.h"
#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/list.h>
#include <asm/uaccess.h>
#include <linux/if_arp.h>
#include "eagle-usb.h"
#include "macros.h"
#include "Dsp.h"
#include "eu_msg.h"
#include "Pipes.h"
#include "eu_utils.h"
#include "eu_sm.h"
#include "Oam.h"
#include "Mpoa.h"
#include "Me.h"
#include "Uni.h"
#include "debug.h"
#include "eu_eth.h"
#include "eu_boot_sm.h"
/* ------------------------------- Private Macros ------------------------------- */
#define CASE_PREFIRM EAGLE_I_PID_PREFIRM: \
case MILLER_A_PID_PREFIRM: \
case MILLER_B_PID_PREFIRM: \
case HEINEKEN_A_PID_PREFIRM: \
case HEINEKEN_B_PID_PREFIRM: \
case EAGLE_IIC_PID_PREFIRM: \
case EAGLE_II_PID_PREFIRM
#define CASE_POSTFIRM EAGLE_I_PID_PSTFIRM: \
case MILLER_A_PID_PSTFIRM: \
case MILLER_B_PID_PSTFIRM: \
case HEINEKEN_A_PID_PSTFIRM: \
case HEINEKEN_B_PID_PSTFIRM: \
case EAGLE_II_PID_PSTFIRM: \
case EAGLE_IIC_PID_PSTFIRM
#define ISPREFIRM(c) ( EAGLE_I_PID_PREFIRM == (c) || \
MILLER_A_PID_PREFIRM == (c) || MILLER_B_PID_PREFIRM == (c) || \
HEINEKEN_A_PID_PREFIRM == (c) || HEINEKEN_B_PID_PREFIRM == (c) || \
EAGLE_II_PID_PREFIRM == (c) || EAGLE_IIC_PID_PREFIRM == (c) \
)
#define ISPOSTFIRM(c) ( EAGLE_I_PID_PSTFIRM == (c) || \
MILLER_A_PID_PSTFIRM == (c) || MILLER_B_PID_PSTFIRM == (c) || \
HEINEKEN_A_PID_PSTFIRM == (c) || HEINEKEN_B_PID_PSTFIRM == (c) || \
EAGLE_II_PID_PSTFIRM == (c) || EAGLE_IIC_PID_PSTFIRM == (c) \
)
/*
* Hardcoded endpoint addresses
*/
#define EP_BULK_IDMA_OUT 0x04
#define EP_BULK_DATA_OUT 0x02
#define EP_BULK_DATA_IN 0x82
#define EP_ISOC_DATA_IN 0x88
#define EP_INT_IN 0x84
#define USB_INTF_IN 0x02
#define FASTEST_ISO_INTF 0x08
/*
* Interrupts
*/
#define EU_INT_LOADSWAPPAGE 0x01
#define EU_INT_INCOMINGCMV 0x02
/* ----------------------- Private Function Declarations ------------------------ */
/*
* USB related
*/
#ifdef LINUX_2_4
static void *eu_probe(struct usb_device *usb, unsigned int ifnum, const struct usb_device_id *id);
static void eu_disconnect(struct usb_device *usb, void *ptr);
static int eu_user(struct usb_device *dev, unsigned int code, void *buf);
#elif defined (LINUX_2_6)
static int eu_probe ( struct usb_interface *intf, const struct usb_device_id *id);
static void eu_disconnect(struct usb_interface *intf);
static int eu_user(struct usb_interface *intf, unsigned int code, void *buf);
#endif
static USB_COMPLETION_PROTO (eu_irq,urb,regs);
static int eu_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data);
/*
* Ethernet device related
*/
static eu_instance_t *eu_init_prefirm ( struct usb_device *usb );
#ifdef LINUX_2_6
static eu_instance_t * eu_init_postfirm ( struct usb_device *usb, struct usb_interface *intf );
#else
static eu_instance_t * eu_init_postfirm ( struct usb_device *usb );
#endif
static void eu_disconnect_postfirm ( eu_instance_t *ins , struct usb_device *usb );
static void eu_process_rcv ( unsigned long data );
static int eu_check_options ( const eu_options_t opt );
/* ----------------------------- Private Variables ------------------------------ */
/*
* List of supported VID/PID
*/
static const struct usb_device_id eu_ids[] =
{
{ USB_DEVICE (EAGLE_VID, EAGLE_I_PID_PREFIRM) },
{ USB_DEVICE (EAGLE_VID, EAGLE_I_PID_PSTFIRM) },
{ USB_DEVICE (EAGLE_VID, EAGLE_II_PID_PREFIRM) },
{ USB_DEVICE (EAGLE_VID, EAGLE_II_PID_PSTFIRM) },
{ USB_DEVICE (EAGLE_VID, EAGLE_IIC_PID_PREFIRM) },
{ USB_DEVICE (EAGLE_VID, EAGLE_IIC_PID_PSTFIRM) },
{ USB_DEVICE (USR_VID, MILLER_A_PID_PREFIRM) },
{ USB_DEVICE (USR_VID, MILLER_A_PID_PSTFIRM) },
{ USB_DEVICE (USR_VID, MILLER_B_PID_PREFIRM) },
{ USB_DEVICE (USR_VID, MILLER_B_PID_PSTFIRM) },
{ USB_DEVICE (USR_VID, HEINEKEN_A_PID_PREFIRM) },
{ USB_DEVICE (USR_VID, HEINEKEN_A_PID_PSTFIRM) },
{ USB_DEVICE (USR_VID, HEINEKEN_B_PID_PREFIRM) },
{ USB_DEVICE (USR_VID, HEINEKEN_B_PID_PSTFIRM) },
{ }
};
/*
* USB driver descriptor
*/
static struct usb_driver eu_driver =
{
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,19)
.owner = THIS_MODULE,
#endif
.name = "eagle-usb",
.id_table = eu_ids,
.probe = eu_probe,
.disconnect = eu_disconnect,
.ioctl = eu_user
};
/*
* Linked list of modem eu_instance_t structs
*/
LIST_HEAD(modem_list);
/*
* Our /proc dir entry
*/
struct proc_dir_entry* eu_procdir;
#define DEFAULT_OPTN0 0x80020066
#define DEFAULT_OPTN2 0x23700000
#define DEFAULT_OPTN3 0x00000000
#define DEFAULT_OPTN4 0x00000000
#define DEFAULT_OPTN5 0x00000000
#define DEFAULT_OPTN6 0x00000000
#define DEFAULT_OPTN7 0x02CD8044
#define DEFAULT_OPTN15 0x00000000
#define DEFAULT_VPI 0x00000008
#define DEFAULT_VCI 0x00000023
#define DEFAULT_ENCAPS MPOA_MODE_PPPOA_VC
#define DEFAULT_LINETYPE 0x00000001
#define DEFAULT_POLLFREQ 0x0000000A
/*
* Default driver options
*/
static const eu_options_t default_options =
{
{ "OPTN0", DEFAULT_OPTN0 },
{ "OPTN2", DEFAULT_OPTN2 },
{ "OPTN3", DEFAULT_OPTN3 },
{ "OPTN4", DEFAULT_OPTN4 },
{ "OPTN5", DEFAULT_OPTN5 },
{ "OPTN6", DEFAULT_OPTN6 },
{ "OPTN7", DEFAULT_OPTN7 },
{ "OPTN15", DEFAULT_OPTN15 },
{ "VPI", DEFAULT_VPI },
{ "VCI", DEFAULT_VCI },
{ "Encapsulation", DEFAULT_ENCAPS },
{ "Linetype", DEFAULT_LINETYPE },
{ "RatePollFreq", DEFAULT_POLLFREQ },
};
/*
* User supplied name for ethernet interface
*/
static char *if_name = NULL;
/*
* User supplied debug level
*/
unsigned int module_dbg_mask = 0x0;
/* -------------------------------- Module Stuff -------------------------------- */
MODULE_AUTHOR ("Anoosh Naderi <[EMAIL PROTECTED]>/Frederick Ros ([EMAIL PROTECTED])");
MODULE_DESCRIPTION ("Eagle USB ADSL Modem driver");
MODULE_DEVICE_TABLE (usb, eu_ids);
MODULE_LICENSE("GPL");
MODULE_PARM (if_name,"s");
MODULE_PARM_DESC (if_name,"Exported ethernet interface name");
MODULE_PARM (module_dbg_mask,"i");
MODULE_PARM_DESC (module_dbg_mask,"Module Debug mask");
EXPORT_NO_SYMBOLS;
/* ----------------------- INITIALIZATION / DESTRUCTION ------------------------ */
/**
* eu_init - Initialize the module.
* Generates CRC table
* Creates /proc/driver/eagle-usb directory
* Register to USB subsystem
*
*/
static int __init eu_init (void)
{
int result = 0;
eu_enters (DBG_INIT);
eu_report ("driver V"EAGLEUSBVERSION" loaded\n");
eu_crc_generate();
eu_procdir = proc_mkdir("driver/eagle-usb",NULL);
if ( eu_procdir )
{
eu_procdir->owner = THIS_MODULE;
}
else
{
eu_report ("could not create /proc/driver/eagle-usb/\n");
result = -ENOMEM;
}
usb_register(&eu_driver);
eu_leaves (DBG_INIT);
return 0;
}
module_init (eu_init);
/**
* eu_exit - Finalize module
*
* Deregister with USB subsystem
* Remove /proc/drivers/eagle-usb directory
*
*/
static void __exit eu_exit (void)
{
eu_enters (DBG_INIT);
/*
* This calls automatically the eu_disconnect method if necessary:
*/
usb_deregister (&eu_driver);
eu_report ("driver unloaded\n");
remove_proc_entry("driver/eagle-usb",NULL);
eu_leaves (DBG_INIT);
}
module_exit (eu_exit);
/**
* eu_probe - Ask driver to probe this device
*
*/
#ifdef LINUX_2_4
static void *eu_probe (
struct usb_device *usb,
unsigned int ifnum,
const struct usb_device_id *id
)
#elif defined(LINUX_2_6)
static int eu_probe (
struct usb_interface *intf,
const struct usb_device_id *id
)
#endif
{
void *ins = NULL;
#ifdef LINUX_2_6
struct usb_device *usb = interface_to_usbdev (intf);
#endif
uint32_t pid = usb->descriptor.idProduct;
eu_enters (DBG_INIT);
eu_dbg (DBG_INIT,"vid (%#X) pid (%#X) \n",
usb->descriptor.idVendor, usb->descriptor.idProduct);
/*
* This driver knows only pre and postfirmware devices.
*/
if ( !ISPREFIRM(pid) && !ISPOSTFIRM(pid) )
{
eu_dbg (DBG_INIT," Not a supported modem\n");
goto byebye;
}
switch ( pid )
{
case CASE_PREFIRM:
ins = eu_init_prefirm ( usb );
break;
case CASE_POSTFIRM:
#ifdef LINUX_2_6
ins = eu_init_postfirm ( usb, intf );
#else
ins = eu_init_postfirm ( usb );
#endif
break;
}
eu_leaves (DBG_INIT);
byebye:
#ifdef LINUX_2_6
if (ins)
{
usb_set_intfdata (intf, ins);
return (0);
}
else
{
return -ENODEV;
}
#else
return (ins);
#endif
}
/*
* eu_init_prefirm - Initialize pre-firmware device
*
* @usb - USB device to init.
*/
static eu_instance_t *eu_init_prefirm ( struct usb_device *usb )
{
eu_instance_t *ins = NULL;
int ret;
uint32_t pid = usb->descriptor.idProduct;
eu_enters (DBG_INIT);
/*
* Create a new pre-firmware device:
*/
ins = GET_KBUFFER (sizeof(eu_instance_t));
if ( !ins )
{
eu_err ("Not enough memory to get new driver structure..\n");
goto byebye;
}
eu_report ("New pre-firmware modem detected\n");
/*
* Reinitialize the modem structure:
*/
memset (ins, 0, sizeof(eu_instance_t));
ins->usbdev = usb;
EU_CLEAR_FLAG (ins, EU_MSG_INITIALIZED);
EU_CLEAR_FLAG (ins, EU_UNPLUG);
eu_report ("Uploading firmware..\n");
ret = eu_load_firmware ( ins, pid );
if ( ret < 0 )
{
eu_err ("Can't upload firmware to modem...\n");
FREE_KBUFFER (ins);
ins = NULL;
goto byebye;
}
eu_report ("Binding eu_instance_t to USB %03d/%03d\n",
usb->bus->busnum, usb->devnum);
list_add (&ins->list,&modem_list);
byebye:
eu_leaves ( DBG_INIT);
return(ins);
}
/**
* eu_init_postfirm - Initialize post firmware device
*
* @usb - USB device to init
*/
#ifdef LINUX_2_6
static eu_instance_t * eu_init_postfirm ( struct usb_device *usb, struct usb_interface *intf )
#else
static eu_instance_t * eu_init_postfirm ( struct usb_device *usb )
#endif
{
int i;
eu_instance_t *ins = NULL;
char path[32];
struct proc_dir_entry* procfile;
int ret = 0;
unsigned int nb_frames;
int tmp;
eu_enters (DBG_INIT);
/*
* Create a new post-firmware device:
*/
ins = GET_KBUFFER (sizeof (eu_instance_t));
if ( !ins )
{
eu_err ("eu_init_postfirm: Not enough memory !\n");
goto byebye;
}
/*
* Initialize our instance
*/
memset ( ins, 0, sizeof(eu_instance_t) );
ins->usbdev = usb;
EU_CLEAR_FLAG ( ins, EU_MSG_INITIALIZED);
EU_CLEAR_FLAG ( ins, EU_UNPLUG);
init_waitqueue_head (&ins->sync_q);
ins->lock = SPIN_LOCK_UNLOCKED;
/*
* Add our new device's list hook to the modem_list
*/
list_add ( &ins->list,&modem_list );
eu_report ("New USB ADSL device detected, waiting for DSP code...\n");
#ifdef LINUX_2_6
eu_report ("Interface %d accepted.\n",intf->altsetting[0].desc.bInterfaceNumber);
#endif
#ifdef USEBULK
EU_CLEAR_FLAG (ins, EU_LOW_RATE);
#else
EU_SET_FLAG (ins, EU_LOW_RATE);
#endif
/*
* Use constants for endpoint addresses - It saves us from parsing through
* descriptors ..
*/
ins->pipe_bulk_idma_out = usb_sndbulkpipe(usb, EP_BULK_IDMA_OUT);
ins->pipe_bulk_data_out = usb_sndbulkpipe(usb, EP_BULK_DATA_OUT);
ins->pipe_bulk_data_in = usb_rcvbulkpipe(usb, EP_BULK_DATA_IN);
ins->pipe_iso_data_in = usb_rcvisocpipe(usb, EP_ISOC_DATA_IN);
ins->pipe_int_in = usb_rcvintpipe(usb, EP_INT_IN);
/*
* Make sure we can get all the memory we need
*/
ins->intr_data = GET_KBUFFER (sizeof (eu_cdc_t));
if ( !ins->intr_data )
{
eu_err ("Can't allocate interrupt buffer\n");
goto free_instance;
}
ins->segmentation_buffer = GET_KBUFFER(OUTGOING_DATA_SIZE);
if ( !ins->segmentation_buffer )
{
eu_err ("Can't allocate segmentation buffer\n");
goto free_int_buff;
}
INIT_LIST_HEAD ( &ins->comp_read_q );
ins->comp_read_q_lock = SPIN_LOCK_UNLOCKED;
#ifdef USEBULK
nb_frames = 0;
#else
nb_frames = FRAMES_PER_ISO_URB;
#endif /* USEBULK */
/*
* Get a lookaside cache
*/
ins->rb_cache = kmem_cache_create ( "eagle-usb",
sizeof(eu_rb_t),
0,0, NULL,NULL);
if ( !ins->rb_cache )
{
eu_err ("eu_init_postfirm : Can't get lookaside cache.\n");
goto free_seg_buff;
}
for ( i=0; i < INCOMING_Q_SIZE; i++ )
{
ins->read_urb[i] = USB_ALLOC_URB ( nb_frames, GFP_ATOMIC );
if ( !ins->read_urb[i] )
{
eu_err ("eu_init_postfirm : Can't allocate URB \n");
goto free_urbs;
}
ins->read_urb[i]->transfer_buffer = NULL;
}
ins->pOAMCell = GET_KBUFFER(128);
if (ins->pOAMCell == 0 )
{
eu_err ("eu_init_postfirm : Can't allocate memory\n");
goto free_urbs;
}
ins->mru = 0;
/*
* Initialize the CTRL URB queue
*/
ret = alloc_queued_urb_ctrl ( ins, CTRL_URB_Q_SIZE );
if (ret != 0)
{
eu_err ("eu_init_postfirm : alloc_queued_urb_ctrl out of memory\n");
goto free_oam_cell;
}
INIT_LIST_HEAD(&ins->ctrl_urb_ipg_q);
ins->ctrl_q_lock = SPIN_LOCK_UNLOCKED;
ins->ctrl_urb_failed= FALSE;
/*
* Initialize needed kernel timers.
* WatchdogTimer is the "management entity", responsible for initiating a regular
* status check of the modem
*/
init_timer(&ins->AdiModemSm.timerSM);
ins->AdiModemSm.timerSM.function = WatchdogTimer;
ins->AdiModemSm.timerSM.data = (unsigned long) ins;
/*
* As UHCI does not allow to queue control urbs, we make our own queueing
*/
init_timer(&ins->ctrl_urb_q_timer);
ins->ctrl_urb_q_timer.function = ctrl_urb_q_watcher;
ins->ctrl_urb_q_timer.data = (unsigned long) ins;
init_timer (&ins->ctrl_urb_retry);
ins->ctrl_urb_retry.function = ctrl_urb_retry_send;
ins->ctrl_urb_retry.data = (unsigned long) ins;
ins->ctrl_urb_failed = NULL;
/*
* Get interrupt urb
*/
ins->urb_int = USB_ALLOC_URB ( 0, GFP_ATOMIC );
if ( !ins->urb_int )
{
eu_err ("eu_init_postfirm : Can't allocate INT URB \n");
goto free_oam_cell;
}
/*
* Get write urb
*/
ins->urb_write = USB_ALLOC_URB ( 0, GFP_ATOMIC );
if ( !ins->urb_write )
{
eu_err ("eu_init_postfirm : Can't allocate WRITE URB \n");
goto free_urb_int;
}
/*
* Get oam_write urb
*/
ins->urb_oam_write = USB_ALLOC_URB ( 0, GFP_ATOMIC );
if ( !ins->urb_oam_write )
{
eu_err ("eu_init_postfirm : Can't allocate OAM WRITE URB \n");
goto free_urb_write;
}
/*
* Other init stuff
*/
ins->AdiModemSm.HeartbeatCounter = 0;
ins->AdiModemSm.CurrentAdiState = STATE_JUST_PLUGGED_IN;
init_timer(&ins->OAMTimer);
ins->OAMTimer.function = OAMTimerFunction;
ins->OAMTimer.data = (unsigned long)ins;
/*
* Interface 1 is for outbound traffic
*/
tmp = USB_DRIVER_CLAIM_INTERFACE(&eu_driver, GET_INTF_PTR(usb,1), ins);
if ( tmp != 0 )
{
eu_report ("Failed to claim interface 1 (%d)\n",-tmp);
goto free_oam_timer;
}
/*
* Interface 2 is for inbound traffic
*/
tmp = USB_DRIVER_CLAIM_INTERFACE(&eu_driver, GET_INTF_PTR(usb,2), ins);
if ( tmp != 0 )
{
eu_report ("Failed to claim interface 2 (%d)\n",-tmp);
goto release_intf_1;
}
ins->users = 3;
#ifndef USEBULK
/*
* Set alternate interface to 8, which is ISO transport
* with the max. packet size ( about 1007 bytes)
*/
if (usb_set_interface(usb, USB_INTF_IN, FASTEST_ISO_INTF) < 0)
{
eu_err ("usb_set_interface failed on iso alt 8\n");
}
#endif /* USEBULK */
/*
* Setup our /proc interface
*/
snprintf ( path,32,"%03d-%03d",ins->usbdev->bus->busnum, ins->usbdev->devnum);
procfile=create_proc_read_entry(path,0, eu_procdir, eu_read_proc, ins);
if (procfile)
{
procfile->owner=THIS_MODULE;
eu_report ("created proc entry at : /proc/driver/eagle-usb/%s\n",
path);
}
else
{
eu_err ("failed to create proc entry at : /proc/driver/%s !\n",
path);
}
/*
* Get MAC address
*/
eu_get_mac_addr ( ins );
/*
* Initialize wait queue
*/
init_waitqueue_head (&ins->thr_wait);
if ( if_name )
{
strncpy ( ins->if_name, if_name, IFNAMSIZ-1);
ins->if_name[IFNAMSIZ-1] = '\0';
}
/*
* Initialize tasklets
*/
tasklet_init ( &ins->rcv_complete_tasklet,
eu_process_rcv,
(unsigned long) ins );
#ifdef LINUX_2_6
/*
* And work
*/
INIT_WORK (&ins->create_eth,eu_eth_create, ins);
#endif
/*
* And boot SM
*/
#ifdef LINUX_2_6
INIT_WORK (&ins->boot_sm, eu_boot_sm, ins);
#elif defined(LINUX_2_4)
INIT_TQUEUE (&ins->boot_sm, eu_boot_sm, ins);
#endif
/*
* And boot state
*/
ins->boot_state = PRE_BOOT;
/*
* We're successfull !!!!
*/
eu_dbg (DBG_INIT,"nb of users: %u\n",ins->users);
goto byebye;
release_intf_1:
usb_driver_release_interface(&eu_driver, GET_INTF_PTR(usb,1));
free_oam_timer:
if ( timer_pending ( &ins->OAMTimer ) )
{
del_timer ( &ins->OAMTimer );
}
free_urb_write:
usb_free_urb ( ins->urb_write );
ins->urb_write = NULL;
free_urb_int:
usb_free_urb ( ins->urb_int );
ins->urb_int = NULL;
free_oam_cell:
FREE_KBUFFER (ins->pOAMCell );
free_urbs:
for ( i=0; i < INCOMING_Q_SIZE; i++ )
{
if ( ins->read_urb[i] ) {
usb_free_urb ( ins->read_urb[i] );
ins->read_urb[i] = NULL;
}
else
{
break;
}
}
kmem_cache_destroy ( ins->rb_cache );
free_seg_buff:
FREE_KBUFFER ( ins->segmentation_buffer );
free_int_buff:
FREE_KBUFFER ( ins->intr_data );
free_instance:
FREE_KBUFFER (ins);
ins = NULL;
byebye:
eu_leaves ( DBG_INIT);
return (ins);
}
/**
* eu_disconnect - Disconnect an USB device from the system
*
* @usb - USB Device to disconnect
* @ptr - User Data ( pointer to associated instance )
*
*/
#ifdef LINUX_2_4
static void eu_disconnect ( struct usb_device *usb, void *ptr )
#elif defined(LINUX_2_6)
static void eu_disconnect ( struct usb_interface *intf )
#endif
{
#ifdef LINUX_2_4
eu_instance_t *ins = (eu_instance_t *)ptr;
#elif defined (LINUX_2_6)
eu_instance_t *ins = usb_get_intfdata (intf);
struct usb_device *usb = interface_to_usbdev (intf);
#endif
uint32_t pid = usb->descriptor.idProduct;
eu_enters (DBG_INIT);
/*
* We can't do anything if we don't have a valid eu_instance_t pointer
*/
if (ins == NULL)
{
eu_err ("eu_disconnect : No device.\n");
goto dis_done;
}
eu_dbg (DBG_INIT,"intf=0x%p intfdate=0x%p ins = 0x%p\n",
intf,usb_get_intfdata (intf),ins);
/*
* Do nothing if you also have no usbdev associated
*/
if (ins->usbdev == NULL )
{
eu_dbg (DBG_INIT,"No usb dev associated.\n");
goto dis_done;
}
eu_dbg (DBG_INIT,"ins->usbdev = 0x%p\n",ins->usbdev);
EU_SET_FLAG (ins, EU_UNPLUG);
eu_dbg (DBG_INIT,"Let check PID\n");
switch (pid)
{
case CASE_PREFIRM:
list_del(&ins->list);
FREE_KBUFFER(ins);
eu_report ("Pre-firmware modem removed\n");
break;
case CASE_POSTFIRM:
/* ins->usbdev = NULL; */
#ifdef LINUX_2_6
usb_set_intfdata (intf, NULL);
#endif
eu_disconnect_postfirm (ins,usb);
ins = NULL;
break;
}
eu_dbg (DBG_INIT,"intf=0x%p intfdata=0x%p ins=0x%p\n",intf,usb_get_intfdata (intf),ins);
dis_done:
eu_leaves (DBG_INIT);
}
/**
* eu_disconnect_postfirm - Perform destruction of a postfirmware device
*
* @ins - Instance to destroy
*
*/
static void eu_disconnect_postfirm ( eu_instance_t *ins , struct usb_device *usb )
{
int i;
char path[32];
/*
* Unlink pending interrupt URBs
*/
if ( EU_TEST_FLAG ( ins, EU_HAS_INT ) )
{
eu_dbg (DBG_INIT,"Stop interrupt URB\n");
ins->urb_int->transfer_flags &= ~URB_ASYNC_UNLINK;
usb_unlink_urb(ins->urb_int);
usb_free_urb (ins->urb_int);
EU_CLEAR_FLAG (ins, EU_HAS_INT);
}
/*
* Decrement the number of user, and destroy this instance only if this
* number reaches 0
*/
ins->users --;
eu_dbg (DBG_INIT,"nb of users: %u\n",ins->users);
if ( ins->users > 0 )
{
eu_dbg (DBG_INIT,"Still %u user(s).. Do nothing\n",ins->users);
return;
}
/*
* If timers are currently running, delete them:
*/
if ( timer_pending (&ins->AdiModemSm.timerSM) )
{
del_timer ( &ins->AdiModemSm.timerSM );
}
if ( timer_pending (&ins->ctrl_urb_q_timer) )
{
del_timer ( &ins->ctrl_urb_q_timer );
}
if ( timer_pending (&ins->ctrl_urb_retry) )
{
del_timer ( &ins->ctrl_urb_retry );
}
/*
* Flush all pending task ...
*/
EU_FLUSH (eu_>boot_sm);
/*
* Free the DSP code:
*/
/*
* FIXME : don't duplicate DSP code for every modem ?
*/
FreeDspData ( &ins->MainPage, &ins->pSwapPages, &ins->SwapPageCount );
if ( timer_pending ( &ins->OAMTimer ) )
{
del_timer ( &ins->OAMTimer );
}
/*
* Remove our network interface from the kernel:
*/
if ( ins->eth )
{
/*
* This will call the eu_close method:
*/
unregister_netdev ( ins->eth );
kfree ( ins->eth );
ins->eth = NULL;
}
EU_CLEAR_FLAG (ins, EU_ETH_REGISTERED);
/*
* Free memory we alloced
*/
FREE_KBUFFER ( ins->intr_data );
for ( i=0; i<INCOMING_Q_SIZE; i++ )
{
if ( ( ins->read_urb[i] ) &&
( ins->read_urb[i]->transfer_buffer ) )
{
kmem_cache_free ( ins->rb_cache,
GET_RBUF (ins->read_urb[i]) );
}
if ( ins->read_urb[i] )
{
ins->read_urb[i]->transfer_flags &= ~URB_ASYNC_UNLINK;
usb_unlink_urb ( ins->read_urb[i] );
usb_free_urb ( ins->read_urb[i] );
ins->read_urb[i] = NULL;
}
}
kmem_cache_destroy ( ins->rb_cache );
tasklet_kill ( &ins->rcv_complete_tasklet);
FREE_KBUFFER ( ins->pOAMCell );
unlink_ipg_ctrl_urb ( ins );
free_queued_urb_ctrl (&ins->ctrl_urb_free_q);
free_queued_urb_ctrl (&ins->ctrl_urb_ipg_q);
/*
* Free write urb: it has been unlinked in eu_eth_close
*/
ins->urb_write->transfer_flags &= ~URB_ASYNC_UNLINK;
usb_unlink_urb ( ins->urb_write );
usb_free_urb ( ins->urb_write );
/*
* Free urb_oam_write
*/
ins->urb_oam_write->transfer_flags &= ~URB_ASYNC_UNLINK;
usb_unlink_urb(ins->urb_oam_write);
usb_free_urb ( ins->urb_oam_write );
/*
* Tell usb that we no longer claim these interfaces as our property
*/
#if 0
/*
* Release interrupt interface
*/
usb_driver_release_interface ( &eu_driver, GET_INTF_PTR (usb,0) );
/*
* Release outbound interface
*/
usb_driver_release_interface ( &eu_driver, GET_INTF_PTR (usb,1) );
/*
* Release inbound interface
*/
usb_driver_release_interface ( &eu_driver, GET_INTF_PTR (usb,2) );
#endif
#if 0
if ( ins->pDriverCMVs )
{
FREE_VBUFFER ( ins->pDriverCMVs );
}
#endif
list_del ( &ins->list );
snprintf ( path,32,"%03d-%03d",usb->bus->busnum, usb->devnum );
remove_proc_entry ( path, eu_procdir );
FREE_KBUFFER ( ins );
eu_report ("ADSL device removed\n");
}
/*******************************************************************************/
/* eu_irq */
/*******************************************************************************/
static USB_COMPLETION_PROTO (eu_irq,urb,regs)
{
eu_instance_t *ins;
eu_enters (DBG_INTS);
/*
* Instance is in the URB context.
*/
ins = (eu_instance_t *)urb->context;
if ( NULL == ins )
{
eu_err ("eu_irq : No device.\n");
goto irq_done;
}
if ( !EU_TEST_FLAG(ins, EU_HAS_INT) )
{
eu_err ("eu_irq : Callback on unregistered interrupt handler!\n");
goto irq_done;
}
if (
( urb->status == -ENOENT ) ||
( urb->status == -ECONNRESET ) ||
( urb->status == -ESHUTDOWN )
)
{
/*
* User cancelled this URB : do nothing, and don't reset status to 0,
* or the URB will be re-used
*/
eu_report ("eu_irq : URB canceled by user.\n");
EU_CLEAR_FLAG (ins, EU_HAS_INT);
goto irq_done;
}
/*
* Lets check the status first, to make sure this was succesfull
*/
if ( urb->status < 0 )
{
eu_err ("eu_irq : URB status indicates error (%d)\n",
urb->status);
urb->status = 0;
goto resubmit;
}
/*
* All is well, we can process the data!
*/
if ( ins->intr_data->bRequestType == 0x08 ) /* device-to-host interrupt */
{
eu_devint_t *pintr;
pintr = (eu_devint_t *) (&(ins->intr_data->data[0]));
switch ( cpu_to_le16 (pintr->intr) )
{
case EU_INT_LOADSWAPPAGE:
{
ins->swap_data = cpu_to_le16 (pintr->intr_info.swap_data);
eu_dbg (DBG_INTS,"interrupt = EU_INT_LOADSWAPPAGE\n");
if ( ins->AdiModemSm.CurrentAdiState != STATE_HARD_RESET_INITIATE )
{
ins->boot_state = UPLOAD_P;
EU_SCHEDULE ( &ins->boot_sm ) ;
}
}
break;
case EU_INT_INCOMINGCMV:
{
eu_dbg (DBG_INTS,"interrupt = EU_INT_INCOMINGCMV\n");
ProcessIncomingCmv ( ins, pintr->intr_info.cmv_data );
}
break;
default:
eu_dbg (DBG_INTS,"interrupt = unsupported(%d)\n", pintr->intr);
break;
}
}
resubmit:
#ifdef LINUX_2_6
{
int ret;
ret = USB_SUBMIT_URB ( urb, GFP_ATOMIC );
if ( ret )
{
eu_err ("eu_irq: URB submission failure (%d)\n",ret);
}
}
#endif
irq_done:
eu_leaves (DBG_INTS);
}
/**
* find_hardware - Look for the given hardware in instance list
*
*/
static eu_instance_t *find_hardware ( struct usb_device *dev )
{
struct list_head *ptr;
eu_instance_t *ins = NULL;
for ( ptr = modem_list.next; ptr != &modem_list; ptr = ptr->next )
{
eu_instance_t *entry;
entry=list_entry (ptr, eu_instance_t, list);
if ( entry->usbdev == dev )
{
ins=entry;
break;
}
}
return ins;
}
/**
* eu_user - ioctl handler for ioctl emited on the USB device file. Ioctls emited
* on the network device will be treated by eu_eth_ioctl
*/
#ifdef LINUX_2_4
static int eu_user ( struct usb_device *dev, unsigned int code, void *buf )
#elif defined (LINUX_2_6)
static int eu_user ( struct usb_interface *intf, unsigned int code, void *buf )
#endif
{
#ifdef LINUX_2_6
struct usb_device *dev = interface_to_usbdev (intf);
#endif
eu_instance_t *ins;
int retval = -ENOTTY;
uint32_t pid = dev->descriptor.idProduct;
/*
* USB automatically transfers user ioctl structure in kernel
* address space (the size is already encoded in the ioctl code):
*/
struct eu_ioctl_info *pIOCTLinfo = (struct eu_ioctl_info *) buf;
MODULE_USER_GET;
if ( !(ins = find_hardware(dev)) )
{
eu_report ("Could not find eu_instance_t for USB device %03d/%03d\n",
dev->bus->busnum, dev->devnum);
MODULE_USER_RELEASE;
return -ENOTTY;
}
/*
* Set/Get debug flags works for pre/post firmwares.
*/
if ( code == EU_IO_SETDBG )
{
if ( NULL == pIOCTLinfo )
{
eu_err ("EU_IO_SETDBG : No data\n");
retval = -EINVAL;
goto byebye;
}
module_dbg_mask = pIOCTLinfo->idma_start;
eu_report ("Debug mask set to 0x%x\n",module_dbg_mask);
retval = 0;
goto byebye;
}
if ( code == EU_IO_GETDBG )
{
if ( NULL == pIOCTLinfo )
{
eu_err ("EU_IO_GETDBG : No data\n");
retval = -EINVAL;
goto byebye;
}
pIOCTLinfo->idma_start = module_dbg_mask;
retval = 0;
goto byebye;
}
/* Check this ioctl if for one of our devices: */
switch (pid)
{
case CASE_PREFIRM:
eu_err ("In pre-firmware mode only get/set debug ioctl is permitted.\n");
retval = -EINVAL;
break;
case CASE_POSTFIRM:
switch (code)
{
#if 0
case EU_IO_CMVS:
retval = -ERESTARTSYS;
if ( !spin_trylock ( &ins->net_lock ) )
{
eu_err ("EU_IO_CMVS : Can't lock\n");
break;
}
if ( ins->flags & EU_OPEN )
{
retval = -EBUSY;
eu_err ("EU_IO_CMVS : Eth device already open.\n");
goto end_set_cmvs;
}
if (NULL == pIOCTLinfo)
{
eu_err ("EU_IO_CMVS : No data.\n");
retval = -EFAULT;
goto end_set_cmvs;
}
if (pIOCTLinfo->buffer == NULL )
{
eu_err ("EU_IO_CMVS: Null input buffer\n");
retval = -EINVAL;
goto end_set_cmvs;
}
if ( pIOCTLinfo->buffer_size == 0 )
{
eu_err ("EU_IO_CMVS: Invalid Buffersize\n");
retval = -EINVAL;
goto end_set_cmvs;
}
/* Get a buffer for CMVs */
eu_dbg (DBG_INIT,"Allocating %d bytes for CMVs\n",pIOCTLinfo->buffer_size);
ins->pDriverCMVs = GET_VBUFFER (pIOCTLinfo->buffer_size);
if ( ins->pDriverCMVs == NULL )
{
eu_err ("EU_IO_CMVS: Not enough memory to get %d bytes\n",
pIOCTLinfo->buffer_size);
retval = -ENOMEM;
goto end_set_cmvs;
}
if (copy_from_user(ins->pDriverCMVs, pIOCTLinfo->buffer, pIOCTLinfo->buffer_size))
{
retval = -EFAULT;
FREE_VBUFFER (ins->pDriverCMVs);
eu_err ("EU_IO_CMVS : copy from user failed.\n");
goto end_set_cmvs;
}
eu_report ("ioctl EU_IO_CMVS received and treated.\n");
retval = 0;
end_set_cmvs:
spin_unlock ( &ins->net_lock);
break;
#endif
case EU_IO_OPTIONS: /* Set driver options */
/*
* Option cannot be set while network interface is up
*/
#if 0
if ( ins->pDriverCMVs == NULL )
{
/* User as not yet sent EU_IO_CMVS */
eu_err ("EU_IO_OPTIONS: CMVs not yet sent.\n");
retval = -ERESTARTSYS;
goto end_set_options;
}
#endif
if (!( EU_TEST_FLAG (ins, EU_OPEN ) ) )
{
eu_options_t opt;
memcpy(&opt, &default_options, sizeof(eu_options_t));
if (NULL == pIOCTLinfo)
{
eu_err ("EU_IO_OPTIONS : No data.\n");
retval = -EFAULT;
break;
}
/* Check the option array size: */
if (sizeof(opt) != pIOCTLinfo->buffer_size)
{
eu_err ("EU_IO_OPTIONS : Invalid Data size\n");
retval = -EINVAL;
break;
}
if (copy_from_user(&opt, pIOCTLinfo->buffer, sizeof(opt)))
{
retval = -EFAULT;
eu_err ("EU_IO_OPTIONS : copy from user failed.\n");
break;
}
/* Options retrieved, check them: */
if ( eu_check_options ( opt ) )
{
/* OK, initialize Mpoa and Msg: */
eu_report ("ioctl EU_IO_OPTIONS received\n");
/*
* Initialize the message handling
*/
if ( !spin_trylock ( &ins->lock ) )
{
eu_err ("EU_IO_OPTIONS : Can't lock\n");
retval = -ERESTARTSYS;
break;
}
eu_msg_initialize ( ins, opt );
MpoaInitialize(ins, opt);
EU_SET_FLAG (ins, EU_MSG_INITIALIZED);
spin_unlock ( &ins->lock );
retval = 0;
}
}
else
{
retval = -EBUSY;
eu_err ("EU_IO_OPTIONS : Eth device already open.\n");
}
break;
case EU_IO_DSP:
/*
* Load DSP code
*/
if ( !EU_TEST_FLAG (ins, EU_MSG_INITIALIZED) )
{
eu_err ("Message handling not initialized."
" Please send options.\n");
retval = -EINVAL;
break;
}
if ( !EU_TEST_FLAG( ins, EU_OPEN ) )
{
uint8_t *pBuf = NULL;
IDMAPage MainPage;
IDMAPage *pSwapPages;
uint32_t SwapPageCount;
if (NULL == pIOCTLinfo)
{
eu_err ("EU_IO_DSP : No data.\n");
retval = -EFAULT;
break;
}
if (pIOCTLinfo->idma_start >= pIOCTLinfo->buffer_size)
{
eu_err ("EU_IO_DSP : Invalid Data Size\n");
retval = -EFAULT;
break;
}
pBuf = GET_VBUFFER(pIOCTLinfo->buffer_size);
if (NULL == pBuf)
{
eu_err ("EU_IO_DSP : No memory.\n");
retval = -ENOMEM;
break;
}
if (copy_from_user(pBuf, pIOCTLinfo->buffer, pIOCTLinfo->buffer_size))
{
eu_err ("EU_IO_DSP : copy from user failed.\n");
retval = -EFAULT;
goto free_adsl_dsp;
}
/*
* Get our DSP code ready for IDMA booting
*/
eu_report ("ioctl EU_IO_DSP received\n");
if ( EU_TEST_FLAG( ins, EU_DSP_IPG ) )
{
retval = -ERESTARTSYS;
goto free_adsl_dsp;
}
EU_SET_FLAG (ins, EU_DSP_IPG);
retval = ProcessDSPCode ( ins,
pBuf,
pIOCTLinfo->idma_start,
pIOCTLinfo->buffer_size,
&MainPage,
&pSwapPages,
&SwapPageCount
);
if (retval != 0)
{
eu_err ("EU_IO_DSP : ProcessDSPCode failed (%d)\n",
retval);
FreeDspData ( &MainPage, &pSwapPages, &SwapPageCount );
goto free_adsl_dsp;
}
EU_SET_FLAG (ins, EU_DSP_LOADED);
/*
* Flush all pending task ...
*/
EU_FLUSH (eu_>boot_sm);
/*
* Ok, we got our DSP code, replace the old DSP code by
* the new one:
*/
FreeDspData ( &ins->MainPage, &ins->pSwapPages, &ins->SwapPageCount );
ins->MainPage.BlockCount = MainPage.BlockCount;
ins->MainPage.Blocks = MainPage.Blocks;
ins->pSwapPages = pSwapPages;
ins->SwapPageCount = SwapPageCount;
/*
* Load the DSP code if necessary:
*/
eu_report ("Loading DSP code to device...\n");
if ( !EU_TEST_FLAG(ins, EU_HAS_INT) )
{
/*
* Get the USB endpoint for IDMA uploading:
*/
#ifdef LINUX_2_4
struct usb_endpoint_descriptor *epint =
GET_INTF_PTR (dev,0)->altsetting[0].endpoint + 0;
uint8_t interval = epint->bInterval;
#elif defined(LINUX_2_6)
uint8_t interval =
GET_INTF_PTR (dev,0)->altsetting[0].endpoint[0].desc.bInterval;
#endif
/*
* Install the interrupt handler to send IDMA pages to the modem
* and handle further incoming data
*/
usb_fill_int_urb ( ins->urb_int, dev, ins->pipe_int_in, ins->intr_data,
sizeof(eu_cdc_t), eu_irq, ins, interval );
EU_SET_FLAG (ins, EU_HAS_INT);
if ( USB_SUBMIT_URB ( ins->urb_int , GFP_KERNEL ) < 0 )
{
eu_err ("Unable to submit interrupt URB!\n");
retval = -EIO;
EU_CLEAR_FLAG (ins, EU_HAS_INT);
goto free_adsl_dsp;
}
}
EU_CLEAR_FLAG (ins, EU_DSP_IPG);
/*
* Send the DSP code to the modem:
*/
ins->boot_state = PRE_BOOT;
if ( !EU_TEST_FLAG(ins,EU_HAS_INT) || boot_the_modem (ins) != 0)
{
eu_err ("Unable to load DSP code to device!\n");
goto free_adsl_dsp;
}
else
{
eu_report ("DSP code successfully loaded to device\n");
}
retval = 0;
free_adsl_dsp:
FREE_VBUFFER(pBuf);
}
else
{
retval = -EBUSY;
eu_err ("EU_IO_DSP : Eth device already open\n");
}
break;
case EU_IO_GETITF: /* Get the network interface name */
{
uint32_t length;
if (NULL == pIOCTLinfo)
{
eu_err ("EU_IO_GETITF : No data.\n");
retval = -EFAULT;
break;
}
if ( !ins->eth )
{
eu_err ("EU_IO_GETIF: eth not yet created !!\n");
retval = -EFAULT;
break;
}
length = strlen(ins->eth->name) + sizeof(char);
if ( NULL == pIOCTLinfo->buffer )
{
/* Get the requested size */
pIOCTLinfo->buffer_size = length;
retval = 0;
}
else
{
/* Get the interface name */
if ( pIOCTLinfo->buffer_size < length )
{
eu_err ("EU_IO_GETITF : Invalid Buffer size\n");
retval = -EINVAL;
break;
}
if ( copy_to_user ( pIOCTLinfo->buffer, ins->eth->name, length ) != 0 )
{
eu_err ("EU_IO_GETITF : copy to user failed\n");
retval = -EFAULT;
break;
}
retval = 0;
}
break;
}
break;
case EU_IO_SYNC: /* Wait for modem "operational" state */
if (wait_event_interruptible(ins->sync_q,
((ins->AdiModemSm.CurrentAdiState & STATE_OPERATIONAL) == STATE_OPERATIONAL)))
retval = -EINTR;
else
retval = 0;
break;
default:
/* Bad ioctl */
break;
}
break;
default:
/* Bad device */
break;
}
byebye:
MODULE_USER_RELEASE;
return retval;
}
/**
* eu_read_proc - /proc interface.
*
*/
static int eu_read_proc ( char *page,
char **start,
off_t off,
int count,
int *eof,
void *data
)
{
eu_instance_t *ins = (eu_instance_t *)data;
int size;
char *p = page;
/*
* If this output needs to be larger than 4K (PAGE_SIZE), we need to do this
* differently
*/
p += sprintf(p, "eagle-usb status display\n");
p += sprintf(p, "-------------------------------------------------------------\n");
p += sprintf(p, "Driver version %s\n",EAGLEUSBVERSION);
p += sprintf(p, "USB Bus : %03d\t USB Device : %03d\t Dbg mask: 0x%x\n",
ins->usbdev->bus->busnum, ins->usbdev->devnum, module_dbg_mask);
if (ins->eth->name)
{
p += sprintf(p, "Ethernet Interface : %s\n",ins->eth->name);
}
else
{
p += sprintf(p, "Ethernet Interface : none\n");
}
p += sprintf(p, "MAC: %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
ins->mac[0],ins->mac[1],ins->mac[2],ins->mac[3],ins->mac[4],
ins->mac[5]);
p += sprintf(p, "Tx Rate %10.10d Rx Rate %10.10d Crc %10.10d\n",
ins->AdiModemSm.UpRate / 1024,
ins->AdiModemSm.DownRate / 1024,
ins->Statistics[STAT_CELLS_LOST_CRC]);
p += sprintf(p, "FEC %10.10d Margin %10.10d Atten %10.10d dB\n",
ins->AdiModemSm.stats_Uncorr_Blks,
ins->AdiModemSm.stats_Cur_SNR & 0xFF,
(ins->AdiModemSm.stats_Cur_Atten & 0xFF)/2);
p += sprintf(p, "VID-CPE %10.10d VID-CO %10.10d HEC %10.10d\n",
ins->AdiModemSm.INFO14,
ins->AdiModemSm.INFO08,
ins->AdiModemSm.DIAG03);
p += sprintf(p, "VPI %10.10d VCI %10.10d Delin ",
ins->Vc.vpi, ins->Vc.vci);
/*Delineation is the only one where we print a string instead of a number*/
if (ins->AdiModemSm.flags & 0x0C00)
p += sprintf(p, "ERROR\n");
else
if (ins->AdiModemSm.flags & 0x0030)
p += sprintf(p, " LOSS\n");
else
p += sprintf(p, " GOOD\n");
p += sprintf(p, "Cells Rx %10.10d Cells Tx %10.10d\n",
ins->Statistics[STAT_CELLS_RX],
ins->Statistics[STAT_CELLS_TX]);
p += sprintf(p, "Pkts Rx %10.10d Pkts Tx %10.10d\n",
ins->Statistics[STAT_PAKTS_RX],
ins->Statistics[STAT_PAKTS_TX]);
p += sprintf(p, "OAM %10.10d Bad VPI %10.10d Bad CRC %10.10d\n",
ins->Statistics[STAT_CELLS_OAM_RCVD],
ins->Statistics[STAT_CELLS_LOST_VPIVCI],
ins->Statistics[STAT_CELLS_LOST_CRC]
);
p += sprintf(p, "Oversiz. %10.10d\n\n",
ins->Statistics[STAT_CELLS_LOST_OTHER] );
switch (ins->AdiModemSm.CurrentAdiState)
{
case STATE_UNDEFINED:
p += sprintf(p, "Modem is unplugged from USB.\n");
break;
case STATE_JUST_PLUGGED_IN:
p += sprintf(p, "Modem waiting for driver response.\n");
p += sprintf (p,"Please send DSP (eaglectrl -d)\n");
break;
case STATE_UNTRAIN:
case STATE_UNTRAIN_TX:
case STATE_UNTRAIN_RX:
p += sprintf(p, "Modem is initializing(UNTRAIN)\n");
break;
case STATE_INITIALIZING:
case STATE_INITIALIZING_TX:
case STATE_INITIALIZING_RX:
p += sprintf(p, "Modem is initializing(INITIALIZING)\n");
break;
case STATE_HARD_RESET_INITIATE:
case STATE_HARD_RESET_END:
case STATE_BOOT_WAIT:
case STATE_BOOT_STAGE_1:
case STATE_BOOT_STAGE_2:
case STATE_BOOT_STAGE_3:
p += sprintf(p, "Modem is booting\n");
break;
case STATE_OPERATIONAL:
case STATE_OPERATIONAL_TX:
case STATE_OPERATIONAL_RX:
p += sprintf(p, "Modem is operational\n");
break;
case STATE_STALLED_FOREVER:
p += sprintf(p, "Modem cannot boot. Unplug other devices and retry.\n");
break;
default:
p += sprintf(p, "Unhandled state\n");
eu_report ("eu_read_proc: unhandled state 0x%X\n", ins->AdiModemSm.CurrentAdiState);
break;
}
p += sprintf(p, "\n");
/*
* Figure out how much of the page we used
*/
size = p - page;
size -= off;
if (size < count)
{
*eof = 1;
if (size <= 0)
return 0;
}
else
size = count;
/*
* Fool caller into thinking we started where he told us to in the page
*/
*start = page + off;
return size;
}
/**
* eu_process_rcv - Process completed receive queue
* Called as a tasklet
*
*/
static void eu_process_rcv ( unsigned long data )
{
eu_instance_t *ins = (eu_instance_t *) data;
unsigned long flags;
/* uint8_t *pbuf; */
eu_rb_t *pbuf;
#ifdef USEBULK
eu_bulk_rb_t *pbulk;
#else
int i;
eu_iso_rb_t *piso;
eu_iso_frame_t *pf;
#endif
int result;
int count = 0;
eu_enters( DBG_READ );
if ( ins == NULL )
{
eu_err ("eu_process_rcv: Null instance !\n");
return;
}
/*
* Treat all messages in the list
*/
while ( !list_empty ( &ins->comp_read_q ) )
{
/*
* Remove head of the list
*/
spin_lock_irqsave (&ins->comp_read_q_lock, flags);
/*
* FIXME : we should use a list function ...
* if list field position change .. we must be able to find it again ...
*
*/
pbuf = list_entry (ins->comp_read_q.next, eu_rb_t, next);
list_del(ins->comp_read_q.next);
spin_unlock_irqrestore (&ins->comp_read_q_lock, flags);
#ifdef USEBULK
pbulk = (eu_bulk_rb_t *) pbuf;
count ++;
result = eu_uni_process_in_data ( ins, &pbulk->data[0], pbulk->length );
if (result)
{
eu_dbg (DBG_READ,"Error %d from eu_uni_process_in_data\n", result);
}
#else
/*
* Now process each frame
*/
piso = (eu_iso_rb_t *) pbuf;
pf = &piso->frames[0];
for ( i=0 ; i<FRAMES_PER_ISO_URB; i++ )
{
if ( pf->status == 0 )
{
count ++;
result = eu_uni_process_in_data ( ins,
&pf->data[0],
pf->length
);
if ( result != 0 )
{
eu_dbg (DBG_READ,"Error %d from eu_uni_process_in_data\n",
result);
}
}
pf ++;
}
#endif /* USEBULK */
/*
* And free the transfer buffer
*/
kmem_cache_free ( ins->rb_cache, pbuf );
}
eu_dbg( DBG_READ ," %d frames processed.\n",count);
eu_leaves ( DBG_READ );
}
/* ------------------------------------ Misc ------------------------------------ */
/**
* eu_check_options - Check given options are accepted
*/
static int eu_check_options ( const eu_options_t opt )
{
int result = 1;
if (opt[CFG_ENCAPS].value != MPOA_MODE_BRIDGED_ETH_LLC &&
opt[CFG_ENCAPS].value != MPOA_MODE_BRIDGED_ETH_VC &&
opt[CFG_ENCAPS].value != MPOA_MODE_ROUTED_IP_LLC &&
opt[CFG_ENCAPS].value != MPOA_MODE_ROUTED_IP_VC &&
opt[CFG_ENCAPS].value != MPOA_MODE_PPPOA_LLC &&
opt[CFG_ENCAPS].value != MPOA_MODE_PPPOA_VC)
result = 0;
return result;
}