All, I took a little time and rewrote the rtl8150 driver using the usbnet framework and would like some folks to try to test it. Please note that I DO NOT have this device, thus it is only compile tested. The module loads cleanly, and that is the extent to how well I know that it works. If anyone has the device and the free time to try it, I would like to hear any feedback. This driver is missing a few features and may only partially work, though most of the basics should be there. At this point, it weighs in at 292 lines compared to 1002 for the current driver.
-- David Hollis <[EMAIL PROTECTED]>
#define DEBUG // error path messages, extra info
#define VERBOSE // more; success messages
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/usb.h>
#include "usbnet.h"
#define DRIVER_VERSION "21-Aug-2006"
static const char driver_name[] = "rtl8150";
#define RTL8150_REQT_READ 0xc0
#define RTL8150_REQT_WRITE 0x40
#define RTL8150_REQ_GET_REGS 0x05
#define RTL8150_REQ_SET_REGS 0x05
/* RTL8150 Registers */
#define CR 0x012e
#define TCR 0x012f
#define RCR 0x0130
#define IDR 0x0120
#define MSR 0x0137
#define PHYADD 0x0138
#define PHYDAT 0x0139
#define PHYCNT 0x013b
#define CSCR 0x014C
#define CSCR_LINK_STATUS (1 << 3)
#define PHY_READ 0x00
#define PHY_WRITE 0x20
#define PHY_GO 0x40
/* FIXME: Lets get rid of this if we can */
#define MII_TIMEOUT 10
static int rtl8150_read_cmd(struct usbnet *dev, u16 index, u16 size, void *data)
{
devdbg(dev, "rtl8150_read_cmd() index=0x%04x size=%d", index, size);
return usb_control_msg(dev->udev,
usb_rcvctrlpipe(dev->udev, 0),
RTL8150_REQ_GET_REGS,
RTL8150_REQT_READ,
index, 0, data, size, USB_CTRL_GET_TIMEOUT);
}
static int rtl8150_write_cmd(struct usbnet *dev, u16 index, u16 size,
void *data)
{
devdbg(dev, "rtl8150_write_cmd() index=0x%04x size=%d", index, size);
return usb_control_msg(dev->udev,
usb_sndctrlpipe(dev->udev, 0),
RTL8150_REQ_SET_REGS,
RTL8150_REQT_WRITE,
index, 0, data, size, USB_CTRL_SET_TIMEOUT);
}
static int rtl8150_mdio_read(struct net_device *netdev, int phy_id, int loc)
{
struct usbnet *dev = netdev_priv(netdev);
int i;
u8 data[3], tmp;
int ret = 0;
data[0] = phy_id;
data[1] = data[2] = 0;
tmp = loc | PHY_READ | PHY_GO;
i = 0;
rtl8150_write_cmd(dev, PHYADD, sizeof(data), data);
rtl8150_write_cmd(dev, PHYCNT, 1, &tmp);
do {
rtl8150_read_cmd(dev, PHYCNT, 1, data);
} while ((data[0] & PHY_GO) && (i++ < MII_TIMEOUT));
if (i < MII_TIMEOUT) {
rtl8150_read_cmd(dev, PHYDAT, 2, data);
ret = data[0] | (data[1] << 8);
}
return ret;
}
static void
rtl8150_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
{
}
static void rtl8150_set_multicast(struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
devdbg(dev, "rtl8150_set_multicast() not implemented");
#if 0
netif_stop_queue(net);
if (net->flags & IFF_PROMISC) {
dev->rx_creg |= cpu_to_le16(0x0001);
info("%s: promiscuous mode", net->name);
} else if (net->mc_count || (net->flags & IFF_ALLMULTI)) {
dev->rx_creg &= cpu_to_le16(0xfffe);
dev->rx_creg |= cpu_to_le16(0x0002);
info("%s: allmulti set", net->name);
} else {
/* ~RX_MULTICAST, ~RX_PROMISCUOUS */
dev->rx_creg &= cpu_to_le16(0x00fc);
}
async_set_registers(dev, RCR, 2);
netif_wake_queue(netdev);
#endif
}
static int rtl8150_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
{
struct usbnet *dev = netdev_priv(net);
return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
}
static void rtl8150_set_ethernet_addr(struct usbnet *dev)
{
u8 node_id[6];
rtl8150_read_cmd(dev, IDR, sizeof(node_id), node_id);
memcpy(dev->net->dev_addr, node_id, sizeof(node_id));
}
static int rtl8150_set_mac_address(struct net_device *net, void *p)
{
struct usbnet *dev = netdev_priv(net);
struct sockaddr *addr = p;
if (netif_running(net))
return -EBUSY;
memcpy(net->dev_addr, addr->sa_data, net->addr_len);
/* Set the IDR registers. */
rtl8150_write_cmd(dev, IDR, sizeof(net->dev_addr), net->dev_addr);
return 0;
}
static int rtl8150_reset(struct usbnet *dev)
{
u8 data = 0x10;
int i = HZ;
u8 rcr, tcr, cr, msr;
devdbg(dev, "rtl8150_reset()");
rtl8150_write_cmd(dev, CR, 1, &data);
do {
rtl8150_read_cmd(dev, CR, 1, &data);
} while ((data & 0x10) && --i);
rtl8150_write_cmd(dev, IDR, 6, dev->net->dev_addr);
/* RCR bit7=1 attach Rx info at the end; =0 HW CRC (which is broken) */
rcr = 0x9e;
tcr = 0xd8;
cr = 0x0c;
/*
if (!(rcr & 0x80))
set_bit(RTL8150_HW_CRC, &dev->flags);
*/
rtl8150_write_cmd(dev, RCR, 1, &rcr);
rtl8150_write_cmd(dev, TCR, 1, &tcr);
rtl8150_write_cmd(dev, CR, 1, &cr);
rtl8150_read_cmd(dev, MSR, 1, &msr);
return 0;
}
static void rtl8150_status(struct usbnet *dev, struct urb *urb)
{
devdbg(dev, "rtl8150_status()");
}
static int rtl8150_check_connect(struct usbnet *dev)
{
int tmp;
rtl8150_read_cmd(dev, CSCR, 2, &tmp);
return (tmp & CSCR_LINK_STATUS);
}
static int rtl8150_get_settings(struct net_device *net, struct ethtool_cmd *cmd)
{
struct usbnet *dev = netdev_priv(net);
return mii_ethtool_gset(&dev->mii, cmd);
}
static void rtl8150_get_drvinfo(struct net_device *net,
struct ethtool_drvinfo *info)
{
/* Inherit standard device info */
usbnet_get_drvinfo(net, info);
strncpy(info->driver, driver_name, sizeof info->driver);
strncpy(info->version, DRIVER_VERSION, sizeof info->version);
}
static struct ethtool_ops rtl8150_ethtool_ops = {
.get_drvinfo = rtl8150_get_drvinfo,
.get_settings = rtl8150_get_settings,
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
};
static int rtl8150_bind(struct usbnet *dev, struct usb_interface *intf)
{
dbg("rtl8150_bind()");
dev->mii.dev = dev->net;
dev->mii.mdio_read = rtl8150_mdio_read;
dev->mii.mdio_write = rtl8150_mdio_write;
/*
dev->mii.phy_id_mask = 0x3f;
dev->mii.reg_num_mask = 0x1f;
dev->mii.phy_id = asix_get_phy_addr(dev);
*/
dev->net->do_ioctl = rtl8150_ioctl;
dev->net->set_multicast_list = rtl8150_set_multicast;
dev->net->set_mac_address = rtl8150_set_mac_address;
dev->net->ethtool_ops = &rtl8150_ethtool_ops;
rtl8150_set_ethernet_addr(dev);
return 0;
}
static const struct driver_info rtl8150_info = {
.description = "RTL8150 USB Ethernet",
.bind = rtl8150_bind,
.reset = rtl8150_reset,
.status = rtl8150_status,
.check_connect = rtl8150_check_connect,
.flags = FLAG_ETHER,
};
static const struct usb_device_id products[] = {
{
USB_DEVICE(0x0bda, 0x8150),
.driver_info = (unsigned long)&rtl8150_info,
}, {
USB_DEVICE(0x0411, 0x0012),
.driver_info = (unsigned long)&rtl8150_info,
}, {
USB_DEVICE(0x3980, 0x0003),
.driver_info = (unsigned long)&rtl8150_info,
}, {
USB_DEVICE(0x07b8, 0x401a),
.driver_info = (unsigned long)&rtl8150_info,
}, {
USB_DEVICE(0x0586, 0x401a),
.driver_info = (unsigned long)&rtl8150_info,
},
{},
};
MODULE_DEVICE_TABLE(usb, products);
static struct usb_driver rtl8150_driver = {
.name = "rtl8150",
.id_table = products,
.probe = usbnet_probe,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.disconnect = usbnet_disconnect,
};
static int __init rtl8150_init(void)
{
return usb_register(&rtl8150_driver);
}
module_init(rtl8150_init);
static void __exit rtl8150_exit(void)
{
usb_deregister(&rtl8150_driver);
}
module_exit(rtl8150_exit);
MODULE_AUTHOR("David Hollis");
MODULE_DESCRIPTION("RTL8150 USB Ethernet Driver");
MODULE_LICENSE("GPL");
obj-m += rtl8150.o KVERSION := `uname -r` KDIR := /lib/modules/$(KVERSION)/build all: make -C $(KDIR) SUBDIRS=`pwd` modules clean: make -C $(KDIR) SUBDIRS=`pwd` clean install: make -C $(KDIR) SUBDIRS=`pwd` install
signature.asc
Description: This is a digitally signed message part
------------------------------------------------------------------------- Using Tomcat but need to do more? Need to support web services, security? Get stuff done quickly with pre-integrated technology to make your job easier Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________ [email protected] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
