REKLAMA

Android_Linux_Vista.rar

mk802 + rj45 na USB: Problemy z połączeniem LAN i Wi-Fi, test kabla 8-żyłowego

Znalazłem sterowniki :) I jest jakiś problem z kartą. Nawet jak wpiszę ręcznie w kartę jak na zrzucie to nie działa. Dodatkowo w router jest wpisana filtracja po macku na 192.168.1.15. http://obrazki.elektroda.pl/6756552000_1350081938.jpg Sterowniki gdyby się komuś przydały. Nazwa to qf9700 ale jest wersja niebieska i biała. I nigdzie nie są podpisane. TE SĄ DO WERSJI BIAŁEJ jak na focie wyżej.


Pobierz plik - link do postu
  • Android_Linux_Vista.rar
    • modules.order
    • .qf9700_android.mod.o.cmd
    • qf9700_android.c
    • qf9700_android.mod.c
    • qf9700_android.ko
    • Makefile
    • README
    • Module.markers
    • qf9700_android.mod.o
    • .qf9700_android.o.cmd
    • qf9700_android.o
    • Module.symvers
    • qf9700_android.h
    • .tmp_versions
      • qf9700_android.mod
    • .qf9700_android.ko.cmd


Android_Linux_Vista.rar > qf9700_android.mod.c

#include & lt; linux/module.h & gt;
#include & lt; linux/vermagic.h & gt;
#include & lt; linux/compiler.h & gt;

MODULE_INFO(vermagic, VERMAGIC_STRING);

struct module __this_module
__attribute__((section( " .gnu.linkonce.this_module " ))) = {
.name = KBUILD_MODNAME,
.init = init_module,
#ifdef CONFIG_MODULE_UNLOAD
.exit = cleanup_module,
#endif
.arch = MODULE_ARCH_INIT,
};

static const char __module_depends[]
__used
__attribute__((section( " .modinfo " ))) =
" depends=usbnet " ;

MODULE_ALIAS( " usb:v0FE6p9700d*dc*dsc*dp*ic*isc*ip* " );


Android_Linux_Vista.rar > qf9700_android.h

/*
* Copyright (c) 2009 jokeliu@163.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* Author : jokeliujl & lt; jokeliu@163.com & gt;
* Date : 2010-10-01
*/

/* qf9700 spec. register table on android platform */
/* Registers */
#define NCR 0x00
#define NSR 0x01
#define TCR 0x02
#define TSR1 0x03
#define TSR2 0x04
#define RCR 0x05
#define RSR 0x06
#define ROCR 0x07
#define BPTR 0x08
#define FCTR 0x09
#define FCR 0x0A
#define EPCR 0x0B
#define EPAR 0x0C
#define EPDR 0x0D // 0x0D ~ 0x0E
#define WCR 0x0F
#define PAR 0x10
#define MAR 0x16
#define PRR 0x1F
#define TWPAL 0x20
#define TWPAH 0x21
#define TRPAL 0x22
#define TRPAH 0x23
#define RWPAL 0x24
#define RWPAH 0x25
#define RRPAL 0x26
#define RRPAH 0x27
#define VID 0x28
#define PID 0x2A
#define CHIPR 0x2C
#define USBDA 0xF0
#define RXC 0xF1
#define TXC_USBS 0xF2
#define USBC 0xF4

/* Bit definition for registers */
// Network Control Reg
#define NCR_RST (1 & lt; & lt; 0)
#define NCR_LBK (3 & lt; & lt; 1)
#define NCR_FDX (1 & lt; & lt; 3)
#define NCR_WAKEEN (1 & lt; & lt; 6)
// Network Status Reg
#define NQF_RXRDY (1 & lt; & lt; 0)
#define NQF_RXOV (1 & lt; & lt; 1)
#define NQF_TX1END (1 & lt; & lt; 2)
#define NQF_TX2END (1 & lt; & lt; 3)
#define NQF_TXFULL (1 & lt; & lt; 4)
#define NQF_WAKEST (1 & lt; & lt; 5)
#define NQF_LINKST (1 & lt; & lt; 6)
#define NQF_SPEED (1 & lt; & lt; 7)
// Tx Control Reg
#define TCR_CRC_DIS (1 & lt; & lt; 1)
#define TCR_PAD_DIS (1 & lt; & lt; 2)
#define TCR_LC_CARE (1 & lt; & lt; 3)
#define TCR_CRS_CARE (1 & lt; & lt; 4)
#define TCR_EXCECM (1 & lt; & lt; 5)
#define TCR_LF_EN (1 & lt; & lt; 6)
// Tx Status Reg for Packet 1
#define TSR1_EC (1 & lt; & lt; 2)
#define TSR1_COL (1 & lt; & lt; 3)
#define TSR1_LC (1 & lt; & lt; 4)
#define TSR1_NC (1 & lt; & lt; 5)
#define TSR1_LOC (1 & lt; & lt; 6)
#define TSR1_TLF (1 & lt; & lt; 7)
// Tx Status Reg for Packet 2
#define TSR2_EC (1 & lt; & lt; 2)
#define TSR2_COL (1 & lt; & lt; 3)
#define TSR2_LC (1 & lt; & lt; 4)
#define TSR2_NC (1 & lt; & lt; 5)
#define TSR2_LOC (1 & lt; & lt; 6)
#define TSR2_TLF (1 & lt; & lt; 7)
// Rx Control Reg
#define RCR_RXEN (1 & lt; & lt; 0)
#define RCR_PRMSC (1 & lt; & lt; 1)
#define RCR_RUNT (1 & lt; & lt; 2)
#define RCR_ALL (1 & lt; & lt; 3)
#define RCR_DIS_CRC (1 & lt; & lt; 4)
#define RCR_DIS_LONG (1 & lt; & lt; 5)
// Rx Status Reg
#define RQF_AE (1 & lt; & lt; 2)
#define RQF_MF (1 & lt; & lt; 6)
#define RQF_RF (1 & lt; & lt; 7)
// Recv Overflow Counter Reg
#define ROCR_ROC (0x7F & lt; & lt; 0)
#define ROCR_RXFU (1 & lt; & lt; 7)
// Back Pressure Threshold Reg
#define BPTR_JPT (0x0F & lt; & lt; 0)
#define BPTR_BPHW (0x0F & lt; & lt; 4)
// Flow Control Threshold Reg
#define FCTR_LWOT (0x0F & lt; & lt; 0)
#define FCTR_HWOT (0x0F & lt; & lt; 4)
// rx/tx Flow Control Reg
#define FCR_FLCE (1 & lt; & lt; 0)
#define FCR_BKPA (1 & lt; & lt; 4)
#define FCR_TXPEN (1 & lt; & lt; 5)
#define FCR_TXPF (1 & lt; & lt; 6)
#define FCR_TXP0 (1 & lt; & lt; 7)
// EEPROM & PHY Control Reg
#define EPCR_ERRE (1 & lt; & lt; 0)
#define EPCR_ERPRW (1 & lt; & lt; 1)
#define EPCR_ERPRR (1 & lt; & lt; 2)
#define EPCR_EPOS (1 & lt; & lt; 3)
#define EPCR_WEP (1 & lt; & lt; 4)
// EEPROM & PHY Address Reg
#define EPAR_EROA (0x3F & lt; & lt; 0)
#define EPAR_PHY_ADR (0x03 & lt; & lt; 6)
// Wakeup Control Reg
#define WCR_MAGICST (1 & lt; & lt; 0)
#define WCR_LINKST (1 & lt; & lt; 2)
#define WCR_MAGICEN (1 & lt; & lt; 3)
#define WCR_LINKEN (1 & lt; & lt; 5)
// Phy Reset Reg
#define PRR_PHY_RST (1 & lt; & lt; 0)
// USB Device Address Reg
#define USBDA_USBFA (0x7F & lt; & lt; 0)
// TX packet Counter & USB Status Reg
#define TXC_USBS_TXC0 (1 & lt; & lt; 0)
#define TXC_USBS_TXC1 (1 & lt; & lt; 1)
#define TXC_USBS_TXC2 (1 & lt; & lt; 2)
#define TXC_USBS_EP1RDY (1 & lt; & lt; 5)
#define TXC_USBS_SUSFLAG (1 & lt; & lt; 6)
#define TXC_USBS_RXFAULT (1 & lt; & lt; 7)
// USB Control Reg
#define USBC_EP3NAK (1 & lt; & lt; 4)
#define USBC_EP3ACK (1 & lt; & lt; 5)

