Greg KH wrote:

On Wed, Aug 10, 2005 at 04:50:35PM -0700, [EMAIL PROTECTED] wrote:
+typedef struct ax88178 ax88178_t;

No typedefs in kernel code please.  Don't create new ones.

+
+static unsigned long multicast_filter_limit = 32;
+
+static void fill_skb_pool(ax88178_t *);
+static void free_skb_pool(ax88178_t *);
+static int ax88178_link_up( void* arg );
+static int async_set_registers(ax88178_t * dev, u8 index, u16 regdata1,
u16 regdata2, u16 size);

Your patch is linewrapped, and can't be applied :(

Care to try it again?

+       while(!test_bit(AX88178_UNPLUG, &dev->flags) )
+       {

Please use the proper formatting for your braces.  Same thing for your
if statements.

Also, put a space after the while and no spaces within the ().  So that
should be:
        while(!test_bit(AX88178_UNPLUG, &dev->flags)) {


+               wait_event_interruptible( dev->speed_queue, dev->state &
STATE_SPEED_CHANGE );

Again, no spaces.

+#if DEBUG

No #ifdefs in .c files.  Please use dev_dbg() instead.

thanks,

greg k-h
Alrighty... 3rd time's the charm, or so I hope.
I went ahead and cleaned up the while statements and #if while I was at.

                     Jimmy Pierce
          [EMAIL PROTECTED]
diff -urN linux/drivers/usb/Makefile linux-2.6.12.1-ax88178/drivers/usb/Makefile
--- linux/drivers/usb/Makefile  Wed Aug 10 10:38:36 2005
+++ linux-2.6.12.1-ax88178/drivers/usb/Makefile Wed Aug 10 10:37:37 2005
@@ -45,6 +45,7 @@
 obj-$(CONFIG_USB_VICAM)                += media/
 obj-$(CONFIG_USB_W9968CF)      += media/
 
+obj-$(CONFIG_USB_AX88178)      += net/
 obj-$(CONFIG_USB_CATC)         += net/
 obj-$(CONFIG_USB_KAWETH)       += net/
 obj-$(CONFIG_USB_PEGASUS)      += net/
diff -urN linux/drivers/usb/net/Makefile 
linux-2.6.12.1-ax88178/drivers/usb/net/Makefile
--- linux/drivers/usb/net/Makefile      Wed Aug 10 10:38:44 2005
+++ linux-2.6.12.1-ax88178/drivers/usb/net/Makefile     Wed Aug 10 10:37:49 2005
@@ -2,6 +2,7 @@
 # Makefile for USB Network drivers
 #
 
+obj-$(CONFIG_USB_AX88178)      += ax88178.o
 obj-$(CONFIG_USB_CATC)         += catc.o
 obj-$(CONFIG_USB_KAWETH)       += kaweth.o
 obj-$(CONFIG_USB_PEGASUS)      += pegasus.o
diff -urN linux/drivers/usb/net/Kconfig 
linux-2.6.12.1-ax88178/drivers/usb/net/Kconfig
--- linux/drivers/usb/net/Kconfig       Wed Aug 10 10:23:45 2005
+++ linux-2.6.12.1-ax88178/drivers/usb/net/Kconfig      Wed Aug 10 10:37:53 2005
@@ -7,6 +7,17 @@
 menu "USB Network Adapters"
        depends on USB && NET
 
+config USB_AX88178
+       tristate "USB AX88178 Based Ethernet device support"
+       ---help---
+         Say yes here to compile support for the Asix 88178 chipset. The
+         following adapters use this chipset:
+
+         AirLink101 AGIGAUSB 
+
+         To compile this driver as a module, choose M here: the 
+         module will be called ax88178.
+
 config USB_CATC
        tristate "USB CATC NetMate-based Ethernet device support (EXPERIMENTAL)"
        depends on EXPERIMENTAL
--- linux/drivers/usb/net/ax88178.c     Wed Dec 31 16:00:00 1969
+++ linux-2.6.12.1-ax88178/drivers/usb/net/ax88178.c    Sat Aug 13 16:53:56 2005
@@ -0,0 +1,1043 @@
+/*
+ *  Copyright (c) 2005 Jimmy Pierce ([EMAIL PROTECTED])
+ *
+ *  Based off the rtl8150 driver written by 
+ *             Petko Manolov <[EMAIL PROTECTED]>
+ *  Thanks to Jamie Painter for pointing out the multiple packets
+ *  per URB
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/signal.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/usb.h>
+#include <asm/uaccess.h>
+
+/* Version Information */
+#define DRIVER_VERSION "v0.4.0 (2005/07/18)"
+#define DRIVER_AUTHOR "Jimmy Pierce <[EMAIL PROTECTED]>"
+#define DRIVER_DESC "ax88178 usb-ethernet driver driver"
+
+#define INTBUFSIZE 512
+
+#define DEBUG 0
+
+#define AX88178_TX_TIMEOUT (HZ)
+#define RX_SKB_POOL_SIZE 8
+
+#define REG_SSMC_W     0x06
+#define REG_PHY_R      0x07
+#define REG_PHY_W      0x08
+#define REG_SMSR_R     0x09
+#define REG_HSMC_W     0x0a
+#define REG_SROMREAD_R 0x0b
+#define REG_SROMWRITE_W        0x0c
+#define REG_SROMENBL_W 0x0d
+#define REG_SROMDSBL_W 0x0e
+#define REG_RXCTRL_R   0x0f
+#define REG_RXCTRL_W   0x10
+#define REG_IPG_R      0x11
+#define REG_IPG_W      0x12
+#define REG_MAC_R      0x13
+#define REG_MAC_W      0x14
+#define REG_MFAR_R     0x15
+#define REG_MFAR_W     0x16
+#define REG_PHYADDR_R  0x19
+#define REG_MSR_R      0x1a
+#define REG_MMR_W      0x1b
+#define REG_GPIO_R     0x1e
+#define REG_GPIO_W     0x1f
+#define REG_RESET_W    0x20
+
+#define REG_UNKNOWN    0x22
+
+#define AX88178_MTU    16388
+#define AX88178_MAX_MTU 16384
+
+#define AX88178_HW_CRC          0
+#define RX_REG_SET              1
+#define AX88178_UNPLUG          2
+#define RX_URB_FAIL             3
+
+#define AX_READ_REG 0xc0
+#define AX_WRITE_REG 0x40
+
+
+#define STATE_SPEED_CHANGE 0x01
+
+/* table of devices that work with this driver */
+static struct usb_device_id ax88178_table[] = {
+       {USB_DEVICE(0x0b95, 0x1780)},
+       {}
+};
+
+MODULE_DEVICE_TABLE(usb, ax88178_table);
+
+struct ax88178 {
+       unsigned long flags;
+       struct usb_device *udev;
+       wait_queue_head_t speed_queue;
+       pid_t   speed_pid;
+       struct tasklet_struct tl;
+       struct net_device_stats stats;
+       struct net_device *netdev;
+       struct urb *rx_urb, *tx_urb, *intr_urb, *ctrl_urb;
+       struct sk_buff *tx_skb, *rx_skb;
+       struct sk_buff *rx_skb_pool[RX_SKB_POOL_SIZE];
+       spinlock_t rx_pool_lock;
+       struct usb_ctrlrequest dr;
+       int intr_interval;
+       u8 rx_creg[8];
+       u8 *intr_buff;
+       u8 phy;
+       u8 state;
+       u8 ready;
+       u8 rx_skb_fix_data[AX88178_MTU + 16];
+       u8 tx_skb_fix_data[AX88178_MTU + 16];
+};
+
+typedef struct ax88178 ax88178_t;
+
+static unsigned long multicast_filter_limit = 32;
+
+static void fill_skb_pool(ax88178_t *);
+static void free_skb_pool(ax88178_t *);
+static int ax88178_link_up( void* arg );
+static int async_set_registers(ax88178_t * dev, u8 index, u16 regdata1, u16 
regdata2, u16 size);
+static inline struct sk_buff *pull_skb(ax88178_t *);
+static void ax88178_disconnect(struct usb_interface *intf);
+static int ax88178_probe(struct usb_interface *intf,
+                          const struct usb_device_id *id);
+
+
+static const char driver_name [] = "ax88178";
+
+static struct usb_driver ax88178_driver = {
+       .owner =        THIS_MODULE,
+       .name =         driver_name,
+       .probe =        ax88178_probe,
+       .disconnect =   ax88178_disconnect,
+       .id_table =     ax88178_table,
+};
+
+/*
+**
+**     device related part of the code
+**
+*/
+static int get_registers(ax88178_t *dev, u8 index, u16 regdata1, u16 regdata2, 
u16 size, void *data)
+{
+       return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
+                              index, AX_READ_REG,
+                              regdata1, regdata2, data, size, HZ / 2);
+}
+
+static int set_registers(ax88178_t *dev, u8 index, u16 regdata1, u16 regdata2, 
u16 size, void *data)
+{
+               
+       return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
+                              index, AX_WRITE_REG,
+                              regdata1, regdata2, data, size, HZ / 2);
+}
+
+static int ax88178_link_up( void *arg )
+{
+       ax88178_t *dev = (ax88178_t*)arg;
+       u8 data[8];
+       u8 speed[2];
+       u8 duplex[2];
+       u16 fd;
+
+       while(!test_bit(AX88178_UNPLUG, &dev->flags) )
+       {
+               wait_event_interruptible( dev->speed_queue, dev->state & 
STATE_SPEED_CHANGE );
+
+               set_registers( dev, REG_SSMC_W, 0, 0, 0, NULL );
+               get_registers( dev, REG_PHY_R, dev->phy, 0x0005, 2, data );
+
+               duplex[0] = data[0];
+               speed[0] = data[1];
+               get_registers( dev, REG_PHY_R, dev->phy, 0x000a, 2, data );
+
+               speed[1] = data[1];
+               duplex[1] = data[0];
+
+               set_registers( dev, REG_HSMC_W, 0, 0, 0, NULL );
+               
+               if( !(speed[0] == 0x45) &&
+                   !(speed[0] == 0x00) && 
+                   !(speed[0] == 0xc5) )
+               {
+                       printk( "Unrecognized speed settings: %02x %02x\n", 
speed[0], speed[1] );
+               }
+
+               dev_dbg( &dev, "DUPLEX: %02x %02x, SPEED: %02x %02x\n", 
duplex[0], duplex[1], speed[0], speed[1] );
+               if( duplex[0] == 0xe1 )
+               {
+                       fd = 0x0002;
+                       dev_dbg( &dev, "Full Duplex " );
+               }
+               else
+               {
+                       fd = 0x0000;
+                       dev_dbg( &dev, "Half Duplex " );
+               }
+               if( (speed[0] & 0xf0) == 0 )
+               {
+                       fd |= 0x0104;
+                       clear_bit(RX_REG_SET, &dev->flags);
+                       set_registers( dev, REG_MMR_W, fd, 0, 0, NULL );
+                       dev_dbg( &dev, "10Mbit Link\n" );
+               }
+               else if( (speed[0] & 0xf0) == 0x40 )
+               {
+                       fd |= 0x0334;
+                       clear_bit(RX_REG_SET, &dev->flags);
+                       set_registers( dev, REG_MMR_W, fd, 0, 0, NULL );
+                       dev_dbg( &dev, "100Mbit Link\n" );
+               }
+               else if( (speed[0] & 0xf0) == 0xc0 )
+               {
+                       fd |= 0x013f;
+                       clear_bit(RX_REG_SET, &dev->flags);
+                       set_registers( dev, REG_MMR_W, fd, 0, 0, NULL );
+                       dev_dbg( &dev, "1000Mbit Link\n" );
+               }
+               data[0] = 0;
+               data[1] = 0;
+               data[2] = 0;
+               data[3] = 0x80;
+               data[4] = 0;
+               data[5] = 0;
+               data[6] = 0;
+               data[7] = 0;
+               set_registers( dev, REG_MFAR_W, 0, 0, 8, data );
+       
+               dev->state &= ~STATE_SPEED_CHANGE;
+               if( !dev->ready )
+               {
+                       dev->ready = 1;
+                       wake_up_interruptible( &dev->speed_queue );
+               }
+       }
+       return 0;
+} 
+
+static void set_ctrl_callback(struct urb *urb, struct pt_regs *regs)
+{
+       ax88178_t *dev;
+       switch (urb->status) {
+       case 0:
+               break;
+       case -EINPROGRESS:
+               break;
+       case -ENOENT:
+               break;
+       default:
+               warn("ctrl urb status %d", urb->status);
+       }
+       dev = urb->context;
+       clear_bit(RX_REG_SET, &dev->flags);
+}
+
+static int async_set_registers(ax88178_t * dev, u8 index, u16 regdata1, u16 
regdata2, u16 size)
+{
+       int ret;
+
+       if (test_bit(RX_REG_SET, &dev->flags))
+               return -EAGAIN;
+
+       dev->dr.bRequestType = AX_WRITE_REG;
+       dev->dr.bRequest = index;
+       dev->dr.wValue = cpu_to_le16(regdata1);
+       dev->dr.wIndex = cpu_to_le16(regdata2);
+       dev->dr.wLength = cpu_to_le16(size);
+       dev->ctrl_urb->transfer_buffer_length = size;
+       usb_fill_control_urb(dev->ctrl_urb, dev->udev,
+                        usb_sndctrlpipe(dev->udev, 0), (char *) &dev->dr,
+                        dev->rx_creg, size, set_ctrl_callback, dev);
+       if ((ret = usb_submit_urb(dev->ctrl_urb, GFP_ATOMIC)))
+               err("control request submission failed: %d", ret);
+       else
+               set_bit(RX_REG_SET, &dev->flags);
+
+       return ret;
+}
+
+static inline void set_ethernet_addr(ax88178_t * dev)
+{
+       u8 node_id[6];
+
+       get_registers(dev, REG_MAC_R, 0, 0, sizeof(node_id), node_id);
+       memcpy(dev->netdev->dev_addr, node_id, sizeof(node_id));
+}
+
+static int ax88178_set_mac_address(struct net_device *netdev, void *p)
+{
+       struct sockaddr *addr = p;
+       ax88178_t *dev = netdev_priv(netdev);
+       int i;
+
+       if (netif_running(netdev))
+               return -EBUSY;
+
+       memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+       dbg("%s: Setting MAC address to ", netdev->name);
+       for (i = 0; i < 5; i++)
+               dbg("%02X:", netdev->dev_addr[i]);
+       dbg("%02X\n", netdev->dev_addr[i]);
+       return (set_registers(dev, REG_MAC_W, 0, 0, sizeof(netdev->dev_addr), 
netdev->dev_addr) < 0);
+}
+
+static int ax88178_reset(ax88178_t * dev)
+{
+       u8 data = 0x4c;
+
+       set_registers(dev, REG_RESET_W, data, 0, 0, 0);
+
+       return 1;
+}
+
+static int alloc_all_urbs(ax88178_t * dev)
+{
+       dev->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!dev->rx_urb)
+               return 0;
+       dev->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!dev->tx_urb) {
+               usb_free_urb(dev->rx_urb);
+               return 0;
+       }
+       dev->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!dev->intr_urb) {
+               usb_free_urb(dev->rx_urb);
+               usb_free_urb(dev->tx_urb);
+               return 0;
+       }
+       dev->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!dev->intr_urb) {
+               usb_free_urb(dev->rx_urb);
+               usb_free_urb(dev->tx_urb);
+               usb_free_urb(dev->intr_urb);
+               return 0;
+       }
+
+       return 1;
+}
+
+static void free_all_urbs(ax88178_t * dev)
+{
+       usb_free_urb(dev->rx_urb);
+       usb_free_urb(dev->tx_urb);
+       usb_free_urb(dev->intr_urb);
+       usb_free_urb(dev->ctrl_urb);
+}
+
+static void unlink_all_urbs(ax88178_t * dev)
+{
+       usb_kill_urb(dev->rx_urb);
+       usb_kill_urb(dev->tx_urb);
+       usb_kill_urb(dev->intr_urb);
+       usb_kill_urb(dev->ctrl_urb);
+}
+
+static inline struct sk_buff *pull_skb(ax88178_t *dev)
+{
+       struct sk_buff *skb;
+       int i;
+
+       for (i = 0; i < RX_SKB_POOL_SIZE; i++) {
+               if (dev->rx_skb_pool[i]) {
+                       skb = dev->rx_skb_pool[i];
+                       dev->rx_skb_pool[i] = NULL;
+                       return skb;
+               }
+       }
+       return NULL;
+}
+
+static void read_bulk_callback(struct urb *urb, struct pt_regs *regs)
+{
+       ax88178_t *dev = urb->context;
+       unsigned pkt_len, res;
+       unsigned int length;
+       struct net_device *netdev;
+       u8 *pointer;
+       if (!dev)
+               return;
+       if (test_bit(AX88178_UNPLUG, &dev->flags))
+               return;
+       netdev = dev->netdev;
+       if (!netif_device_present(netdev))
+               return;
+
+       switch (urb->status) {
+       case 0:
+               break;
+       case -ENOENT:
+               return; // the urb is in unlink state 
+       case -ETIMEDOUT:
+               warn("may be reset is needed?..");
+               goto goon;
+       default:
+               warn("Rx status %d", urb->status);
+               goto goon;
+       }
+
+       res = urb->actual_length;
+       if( !res )
+               goto goon;
+
+       if (!dev->rx_skb)
+               goto resched;
+       // protect against short packets (tell me why we got some?!?) 
+       if (urb->actual_length < 4)
+               goto goon;
+
+       pointer = dev->rx_skb_fix_data;
+
+       length = cpu_to_le16( *((u16*)(pointer)) );
+       pkt_len = res;
+       while( pkt_len > 4 )
+       {
+
+               if( length <= AX88178_MTU )
+               {
+               memcpy( dev->rx_skb->data, pointer + 4, length );
+
+               skb_put(dev->rx_skb, length);
+               dev->rx_skb->protocol = eth_type_trans(dev->rx_skb, netdev);
+               netif_rx(dev->rx_skb);
+               dev->stats.rx_packets++;
+               dev->stats.rx_bytes += pkt_len;
+
+               spin_lock(&dev->rx_pool_lock);
+               dev->rx_skb = pull_skb(dev);
+               spin_unlock(&dev->rx_pool_lock);
+               if (!dev->rx_skb)
+                       goto resched;
+
+               }
+               else
+               {
+                       printk( "length: %d data: %02x%02x %02x%02x\n", length, 
pointer[0], pointer[1], pointer[2], pointer[3] );
+               }
+
+               if( length & 0x0001 )
+                       length++;
+               if( length > pkt_len || length < 0 )
+                               printk( "***** urb_len: %d pkt_len: %d %02x%02x 
%02x%02x %02x%02x %02x%02x off: %d\n", urb->actual_length, pkt_len, 
pointer[-4], pointer[-3], pointer[-2], pointer[-1], pointer[0], pointer[1], 
pointer[2], pointer[3], (int)((int)pointer - (int)dev->rx_skb_fix_data) );
+
+               do{
+                       pkt_len -= length + 4;
+                       pointer += length + 4;
+                       if( pointer > urb->actual_length + dev->rx_skb_fix_data 
)
+                       {
+                               printk( "????? pkt_len: %d %02x%02x %02x%02x 
%02x%02x %02x%02x off: %d\n", pkt_len, pointer[-4], pointer[-3], pointer[-2], 
pointer[-1], pointer[0], pointer[1], pointer[2], pointer[3], (int)((int)pointer 
- (int)dev->rx_skb_fix_data) );
+                               pkt_len = 0;
+                               break;
+                       }
+                       length = cpu_to_le16( *((u16*)(pointer)) );
+                       if( length & 0x0001 )
+                               length++;
+                       dev_dbg( &dev, "LOOP: length %d pkt: %d\n", length, 
pkt_len );
+                       if( pkt_len < 4 )
+                               break;
+               }while( length == 0 );
+       }
+goon:
+       usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 2),
+                     dev->rx_skb_fix_data, AX88178_MTU, read_bulk_callback, 
dev);
+       if (usb_submit_urb(dev->rx_urb, GFP_ATOMIC)) {
+               set_bit(RX_URB_FAIL, &dev->flags);
+               goto resched;
+       } else {
+               clear_bit(RX_URB_FAIL, &dev->flags);
+       }
+
+       return;
+resched:
+       tasklet_schedule(&dev->tl);
+}
+
+static void rx_fixup(unsigned long data)
+{
+
+        ax88178_t *dev;
+        struct sk_buff *skb;
+
+        dev = (ax88178_t *)data;
+        spin_lock_irq(&dev->rx_pool_lock);
+        fill_skb_pool(dev);
+        spin_unlock_irq(&dev->rx_pool_lock);
+        if (test_bit(RX_URB_FAIL, &dev->flags))
+                if (dev->rx_skb)
+                        goto try_again;
+        spin_lock_irq(&dev->rx_pool_lock);
+        skb = pull_skb(dev);
+        spin_unlock_irq(&dev->rx_pool_lock);
+        if (skb == NULL)
+                goto tlsched;
+        dev->rx_skb = skb;
+        usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 
2),
+                      dev->rx_skb_fix_data, AX88178_MTU, read_bulk_callback, 
dev);
+try_again:
+        if (usb_submit_urb(dev->rx_urb, GFP_ATOMIC)) {
+                set_bit(RX_URB_FAIL, &dev->flags);
+               if( test_bit(AX88178_UNPLUG, &dev->flags) )
+                       return;
+                goto tlsched;
+         } else {
+                clear_bit(RX_URB_FAIL, &dev->flags);
+        }
+
+        return;
+tlsched:
+        tasklet_schedule(&dev->tl);
+
+}
+
+static void write_bulk_callback(struct urb *urb, struct pt_regs *regs)
+{
+       ax88178_t *dev;
+       dev = urb->context;
+       if (!dev)
+               return;
+       dev_kfree_skb_irq(dev->tx_skb);
+       if (!netif_device_present(dev->netdev))
+               return;
+       if (urb->status)
+               info("%s: Tx status %d", dev->netdev->name, urb->status);
+       dev->netdev->trans_start = jiffies;
+       netif_wake_queue(dev->netdev);
+}
+
+static void intr_callback(struct urb *urb, struct pt_regs *regs)
+{
+       ax88178_t *dev;
+       __u8 *d;
+       int status;
+
+       dev = urb->context;
+       if (!dev)
+               return;
+       switch (urb->status) {
+       case 0:                 // success 
+               break;
+       case -ECONNRESET:       // unlink
+       case -ENOENT:
+       case -ESHUTDOWN:
+               return;
+       // -EPIPE:  should clear the halt 
+       default:
+               printk("%s: intr status %d", dev->netdev->name, urb->status);
+               goto resubmit;
+       }
+
+       d = urb->transfer_buffer;
+       if (d[2] & 0x04) {
+               dev->stats.tx_errors++;
+       }
+       // Report link status changes to the network stack 
+       if ((d[2] & 0x01) == 0) {
+               if (netif_carrier_ok(dev->netdev)) {
+                       netif_carrier_off(dev->netdev);
+                       printk("%s: LINK LOST\n", __func__);
+               }
+       } else {
+               if (!netif_carrier_ok(dev->netdev)) {
+                       dev->state |= STATE_SPEED_CHANGE;
+                       wake_up_interruptible( &dev->speed_queue );
+                       netif_carrier_on(dev->netdev);
+                       printk("%s: LINK CAME BACK\n", __func__);
+               }
+       }
+
+resubmit:
+       status = usb_submit_urb (urb, SLAB_ATOMIC);
+       if (status)
+               err ("can't resubmit intr, %s-%s/input0, status %d",
+                               dev->udev->bus->bus_name,
+                               dev->udev->devpath, status);
+}
+
+
+//
+//
+//     network related part of the code
+//
+
+
+static void fill_skb_pool(ax88178_t *dev)
+{
+       struct sk_buff *skb;
+       int i;
+
+       for (i = 0; i < RX_SKB_POOL_SIZE; i++) {
+               if (dev->rx_skb_pool[i])
+                       continue;
+               skb = dev_alloc_skb(AX88178_MTU + 6);
+               if (!skb) {
+                       return;
+               }
+               skb->dev = dev->netdev;
+               skb_reserve(skb, 2);
+               dev->rx_skb_pool[i] = skb;
+       }
+}
+
+static void free_skb_pool(ax88178_t *dev)
+{
+       int i;
+
+       for (i = 0; i < RX_SKB_POOL_SIZE; i++)
+               if (dev->rx_skb_pool[i])
+                       dev_kfree_skb(dev->rx_skb_pool[i]);
+}
+
+static int init_net_registers(ax88178_t * dev)
+{
+       int retval = 0;
+       u8 data[8];
+       
+       retval = set_registers( dev, REG_SROMENBL_W, 0, 0, 0, NULL );
+       if( retval < 0 )
+               goto out;
+       retval = get_registers( dev, REG_SROMREAD_R, 0x0017, 0, 2, data );
+       if( retval < 0 )
+               goto out;
+       retval = set_registers( dev, REG_SROMDSBL_W, 0, 0, 0, NULL );
+       if( retval < 0 )
+               goto out;
+       retval = set_registers( dev, REG_GPIO_W, 0x008c, 0, 0, NULL );
+       if( retval < 0 )
+               goto out;
+       retval = set_registers( dev, REG_GPIO_W, 0x001c, 0, 0, NULL );
+       if( retval < 0 )
+               goto out;
+       retval = set_registers( dev, REG_GPIO_W, 0x003c, 0, 0, NULL );
+       if( retval < 0 )
+               goto out;
+       retval = set_registers( dev, REG_UNKNOWN, 0, 0, 0, NULL );
+       if( retval < 0 )
+               goto out;
+
+       return 0;
+
+out:
+       printk( "Error encountered while initializing net registers: %d\n", 
retval );
+       return retval;
+}
+
+static int enable_net_traffic(ax88178_t * dev)
+{
+
+       int res = 0;
+       u8 data[8];
+       
+       res = set_registers( dev, REG_RESET_W, 0x0048, 0, 0, NULL );
+       if( res < 0 )
+               goto out;
+       res = set_registers( dev, REG_RXCTRL_W, 0, 0, 0, NULL );
+       if( res < 0 )
+               goto out;
+       res = set_registers( dev, REG_SSMC_W, 0, 0, 0, NULL );
+       if( res < 0 )
+               goto out;
+       res = get_registers( dev, REG_PHYADDR_R, 0, 0, 2, data );
+       if( res < 0 )
+               goto out;
+       dev->phy = data[1];
+       res = get_registers( dev, REG_PHY_R, dev->phy, 0x0002, 2, data );
+       if( res < 0 )
+               goto out;
+       res = get_registers( dev, REG_PHY_R, dev->phy, 0x001b, 2, data );
+       if( res < 0 )
+               goto out;
+       data[0] = 0x00;
+       data[1] = 0x80;
+       res = set_registers( dev, REG_PHY_W, dev->phy, 0, 2, data );
+       if( res < 0 )
+               goto out;
+       res = get_registers( dev, REG_PHY_R, dev->phy, 0x0000, 2, data );
+       if( res < 0 )
+               goto out;
+       if( res < 0 )
+               goto out;
+       data[0] = 0x41;
+       data[1] = 0x43;
+       res = set_registers( dev, REG_PHY_W, dev->phy, 0x0018, 2, data );
+       if( res < 0 )
+               goto out;
+       data[0] = 0xe1;
+       data[1] = 0x05;
+       res = set_registers( dev, REG_PHY_W, dev->phy, 0x0004, 2, data );
+       if( res < 0 )
+               goto out;
+       data[0] = 0x00;
+       data[1] = 0x02;
+       res = set_registers( dev, REG_PHY_W, dev->phy, 0x0009, 2, data );
+       if( res < 0 )
+               goto out;
+       data[0] = 0x00;
+       data[1] = 0x12;
+       res = set_registers( dev, REG_PHY_W, dev->phy, 0x0000, 2, data );
+       if( res < 0 )
+               goto out;
+       res = set_registers( dev, REG_HSMC_W, 0, 0, 0, NULL );
+       if( res < 0 )
+               goto out;
+       res = set_registers( dev, REG_MMR_W, 0x013f, 0x0000, 0, NULL );
+       if( res < 0 )
+               goto out;
+       res = set_registers( dev, REG_IPG_W, 0x0c15, 0x000e, 0, NULL );
+       if( res < 0 )
+               goto out;
+       res = set_registers( dev, REG_IPG_W, 0x0c15, 0x000e, 0, NULL );
+       if( res < 0 )
+               goto out;
+       res = set_registers( dev, REG_RXCTRL_W, 0x0388, 0, 0, NULL );
+       if( res < 0 )
+               goto out;
+       res = set_registers( dev, REG_RXCTRL_W, 0x0398, 0, 0, NULL );
+       if( res < 0 )
+               goto out;
+       return 0;
+out:
+       printk( "Error encountered while enabling net traffic: %d\n", res );
+       return res;
+}
+
+static void disable_net_traffic(ax88178_t * dev)
+{
+       set_registers(dev, REG_RXCTRL_W, 0x0318, 0, 0, NULL);
+       set_registers(dev, REG_MMR_W, 0x0276, 0, 0, NULL );
+       set_registers(dev, REG_GPIO_W, 0x0200, 0, 0, NULL );
+}
+
+static struct net_device_stats *ax88178_netdev_stats(struct net_device *dev)
+{
+       return &((ax88178_t *)netdev_priv(dev))->stats;
+}
+
+static void ax88178_tx_timeout(struct net_device *netdev)
+{
+       ax88178_t *dev = netdev_priv(netdev);
+       warn("%s: Tx timeout.", netdev->name);
+       dev->tx_urb->transfer_flags |= URB_ASYNC_UNLINK;
+       usb_unlink_urb(dev->tx_urb);
+       dev->stats.tx_errors++;
+}
+
+static void ax88178_set_multicast(struct net_device *netdev)
+{
+       ax88178_t *dev = netdev_priv(netdev);
+       u16 data = 0x0398;
+       netif_stop_queue(netdev);
+       if (netdev->flags & IFF_PROMISC) {
+                data |= 0x0001;
+               info("%s: promiscuous mode", netdev->name);
+       } else if ((netdev->mc_count > multicast_filter_limit) ||
+                  (netdev->flags & IFF_ALLMULTI)) {
+               data |= 0x0002;
+               info("%s: allmulti set", netdev->name);
+       } 
+       async_set_registers(dev, REG_RXCTRL_W, data, 0, 0);
+       netif_wake_queue(netdev);
+}
+
+static int ax88178_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+       ax88178_t *dev = netdev_priv(netdev);
+       int count, res;
+       short invheadcount;
+
+
+
+       netif_stop_queue(netdev);
+       count = skb->len;
+//     count = ((skb->len + 2) & 0x3f) ? skb->len + 2 : skb->len + 3;
+       memcpy( dev->tx_skb_fix_data + 4, skb->data, count );
+       
+       invheadcount = 0xffff - count;
+       memcpy( dev->tx_skb_fix_data, &count, 2 );
+       memcpy( dev->tx_skb_fix_data + 2, &invheadcount, 2 );
+       dev->tx_skb = skb;
+       usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 3),
+                     dev->tx_skb_fix_data, count + 4, write_bulk_callback, 
dev);
+       if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) {
+               warn("failed tx_urb %d\n", res);
+               dev->stats.tx_errors++;
+               netif_start_queue(netdev);
+       } else {
+               dev->stats.tx_packets++;
+               dev->stats.tx_bytes += skb->len;
+               netdev->trans_start = jiffies;
+       }
+
+       return 0;
+}
+
+
+static int ax88178_open(struct net_device *netdev)
+{
+       ax88178_t *dev = netdev_priv(netdev);
+       int res;
+
+       if (dev->rx_skb == NULL)
+               dev->rx_skb = pull_skb(dev);
+       if (!dev->rx_skb)
+               return -ENOMEM;
+
+       dev->ready = 0;
+       set_registers(dev, REG_MAC_W, 0, 0, 6, netdev->dev_addr);
+       dev->state |= STATE_SPEED_CHANGE;
+       dev->speed_pid = kernel_thread(ax88178_link_up, dev, 
CLONE_FS|CLONE_FILES );
+       wait_event_interruptible( dev->speed_queue, dev->ready );
+       
+       usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 2),
+                     dev->rx_skb->data, AX88178_MTU, read_bulk_callback, dev);
+       if ((res = usb_submit_urb(dev->rx_urb, GFP_KERNEL)))
+               warn("%s: rx_urb submit failed: %d", __FUNCTION__, res);
+       netif_start_queue(netdev);
+       usb_fill_int_urb(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev, 1),
+                    dev->intr_buff, INTBUFSIZE, intr_callback,
+                    dev, dev->intr_interval);
+       if ((res = usb_submit_urb(dev->intr_urb, GFP_KERNEL)))
+               warn("%s: intr_urb submit failed: %d", __FUNCTION__, res);
+
+       return res;
+}
+
+static int ax88178_close(struct net_device *netdev)
+{
+       ax88178_t *dev = netdev_priv(netdev);
+       int res = 0;
+
+       netif_stop_queue(netdev);
+       unlink_all_urbs(dev);
+       kill_proc( dev->speed_pid, SIGTERM, 1);
+       dev->state = STATE_SPEED_CHANGE;
+       flush_scheduled_work();
+
+       return res;
+}
+
+static void ax88178_get_drvinfo(struct net_device *netdev, struct 
ethtool_drvinfo *info)
+{
+       ax88178_t *dev = netdev_priv(netdev);
+
+       strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN);
+       strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
+       usb_make_path(dev->udev, info->bus_info, sizeof info->bus_info);
+}
+
+static int ax88178_get_settings(struct net_device *netdev, struct ethtool_cmd 
*ecmd)
+{
+       ax88178_t *dev = netdev_priv(netdev);
+       short lpa;
+
+       get_registers( dev, REG_MSR_R, 0, 0, 2, &lpa );
+
+       ecmd->supported = (SUPPORTED_10baseT_Half |
+                         SUPPORTED_10baseT_Full |
+                         SUPPORTED_100baseT_Half |
+                         SUPPORTED_100baseT_Full |
+                         SUPPORTED_1000baseT_Full |
+                         SUPPORTED_1000baseT_Full |
+                         SUPPORTED_Autoneg |
+                         SUPPORTED_TP | SUPPORTED_MII);
+       ecmd->port = PORT_TP;
+       ecmd->transceiver = XCVR_INTERNAL;
+       ecmd->phy_address = dev->phy;
+       ecmd->autoneg = AUTONEG_ENABLE;
+       if( lpa & 0x0001 )
+               ecmd->speed = SPEED_1000;
+       else
+       {
+               if( lpa & 0x0200 )
+                       ecmd->speed = SPEED_100;
+               else
+                       ecmd->speed = SPEED_10;
+       }
+       if( lpa & 0x0002 )
+               ecmd->duplex = DUPLEX_FULL;
+       else
+               ecmd->duplex = DUPLEX_HALF;
+
+       return 0;
+}
+
+static struct ethtool_ops ops = {
+       .get_drvinfo = ax88178_get_drvinfo,
+       .get_settings = ax88178_get_settings,
+       .get_link = ethtool_op_get_link
+};
+
+/*
+static int ax88178_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
+{
+       ax88178_t *dev = netdev_priv(netdev);
+       u16 *data = (u16 *) & rq->ifr_ifru;
+       int res = 0;
+
+       switch (cmd) {
+       case SIOCDEVPRIVATE:
+               data[0] = dev->phy;
+       case SIOCDEVPRIVATE + 1:
+               read_mii_word(dev, dev->phy, (data[1] & 0x1f), &data[3]);
+               break;
+       case SIOCDEVPRIVATE + 2:
+               if (!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+               write_mii_word(dev, dev->phy, (data[1] & 0x1f), data[2]);
+               break;
+       default:
+               res = -EOPNOTSUPP;
+       }
+
+       return res;
+}
+*/
+
+static int ax88178_change_mtu( struct net_device *dev, int new_mtu )
+{
+       if(  new_mtu > AX88178_MAX_MTU)
+               return -EINVAL;
+       dev->mtu = new_mtu;
+       return 0;
+}
+
+static int ax88178_probe(struct usb_interface *intf,
+                        const struct usb_device_id *id)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       ax88178_t *dev;
+       struct net_device *netdev;
+       int res;
+
+       netdev = alloc_etherdev(sizeof(ax88178_t));
+       if (!netdev) {
+               err("Out of memory");
+               return -ENOMEM;
+       }
+
+       dev = netdev_priv(netdev);
+       memset(dev, 0, sizeof(ax88178_t));
+
+       dev->intr_buff = kmalloc(INTBUFSIZE, GFP_KERNEL);
+       if (!dev->intr_buff) {
+               free_netdev(netdev);
+               return -ENOMEM;
+       }
+
+       tasklet_init(&dev->tl, rx_fixup, (unsigned long)dev);
+       spin_lock_init(&dev->rx_pool_lock);
+
+       dev->state = 0;
+       init_waitqueue_head( &dev->speed_queue );
+       
+
+       dev->udev = udev;
+       dev->netdev = netdev;
+       SET_MODULE_OWNER(netdev);
+
+       netdev->open = ax88178_open;
+       netdev->stop = ax88178_close;
+       netdev->change_mtu = ax88178_change_mtu;
+//     netdev->do_ioctl = ax88178_ioctl;
+       netdev->watchdog_timeo = AX88178_TX_TIMEOUT;
+       netdev->tx_timeout = ax88178_tx_timeout;
+       netdev->hard_start_xmit = ax88178_start_xmit;
+       netdev->set_multicast_list = ax88178_set_multicast;
+       netdev->set_mac_address = ax88178_set_mac_address;
+       netdev->get_stats = ax88178_netdev_stats;
+//     netdev->mtu = 1500;
+       SET_ETHTOOL_OPS(netdev, &ops);
+       dev->intr_interval = 100;       // 100ms 
+
+       if (!alloc_all_urbs(dev)) {
+               err("out of memory");
+               goto out;
+       }
+       if (!ax88178_reset(dev)) {
+               err("couldn't reset the device");
+               goto out1;
+       }
+       fill_skb_pool(dev);
+       set_ethernet_addr(dev);
+       info("%s: ax88178 is detected", netdev->name);
+       
+       usb_set_intfdata(intf, dev);
+
+       SET_NETDEV_DEV(netdev, &intf->dev);
+       if (register_netdev(netdev) != 0) {
+               err("couldn't register the device");
+               goto out2;
+       }
+
+       res = init_net_registers( dev );
+       if( res < 0 )
+               goto out2;
+       enable_net_traffic(dev);
+       return 0;
+
+out2:
+       usb_set_intfdata(intf, NULL);
+       free_skb_pool(dev);
+out1:
+       free_all_urbs(dev);
+out:
+       kfree(dev->intr_buff);
+       free_netdev(netdev);
+       return -EIO;
+}
+
+static void ax88178_disconnect(struct usb_interface *intf)
+{
+       ax88178_t *dev = usb_get_intfdata(intf);
+
+       usb_set_intfdata(intf, NULL);
+       if (dev) {
+               set_bit(AX88178_UNPLUG, &dev->flags);
+               tasklet_kill( &dev->tl );
+               unregister_netdev(dev->netdev);
+               disable_net_traffic( dev );
+               unlink_all_urbs(dev);
+               free_all_urbs(dev);
+               free_skb_pool(dev);
+               if (dev->rx_skb)
+                       dev_kfree_skb(dev->rx_skb);
+               kfree(dev->intr_buff);
+               free_netdev(dev->netdev);
+       }
+}
+
+static int __init usb_ax88178_init(void)
+{
+       info(DRIVER_DESC " " DRIVER_VERSION);
+       return usb_register(&ax88178_driver);
+}
+
+static void __exit usb_ax88178_exit(void)
+{
+       usb_deregister(&ax88178_driver);
+}
+
+module_init(usb_ax88178_init);
+module_exit(usb_ax88178_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");

Reply via email to