Click to See Complete Forum and Search --> : Ethernet card driver found, how to install?


sawman46445
07-05-2001, 06:56 PM
Hi!
I'm using a USB Ethernet crd called Netmate from CATC, after tribes and tribulations I finally found the ONLY driver for Linux.
it's a catc.c file, now I know that I'm supposed to somehow comile it, now the iminent question is HOW?
--saw

TheMuso
07-06-2001, 09:57 AM
Is there any information at the top or bottom of the file to give you information about other libraries or files needed, and/or compile commands?

sawman46445
07-06-2001, 01:55 PM
I AM a programmer but I don't know any C, I could go through but I'm as lazy as a panda...
So here is the WHOLE code... enjoy lol... if you could help me I'd be VERY thankful...
/* catc.c: A Linux device driver for the CATC USB-Ethernet adapter. */
/*
Written/copyright 1999-2000 by Donald Becker.

This software may be used and distributed according to the terms of the
GNU General Public License (GPL), incorporated herein by reference.
Drivers based on or derived from this code fall under the GPL and must
retain the authorship, copyright and license notice.
This file is not a complete program and may only be used when the
entire program is licensed under the GPL.
Contact the author, Donald Becker, for alternate license terms.

The author may be reached as becker@scyld.com, or
Donald Becker
312 Severn Ave. #W302
Annapolis MD 21403

Support and updates available at
http://www.scyld.com/usb/index.html
*/

static const char version[] =
"catc.c:v1.00 7/17/2000 Written by Donald Becker, <becker@scyld.com>.\n"
" Information and updates at <A HREF="http://www.scyld.com/linux/usb.html\n";" TARGET=_blank>http://www.scyld.com/linux/usb.html\n";</A>

/* A few user-configurable values. These may be modified when a driver
module is loaded.*/

static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */

/* The following parameter enables stand-along testing by looping the
data back at several points within the device. */
static int loopback = 0; /* 0 normal, 1 internal LB, 2 xcvr LB. */

/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
Typical is a 64 element hash table based on the Ethernet CRC.
USB updates have high overhead, so this is an important parameter.
*/
static int multicast_filter_limit = 32;

/* Used to pass the media type, etc.
Both 'options[]' and 'full_duplex[]' should exist for driver
interoperability.
The media type is usually passed in 'options[]'.
*/
#define MAX_UNITS 8 /* More are supported, limit only on options */
static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};

/* Operational parameters that are set at compile time. */

/* Operational parameters that usually are not changed. */
/* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT (2*HZ)
/* Minimum time in jiffies between reading statisitcs registers. */
#define STATS_UPDATE (5*HZ)

#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/

#if ! defined(__KERNEL__)
#define __KERNEL__
#endif
#if !defined(__OPTIMIZE__)
#warning You must compile this file with the correct options!
#warning See the last lines of the source file.
#error You must compile this driver with the proper options, including "-O".
#endif
#if !defined(__OPTIMIZE__)
#warning You probably wanted to comile this driver as a module with -DMODULE.
#endif

/* Include files, designed to support most kernel versions 2.0.0 and later. */
#include &lt;linux/config.h&gt;
#if defined(CONFIG_SMP) && ! defined(__SMP__)
#define __SMP__
#endif
#if defined(MODULE) && defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
#define MODVERSIONS
#endif

#include &lt;linux/version.h&gt;
#include &lt;linux/module.h&gt;
/* Older kernels do not include this automatically. */
#if LINUX_VERSION_CODE &lt; 0x20300 && defined(MODVERSIONS)
#include &lt;linux/modversions.h&gt;
#endif

#include &lt;linux/kernel.h&gt;
#include &lt;linux/string.h&gt;
#include &lt;linux/timer.h&gt;
#include &lt;linux/errno.h&gt;
#include &lt;linux/malloc.h&gt;
#include &lt;linux/interrupt.h&gt;
#include &lt;linux/netdevice.h&gt;
#include &lt;linux/etherdevice.h&gt;
#include &lt;linux/skbuff.h&gt;
#include &lt;asm/processor.h&gt; /* Processor type for cache alignment. */
#include &lt;asm/bitops.h&gt;

#include "usb.h"

#if (LINUX_VERSION_CODE &gt;= 0x20100) && defined(MODULE)
char kernel_version[] = UTS_RELEASE;
#endif
#if LINUX_VERSION_CODE &lt; 0x2030d
#define net_device device
#endif
#if ! defined(CAP_NET_ADMIN)
#define capable(CAP_XXX) (suser())
#endif
#if ! defined(HAS_NETIF_QUEUE)
#define netif_wake_queue(dev) mark_bh(NET_BH);
#endif

MODULE_AUTHOR("Donald Becker &lt;becker@tidalwave.net&gt;");
MODULE_DESCRIPTION("CATC USB-Ethernet driver");
MODULE_PARM(debug, "i");
MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
MODULE_PARM(loopback, "i");

/*
Theory of Operation

I. Board Compatibility

This driver is designed for the CATC Netmate USB-Ethernet adapter. Adapters
based on the CATC design from smartBridges and other are also supported.
New IDs may be added to usb_id_tbl[].

II. Adapter-specific settings

The driver must guess the speed of the internal packet RAM.
There may be a future option to override this should the product line change.

III. Driver operation

This USB adapter has the standard control endpoint, two (Tx and Rx) bulk
data endpoints, and an optional interrupt/status endpoint.

IV. Notes

This chip is confused about its endianness. USB is LSB first/lowest, but
this chip puts multibyte values MSB lowest.

The statistic counts are unreliable: the 16 bit counters must be read as two
byte reads and later cleared with a write. That leaves a dead period
where event are not counted.

Unknown details:
Several methods are provided to read the station address and EEPROM.
Why? Which one is preferred?

What speed memory is in the device? How many wait states? Is this stored
in the EEPROM?

Packets-per-burst register is not documented, except in an example.
Reset device is incorrectly documented in the table.

IVb. References

USB-EL1210A Ethernet Link Controller ASIC Designer's Guide v1.0
Computer Access Technology Corp. (CATC)
25 Oct 1999 (marked "CATC Confidental", provided without a NDA).

Scyld USB Driver Implementer Guide for v1.00.
Derived from Scyld usb-net-skeleton.c v1.03 usb-netskel-000210.

Various USB background documents from http://www.usb.org/ http://www.linux-usb.org/

IVc. Errata

This device does not support NWay autonegotiation or full duplex operation.

*/


/* This table drives the USB probe routines. Note the matching code. The
mask allows us to support ranges of product numbers from a single vendor.
Product numbers should be added as constants, not symbolic names.
*/