/* Variables */
#define QF_RD_REGS 0x00
#define QF_WR_REGS 0x01
#define QF_WR_REG 0x03
#define QF_REQ_RD_REG (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
#define QF_REQ_WR_REG (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE)

#define QF_SHARE_TIMEOUT 1000
#define QF_EEPROM_LEN 256
#define QF_MCAST_SIZE 8
#define QF_MCAST_MAX 64
#define QF_TX_OVERHEAD 2 // 2bytes header
#define QF_RX_OVERHEAD 7 // 3bytes header + 4crc tail

/*----------------------------------------------------------------------------------------------*/


Android_Linux_Vista.rar > qf9700_android.c

/*
* QF9700_android one chip USB 1.1 ethernet devices
*
* Author : jokeliujl & lt; jokeliu@163.com & gt;
* Date : 2010-10-01
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed " as is " without any warranty of any
* kind, whether express or implied.
*/

//#define DEBUG

#include & lt; linux/module.h & gt;
#include & lt; linux/sched.h & gt;
#include & lt; linux/stddef.h & gt;
#include & lt; linux/init.h & gt;
#include & lt; linux/netdevice.h & gt;
#include & lt; linux/etherdevice.h & gt;
#include & lt; linux/ethtool.h & gt;
#include & lt; linux/mii.h & gt;
#include & lt; linux/usb.h & gt;
#include & lt; linux/crc32.h & gt;
#include & lt; linux/usb/usbnet.h & gt;

#include " qf9700_android.h "

/* ------------------------------------------------------------------------------------------ */
/* qf9700_android mac and phy operations */
/* qf9700_android read some registers from MAC */
static int qf_read(struct usbnet *dev, u8 reg, u16 length, void *data)
{
void *buf;
int err = -ENOMEM;

devdbg(dev, " qf_read() reg=0x%02x length=%d " , reg, length);

buf = kmalloc(length, GFP_KERNEL);
if (!buf)
goto out;

err = usb_control_msg(dev- & gt; udev, usb_rcvctrlpipe(dev- & gt; udev, 0),
QF_RD_REGS, QF_REQ_RD_REG,
0, reg, buf, length, USB_CTRL_SET_TIMEOUT);
if (err == length)
memcpy(data, buf, length);
else if (err & gt; = 0)
err = -EINVAL;
kfree(buf);

out:
return err;
}

/* qf9700_android write some registers to MAC */
static int qf_write(struct usbnet *dev, u8 reg, u16 length, void *data)
{
void *buf = NULL;
int err = -ENOMEM;

devdbg(dev, " qf_write() reg=0x%02x, length=%d " , reg, length);

if (data) {
buf = kmalloc(length, GFP_KERNEL);
if (!buf)
goto out;
memcpy(buf, data, length);
}

err = usb_control_msg(dev- & gt; udev, usb_sndctrlpipe(dev- & gt; udev, 0),
QF_WR_REGS, QF_REQ_WR_REG,
0, reg, buf, length, USB_CTRL_SET_TIMEOUT);
kfree(buf);
if (err & gt; = 0 & & err & lt; length)
err = -EINVAL;
out:
return err;
}

/* qf9700_android read one register from MAC */
static int qf_read_reg(struct usbnet *dev, u8 reg, u8 *value)
{
return qf_read(dev, reg, 1, value);
}

/* qf9700_android write one register to MAC */
static int qf_write_reg(struct usbnet *dev, u8 reg, u8 value)
{
devdbg(dev, " qf_write_reg() reg=0x%02x, value=0x%02x " , reg, value);
return usb_control_msg(dev- & gt; udev, usb_sndctrlpipe(dev- & gt; udev, 0),
QF_WR_REG, QF_REQ_WR_REG,
value, reg, NULL, 0, USB_CTRL_SET_TIMEOUT);
}

/* async mode for writing registers or reg blocks */
static void qf_write_async_callback(struct urb *urb)
{
struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb- & gt; context;

if (urb- & gt; status & lt; 0)
printk(KERN_DEBUG " qf_write_async_callback() failed with %d\n " , urb- & gt; status);

kfree(req);
usb_free_urb(urb);
}

static void qf_write_async_helper(struct usbnet *dev, u8 reg, u8 value, u16 length, void *data)
{
struct usb_ctrlrequest *req;
struct urb *urb;
int status;

urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
deverr(dev, " Error allocating URB in qf_write_async_helper! " );
return;
}

req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
if (!req) {
deverr(dev, " Failed to allocate memory for control request " );
usb_free_urb(urb);
return;
}

