2005-04-17 02:20:36 +04:00
/********************************************************************
Filename : via - ircc . c
Version : 1.0
Description : Driver for the VIA VT8231 / VT8233 IrDA chipsets
Author : VIA Technologies , inc
Date : 08 / 06 / 2003
Copyright ( c ) 1998 - 2003 VIA Technologies , Inc .
This program is free software ; you can redistribute it and / or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation ; either version 2 , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful , but WITHOUT
ANY WARRANTIES OR REPRESENTATIONS ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
See the GNU General Public License for more details .
You should have received a copy of the GNU General Public License along with
this program ; if not , write to the Free Software Foundation , Inc . ,
59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
F01 Oct / 02 / 02 : Modify code for V0 .11 ( move out back to back transfer )
F02 Oct / 28 / 02 : Add SB device ID for 3147 and 3177.
Comment :
jul / 09 / 2002 : only implement two kind of dongle currently .
Oct / 02 / 2002 : work on VT8231 and VT8233 .
Aug / 06 / 2003 : change driver format to pci driver .
2004 - 02 - 16 : < sda @ bdit . de >
- Removed unneeded ' legacy ' pci stuff .
- Make sure SIR mode is set ( hw_init ( ) ) before calling mode - dependant stuff .
- On speed change from core , don ' t send SIR frame with new speed .
Use current speed and change speeds later .
- Make module - param dongle_id actually work .
- New dongle_id 17 ( 0x11 ) : TDFS4500 . Single - ended SIR only .
Tested with home - grown PCB on EPIA boards .
- Code cleanup .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/types.h>
# include <linux/skbuff.h>
# include <linux/netdevice.h>
# include <linux/ioport.h>
# include <linux/delay.h>
# include <linux/slab.h>
# include <linux/init.h>
# include <linux/rtnetlink.h>
# include <linux/pci.h>
# include <linux/dma-mapping.h>
# include <asm/io.h>
# include <asm/dma.h>
# include <asm/byteorder.h>
# include <linux/pm.h>
# include <net/irda/wrapper.h>
# include <net/irda/irda.h>
# include <net/irda/irda_device.h>
# include "via-ircc.h"
# define VIA_MODULE_NAME "via-ircc"
# define CHIP_IO_EXTENT 0x40
static char * driver_name = VIA_MODULE_NAME ;
/* Module parameters */
static int qos_mtt_bits = 0x07 ; /* 1 ms or more */
static int dongle_id = 0 ; /* default: probe */
/* We can't guess the type of connected dongle, user *must* supply it. */
module_param ( dongle_id , int , 0 ) ;
/* FIXME : we should not need this, because instances should be automatically
* managed by the PCI layer . Especially that we seem to only be using the
* first entry . Jean II */
/* Max 4 instances for now */
static struct via_ircc_cb * dev_self [ ] = { NULL , NULL , NULL , NULL } ;
/* Some prototypes */
static int via_ircc_open ( int i , chipio_t * info , unsigned int id ) ;
static int via_ircc_close ( struct via_ircc_cb * self ) ;
static int via_ircc_dma_receive ( struct via_ircc_cb * self ) ;
static int via_ircc_dma_receive_complete ( struct via_ircc_cb * self ,
int iobase ) ;
static int via_ircc_hard_xmit_sir ( struct sk_buff * skb ,
struct net_device * dev ) ;
static int via_ircc_hard_xmit_fir ( struct sk_buff * skb ,
struct net_device * dev ) ;
static void via_hw_init ( struct via_ircc_cb * self ) ;
static void via_ircc_change_speed ( struct via_ircc_cb * self , __u32 baud ) ;
static irqreturn_t via_ircc_interrupt ( int irq , void * dev_id ,
struct pt_regs * regs ) ;
static int via_ircc_is_receiving ( struct via_ircc_cb * self ) ;
static int via_ircc_read_dongle_id ( int iobase ) ;
static int via_ircc_net_open ( struct net_device * dev ) ;
static int via_ircc_net_close ( struct net_device * dev ) ;
static int via_ircc_net_ioctl ( struct net_device * dev , struct ifreq * rq ,
int cmd ) ;
static struct net_device_stats * via_ircc_net_get_stats ( struct net_device
* dev ) ;
static void via_ircc_change_dongle_speed ( int iobase , int speed ,
int dongle_id ) ;
static int RxTimerHandler ( struct via_ircc_cb * self , int iobase ) ;
static void hwreset ( struct via_ircc_cb * self ) ;
static int via_ircc_dma_xmit ( struct via_ircc_cb * self , u16 iobase ) ;
static int upload_rxdata ( struct via_ircc_cb * self , int iobase ) ;
static int __devinit via_init_one ( struct pci_dev * pcidev , const struct pci_device_id * id ) ;
static void __devexit via_remove_one ( struct pci_dev * pdev ) ;
/* FIXME : Should use udelay() instead, even if we are x86 only - Jean II */
static void iodelay ( int udelay )
{
u8 data ;
int i ;
for ( i = 0 ; i < udelay ; i + + ) {
data = inb ( 0x80 ) ;
}
}
static struct pci_device_id via_pci_tbl [ ] = {
{ PCI_VENDOR_ID_VIA , 0x8231 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ PCI_VENDOR_ID_VIA , 0x3109 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 1 } ,
{ PCI_VENDOR_ID_VIA , 0x3074 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 2 } ,
{ PCI_VENDOR_ID_VIA , 0x3147 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 3 } ,
{ PCI_VENDOR_ID_VIA , 0x3177 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 4 } ,
{ 0 , }
} ;
MODULE_DEVICE_TABLE ( pci , via_pci_tbl ) ;
static struct pci_driver via_driver = {
. name = VIA_MODULE_NAME ,
. id_table = via_pci_tbl ,
. probe = via_init_one ,
. remove = __devexit_p ( via_remove_one ) ,
} ;
/*
* Function via_ircc_init ( )
*
* Initialize chip . Just find out chip type and resource .
*/
static int __init via_ircc_init ( void )
{
int rc ;
IRDA_DEBUG ( 3 , " %s() \n " , __FUNCTION__ ) ;
rc = pci_register_driver ( & via_driver ) ;
if ( rc < 0 ) {
IRDA_DEBUG ( 0 , " %s(): error rc = %d, returning -ENODEV... \n " ,
__FUNCTION__ , rc ) ;
return - ENODEV ;
}
return 0 ;
}
static int __devinit via_init_one ( struct pci_dev * pcidev , const struct pci_device_id * id )
{
int rc ;
u8 temp , oldPCI_40 , oldPCI_44 , bTmp , bTmp1 ;
u16 Chipset , FirDRQ1 , FirDRQ0 , FirIRQ , FirIOBase ;
chipio_t info ;
IRDA_DEBUG ( 2 , " %s(): Device ID=(0X%X) \n " , __FUNCTION__ , id - > device ) ;
rc = pci_enable_device ( pcidev ) ;
if ( rc ) {
IRDA_DEBUG ( 0 , " %s(): error rc = %d \n " , __FUNCTION__ , rc ) ;
return - ENODEV ;
}
// South Bridge exist
if ( ReadLPCReg ( 0x20 ) ! = 0x3C )
Chipset = 0x3096 ;
else
Chipset = 0x3076 ;
if ( Chipset = = 0x3076 ) {
IRDA_DEBUG ( 2 , " %s(): Chipset = 3076 \n " , __FUNCTION__ ) ;
WriteLPCReg ( 7 , 0x0c ) ;
temp = ReadLPCReg ( 0x30 ) ; //check if BIOS Enable Fir
if ( ( temp & 0x01 ) = = 1 ) { // BIOS close or no FIR
WriteLPCReg ( 0x1d , 0x82 ) ;
WriteLPCReg ( 0x23 , 0x18 ) ;
temp = ReadLPCReg ( 0xF0 ) ;
if ( ( temp & 0x01 ) = = 0 ) {
temp = ( ReadLPCReg ( 0x74 ) & 0x03 ) ; //DMA
FirDRQ0 = temp + 4 ;
temp = ( ReadLPCReg ( 0x74 ) & 0x0C ) > > 2 ;
FirDRQ1 = temp + 4 ;
} else {
temp = ( ReadLPCReg ( 0x74 ) & 0x0C ) > > 2 ; //DMA
FirDRQ0 = temp + 4 ;
FirDRQ1 = FirDRQ0 ;
}
FirIRQ = ( ReadLPCReg ( 0x70 ) & 0x0f ) ; //IRQ
FirIOBase = ReadLPCReg ( 0x60 ) < < 8 ; //IO Space :high byte
FirIOBase = FirIOBase | ReadLPCReg ( 0x61 ) ; //low byte
FirIOBase = FirIOBase ;
info . fir_base = FirIOBase ;
info . irq = FirIRQ ;
info . dma = FirDRQ1 ;
info . dma2 = FirDRQ0 ;
pci_read_config_byte ( pcidev , 0x40 , & bTmp ) ;
pci_write_config_byte ( pcidev , 0x40 , ( ( bTmp | 0x08 ) & 0xfe ) ) ;
pci_read_config_byte ( pcidev , 0x42 , & bTmp ) ;
pci_write_config_byte ( pcidev , 0x42 , ( bTmp | 0xf0 ) ) ;
pci_write_config_byte ( pcidev , 0x5a , 0xc0 ) ;
WriteLPCReg ( 0x28 , 0x70 ) ;
if ( via_ircc_open ( 0 , & info , 0x3076 ) = = 0 )
rc = 0 ;
} else
rc = - ENODEV ; //IR not turn on
} else { //Not VT1211
IRDA_DEBUG ( 2 , " %s(): Chipset = 3096 \n " , __FUNCTION__ ) ;
pci_read_config_byte ( pcidev , 0x67 , & bTmp ) ; //check if BIOS Enable Fir
if ( ( bTmp & 0x01 ) = = 1 ) { // BIOS enable FIR
//Enable Double DMA clock
pci_read_config_byte ( pcidev , 0x42 , & oldPCI_40 ) ;
pci_write_config_byte ( pcidev , 0x42 , oldPCI_40 | 0x80 ) ;
pci_read_config_byte ( pcidev , 0x40 , & oldPCI_40 ) ;
pci_write_config_byte ( pcidev , 0x40 , oldPCI_40 & 0xf7 ) ;
pci_read_config_byte ( pcidev , 0x44 , & oldPCI_44 ) ;
pci_write_config_byte ( pcidev , 0x44 , 0x4e ) ;
//---------- read configuration from Function0 of south bridge
if ( ( bTmp & 0x02 ) = = 0 ) {
pci_read_config_byte ( pcidev , 0x44 , & bTmp1 ) ; //DMA
FirDRQ0 = ( bTmp1 & 0x30 ) > > 4 ;
pci_read_config_byte ( pcidev , 0x44 , & bTmp1 ) ;
FirDRQ1 = ( bTmp1 & 0xc0 ) > > 6 ;
} else {
pci_read_config_byte ( pcidev , 0x44 , & bTmp1 ) ; //DMA
FirDRQ0 = ( bTmp1 & 0x30 ) > > 4 ;
FirDRQ1 = 0 ;
}
pci_read_config_byte ( pcidev , 0x47 , & bTmp1 ) ; //IRQ
FirIRQ = bTmp1 & 0x0f ;
pci_read_config_byte ( pcidev , 0x69 , & bTmp ) ;
FirIOBase = bTmp < < 8 ; //hight byte
pci_read_config_byte ( pcidev , 0x68 , & bTmp ) ;
FirIOBase = ( FirIOBase | bTmp ) & 0xfff0 ;
//-------------------------
info . fir_base = FirIOBase ;
info . irq = FirIRQ ;
info . dma = FirDRQ1 ;
info . dma2 = FirDRQ0 ;
if ( via_ircc_open ( 0 , & info , 0x3096 ) = = 0 )
rc = 0 ;
} else
rc = - ENODEV ; //IR not turn on !!!!!
} //Not VT1211
IRDA_DEBUG ( 2 , " %s(): End - rc = %d \n " , __FUNCTION__ , rc ) ;
return rc ;
}
/*
* Function via_ircc_clean ( )
*
* Close all configured chips
*
*/
static void via_ircc_clean ( void )
{
int i ;
IRDA_DEBUG ( 3 , " %s() \n " , __FUNCTION__ ) ;
2006-08-15 11:05:38 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( dev_self ) ; i + + ) {
2005-04-17 02:20:36 +04:00
if ( dev_self [ i ] )
via_ircc_close ( dev_self [ i ] ) ;
}
}
static void __devexit via_remove_one ( struct pci_dev * pdev )
{
IRDA_DEBUG ( 3 , " %s() \n " , __FUNCTION__ ) ;
/* FIXME : This is ugly. We should use pci_get_drvdata(pdev);
* to get our driver instance and call directly via_ircc_close ( ) .
* See vlsi_ir for details . . .
* Jean II */
via_ircc_clean ( ) ;
/* FIXME : This should be in via_ircc_close(), because here we may
* theoritically disable still configured devices : - ( - Jean II */
pci_disable_device ( pdev ) ;
}
static void __exit via_ircc_cleanup ( void )
{
IRDA_DEBUG ( 3 , " %s() \n " , __FUNCTION__ ) ;
/* FIXME : This should be redundant, as pci_unregister_driver()
* should call via_remove_one ( ) on each device .
* Jean II */
via_ircc_clean ( ) ;
/* Cleanup all instances of the driver */
pci_unregister_driver ( & via_driver ) ;
}
/*
* Function via_ircc_open ( iobase , irq )
*
* Open driver instance
*
*/
static __devinit int via_ircc_open ( int i , chipio_t * info , unsigned int id )
{
struct net_device * dev ;
struct via_ircc_cb * self ;
int err ;
IRDA_DEBUG ( 3 , " %s() \n " , __FUNCTION__ ) ;
2006-08-15 11:05:38 +04:00
if ( i > = ARRAY_SIZE ( dev_self ) )
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
/* Allocate new instance of the driver */
dev = alloc_irdadev ( sizeof ( struct via_ircc_cb ) ) ;
if ( dev = = NULL )
return - ENOMEM ;
self = dev - > priv ;
self - > netdev = dev ;
spin_lock_init ( & self - > lock ) ;
/* FIXME : We should store our driver instance in the PCI layer,
* using pci_set_drvdata ( ) , not in this array .
* See vlsi_ir for details . . . - Jean II */
/* FIXME : 'i' is always 0 (see via_init_one()) :-( - Jean II */
/* Need to store self somewhere */
dev_self [ i ] = self ;
self - > index = i ;
/* Initialize Resource */
self - > io . cfg_base = info - > cfg_base ;
self - > io . fir_base = info - > fir_base ;
self - > io . irq = info - > irq ;
self - > io . fir_ext = CHIP_IO_EXTENT ;
self - > io . dma = info - > dma ;
self - > io . dma2 = info - > dma2 ;
self - > io . fifo_size = 32 ;
self - > chip_id = id ;
self - > st_fifo . len = 0 ;
self - > RxDataReady = 0 ;
/* Reserve the ioports that we need */
if ( ! request_region ( self - > io . fir_base , self - > io . fir_ext , driver_name ) ) {
IRDA_DEBUG ( 0 , " %s(), can't get iobase of 0x%03x \n " ,
__FUNCTION__ , self - > io . fir_base ) ;
err = - ENODEV ;
goto err_out1 ;
}
/* Initialize QoS for this device */
irda_init_max_qos_capabilies ( & self - > qos ) ;
/* Check if user has supplied the dongle id or not */
if ( ! dongle_id )
dongle_id = via_ircc_read_dongle_id ( self - > io . fir_base ) ;
self - > io . dongle_id = dongle_id ;
/* The only value we must override it the baudrate */
/* Maximum speeds and capabilities are dongle-dependant. */
switch ( self - > io . dongle_id ) {
case 0x0d :
self - > qos . baud_rate . bits =
IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200 |
IR_576000 | IR_1152000 | ( IR_4000000 < < 8 ) ;
break ;
default :
self - > qos . baud_rate . bits =
IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200 ;
break ;
}
/* Following was used for testing:
*
* self - > qos . baud_rate . bits = IR_9600 ;
*
* Is is no good , as it prohibits ( error - prone ) speed - changes .
*/
self - > qos . min_turn_time . bits = qos_mtt_bits ;
irda_qos_bits_to_value ( & self - > qos ) ;
/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
self - > rx_buff . truesize = 14384 + 2048 ;
self - > tx_buff . truesize = 14384 + 2048 ;
/* Allocate memory if needed */
self - > rx_buff . head =
dma_alloc_coherent ( NULL , self - > rx_buff . truesize ,
& self - > rx_buff_dma , GFP_KERNEL ) ;
if ( self - > rx_buff . head = = NULL ) {
err = - ENOMEM ;
goto err_out2 ;
}
memset ( self - > rx_buff . head , 0 , self - > rx_buff . truesize ) ;
self - > tx_buff . head =
dma_alloc_coherent ( NULL , self - > tx_buff . truesize ,
& self - > tx_buff_dma , GFP_KERNEL ) ;
if ( self - > tx_buff . head = = NULL ) {
err = - ENOMEM ;
goto err_out3 ;
}
memset ( self - > tx_buff . head , 0 , self - > tx_buff . truesize ) ;
self - > rx_buff . in_frame = FALSE ;
self - > rx_buff . state = OUTSIDE_FRAME ;
self - > tx_buff . data = self - > tx_buff . head ;
self - > rx_buff . data = self - > rx_buff . head ;
/* Reset Tx queue info */
self - > tx_fifo . len = self - > tx_fifo . ptr = self - > tx_fifo . free = 0 ;
self - > tx_fifo . tail = self - > tx_buff . head ;
/* Keep track of module usage */
SET_MODULE_OWNER ( dev ) ;
/* Override the network functions we need to use */
dev - > hard_start_xmit = via_ircc_hard_xmit_sir ;
dev - > open = via_ircc_net_open ;
dev - > stop = via_ircc_net_close ;
dev - > do_ioctl = via_ircc_net_ioctl ;
dev - > get_stats = via_ircc_net_get_stats ;
err = register_netdev ( dev ) ;
if ( err )
goto err_out4 ;
IRDA_MESSAGE ( " IrDA: Registered device %s (via-ircc) \n " , dev - > name ) ;
/* Initialise the hardware..
*/
self - > io . speed = 9600 ;
via_hw_init ( self ) ;
return 0 ;
err_out4 :
dma_free_coherent ( NULL , self - > tx_buff . truesize ,
self - > tx_buff . head , self - > tx_buff_dma ) ;
err_out3 :
dma_free_coherent ( NULL , self - > rx_buff . truesize ,
self - > rx_buff . head , self - > rx_buff_dma ) ;
err_out2 :
release_region ( self - > io . fir_base , self - > io . fir_ext ) ;
err_out1 :
free_netdev ( dev ) ;
dev_self [ i ] = NULL ;
return err ;
}
/*
* Function via_ircc_close ( self )
*
* Close driver instance
*
*/
static int via_ircc_close ( struct via_ircc_cb * self )
{
int iobase ;
IRDA_DEBUG ( 3 , " %s() \n " , __FUNCTION__ ) ;
IRDA_ASSERT ( self ! = NULL , return - 1 ; ) ;
iobase = self - > io . fir_base ;
ResetChip ( iobase , 5 ) ; //hardware reset.
/* Remove netdevice */
unregister_netdev ( self - > netdev ) ;
/* Release the PORT that this driver is using */
IRDA_DEBUG ( 2 , " %s(), Releasing Region %03x \n " ,
__FUNCTION__ , self - > io . fir_base ) ;
release_region ( self - > io . fir_base , self - > io . fir_ext ) ;
if ( self - > tx_buff . head )
dma_free_coherent ( NULL , self - > tx_buff . truesize ,
self - > tx_buff . head , self - > tx_buff_dma ) ;
if ( self - > rx_buff . head )
dma_free_coherent ( NULL , self - > rx_buff . truesize ,
self - > rx_buff . head , self - > rx_buff_dma ) ;
dev_self [ self - > index ] = NULL ;
free_netdev ( self - > netdev ) ;
return 0 ;
}
/*
* Function via_hw_init ( self )
*
* Returns non - negative on success .
*
* Formerly via_ircc_setup
*/
static void via_hw_init ( struct via_ircc_cb * self )
{
int iobase = self - > io . fir_base ;
IRDA_DEBUG ( 3 , " %s() \n " , __FUNCTION__ ) ;
SetMaxRxPacketSize ( iobase , 0x0fff ) ; //set to max:4095
// FIFO Init
EnRXFIFOReadyInt ( iobase , OFF ) ;
EnRXFIFOHalfLevelInt ( iobase , OFF ) ;
EnTXFIFOHalfLevelInt ( iobase , OFF ) ;
EnTXFIFOUnderrunEOMInt ( iobase , ON ) ;
EnTXFIFOReadyInt ( iobase , OFF ) ;
InvertTX ( iobase , OFF ) ;
InvertRX ( iobase , OFF ) ;
if ( ReadLPCReg ( 0x20 ) = = 0x3c )
WriteLPCReg ( 0xF0 , 0 ) ; // for VT1211
/* Int Init */
EnRXSpecInt ( iobase , ON ) ;
/* The following is basically hwreset */
/* If this is the case, why not just call hwreset() ? Jean II */
ResetChip ( iobase , 5 ) ;
EnableDMA ( iobase , OFF ) ;
EnableTX ( iobase , OFF ) ;
EnableRX ( iobase , OFF ) ;
EnRXDMA ( iobase , OFF ) ;
EnTXDMA ( iobase , OFF ) ;
RXStart ( iobase , OFF ) ;
TXStart ( iobase , OFF ) ;
InitCard ( iobase ) ;
CommonInit ( iobase ) ;
SIRFilter ( iobase , ON ) ;
SetSIR ( iobase , ON ) ;
CRC16 ( iobase , ON ) ;
EnTXCRC ( iobase , 0 ) ;
WriteReg ( iobase , I_ST_CT_0 , 0x00 ) ;
SetBaudRate ( iobase , 9600 ) ;
SetPulseWidth ( iobase , 12 ) ;
SetSendPreambleCount ( iobase , 0 ) ;
self - > io . speed = 9600 ;
self - > st_fifo . len = 0 ;
via_ircc_change_dongle_speed ( iobase , self - > io . speed ,
self - > io . dongle_id ) ;
WriteReg ( iobase , I_ST_CT_0 , 0x80 ) ;
}
/*
* Function via_ircc_read_dongle_id ( void )
*
*/
static int via_ircc_read_dongle_id ( int iobase )
{
int dongle_id = 9 ; /* Default to IBM */
IRDA_ERROR ( " via-ircc: dongle probing not supported, please specify dongle_id module parameter. \n " ) ;
return dongle_id ;
}
/*
* Function via_ircc_change_dongle_speed ( iobase , speed , dongle_id )
* Change speed of the attach dongle
* only implement two type of dongle currently .
*/
static void via_ircc_change_dongle_speed ( int iobase , int speed ,
int dongle_id )
{
u8 mode = 0 ;
/* speed is unused, as we use IsSIROn()/IsMIROn() */
speed = speed ;
IRDA_DEBUG ( 1 , " %s(): change_dongle_speed to %d for 0x%x, %d \n " ,
__FUNCTION__ , speed , iobase , dongle_id ) ;
switch ( dongle_id ) {
/* Note: The dongle_id's listed here are derived from
* nsc - ircc . c */
case 0x08 : /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */
UseOneRX ( iobase , ON ) ; // use one RX pin RX1,RX2
InvertTX ( iobase , OFF ) ;
InvertRX ( iobase , OFF ) ;
EnRX2 ( iobase , ON ) ; //sir to rx2
EnGPIOtoRX2 ( iobase , OFF ) ;
if ( IsSIROn ( iobase ) ) { //sir
// Mode select Off
SlowIRRXLowActive ( iobase , ON ) ;
udelay ( 1000 ) ;
SlowIRRXLowActive ( iobase , OFF ) ;
} else {
if ( IsMIROn ( iobase ) ) { //mir
// Mode select On
SlowIRRXLowActive ( iobase , OFF ) ;
udelay ( 20 ) ;
} else { // fir
if ( IsFIROn ( iobase ) ) { //fir
// Mode select On
SlowIRRXLowActive ( iobase , OFF ) ;
udelay ( 20 ) ;
}
}
}
break ;
case 0x09 : /* IBM31T1100 or Temic TFDS6000/TFDS6500 */
UseOneRX ( iobase , ON ) ; //use ONE RX....RX1
InvertTX ( iobase , OFF ) ;
InvertRX ( iobase , OFF ) ; // invert RX pin
EnRX2 ( iobase , ON ) ;
EnGPIOtoRX2 ( iobase , OFF ) ;
if ( IsSIROn ( iobase ) ) { //sir
// Mode select On
SlowIRRXLowActive ( iobase , ON ) ;
udelay ( 20 ) ;
// Mode select Off
SlowIRRXLowActive ( iobase , OFF ) ;
}
if ( IsMIROn ( iobase ) ) { //mir
// Mode select On
SlowIRRXLowActive ( iobase , OFF ) ;
udelay ( 20 ) ;
// Mode select Off
SlowIRRXLowActive ( iobase , ON ) ;
} else { // fir
if ( IsFIROn ( iobase ) ) { //fir
// Mode select On
SlowIRRXLowActive ( iobase , OFF ) ;
// TX On
WriteTX ( iobase , ON ) ;
udelay ( 20 ) ;
// Mode select OFF
SlowIRRXLowActive ( iobase , ON ) ;
udelay ( 20 ) ;
// TX Off
WriteTX ( iobase , OFF ) ;
}
}
break ;
case 0x0d :
UseOneRX ( iobase , OFF ) ; // use two RX pin RX1,RX2
InvertTX ( iobase , OFF ) ;
InvertRX ( iobase , OFF ) ;
SlowIRRXLowActive ( iobase , OFF ) ;
if ( IsSIROn ( iobase ) ) { //sir
EnGPIOtoRX2 ( iobase , OFF ) ;
WriteGIO ( iobase , OFF ) ;
EnRX2 ( iobase , OFF ) ; //sir to rx2
} else { // fir mir
EnGPIOtoRX2 ( iobase , OFF ) ;
WriteGIO ( iobase , OFF ) ;
EnRX2 ( iobase , OFF ) ; //fir to rx
}
break ;
case 0x11 : /* Temic TFDS4500 */
IRDA_DEBUG ( 2 , " %s: Temic TFDS4500: One RX pin, TX normal, RX inverted. \n " , __FUNCTION__ ) ;
UseOneRX ( iobase , ON ) ; //use ONE RX....RX1
InvertTX ( iobase , OFF ) ;
InvertRX ( iobase , ON ) ; // invert RX pin
EnRX2 ( iobase , ON ) ; //sir to rx2
EnGPIOtoRX2 ( iobase , OFF ) ;
if ( IsSIROn ( iobase ) ) { //sir
// Mode select On
SlowIRRXLowActive ( iobase , ON ) ;
udelay ( 20 ) ;
// Mode select Off
SlowIRRXLowActive ( iobase , OFF ) ;
} else {
IRDA_DEBUG ( 0 , " %s: Warning: TFDS4500 not running in SIR mode ! \n " , __FUNCTION__ ) ;
}
break ;
case 0x0ff : /* Vishay */
if ( IsSIROn ( iobase ) )
mode = 0 ;
else if ( IsMIROn ( iobase ) )
mode = 1 ;
else if ( IsFIROn ( iobase ) )
mode = 2 ;
else if ( IsVFIROn ( iobase ) )
mode = 5 ; //VFIR-16
SI_SetMode ( iobase , mode ) ;
break ;
default :
IRDA_ERROR ( " %s: Error: dongle_id %d unsupported ! \n " ,
__FUNCTION__ , dongle_id ) ;
}
}
/*
* Function via_ircc_change_speed ( self , baud )
*
* Change the speed of the device
*
*/
static void via_ircc_change_speed ( struct via_ircc_cb * self , __u32 speed )
{
struct net_device * dev = self - > netdev ;
u16 iobase ;
u8 value = 0 , bTmp ;
iobase = self - > io . fir_base ;
/* Update accounting for new speed */
self - > io . speed = speed ;
IRDA_DEBUG ( 1 , " %s: change_speed to %d bps. \n " , __FUNCTION__ , speed ) ;
WriteReg ( iobase , I_ST_CT_0 , 0x0 ) ;
/* Controller mode sellection */
switch ( speed ) {
case 2400 :
case 9600 :
case 19200 :
case 38400 :
case 57600 :
case 115200 :
value = ( 115200 / speed ) - 1 ;
SetSIR ( iobase , ON ) ;
CRC16 ( iobase , ON ) ;
break ;
case 576000 :
/* FIXME: this can't be right, as it's the same as 115200,
* and 576000 is MIR , not SIR . */
value = 0 ;
SetSIR ( iobase , ON ) ;
CRC16 ( iobase , ON ) ;
break ;
case 1152000 :
value = 0 ;
SetMIR ( iobase , ON ) ;
/* FIXME: CRC ??? */
break ;
case 4000000 :
value = 0 ;
SetFIR ( iobase , ON ) ;
SetPulseWidth ( iobase , 0 ) ;
SetSendPreambleCount ( iobase , 14 ) ;
CRC16 ( iobase , OFF ) ;
EnTXCRC ( iobase , ON ) ;
break ;
case 16000000 :
value = 0 ;
SetVFIR ( iobase , ON ) ;
/* FIXME: CRC ??? */
break ;
default :
value = 0 ;
break ;
}
/* Set baudrate to 0x19[2..7] */
bTmp = ( ReadReg ( iobase , I_CF_H_1 ) & 0x03 ) ;
bTmp | = value < < 2 ;
WriteReg ( iobase , I_CF_H_1 , bTmp ) ;
/* Some dongles may need to be informed about speed changes. */
via_ircc_change_dongle_speed ( iobase , speed , self - > io . dongle_id ) ;
/* Set FIFO size to 64 */
SetFIFO ( iobase , 64 ) ;
/* Enable IR */
WriteReg ( iobase , I_ST_CT_0 , 0x80 ) ;
// EnTXFIFOHalfLevelInt(iobase,ON);
/* Enable some interrupts so we can receive frames */
//EnAllInt(iobase,ON);
if ( IsSIROn ( iobase ) ) {
SIRFilter ( iobase , ON ) ;
SIRRecvAny ( iobase , ON ) ;
} else {
SIRFilter ( iobase , OFF ) ;
SIRRecvAny ( iobase , OFF ) ;
}
if ( speed > 115200 ) {
/* Install FIR xmit handler */
dev - > hard_start_xmit = via_ircc_hard_xmit_fir ;
via_ircc_dma_receive ( self ) ;
} else {
/* Install SIR xmit handler */
dev - > hard_start_xmit = via_ircc_hard_xmit_sir ;
}
netif_wake_queue ( dev ) ;
}
/*
* Function via_ircc_hard_xmit ( skb , dev )
*
* Transmit the frame !
*
*/
static int via_ircc_hard_xmit_sir ( struct sk_buff * skb ,
struct net_device * dev )
{
struct via_ircc_cb * self ;
unsigned long flags ;
u16 iobase ;
__u32 speed ;
self = ( struct via_ircc_cb * ) dev - > priv ;
IRDA_ASSERT ( self ! = NULL , return 0 ; ) ;
iobase = self - > io . fir_base ;
netif_stop_queue ( dev ) ;
/* Check if we need to change the speed */
speed = irda_get_next_speed ( skb ) ;
if ( ( speed ! = self - > io . speed ) & & ( speed ! = - 1 ) ) {
/* Check for empty frame */
if ( ! skb - > len ) {
via_ircc_change_speed ( self , speed ) ;
dev - > trans_start = jiffies ;
dev_kfree_skb ( skb ) ;
return 0 ;
} else
self - > new_speed = speed ;
}
InitCard ( iobase ) ;
CommonInit ( iobase ) ;
SIRFilter ( iobase , ON ) ;
SetSIR ( iobase , ON ) ;
CRC16 ( iobase , ON ) ;
EnTXCRC ( iobase , 0 ) ;
WriteReg ( iobase , I_ST_CT_0 , 0x00 ) ;
spin_lock_irqsave ( & self - > lock , flags ) ;
self - > tx_buff . data = self - > tx_buff . head ;
self - > tx_buff . len =
async_wrap_skb ( skb , self - > tx_buff . data ,
self - > tx_buff . truesize ) ;
self - > stats . tx_bytes + = self - > tx_buff . len ;
/* Send this frame with old speed */
SetBaudRate ( iobase , self - > io . speed ) ;
SetPulseWidth ( iobase , 12 ) ;
SetSendPreambleCount ( iobase , 0 ) ;
WriteReg ( iobase , I_ST_CT_0 , 0x80 ) ;
EnableTX ( iobase , ON ) ;
EnableRX ( iobase , OFF ) ;
ResetChip ( iobase , 0 ) ;
ResetChip ( iobase , 1 ) ;
ResetChip ( iobase , 2 ) ;
ResetChip ( iobase , 3 ) ;
ResetChip ( iobase , 4 ) ;
EnAllInt ( iobase , ON ) ;
EnTXDMA ( iobase , ON ) ;
EnRXDMA ( iobase , OFF ) ;
irda_setup_dma ( self - > io . dma , self - > tx_buff_dma , self - > tx_buff . len ,
DMA_TX_MODE ) ;
SetSendByte ( iobase , self - > tx_buff . len ) ;
RXStart ( iobase , OFF ) ;
TXStart ( iobase , ON ) ;
dev - > trans_start = jiffies ;
spin_unlock_irqrestore ( & self - > lock , flags ) ;
dev_kfree_skb ( skb ) ;
return 0 ;
}
static int via_ircc_hard_xmit_fir ( struct sk_buff * skb ,
struct net_device * dev )
{
struct via_ircc_cb * self ;
u16 iobase ;
__u32 speed ;
unsigned long flags ;
self = ( struct via_ircc_cb * ) dev - > priv ;
iobase = self - > io . fir_base ;
if ( self - > st_fifo . len )
return 0 ;
if ( self - > chip_id = = 0x3076 )
iodelay ( 1500 ) ;
else
udelay ( 1500 ) ;
netif_stop_queue ( dev ) ;
speed = irda_get_next_speed ( skb ) ;
if ( ( speed ! = self - > io . speed ) & & ( speed ! = - 1 ) ) {
if ( ! skb - > len ) {
via_ircc_change_speed ( self , speed ) ;
dev - > trans_start = jiffies ;
dev_kfree_skb ( skb ) ;
return 0 ;
} else
self - > new_speed = speed ;
}
spin_lock_irqsave ( & self - > lock , flags ) ;
self - > tx_fifo . queue [ self - > tx_fifo . free ] . start = self - > tx_fifo . tail ;
self - > tx_fifo . queue [ self - > tx_fifo . free ] . len = skb - > len ;
self - > tx_fifo . tail + = skb - > len ;
self - > stats . tx_bytes + = skb - > len ;
memcpy ( self - > tx_fifo . queue [ self - > tx_fifo . free ] . start , skb - > data ,
skb - > len ) ;
self - > tx_fifo . len + + ;
self - > tx_fifo . free + + ;
//F01 if (self->tx_fifo.len == 1) {
via_ircc_dma_xmit ( self , iobase ) ;
//F01 }
//F01 if (self->tx_fifo.free < (MAX_TX_WINDOW -1 )) netif_wake_queue(self->netdev);
dev - > trans_start = jiffies ;
dev_kfree_skb ( skb ) ;
spin_unlock_irqrestore ( & self - > lock , flags ) ;
return 0 ;
}
static int via_ircc_dma_xmit ( struct via_ircc_cb * self , u16 iobase )
{
EnTXDMA ( iobase , OFF ) ;
self - > io . direction = IO_XMIT ;
EnPhys ( iobase , ON ) ;
EnableTX ( iobase , ON ) ;
EnableRX ( iobase , OFF ) ;
ResetChip ( iobase , 0 ) ;
ResetChip ( iobase , 1 ) ;
ResetChip ( iobase , 2 ) ;
ResetChip ( iobase , 3 ) ;
ResetChip ( iobase , 4 ) ;
EnAllInt ( iobase , ON ) ;
EnTXDMA ( iobase , ON ) ;
EnRXDMA ( iobase , OFF ) ;
irda_setup_dma ( self - > io . dma ,
( ( u8 * ) self - > tx_fifo . queue [ self - > tx_fifo . ptr ] . start -
self - > tx_buff . head ) + self - > tx_buff_dma ,
self - > tx_fifo . queue [ self - > tx_fifo . ptr ] . len , DMA_TX_MODE ) ;
IRDA_DEBUG ( 1 , " %s: tx_fifo.ptr=%x,len=%x,tx_fifo.len=%x.. \n " ,
__FUNCTION__ , self - > tx_fifo . ptr ,
self - > tx_fifo . queue [ self - > tx_fifo . ptr ] . len ,
self - > tx_fifo . len ) ;
SetSendByte ( iobase , self - > tx_fifo . queue [ self - > tx_fifo . ptr ] . len ) ;
RXStart ( iobase , OFF ) ;
TXStart ( iobase , ON ) ;
return 0 ;
}
/*
* Function via_ircc_dma_xmit_complete ( self )
*
* The transfer of a frame in finished . This function will only be called
* by the interrupt handler
*
*/
static int via_ircc_dma_xmit_complete ( struct via_ircc_cb * self )
{
int iobase ;
int ret = TRUE ;
u8 Tx_status ;
IRDA_DEBUG ( 3 , " %s() \n " , __FUNCTION__ ) ;
iobase = self - > io . fir_base ;
/* Disable DMA */
// DisableDmaChannel(self->io.dma);
/* Check for underrrun! */
/* Clear bit, by writing 1 into it */
Tx_status = GetTXStatus ( iobase ) ;
if ( Tx_status & 0x08 ) {
self - > stats . tx_errors + + ;
self - > stats . tx_fifo_errors + + ;
hwreset ( self ) ;
// how to clear underrrun ?
} else {
self - > stats . tx_packets + + ;
ResetChip ( iobase , 3 ) ;
ResetChip ( iobase , 4 ) ;
}
/* Check if we need to change the speed */
if ( self - > new_speed ) {
via_ircc_change_speed ( self , self - > new_speed ) ;
self - > new_speed = 0 ;
}
/* Finished with this frame, so prepare for next */
if ( IsFIROn ( iobase ) ) {
if ( self - > tx_fifo . len ) {
self - > tx_fifo . len - - ;
self - > tx_fifo . ptr + + ;
}
}
IRDA_DEBUG ( 1 ,
" %s: tx_fifo.len=%x ,tx_fifo.ptr=%x,tx_fifo.free=%x... \n " ,
__FUNCTION__ ,
self - > tx_fifo . len , self - > tx_fifo . ptr , self - > tx_fifo . free ) ;
/* F01_S
// Any frames to be sent back-to-back?
if ( self - > tx_fifo . len ) {
// Not finished yet!
via_ircc_dma_xmit ( self , iobase ) ;
ret = FALSE ;
} else {
F01_E */
// Reset Tx FIFO info
self - > tx_fifo . len = self - > tx_fifo . ptr = self - > tx_fifo . free = 0 ;
self - > tx_fifo . tail = self - > tx_buff . head ;
//F01 }
// Make sure we have room for more frames
//F01 if (self->tx_fifo.free < (MAX_TX_WINDOW -1 )) {
// Not busy transmitting anymore
// Tell the network layer, that we can accept more frames
netif_wake_queue ( self - > netdev ) ;
//F01 }
return ret ;
}
/*
* Function via_ircc_dma_receive ( self )
*
* Set configuration for receive a frame .
*
*/
static int via_ircc_dma_receive ( struct via_ircc_cb * self )
{
int iobase ;
iobase = self - > io . fir_base ;
IRDA_DEBUG ( 3 , " %s() \n " , __FUNCTION__ ) ;
self - > tx_fifo . len = self - > tx_fifo . ptr = self - > tx_fifo . free = 0 ;
self - > tx_fifo . tail = self - > tx_buff . head ;
self - > RxDataReady = 0 ;
self - > io . direction = IO_RECV ;
self - > rx_buff . data = self - > rx_buff . head ;
self - > st_fifo . len = self - > st_fifo . pending_bytes = 0 ;
self - > st_fifo . tail = self - > st_fifo . head = 0 ;
EnPhys ( iobase , ON ) ;
EnableTX ( iobase , OFF ) ;
EnableRX ( iobase , ON ) ;
ResetChip ( iobase , 0 ) ;
ResetChip ( iobase , 1 ) ;
ResetChip ( iobase , 2 ) ;
ResetChip ( iobase , 3 ) ;
ResetChip ( iobase , 4 ) ;
EnAllInt ( iobase , ON ) ;
EnTXDMA ( iobase , OFF ) ;
EnRXDMA ( iobase , ON ) ;
irda_setup_dma ( self - > io . dma2 , self - > rx_buff_dma ,
self - > rx_buff . truesize , DMA_RX_MODE ) ;
TXStart ( iobase , OFF ) ;
RXStart ( iobase , ON ) ;
return 0 ;
}
/*
* Function via_ircc_dma_receive_complete ( self )
*
* Controller Finished with receiving frames ,
* and this routine is call by ISR
*
*/
static int via_ircc_dma_receive_complete ( struct via_ircc_cb * self ,
int iobase )
{
struct st_fifo * st_fifo ;
struct sk_buff * skb ;
int len , i ;
u8 status = 0 ;
iobase = self - > io . fir_base ;
st_fifo = & self - > st_fifo ;
if ( self - > io . speed < 4000000 ) { //Speed below FIR
len = GetRecvByte ( iobase , self ) ;
skb = dev_alloc_skb ( len + 1 ) ;
if ( skb = = NULL )
return FALSE ;
// Make sure IP header gets aligned
skb_reserve ( skb , 1 ) ;
skb_put ( skb , len - 2 ) ;
if ( self - > chip_id = = 0x3076 ) {
for ( i = 0 ; i < len - 2 ; i + + )
skb - > data [ i ] = self - > rx_buff . data [ i * 2 ] ;
} else {
if ( self - > chip_id = = 0x3096 ) {
for ( i = 0 ; i < len - 2 ; i + + )
skb - > data [ i ] =
self - > rx_buff . data [ i ] ;
}
}
// Move to next frame
self - > rx_buff . data + = len ;
self - > stats . rx_bytes + = len ;
self - > stats . rx_packets + + ;
skb - > dev = self - > netdev ;
skb - > mac . raw = skb - > data ;
skb - > protocol = htons ( ETH_P_IRDA ) ;
netif_rx ( skb ) ;
return TRUE ;
}
else { //FIR mode
len = GetRecvByte ( iobase , self ) ;
if ( len = = 0 )
return TRUE ; //interrupt only, data maybe move by RxT
if ( ( ( len - 4 ) < 2 ) | | ( ( len - 4 ) > 2048 ) ) {
IRDA_DEBUG ( 1 , " %s(): Trouble:len=%x,CurCount=%x,LastCount=%x.. \n " ,
__FUNCTION__ , len , RxCurCount ( iobase , self ) ,
self - > RxLastCount ) ;
hwreset ( self ) ;
return FALSE ;
}
IRDA_DEBUG ( 2 , " %s(): fifo.len=%x,len=%x,CurCount=%x.. \n " ,
__FUNCTION__ ,
st_fifo - > len , len - 4 , RxCurCount ( iobase , self ) ) ;
st_fifo - > entries [ st_fifo - > tail ] . status = status ;
st_fifo - > entries [ st_fifo - > tail ] . len = len ;
st_fifo - > pending_bytes + = len ;
st_fifo - > tail + + ;
st_fifo - > len + + ;
if ( st_fifo - > tail > MAX_RX_WINDOW )
st_fifo - > tail = 0 ;
self - > RxDataReady = 0 ;
// It maybe have MAX_RX_WINDOW package receive by
// receive_complete before Timer IRQ
/* F01_S
if ( st_fifo - > len < ( MAX_RX_WINDOW + 2 ) ) {
RXStart ( iobase , ON ) ;
SetTimer ( iobase , 4 ) ;
}
else {
F01_E */
EnableRX ( iobase , OFF ) ;
EnRXDMA ( iobase , OFF ) ;
RXStart ( iobase , OFF ) ;
//F01_S
// Put this entry back in fifo
if ( st_fifo - > head > MAX_RX_WINDOW )
st_fifo - > head = 0 ;
status = st_fifo - > entries [ st_fifo - > head ] . status ;
len = st_fifo - > entries [ st_fifo - > head ] . len ;
st_fifo - > head + + ;
st_fifo - > len - - ;
skb = dev_alloc_skb ( len + 1 - 4 ) ;
/*
* if frame size , data ptr , or skb ptr are wrong , the get next
* entry .
*/
if ( ( skb = = NULL ) | | ( skb - > data = = NULL )
| | ( self - > rx_buff . data = = NULL ) | | ( len < 6 ) ) {
self - > stats . rx_dropped + + ;
return TRUE ;
}
skb_reserve ( skb , 1 ) ;
skb_put ( skb , len - 4 ) ;
memcpy ( skb - > data , self - > rx_buff . data , len - 4 ) ;
IRDA_DEBUG ( 2 , " %s(): len=%x.rx_buff=%p \n " , __FUNCTION__ ,
len - 4 , self - > rx_buff . data ) ;
// Move to next frame
self - > rx_buff . data + = len ;
self - > stats . rx_bytes + = len ;
self - > stats . rx_packets + + ;
skb - > dev = self - > netdev ;
skb - > mac . raw = skb - > data ;
skb - > protocol = htons ( ETH_P_IRDA ) ;
netif_rx ( skb ) ;
//F01_E
} //FIR
return TRUE ;
}
/*
* if frame is received , but no INT , then use this routine to upload frame .
*/
static int upload_rxdata ( struct via_ircc_cb * self , int iobase )
{
struct sk_buff * skb ;
int len ;
struct st_fifo * st_fifo ;
st_fifo = & self - > st_fifo ;
len = GetRecvByte ( iobase , self ) ;
IRDA_DEBUG ( 2 , " %s(): len=%x \n " , __FUNCTION__ , len ) ;
2006-09-26 09:31:03 +04:00
if ( ( len - 4 ) < 2 ) {
self - > stats . rx_dropped + + ;
return FALSE ;
}
2005-04-17 02:20:36 +04:00
skb = dev_alloc_skb ( len + 1 ) ;
2006-09-26 09:31:03 +04:00
if ( skb = = NULL ) {
2005-04-17 02:20:36 +04:00
self - > stats . rx_dropped + + ;
return FALSE ;
}
skb_reserve ( skb , 1 ) ;
skb_put ( skb , len - 4 + 1 ) ;
memcpy ( skb - > data , self - > rx_buff . data , len - 4 + 1 ) ;
st_fifo - > tail + + ;
st_fifo - > len + + ;
if ( st_fifo - > tail > MAX_RX_WINDOW )
st_fifo - > tail = 0 ;
// Move to next frame
self - > rx_buff . data + = len ;
self - > stats . rx_bytes + = len ;
self - > stats . rx_packets + + ;
skb - > dev = self - > netdev ;
skb - > mac . raw = skb - > data ;
skb - > protocol = htons ( ETH_P_IRDA ) ;
netif_rx ( skb ) ;
if ( st_fifo - > len < ( MAX_RX_WINDOW + 2 ) ) {
RXStart ( iobase , ON ) ;
} else {
EnableRX ( iobase , OFF ) ;
EnRXDMA ( iobase , OFF ) ;
RXStart ( iobase , OFF ) ;
}
return TRUE ;
}
/*
* Implement back to back receive , use this routine to upload data .
*/
static int RxTimerHandler ( struct via_ircc_cb * self , int iobase )
{
struct st_fifo * st_fifo ;
struct sk_buff * skb ;
int len ;
u8 status ;
st_fifo = & self - > st_fifo ;
if ( CkRxRecv ( iobase , self ) ) {
// if still receiving ,then return ,don't upload frame
self - > RetryCount = 0 ;
SetTimer ( iobase , 20 ) ;
self - > RxDataReady + + ;
return FALSE ;
} else
self - > RetryCount + + ;
if ( ( self - > RetryCount > = 1 ) | |
( ( st_fifo - > pending_bytes + 2048 ) > self - > rx_buff . truesize )
| | ( st_fifo - > len > = ( MAX_RX_WINDOW ) ) ) {
while ( st_fifo - > len > 0 ) { //upload frame
// Put this entry back in fifo
if ( st_fifo - > head > MAX_RX_WINDOW )
st_fifo - > head = 0 ;
status = st_fifo - > entries [ st_fifo - > head ] . status ;
len = st_fifo - > entries [ st_fifo - > head ] . len ;
st_fifo - > head + + ;
st_fifo - > len - - ;
skb = dev_alloc_skb ( len + 1 - 4 ) ;
/*
* if frame size , data ptr , or skb ptr are wrong ,
* then get next entry .
*/
if ( ( skb = = NULL ) | | ( skb - > data = = NULL )
| | ( self - > rx_buff . data = = NULL ) | | ( len < 6 ) ) {
self - > stats . rx_dropped + + ;
continue ;
}
skb_reserve ( skb , 1 ) ;
skb_put ( skb , len - 4 ) ;
memcpy ( skb - > data , self - > rx_buff . data , len - 4 ) ;
IRDA_DEBUG ( 2 , " %s(): len=%x.head=%x \n " , __FUNCTION__ ,
len - 4 , st_fifo - > head ) ;
// Move to next frame
self - > rx_buff . data + = len ;
self - > stats . rx_bytes + = len ;
self - > stats . rx_packets + + ;
skb - > dev = self - > netdev ;
skb - > mac . raw = skb - > data ;
skb - > protocol = htons ( ETH_P_IRDA ) ;
netif_rx ( skb ) ;
} //while
self - > RetryCount = 0 ;
IRDA_DEBUG ( 2 ,
" %s(): End of upload HostStatus=%x,RxStatus=%x \n " ,
__FUNCTION__ ,
GetHostStatus ( iobase ) , GetRXStatus ( iobase ) ) ;
/*
* if frame is receive complete at this routine , then upload
* frame .
*/
if ( ( GetRXStatus ( iobase ) & 0x10 )
& & ( RxCurCount ( iobase , self ) ! = self - > RxLastCount ) ) {
upload_rxdata ( self , iobase ) ;
if ( irda_device_txqueue_empty ( self - > netdev ) )
via_ircc_dma_receive ( self ) ;
}
} // timer detect complete
else
SetTimer ( iobase , 4 ) ;
return TRUE ;
}
/*
* Function via_ircc_interrupt ( irq , dev_id , regs )
*
* An interrupt from the chip has arrived . Time to do some work
*
*/
static irqreturn_t via_ircc_interrupt ( int irq , void * dev_id ,
struct pt_regs * regs )
{
struct net_device * dev = ( struct net_device * ) dev_id ;
struct via_ircc_cb * self ;
int iobase ;
u8 iHostIntType , iRxIntType , iTxIntType ;
if ( ! dev ) {
IRDA_WARNING ( " %s: irq %d for unknown device. \n " , driver_name ,
irq ) ;
return IRQ_NONE ;
}
self = ( struct via_ircc_cb * ) dev - > priv ;
iobase = self - > io . fir_base ;
spin_lock ( & self - > lock ) ;
iHostIntType = GetHostStatus ( iobase ) ;
IRDA_DEBUG ( 4 , " %s(): iHostIntType %02x: %s %s %s %02x \n " ,
__FUNCTION__ , iHostIntType ,
( iHostIntType & 0x40 ) ? " Timer " : " " ,
( iHostIntType & 0x20 ) ? " Tx " : " " ,
( iHostIntType & 0x10 ) ? " Rx " : " " ,
( iHostIntType & 0x0e ) > > 1 ) ;
if ( ( iHostIntType & 0x40 ) ! = 0 ) { //Timer Event
self - > EventFlag . TimeOut + + ;
ClearTimerInt ( iobase , 1 ) ;
if ( self - > io . direction = = IO_XMIT ) {
via_ircc_dma_xmit ( self , iobase ) ;
}
if ( self - > io . direction = = IO_RECV ) {
/*
* frame ready hold too long , must reset .
*/
if ( self - > RxDataReady > 30 ) {
hwreset ( self ) ;
if ( irda_device_txqueue_empty ( self - > netdev ) ) {
via_ircc_dma_receive ( self ) ;
}
} else { // call this to upload frame.
RxTimerHandler ( self , iobase ) ;
}
} //RECV
} //Timer Event
if ( ( iHostIntType & 0x20 ) ! = 0 ) { //Tx Event
iTxIntType = GetTXStatus ( iobase ) ;
IRDA_DEBUG ( 4 , " %s(): iTxIntType %02x: %s %s %s %s \n " ,
__FUNCTION__ , iTxIntType ,
( iTxIntType & 0x08 ) ? " FIFO underr. " : " " ,
( iTxIntType & 0x04 ) ? " EOM " : " " ,
( iTxIntType & 0x02 ) ? " FIFO ready " : " " ,
( iTxIntType & 0x01 ) ? " Early EOM " : " " ) ;
if ( iTxIntType & 0x4 ) {
self - > EventFlag . EOMessage + + ; // read and will auto clean
if ( via_ircc_dma_xmit_complete ( self ) ) {
if ( irda_device_txqueue_empty
( self - > netdev ) ) {
via_ircc_dma_receive ( self ) ;
}
} else {
self - > EventFlag . Unknown + + ;
}
} //EOP
} //Tx Event
//----------------------------------------
if ( ( iHostIntType & 0x10 ) ! = 0 ) { //Rx Event
/* Check if DMA has finished */
iRxIntType = GetRXStatus ( iobase ) ;
IRDA_DEBUG ( 4 , " %s(): iRxIntType %02x: %s %s %s %s %s %s %s \n " ,
__FUNCTION__ , iRxIntType ,
( iRxIntType & 0x80 ) ? " PHY err. " : " " ,
( iRxIntType & 0x40 ) ? " CRC err " : " " ,
( iRxIntType & 0x20 ) ? " FIFO overr. " : " " ,
( iRxIntType & 0x10 ) ? " EOF " : " " ,
( iRxIntType & 0x08 ) ? " RxData " : " " ,
( iRxIntType & 0x02 ) ? " RxMaxLen " : " " ,
( iRxIntType & 0x01 ) ? " SIR bad " : " " ) ;
if ( ! iRxIntType )
IRDA_DEBUG ( 3 , " %s(): RxIRQ =0 \n " , __FUNCTION__ ) ;
if ( iRxIntType & 0x10 ) {
if ( via_ircc_dma_receive_complete ( self , iobase ) ) {
//F01 if(!(IsFIROn(iobase))) via_ircc_dma_receive(self);
via_ircc_dma_receive ( self ) ;
}
} // No ERR
else { //ERR
IRDA_DEBUG ( 4 , " %s(): RxIRQ ERR:iRxIntType=%x,HostIntType=%x,CurCount=%x,RxLastCount=%x_____ \n " ,
__FUNCTION__ , iRxIntType , iHostIntType ,
RxCurCount ( iobase , self ) ,
self - > RxLastCount ) ;
if ( iRxIntType & 0x20 ) { //FIFO OverRun ERR
ResetChip ( iobase , 0 ) ;
ResetChip ( iobase , 1 ) ;
} else { //PHY,CRC ERR
if ( iRxIntType ! = 0x08 )
hwreset ( self ) ; //F01
}
via_ircc_dma_receive ( self ) ;
} //ERR
} //Rx Event
spin_unlock ( & self - > lock ) ;
return IRQ_RETVAL ( iHostIntType ) ;
}
static void hwreset ( struct via_ircc_cb * self )
{
int iobase ;
iobase = self - > io . fir_base ;
IRDA_DEBUG ( 3 , " %s() \n " , __FUNCTION__ ) ;
ResetChip ( iobase , 5 ) ;
EnableDMA ( iobase , OFF ) ;
EnableTX ( iobase , OFF ) ;
EnableRX ( iobase , OFF ) ;
EnRXDMA ( iobase , OFF ) ;
EnTXDMA ( iobase , OFF ) ;
RXStart ( iobase , OFF ) ;
TXStart ( iobase , OFF ) ;
InitCard ( iobase ) ;
CommonInit ( iobase ) ;
SIRFilter ( iobase , ON ) ;
SetSIR ( iobase , ON ) ;
CRC16 ( iobase , ON ) ;
EnTXCRC ( iobase , 0 ) ;
WriteReg ( iobase , I_ST_CT_0 , 0x00 ) ;
SetBaudRate ( iobase , 9600 ) ;
SetPulseWidth ( iobase , 12 ) ;
SetSendPreambleCount ( iobase , 0 ) ;
WriteReg ( iobase , I_ST_CT_0 , 0x80 ) ;
/* Restore speed. */
via_ircc_change_speed ( self , self - > io . speed ) ;
self - > st_fifo . len = 0 ;
}
/*
* Function via_ircc_is_receiving ( self )
*
* Return TRUE is we are currently receiving a frame
*
*/
static int via_ircc_is_receiving ( struct via_ircc_cb * self )
{
int status = FALSE ;
int iobase ;
IRDA_ASSERT ( self ! = NULL , return FALSE ; ) ;
iobase = self - > io . fir_base ;
if ( CkRxRecv ( iobase , self ) )
status = TRUE ;
IRDA_DEBUG ( 2 , " %s(): status=%x.... \n " , __FUNCTION__ , status ) ;
return status ;
}
/*
* Function via_ircc_net_open ( dev )
*
* Start the device
*
*/
static int via_ircc_net_open ( struct net_device * dev )
{
struct via_ircc_cb * self ;
int iobase ;
char hwname [ 32 ] ;
IRDA_DEBUG ( 3 , " %s() \n " , __FUNCTION__ ) ;
IRDA_ASSERT ( dev ! = NULL , return - 1 ; ) ;
self = ( struct via_ircc_cb * ) dev - > priv ;
self - > stats . rx_packets = 0 ;
IRDA_ASSERT ( self ! = NULL , return 0 ; ) ;
iobase = self - > io . fir_base ;
if ( request_irq ( self - > io . irq , via_ircc_interrupt , 0 , dev - > name , dev ) ) {
IRDA_WARNING ( " %s, unable to allocate irq=%d \n " , driver_name ,
self - > io . irq ) ;
return - EAGAIN ;
}
/*
* Always allocate the DMA channel after the IRQ , and clean up on
* failure .
*/
if ( request_dma ( self - > io . dma , dev - > name ) ) {
IRDA_WARNING ( " %s, unable to allocate dma=%d \n " , driver_name ,
self - > io . dma ) ;
free_irq ( self - > io . irq , self ) ;
return - EAGAIN ;
}
if ( self - > io . dma2 ! = self - > io . dma ) {
if ( request_dma ( self - > io . dma2 , dev - > name ) ) {
IRDA_WARNING ( " %s, unable to allocate dma2=%d \n " ,
driver_name , self - > io . dma2 ) ;
free_irq ( self - > io . irq , self ) ;
return - EAGAIN ;
}
}
/* turn on interrupts */
EnAllInt ( iobase , ON ) ;
EnInternalLoop ( iobase , OFF ) ;
EnExternalLoop ( iobase , OFF ) ;
/* */
via_ircc_dma_receive ( self ) ;
/* Ready to play! */
netif_start_queue ( dev ) ;
/*
* Open new IrLAP layer instance , now that everything should be
* initialized properly
*/
sprintf ( hwname , " VIA @ 0x%x " , iobase ) ;
self - > irlap = irlap_open ( dev , & self - > qos , hwname ) ;
self - > RxLastCount = 0 ;
return 0 ;
}
/*
* Function via_ircc_net_close ( dev )
*
* Stop the device
*
*/
static int via_ircc_net_close ( struct net_device * dev )
{
struct via_ircc_cb * self ;
int iobase ;
IRDA_DEBUG ( 3 , " %s() \n " , __FUNCTION__ ) ;
IRDA_ASSERT ( dev ! = NULL , return - 1 ; ) ;
self = ( struct via_ircc_cb * ) dev - > priv ;
IRDA_ASSERT ( self ! = NULL , return 0 ; ) ;
/* Stop device */
netif_stop_queue ( dev ) ;
/* Stop and remove instance of IrLAP */
if ( self - > irlap )
irlap_close ( self - > irlap ) ;
self - > irlap = NULL ;
iobase = self - > io . fir_base ;
EnTXDMA ( iobase , OFF ) ;
EnRXDMA ( iobase , OFF ) ;
DisableDmaChannel ( self - > io . dma ) ;
/* Disable interrupts */
EnAllInt ( iobase , OFF ) ;
free_irq ( self - > io . irq , dev ) ;
free_dma ( self - > io . dma ) ;
return 0 ;
}
/*
* Function via_ircc_net_ioctl ( dev , rq , cmd )
*
* Process IOCTL commands for this device
*
*/
static int via_ircc_net_ioctl ( struct net_device * dev , struct ifreq * rq ,
int cmd )
{
struct if_irda_req * irq = ( struct if_irda_req * ) rq ;
struct via_ircc_cb * self ;
unsigned long flags ;
int ret = 0 ;
IRDA_ASSERT ( dev ! = NULL , return - 1 ; ) ;
self = dev - > priv ;
IRDA_ASSERT ( self ! = NULL , return - 1 ; ) ;
IRDA_DEBUG ( 1 , " %s(), %s, (cmd=0x%X) \n " , __FUNCTION__ , dev - > name ,
cmd ) ;
/* Disable interrupts & save flags */
spin_lock_irqsave ( & self - > lock , flags ) ;
switch ( cmd ) {
case SIOCSBANDWIDTH : /* Set bandwidth */
if ( ! capable ( CAP_NET_ADMIN ) ) {
ret = - EPERM ;
goto out ;
}
via_ircc_change_speed ( self , irq - > ifr_baudrate ) ;
break ;
case SIOCSMEDIABUSY : /* Set media busy */
if ( ! capable ( CAP_NET_ADMIN ) ) {
ret = - EPERM ;
goto out ;
}
irda_device_set_media_busy ( self - > netdev , TRUE ) ;
break ;
case SIOCGRECEIVING : /* Check if we are receiving right now */
irq - > ifr_receiving = via_ircc_is_receiving ( self ) ;
break ;
default :
ret = - EOPNOTSUPP ;
}
out :
spin_unlock_irqrestore ( & self - > lock , flags ) ;
return ret ;
}
static struct net_device_stats * via_ircc_net_get_stats ( struct net_device
* dev )
{
struct via_ircc_cb * self = ( struct via_ircc_cb * ) dev - > priv ;
return & self - > stats ;
}
MODULE_AUTHOR ( " VIA Technologies,inc " ) ;
MODULE_DESCRIPTION ( " VIA IrDA Device Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
module_init ( via_ircc_init ) ;
module_exit ( via_ircc_cleanup ) ;