static void *usb_dev_scan(struct usb_device *dev, unsigned int unused);
static void *catc_attach(struct usb_device *usbdev, int chip_idx, int dev_idx);
static void catc_disconnect(struct usb_device *dev, void *dev_ptr);
static int netdev_pwr_event(void *dev_instance, int event);
enum chip_capability_flags {
ScanMIIXcvrs=0x10000, HasMIIXcvr=0x20000, HasPNAXcvr=0x40000,
UseTxCount=0x80000, };

static struct usb_id_info {
const char *name;
struct match_info { u16 vendor, product, product_mask; } id;
void *(*attach)(struct usb_device *usbdev, int chip_idx, int ifnum);
int drv_flags; /* Driver use, intended as capability flags. */
} usb_id_tbl[] = {
{"CATC Netmate USB Ethernet", {0x0423, 0x000a, 0xffff},
catc_attach, UseTxCount },
{"CATC Netmate II USB Ethernet", {0x0423, 0x000c, 0xffff},
catc_attach, UseTxCount },
{"smartBridges smartNIC USB Ethernet", {0x08d1, 0x0001, 0xffff},
catc_attach, UseTxCount },
{ 0, }, /* 0 terminated list. */
};

/* This structure is from the Linus-derived interface.
I expect it to be expanded to include a power control interface, and
perhaps a device-id match filter. */
static struct usb_driver catc_usb_id = {
"CATC USB-EL1210A USB-Ethernet",
usb_dev_scan,
catc_disconnect,
};

static LIST_HEAD(catc_list);

/* The on-chip registers accessable through vendor-specific commands. */
enum register_offsets {
TxBufCount=0x20, RxBufCount=0x21, OpModes=0x22, TxQed=0x23, RxQed=0x24,
RxFilter=0x60,
StationAddr5=0x62, StationAddr0=0x67, LEDCtrl=0x81,
MulticastFilter=0x7a80, /* Memory address. */
};
/* Operating mode bits and Rx filter bit in OpModes/RxFilter registers. */
enum op_mode_bits {
OpLoopback=0x80, OpWin95bugfix=0x40, OpTxMerge=0x20, OpRxMerge=0x10,
OpLenInclude=0x08, Op3MemWaits=0x03,
};
enum rx_filter_bits {
RxEnable=0x01, RxPolarity=0x02,
};

static int catc_get_register(struct usb_device *udev, int regnum);
static int catc_set_register(struct usb_device *udev, int regnum, int value);

#define TX_Q 4
#define RX_Q 4
#define TX_QUEUE_LEN 1

#define PRIV_ALIGN 15 /* Required alignment mask */
/* Use __attribute__((aligned (L1_CACHE_BYTES))) to maintain alignment
within the structure. */
struct netdev_private {
struct net_device *next_module; /* Link for devices of this type. */
void *priv_addr; /* Unaligned address for kfree */
const char *product_name;
struct list_head list;
struct net_device_stats stats;
long last_stats;
struct timer_list timer; /* Media monitoring timer. */
/* Frequently used values: keep some adjacent for cache effect. */
int chip_id, drv_flags;
struct usb_device *usb_dev;

struct urb *rx_urb0, *rx_urb1, *tx_urb, *irq_urb, *ctrl_urb;
void *usb_tx_xfer, *usb_rx_xfer;
struct tx_context {
struct net_device *netdev;
struct sk_buff *skb;
void *buffer;
struct urb *urb;
} txcontext[TX_Q];
struct rx_context {
struct net_device *netdev;
struct sk_buff *skb;
void *buffer;
struct urb *urb;
} rxcontext[RX_Q];
struct urb tx_urbs[TX_Q];
struct urb *rx_urbs[RX_Q];
unsigned int cur_tx, dirty_tx;

unsigned int ctrl_out_pipe, tx_out_pipe, rx_in_pipe, irq_pipe;
unsigned int irq_period;
void *rxbuffer;
void *irq_handle;

/* Local copy of the registers. Note endian problem. */
unsigned char cur_ether_ctrl[4], cur_multicast[64];
unsigned char new_ether_ctrl[4], new_multicast[64];

unsigned int tx_full:1; /* The Tx queue is full. */
/* These values are keep track of the transceiver/media in use. */
unsigned int full_duplex:1; /* Full-duplex operation requested. */
unsigned int duplex_lock:1;
unsigned int medialock:1; /* Do not sense media. */
unsigned int default_port:4; /* Last dev-&gt;if_port value. */

/* Last in structure to minimize lossage with wild writes */
unsigned char ctrl_msg[8];
unsigned char intr_buffer[8]; /* Interrupt pipe message. */
};

static int netdev_open(struct net_device *dev);
static int start_hardware(struct net_device *dev);
static void netdev_timer(unsigned long data);
static void tx_timeout(struct net_device *dev);
static int start_tx(struct sk_buff *skb, struct net_device *dev);
static void ctrl_urb_done(struct urb *urb_that_finished);
static void irq_urb_done(struct urb *urb_that_finished);
static void tx_urb_done(struct urb *urb_that_finished);
static void rx_urb_done(struct urb *urb_that_finished);
static void set_rx_mode(struct net_device *dev);
static struct net_device_stats *get_stats(struct net_device *dev);
static int netdev_close(struct net_device *dev);



/* A list of our installed devices, for removing the driver module. */
static struct net_device *root_net_dev = NULL;

/* This device scan is generic, the attach routine below contains all
adapter-specific configuration. */
static void *usb_dev_scan(struct usb_device *dev, unsigned int ifnum)
{
int i;

printk(KERN_DEBUG "USB-Ethernet driver checking for a known device.\n");
printk(KERN_DEBUG " USB IDs 0x%4.4x 0x%4.4x Configurations: %d, "
"interfaces %d.\n",
dev-&gt;descriptor.idVendor, dev-&gt;descriptor.idProduct,
dev-&gt;descriptor.bNumConfigurations,
dev-&gt;config[0].bNumInterfaces);
printk(KERN_DEBUG " Adapters options %d %d %d.\n", ifnum,
options[0], full_duplex[0]);

for (i = 0; usb_id_tbl[i].name; i++ ) {
if (dev-&gt;descriptor.idVendor == usb_id_tbl[i].id.vendor &&
dev-&gt;descriptor.idProduct == usb_id_tbl[i].id.product)
break;
}
if (usb_id_tbl[i].name == NULL) {
printk(KERN_DEBUG "catc: No matching entry found for device"
" 0x%4.4x 0x%4.4x.\n",
dev-&gt;descriptor.idVendor, dev-&gt;descriptor.idProduct);
return 0;
}

if (dev-&gt;descriptor.bNumConfigurations != 1 ||
dev-&gt;config[0].bNumInterfaces != 1) {
printk(KERN_ERR "This USB device did not report the expected "
"configuration, driver not installed.\n");
return 0;
}

printk(KERN_INFO "Found recognized USB device '%s'.\n",
usb_id_tbl[i].name);
return usb_id_tbl[i].attach(dev, i, ifnum);
}