req- & gt; bRequestType = QF_REQ_WR_REG;
req- & gt; bRequest = length ? QF_WR_REGS : QF_WR_REG;
req- & gt; wValue = cpu_to_le16(value);
req- & gt; wIndex = cpu_to_le16(reg);
req- & gt; wLength = cpu_to_le16(length);

usb_fill_control_urb(urb, dev- & gt; udev, usb_sndctrlpipe(dev- & gt; udev, 0),
(void *)req, data, length,
qf_write_async_callback, req);

status = usb_submit_urb(urb, GFP_ATOMIC);
if (status & lt; 0) {
deverr(dev, " Error submitting the control message: status=%d " ,
status);
kfree(req);
usb_free_urb(urb);
}

return;
}

static void qf_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
{
devdbg(dev, " qf_write_async() reg=0x%02x length=%d " , reg, length);

qf_write_async_helper(dev, reg, 0, length, data);
}

static void qf_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
{
devdbg(dev, " qf_write_reg_async() reg=0x%02x value=0x%02x " , reg, value);

qf_write_async_helper(dev, reg, value, 0, NULL);
}

/* qf9700_android read one word from phy or eeprom */
static int qf_share_read_word(struct usbnet *dev, int phy, u8 reg, __le16 *value)
{
int ret, i;

mutex_lock( & dev- & gt; phy_mutex);

qf_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
qf_write_reg(dev, EPCR, phy ? 0xc : 0x4);

for (i = 0; i & lt; QF_SHARE_TIMEOUT; i++) {
u8 tmp;

udelay(1);
ret = qf_read_reg(dev, EPCR, & tmp);
if (ret & lt; 0)
goto out;

/* ready */
if ((tmp & 1) == 0)
break;
}

if (i & gt; = QF_SHARE_TIMEOUT) {
deverr(dev, " %s read timed out! " , phy ? " phy " : " eeprom " );
ret = -EIO;
goto out;
}

qf_write_reg(dev, EPCR, 0x0);
ret = qf_read(dev, EPDR, 2, value);

devdbg(dev, " read shared %d 0x%02x returned 0x%04x, %d " ,
phy, reg, *value, ret);

out:
mutex_unlock( & dev- & gt; phy_mutex);
return ret;
}

/* write one word to phy or eeprom */
static int qf_share_write_word(struct usbnet *dev, int phy, u8 reg, __le16 value)
{
int ret, i;

mutex_lock( & dev- & gt; phy_mutex);

ret = qf_write(dev, EPDR, 2, & value);
if (ret & lt; 0)
goto out;

qf_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
qf_write_reg(dev, EPCR, phy ? 0x1a : 0x12);

for (i = 0; i & lt; QF_SHARE_TIMEOUT; i++) {
u8 tmp;

udelay(1);
ret = qf_read_reg(dev, EPCR, & tmp);
if (ret & lt; 0)
goto out;

/* ready */
if ((tmp & 1) == 0)
break;
}

if (i & gt; = QF_SHARE_TIMEOUT) {
deverr(dev, " %s write timed out! " , phy ? " phy " : " eeprom " );
ret = -EIO;
goto out;
}

qf_write_reg(dev, EPCR, 0x0);

out:
mutex_unlock( & dev- & gt; phy_mutex);
return ret;
}

static int qf_read_eeprom_word(struct usbnet *dev, u8 offset, void *value)
{
return qf_share_read_word(dev, 0, offset, value);
}


static int qf9700_android_get_eeprom_len(struct net_device *dev)
{
return QF_EEPROM_LEN;
}

/* get qf9700_android eeprom information */
static int qf9700_android_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, u8 * data)
{
struct usbnet *dev = netdev_priv(net);
__le16 *ebuf = (__le16 *) data;
int i;

/* access is 16bit */
if ((eeprom- & gt; offset % 2) || (eeprom- & gt; len % 2))
return -EINVAL;

for (i = 0; i & lt; eeprom- & gt; len / 2; i++) {
if (qf_read_eeprom_word(dev, eeprom- & gt; offset / 2 + i, & ebuf[i]) & lt; 0)
return -EINVAL;
}
return 0;
}

/* qf9700_android mii-phy register read by word */
static int qf9700_android_mdio_read(struct net_device *netdev, int phy_id, int loc)
{
struct usbnet *dev = netdev_priv(netdev);

__le16 res;

if (phy_id) {
devdbg(dev, " Only internal phy supported " );
return 0;
}

qf_share_read_word(dev, 1, loc, & res);

devdbg(dev,
" qf9700_android_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x " ,
phy_id, loc, le16_to_cpu(res));

return le16_to_cpu(res);
}

/* qf9700_android mii-phy register write by word */
static void qf9700_android_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
{
struct usbnet *dev = netdev_priv(netdev);
__le16 res = cpu_to_le16(val);

if (phy_id) {
devdbg(dev, " Only internal phy supported " );
return;
}

devdbg(dev, " qf9700_android_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x " ,
phy_id, loc, val);

qf_share_write_word(dev, 1, loc, res);
}

/*-------------------------------------------------------------------------------------------*/

static void qf9700_android_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
{
/* Inherit standard device info */
usbnet_get_drvinfo(net, info);
info- & gt; eedump_len = QF_EEPROM_LEN;
}

static u32 qf9700_android_get_link(struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);

return mii_link_ok( & dev- & gt; mii);
}

static int qf9700_android_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
{
struct usbnet *dev = netdev_priv(net);

return generic_mii_ioctl( & dev- & gt; mii, if_mii(rq), cmd, NULL);
}

static struct ethtool_ops qf9700_android_ethtool_ops = {
.get_drvinfo = qf9700_android_get_drvinfo,
.get_link = qf9700_android_get_link,
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
.get_eeprom_len = qf9700_android_get_eeprom_len,
.get_eeprom = qf9700_android_get_eeprom,
.get_settings = usbnet_get_settings,
.set_settings = usbnet_set_settings,
.nway_reset = usbnet_nway_reset,
};

