From: Ben Greear <greearb@candelatech.com>
To: NetDev <netdev@vger.kernel.org>, petkan@users.sourceforge.net
Subject: rtl8150 usb driver, needs more vendor ids?
Date: Mon, 19 Jun 2006 23:46:18 -0700 [thread overview]
Message-ID: <449799BA.1050303@candelatech.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 1264 bytes --]
Someone put a wired usb-to-ethernet adapter into a system running
the 2.6.13.5 kernel. The driver is evidently the rtl8150, and this
person sent me what appeared to be a modified version of the rtl8150
that is in the kernel. The kernel driver does not appear to even attempt
to use this device.
Here is the output from /proc/bus/usb/devices:
T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 4 Spd=12 MxCh= 0
D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=07a6 ProdID=8511 Rev= 1.01
S: Manufacturer=ADMtek
S: Product=USB To LAN Converter
S: SerialNumber=0001
C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr=160mA
I: If#= 0 Alt= 0 #EPs= 3 Cls=00(>ifc ) Sub=00 Prot=00 Driver=(none)
E: Ad=81(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
E: Ad=83(I) Atr=03(Int.) MxPS= 8 Ivl=1ms
The vendor driver (GPL) I received is available here:
http://www.candelatech.com/oss/RTL8150.C
When I get a chance later this week, I plan to add this vendor id
and see if it works. Since the physical equipment is half a world
away, I'd welcome any conjecture as to whether simply adding the
device ID will work or not...
Thanks,
Ben
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
[-- Attachment #2: RTL8150.C --]
[-- Type: text/x-c++src, Size: 35649 bytes --]
/*
** Pegasus: USB 10/100Mbps/HomePNA (1Mbps) Controller
**
** Copyright (c) 1999,2000 Petko Manolov - Petkan (petkan@dce.bg)
**
**
** ChangeLog:
** .... Most of the time spend reading sources & docs.
** v0.2.x First official release for the Linux kernel.
** v0.3.0 Beutified and structured, some bugs fixed.
** v0.3.x URBifying bulk requests and bugfixing. First relatively
** stable release. Still can touch device's registers only
** from top-halves.
** v0.4.0 Control messages remained unurbified are now URBs.
** Now we can touch the HW at any time.
** v0.4.9 Control urbs again use process context to wait. Argh...
** Some long standing bugs (enable_net_traffic) fixed.
** Also nasty trick about resubmiting control urb from
** interrupt context used. Please let me know how it
** behaves. Pegasus II support added since this version.
** TODO: suppressing HCD warnings spewage on disconnect.
** v0.4.13 Ethernet address is now set at probe(), not at open()
** time as this seems to break dhcpd.
*/
/*
* 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 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
**
** ChangeLog of Realtek:
** 1.0.0 First release for RTL8150 USB Fast Ethernet NIC
**
*/
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/malloc.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/usb.h>
static const char *version = __FILE__ ": v1.0.0 2001/01/31 (C) 2001 Realtek Semiconductor Corp.(shwei@realtek.com.tw)";
/// define this to use interrupt endpoint 3
#define RTL8150_USE_INTR
#define RTL8150_MTU 1500
#define RTL8150_MAX_MTU 1536
#define RTL8150_MIN_PACKET_LENGTH 60
/// phy registers index
#define MII_PHY_ID1 0x02
#define MII_PHY_ID2 0x03
/// manufacture ID of HPNA PHY
#define AMD_PHY_ID 0x6b90
#define NS_PHY_ID 0x5c20
/// rtl8150->features
#define FEATURE_DEFAULT 0x00
#define FEATURE_HAS_HOME_PNA 0x01
/// rtl8150 states
#define RTL8150_PRESENT 0x00000001
#define RTL8150_RUNNING 0x00000002
#define RTL8150_TX_BUSY 0x00000004
#define RTL8150_RX_BUSY 0x00000008
#define RTL8150_UNPLUG 0x00000040
/// ctrl urb
#define CTRL_URB_RUNNING 0x00000010
#define CTRL_URB_SLEEP 0x00000020
//#define ETH_REGS_CHANGE 0x40000000
#define ETH_REGS_CHANGED 0x80000000
#define REG_TIMEOUT (HZ)
#define RTL8150_TX_TIMEOUT (HZ*10)
/// vendor memory read & write
#define RTL8150_REQT_READ 0xc0
#define RTL8150_REQT_WRITE 0x40
#define RTL8150_REQ_GET_REG 0x05
#define RTL8150_REQ_SET_REG 0x05
#define NUM_CTRL_URBS 0x10
#define ALIGN(x) x __attribute__((aligned(L1_CACHE_BYTES)))
#define SIZE32_BIT0 0x00000001
#define SIZE32_BIT1 0x00000002
#define SIZE32_BIT2 0x00000004
#define SIZE32_BIT3 0x00000008
#define SIZE32_BIT4 0x00000010
#define SIZE32_BIT5 0x00000020
#define SIZE32_BIT6 0x00000040
#define SIZE32_BIT7 0x00000080
#define SIZE32_BIT8 0x00000100
#define SIZE32_BIT9 0x00000200
#define SIZE32_BIT10 0x00000400
#define SIZE32_BIT11 0x00000800
#define SIZE32_BIT12 0x00001000
#define SIZE32_BIT13 0x00002000
#define SIZE32_BIT14 0x00004000
#define SIZE32_BIT15 0x00008000
#define SIZE32_BIT16 0x00010000
#define SIZE32_BIT17 0x00020000
#define SIZE32_BIT18 0x00040000
#define SIZE32_BIT19 0x00080000
#define SIZE32_BIT20 0x00100000
#define SIZE32_BIT21 0x00200000
#define SIZE32_BIT22 0x00400000
#define SIZE32_BIT23 0x00800000
#define SIZE32_BIT24 0x01000000
#define SIZE32_BIT25 0x02000000
#define SIZE32_BIT26 0x04000000
#define SIZE32_BIT27 0x08000000
#define SIZE32_BIT28 0x10000000
#define SIZE32_BIT29 0x20000000
#define SIZE32_BIT30 0x40000000
#define SIZE32_BIT31 0x80000000
#define SIZE16_BIT0 0x0001
#define SIZE16_BIT1 0x0002
#define SIZE16_BIT2 0x0004
#define SIZE16_BIT3 0x0008
#define SIZE16_BIT4 0x0010
#define SIZE16_BIT5 0x0020
#define SIZE16_BIT6 0x0040
#define SIZE16_BIT7 0x0080
#define SIZE16_BIT8 0x0100
#define SIZE16_BIT9 0x0200
#define SIZE16_BIT10 0x0400
#define SIZE16_BIT11 0x0800
#define SIZE16_BIT12 0x1000
#define SIZE16_BIT13 0x2000
#define SIZE16_BIT14 0x4000
#define SIZE16_BIT15 0x8000
#define SIZE8_BIT0 0x01
#define SIZE8_BIT1 0x02
#define SIZE8_BIT2 0x04
#define SIZE8_BIT3 0x08
#define SIZE8_BIT4 0x10
#define SIZE8_BIT5 0x20
#define SIZE8_BIT6 0x40
#define SIZE8_BIT7 0x80
/// registers index
#define IDR0 0x0120
#define Command 0x012e
#define TxConfig 0x012f
#define RxConfig 0x0130
#define TxStst 0x0132
#define RxStst 0x0133
#define Config 0x0135
#define Config1 0x0136
#define MediaStst 0x0137
#define MiiPhyAddr 0x0138
#define MiiPhyData 0x0139
#define MiiPhyAccess 0x013b
#define GPPCtrl 0x013d
#define WakeUpEventCtrl 0x013e
#define BasicModeCtrl 0x0140
#define BasicModeStst 0x0142
#define AutoNegoAdver 0x0144
#define AutoNegoLinkPartner 0x0146
#define AutoNegoExpan 0x0148
#define NwayTst 0x014a
#define CSConfig 0x014c
/// which HPNA PHY
enum hpna_phy {
UNKNOWN_PHY = 0,
AMD_PHY = 1,
NS_PHY = 2,
};
/// loopback mode
enum loopback_mode{
NORMAL_OPERATION = 0,
DIGITAL_LOOPBACK = 1,
ANALOG_LOOPBACK = 2,
};
/// EEPROM index
#define EPROM_IDR0 0x1202
#define EPROM_Config0 0x1208
#define EPROM_MSR 0x1209
#define EPROM_GPCP 0x120a
#define EPROM_UDP 0x120b
#define EPROM_ATTR 0x120c
#define EPROM_PHY2_PARM 0x120d
#define EPROM_PHY1_PARM 0x120e
#define EPROM_TW1_PARM 0x1212
#define EPROM_MAXPOR 0x1216
#define EPROM_Interv 0x1217
#define EPROM_LanguageID 0x1218
#define EPROM_ManufactureID 0x121a
#define EPROM_ProductID 0x121c
#define EPROM_SerialNumber 0x121e
#define EPROM_ManufactureString 0x1228
#define EPROM_ProductString 0x1250
/// Command Register
#define WEPROM SIZE8_BIT5
#define SOFT_RST SIZE8_BIT4
#define RE SIZE8_BIT3
#define TE SIZE8_BIT2
#define EP3CLEAR SIZE8_BIT1
#define AUTOLOAD SIZE8_BIT0
/// Transmit Configuration Register
#define TXRR1 SIZE8_BIT7
#define TXRR0 SIZE8_BIT6
#define IFG1 SIZE8_BIT4
#define IFG0 SIZE8_BIT3
#define LBK1 SIZE8_BIT2
#define LBK0 SIZE8_BIT1
#define NOCRC SIZE8_BIT0
/// Receive Configuration Register
#define EARRX SIZE16_BIT10
#define TAIL SIZE16_BIT7
#define AER SIZE16_BIT6
#define AR SIZE16_BIT5
#define AM SIZE16_BIT4
#define AB SIZE16_BIT3
#define AD SIZE16_BIT2
#define AAM SIZE16_BIT1
#define AAP SIZE16_BIT0
/// Transmit Status Register
#define ECOL SIZE8_BIT5
#define LCOL SIZE8_BIT4
#define LOSS_CRS SIZE8_BIT3
#define JBR SIZE8_BIT2
#define TX_BUF_EMPTY SIZE8_BIT1
#define TX_BUF_FULL SIZE8_BIT0
/// Receive Status Register
#define WEVENT SIZE8_BIT7
#define RX_BUF_FULL SIZE8_BIT6
#define LKCHG SIZE8_BIT5
#define RUNT SIZE8_BIT4
#define LONG SIZE8_BIT3
#define CRC SIZE8_BIT2
#define FAE SIZE8_BIT1
#define ROK SIZE8_BIT0
/// Configuration Register0
#define SUSLED SIZE8_BIT7
#define PARM_EN SIZE8_BIT6
#define LDPS SIZE8_BIT3
#define MSEL SIZE8_BIT2
#define LEDS1 SIZE8_BIT1
#define LEDS0 SIZE8_BIT0
/// Configuration Register1
#define BWF SIZE8_BIT6
#define MWF SIZE8_BIT5
#define UWF SIZE8_BIT4
#define LONGWF1 SIZE8_BIT1
#define LONGWF0 SIZE8_BIT0
/// Media Status Register
#define TXFCE SIZE8_BIT7
#define RXFCE SIZE8_BIT6
#define DUPLEX SIZE8_BIT4
#define SPEED_100 SIZE8_BIT3
#define LINK SIZE8_BIT2
#define TXPF SIZE8_BIT1
#define RXPF SIZE8_BIT0
typedef struct rtl8150 {
struct usb_device *usb; // store "dev" passed in rtl8150_probe( struct usb_device *dev...)
struct net_device *net; // store "net" returned by init_etherdev()
struct net_device_stats stats;
unsigned flags;
unsigned features;
int intr_interval;
struct urb ctrl_urb, rx_urb, tx_urb, intr_urb;
devrequest dr;
wait_queue_head_t ctrl_wait;
struct semaphore ctrl_sem;
unsigned char ALIGN(rx_buff[RTL8150_MAX_MTU]);
unsigned char ALIGN(tx_buff[RTL8150_MAX_MTU]);
unsigned char ALIGN(intr_buff[8]);
__u8 eth_regs[4];
__u8 phy;
__u8 hpna_phy;
__u8 gpio_res;
/// added by Owen on 01/11/2000
__u8 get_registers_flag;
__u8 set_registers_flag;
} rtl8150_t;
struct usb_eth_dev {
char *name;
__u16 vendor;
__u16 device;
__u32 private; /* LSB is gpio reset value */
};
static int loopback = 0;
static int mii_mode = 0;
static int multicast_filter_limit = 32;
MODULE_AUTHOR("shwei@realtek.com.tw");
MODULE_DESCRIPTION("Realtek RTL8150 USB 10/100 Fast Ethernet Driver");
MODULE_PARM(loopback, "i");
MODULE_PARM(mii_mode, "i");
MODULE_PARM_DESC(loopback, "Enable MAC loopback mode (bit 0)");
MODULE_PARM_DESC(mii_mode, "Enable HomePNA mode (bit 0) - default = MII mode = 0");
static struct usb_eth_dev usb_dev_id[] = {
{"Realtek RTL8150 USB 10/100 Fast Ethernet Adatper", 0x0bda, 0x8150, FEATURE_DEFAULT},
{"Realtek RTL8150 USB 1Mbps HomePNA", 0x0bda, 0x8151, FEATURE_HAS_HOME_PNA | FEATURE_DEFAULT},
{NULL, 0, 0, 0}
};
static void set_registers_callback( urb_t *urb )
{
rtl8150_t *rtl8150 = urb->context;
//info( "+set_registers_callback()");
if ( !rtl8150 )
return;
switch ( urb->status ) {
case USB_ST_NOERROR:
break;
case USB_ST_URB_PENDING:
//info( " set_registers_callback: case USB_ST_URB_PENDING" );
return;
case USB_ST_URB_KILLED:
break;
default:
//info( " set_registers_callback: default: status = 0x%x", urb->status );
warn( __FUNCTION__ " status %d", urb->status);
}
rtl8150->flags &= ~ETH_REGS_CHANGED;
if ( rtl8150->flags & CTRL_URB_SLEEP )
{
rtl8150->flags &= ~CTRL_URB_SLEEP;
/// marked and added by Owen on 01/11/2001
///wake_up_interruptible( &rtl8150->ctrl_wait );
rtl8150->set_registers_flag = 0;
}
//info("-set_registers_callback()");
}
static void get_registers_callback( urb_t *urb )
{
rtl8150_t *rtl8150 = urb->context;
///info( "+get_registers_callback()");
if ( !rtl8150 )
return;
switch ( urb->status ) {
case USB_ST_NOERROR:
break;
case USB_ST_URB_PENDING:
//info( " get_registers_callback: case USB_ST_URB_PENDING" );
return;
case USB_ST_URB_KILLED:
break;
default:
//info( " get_registers_callback: default: status = 0x%x", urb->status );
warn( __FUNCTION__ " status %d", urb->status);
}
rtl8150->flags &= ~ETH_REGS_CHANGED;
if ( rtl8150->flags & CTRL_URB_SLEEP )
{
rtl8150->flags &= ~CTRL_URB_SLEEP;
/// marked and added by Owen on 01/11/2001
///wake_up_interruptible( &rtl8150->ctrl_wait );
rtl8150->get_registers_flag = 0;
}
///info("-get_registers_callback()");
}
static int get_registers(rtl8150_t *rtl8150, __u16 indx, __u16 size, void *data)
{
int ret;
///info( "+get_registers()=====>" );
rtl8150->dr.requesttype = RTL8150_REQT_READ;
rtl8150->dr.request = RTL8150_REQ_GET_REG;
rtl8150->dr.value = cpu_to_le16p(&indx);
rtl8150->dr.index = 0;
rtl8150->dr.length =
rtl8150->ctrl_urb.transfer_buffer_length = cpu_to_le16p(&size);
FILL_CONTROL_URB( &rtl8150->ctrl_urb, rtl8150->usb,
usb_rcvctrlpipe(rtl8150->usb,0),
(char *)&rtl8150->dr,
data, size, get_registers_callback, rtl8150 );
if ( (ret = usb_submit_urb( &rtl8150->ctrl_urb )) ) {
info( " get_registers: usb_submit_urb failed" );
err( __FUNCTION__ " BAD CTRLs %d", ret);
goto out;
}
rtl8150->flags |= CTRL_URB_SLEEP;
/// marked by Owen on 01/11/2001
//interruptible_sleep_on( &rtl8150->ctrl_wait );
out:
///info( "-get_registers()<=====" );
return ret;
}
static int set_registers(rtl8150_t *rtl8150, __u16 indx, __u16 size, void *data)
{
int ret;
///info( "+set_registers() =====>" );
/// marked by Owen on 01/11/2001
//if ( rtl8150->flags & ETH_REGS_CHANGED ) {
// rtl8150->flags |= CTRL_URB_SLEEP ;
// interruptible_sleep_on( &rtl8150->ctrl_wait );
//}
rtl8150->dr.requesttype = RTL8150_REQT_WRITE;
rtl8150->dr.request = RTL8150_REQ_SET_REG;
rtl8150->dr.value = cpu_to_le16p( &indx );
rtl8150->dr.index = 0;
rtl8150->dr.length = rtl8150->ctrl_urb.transfer_buffer_length = cpu_to_le16p( &size );
FILL_CONTROL_URB( &rtl8150->ctrl_urb, rtl8150->usb,
usb_sndctrlpipe(rtl8150->usb,0),
(char *)&rtl8150->dr,
data, size, set_registers_callback, rtl8150 );
if ( (ret = usb_submit_urb( &rtl8150->ctrl_urb )) ) {
info( " set_registers: usb_submit_urb failed" );
err( __FUNCTION__ " BAD CTRL %d", ret);
return ret;
}
rtl8150->flags |= CTRL_URB_SLEEP;
/// marked by Owen on 01/11/2001
//interruptible_sleep_on( &rtl8150->ctrl_wait );
///info( "-set_registers()<=====" );
return ret;
}
static int read_phy_word( rtl8150_t *rtl8150, __u8 phy, __u8 indx, __u16 *regd )
{
int i;
__u8 MiiPhyAccessContent;
/*
set_register( rtl8150, MiiPhyAccess, 0 );
set_register( rtl8150, MiiPhyAddr, phy );
set_register( rtl8150, MiiPhyAccess, (0x40 | indx) );
for (i = 0; i < REG_TIMEOUT; i++)
{
get_registers( rtl8150, MiiPhyAccess, 1, &MiiPhyAccessContent );
if ( (MiiPhyAccessContent & 0x40) == 0)
break;
}
if ( i < REG_TIMEOUT )
{
get_registers( rtl8150, MiiPhyData, 2, regd );
return 0;
}
warn( __FUNCTION__ " failed" );
*/
return 1;
}
static int write_phy_word( rtl8150_t *rtl8150, __u8 phy, __u8 indx, __u16 regd )
{
int i;
__u8 data[2] = { 0, 0 };
__u8 MiiPhyAccessContent;
//info( "write_phy_word() =====>" );
/*
*data = cpu_to_le16p( ®d );
set_register( rtl8150, MiiPhyAccess, 0 );
set_register( rtl8150, MiiPhyAddr, phy );
set_registers( rtl8150, MiiPhyData, 2, data );
set_register( rtl8150, MiiPhyAccess, (0x60 | indx) );
for (i = 0; i < REG_TIMEOUT; i++)
{
get_registers( rtl8150, MiiPhyAccess, 1, &MiiPhyAccessContent );
if ( (MiiPhyAccessContent & 0x40) == 0)
break;
}
if ( i < REG_TIMEOUT )
return 0;
warn( __FUNCTION__ " failed" );
*/
return 1;
}
static int read_eprom_word( rtl8150_t *rtl8150, __u8 index, __u16 *retdata )
{
int i, tmp;
//info( "+read_eprom_word() =====>" );
while( rtl8150->get_registers_flag == 1 )
;
rtl8150->get_registers_flag = 1;
get_registers( rtl8150, index, 2, retdata );
while( rtl8150->get_registers_flag == 1 )
;
//info( "-read_eprom_word() <=====" );
return 0;
}
static int read_eprom_byte( rtl8150_t *rtl8150, __u16 index, __u8 *retdata )
{
int i, tmp;
//info( "+read_eprom_byte() =====>" );
while( rtl8150->get_registers_flag == 1 )
;
rtl8150->get_registers_flag = 1;
get_registers( rtl8150, index, 1, retdata );
while( rtl8150->get_registers_flag == 1 )
;
//info( "-read_eprom_byte() <=====");
return 0;
}
#ifdef RTL8150_WRITE_EEPROM
static inline void enable_eprom_write( rtl8150_t *rtl8150 )
{
__u8 tmp;
//info( "+enable_eprom_write() =====>" );
//info( "-enable_eprom_write() <=====" );
}
static inline void disable_eprom_write( rtl8150_t *rtl8150 )
{
__u8 tmp;
//info( "+disable_eprom_write() =====>" );
//info( "-disable_eprom_write() <=====" );
}
static int write_eprom_word( rtl8150_t *rtl8150, __u8 index, __u16 data )
{
int i, tmp;
__u8 d[4] = {0x3f, 0, 0, EPROM_WRITE};
//info( "+write_eprom_word() =====>" );
/*
set_registers( rtl8150, EpromOffset, 4, d );
enable_eprom_write( rtl8150 );
set_register( rtl8150, EpromOffset, index );
set_registers( rtl8150, EpromData, 2, &data );
set_register( rtl8150, EpromCtrl, EPROM_WRITE );
for ( i=0; i < REG_TIMEOUT; i++ ) {
get_registers( rtl8150, EpromCtrl, 1, &tmp );
if ( tmp & EPROM_DONE )
break;
}
disable_eprom_write( rtl8150 );
if ( i < REG_TIMEOUT )
return 0;
warn( __FUNCTION__ " failed" );
*/
//info( "-write_eprom_word <=====");
return -1;
}
#endif /* RTL8150_WRITE_EEPROM */
static inline void get_node_id( rtl8150_t *rtl8150, __u8 *id )
{
int i;
info( "+get_node_id() =====>" );
for (i=0; i < 6; i++)
{
while( rtl8150->get_registers_flag == 1 )
;
rtl8150->get_registers_flag = 1;
get_registers( rtl8150, IDR0+i, 1, &id[i] );
while( rtl8150->get_registers_flag == 1 )
;
}
info( "-get_node_id() <=====" );
}
static void set_ethernet_addr( rtl8150_t *rtl8150 )
{
__u8 node_id[6];
info( "+set_ethernet_addr() =====>" );
get_node_id(rtl8150, node_id);
memcpy( rtl8150->net->dev_addr, node_id, sizeof(node_id) );
info( " set_ethernet_addr: node id = %x %x %x %x %x %x",
node_id[0], node_id[1], node_id[2], node_id[3], node_id[4], node_id[5] );
info( "-set_ethernet_addr() <======" );
}
static inline int reset_mac( rtl8150_t *rtl8150 )
{
__u8 data = 0;
int i;
info( "+reset_mac() =====>" );
/// software reset
data = SOFT_RST;
///info( " reset_mac: before set_register(rtl8150, Command, data)" );
while( rtl8150->set_registers_flag == 1 )
;
rtl8150->set_registers_flag = 1;
set_registers(rtl8150, Command, 1, &data);
while( rtl8150->set_registers_flag == 1 )
;
///info( " reset_mac: after set_register( rtl8150, Command, data)" );
for (i = 0; i < REG_TIMEOUT; i++)
{
while( rtl8150->get_registers_flag == 1 )
;
rtl8150->get_registers_flag = 1;
get_registers(rtl8150, Command, 1, &data);
while( rtl8150->get_registers_flag == 1 )
;
if ( ~(data & SOFT_RST) )
{
break;
}
}
if ( i == REG_TIMEOUT )
{
info( " reset_mac: software reset failed" );
return 1;
}
info( "-reset_mac() <=====" );
return 0;
}
static int enable_net_traffic( struct net_device *dev, struct usb_device *usb )
{
__u16 linkpart, bmsr;
__u8 data[4];
__u8 byte_tmp = 0;
rtl8150_t *rtl8150 = dev->priv;
__u16 rx_config_content;
info("+enable_net_traffic() =====>");
/// check if link okay!
while( rtl8150->get_registers_flag == 1 )
;
rtl8150->get_registers_flag = 1;
get_registers( rtl8150, MediaStst, 1, &byte_tmp );
while( rtl8150->get_registers_flag == 1 )
;
info(" enable_net_traffic: MediaStst = 0x%x", byte_tmp);
if ( byte_tmp & LINK )
info(" enable_net_traffic: LINK ON");
else
info(" enable_net_traffic: LINK OFF");
/// software reset
/// byte_tmp = SOFT_RST;
///set_register( rtl8150, Command, 1, &byte_tmp );
/// set Transmit Configuration Register
///info(" enable_net_traffic: before setting Tx Config");
while( rtl8150->set_registers_flag == 1 )
;
rtl8150->set_registers_flag = 1;
byte_tmp = TXRR1 | TXRR0 | IFG1 | IFG0;
set_registers( rtl8150, TxConfig, 1, &byte_tmp);
while( rtl8150->set_registers_flag == 1)
;
///while( rtl8150->get_registers_flag == 1 )
/// ;
///rtl8150->get_registers_flag = 1;
///get_registers( rtl8150, TxConfig, 1, &byte_tmp );
///while( rtl8150->get_registers_flag == 1 )
/// ;
///info( "enable_net_traffic: TxConfig = 0x%x", byte_tmp );
///info(" enable_net_traffic: after setting Tx Config");
/// set Receive Configuration Register
///info(" enable_net_traffic: before setting Rx Config");
while( rtl8150->set_registers_flag == 1 )
;
rtl8150->set_registers_flag = 1;
rx_config_content = AM | AB | AD | AAM;
set_registers( rtl8150, RxConfig, 2, &rx_config_content );
while( rtl8150->set_registers_flag == 1 )
;
///info(" enable_net_traffic: after setting Rx Config");
/// enable Tx and Rx
///info(" enable_net_traffic: before enabling Tx and Rx" );
while( rtl8150->set_registers_flag == 1 )
;
rtl8150->set_registers_flag = 1;
byte_tmp = RE | TE;
set_registers( rtl8150, Command, 1, &byte_tmp );
while( rtl8150->set_registers_flag == 1 )
;
///info(" enable_net_traffic: after enabling Tx and Rx" );
///while( rtl8150->get_registers_flag == 1 )
/// ;
///rtl8150->get_registers_flag = 1;
///get_register( rtl8150, Command, &byte_tmp);
///while( rtl8150->get_registers_flag == 1 )
/// ;
///info(" enable_net_traffic: Command = 0x%x", byte_tmp );
info( "-enable_net_traffic() <=====");
return 0;
}
static void read_bulk_callback( struct urb *urb )
{
rtl8150_t *rtl8150 = urb->context;
struct net_device *net;
int count = urb->actual_length, res;
int rx_status;
struct sk_buff *skb;
__u16 pkt_len;
//info( "+read_bulk_callback() =====>" );
if ( !rtl8150 || !(rtl8150->flags & RTL8150_RUNNING) )
return;
net = rtl8150->net;
if ( !netif_device_present(net) )
return;
if ( rtl8150->flags & RTL8150_RX_BUSY )
{
rtl8150->stats.rx_errors++;
return;
}
rtl8150->flags |= RTL8150_RX_BUSY;
switch ( urb->status ) {
case USB_ST_NOERROR:
break;
case USB_ST_NORESPONSE:
info( " read_bulk_callback: NO RESPONSE" );
dbg( "reset MAC" );
rtl8150->flags &= ~RTL8150_RX_BUSY;
break;
default:
info( " read_bulk_callback: Rx status = 0x%x", urb->status);
dbg( "%s: RX status %d", net->name, urb->status );
goto goon;
}
pkt_len = count - 4;
//info(" read_bulk_callback: packet length = 0x%x", pkt_len );
//info(" read_bulk_callback: packet = %x %x %x %x %x %x %x %x %x %x %x %x", rtl8150->rx_buff[0], rtl8150->rx_buff[1],
// rtl8150->rx_buff[2], rtl8150->rx_buff[3], rtl8150->rx_buff[4], rtl8150->rx_buff[5],
// rtl8150->rx_buff[6], rtl8150->rx_buff[7], rtl8150->rx_buff[8], rtl8150->rx_buff[9],
// rtl8150->rx_buff[10], rtl8150->rx_buff[11] );
if ( !(skb = dev_alloc_skb(pkt_len+2)) ) /// why "pkt_len + 2"
goto goon;
skb->dev = net;
skb_reserve(skb, 2);
eth_copy_and_sum(skb, rtl8150->rx_buff, pkt_len, 0);
skb_put(skb, pkt_len);
/// in "Linux Device Drivers", the two statements above should be
/// "memcpy( skb_put( skb, pkt_len), rtl8150->rx_buff, pkt_len );"
skb->protocol = eth_type_trans(skb, net);
netif_rx(skb); /// call this system call to transfer the "skb" to the upper layer
rtl8150->stats.rx_packets++;
rtl8150->stats.rx_bytes += pkt_len;
goon:
FILL_BULK_URB( &rtl8150->rx_urb, rtl8150->usb,
usb_rcvbulkpipe(rtl8150->usb, 1),
rtl8150->rx_buff, RTL8150_MAX_MTU,
read_bulk_callback, rtl8150 );
if ( (res = usb_submit_urb(&rtl8150->rx_urb)) )
{
info( " read_bulk_callback: usb_submit_urb failed" );
warn( __FUNCTION__ " failed submint rx_urb %d", res);
}
rtl8150->flags &= ~RTL8150_RX_BUSY;
//info( "-read_bulk_callback() <=====");
}
static void write_bulk_callback( struct urb *urb )
{
rtl8150_t *rtl8150 = urb->context;
///info( "+write_bulk_callback() =====>" );
if ( !rtl8150 || !(rtl8150->flags & RTL8150_RUNNING) )
return;
if ( !netif_device_present(rtl8150->net) )
return;
if ( urb->status )
info("%s: TX status %d", rtl8150->net->name, urb->status);
netif_wake_queue( rtl8150->net );
///info( "-write_bulk_callback() <=====" );
}
#ifdef RTL8150_USE_INTR
static void intr_callback( struct urb *urb )
{
rtl8150_t *rtl8150 = urb->context;
struct net_device *net;
__u8 *d;
///info( "intr_callback() =====>" );
if ( !rtl8150 )
return;
d = urb->transfer_buffer;
net = rtl8150->net;
/// if ( d[0] & 0xfc ) {
/// rtl8150->stats.tx_errors++;
/// if ( d[0] & TX_UNDERRUN )
/// rtl8150->stats.tx_fifo_errors++;
/// if ( d[0] & (EXCESSIVE_COL | JABBER_TIMEOUT) )
/// rtl8150->stats.tx_aborted_errors++;
/// if ( d[0] & LATE_COL )
/// rtl8150->stats.tx_window_errors++;
/// if ( d[0] & (NO_CARRIER | LOSS_CARRIER) )
/// rtl8150->stats.tx_carrier_errors++;
/// }
switch ( urb->status )
{
case USB_ST_NOERROR:
break;
case USB_ST_URB_KILLED:
break;
default:
info("intr status %d", urb->status);
}
}
#endif
static void rtl8150_tx_timeout( struct net_device *net )
{
rtl8150_t *rtl8150 = net->priv;
info( "+rtl8150_tx_timeout() =====>" );
if ( !rtl8150 )
return;
usb_unlink_urb( &rtl8150->tx_urb );
warn("%s: Tx timed out.", net->name);
rtl8150->stats.tx_errors++;
net->trans_start = jiffies;
netif_wake_queue( net );
info( "-rtl8150_tx_timeout() <=====" );
}
static int rtl8150_start_xmit( struct sk_buff *skb, struct net_device *net )
{
rtl8150_t *rtl8150 = net->priv;
int count = ((skb->len) & 0x3f) ? skb->len : skb->len+1;
/// increase 64n-length packet by one, because the host controller sometimes doesn't send
/// 0-length usb packet to end the 64n-length packet.
int res;
//info( "+rtl8150_start_xmit() =====>" );
netif_stop_queue( net );
memcpy( rtl8150->tx_buff, skb->data, skb->len );
if(count < RTL8150_MIN_PACKET_LENGTH)
count = RTL8150_MIN_PACKET_LENGTH;
FILL_BULK_URB( &rtl8150->tx_urb, rtl8150->usb,
usb_sndbulkpipe(rtl8150->usb, 2),
rtl8150->tx_buff, RTL8150_MAX_MTU,
write_bulk_callback, rtl8150 );
rtl8150->tx_urb.transfer_buffer_length = count;
//info( " rtl8150_start_xmit: packet length = 0x%x", count);
//info( " rtl8150_start_xmit: packet = %x %x %x %x %x %x %x %x %x %x %x %x", rtl8150->tx_buff[0], rtl8150->tx_buff[1],
// rtl8150->tx_buff[2], rtl8150->tx_buff[3], rtl8150->tx_buff[4], rtl8150->tx_buff[5],
// rtl8150->tx_buff[6], rtl8150->tx_buff[7], rtl8150->tx_buff[8], rtl8150->tx_buff[9],
// rtl8150->tx_buff[10], rtl8150->tx_buff[11]);
rtl8150->tx_urb.transfer_flags |= USB_ASYNC_UNLINK;
if ((res = usb_submit_urb(&rtl8150->tx_urb)))
{
warn("failed tx_urb %d", res);
rtl8150->stats.tx_errors++;
netif_start_queue( net );
}
else
{
rtl8150->stats.tx_packets++;
rtl8150->stats.tx_bytes += skb->len;
net->trans_start = jiffies; /// record the time stamp
}
dev_kfree_skb(skb);
//info( "-rtl8150_start_xmit() <=====" );
return 0;
}
/// this function is called when "ifconfig ethx" or "netstat"
static struct net_device_stats *rtl8150_netdev_stats( struct net_device *dev )
{
//info( "+rtl8150_netdev_stats() =====>" );
return &((rtl8150_t *)dev->priv)->stats;
//info( "-rtl8150_netdev_stats() <=====" );
}
static inline void disable_net_traffic( rtl8150_t *rtl8150 )
{
__u8 tmp = 0;
info( "+disable_net_traffic() =====>" );
set_registers( rtl8150, Command, 1, &tmp );
info( "-disable_net_traffic() <=====" );
}
static inline void get_interrupt_interval( rtl8150_t *rtl8150 )
{
__u8 data;
info( "+get_interrupt_interval() =====>" );
read_eprom_byte( rtl8150, EPROM_Interv, &data );
rtl8150->intr_interval = data;
info( "-get_interrupt_interval() <=====" );
}
/// this function is called when "ifconfig ethx xxx ....."
static int rtl8150_open(struct net_device *net)
{
rtl8150_t *rtl8150 = (rtl8150_t *)net->priv;
int res;
info( "+rtl8150_open() =====>" );
MOD_INC_USE_COUNT;
///info( " rtl8150_open: before enable_net_traffic()" );
if ( (res = enable_net_traffic(net, rtl8150->usb)) )
{
info(" rtl8150_open: enable_net_traffic failed");
err("can't enable_net_traffic() - %d", res);
MOD_DEC_USE_COUNT;
return -EIO;
}
/// initiate the rx operation
info( " rtl8150_open: initiate the rx operation" );
FILL_BULK_URB( &rtl8150->rx_urb, rtl8150->usb,
usb_rcvbulkpipe(rtl8150->usb, 1),
rtl8150->rx_buff, RTL8150_MAX_MTU,
read_bulk_callback, rtl8150 );
if ( (res = usb_submit_urb(&rtl8150->rx_urb)) )
{
info(" rtl8150_open: usb_submit_urb failed" );
warn( __FUNCTION__ " failed rx_urb %d", res );
}
/*
/// initiate the interrupt operation
#ifdef RTL8150_USE_INTR
get_interrupt_interval( rtl8150 );
FILL_INT_URB( &rtl8150->intr_urb, rtl8150->usb,
usb_rcvintpipe(rtl8150->usb, 3),
rtl8150->intr_buff, sizeof(rtl8150->intr_buff),
intr_callback, rtl8150, rtl8150->intr_interval );
if ( (res = usb_submit_urb(&rtl8150->intr_urb)) )
warn( __FUNCTION__ " failed intr_urb %d", res);
#endif
*/
netif_start_queue( net );
rtl8150->flags |= RTL8150_RUNNING;
info( "-rt8150_open() <=====" );
return 0;
}
/// this funciton is called when "ifconfig ethx down"
static int rtl8150_close( struct net_device *net )
{
rtl8150_t *rtl8150 = net->priv;
info( "+rtl8150_close() =====>" );
rtl8150->flags &= ~RTL8150_RUNNING;
netif_stop_queue( net );
if ( !(rtl8150->flags & RTL8150_UNPLUG) )
disable_net_traffic( rtl8150 );
usb_unlink_urb( &rtl8150->rx_urb );
usb_unlink_urb( &rtl8150->tx_urb );
usb_unlink_urb( &rtl8150->ctrl_urb );
usb_unlink_urb( &rtl8150->intr_urb );
MOD_DEC_USE_COUNT;
info( "-rtl8150_close() <=====" );
return 0;
}
static int rtl8150_ioctl( struct net_device *net, struct ifreq *rq, int cmd )
{
__u16 *data = (__u16 *)&rq->ifr_data;
rtl8150_t *rtl8150 = net->priv;
info( "+rtl8150_ioctl() =====> return -EOPNOTSUPP directly" );
return -EOPNOTSUPP;
switch(cmd) {
case SIOCDEVPRIVATE:
data[0] = rtl8150->phy;
case SIOCDEVPRIVATE+1:
read_phy_word(rtl8150, data[0], data[1]&0x1f, &data[3]);
return 0;
case SIOCDEVPRIVATE+2:
if ( !capable(CAP_NET_ADMIN) )
return -EPERM;
write_phy_word(rtl8150, rtl8150->phy, data[1] & 0x1f, data[2]);
return 0;
default:
return -EOPNOTSUPP;
}
}
static void rtl8150_set_multicast( struct net_device *net )
{
__u16 rcr_content;
rtl8150_t *rtl8150 = net->priv;
info( "+rtl8150_set_multicast() =====>" );
netif_stop_queue(net);
while( rtl8150->get_registers_flag == 1 )
;
rtl8150->get_registers_flag = 1;
get_registers( rtl8150, RxConfig, 2, &rcr_content );
while( rtl8150->get_registers_flag == 1 )
;
if (net->flags & IFF_PROMISC)
{
rcr_content |= AAP;
info(" %s: Promiscuous mode enabled", net->name);
}
else if( (net->mc_count > multicast_filter_limit) || (net->flags & IFF_ALLMULTI) )
{
rcr_content |= AAM;
rcr_content &= ~AAP;
info(" %s set allmulti", net->name);
}
else
{
rcr_content &= ~AAM;
rcr_content &= ~AAP;
info(" %s: No Promiscuous and All Multicast", net->name);
/// added by Owen, please refer to 14.14.2 of Linux Device Drivers
/// if( net->mc_count==0 )
/// ff_get_only_own_packets();
/// else
/// {
/// struct dev_mc_list *mcptr;
/// ff_clear_mc_list();
/// for( mc_ptr = net->mc_list; mc_ptr; mc_ptr = mc_ptr->next )
/// ff_store_mc_address( mc_ptr->dmi_addr );
// ff_get_packets_in_multicast_list();
/// }
}
while( rtl8150->set_registers_flag == 1 )
;
rtl8150->set_registers_flag = 1;
set_registers( rtl8150, RxConfig, 2, &rcr_content );
while( rtl8150->set_registers_flag == 1 )
;
netif_wake_queue(net);
info( "-rtl8150_set_multicast() <=====" );
}
static int check_device_ids( __u16 vendor, __u16 product )
{
int i=0;
info( "+check_device_ids() =====>" );
info( " check_device_ids: vendor id = 0x%x", vendor );
info( " check_device_ids: device id = 0x%x", product );
while ( usb_dev_id[i].name ) {
if ( (usb_dev_id[i].vendor == vendor) && (usb_dev_id[i].device == product) )
{
info( " check_device_ids: BINGO!" );
info( "-check_device_ids() <=====" );
return i;
}
i++;
}
info( " check_device_ids: not our device");
info( "-check_device_ids() <=====" );
return -1;
}
static void mii_HPNA_phy_probe( rtl8150_t *rtl8150 )
{
int i;
__u16 tmp;
/*
for ( i=0; i < 32; i++ )
{
read_phy_word( rtl8150, i, MII_PHY_ID2, &tmp );
tmp = tmp & 0xfff0;
if( tmp == AMD_PHY_ID )
{
rtl8150->hpna_phy = AMD_PHY;
rtl8150->phy = i;
return;
}
else if( tmp == NS_PHY_ID )
{
rtl8150->hpna_phy = NS_PHY;
rtl8150->phy = i;
return;
}
else
continue;
}
rtl8150->phy = 0;
rtl8150->hpna_phy = UNKNOWN_PHY;
*/
}
static void * rtl8150_probe( struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)
{
struct net_device *net;
rtl8150_t *rtl8150;
int dev_indx;
info( "+rtl8150_probe() =====>" );
///info( " rtl8150_probe: before check_deice_ids()" );
if ( (dev_indx = check_device_ids(dev->descriptor.idVendor, dev->descriptor.idProduct)) == -1 )
{
info( " rtl8150_pbobe: this is not my device!" );
return NULL;
}
///info( " rtl8150_probe: after check_device_ids()" );
///info( " rtl8150_probe: before usb_set_configuration()" );
/// the following is for fixing the bug of 1st-cut, and must be removed in 2nd-cut
dev->config[0].bConfigurationValue = 1;
////////////////////////////////////////////////
if (usb_set_configuration(dev, dev->config[0].bConfigurationValue))
{
err("usb_set_configuration() failed");
info( " rtl8150_probe: usb_set_configuration() failed" );
return NULL;
}
///info( " rtl8150_probe: after usb_set_configuration()" );
if(!(rtl8150 = kmalloc(sizeof(struct rtl8150), GFP_KERNEL)))
{
err("out of memory allocating device structure");
info( " rtl8150_probe: out of memory allocating device structure" );
return NULL;
}
/// added by Owen on 01/11/2000
rtl8150->get_registers_flag = 0;
rtl8150->set_registers_flag = 0;
///info( " rtl8150_probe: before usb_inc_dev_use()" );
usb_inc_dev_use( dev );
memset(rtl8150, 0, sizeof(struct rtl8150));
///info( " rtl8150_probe: after usb_inc_dev_use()" );
///info( " rtl8150_probe: before init_MUTEX()" );
init_MUTEX( &rtl8150-> ctrl_sem );
///info( " rtl8150_probe: after init_MUTEX()" );
///info( " rtl8150_probe: before init_waitqueue_head()" );
init_waitqueue_head( &rtl8150->ctrl_wait );
///info( " rtl8150_probe: after init_waitqueue_head()" );
///info( " rtl8150_probe: before init_etherdev()" );
net = init_etherdev( NULL, 0 );
if ( !net )
{
kfree( rtl8150 );
info( " rtl8150_probe: init_etherdev() failed" );
return NULL;
}
///info( " rtl8150_probe: after init_etherdev()" );
rtl8150->usb = dev;
rtl8150->net = net;
net->priv = rtl8150;
net->open = rtl8150_open;
net->stop = rtl8150_close;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,48)
net->watchdog_timeo = RTL8150_TX_TIMEOUT;
net->tx_timeout = rtl8150_tx_timeout;
#endif
net->do_ioctl = rtl8150_ioctl;
net->hard_start_xmit = rtl8150_start_xmit;
net->set_multicast_list = rtl8150_set_multicast;
net->get_stats = rtl8150_netdev_stats;
net->mtu = RTL8150_MTU; // 1500
rtl8150->features = usb_dev_id[dev_indx].private;
///info( " rtl8150_probe: before reset_mac()" );
if ( reset_mac(rtl8150) )
{
err("can't reset MAC");
info( " rtl8150_probe: reset_mac() failed" );
unregister_netdev( rtl8150->net );
kfree(rtl8150);
rtl8150 = NULL;
return NULL;
}
///info( " rtl8150_probe: after reset_mac()" );
///info( " rtl8150_probe: before set_ethernet_addr()" );
set_ethernet_addr( rtl8150 );
///info( " rtl8150_probe: after set_ethernet_addr()" );
if( rtl8150->features & FEATURE_HAS_HOME_PNA )
mii_HPNA_phy_probe( rtl8150 );
info( "%s: %s", net->name, usb_dev_id[dev_indx].name );
info( "-rtl8150_probe() <=====" );
return rtl8150;
}
static void rtl8150_disconnect( struct usb_device *dev, void *ptr )
{
struct rtl8150 *rtl8150 = ptr;
info( "+rtl8150_disconnect() =====>" );
if ( !rtl8150 ) {
info( " rtl8150_disconnect: unregister non-existant device" );
warn("unregistering non-existant device");
return;
}
rtl8150->flags |= RTL8150_UNPLUG;
unregister_netdev( rtl8150->net );
usb_dec_dev_use( dev );
kfree( rtl8150 );
rtl8150 = NULL;
info( "-rtl8150_disconnect() <=====" );
}
static struct usb_driver rtl8150_driver = {
name: "RTL8150",
probe: rtl8150_probe,
disconnect: rtl8150_disconnect,
};
/// this function is called when "insmod rtl8150.o"
int __init rtl8150_init(void)
{
int registerResult;
info( "+rtl8150_init() =====>" );
info( "%s", version );
registerResult = usb_register( &rtl8150_driver );
info( "-rtl8150_init() <=====" );
return registerResult;
}
/// this funciton is called when "rmmod rtl8150"
void __exit rtl8150_exit(void)
{
info( "+rtl8150_exit() =====>" );
usb_deregister( &rtl8150_driver );
info( "-rtl8150_exit() <=====" );
}
module_init( rtl8150_init );
module_exit( rtl8150_exit );
next reply other threads:[~2006-06-20 6:46 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-06-20 6:46 Ben Greear [this message]
2006-06-20 10:13 ` rtl8150 usb driver, needs more vendor ids? Petko Manolov
2006-06-20 14:25 ` Ben Greear
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=449799BA.1050303@candelatech.com \
--to=greearb@candelatech.com \
--cc=netdev@vger.kernel.org \
--cc=petkan@users.sourceforge.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.