static void *catc_attach(struct usb_device *usbdev, int chip_idx, int ifnum)
{
struct net_device *dev;
struct netdev_private *np;
unsigned char eeprom[128];
int config_idx = usbdev-&gt;config[0].bConfigurationValue;
struct usb_interface_descriptor *if_setting =
usbdev-&gt;actconfig-&gt;interface[ifnum].altsetting;
int i;

dev = init_etherdev(0, 0);

if (usb_set_configuration(usbdev, config_idx)) {
printk(KERN_WARNING "%s: Setting CATC configuration to %d failed.\n",
dev-&gt;name, config_idx);
}

#ifndef final_version /* Remove before release */
if (debug &gt; 1) {

char *manf, *product, *serial;

usb_show_device(usbdev);
printk(KERN_DEBUG "catc: ID string indices %d, %d, %d.\n",
usbdev-&gt;descriptor.iManufacturer,
usbdev-&gt;descriptor.iProduct,
usbdev-&gt;descriptor.iSerialNumber );

/* Sleazy code: It knows about internals and printk(..NULL) works. */
manf = usb_string(usbdev, usbdev-&gt;descriptor.iManufacturer);
usbdev-&gt;string = 0;
product = usb_string(usbdev, usbdev-&gt;descriptor.iProduct);
usbdev-&gt;string = 0;
serial = usb_string(usbdev, usbdev-&gt;descriptor.iSerialNumber);
usbdev-&gt;string = 0;
printk(KERN_DEBUG "catc: Device reported '%s' Product '%s' Serial "
"'%s'.\n",
manf, product, serial);
if (manf) kfree(manf);
if (product) kfree(product);
if (serial) kfree(serial);
for (i = 0; i &lt; if_setting-&gt;bNumEndpoints; i++)
printk(KERN_DEBUG " Endpoint %d address %2.2x %s.\n",
i, if_setting-&gt;endpoint[i].bEndpointAddress,
(if_setting-&gt;endpoint[i].bmAttributes &
USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK
? "Bulk" : "Other");
}
#endif

printk(KERN_INFO "%s: %s at %d (+%d), ",
dev-&gt;name, usb_id_tbl[chip_idx].name, usbdev-&gt;devnum, ifnum);

/* Fetch the station address. */
usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0)
/* usb_rcvdefctrl(usbdev) */,
0xF2, 0xC0, 0, 0, dev-&gt;dev_addr, 6, 10);

for (i = 0; i &lt; 5; i++)
printk("%2.2x:", dev-&gt;dev_addr[i]);
printk("%2.2x.\n", dev-&gt;dev_addr[i]);

usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
0xFD, 0xC0, 0, 0, eeprom, sizeof(eeprom), 50);
#if ! defined(final_version) && 1
/* Dump the EEPROM contents during development. */
if (debug &gt; 4)
for (i = 0; i &lt; 0x100; i++)
printk("%2.2x%s", eeprom[i], i % 16 != 15 ? " " : "\n");
#endif

/* All bogusness checks have been done at this point. */

dev-&gt;base_addr = 0;
dev-&gt;irq = 0;

{ /* Make certain elements e.g. descriptor lists are aligned. */
void *mem = kmalloc(sizeof(*np) + PRIV_ALIGN, GFP_KERNEL);
dev-&gt;priv = np = (void *)(((long)mem + PRIV_ALIGN) & ~PRIV_ALIGN);
memset(np, 0, sizeof(*np));
np-&gt;priv_addr = mem;
}

MOD_INC_USE_COUNT;
list_add(&np-&gt;list, &catc_list);

np-&gt;usb_dev = usbdev;
np-&gt;chip_id = chip_idx;
np-&gt;drv_flags = usb_id_tbl[chip_idx].drv_flags;
np-&gt;duplex_lock = full_duplex[0];

np-&gt;irq_period =
if_setting-&gt;bNumEndpoints &gt; 2 ? if_setting-&gt;endpoint[2].bInterval : 0;

/* Reset the adapter. */
printk(KERN_DEBUG "%s: Resetting the device, irq_period %d.\n",
dev-&gt;name, np-&gt;irq_period);
usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0)
/* usb_snddefctrl(usbdev) */,
0xF4, 0x40, 0, 0, 0, 0, 10);
printk(KERN_DEBUG "%s: Resetting the device.\n",
dev-&gt;name);
/* Set the LED to flash slowly. */
catc_set_register(np-&gt;usb_dev, LEDCtrl, 0x01);

/* The chip-specific entries in the device structure. */
dev-&gt;open = &netdev_open;
dev-&gt;hard_start_xmit = &start_tx;
dev-&gt;stop = &netdev_close;
dev-&gt;get_stats = &get_stats;
dev-&gt;set_multicast_list = &set_rx_mode;
/* dev-&gt;do_ioctl = &mii_ioctl; */

return dev;
}



/* A value-return single register read. */
static int catc_get_register(struct usb_device *usbdev, int regnum)
{
/* Note: stack variables should not be used as target buffers! */
unsigned char buf[4]; /* Generously sized to avoid overflow bug. */
usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
0xFB, 0xC0, 0, regnum, buf, 1, 10);
return buf[0];
}

/* The upper byte of VALUE is a mask.
Set bits in the mask leave the original value intact. */
static int catc_set_register(struct usb_device *usbdev, int regnum, int value)
{
return usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0),
0xFA, 0x40, value, regnum, 0, 0, 10);
}

static void catc_disconnect(struct usb_device *usbdev, void *dev_ptr)
{
struct net_device *dev = dev_ptr;
struct netdev_private *np;
if (dev == NULL) { /* Doh! Something screwed up. */
printk(KERN_ERR "Disconnect for NULL CATC device.\n");
return;
}
printk(KERN_DEBUG "%s: Disconnect for CATC device.\n", dev-&gt;name);
if (dev-&gt;flags & IFF_UP) {
printk(KERN_ERR "%s: USB interface was detached while still active.\n",
dev-&gt;name);
dev_close(dev);
}

unregister_netdev(dev);
np = dev-&gt;priv;
list_del(&np-&gt;list);
if (np-&gt;priv_addr)
kfree(np-&gt;priv_addr);
kfree(dev);
MOD_DEC_USE_COUNT;
return;
}