static void qf9700_android_set_multicast(struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
/* We use the 20 byte dev- & gt; data for our 8 byte filter buffer
* to avoid allocating memory that is tricky to free later */
u8 *hashes = (u8 *) & dev- & gt; data;
u8 rx_ctl = 0x31; // enable, disable_long, disable_crc

memset(hashes, 0x00, QF_MCAST_SIZE);
hashes[QF_MCAST_SIZE - 1] |= 0x80; /* broadcast address */

if (net- & gt; flags & IFF_PROMISC) {
rx_ctl |= 0x02;
} else if (net- & gt; flags & IFF_ALLMULTI || net- & gt; mc_count & gt; QF_MCAST_MAX) {
rx_ctl |= 0x04;
} else if (net- & gt; mc_count) {
struct dev_mc_list *mc_list = net- & gt; mc_list;
int i;

for (i = 0; i & lt; net- & gt; mc_count; i++, mc_list = mc_list- & gt; next) {
u32 crc = ether_crc(ETH_ALEN, mc_list- & gt; dmi_addr) & gt; & gt; 26;
hashes[crc & gt; & gt; 3] |= 1 & lt; & lt; (crc & 0x7);
}
}

qf_write_async(dev, MAR, QF_MCAST_SIZE, hashes);
qf_write_reg_async(dev, RCR, rx_ctl);
}

static int qf9700_android_bind(struct usbnet *dev, struct usb_interface *intf)
{
int ret;

ret = usbnet_get_endpoints(dev, intf);
if (ret)
goto out;

dev- & gt; net- & gt; do_ioctl = qf9700_android_ioctl;
dev- & gt; net- & gt; set_multicast_list = qf9700_android_set_multicast;
dev- & gt; net- & gt; ethtool_ops = & qf9700_android_ethtool_ops;
dev- & gt; net- & gt; hard_header_len += QF_TX_OVERHEAD;
dev- & gt; hard_mtu = dev- & gt; net- & gt; mtu + dev- & gt; net- & gt; hard_header_len;
dev- & gt; rx_urb_size = dev- & gt; net- & gt; mtu + ETH_HLEN + QF_RX_OVERHEAD;

dev- & gt; mii.dev = dev- & gt; net;
dev- & gt; mii.mdio_read = qf9700_android_mdio_read;
dev- & gt; mii.mdio_write = qf9700_android_mdio_write;
dev- & gt; mii.phy_id_mask = 0x1f;
dev- & gt; mii.reg_num_mask = 0x1f;

/* reset the qf9700_android */
qf_write_reg(dev, NCR, 1);
udelay(20);

/* read MAC */
if (qf_read(dev, PAR, ETH_ALEN, dev- & gt; net- & gt; dev_addr) & lt; 0) {
printk(KERN_ERR " Error reading MAC address\n " );
ret = -ENODEV;
goto out;
}

/* power up and reset phy */
qf_write_reg(dev, PRR, 1);
udelay(20 * 1000); // at least 10ms, here 20ms for safe
qf_write_reg(dev, PRR, 0);
udelay(2 * 1000); // at least 1ms, here 2ms for reading right register

/* receive broadcast packets */
qf9700_android_set_multicast(dev- & gt; net);

qf9700_android_mdio_write(dev- & gt; net, dev- & gt; mii.phy_id, MII_BMCR, BMCR_RESET);
qf9700_android_mdio_write(dev- & gt; net, dev- & gt; mii.phy_id, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
mii_nway_restart( & dev- & gt; mii);

out:
return ret;
}

static int qf9700_android_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
u8 status;
int len;

/* format:
b0: rx status
b1: packet length (incl crc) low
b2: packet length (incl crc) high
b3..n-4: packet data
bn-3..bn: ethernet crc
*/

if (unlikely(skb- & gt; len & lt; QF_RX_OVERHEAD)) {
dev_err( & dev- & gt; udev- & gt; dev, " unexpected tiny rx frame\n " );
return 0;
}

status = skb- & gt; data[0];
len = (skb- & gt; data[1] | (skb- & gt; data[2] & lt; & lt; 8)) - 4;

if (unlikely(status & 0xbf)) {
if (status & 0x01) dev- & gt; stats.rx_fifo_errors++;
if (status & 0x02) dev- & gt; stats.rx_crc_errors++;
if (status & 0x04) dev- & gt; stats.rx_frame_errors++;
if (status & 0x20) dev- & gt; stats.rx_missed_errors++;
if (status & 0x90) dev- & gt; stats.rx_length_errors++;
return 0;
}

skb_pull(skb, 3);
skb_trim(skb, len);

return 1;
}

static struct sk_buff *qf9700_android_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
{
int len;

/* format:
b0: packet length low
b1: packet length high
b3..n: packet data
*/

len = skb- & gt; len;

if (skb_headroom(skb) & lt; QF_TX_OVERHEAD) {
struct sk_buff *skb2;

skb2 = skb_copy_expand(skb, QF_TX_OVERHEAD, 0, flags);
dev_kfree_skb_any(skb);
skb = skb2;
if (!skb)
return NULL;
}

__skb_push(skb, QF_TX_OVERHEAD);

/* usbnet adds padding if length is a multiple of packet size
if so, adjust length value in header */
if ((skb- & gt; len % dev- & gt; maxpacket) == 0)
len++;

skb- & gt; data[0] = len;
skb- & gt; data[1] = len & gt; & gt; 8;

return skb;
}

static void qf9700_android_status(struct usbnet *dev, struct urb *urb)
{
int link;
u8 *buf;

/* format:
b0: net status
b1: tx status 1
b2: tx status 2
b3: rx status
b4: rx overflow
b5: rx count
b6: tx count
b7: gpr
*/

if (urb- & gt; actual_length & lt; 8)
return;

buf = urb- & gt; transfer_buffer;

link = !!(buf[0] & 0x40);
if (netif_carrier_ok(dev- & gt; net) != link) {
if (link) {
netif_carrier_on(dev- & gt; net);
usbnet_defer_kevent (dev, EVENT_LINK_RESET);
}
else
netif_carrier_off(dev- & gt; net);
devdbg(dev, " Link Status is: %d " , link);
}
}

static int qf9700_android_link_reset(struct usbnet *dev)
{
struct ethtool_cmd ecmd;

mii_check_media( & dev- & gt; mii, 1, 1);
mii_ethtool_gset( & dev- & gt; mii, & ecmd);

devdbg(dev, " link_reset() speed: %d duplex: %d " ,
ecmd.speed, ecmd.duplex);

return 0;
}

static const struct driver_info qf9700_android_info = {
.description = " QF9700_ANDROID USB Ethernet " ,
.flags = FLAG_ETHER,
.bind = qf9700_android_bind,
.rx_fixup = qf9700_android_rx_fixup,
.tx_fixup = qf9700_android_tx_fixup,
.status = qf9700_android_status,
.link_reset = qf9700_android_link_reset,
.reset = qf9700_android_link_reset,
};

static const struct usb_device_id products[] = {
{
USB_DEVICE(0x0fe6, 0x9700), /* QF9700_ANDROID device */
.driver_info = (unsigned long) & qf9700_android_info,
},
{}, // END
};

MODULE_DEVICE_TABLE(usb, products);

static struct usb_driver qf9700_android_driver = {
.name = " qf9700_android " ,
.id_table = products,
.probe = usbnet_probe,
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
};

static int __init qf9700_android_init(void)
{
return usb_register( & qf9700_android_driver);
}

static void __exit qf9700_android_exit(void)
{
usb_deregister( & qf9700_android_driver);
}

module_init(qf9700_android_init);
module_exit(qf9700_android_exit);

MODULE_AUTHOR( " jokeliu & lt; jokeliu@163.com & gt; " );
MODULE_DESCRIPTION( " QF9700 one chip USB 1.1 ethernet devices on android platform " );
MODULE_LICENSE( " GPL " );


Android_Linux_Vista.rar > qf9700.h

/*
* Copyright (c) 2009 jokeliu@163.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* Author : jokeliujl & lt; jokeliu@163.com & gt;
* Date : 2010-10-01
*/

/* qf9700 spec. register table */
/* Registers */
#define NCR 0x00
#define NSR 0x01
#define TCR 0x02
#define TSR1 0x03
#define TSR2 0x04
#define RCR 0x05
#define RSR 0x06
#define ROCR 0x07
#define BPTR 0x08
#define FCTR 0x09
#define FCR 0x0A
#define EPCR 0x0B
#define EPAR 0x0C
#define EPDR 0x0D // 0x0D ~ 0x0E
#define WCR 0x0F
#define PAR 0x10
#define MAR 0x16
#define PRR 0x1F
#define TWPAL 0x20
#define TWPAH 0x21
#define TRPAL 0x22
#define TRPAH 0x23
#define RWPAL 0x24
#define RWPAH 0x25
#define RRPAL 0x26
#define RRPAH 0x27
#define VID 0x28
#define PID 0x2A
#define CHIPR 0x2C
#define USBDA 0xF0
#define RXC 0xF1
#define TXC_USBS 0xF2
#define USBC 0xF4

/* Bit definition for registers */
// Network Control Reg
#define NCR_RST (1 & lt; & lt; 0)
#define NCR_LBK (3 & lt; & lt; 1)
#define NCR_FDX (1 & lt; & lt; 3)
#define NCR_WAKEEN (1 & lt; & lt; 6)
// Network Status Reg
#define NQF_RXRDY (1 & lt; & lt; 0)
#define NQF_RXOV (1 & lt; & lt; 1)
#define NQF_TX1END (1 & lt; & lt; 2)
#define NQF_TX2END (1 & lt; & lt; 3)
#define NQF_TXFULL (1 & lt; & lt; 4)
#define NQF_WAKEST (1 & lt; & lt; 5)
#define NQF_LINKST (1 & lt; & lt; 6)
#define NQF_SPEED (1 & lt; & lt; 7)
// Tx Control Reg
#define TCR_CRC_DIS (1 & lt; & lt; 1)
#define TCR_PAD_DIS (1 & lt; & lt; 2)
#define TCR_LC_CARE (1 & lt; & lt; 3)
#define TCR_CRS_CARE (1 & lt; & lt; 4)
#define TCR_EXCECM (1 & lt; & lt; 5)
#define TCR_LF_EN (1 & lt; & lt; 6)
// Tx Status Reg for Packet 1
#define TSR1_EC (1 & lt; & lt; 2)
#define TSR1_COL (1 & lt; & lt; 3)
#define TSR1_LC (1 & lt; & lt; 4)
#define TSR1_NC (1 & lt; & lt; 5)
#define TSR1_LOC (1 & lt; & lt; 6)
#define TSR1_TLF (1 & lt; & lt; 7)
// Tx Status Reg for Packet 2
#define TSR2_EC (1 & lt; & lt; 2)
#define TSR2_COL (1 & lt; & lt; 3)
#define TSR2_LC (1 & lt; & lt; 4)
#define TSR2_NC (1 & lt; & lt; 5)
#define TSR2_LOC (1 & lt; & lt; 6)
#define TSR2_TLF (1 & lt; & lt; 7)
// Rx Control Reg
#define RCR_RXEN (1 & lt; & lt; 0)
#define RCR_PRMSC (1 & lt; & lt; 1)
#define RCR_RUNT (1 & lt; & lt; 2)
#define RCR_ALL (1 & lt; & lt; 3)
#define RCR_DIS_CRC (1 & lt; & lt; 4)
#define RCR_DIS_LONG (1 & lt; & lt; 5)
// Rx Status Reg
#define RQF_AE (1 & lt; & lt; 2)
#define RQF_MF (1 & lt; & lt; 6)
#define RQF_RF (1 & lt; & lt; 7)
// Recv Overflow Counter Reg
#define ROCR_ROC (0x7F & lt; & lt; 0)
#define ROCR_RXFU (1 & lt; & lt; 7)
// Back Pressure Threshold Reg
#define BPTR_JPT (0x0F & lt; & lt; 0)
#define BPTR_BPHW (0x0F & lt; & lt; 4)
// Flow Control Threshold Reg
#define FCTR_LWOT (0x0F & lt; & lt; 0)
#define FCTR_HWOT (0x0F & lt; & lt; 4)
// rx/tx Flow Control Reg
#define FCR_FLCE (1 & lt; & lt; 0)
#define FCR_BKPA (1 & lt; & lt; 4)
#define FCR_TXPEN (1 & lt; & lt; 5)
#define FCR_TXPF (1 & lt; & lt; 6)
#define FCR_TXP0 (1 & lt; & lt; 7)
// EEPROM & PHY Control Reg
#define EPCR_ERRE (1 & lt; & lt; 0)
#define EPCR_ERPRW (1 & lt; & lt; 1)
#define EPCR_ERPRR (1 & lt; & lt; 2)
#define EPCR_EPOS (1 & lt; & lt; 3)
#define EPCR_WEP (1 & lt; & lt; 4)
// EEPROM & PHY Address Reg
#define EPAR_EROA (0x3F & lt; & lt; 0)
#define EPAR_PHY_ADR (0x03 & lt; & lt; 6)
// Wakeup Control Reg
#define WCR_MAGICST (1 & lt; & lt; 0)
#define WCR_LINKST (1 & lt; & lt; 2)
#define WCR_MAGICEN (1 & lt; & lt; 3)
#define WCR_LINKEN (1 & lt; & lt; 5)
// Phy Reset Reg
#define PRR_PHY_RST (1 & lt; & lt; 0)
// USB Device Address Reg
#define USBDA_USBFA (0x7F & lt; & lt; 0)
// TX packet Counter & USB Status Reg
#define TXC_USBS_TXC0 (1 & lt; & lt; 0)
#define TXC_USBS_TXC1 (1 & lt; & lt; 1)
#define TXC_USBS_TXC2 (1 & lt; & lt; 2)
#define TXC_USBS_EP1RDY (1 & lt; & lt; 5)
#define TXC_USBS_SUSFLAG (1 & lt; & lt; 6)
#define TXC_USBS_RXFAULT (1 & lt; & lt; 7)
// USB Control Reg
#define USBC_EP3NAK (1 & lt; & lt; 4)
#define USBC_EP3ACK (1 & lt; & lt; 5)