static int netdev_open(struct net_device *dev)
{
struct netdev_private *np = (struct netdev_private *)dev-&gt;priv;
struct usb_device *usbdev = np-&gt;usb_dev;
int status, i;

/* Do we need to reset the chip??? */

if (debug &gt; 1)
printk(KERN_DEBUG "%s: netdev_open (USB dev=%p).\n", dev-&gt;name,
np-&gt;usb_dev);

MOD_INC_USE_COUNT;

np-&gt;dirty_tx = np-&gt;cur_tx = 0;

np-&gt;ctrl_out_pipe = usb_sndctrlpipe(usbdev, 0);
np-&gt;tx_out_pipe = usb_sndbulkpipe(usbdev, 1);
np-&gt;rx_in_pipe = usb_rcvbulkpipe(usbdev, 1);
np-&gt;irq_pipe = usb_rcvintpipe(usbdev, 2);

np-&gt;ctrl_urb = usb_alloc_urb(0);
FILL_CONTROL_URB(np-&gt;ctrl_urb, usbdev, np-&gt;ctrl_out_pipe, np-&gt;ctrl_msg,
0, 0, ctrl_urb_done, dev);
np-&gt;ctrl_msg[0] = 0x40;
np-&gt;ctrl_msg[1] = 0xFC;
np-&gt;ctrl_msg[2] = np-&gt;ctrl_msg[3] = 0;
np-&gt;ctrl_msg[4] = 0x80; np-&gt;ctrl_msg[5] = 0x7a;
np-&gt;ctrl_msg[6] = np-&gt;ctrl_msg[7] = 0;

start_hardware(dev);

#if 0
if (debug &gt; 2)
printk(KERN_DEBUG "%s: Done setting up for normal operation, %2.2x "
"%2.2x.\n",
dev-&gt;name, catc_get_register(np-&gt;usb_dev, 0),
catc_get_register(np-&gt;usb_dev, 1));
#endif

if (dev-&gt;if_port == 0)
dev-&gt;if_port = np-&gt;default_port;

dev-&gt;tbusy = 0;
dev-&gt;interrupt = 0;

#if 0
catc_set_register(np-&gt;usb_dev, EtherCtrl, 0xF8);
catc_set_register(np-&gt;usb_dev, EtherCtrl2,
loopback & 1 ? 0x000C : 0x04);
if (debug &gt; 2)
printk(KERN_DEBUG "%s: Set Rx mode to %x.\n",
dev-&gt;name, 0);

#endif

for (i = 0; i &lt; TX_Q; i++) {
struct tx_context *txc = &(np-&gt;txcontext[i]);
txc-&gt;netdev = dev;
txc-&gt;skb = 0;
txc-&gt;buffer = kmalloc(1536, GFP_KERNEL);
txc-&gt;urb = usb_alloc_urb(0);
FILL_BULK_URB(txc-&gt;urb, np-&gt;usb_dev, np-&gt;tx_out_pipe, txc-&gt;buffer,
0, tx_urb_done, txc);
}
for (i = 0; i &lt; TX_Q; i++) {
FILL_BULK_URB(&np-&gt;tx_urbs[i], np-&gt;usb_dev, np-&gt;tx_out_pipe, 0, 0,
tx_urb_done, 0);
}

for (i = 0; i &lt; RX_Q; i++) {
struct sk_buff *skb = dev_alloc_skb(1536);
struct urb *urb = usb_alloc_urb(0);
if (skb == NULL)
break;
skb-&gt;dev = dev;
/* Note: the 2 bytes of prefixed length will align the IP header */
np-&gt;rx_urbs[i] = urb;
if (i && 0)
np-&gt;rx_urbs[i-1]-&gt;next = urb;
FILL_BULK_URB(urb, np-&gt;usb_dev, np-&gt;rx_in_pipe, skb-&gt;tail,
1536, rx_urb_done, skb);
}
if (i && 0)
np-&gt;rx_urbs[i-1]-&gt;next = np-&gt;rx_urbs[0];

np-&gt;rxbuffer = kmalloc(3800, GFP_KERNEL);
memset(np-&gt;rxbuffer, 0x89, 3800);
np-&gt;rx_urb0 = usb_alloc_urb(0);
np-&gt;rx_urb1 = usb_alloc_urb(0);

FILL_BULK_URB(np-&gt;rx_urb0, np-&gt;usb_dev, np-&gt;rx_in_pipe, np-&gt;rxbuffer,
1536, rx_urb_done, dev);
FILL_BULK_URB(np-&gt;rx_urb1, np-&gt;usb_dev, np-&gt;rx_in_pipe, np-&gt;rxbuffer+1536,
1536, rx_urb_done, dev);
/* np-&gt;rx_urb0-&gt;next = np-&gt;rx_urb1;*/
if ((status = usb_submit_urb(np-&gt;rx_urb0)) &lt; 0)
printk(KERN_ERR "%s: Problem submitting receive URB #0, status %d, "
"pipe 0x%x.\n",
dev-&gt;name, status, np-&gt;rx_in_pipe);
if ((status = usb_submit_urb(np-&gt;rx_urb1)) &lt; 0) {
/* Acckkk!!! This USB stack cannot handle multiple receive buffers. */
printk(KERN_ERR "%s: Failed submitting receive URB #1, status %d, "
"pipe 0x%x.\n"
KERN_ERR "%s: This USB stack cannot handle more than one "
"receive buffer.\n",
dev-&gt;name, status, np-&gt;rx_in_pipe, dev-&gt;name);
usb_free_urb(np-&gt;rx_urb1);
np-&gt;rx_urb1 = 0;
} else {
if (debug &gt; 1)
printk(KERN_DEBUG "%s: Submitted receive URB #1, status %d, "
"pipe 0x%x.\n",
dev-&gt;name, status, np-&gt;rx_in_pipe);
}

/* Clear the error bits and Rx missed count. */
#if 0
{
unsigned char regs[5];
catc_get_registers(usbdev, 0x2B, regs, 5);
}
#endif

if (np-&gt;irq_period && (np-&gt;irq_urb = usb_alloc_urb(0)) != NULL) {
if (debug &gt; 1)
printk(KERN_DEBUG "%s: Adding an interrupt pipe with period %d.\n",
dev-&gt;name, np-&gt;irq_period);
FILL_INT_URB(np-&gt;irq_urb, np-&gt;usb_dev, np-&gt;irq_pipe, np-&gt;intr_buffer,
sizeof(np-&gt;intr_buffer),
irq_urb_done, dev, np-&gt;irq_period);

if ((status = usb_submit_urb(np-&gt;irq_urb)) &lt; 0)
printk(KERN_ERR "%s: Problem submitting interrupt URB, status %d, "
"pipe 0x%x.\n",
dev-&gt;name, status, np-&gt;irq_pipe);
}

dev-&gt;start = 1;
if (debug &gt; 2)
printk(KERN_DEBUG "%s: Done netdev_open().\n", dev-&gt;name);

/* Set the timer to check for link beat. */
init_timer(&np-&gt;timer);
np-&gt;timer.expires = jiffies + 3*HZ;
np-&gt;timer.data = (unsigned long)dev;
np-&gt;timer.function = &netdev_timer; /* timer handler */
add_timer(&np-&gt;timer);

return 0;
}

static int start_hardware(struct net_device *dev)
{
struct netdev_private *np = (struct netdev_private *)dev-&gt;priv;
struct usb_device *usbdev = np-&gt;usb_dev;
int i;

if (debug &gt; 2)
printk(KERN_DEBUG "%s: Initializing the hardware.\n",
dev-&gt;name);
/* Send a reset message. */
usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0)
/* usb_snddefctrl(usbdev) */,
0xF4, 0x40, 0, 0, 0, 0, 10);
/* Rewrite the station address. */
for (i = 0; i &lt; 6; i++)
catc_set_register(np-&gt;usb_dev, StationAddr0 - i, dev-&gt;dev_addr[i]);

if (debug &gt; 3)
printk(KERN_DEBUG "%s: Set the station address, now enabling.\n",
dev-&gt;name);

catc_set_register(np-&gt;usb_dev, 0x25, 1); /* Maximum burst */
catc_set_register(np-&gt;usb_dev, LEDCtrl, 0x08);
catc_set_register(np-&gt;usb_dev, TxBufCount, 4);
catc_set_register(np-&gt;usb_dev, RxBufCount, 16);
catc_set_register(np-&gt;usb_dev, OpModes,
OpLenInclude | Op3MemWaits | (loopback ? OpLoopback:0));
catc_set_register(np-&gt;usb_dev, RxFilter, 0x1f | RxEnable);

if (debug &gt; 3)
printk(KERN_DEBUG "%s: Filling the multicast list.\n",
dev-&gt;name);
/* Configure the multicast list. */
memset(np-&gt;new_multicast, 0xff, sizeof(np-&gt;new_multicast));
usb_control_msg(np-&gt;usb_dev, usb_sndctrlpipe(np-&gt;usb_dev, 0),
0xFC, 0x40, 0, 0x7a80, np-&gt;new_multicast, 64, 10);

#if 0
/* Set up for normal operation. */
*(u32*)np-&gt;cur_ether_ctrl = 0;
np-&gt;new_ether_ctrl[0] = 0xC8;
np-&gt;new_ether_ctrl[1] = 0x18 & (loopback || np-&gt;duplex_lock ? 0x20 : 0);
np-&gt;new_ether_ctrl[2] = loopback & 1 ? 0x000D : 0x01;
np-&gt;new_ether_ctrl[3] = 0; /* Just a pad */

catc_set_registers(np-&gt;usb_dev, EtherCtrl, np-&gt;new_ether_ctrl, 3);
memcpy(np-&gt;cur_ether_ctrl, np-&gt;new_ether_ctrl, 4);
#endif
return 0;
}

/* We cannot do anything on the USB bus in the timer routine.
The USB stack should provide an alternate timer structure based on
transaction cycles. For now the driver relies on periodic interrupts,
which doesn't let us detect device failure. */
static void netdev_timer(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
struct netdev_private *np = (struct netdev_private *)dev-&gt;priv;
int next_tick = 10*HZ;

if (debug &gt; 3) {
printk(KERN_DEBUG "%s: Media selection timer tick, USB dev %p.\n",
dev-&gt;name, np-&gt;usb_dev);
}
#if 0
/* This will either have a small false-trigger window or will not catch
tbusy incorrectly set when the queue is empty. */
if (test_bit(0, (void*)&dev-&gt;tbusy) &&
(jiffies - dev-&gt;trans_start) &gt; TX_TIMEOUT) {
tx_timeout(dev);
}
check_duplex(dev);
#endif
np-&gt;timer.expires = jiffies + next_tick;
add_timer(&np-&gt;timer);
}

/* Completion of the occasional control stream Rx mode change. */
static void ctrl_urb_done(struct urb *urb)
{
struct net_device *dev = urb-&gt;context;
struct netdev_private *np = dev-&gt;priv;

if (debug &gt; 2) {
printk(KERN_DEBUG "%s: Control URB done.\n", dev-&gt;name);
return;
}

switch (urb-&gt;status) {
case USB_ST_NOERROR:
if (memcmp(np-&gt;cur_ether_ctrl, np-&gt;new_ether_ctrl, 4)) {
if (debug &gt; 2)
printk(KERN_DEBUG "%s: USB setting Rx mode %2.2x..%2.2x.\n",
dev-&gt;name, np-&gt;new_ether_ctrl[0],
np-&gt;new_ether_ctrl[2]);
np-&gt;ctrl_msg[4] = RxFilter;
np-&gt;ctrl_msg[6] = 3;
np-&gt;ctrl_urb-&gt;transfer_buffer = np-&gt;new_ether_ctrl;
np-&gt;ctrl_urb-&gt;transfer_buffer_length = 3;
usb_submit_urb(np-&gt;ctrl_urb);
memcpy(np-&gt;cur_ether_ctrl, np-&gt;new_ether_ctrl, 4);
} else if (memcmp(np-&gt;cur_multicast, np-&gt;new_multicast, 8)) {
if (debug &gt; 2)
printk(KERN_DEBUG "%s: USB Setting Rx multicast filter.\n",
dev-&gt;name);
np-&gt;ctrl_msg[4] = MulticastFilter;
np-&gt;ctrl_msg[6] = 64;
np-&gt;ctrl_urb-&gt;transfer_buffer = np-&gt;new_multicast;
np-&gt;ctrl_urb-&gt;transfer_buffer_length = 64;
#if 0
usb_submit_urb(np-&gt;ctrl_urb);
#endif
memcpy(np-&gt;cur_multicast, np-&gt;new_multicast, 8);
}
break;
case USB_ST_URB_KILLED:
default:
return;
}
return;
}