/* Variables */
#define QF_RD_REGS 0x00
#define QF_WR_REGS 0x01
#define QF_WR_REG 0x03
#define QF_REQ_RD_REG (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
#define QF_REQ_WR_REG (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE)

#define QF_SHARE_TIMEOUT 1000
#define QF_EEPROM_LEN 256
#define QF_MCAST_SIZE 8
#define QF_MCAST_MAX 64
#define QF_TX_OVERHEAD 2 // 2bytes header
#define QF_RX_OVERHEAD 7 // 3bytes header + 4crc tail

/*----------------------------------------------------------------------------------------------*/


Android_Linux_Vista.rar > qf9700.c

/*
* QF9700 one chip USB 1.1 ethernet devices
*
* Author : jokeliujl & lt; jokeliu@163.com & gt;
* Date : 2010-10-01
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed " as is " without any warranty of any
* kind, whether express or implied.
*/

//#define DEBUG

#include & lt; linux/module.h & gt;
#include & lt; linux/sched.h & gt;
#include & lt; linux/stddef.h & gt;
#include & lt; linux/init.h & gt;
#include & lt; linux/netdevice.h & gt;
#include & lt; linux/etherdevice.h & gt;
#include & lt; linux/ethtool.h & gt;
#include & lt; linux/mii.h & gt;
#include & lt; linux/usb.h & gt;
#include & lt; linux/crc32.h & gt;
#include & lt; linux/usb/usbnet.h & gt;

#include " qf9700.h "

/* ------------------------------------------------------------------------------------------ */
/* qf9700 mac and phy operations */
/* qf9700 read some registers from MAC */
static int qf_read(struct usbnet *dev, u8 reg, u16 length, void *data)
{
void *buf;
int err = -ENOMEM;

devdbg(dev, " qf_read() reg=0x%02x length=%d " , reg, length);

buf = kmalloc(length, GFP_KERNEL);
if (!buf)
goto out;

err = usb_control_msg(dev- & gt; udev, usb_rcvctrlpipe(dev- & gt; udev, 0),
QF_RD_REGS, QF_REQ_RD_REG,
0, reg, buf, length, USB_CTRL_SET_TIMEOUT);
if (err == length)
memcpy(data, buf, length);
else if (err & gt; = 0)
err = -EINVAL;
kfree(buf);

out:
return err;
}

/* qf9700 write some registers to MAC */
static int qf_write(struct usbnet *dev, u8 reg, u16 length, void *data)
{
void *buf = NULL;
int err = -ENOMEM;

devdbg(dev, " qf_write() reg=0x%02x, length=%d " , reg, length);

if (data) {
buf = kmalloc(length, GFP_KERNEL);
if (!buf)
goto out;
memcpy(buf, data, length);
}

err = usb_control_msg(dev- & gt; udev, usb_sndctrlpipe(dev- & gt; udev, 0),
QF_WR_REGS, QF_REQ_WR_REG,
0, reg, buf, length, USB_CTRL_SET_TIMEOUT);
kfree(buf);
if (err & gt; = 0 & & err & lt; length)
err = -EINVAL;
out:
return err;
}

/* qf9700 read one register from MAC */
static int qf_read_reg(struct usbnet *dev, u8 reg, u8 *value)
{
return qf_read(dev, reg, 1, value);
}

/* qf9700 write one register to MAC */
static int qf_write_reg(struct usbnet *dev, u8 reg, u8 value)
{
devdbg(dev, " qf_write_reg() reg=0x%02x, value=0x%02x " , reg, value);
return usb_control_msg(dev- & gt; udev, usb_sndctrlpipe(dev- & gt; udev, 0),
QF_WR_REG, QF_REQ_WR_REG,
value, reg, NULL, 0, USB_CTRL_SET_TIMEOUT);
}

/* async mode for writing registers or reg blocks */
static void qf_write_async_callback(struct urb *urb)
{
struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb- & gt; context;

if (urb- & gt; status & lt; 0)
printk(KERN_DEBUG " qf_write_async_callback() failed with %d\n " , urb- & gt; status);

kfree(req);
usb_free_urb(urb);
}

static void qf_write_async_helper(struct usbnet *dev, u8 reg, u8 value, u16 length, void *data)
{
struct usb_ctrlrequest *req;
struct urb *urb;
int status;

urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
deverr(dev, " Error allocating URB in qf_write_async_helper! " );
return;
}

req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
if (!req) {
deverr(dev, " Failed to allocate memory for control request " );
usb_free_urb(urb);
return;
}

req- & gt; bRequestType = QF_REQ_WR_REG;
req- & gt; bRequest = length ? QF_WR_REGS : QF_WR_REG;
req- & gt; wValue = cpu_to_le16(value);
req- & gt; wIndex = cpu_to_le16(reg);
req- & gt; wLength = cpu_to_le16(length);

usb_fill_control_urb(urb, dev- & gt; udev, usb_sndctrlpipe(dev- & gt; udev, 0),
(void *)req, data, length,
qf_write_async_callback, req);

status = usb_submit_urb(urb, GFP_ATOMIC);
if (status & lt; 0) {
deverr(dev, " Error submitting the control message: status=%d " ,
status);
kfree(req);
usb_free_urb(urb);
}

return;
}

static void qf_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
{
devdbg(dev, " qf_write_async() reg=0x%02x length=%d " , reg, length);

qf_write_async_helper(dev, reg, 0, length, data);
}

static void qf_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
{
devdbg(dev, " qf_write_reg_async() reg=0x%02x value=0x%02x " , reg, value);

qf_write_async_helper(dev, reg, value, 0, NULL);
}

/* qf9700 read one word from phy or eeprom */
static int qf_share_read_word(struct usbnet *dev, int phy, u8 reg, __le16 *value)
{
int ret, i;

mutex_lock( & dev- & gt; phy_mutex);

qf_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
qf_write_reg(dev, EPCR, phy ? 0xc : 0x4);

for (i = 0; i & lt; QF_SHARE_TIMEOUT; i++) {
u8 tmp;

udelay(1);
ret = qf_read_reg(dev, EPCR, & tmp);
if (ret & lt; 0)
goto out;

/* ready */
if ((tmp & 1) == 0)
break;
}

if (i & gt; = QF_SHARE_TIMEOUT) {
deverr(dev, " %s read timed out! " , phy ? " phy " : " eeprom " );
ret = -EIO;
goto out;
}

qf_write_reg(dev, EPCR, 0x0);
ret = qf_read(dev, EPDR, 2, value);

devdbg(dev, " read shared %d 0x%02x returned 0x%04x, %d " ,
phy, reg, *value, ret);

out:
mutex_unlock( & dev- & gt; phy_mutex);
return ret;
}

/* write one word to phy or eeprom */
static int qf_share_write_word(struct usbnet *dev, int phy, u8 reg, __le16 value)
{
int ret, i;

mutex_lock( & dev- & gt; phy_mutex);

ret = qf_write(dev, EPDR, 2, & value);
if (ret & lt; 0)
goto out;

qf_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
qf_write_reg(dev, EPCR, phy ? 0x1a : 0x12);

for (i = 0; i & lt; QF_SHARE_TIMEOUT; i++) {
u8 tmp;

udelay(1);
ret = qf_read_reg(dev, EPCR, & tmp);
if (ret & lt; 0)
goto out;

/* ready */
if ((tmp & 1) == 0)
break;
}

if (i & gt; = QF_SHARE_TIMEOUT) {
deverr(dev, " %s write timed out! " , phy ? " phy " : " eeprom " );
ret = -EIO;
goto out;
}

qf_write_reg(dev, EPCR, 0x0);

out:
mutex_unlock( & dev- & gt; phy_mutex);
return ret;
}

static int qf_read_eeprom_word(struct usbnet *dev, u8 offset, void *value)
{
return qf_share_read_word(dev, 0, offset, value);
}


static int qf9700_get_eeprom_len(struct net_device *dev)
{
return QF_EEPROM_LEN;
}

/* get qf9700 eeprom information */
static int qf9700_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, u8 * data)
{
struct usbnet *dev = netdev_priv(net);
__le16 *ebuf = (__le16 *) data;
int i;

/* access is 16bit */
if ((eeprom- & gt; offset % 2) || (eeprom- & gt; len % 2))
return -EINVAL;

for (i = 0; i & lt; eeprom- & gt; len / 2; i++) {
if (qf_read_eeprom_word(dev, eeprom- & gt; offset / 2 + i, & ebuf[i]) & lt; 0)
return -EINVAL;
}
return 0;
}

/* qf9700 mii-phy register read by word */
static int qf9700_mdio_read(struct net_device *netdev, int phy_id, int loc)
{
struct usbnet *dev = netdev_priv(netdev);

__le16 res;

if (phy_id) {
devdbg(dev, " Only internal phy supported " );
return 0;
}

qf_share_read_word(dev, 1, loc, & res);

devdbg(dev,
" qf9700_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x " ,
phy_id, loc, le16_to_cpu(res));

return le16_to_cpu(res);
}

/* qf9700 mii-phy register write by word */
static void qf9700_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
{
struct usbnet *dev = netdev_priv(netdev);
__le16 res = cpu_to_le16(val);

if (phy_id) {
devdbg(dev, " Only internal phy supported " );
return;
}

devdbg(dev, " qf9700_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x " ,
phy_id, loc, val);

qf_share_write_word(dev, 1, loc, res);
}

/*-------------------------------------------------------------------------------------------*/

static void qf9700_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
{
/* Inherit standard device info */
usbnet_get_drvinfo(net, info);
info- & gt; eedump_len = QF_EEPROM_LEN;
}

static u32 qf9700_get_link(struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);

return mii_link_ok( & dev- & gt; mii);
}

static int qf9700_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
{
struct usbnet *dev = netdev_priv(net);

return generic_mii_ioctl( & dev- & gt; mii, if_mii(rq), cmd, NULL);
}

static struct ethtool_ops qf9700_ethtool_ops = {
.get_drvinfo = qf9700_get_drvinfo,
.get_link = qf9700_get_link,
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
.get_eeprom_len = qf9700_get_eeprom_len,
.get_eeprom = qf9700_get_eeprom,
.get_settings = usbnet_get_settings,
.set_settings = usbnet_set_settings,
.nway_reset = usbnet_nway_reset,
};

static void qf9700_set_multicast(struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
/* We use the 20 byte dev- & gt; data for our 8 byte filter buffer
* to avoid allocating memory that is tricky to free later */
u8 *hashes = (u8 *) & dev- & gt; data;
u8 rx_ctl = 0x31; // enable, disable_long, disable_crc

memset(hashes, 0x00, QF_MCAST_SIZE);
hashes[QF_MCAST_SIZE - 1] |= 0x80; /* broadcast address */

if (net- & gt; flags & IFF_PROMISC) {
rx_ctl |= 0x02;
} else if (net- & gt; flags & IFF_ALLMULTI || net- & gt; mc_count & gt; QF_MCAST_MAX) {
rx_ctl |= 0x04;
} else if (net- & gt; mc_count) {
struct dev_mc_list *mc_list = net- & gt; mc_list;
int i;

for (i = 0; i & lt; net- & gt; mc_count; i++, mc_list = mc_list- & gt; next) {
u32 crc = ether_crc(ETH_ALEN, mc_list- & gt; dmi_addr) & gt; & gt; 26;
hashes[crc & gt; & gt; 3] |= 1 & lt; & lt; (crc & 0x7);
}
}

qf_write_async(dev, MAR, QF_MCAST_SIZE, hashes);
qf_write_reg_async(dev, RCR, rx_ctl);
}