/* Deal with the periodic interrupt pipe status update. */
static void irq_urb_done(struct urb *urb)
{
struct net_device *dev = urb-&gt;context;
struct netdev_private *np = dev-&gt;priv;
unsigned char *data = urb-&gt;transfer_buffer;

/* The interrupt info is in the data buffer. */
if (debug &gt; 5) {
printk(KERN_DEBUG "%s: Interrupt time %ld status %d, "
"data %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x.\n",
dev-&gt;name, jiffies, urb-&gt;status,
data[0], data[1], data[2], data[3],
data[4], data[5], data[6], data[7]);
return;
}
switch (urb-&gt;status) {
case USB_ST_NOERROR:
if (data[0] & 0xFC) {
np-&gt;stats.tx_errors++;
if (data[0] & 0x80) np-&gt;stats.tx_fifo_errors++;
if (data[0] & 0x44) np-&gt;stats.tx_aborted_errors++;
if (data[0] & 0x20) np-&gt;stats.tx_window_errors++;
if (data[0] & 0x18) np-&gt;stats.tx_carrier_errors++;
}
/* Tx packet count in (data[1] & 0x0f) */
/* Hmmm, should simple missed packets be counted as an error? */
if (data[2] & 0x01) np-&gt;stats.rx_over_errors++;
np-&gt;stats.rx_missed_errors += data[3] + (data[4]&lt;&lt;8);
if ((data[5] & 1) == 0) { /* Link off */
/* We should switch transceivers here. */
}
if (memcmp(np-&gt;cur_ether_ctrl, np-&gt;new_ether_ctrl, 4)) {
if (debug &gt; 2)
printk(KERN_DEBUG "%s: USB setting Rx mode %2.2x..%2.2x.\n",
dev-&gt;name, np-&gt;new_ether_ctrl[0],
np-&gt;new_ether_ctrl[2]);
np-&gt;ctrl_msg[4] = RxFilter;
np-&gt;ctrl_msg[6] = 3;
np-&gt;ctrl_urb-&gt;transfer_buffer = np-&gt;new_ether_ctrl;
np-&gt;ctrl_urb-&gt;transfer_buffer_length = 3;
usb_submit_urb(np-&gt;ctrl_urb);
memcpy(np-&gt;cur_ether_ctrl, np-&gt;new_ether_ctrl, 4);
}
break;
case USB_ST_URB_KILLED:
default:
return;
}
}

static void tx_timeout(struct net_device *dev)
{
struct netdev_private *np = (struct netdev_private *)dev-&gt;priv;
unsigned char *d = np-&gt;intr_buffer; /* Short name for last irq status. */

printk(KERN_WARNING "%s: Transmit timed out. Last status %2.2x %2.2x "
"%2.2x %2.2x %2.2x.\n",
dev-&gt;name, d[0], d[1], d[2], d[3], d[4]);

dev-&gt;if_port = 0;
/* Reload the adapter registers. */
start_hardware(dev);

/* Clear transmit demands. */
clear_bit(0, (void*)&dev-&gt;tbusy);
if (np-&gt;tx_full) {
np-&gt;tx_full = 0;
netif_wake_queue(dev);
}

dev-&gt;trans_start = jiffies;
np-&gt;stats.tx_errors++;
return;
}

static void tx_urb_done(struct urb *urb)
{
struct tx_context *txc = urb-&gt;context;
struct sk_buff *skb = txc-&gt;skb;
struct net_device *dev = skb-&gt;dev;
struct netdev_private *np = dev-&gt;priv;

if (debug &gt; 2) {
if (urb-&gt;status != 0 || debug &gt; 3)
printk(KERN_DEBUG "%s: Tx packet transfer %d status %d, count %d.\n",
dev-&gt;name, np-&gt;dirty_tx, urb-&gt;status, urb-&gt;actual_length);
}
if (skb) {
np-&gt;stats.tx_packets++;
#if LINUX_VERSION_CODE &gt; 0x20127
np-&gt;stats.tx_bytes += skb-&gt;len;
#endif
/* Free the original skb. */
dev_kfree_skb(skb);
}
np-&gt;dirty_tx++;
clear_bit(0, (void*)&dev-&gt;tbusy);
if (np-&gt;tx_full) {
np-&gt;tx_full = 0;
netif_wake_queue(dev);
}
return;
}

static int start_tx(struct sk_buff *skb, struct net_device *dev)
{
struct netdev_private *np = (struct netdev_private *)dev-&gt;priv;
int status;

/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev-&gt;tbusy), but set_bit() works as well. */
if (test_and_set_bit(0, (void*)&dev-&gt;tbusy) != 0) {
/* This watchdog code is redundant with the media monitor timer. */
if (jiffies - dev-&gt;trans_start &gt; TX_TIMEOUT)
tx_timeout(dev);
return 1;
}

/* The end of the packet is marked by a short (under 64 byte) transfer.
For now we just pad a packet that would fit exactly. This is harmless
using IP, but should be corrected. */
if (1) {
struct tx_context *txc = &(np-&gt;txcontext[np-&gt;cur_tx++ % TX_Q]);
((u16*)txc-&gt;buffer)[0] = cpu_to_le16(skb-&gt;len);
memcpy(txc-&gt;buffer+2, skb-&gt;data, skb-&gt;len);

txc-&gt;skb = skb;
txc-&gt;urb-&gt;transfer_buffer_length = skb-&gt;len + 2;

if ((status = usb_submit_urb(txc-&gt;urb)) &lt; 0) {
printk(KERN_ERR "%s: Problem submitting transmit URB, %d.\n",
dev-&gt;name, status);
}
} else {
struct urb *urb = &(np-&gt;tx_urbs[np-&gt;cur_tx++ % TX_Q]);

if (np-&gt;drv_flags & UseTxCount) {
/* Prefix the count: we should usually have the headroom. */
if ((unsigned)skb_headroom(skb) &lt; 2 || skb_cloned(skb)) {
struct sk_buff *skb2 = skb_realloc_headroom(skb, 2);
if (debug &gt; 1)
printk(KERN_ERR "%s: Had to copy a transmit skbuff.\n",
dev-&gt;name);
kfree_skb(skb);
skb = skb2;
}
((u16*)(skb-&gt;data-2))[0] = cpu_to_le16(skb-&gt;len);
}
urb-&gt;transfer_buffer = skb-&gt;data - 2;
urb-&gt;transfer_buffer_length = skb-&gt;len + 2;
urb-&gt;context = skb;

if ((status = usb_submit_urb(urb)) &lt; 0) {
printk(KERN_ERR "%s: Problem submitting transmit URB, %d.\n",
dev-&gt;name, status);
}
}

if (np-&gt;cur_tx - np-&gt;dirty_tx &lt; TX_QUEUE_LEN)
clear_bit(0, (void*)&dev-&gt;tbusy); /* Typical path */
else
np-&gt;tx_full = 1;

dev-&gt;trans_start = jiffies;

if (debug &gt; 4)
printk(KERN_DEBUG "%s: Transmit frame len %d buf %p.\n", dev-&gt;name,
skb-&gt;len, skb-&gt;data);

return 0;
}