static int qf9700_bind(struct usbnet *dev, struct usb_interface *intf)
{
int ret;

ret = usbnet_get_endpoints(dev, intf);
if (ret)
goto out;

dev- & gt; net- & gt; do_ioctl = qf9700_ioctl;
dev- & gt; net- & gt; set_multicast_list = qf9700_set_multicast;
dev- & gt; net- & gt; ethtool_ops = & qf9700_ethtool_ops;
dev- & gt; net- & gt; hard_header_len += QF_TX_OVERHEAD;
dev- & gt; hard_mtu = dev- & gt; net- & gt; mtu + dev- & gt; net- & gt; hard_header_len;
dev- & gt; rx_urb_size = dev- & gt; net- & gt; mtu + ETH_HLEN + QF_RX_OVERHEAD;

dev- & gt; mii.dev = dev- & gt; net;
dev- & gt; mii.mdio_read = qf9700_mdio_read;
dev- & gt; mii.mdio_write = qf9700_mdio_write;
dev- & gt; mii.phy_id_mask = 0x1f;
dev- & gt; mii.reg_num_mask = 0x1f;

/* reset the qf9700 */
qf_write_reg(dev, NCR, 1);
udelay(20);

/* read MAC */
if (qf_read(dev, PAR, ETH_ALEN, dev- & gt; net- & gt; dev_addr) & lt; 0) {
printk(KERN_ERR " Error reading MAC address\n " );
ret = -ENODEV;
goto out;
}

/* power up and reset phy */
qf_write_reg(dev, PRR, 1);
udelay(20 * 1000); // at least 10ms, here 20ms for safe
qf_write_reg(dev, PRR, 0);
udelay(2 * 1000); // at least 1ms, here 2ms for reading right register

/* receive broadcast packets */
qf9700_set_multicast(dev- & gt; net);

qf9700_mdio_write(dev- & gt; net, dev- & gt; mii.phy_id, MII_BMCR, BMCR_RESET);
qf9700_mdio_write(dev- & gt; net, dev- & gt; mii.phy_id, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
mii_nway_restart( & dev- & gt; mii);

out:
return ret;
}

static int qf9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
u8 status;
int len;

/* format:
b0: rx status
b1: packet length (incl crc) low
b2: packet length (incl crc) high
b3..n-4: packet data
bn-3..bn: ethernet crc
*/

if (unlikely(skb- & gt; len & lt; QF_RX_OVERHEAD)) {
dev_err( & dev- & gt; udev- & gt; dev, " unexpected tiny rx frame\n " );
return 0;
}

status = skb- & gt; data[0];
len = (skb- & gt; data[1] | (skb- & gt; data[2] & lt; & lt; 8)) - 4;

if (unlikely(status & 0xbf)) {
if (status & 0x01) dev- & gt; stats.rx_fifo_errors++;
if (status & 0x02) dev- & gt; stats.rx_crc_errors++;
if (status & 0x04) dev- & gt; stats.rx_frame_errors++;
if (status & 0x20) dev- & gt; stats.rx_missed_errors++;
if (status & 0x90) dev- & gt; stats.rx_length_errors++;
return 0;
}

skb_pull(skb, 3);
skb_trim(skb, len);

return 1;
}

static struct sk_buff *qf9700_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
{
int len;

/* format:
b0: packet length low
b1: packet length high
b3..n: packet data
*/

len = skb- & gt; len;

if (skb_headroom(skb) & lt; QF_TX_OVERHEAD) {
struct sk_buff *skb2;

skb2 = skb_copy_expand(skb, QF_TX_OVERHEAD, 0, flags);
dev_kfree_skb_any(skb);
skb = skb2;
if (!skb)
return NULL;
}

__skb_push(skb, QF_TX_OVERHEAD);

/* usbnet adds padding if length is a multiple of packet size
if so, adjust length value in header */
if ((skb- & gt; len % dev- & gt; maxpacket) == 0)
len++;

skb- & gt; data[0] = len;
skb- & gt; data[1] = len & gt; & gt; 8;

return skb;
}

static void qf9700_status(struct usbnet *dev, struct urb *urb)
{
int link;
u8 *buf;

/* format:
b0: net status
b1: tx status 1
b2: tx status 2
b3: rx status
b4: rx overflow
b5: rx count
b6: tx count
b7: gpr
*/

if (urb- & gt; actual_length & lt; 8)
return;

buf = urb- & gt; transfer_buffer;

link = !!(buf[0] & 0x40);
if (netif_carrier_ok(dev- & gt; net) != link) {
if (link) {
netif_carrier_on(dev- & gt; net);
usbnet_defer_kevent (dev, EVENT_LINK_RESET);
}
else
netif_carrier_off(dev- & gt; net);
devdbg(dev, " Link Status is: %d " , link);
}
}

static int qf9700_link_reset(struct usbnet *dev)
{
struct ethtool_cmd ecmd;

mii_check_media( & dev- & gt; mii, 1, 1);
mii_ethtool_gset( & dev- & gt; mii, & ecmd);

devdbg(dev, " link_reset() speed: %d duplex: %d " ,
ecmd.speed, ecmd.duplex);

return 0;
}

static const struct driver_info qf9700_info = {
.description = " QF9700 USB Ethernet " ,
.flags = FLAG_ETHER,
.bind = qf9700_bind,
.rx_fixup = qf9700_rx_fixup,
.tx_fixup = qf9700_tx_fixup,
.status = qf9700_status,
.link_reset = qf9700_link_reset,
.reset = qf9700_link_reset,
};

static const struct usb_device_id products[] = {
{
USB_DEVICE(0x0fe6, 0x9700), /* QF9700 */
.driver_info = (unsigned long) & qf9700_info,
},
{}, // END
};

MODULE_DEVICE_TABLE(usb, products);

static struct usb_driver qf9700_driver = {
.name = " qf9700 " ,
.id_table = products,
.probe = usbnet_probe,
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
};

static int __init qf9700_init(void)
{
return usb_register( & qf9700_driver);
}

static void __exit qf9700_exit(void)
{
usb_deregister( & qf9700_driver);
}

module_init(qf9700_init);
module_exit(qf9700_exit);

MODULE_AUTHOR( " jokeliu & lt; jokeliu@163.com & gt; " );
MODULE_DESCRIPTION( " QF9700 one chip USB 1.1 ethernet devices " );
MODULE_LICENSE( " GPL " );


Android_Linux_Vista.rar > qf9700.mod.c

#include & lt; linux/module.h & gt;
#include & lt; linux/vermagic.h & gt;
#include & lt; linux/compiler.h & gt;

MODULE_INFO(vermagic, VERMAGIC_STRING);

struct module __this_module
__attribute__((section( " .gnu.linkonce.this_module " ))) = {
.name = KBUILD_MODNAME,
.init = init_module,
#ifdef CONFIG_MODULE_UNLOAD
.exit = cleanup_module,
#endif
.arch = MODULE_ARCH_INIT,
};

static const char __module_depends[]
__used
__attribute__((section( " .modinfo " ))) =
" depends=usbnet " ;

MODULE_ALIAS( " usb:v0FE6p9700d*dc*dsc*dp*ic*isc*ip* " );