/* Arrruuuuggggg.
This is the receive routine, rewritten for URB support.
I still use only a single receive buffer. This should be fixed.
*/
static void rx_urb_done(struct urb *urb)
{
struct net_device *dev = urb-&gt;context;
struct netdev_private *np = dev-&gt;priv;
void *pkt_start = urb-&gt;transfer_buffer + 2;
int count = urb-&gt;actual_length;

if (debug &gt; 4)
printk(KERN_DEBUG "%s: rx_urb_done, status %d, count %d, buffer %p "
"(%p).\n",
dev-&gt;name, urb-&gt;status, urb-&gt;actual_length,
urb-&gt;transfer_buffer, np-&gt;rxbuffer);
if (urb-&gt;status == USB_ST_URB_KILLED)
return;
if (urb-&gt;status != 0)
return;
{
struct sk_buff *skb;
/* Length omits CRC and status. */
int pkt_len = le16_to_cpu(*(u16*)urb-&gt;transfer_buffer);

#ifndef final_version
if (debug &gt; 4)
printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d"
" of %d.\n",
pkt_len, count);
#endif
/* Check if the packet is long enough to accept without copying
to a minimally-sized skbuff. */
if ((skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
skb-&gt;dev = dev;
skb_reserve(skb, 2); /* 16 byte align the IP header */
eth_copy_and_sum(skb, pkt_start, pkt_len, 0);
skb_put(skb, pkt_len);
}
/* You will want this info for the initial debug. */
if (debug &gt; 5)
printk(KERN_DEBUG " Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:"
"%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x "
"%d.%d.%d.%d.\n",
skb-&gt;data[0], skb-&gt;data[1], skb-&gt;data[2], skb-&gt;data[3],
skb-&gt;data[4], skb-&gt;data[5], skb-&gt;data[6], skb-&gt;data[7],
skb-&gt;data[8], skb-&gt;data[9], skb-&gt;data[10],
skb-&gt;data[11], skb-&gt;data[12], skb-&gt;data[13],
skb-&gt;data[14], skb-&gt;data[15], skb-&gt;data[16],
skb-&gt;data[17]);

skb-&gt;protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev-&gt;last_rx = jiffies;
np-&gt;stats.rx_packets++;
#if LINUX_VERSION_CODE &gt; 0x20127
np-&gt;stats.rx_bytes += pkt_len;
#endif
}

if (usb_submit_urb(urb) &lt; 0) {
printk(KERN_ERR "%s: Problem submitting receive URB.\n", dev-&gt;name);
}
return;
}

static struct net_device_stats *get_stats(struct net_device *dev)
{
struct netdev_private *np = (struct netdev_private *)dev-&gt;priv;

/* Getting statistics over USB is painfully slow.
Limit the update rate. */
if (jiffies - np-&gt;last_stats &gt; STATS_UPDATE) {
u16 crc_errs = 0, txcolls = 0;
if (debug)
printk(KERN_DEBUG "%s: Getting statistics.\n", dev-&gt;name);

usb_control_msg(np-&gt;usb_dev, usb_rcvctrlpipe(np-&gt;usb_dev, 0),
0xFB, 0xC0, 0, 0x70, &crc_errs, 1, 10);
/* Actually the single-collision count. */
usb_control_msg(np-&gt;usb_dev, usb_rcvctrlpipe(np-&gt;usb_dev, 0),
0xFB, 0xC0, 0, 0x6A, &txcolls, 1, 10);
np-&gt;stats.rx_crc_errors += crc_errs;
np-&gt;stats.collisions += txcolls;
np-&gt;last_stats = jiffies;
if (debug)
printk(KERN_DEBUG "%s: Statistics %d, %d, %d.\n", dev-&gt;name,
crc_errs, txcolls, 0);
}
return &np-&gt;stats;
}

/* The little-endian AUTODIN II ethernet CRC calculations.
A big-endian version is also available.
This is slow but compact code. Do not use this routine for bulk data,
use a table-based routine instead.
This is common code and should be moved to net/core/crc.c.
Chips may use the upper or lower CRC bits, and may reverse and/or invert
them. Select the endian-ness that results in minimal calculations.
*/
static unsigned const ethernet_polynomial_le = 0xedb88320U;
static inline unsigned ether_crc_le(int length, unsigned char *data)
{
unsigned int crc = 0xffffffff; /* Initial value. */
while(--length &gt;= 0) {
unsigned char current_octet = *data++;
int bit;
for (bit = 8; --bit &gt;= 0; current_octet &gt;&gt;= 1) {
if ((crc ^ current_octet) & 1) {
crc &gt;&gt;= 1;
crc ^= ethernet_polynomial_le;
} else
crc &gt;&gt;= 1;
}
}
return crc;
}

/* Configuration is both in EtherCtrl and EtherCtrl2. */
enum { RxAllMulticast=0x02, RxPromiscuous=0x04 };

static void set_rx_mode(struct net_device *dev)
{
struct netdev_private *np = (struct netdev_private *)dev-&gt;priv;

if (dev-&gt;flags & IFF_PROMISC) { /* Set promiscuous. */
/* Unconditionally log net taps. */
printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev-&gt;name);
np-&gt;new_ether_ctrl[2] |= RxPromiscuous;
} else if ((dev-&gt;mc_count &gt; multicast_filter_limit)
|| (dev-&gt;flags & IFF_ALLMULTI)) {
np-&gt;new_ether_ctrl[0] |= RxAllMulticast;
np-&gt;new_ether_ctrl[2] &= ~RxPromiscuous;
} else {
struct dev_mc_list *mclist;
u32 mc_filter[2]; /* Multicast hash filter */
int i;
memset(mc_filter, 0, sizeof(mc_filter));
for (i = 0, mclist = dev-&gt;mc_list; mclist && i &lt; dev-&gt;mc_count;
i++, mclist = mclist-&gt;next) {
set_bit(ether_crc_le(ETH_ALEN, mclist-&gt;dmi_addr) & 0x3f,
mc_filter);
}
np-&gt;new_ether_ctrl[0] &= ~RxAllMulticast;
np-&gt;new_ether_ctrl[2] &= ~RxPromiscuous;
}
/* Do an update to the registers if needed. */
#if 0
ctrl_urb_done(np-&gt;ctrl_urb);
#endif
}

static int netdev_close(struct net_device *dev)
{
struct netdev_private *np = (struct netdev_private *)dev-&gt;priv;

dev-&gt;start = 0;
dev-&gt;tbusy = 1;

if (debug &gt; 1) {
printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev-&gt;name);
}
#if 0
if (debug &gt; 2) {
u8 regs[4];
catc_get_registers(np-&gt;usb_dev, 0, regs, 4);
printk(KERN_DEBUG "%s: Close register value %2.2x %2.2x %2.2x "
"%2.2x.\n",
dev-&gt;name, regs[0], regs[1], regs[2], regs[3]);
}
#endif

/* Disable interrupt reports. */
if (np-&gt;rx_urb0) {
usb_unlink_urb(np-&gt;rx_urb0);
usb_free_urb(np-&gt;rx_urb0);
np-&gt;rx_urb0 = 0;
}
if (np-&gt;rx_urb1) {
usb_unlink_urb(np-&gt;rx_urb1);
usb_free_urb(np-&gt;rx_urb1);
np-&gt;rx_urb1 = 0;
}
if (np-&gt;irq_urb) { /* cf. np-&gt;irq_period */
usb_unlink_urb(np-&gt;irq_urb);
usb_free_urb(np-&gt;irq_urb);
np-&gt;irq_urb = 0;
}
#if 0
if (np-&gt;tx_urb) {
usb_unlink_urb(np-&gt;tx_urb);
usb_free_urb(np-&gt;tx_urb);
}
#endif

if (debug &gt; 1)
printk(KERN_DEBUG "%s: Rx/Tx endpoints shut down, now trying Ctrl..\n",
dev-&gt;name);

#if 0
/* Ooopss, something is horribly wrong with this!. */
if (np-&gt;irq_handle)
usb_release_irq(np-&gt;usb_dev, np-&gt;irq_handle, np-&gt;ctrl_intr_pipe);
if (debug &gt; 1)
printk(KERN_DEBUG "%s: Control endpoint shut down.\n",
dev-&gt;name);
#endif
/* Stop the chip's Tx and Rx. */

del_timer(&np-&gt;timer);

/* Shut off the LEDs. */

if (debug &gt; 1)
printk(KERN_DEBUG "%s: Close completed.\n",
dev-&gt;name);

MOD_DEC_USE_COUNT;

return 0;
}

enum drv_pwr_action {
DRV_NOOP, /* No action. */
DRV_ATTACH, /* The driver may expect power ops. */
DRV_SUSPEND, /* Machine suspending, next event RESUME or DETACH. */
DRV_RESUME, /* Resume from previous SUSPEND */
DRV_DETACH, /* Card will-be/is gone. Valid from SUSPEND! */
DRV_PWR_WakeOn, /* Put device in e.g. Wake-On-LAN mode. */
DRV_PWR_DOWN, /* Go to lowest power mode. */
DRV_PWR_UP, /* Go to normal power mode. */
};

static int netdev_pwr_event(void *dev_instance, int event)
{
struct net_device *dev = dev_instance;
struct netdev_private *np = (struct netdev_private *)dev-&gt;priv;

if (debug &gt; 1)
printk(KERN_DEBUG "%s: Handling power event %d.\n", dev-&gt;name, event);
switch(event) {
case DRV_ATTACH:
MOD_INC_USE_COUNT;
break;
case DRV_SUSPEND:
/* Disable interrupts, stop Tx and Rx. */
break;
case DRV_RESUME:
/* This is incomplete: the actions are very chip specific. */
set_rx_mode(dev);
break;
case DRV_DETACH: {
if (dev-&gt;flags & IFF_UP) {
/* Some, but not all, kernel versions close automatically. */
dev_close(dev);
dev-&gt;flags &= ~(IFF_UP|IFF_RUNNING);
}
unregister_netdev(dev);
list_del(&np-&gt;list);
if (np-&gt;priv_addr)
kfree(np-&gt;priv_addr);
kfree(dev);
MOD_DEC_USE_COUNT;
break;
}
}

return 0;
}

#ifdef CONFIG_APM
#include &lt;linux/apm_bios.h&gt;

static int handle_apm_event(apm_event_t event)
{
static int down = 0;

if (debug &gt; 1)
printk(KERN_DEBUG "catc: Handling APM event %d.\n", event);
switch (event) {
case APM_SYS_SUSPEND:
case APM_USER_SUSPEND:
if (down) {
printk(KERN_DEBUG "catc: Received extra suspend event\n");
break;
}
down = 1;
break;
case APM_NORMAL_RESUME:
case APM_CRITICAL_RESUME:
if (!down) {
printk(KERN_DEBUG "catc: Received bogus resume event\n");
break;
}
down = 0;
/* We should step through the device list and do set_rx_mode(dev); */
break;
}
return 0;
}
#endif


#ifdef MODULE
int init_module(void)
{
if (debug) /* Emit version even if no cards detected. */
printk(KERN_INFO "%s", version);
#if defined(CONFIG_APM)
apm_register_callback(&handle_apm_event);
#endif
return usb_register(&catc_usb_id);
}

void cleanup_module(void)
{
if (root_net_dev) {
printk(KERN_ERR "catc.c: Device list not empty.\n");
}

#if rmmod_while_busy
while ( ! list_empty(&usbdev_list)) {
struct digitadev *dev = (void*)usbdev_list.next;
printk(KERN_ERR "%s: Disconnecting from device.\n", dev-&gt;name);
usb_driver_release_interface(&digita_usb_id,
dev-&gt;usb_dev-&gt;actconfig-&gt;interface);
list_del(&dev-&gt;list);
if (dev-&gt;priv_addr)
kfree(dev-&gt;priv_addr);
}
#endif

#if defined(CONFIG_APM)
apm_unregister_callback(&handle_apm_event);
#endif
usb_deregister(&catc_usb_id);
}

#else /* not a MODULE */

/* This function is called when statically linked into the kernel.
You *must* rename this to avoid name conflicts, and patch the new
entry into the static USB initialization list. */
int catc_init(void)
{
#if defined(CONFIG_APM)
apm_register_callback(&handle_apm_event);
#endif
/* Always emit version information for bug reports. */
printk(KERN_INFO "%s", version);
return usb_register(&catc_driver);
}

#endif /* MODULE */

/*
* Local variables:
* compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c catc.c"
* simple-compile-command: "gcc -DMODULE -O6 -c catc.c"
* c-indent-level: 4
* c-basic-offset: 4
* tab-width: 4
* End:
*/

bdg1983
07-06-2001, 05:11 PM
I know very little on the subject.

Since it's mentioned at the end of the source code, why not just try 'gcc -DMODULE -O6 -c catc.c'? If that doesn't work, then try the line prior to that.

bdg1983
07-06-2001, 05:13 PM
Probably would be easier to shell out the $10 to $20 and get a supported pci ethernet card.

sawman46445
07-06-2001, 06:04 PM
thanx!

bdg1983
07-07-2001, 06:05 AM
Did you try 'gcc -DMODULE -O6 -c catc.c' and if so, what were the results?

Chatterjee
07-08-2001, 01:06 AM
http://www.scyld.com/network/updates.html

I believe that link may help you. If it does, could you post how it did? Thanks!
-S

sawman46445
07-08-2001, 07:06 PM
Hi!
All worked well but one thing: the USB drivers were'nt there! So I downloaded the scyld USB drivers and was on my way to test how it all works right when I read my e-mail notofication about ur replys, I'm gonne see if it work sin a few mins.!
Thanx for ur help!
--saw