Move USB network drivers to drivers/net/usb.

It is preferable to group drivers by usage (net, scsi, ATA, ...) than
by bus.  When reviewing drivers, the [PCI|USB|PCMCIA|...] maintainer
is probably less qualified on networking issues than a networking
maintainer.  Also, from a practical standpoint, chips often
appear on multiple buses, which is why we do not put drivers into
drivers/pci/net.

Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
此提交包含在:
Jeff Garzik
2007-05-09 21:31:55 -04:00
父節點 3cb7396b7b
當前提交 5b2fc49991
共有 24 個檔案被更改,包括 10 行新增9 行删除

338
drivers/net/usb/Kconfig 一般檔案
查看文件

@@ -0,0 +1,338 @@
#
# USB Network devices configuration
#
comment "Networking support is needed for USB Network Adapter support"
depends on USB && !NET
menu "USB Network Adapters"
depends on USB && NET
config USB_CATC
tristate "USB CATC NetMate-based Ethernet device support (EXPERIMENTAL)"
depends on EXPERIMENTAL
select CRC32
---help---
Say Y if you want to use one of the following 10Mbps USB Ethernet
device based on the EL1210A chip. Supported devices are:
Belkin F5U011
Belkin F5U111
CATC NetMate
CATC NetMate II
smartBridges smartNIC
This driver makes the adapter appear as a normal Ethernet interface,
typically on eth0, if it is the only ethernet device, or perhaps on
eth1, if you have a PCI or ISA ethernet card installed.
To compile this driver as a module, choose M here: the
module will be called catc.
config USB_KAWETH
tristate "USB KLSI KL5USB101-based ethernet device support"
---help---
Say Y here if you want to use one of the following 10Mbps only
USB Ethernet adapters based on the KLSI KL5KUSB101B chipset:
3Com 3C19250
ADS USB-10BT
ATEN USB Ethernet
ASANTE USB To Ethernet Adapter
AOX Endpoints USB Ethernet
Correga K.K.
D-Link DSB-650C and DU-E10
Entrega / Portgear E45
I-O DATA USB-ET/T
Jaton USB Ethernet Device Adapter
Kingston Technology USB Ethernet Adapter
Linksys USB10T
Mobility USB-Ethernet Adapter
NetGear EA-101
Peracom Enet and Enet2
Portsmith Express Ethernet Adapter
Shark Pocket Adapter
SMC 2202USB
Sony Vaio port extender
This driver is likely to work with most 10Mbps only USB Ethernet
adapters, including some "no brand" devices. It does NOT work on
SmartBridges smartNIC or on Belkin F5U111 devices - you should use
the CATC NetMate driver for those. If you are not sure which one
you need, select both, and the correct one should be selected for
you.
This driver makes the adapter appear as a normal Ethernet interface,
typically on eth0, if it is the only ethernet device, or perhaps on
eth1, if you have a PCI or ISA ethernet card installed.
To compile this driver as a module, choose M here: the
module will be called kaweth.
config USB_PEGASUS
tristate "USB Pegasus/Pegasus-II based ethernet device support"
select MII
---help---
Say Y here if you know you have Pegasus or Pegasus-II based adapter.
If in doubt then look at <file:drivers/usb/net/pegasus.h> for the
complete list of supported devices.
If your particular adapter is not in the list and you are _sure_ it
is Pegasus or Pegasus II based then send me
<petkan@users.sourceforge.net> vendor and device IDs.
To compile this driver as a module, choose M here: the
module will be called pegasus.
config USB_RTL8150
tristate "USB RTL8150 based ethernet device support (EXPERIMENTAL)"
depends on EXPERIMENTAL
select MII
help
Say Y here if you have RTL8150 based usb-ethernet adapter.
Send me <petkan@users.sourceforge.net> any comments you may have.
You can also check for updates at <http://pegasus2.sourceforge.net/>.
To compile this driver as a module, choose M here: the
module will be called rtl8150.
config USB_USBNET_MII
tristate
default n
config USB_USBNET
tristate "Multi-purpose USB Networking Framework"
select MII if USB_USBNET_MII != n
---help---
This driver supports several kinds of network links over USB,
with "minidrivers" built around a common network driver core
that supports deep queues for efficient transfers. (This gives
better performance with small packets and at high speeds).
The USB host runs "usbnet", and the other end of the link might be:
- Another USB host, when using USB "network" or "data transfer"
cables. These are often used to network laptops to PCs, like
"Laplink" parallel cables or some motherboards. These rely
on specialized chips from many suppliers.
- An intelligent USB gadget, perhaps embedding a Linux system.
These include PDAs running Linux (iPaq, Yopy, Zaurus, and
others), and devices that interoperate using the standard
CDC-Ethernet specification (including many cable modems).
- Network adapter hardware (like those for 10/100 Ethernet) which
uses this driver framework.
The link will appear with a name like "usb0", when the link is
a two-node link, or "eth0" for most CDC-Ethernet devices. Those
two-node links are most easily managed with Ethernet Bridging
(CONFIG_BRIDGE) instead of routing.
For more information see <http://www.linux-usb.org/usbnet/>.
To compile this driver as a module, choose M here: the
module will be called usbnet.
config USB_NET_AX8817X
tristate "ASIX AX88xxx Based USB 2.0 Ethernet Adapters"
depends on USB_USBNET && NET_ETHERNET
select CRC32
select USB_USBNET_MII
default y
help
This option adds support for ASIX AX88xxx based USB 2.0
10/100 Ethernet adapters.
This driver should work with at least the following devices:
* Aten UC210T
* ASIX AX88172
* Billionton Systems, USB2AR
* Buffalo LUA-U2-KTX
* Corega FEther USB2-TX
* D-Link DUB-E100
* Hawking UF200
* Linksys USB200M
* Netgear FA120
* Sitecom LN-029
* Intellinet USB 2.0 Ethernet
* ST Lab USB 2.0 Ethernet
* TrendNet TU2-ET100
This driver creates an interface named "ethX", where X depends on
what other networking devices you have in use.
config USB_NET_CDCETHER
tristate "CDC Ethernet support (smart devices such as cable modems)"
depends on USB_USBNET
default y
help
This option supports devices conforming to the Communication Device
Class (CDC) Ethernet Control Model, a specification that's easy to
implement in device firmware. The CDC specifications are available
from <http://www.usb.org/>.
CDC Ethernet is an implementation option for DOCSIS cable modems
that support USB connectivity, used for non-Microsoft USB hosts.
The Linux-USB CDC Ethernet Gadget driver is an open implementation.
This driver should work with at least the following devices:
* Ericsson PipeRider (all variants)
* Motorola (DM100 and SB4100)
* Broadcom Cable Modem (reference design)
* Toshiba PCX1100U
* ...
This driver creates an interface named "ethX", where X depends on
what other networking devices you have in use. However, if the
IEEE 802 "local assignment" bit is set in the address, a "usbX"
name is used instead.
config USB_NET_DM9601
tristate "Davicom DM9601 based USB 1.1 10/100 ethernet devices"
depends on USB_USBNET
select CRC32
select USB_USBNET_MII
help
This option adds support for Davicom DM9601 based USB 1.1
10/100 Ethernet adapters.
config USB_NET_GL620A
tristate "GeneSys GL620USB-A based cables"
depends on USB_USBNET
help
Choose this option if you're using a host-to-host cable,
or PC2PC motherboard, with this chip.
Note that the half-duplex "GL620USB" is not supported.
config USB_NET_NET1080
tristate "NetChip 1080 based cables (Laplink, ...)"
default y
depends on USB_USBNET
help
Choose this option if you're using a host-to-host cable based
on this design: one NetChip 1080 chip and supporting logic,
optionally with LEDs that indicate traffic
config USB_NET_PLUSB
tristate "Prolific PL-2301/2302 based cables"
# if the handshake/init/reset problems, from original 'plusb',
# are ever resolved ... then remove "experimental"
depends on USB_USBNET && EXPERIMENTAL
help
Choose this option if you're using a host-to-host cable
with one of these chips.
config USB_NET_MCS7830
tristate "MosChip MCS7830 based Ethernet adapters"
depends on USB_USBNET
select USB_USBNET_MII
help
Choose this option if you're using a 10/100 Ethernet USB2
adapter based on the MosChip 7830 controller. This includes
adapters marketed under the DeLOCK brand.
config USB_NET_RNDIS_HOST
tristate "Host for RNDIS and ActiveSync devices (EXPERIMENTAL)"
depends on USB_USBNET && EXPERIMENTAL
select USB_NET_CDCETHER
help
This option enables hosting "Remote NDIS" USB networking links,
as encouraged by Microsoft (instead of CDC Ethernet!) for use in
various devices that may only support this protocol. A variant
of this protocol (with even less public documentation) seems to
be at the root of Microsoft's "ActiveSync" too.
Avoid using this protocol unless you have no better options.
The protocol specification is incomplete, and is controlled by
(and for) Microsoft; it isn't an "Open" ecosystem or market.
config USB_NET_CDC_SUBSET
tristate "Simple USB Network Links (CDC Ethernet subset)"
depends on USB_USBNET
default y
help
This driver module supports USB network devices that can work
without any device-specific information. Select it if you have
one of these drivers.
Note that while many USB host-to-host cables can work in this mode,
that may mean not being able to talk to Win32 systems or more
commonly not being able to handle certain events (like replugging
the host on the other end) very well. Also, these devices will
not generally have permanently assigned Ethernet addresses.
config USB_ALI_M5632
boolean "ALi M5632 based 'USB 2.0 Data Link' cables"
depends on USB_NET_CDC_SUBSET
help
Choose this option if you're using a host-to-host cable
based on this design, which supports USB 2.0 high speed.
config USB_AN2720
boolean "AnchorChips 2720 based cables (Xircom PGUNET, ...)"
depends on USB_NET_CDC_SUBSET
help
Choose this option if you're using a host-to-host cable
based on this design. Note that AnchorChips is now a
Cypress brand.
config USB_BELKIN
boolean "eTEK based host-to-host cables (Advance, Belkin, ...)"
depends on USB_NET_CDC_SUBSET
default y
help
Choose this option if you're using a host-to-host cable
based on this design: two NetChip 2890 chips and an Atmel
microcontroller, with LEDs that indicate traffic.
config USB_ARMLINUX
boolean "Embedded ARM Linux links (iPaq, ...)"
depends on USB_NET_CDC_SUBSET
default y
help
Choose this option to support the "usb-eth" networking driver
used by most of the ARM Linux community with device controllers
such as the SA-11x0 and PXA-25x UDCs, or the tftp capabilities
in some PXA versions of the "blob" boot loader.
Linux-based "Gumstix" PXA-25x based systems use this protocol
to talk with other Linux systems.
Although the ROMs shipped with Sharp Zaurus products use a
different link level framing protocol, you can have them use
this simpler protocol by installing a different kernel.
config USB_EPSON2888
boolean "Epson 2888 based firmware (DEVELOPMENT)"
depends on USB_NET_CDC_SUBSET
help
Choose this option to support the usb networking links used
by some sample firmware from Epson.
config USB_KC2190
boolean "KT Technology KC2190 based cables (InstaNet)"
depends on USB_NET_CDC_SUBSET && EXPERIMENTAL
help
<20>Choose this option if you're using a host-to-host cable
<20>with one of these chips.
config USB_NET_ZAURUS
tristate "Sharp Zaurus (stock ROMs) and compatible"
depends on USB_USBNET
select USB_NET_CDCETHER
select CRC32
default y
help
Choose this option to support the usb networking links used by
Zaurus models like the SL-5000D, SL-5500, SL-5600, A-300, B-500.
This also supports some related device firmware, as used in some
PDAs from Olympus and some cell phones from Motorola.
If you install an alternate image, such as the Linux 2.6 based
versions of OpenZaurus, you should no longer need to support this
protocol. Only the "eth-fd" or "net_fd" drivers in these devices
really need this non-conformant variant of CDC Ethernet (or in
some cases CDC MDLM) protocol, not "g_ether".
endmenu

23
drivers/net/usb/Makefile 一般檔案
查看文件

@@ -0,0 +1,23 @@
#
# Makefile for USB Network drivers
#
obj-$(CONFIG_USB_CATC) += catc.o
obj-$(CONFIG_USB_KAWETH) += kaweth.o
obj-$(CONFIG_USB_PEGASUS) += pegasus.o
obj-$(CONFIG_USB_RTL8150) += rtl8150.o
obj-$(CONFIG_USB_NET_AX8817X) += asix.o
obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o
obj-$(CONFIG_USB_NET_DM9601) += dm9601.o
obj-$(CONFIG_USB_NET_GL620A) += gl620a.o
obj-$(CONFIG_USB_NET_NET1080) += net1080.o
obj-$(CONFIG_USB_NET_PLUSB) += plusb.o
obj-$(CONFIG_USB_NET_RNDIS_HOST) += rndis_host.o
obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o
obj-$(CONFIG_USB_NET_ZAURUS) += zaurus.o
obj-$(CONFIG_USB_NET_MCS7830) += mcs7830.o
obj-$(CONFIG_USB_USBNET) += usbnet.o
ifeq ($(CONFIG_USB_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
endif

1490
drivers/net/usb/asix.c 一般檔案

檔案差異因為檔案過大而無法顯示 載入差異

963
drivers/net/usb/catc.c 一般檔案
查看文件

@@ -0,0 +1,963 @@
/*
* Copyright (c) 2001 Vojtech Pavlik
*
* CATC EL1210A NetMate USB Ethernet driver
*
* Sponsored by SuSE
*
* Based on the work of
* Donald Becker
*
* Old chipset support added by Simon Evans <spse@secret.org.uk> 2002
* - adds support for Belkin F5U011
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/ethtool.h>
#include <linux/crc32.h>
#include <linux/bitops.h>
#include <asm/uaccess.h>
#undef DEBUG
#include <linux/usb.h>
/*
* Version information.
*/
#define DRIVER_VERSION "v2.8"
#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@suse.cz>"
#define DRIVER_DESC "CATC EL1210A NetMate USB Ethernet driver"
#define SHORT_DRIVER_DESC "EL1210A NetMate USB Ethernet"
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
static const char driver_name[] = "catc";
/*
* Some defines.
*/
#define STATS_UPDATE (HZ) /* Time between stats updates */
#define TX_TIMEOUT (5*HZ) /* Max time the queue can be stopped */
#define PKT_SZ 1536 /* Max Ethernet packet size */
#define RX_MAX_BURST 15 /* Max packets per rx buffer (> 0, < 16) */
#define TX_MAX_BURST 15 /* Max full sized packets per tx buffer (> 0) */
#define CTRL_QUEUE 16 /* Max control requests in flight (power of two) */
#define RX_PKT_SZ 1600 /* Max size of receive packet for F5U011 */
/*
* Control requests.
*/
enum control_requests {
ReadMem = 0xf1,
GetMac = 0xf2,
Reset = 0xf4,
SetMac = 0xf5,
SetRxMode = 0xf5, /* F5U011 only */
WriteROM = 0xf8,
SetReg = 0xfa,
GetReg = 0xfb,
WriteMem = 0xfc,
ReadROM = 0xfd,
};
/*
* Registers.
*/
enum register_offsets {
TxBufCount = 0x20,
RxBufCount = 0x21,
OpModes = 0x22,
TxQed = 0x23,
RxQed = 0x24,
MaxBurst = 0x25,
RxUnit = 0x60,
EthStatus = 0x61,
StationAddr0 = 0x67,
EthStats = 0x69,
LEDCtrl = 0x81,
};
enum eth_stats {
TxSingleColl = 0x00,
TxMultiColl = 0x02,
TxExcessColl = 0x04,
RxFramErr = 0x06,
};
enum op_mode_bits {
Op3MemWaits = 0x03,
OpLenInclude = 0x08,
OpRxMerge = 0x10,
OpTxMerge = 0x20,
OpWin95bugfix = 0x40,
OpLoopback = 0x80,
};
enum rx_filter_bits {
RxEnable = 0x01,
RxPolarity = 0x02,
RxForceOK = 0x04,
RxMultiCast = 0x08,
RxPromisc = 0x10,
AltRxPromisc = 0x20, /* F5U011 uses different bit */
};
enum led_values {
LEDFast = 0x01,
LEDSlow = 0x02,
LEDFlash = 0x03,
LEDPulse = 0x04,
LEDLink = 0x08,
};
enum link_status {
LinkNoChange = 0,
LinkGood = 1,
LinkBad = 2
};
/*
* The catc struct.
*/
#define CTRL_RUNNING 0
#define RX_RUNNING 1
#define TX_RUNNING 2
struct catc {
struct net_device *netdev;
struct usb_device *usbdev;
struct net_device_stats stats;
unsigned long flags;
unsigned int tx_ptr, tx_idx;
unsigned int ctrl_head, ctrl_tail;
spinlock_t tx_lock, ctrl_lock;
u8 tx_buf[2][TX_MAX_BURST * (PKT_SZ + 2)];
u8 rx_buf[RX_MAX_BURST * (PKT_SZ + 2)];
u8 irq_buf[2];
u8 ctrl_buf[64];
struct usb_ctrlrequest ctrl_dr;
struct timer_list timer;
u8 stats_buf[8];
u16 stats_vals[4];
unsigned long last_stats;
u8 multicast[64];
struct ctrl_queue {
u8 dir;
u8 request;
u16 value;
u16 index;
void *buf;
int len;
void (*callback)(struct catc *catc, struct ctrl_queue *q);
} ctrl_queue[CTRL_QUEUE];
struct urb *tx_urb, *rx_urb, *irq_urb, *ctrl_urb;
u8 is_f5u011; /* Set if device is an F5U011 */
u8 rxmode[2]; /* Used for F5U011 */
atomic_t recq_sz; /* Used for F5U011 - counter of waiting rx packets */
};
/*
* Useful macros.
*/
#define catc_get_mac(catc, mac) catc_ctrl_msg(catc, USB_DIR_IN, GetMac, 0, 0, mac, 6)
#define catc_reset(catc) catc_ctrl_msg(catc, USB_DIR_OUT, Reset, 0, 0, NULL, 0)
#define catc_set_reg(catc, reg, val) catc_ctrl_msg(catc, USB_DIR_OUT, SetReg, val, reg, NULL, 0)
#define catc_get_reg(catc, reg, buf) catc_ctrl_msg(catc, USB_DIR_IN, GetReg, 0, reg, buf, 1)
#define catc_write_mem(catc, addr, buf, size) catc_ctrl_msg(catc, USB_DIR_OUT, WriteMem, 0, addr, buf, size)
#define catc_read_mem(catc, addr, buf, size) catc_ctrl_msg(catc, USB_DIR_IN, ReadMem, 0, addr, buf, size)
#define f5u011_rxmode(catc, rxmode) catc_ctrl_msg(catc, USB_DIR_OUT, SetRxMode, 0, 1, rxmode, 2)
#define f5u011_rxmode_async(catc, rxmode) catc_ctrl_async(catc, USB_DIR_OUT, SetRxMode, 0, 1, &rxmode, 2, NULL)
#define f5u011_mchash_async(catc, hash) catc_ctrl_async(catc, USB_DIR_OUT, SetRxMode, 0, 2, &hash, 8, NULL)
#define catc_set_reg_async(catc, reg, val) catc_ctrl_async(catc, USB_DIR_OUT, SetReg, val, reg, NULL, 0, NULL)
#define catc_get_reg_async(catc, reg, cb) catc_ctrl_async(catc, USB_DIR_IN, GetReg, 0, reg, NULL, 1, cb)
#define catc_write_mem_async(catc, addr, buf, size) catc_ctrl_async(catc, USB_DIR_OUT, WriteMem, 0, addr, buf, size, NULL)
/*
* Receive routines.
*/
static void catc_rx_done(struct urb *urb)
{
struct catc *catc = urb->context;
u8 *pkt_start = urb->transfer_buffer;
struct sk_buff *skb;
int pkt_len, pkt_offset = 0;
if (!catc->is_f5u011) {
clear_bit(RX_RUNNING, &catc->flags);
pkt_offset = 2;
}
if (urb->status) {
dbg("rx_done, status %d, length %d", urb->status, urb->actual_length);
return;
}
do {
if(!catc->is_f5u011) {
pkt_len = le16_to_cpup((__le16*)pkt_start);
if (pkt_len > urb->actual_length) {
catc->stats.rx_length_errors++;
catc->stats.rx_errors++;
break;
}
} else {
pkt_len = urb->actual_length;
}
if (!(skb = dev_alloc_skb(pkt_len)))
return;
eth_copy_and_sum(skb, pkt_start + pkt_offset, pkt_len, 0);
skb_put(skb, pkt_len);
skb->protocol = eth_type_trans(skb, catc->netdev);
netif_rx(skb);
catc->stats.rx_packets++;
catc->stats.rx_bytes += pkt_len;
/* F5U011 only does one packet per RX */
if (catc->is_f5u011)
break;
pkt_start += (((pkt_len + 1) >> 6) + 1) << 6;
} while (pkt_start - (u8 *) urb->transfer_buffer < urb->actual_length);
catc->netdev->last_rx = jiffies;
if (catc->is_f5u011) {
if (atomic_read(&catc->recq_sz)) {
int status;
atomic_dec(&catc->recq_sz);
dbg("getting extra packet");
urb->dev = catc->usbdev;
if ((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
dbg("submit(rx_urb) status %d", status);
}
} else {
clear_bit(RX_RUNNING, &catc->flags);
}
}
}
static void catc_irq_done(struct urb *urb)
{
struct catc *catc = urb->context;
u8 *data = urb->transfer_buffer;
int status;
unsigned int hasdata = 0, linksts = LinkNoChange;
if (!catc->is_f5u011) {
hasdata = data[1] & 0x80;
if (data[1] & 0x40)
linksts = LinkGood;
else if (data[1] & 0x20)
linksts = LinkBad;
} else {
hasdata = (unsigned int)(be16_to_cpup((__be16*)data) & 0x0fff);
if (data[0] == 0x90)
linksts = LinkGood;
else if (data[0] == 0xA0)
linksts = LinkBad;
}
switch (urb->status) {
case 0: /* success */
break;
case -ECONNRESET: /* unlink */
case -ENOENT:
case -ESHUTDOWN:
return;
/* -EPIPE: should clear the halt */
default: /* error */
dbg("irq_done, status %d, data %02x %02x.", urb->status, data[0], data[1]);
goto resubmit;
}
if (linksts == LinkGood) {
netif_carrier_on(catc->netdev);
dbg("link ok");
}
if (linksts == LinkBad) {
netif_carrier_off(catc->netdev);
dbg("link bad");
}
if (hasdata) {
if (test_and_set_bit(RX_RUNNING, &catc->flags)) {
if (catc->is_f5u011)
atomic_inc(&catc->recq_sz);
} else {
catc->rx_urb->dev = catc->usbdev;
if ((status = usb_submit_urb(catc->rx_urb, GFP_ATOMIC)) < 0) {
err("submit(rx_urb) status %d", status);
}
}
}
resubmit:
status = usb_submit_urb (urb, GFP_ATOMIC);
if (status)
err ("can't resubmit intr, %s-%s, status %d",
catc->usbdev->bus->bus_name,
catc->usbdev->devpath, status);
}
/*
* Transmit routines.
*/
static int catc_tx_run(struct catc *catc)
{
int status;
if (catc->is_f5u011)
catc->tx_ptr = (catc->tx_ptr + 63) & ~63;
catc->tx_urb->transfer_buffer_length = catc->tx_ptr;
catc->tx_urb->transfer_buffer = catc->tx_buf[catc->tx_idx];
catc->tx_urb->dev = catc->usbdev;
if ((status = usb_submit_urb(catc->tx_urb, GFP_ATOMIC)) < 0)
err("submit(tx_urb), status %d", status);
catc->tx_idx = !catc->tx_idx;
catc->tx_ptr = 0;
catc->netdev->trans_start = jiffies;
return status;
}
static void catc_tx_done(struct urb *urb)
{
struct catc *catc = urb->context;
unsigned long flags;
int r;
if (urb->status == -ECONNRESET) {
dbg("Tx Reset.");
urb->status = 0;
catc->netdev->trans_start = jiffies;
catc->stats.tx_errors++;
clear_bit(TX_RUNNING, &catc->flags);
netif_wake_queue(catc->netdev);
return;
}
if (urb->status) {
dbg("tx_done, status %d, length %d", urb->status, urb->actual_length);
return;
}
spin_lock_irqsave(&catc->tx_lock, flags);
if (catc->tx_ptr) {
r = catc_tx_run(catc);
if (unlikely(r < 0))
clear_bit(TX_RUNNING, &catc->flags);
} else {
clear_bit(TX_RUNNING, &catc->flags);
}
netif_wake_queue(catc->netdev);
spin_unlock_irqrestore(&catc->tx_lock, flags);
}
static int catc_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct catc *catc = netdev_priv(netdev);
unsigned long flags;
int r = 0;
char *tx_buf;
spin_lock_irqsave(&catc->tx_lock, flags);
catc->tx_ptr = (((catc->tx_ptr - 1) >> 6) + 1) << 6;
tx_buf = catc->tx_buf[catc->tx_idx] + catc->tx_ptr;
*((u16*)tx_buf) = (catc->is_f5u011) ? cpu_to_be16((u16)skb->len) : cpu_to_le16((u16)skb->len);
skb_copy_from_linear_data(skb, tx_buf + 2, skb->len);
catc->tx_ptr += skb->len + 2;
if (!test_and_set_bit(TX_RUNNING, &catc->flags)) {
r = catc_tx_run(catc);
if (r < 0)
clear_bit(TX_RUNNING, &catc->flags);
}
if ((catc->is_f5u011 && catc->tx_ptr)
|| (catc->tx_ptr >= ((TX_MAX_BURST - 1) * (PKT_SZ + 2))))
netif_stop_queue(netdev);
spin_unlock_irqrestore(&catc->tx_lock, flags);
if (r >= 0) {
catc->stats.tx_bytes += skb->len;
catc->stats.tx_packets++;
}
dev_kfree_skb(skb);
return 0;
}
static void catc_tx_timeout(struct net_device *netdev)
{
struct catc *catc = netdev_priv(netdev);
warn("Transmit timed out.");
usb_unlink_urb(catc->tx_urb);
}
/*
* Control messages.
*/
static int catc_ctrl_msg(struct catc *catc, u8 dir, u8 request, u16 value, u16 index, void *buf, int len)
{
int retval = usb_control_msg(catc->usbdev,
dir ? usb_rcvctrlpipe(catc->usbdev, 0) : usb_sndctrlpipe(catc->usbdev, 0),
request, 0x40 | dir, value, index, buf, len, 1000);
return retval < 0 ? retval : 0;
}
static void catc_ctrl_run(struct catc *catc)
{
struct ctrl_queue *q = catc->ctrl_queue + catc->ctrl_tail;
struct usb_device *usbdev = catc->usbdev;
struct urb *urb = catc->ctrl_urb;
struct usb_ctrlrequest *dr = &catc->ctrl_dr;
int status;
dr->bRequest = q->request;
dr->bRequestType = 0x40 | q->dir;
dr->wValue = cpu_to_le16(q->value);
dr->wIndex = cpu_to_le16(q->index);
dr->wLength = cpu_to_le16(q->len);
urb->pipe = q->dir ? usb_rcvctrlpipe(usbdev, 0) : usb_sndctrlpipe(usbdev, 0);
urb->transfer_buffer_length = q->len;
urb->transfer_buffer = catc->ctrl_buf;
urb->setup_packet = (void *) dr;
urb->dev = usbdev;
if (!q->dir && q->buf && q->len)
memcpy(catc->ctrl_buf, q->buf, q->len);
if ((status = usb_submit_urb(catc->ctrl_urb, GFP_KERNEL)))
err("submit(ctrl_urb) status %d", status);
}
static void catc_ctrl_done(struct urb *urb)
{
struct catc *catc = urb->context;
struct ctrl_queue *q;
unsigned long flags;
if (urb->status)
dbg("ctrl_done, status %d, len %d.", urb->status, urb->actual_length);
spin_lock_irqsave(&catc->ctrl_lock, flags);
q = catc->ctrl_queue + catc->ctrl_tail;
if (q->dir) {
if (q->buf && q->len)
memcpy(q->buf, catc->ctrl_buf, q->len);
else
q->buf = catc->ctrl_buf;
}
if (q->callback)
q->callback(catc, q);
catc->ctrl_tail = (catc->ctrl_tail + 1) & (CTRL_QUEUE - 1);
if (catc->ctrl_head != catc->ctrl_tail)
catc_ctrl_run(catc);
else
clear_bit(CTRL_RUNNING, &catc->flags);
spin_unlock_irqrestore(&catc->ctrl_lock, flags);
}
static int catc_ctrl_async(struct catc *catc, u8 dir, u8 request, u16 value,
u16 index, void *buf, int len, void (*callback)(struct catc *catc, struct ctrl_queue *q))
{
struct ctrl_queue *q;
int retval = 0;
unsigned long flags;
spin_lock_irqsave(&catc->ctrl_lock, flags);
q = catc->ctrl_queue + catc->ctrl_head;
q->dir = dir;
q->request = request;
q->value = value;
q->index = index;
q->buf = buf;
q->len = len;
q->callback = callback;
catc->ctrl_head = (catc->ctrl_head + 1) & (CTRL_QUEUE - 1);
if (catc->ctrl_head == catc->ctrl_tail) {
err("ctrl queue full");
catc->ctrl_tail = (catc->ctrl_tail + 1) & (CTRL_QUEUE - 1);
retval = -1;
}
if (!test_and_set_bit(CTRL_RUNNING, &catc->flags))
catc_ctrl_run(catc);
spin_unlock_irqrestore(&catc->ctrl_lock, flags);
return retval;
}
/*
* Statistics.
*/
static void catc_stats_done(struct catc *catc, struct ctrl_queue *q)
{
int index = q->index - EthStats;
u16 data, last;
catc->stats_buf[index] = *((char *)q->buf);
if (index & 1)
return;
data = ((u16)catc->stats_buf[index] << 8) | catc->stats_buf[index + 1];
last = catc->stats_vals[index >> 1];
switch (index) {
case TxSingleColl:
case TxMultiColl:
catc->stats.collisions += data - last;
break;
case TxExcessColl:
catc->stats.tx_aborted_errors += data - last;
catc->stats.tx_errors += data - last;
break;
case RxFramErr:
catc->stats.rx_frame_errors += data - last;
catc->stats.rx_errors += data - last;
break;
}
catc->stats_vals[index >> 1] = data;
}
static void catc_stats_timer(unsigned long data)
{
struct catc *catc = (void *) data;
int i;
for (i = 0; i < 8; i++)
catc_get_reg_async(catc, EthStats + 7 - i, catc_stats_done);
mod_timer(&catc->timer, jiffies + STATS_UPDATE);
}
static struct net_device_stats *catc_get_stats(struct net_device *netdev)
{
struct catc *catc = netdev_priv(netdev);
return &catc->stats;
}
/*
* Receive modes. Broadcast, Multicast, Promisc.
*/
static void catc_multicast(unsigned char *addr, u8 *multicast)
{
u32 crc;
crc = ether_crc_le(6, addr);
multicast[(crc >> 3) & 0x3f] |= 1 << (crc & 7);
}
static void catc_set_multicast_list(struct net_device *netdev)
{
struct catc *catc = netdev_priv(netdev);
struct dev_mc_list *mc;
u8 broadcast[6];
u8 rx = RxEnable | RxPolarity | RxMultiCast;
int i;
memset(broadcast, 0xff, 6);
memset(catc->multicast, 0, 64);
catc_multicast(broadcast, catc->multicast);
catc_multicast(netdev->dev_addr, catc->multicast);
if (netdev->flags & IFF_PROMISC) {
memset(catc->multicast, 0xff, 64);
rx |= (!catc->is_f5u011) ? RxPromisc : AltRxPromisc;
}
if (netdev->flags & IFF_ALLMULTI) {
memset(catc->multicast, 0xff, 64);
} else {
for (i = 0, mc = netdev->mc_list; mc && i < netdev->mc_count; i++, mc = mc->next) {
u32 crc = ether_crc_le(6, mc->dmi_addr);
if (!catc->is_f5u011) {
catc->multicast[(crc >> 3) & 0x3f] |= 1 << (crc & 7);
} else {
catc->multicast[7-(crc >> 29)] |= 1 << ((crc >> 26) & 7);
}
}
}
if (!catc->is_f5u011) {
catc_set_reg_async(catc, RxUnit, rx);
catc_write_mem_async(catc, 0xfa80, catc->multicast, 64);
} else {
f5u011_mchash_async(catc, catc->multicast);
if (catc->rxmode[0] != rx) {
catc->rxmode[0] = rx;
dbg("Setting RX mode to %2.2X %2.2X", catc->rxmode[0], catc->rxmode[1]);
f5u011_rxmode_async(catc, catc->rxmode);
}
}
}
static void catc_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
struct catc *catc = netdev_priv(dev);
strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN);
strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
usb_make_path (catc->usbdev, info->bus_info, sizeof info->bus_info);
}
static int catc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct catc *catc = netdev_priv(dev);
if (!catc->is_f5u011)
return -EOPNOTSUPP;
cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_TP;
cmd->advertising = ADVERTISED_10baseT_Half | ADVERTISED_TP;
cmd->speed = SPEED_10;
cmd->duplex = DUPLEX_HALF;
cmd->port = PORT_TP;
cmd->phy_address = 0;
cmd->transceiver = XCVR_INTERNAL;
cmd->autoneg = AUTONEG_DISABLE;
cmd->maxtxpkt = 1;
cmd->maxrxpkt = 1;
return 0;
}
static struct ethtool_ops ops = {
.get_drvinfo = catc_get_drvinfo,
.get_settings = catc_get_settings,
.get_link = ethtool_op_get_link
};
/*
* Open, close.
*/
static int catc_open(struct net_device *netdev)
{
struct catc *catc = netdev_priv(netdev);
int status;
catc->irq_urb->dev = catc->usbdev;
if ((status = usb_submit_urb(catc->irq_urb, GFP_KERNEL)) < 0) {
err("submit(irq_urb) status %d", status);
return -1;
}
netif_start_queue(netdev);
if (!catc->is_f5u011)
mod_timer(&catc->timer, jiffies + STATS_UPDATE);
return 0;
}
static int catc_stop(struct net_device *netdev)
{
struct catc *catc = netdev_priv(netdev);
netif_stop_queue(netdev);
if (!catc->is_f5u011)
del_timer_sync(&catc->timer);
usb_kill_urb(catc->rx_urb);
usb_kill_urb(catc->tx_urb);
usb_kill_urb(catc->irq_urb);
usb_kill_urb(catc->ctrl_urb);
return 0;
}
/*
* USB probe, disconnect.
*/
static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *usbdev = interface_to_usbdev(intf);
struct net_device *netdev;
struct catc *catc;
u8 broadcast[6];
int i, pktsz;
if (usb_set_interface(usbdev,
intf->altsetting->desc.bInterfaceNumber, 1)) {
err("Can't set altsetting 1.");
return -EIO;
}
netdev = alloc_etherdev(sizeof(struct catc));
if (!netdev)
return -ENOMEM;
catc = netdev_priv(netdev);
netdev->open = catc_open;
netdev->hard_start_xmit = catc_hard_start_xmit;
netdev->stop = catc_stop;
netdev->get_stats = catc_get_stats;
netdev->tx_timeout = catc_tx_timeout;
netdev->watchdog_timeo = TX_TIMEOUT;
netdev->set_multicast_list = catc_set_multicast_list;
SET_ETHTOOL_OPS(netdev, &ops);
catc->usbdev = usbdev;
catc->netdev = netdev;
spin_lock_init(&catc->tx_lock);
spin_lock_init(&catc->ctrl_lock);
init_timer(&catc->timer);
catc->timer.data = (long) catc;
catc->timer.function = catc_stats_timer;
catc->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
catc->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
catc->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
catc->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
if ((!catc->ctrl_urb) || (!catc->tx_urb) ||
(!catc->rx_urb) || (!catc->irq_urb)) {
err("No free urbs available.");
usb_free_urb(catc->ctrl_urb);
usb_free_urb(catc->tx_urb);
usb_free_urb(catc->rx_urb);
usb_free_urb(catc->irq_urb);
free_netdev(netdev);
return -ENOMEM;
}
/* The F5U011 has the same vendor/product as the netmate but a device version of 0x130 */
if (le16_to_cpu(usbdev->descriptor.idVendor) == 0x0423 &&
le16_to_cpu(usbdev->descriptor.idProduct) == 0xa &&
le16_to_cpu(catc->usbdev->descriptor.bcdDevice) == 0x0130) {
dbg("Testing for f5u011");
catc->is_f5u011 = 1;
atomic_set(&catc->recq_sz, 0);
pktsz = RX_PKT_SZ;
} else {
pktsz = RX_MAX_BURST * (PKT_SZ + 2);
}
usb_fill_control_urb(catc->ctrl_urb, usbdev, usb_sndctrlpipe(usbdev, 0),
NULL, NULL, 0, catc_ctrl_done, catc);
usb_fill_bulk_urb(catc->tx_urb, usbdev, usb_sndbulkpipe(usbdev, 1),
NULL, 0, catc_tx_done, catc);
usb_fill_bulk_urb(catc->rx_urb, usbdev, usb_rcvbulkpipe(usbdev, 1),
catc->rx_buf, pktsz, catc_rx_done, catc);
usb_fill_int_urb(catc->irq_urb, usbdev, usb_rcvintpipe(usbdev, 2),
catc->irq_buf, 2, catc_irq_done, catc, 1);
if (!catc->is_f5u011) {
dbg("Checking memory size\n");
i = 0x12345678;
catc_write_mem(catc, 0x7a80, &i, 4);
i = 0x87654321;
catc_write_mem(catc, 0xfa80, &i, 4);
catc_read_mem(catc, 0x7a80, &i, 4);
switch (i) {
case 0x12345678:
catc_set_reg(catc, TxBufCount, 8);
catc_set_reg(catc, RxBufCount, 32);
dbg("64k Memory\n");
break;
default:
warn("Couldn't detect memory size, assuming 32k");
case 0x87654321:
catc_set_reg(catc, TxBufCount, 4);
catc_set_reg(catc, RxBufCount, 16);
dbg("32k Memory\n");
break;
}
dbg("Getting MAC from SEEROM.");
catc_get_mac(catc, netdev->dev_addr);
dbg("Setting MAC into registers.");
for (i = 0; i < 6; i++)
catc_set_reg(catc, StationAddr0 - i, netdev->dev_addr[i]);
dbg("Filling the multicast list.");
memset(broadcast, 0xff, 6);
catc_multicast(broadcast, catc->multicast);
catc_multicast(netdev->dev_addr, catc->multicast);
catc_write_mem(catc, 0xfa80, catc->multicast, 64);
dbg("Clearing error counters.");
for (i = 0; i < 8; i++)
catc_set_reg(catc, EthStats + i, 0);
catc->last_stats = jiffies;
dbg("Enabling.");
catc_set_reg(catc, MaxBurst, RX_MAX_BURST);
catc_set_reg(catc, OpModes, OpTxMerge | OpRxMerge | OpLenInclude | Op3MemWaits);
catc_set_reg(catc, LEDCtrl, LEDLink);
catc_set_reg(catc, RxUnit, RxEnable | RxPolarity | RxMultiCast);
} else {
dbg("Performing reset\n");
catc_reset(catc);
catc_get_mac(catc, netdev->dev_addr);
dbg("Setting RX Mode");
catc->rxmode[0] = RxEnable | RxPolarity | RxMultiCast;
catc->rxmode[1] = 0;
f5u011_rxmode(catc, catc->rxmode);
}
dbg("Init done.");
printk(KERN_INFO "%s: %s USB Ethernet at usb-%s-%s, ",
netdev->name, (catc->is_f5u011) ? "Belkin F5U011" : "CATC EL1210A NetMate",
usbdev->bus->bus_name, usbdev->devpath);
for (i = 0; i < 5; i++) printk("%2.2x:", netdev->dev_addr[i]);
printk("%2.2x.\n", netdev->dev_addr[i]);
usb_set_intfdata(intf, catc);
SET_NETDEV_DEV(netdev, &intf->dev);
if (register_netdev(netdev) != 0) {
usb_set_intfdata(intf, NULL);
usb_free_urb(catc->ctrl_urb);
usb_free_urb(catc->tx_urb);
usb_free_urb(catc->rx_urb);
usb_free_urb(catc->irq_urb);
free_netdev(netdev);
return -EIO;
}
return 0;
}
static void catc_disconnect(struct usb_interface *intf)
{
struct catc *catc = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL);
if (catc) {
unregister_netdev(catc->netdev);
usb_free_urb(catc->ctrl_urb);
usb_free_urb(catc->tx_urb);
usb_free_urb(catc->rx_urb);
usb_free_urb(catc->irq_urb);
free_netdev(catc->netdev);
}
}
/*
* Module functions and tables.
*/
static struct usb_device_id catc_id_table [] = {
{ USB_DEVICE(0x0423, 0xa) }, /* CATC Netmate, Belkin F5U011 */
{ USB_DEVICE(0x0423, 0xc) }, /* CATC Netmate II, Belkin F5U111 */
{ USB_DEVICE(0x08d1, 0x1) }, /* smartBridges smartNIC */
{ }
};
MODULE_DEVICE_TABLE(usb, catc_id_table);
static struct usb_driver catc_driver = {
.name = driver_name,
.probe = catc_probe,
.disconnect = catc_disconnect,
.id_table = catc_id_table,
};
static int __init catc_init(void)
{
int result = usb_register(&catc_driver);
if (result == 0)
info(DRIVER_VERSION " " DRIVER_DESC);
return result;
}
static void __exit catc_exit(void)
{
usb_deregister(&catc_driver);
}
module_init(catc_init);
module_exit(catc_exit);

570
drivers/net/usb/cdc_ether.c 一般檔案
查看文件

@@ -0,0 +1,570 @@
/*
* CDC Ethernet based networking peripherals
* Copyright (C) 2003-2005 by David Brownell
* Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// #define DEBUG // error path messages, extra info
// #define VERBOSE // more; success messages
#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ctype.h>
#include <linux/ethtool.h>
#include <linux/workqueue.h>
#include <linux/mii.h>
#include <linux/usb.h>
#include <linux/usb/cdc.h>
#include "usbnet.h"
#if defined(CONFIG_USB_NET_RNDIS_HOST) || defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
static int is_rndis(struct usb_interface_descriptor *desc)
{
return desc->bInterfaceClass == USB_CLASS_COMM
&& desc->bInterfaceSubClass == 2
&& desc->bInterfaceProtocol == 0xff;
}
static int is_activesync(struct usb_interface_descriptor *desc)
{
return desc->bInterfaceClass == USB_CLASS_MISC
&& desc->bInterfaceSubClass == 1
&& desc->bInterfaceProtocol == 1;
}
#else
#define is_rndis(desc) 0
#define is_activesync(desc) 0
#endif
/*
* probes control interface, claims data interface, collects the bulk
* endpoints, activates data interface (if needed), maybe sets MTU.
* all pure cdc, except for certain firmware workarounds, and knowing
* that rndis uses one different rule.
*/
int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
{
u8 *buf = intf->cur_altsetting->extra;
int len = intf->cur_altsetting->extralen;
struct usb_interface_descriptor *d;
struct cdc_state *info = (void *) &dev->data;
int status;
int rndis;
struct usb_driver *driver = driver_of(intf);
if (sizeof dev->data < sizeof *info)
return -EDOM;
/* expect strict spec conformance for the descriptors, but
* cope with firmware which stores them in the wrong place
*/
if (len == 0 && dev->udev->actconfig->extralen) {
/* Motorola SB4100 (and others: Brad Hards says it's
* from a Broadcom design) put CDC descriptors here
*/
buf = dev->udev->actconfig->extra;
len = dev->udev->actconfig->extralen;
if (len)
dev_dbg(&intf->dev,
"CDC descriptors on config\n");
}
/* this assumes that if there's a non-RNDIS vendor variant
* of cdc-acm, it'll fail RNDIS requests cleanly.
*/
rndis = is_rndis(&intf->cur_altsetting->desc)
|| is_activesync(&intf->cur_altsetting->desc);
memset(info, 0, sizeof *info);
info->control = intf;
while (len > 3) {
if (buf [1] != USB_DT_CS_INTERFACE)
goto next_desc;
/* use bDescriptorSubType to identify the CDC descriptors.
* We expect devices with CDC header and union descriptors.
* For CDC Ethernet we need the ethernet descriptor.
* For RNDIS, ignore two (pointless) CDC modem descriptors
* in favor of a complicated OID-based RPC scheme doing what
* CDC Ethernet achieves with a simple descriptor.
*/
switch (buf [2]) {
case USB_CDC_HEADER_TYPE:
if (info->header) {
dev_dbg(&intf->dev, "extra CDC header\n");
goto bad_desc;
}
info->header = (void *) buf;
if (info->header->bLength != sizeof *info->header) {
dev_dbg(&intf->dev, "CDC header len %u\n",
info->header->bLength);
goto bad_desc;
}
break;
case USB_CDC_ACM_TYPE:
/* paranoia: disambiguate a "real" vendor-specific
* modem interface from an RNDIS non-modem.
*/
if (rndis) {
struct usb_cdc_acm_descriptor *d;
d = (void *) buf;
if (d->bmCapabilities) {
dev_dbg(&intf->dev,
"ACM capabilities %02x, "
"not really RNDIS?\n",
d->bmCapabilities);
goto bad_desc;
}
}
break;
case USB_CDC_UNION_TYPE:
if (info->u) {
dev_dbg(&intf->dev, "extra CDC union\n");
goto bad_desc;
}
info->u = (void *) buf;
if (info->u->bLength != sizeof *info->u) {
dev_dbg(&intf->dev, "CDC union len %u\n",
info->u->bLength);
goto bad_desc;
}
/* we need a master/control interface (what we're
* probed with) and a slave/data interface; union
* descriptors sort this all out.
*/
info->control = usb_ifnum_to_if(dev->udev,
info->u->bMasterInterface0);
info->data = usb_ifnum_to_if(dev->udev,
info->u->bSlaveInterface0);
if (!info->control || !info->data) {
dev_dbg(&intf->dev,
"master #%u/%p slave #%u/%p\n",
info->u->bMasterInterface0,
info->control,
info->u->bSlaveInterface0,
info->data);
goto bad_desc;
}
if (info->control != intf) {
dev_dbg(&intf->dev, "bogus CDC Union\n");
/* Ambit USB Cable Modem (and maybe others)
* interchanges master and slave interface.
*/
if (info->data == intf) {
info->data = info->control;
info->control = intf;
} else
goto bad_desc;
}
/* a data interface altsetting does the real i/o */
d = &info->data->cur_altsetting->desc;
if (d->bInterfaceClass != USB_CLASS_CDC_DATA) {
dev_dbg(&intf->dev, "slave class %u\n",
d->bInterfaceClass);
goto bad_desc;
}
break;
case USB_CDC_ETHERNET_TYPE:
if (info->ether) {
dev_dbg(&intf->dev, "extra CDC ether\n");
goto bad_desc;
}
info->ether = (void *) buf;
if (info->ether->bLength != sizeof *info->ether) {
dev_dbg(&intf->dev, "CDC ether len %u\n",
info->ether->bLength);
goto bad_desc;
}
dev->hard_mtu = le16_to_cpu(
info->ether->wMaxSegmentSize);
/* because of Zaurus, we may be ignoring the host
* side link address we were given.
*/
break;
}
next_desc:
len -= buf [0]; /* bLength */
buf += buf [0];
}
/* Microsoft ActiveSync based RNDIS devices lack the CDC descriptors,
* so we'll hard-wire the interfaces and not check for descriptors.
*/
if (is_activesync(&intf->cur_altsetting->desc) && !info->u) {
info->control = usb_ifnum_to_if(dev->udev, 0);
info->data = usb_ifnum_to_if(dev->udev, 1);
if (!info->control || !info->data) {
dev_dbg(&intf->dev,
"activesync: master #0/%p slave #1/%p\n",
info->control,
info->data);
goto bad_desc;
}
} else if (!info->header || !info->u || (!rndis && !info->ether)) {
dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n",
info->header ? "" : "header ",
info->u ? "" : "union ",
info->ether ? "" : "ether ");
goto bad_desc;
}
/* claim data interface and set it up ... with side effects.
* network traffic can't flow until an altsetting is enabled.
*/
status = usb_driver_claim_interface(driver, info->data, dev);
if (status < 0)
return status;
status = usbnet_get_endpoints(dev, info->data);
if (status < 0) {
/* ensure immediate exit from usbnet_disconnect */
usb_set_intfdata(info->data, NULL);
usb_driver_release_interface(driver, info->data);
return status;
}
/* status endpoint: optional for CDC Ethernet, not RNDIS (or ACM) */
dev->status = NULL;
if (info->control->cur_altsetting->desc.bNumEndpoints == 1) {
struct usb_endpoint_descriptor *desc;
dev->status = &info->control->cur_altsetting->endpoint [0];
desc = &dev->status->desc;
if (!usb_endpoint_is_int_in(desc)
|| (le16_to_cpu(desc->wMaxPacketSize)
< sizeof(struct usb_cdc_notification))
|| !desc->bInterval) {
dev_dbg(&intf->dev, "bad notification endpoint\n");
dev->status = NULL;
}
}
if (rndis && !dev->status) {
dev_dbg(&intf->dev, "missing RNDIS status endpoint\n");
usb_set_intfdata(info->data, NULL);
usb_driver_release_interface(driver, info->data);
return -ENODEV;
}
return 0;
bad_desc:
dev_info(&dev->udev->dev, "bad CDC descriptors\n");
return -ENODEV;
}
EXPORT_SYMBOL_GPL(usbnet_generic_cdc_bind);
void usbnet_cdc_unbind(struct usbnet *dev, struct usb_interface *intf)
{
struct cdc_state *info = (void *) &dev->data;
struct usb_driver *driver = driver_of(intf);
/* disconnect master --> disconnect slave */
if (intf == info->control && info->data) {
/* ensure immediate exit from usbnet_disconnect */
usb_set_intfdata(info->data, NULL);
usb_driver_release_interface(driver, info->data);
info->data = NULL;
}
/* and vice versa (just in case) */
else if (intf == info->data && info->control) {
/* ensure immediate exit from usbnet_disconnect */
usb_set_intfdata(info->control, NULL);
usb_driver_release_interface(driver, info->control);
info->control = NULL;
}
}
EXPORT_SYMBOL_GPL(usbnet_cdc_unbind);
/*-------------------------------------------------------------------------
*
* Communications Device Class, Ethernet Control model
*
* Takes two interfaces. The DATA interface is inactive till an altsetting
* is selected. Configuration data includes class descriptors. There's
* an optional status endpoint on the control interface.
*
* This should interop with whatever the 2.4 "CDCEther.c" driver
* (by Brad Hards) talked with, with more functionality.
*
*-------------------------------------------------------------------------*/
static void dumpspeed(struct usbnet *dev, __le32 *speeds)
{
if (netif_msg_timer(dev))
devinfo(dev, "link speeds: %u kbps up, %u kbps down",
__le32_to_cpu(speeds[0]) / 1000,
__le32_to_cpu(speeds[1]) / 1000);
}
static void cdc_status(struct usbnet *dev, struct urb *urb)
{
struct usb_cdc_notification *event;
if (urb->actual_length < sizeof *event)
return;
/* SPEED_CHANGE can get split into two 8-byte packets */
if (test_and_clear_bit(EVENT_STS_SPLIT, &dev->flags)) {
dumpspeed(dev, (__le32 *) urb->transfer_buffer);
return;
}
event = urb->transfer_buffer;
switch (event->bNotificationType) {
case USB_CDC_NOTIFY_NETWORK_CONNECTION:
if (netif_msg_timer(dev))
devdbg(dev, "CDC: carrier %s",
event->wValue ? "on" : "off");
if (event->wValue)
netif_carrier_on(dev->net);
else
netif_carrier_off(dev->net);
break;
case USB_CDC_NOTIFY_SPEED_CHANGE: /* tx/rx rates */
if (netif_msg_timer(dev))
devdbg(dev, "CDC: speed change (len %d)",
urb->actual_length);
if (urb->actual_length != (sizeof *event + 8))
set_bit(EVENT_STS_SPLIT, &dev->flags);
else
dumpspeed(dev, (__le32 *) &event[1]);
break;
/* USB_CDC_NOTIFY_RESPONSE_AVAILABLE can happen too (e.g. RNDIS),
* but there are no standard formats for the response data.
*/
default:
deverr(dev, "CDC: unexpected notification %02x!",
event->bNotificationType);
break;
}
}
static u8 nibble(unsigned char c)
{
if (likely(isdigit(c)))
return c - '0';
c = toupper(c);
if (likely(isxdigit(c)))
return 10 + c - 'A';
return 0;
}
static inline int
get_ethernet_addr(struct usbnet *dev, struct usb_cdc_ether_desc *e)
{
int tmp, i;
unsigned char buf [13];
tmp = usb_string(dev->udev, e->iMACAddress, buf, sizeof buf);
if (tmp != 12) {
dev_dbg(&dev->udev->dev,
"bad MAC string %d fetch, %d\n", e->iMACAddress, tmp);
if (tmp >= 0)
tmp = -EINVAL;
return tmp;
}
for (i = tmp = 0; i < 6; i++, tmp += 2)
dev->net->dev_addr [i] =
(nibble(buf [tmp]) << 4) + nibble(buf [tmp + 1]);
return 0;
}
static int cdc_bind(struct usbnet *dev, struct usb_interface *intf)
{
int status;
struct cdc_state *info = (void *) &dev->data;
status = usbnet_generic_cdc_bind(dev, intf);
if (status < 0)
return status;
status = get_ethernet_addr(dev, info->ether);
if (status < 0) {
usb_set_intfdata(info->data, NULL);
usb_driver_release_interface(driver_of(intf), info->data);
return status;
}
/* FIXME cdc-ether has some multicast code too, though it complains
* in routine cases. info->ether describes the multicast support.
* Implement that here, manipulating the cdc filter as needed.
*/
return 0;
}
static const struct driver_info cdc_info = {
.description = "CDC Ethernet Device",
.flags = FLAG_ETHER,
// .check_connect = cdc_check_connect,
.bind = cdc_bind,
.unbind = usbnet_cdc_unbind,
.status = cdc_status,
};
/*-------------------------------------------------------------------------*/
static const struct usb_device_id products [] = {
/*
* BLACKLIST !!
*
* First blacklist any products that are egregiously nonconformant
* with the CDC Ethernet specs. Minor braindamage we cope with; when
* they're not even trying, needing a separate driver is only the first
* of the differences to show up.
*/
#define ZAURUS_MASTER_INTERFACE \
.bInterfaceClass = USB_CLASS_COMM, \
.bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, \
.bInterfaceProtocol = USB_CDC_PROTO_NONE
/* SA-1100 based Sharp Zaurus ("collie"), or compatible;
* wire-incompatible with true CDC Ethernet implementations.
* (And, it seems, needlessly so...)
*/
{
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x8004,
ZAURUS_MASTER_INTERFACE,
.driver_info = 0,
},
/* PXA-25x based Sharp Zaurii. Note that it seems some of these
* (later models especially) may have shipped only with firmware
* advertising false "CDC MDLM" compatibility ... but we're not
* clear which models did that, so for now let's assume the worst.
*/
{
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x8005, /* A-300 */
ZAURUS_MASTER_INTERFACE,
.driver_info = 0,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x8006, /* B-500/SL-5600 */
ZAURUS_MASTER_INTERFACE,
.driver_info = 0,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x8007, /* C-700 */
ZAURUS_MASTER_INTERFACE,
.driver_info = 0,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x9031, /* C-750 C-760 */
ZAURUS_MASTER_INTERFACE,
.driver_info = 0,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x9032, /* SL-6000 */
ZAURUS_MASTER_INTERFACE,
.driver_info = 0,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
/* reported with some C860 units */
.idProduct = 0x9050, /* C-860 */
ZAURUS_MASTER_INTERFACE,
.driver_info = 0,
},
/* Olympus has some models with a Zaurus-compatible option.
* R-1000 uses a FreeScale i.MXL cpu (ARMv4T)
*/
{
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x07B4,
.idProduct = 0x0F02, /* R-1000 */
ZAURUS_MASTER_INTERFACE,
.driver_info = 0,
},
/*
* WHITELIST!!!
*
* CDC Ether uses two interfaces, not necessarily consecutive.
* We match the main interface, ignoring the optional device
* class so we could handle devices that aren't exclusively
* CDC ether.
*
* NOTE: this match must come AFTER entries blacklisting devices
* because of bugs/quirks in a given product (like Zaurus, above).
*/
{
USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET,
USB_CDC_PROTO_NONE),
.driver_info = (unsigned long) &cdc_info,
},
{ }, // END
};
MODULE_DEVICE_TABLE(usb, products);
static struct usb_driver cdc_driver = {
.name = "cdc_ether",
.id_table = products,
.probe = usbnet_probe,
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
};
static int __init cdc_init(void)
{
BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data)
< sizeof(struct cdc_state)));
return usb_register(&cdc_driver);
}
module_init(cdc_init);
static void __exit cdc_exit(void)
{
usb_deregister(&cdc_driver);
}
module_exit(cdc_exit);
MODULE_AUTHOR("David Brownell");
MODULE_DESCRIPTION("USB CDC Ethernet devices");
MODULE_LICENSE("GPL");

344
drivers/net/usb/cdc_subset.c 一般檔案
查看文件

@@ -0,0 +1,344 @@
/*
* Simple "CDC Subset" USB Networking Links
* Copyright (C) 2000-2005 by David Brownell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/workqueue.h>
#include <linux/mii.h>
#include <linux/usb.h>
#include "usbnet.h"
/*
* This supports simple USB network links that don't require any special
* framing or hardware control operations. The protocol used here is a
* strict subset of CDC Ethernet, with three basic differences reflecting
* the goal that almost any hardware should run it:
*
* - Minimal runtime control: one interface, no altsettings, and
* no vendor or class specific control requests. If a device is
* configured, it is allowed to exchange packets with the host.
* Fancier models would mean not working on some hardware.
*
* - Minimal manufacturing control: no IEEE "Organizationally
* Unique ID" required, or an EEPROMs to store one. Each host uses
* one random "locally assigned" Ethernet address instead, which can
* of course be overridden using standard tools like "ifconfig".
* (With 2^46 such addresses, same-net collisions are quite rare.)
*
* - There is no additional framing data for USB. Packets are written
* exactly as in CDC Ethernet, starting with an Ethernet header and
* terminated by a short packet. However, the host will never send a
* zero length packet; some systems can't handle those robustly.
*
* Anything that can transmit and receive USB bulk packets can implement
* this protocol. That includes both smart peripherals and quite a lot
* of "host-to-host" USB cables (which embed two devices back-to-back).
*
* Note that although Linux may use many of those host-to-host links
* with this "cdc_subset" framing, that doesn't mean there may not be a
* better approach. Handling the "other end unplugs/replugs" scenario
* well tends to require chip-specific vendor requests. Also, Windows
* peers at the other end of host-to-host cables may expect their own
* framing to be used rather than this "cdc_subset" model.
*/
#if defined(CONFIG_USB_EPSON2888) || defined(CONFIG_USB_ARMLINUX)
/* PDA style devices are always connected if present */
static int always_connected (struct usbnet *dev)
{
return 0;
}
#endif
#ifdef CONFIG_USB_ALI_M5632
#define HAVE_HARDWARE
/*-------------------------------------------------------------------------
*
* ALi M5632 driver ... does high speed
*
* NOTE that the MS-Windows drivers for this chip use some funky and
* (naturally) undocumented 7-byte prefix to each packet, so this is a
* case where we don't currently interoperate. Also, once you unplug
* one end of the cable, you need to replug the other end too ... since
* chip docs are unavailable, there's no way to reset the relevant state
* short of a power cycle.
*
*-------------------------------------------------------------------------*/
static const struct driver_info ali_m5632_info = {
.description = "ALi M5632",
};
#endif
#ifdef CONFIG_USB_AN2720
#define HAVE_HARDWARE
/*-------------------------------------------------------------------------
*
* AnchorChips 2720 driver ... http://www.cypress.com
*
* This doesn't seem to have a way to detect whether the peer is
* connected, or need any reset handshaking. It's got pretty big
* internal buffers (handles most of a frame's worth of data).
* Chip data sheets don't describe any vendor control messages.
*
*-------------------------------------------------------------------------*/
static const struct driver_info an2720_info = {
.description = "AnchorChips/Cypress 2720",
// no reset available!
// no check_connect available!
.in = 2, .out = 2, // direction distinguishes these
};
#endif /* CONFIG_USB_AN2720 */
#ifdef CONFIG_USB_BELKIN
#define HAVE_HARDWARE
/*-------------------------------------------------------------------------
*
* Belkin F5U104 ... two NetChip 2280 devices + Atmel AVR microcontroller
*
* ... also two eTEK designs, including one sold as "Advance USBNET"
*
*-------------------------------------------------------------------------*/
static const struct driver_info belkin_info = {
.description = "Belkin, eTEK, or compatible",
};
#endif /* CONFIG_USB_BELKIN */
#ifdef CONFIG_USB_EPSON2888
#define HAVE_HARDWARE
/*-------------------------------------------------------------------------
*
* EPSON USB clients
*
* This is the same idea as Linux PDAs (below) except the firmware in the
* device might not be Tux-powered. Epson provides reference firmware that
* implements this interface. Product developers can reuse or modify that
* code, such as by using their own product and vendor codes.
*
* Support was from Juro Bystricky <bystricky.juro@erd.epson.com>
*
*-------------------------------------------------------------------------*/
static const struct driver_info epson2888_info = {
.description = "Epson USB Device",
.check_connect = always_connected,
.in = 4, .out = 3,
};
#endif /* CONFIG_USB_EPSON2888 */
/*-------------------------------------------------------------------------
*
* info from Jonathan McDowell <noodles@earth.li>
*
*-------------------------------------------------------------------------*/
#ifdef CONFIG_USB_KC2190
#define HAVE_HARDWARE
static const struct driver_info kc2190_info = {
.description = "KC Technology KC-190",
};
#endif /* CONFIG_USB_KC2190 */
#ifdef CONFIG_USB_ARMLINUX
#define HAVE_HARDWARE
/*-------------------------------------------------------------------------
*
* Intel's SA-1100 chip integrates basic USB support, and is used
* in PDAs like some iPaqs, the Yopy, some Zaurus models, and more.
* When they run Linux, arch/arm/mach-sa1100/usb-eth.c may be used to
* network using minimal USB framing data.
*
* This describes the driver currently in standard ARM Linux kernels.
* The Zaurus uses a different driver (see later).
*
* PXA25x and PXA210 use XScale cores (ARM v5TE) with better USB support
* and different USB endpoint numbering than the SA1100 devices. The
* mach-pxa/usb-eth.c driver re-uses the device ids from mach-sa1100
* so we rely on the endpoint descriptors.
*
*-------------------------------------------------------------------------*/
static const struct driver_info linuxdev_info = {
.description = "Linux Device",
.check_connect = always_connected,
};
static const struct driver_info yopy_info = {
.description = "Yopy",
.check_connect = always_connected,
};
static const struct driver_info blob_info = {
.description = "Boot Loader OBject",
.check_connect = always_connected,
};
#endif /* CONFIG_USB_ARMLINUX */
/*-------------------------------------------------------------------------*/
#ifndef HAVE_HARDWARE
#error You need to configure some hardware for this driver
#endif
/*
* chip vendor names won't normally be on the cables, and
* may not be on the device.
*/
static const struct usb_device_id products [] = {
#ifdef CONFIG_USB_ALI_M5632
{
USB_DEVICE (0x0402, 0x5632), // ALi defaults
.driver_info = (unsigned long) &ali_m5632_info,
},
{
USB_DEVICE (0x182d,0x207c), // SiteCom CN-124
.driver_info = (unsigned long) &ali_m5632_info,
},
#endif
#ifdef CONFIG_USB_AN2720
{
USB_DEVICE (0x0547, 0x2720), // AnchorChips defaults
.driver_info = (unsigned long) &an2720_info,
}, {
USB_DEVICE (0x0547, 0x2727), // Xircom PGUNET
.driver_info = (unsigned long) &an2720_info,
},
#endif
#ifdef CONFIG_USB_BELKIN
{
USB_DEVICE (0x050d, 0x0004), // Belkin
.driver_info = (unsigned long) &belkin_info,
}, {
USB_DEVICE (0x056c, 0x8100), // eTEK
.driver_info = (unsigned long) &belkin_info,
}, {
USB_DEVICE (0x0525, 0x9901), // Advance USBNET (eTEK)
.driver_info = (unsigned long) &belkin_info,
},
#endif
#ifdef CONFIG_USB_EPSON2888
{
USB_DEVICE (0x0525, 0x2888), // EPSON USB client
.driver_info = (unsigned long) &epson2888_info,
},
#endif
#ifdef CONFIG_USB_KC2190
{
USB_DEVICE (0x050f, 0x0190), // KC-190
.driver_info = (unsigned long) &kc2190_info,
},
#endif
#ifdef CONFIG_USB_ARMLINUX
/*
* SA-1100 using standard ARM Linux kernels, or compatible.
* Often used when talking to Linux PDAs (iPaq, Yopy, etc).
* The sa-1100 "usb-eth" driver handles the basic framing.
*
* PXA25x or PXA210 ... these use a "usb-eth" driver much like
* the sa1100 one, but hardware uses different endpoint numbers.
*
* Or the Linux "Ethernet" gadget on hardware that can't talk
* CDC Ethernet (e.g., no altsettings), in either of two modes:
* - acting just like the old "usb-eth" firmware, though
* the implementation is different
* - supporting RNDIS as the first/default configuration for
* MS-Windows interop; Linux needs to use the other config
*/
{
// 1183 = 0x049F, both used as hex values?
// Compaq "Itsy" vendor/product id
USB_DEVICE (0x049F, 0x505A), // usb-eth, or compatible
.driver_info = (unsigned long) &linuxdev_info,
}, {
USB_DEVICE (0x0E7E, 0x1001), // G.Mate "Yopy"
.driver_info = (unsigned long) &yopy_info,
}, {
USB_DEVICE (0x8086, 0x07d3), // "blob" bootloader
.driver_info = (unsigned long) &blob_info,
}, {
// Linux Ethernet/RNDIS gadget on pxa210/25x/26x, second config
// e.g. Gumstix, current OpenZaurus, ...
USB_DEVICE_VER (0x0525, 0xa4a2, 0x0203, 0x0203),
.driver_info = (unsigned long) &linuxdev_info,
},
#endif
{ }, // END
};
MODULE_DEVICE_TABLE(usb, products);
/*-------------------------------------------------------------------------*/
static struct usb_driver cdc_subset_driver = {
.name = "cdc_subset",
.probe = usbnet_probe,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.disconnect = usbnet_disconnect,
.id_table = products,
};
static int __init cdc_subset_init(void)
{
return usb_register(&cdc_subset_driver);
}
module_init(cdc_subset_init);
static void __exit cdc_subset_exit(void)
{
usb_deregister(&cdc_subset_driver);
}
module_exit(cdc_subset_exit);
MODULE_AUTHOR("David Brownell");
MODULE_DESCRIPTION("Simple 'CDC Subset' USB networking links");
MODULE_LICENSE("GPL");

619
drivers/net/usb/dm9601.c 一般檔案
查看文件

@@ -0,0 +1,619 @@
/*
* Davicom DM9601 USB 1.1 10/100Mbps ethernet devices
*
* Peter Korsgaard <jacmet@sunsite.dk>
*
* 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 <linux/module.h>
#include <linux/sched.h>
#include <linux/stddef.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/usb.h>
#include <linux/crc32.h>
#include "usbnet.h"
/* datasheet:
http://www.davicom.com.tw/big5/download/Data%20Sheet/DM9601-DS-P01-930914.pdf
*/
/* control requests */
#define DM_READ_REGS 0x00
#define DM_WRITE_REGS 0x01
#define DM_READ_MEMS 0x02
#define DM_WRITE_REG 0x03
#define DM_WRITE_MEMS 0x05
#define DM_WRITE_MEM 0x07
/* registers */
#define DM_NET_CTRL 0x00
#define DM_RX_CTRL 0x05
#define DM_SHARED_CTRL 0x0b
#define DM_SHARED_ADDR 0x0c
#define DM_SHARED_DATA 0x0d /* low + high */
#define DM_PHY_ADDR 0x10 /* 6 bytes */
#define DM_MCAST_ADDR 0x16 /* 8 bytes */
#define DM_GPR_CTRL 0x1e
#define DM_GPR_DATA 0x1f
#define DM_MAX_MCAST 64
#define DM_MCAST_SIZE 8
#define DM_EEPROM_LEN 256
#define DM_TX_OVERHEAD 2 /* 2 byte header */
#define DM_RX_OVERHEAD 7 /* 3 byte header + 4 byte crc tail */
#define DM_TIMEOUT 1000
static int dm_read(struct usbnet *dev, u8 reg, u16 length, void *data)
{
devdbg(dev, "dm_read() reg=0x%02x length=%d", reg, length);
return usb_control_msg(dev->udev,
usb_rcvctrlpipe(dev->udev, 0),
DM_READ_REGS,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, reg, data, length, USB_CTRL_SET_TIMEOUT);
}
static int dm_read_reg(struct usbnet *dev, u8 reg, u8 *value)
{
return dm_read(dev, reg, 1, value);
}
static int dm_write(struct usbnet *dev, u8 reg, u16 length, void *data)
{
devdbg(dev, "dm_write() reg=0x%02x, length=%d", reg, length);
return usb_control_msg(dev->udev,
usb_sndctrlpipe(dev->udev, 0),
DM_WRITE_REGS,
USB_DIR_OUT | USB_TYPE_VENDOR |USB_RECIP_DEVICE,
0, reg, data, length, USB_CTRL_SET_TIMEOUT);
}
static int dm_write_reg(struct usbnet *dev, u8 reg, u8 value)
{
devdbg(dev, "dm_write_reg() reg=0x%02x, value=0x%02x", reg, value);
return usb_control_msg(dev->udev,
usb_sndctrlpipe(dev->udev, 0),
DM_WRITE_REG,
USB_DIR_OUT | USB_TYPE_VENDOR |USB_RECIP_DEVICE,
value, reg, NULL, 0, USB_CTRL_SET_TIMEOUT);
}
static void dm_write_async_callback(struct urb *urb)
{
struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;
if (urb->status < 0)
printk(KERN_DEBUG "dm_write_async_callback() failed with %d",
urb->status);
kfree(req);
usb_free_urb(urb);
}
static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
{
struct usb_ctrlrequest *req;
struct urb *urb;
int status;
devdbg(dev, "dm_write_async() reg=0x%02x length=%d", reg, length);
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
deverr(dev, "Error allocating URB in dm_write_async!");
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->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
req->bRequest = DM_WRITE_REGS;
req->wValue = 0;
req->wIndex = cpu_to_le16(reg);
req->wLength = cpu_to_le16(length);
usb_fill_control_urb(urb, dev->udev,
usb_sndctrlpipe(dev->udev, 0),
(void *)req, data, length,
dm_write_async_callback, req);
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status < 0) {
deverr(dev, "Error submitting the control message: status=%d",
status);
kfree(req);
usb_free_urb(urb);
}
}
static void dm_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
{
struct usb_ctrlrequest *req;
struct urb *urb;
int status;
devdbg(dev, "dm_write_reg_async() reg=0x%02x value=0x%02x",
reg, value);
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
deverr(dev, "Error allocating URB in dm_write_async!");
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->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
req->bRequest = DM_WRITE_REG;
req->wValue = cpu_to_le16(value);
req->wIndex = cpu_to_le16(reg);
req->wLength = 0;
usb_fill_control_urb(urb, dev->udev,
usb_sndctrlpipe(dev->udev, 0),
(void *)req, NULL, 0, dm_write_async_callback, req);
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status < 0) {
deverr(dev, "Error submitting the control message: status=%d",
status);
kfree(req);
usb_free_urb(urb);
}
}
static int dm_read_shared_word(struct usbnet *dev, int phy, u8 reg, u16 *value)
{
int ret, i;
mutex_lock(&dev->phy_mutex);
dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg);
dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0xc : 0x4);
for (i = 0; i < DM_TIMEOUT; i++) {
u8 tmp;
udelay(1);
ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp);
if (ret < 0)
goto out;
/* ready */
if ((tmp & 1) == 0)
break;
}
if (i == DM_TIMEOUT) {
deverr(dev, "%s read timed out!", phy ? "phy" : "eeprom");
ret = -EIO;
goto out;
}
dm_write_reg(dev, DM_SHARED_CTRL, 0x0);
ret = dm_read(dev, DM_SHARED_DATA, 2, value);
devdbg(dev, "read shared %d 0x%02x returned 0x%04x, %d",
phy, reg, *value, ret);
out:
mutex_unlock(&dev->phy_mutex);
return ret;
}
static int dm_write_shared_word(struct usbnet *dev, int phy, u8 reg, u16 value)
{
int ret, i;
mutex_lock(&dev->phy_mutex);
ret = dm_write(dev, DM_SHARED_DATA, 2, &value);
if (ret < 0)
goto out;
dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg);
dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0x1c : 0x14);
for (i = 0; i < DM_TIMEOUT; i++) {
u8 tmp;
udelay(1);
ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp);
if (ret < 0)
goto out;
/* ready */
if ((tmp & 1) == 0)
break;
}
if (i == DM_TIMEOUT) {
deverr(dev, "%s write timed out!", phy ? "phy" : "eeprom");
ret = -EIO;
goto out;
}
dm_write_reg(dev, DM_SHARED_CTRL, 0x0);
out:
mutex_unlock(&dev->phy_mutex);
return ret;
}
static int dm_read_eeprom_word(struct usbnet *dev, u8 offset, void *value)
{
return dm_read_shared_word(dev, 0, offset, value);
}
static int dm9601_get_eeprom_len(struct net_device *dev)
{
return DM_EEPROM_LEN;
}
static int dm9601_get_eeprom(struct net_device *net,
struct ethtool_eeprom *eeprom, u8 * data)
{
struct usbnet *dev = netdev_priv(net);
u16 *ebuf = (u16 *) data;
int i;
/* access is 16bit */
if ((eeprom->offset % 2) || (eeprom->len % 2))
return -EINVAL;
for (i = 0; i < eeprom->len / 2; i++) {
if (dm_read_eeprom_word(dev, eeprom->offset / 2 + i,
&ebuf[i]) < 0)
return -EINVAL;
}
return 0;
}
static int dm9601_mdio_read(struct net_device *netdev, int phy_id, int loc)
{
struct usbnet *dev = netdev_priv(netdev);
u16 res;
if (phy_id) {
devdbg(dev, "Only internal phy supported");
return 0;
}
dm_read_shared_word(dev, 1, loc, &res);
devdbg(dev,
"dm9601_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x",
phy_id, loc, le16_to_cpu(res));
return le16_to_cpu(res);
}
static void dm9601_mdio_write(struct net_device *netdev, int phy_id, int loc,
int val)
{
struct usbnet *dev = netdev_priv(netdev);
u16 res = cpu_to_le16(val);
if (phy_id) {
devdbg(dev, "Only internal phy supported");
return;
}
devdbg(dev,"dm9601_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x",
phy_id, loc, val);
dm_write_shared_word(dev, 1, loc, res);
}
static void dm9601_get_drvinfo(struct net_device *net,
struct ethtool_drvinfo *info)
{
/* Inherit standard device info */
usbnet_get_drvinfo(net, info);
info->eedump_len = DM_EEPROM_LEN;
}
static u32 dm9601_get_link(struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
return mii_link_ok(&dev->mii);
}
static int dm9601_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
{
struct usbnet *dev = netdev_priv(net);
return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
}
static struct ethtool_ops dm9601_ethtool_ops = {
.get_drvinfo = dm9601_get_drvinfo,
.get_link = dm9601_get_link,
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
.get_eeprom_len = dm9601_get_eeprom_len,
.get_eeprom = dm9601_get_eeprom,
.get_settings = usbnet_get_settings,
.set_settings = usbnet_set_settings,
.nway_reset = usbnet_nway_reset,
};
static void dm9601_set_multicast(struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
/* We use the 20 byte dev->data for our 8 byte filter buffer
* to avoid allocating memory that is tricky to free later */
u8 *hashes = (u8 *) & dev->data;
u8 rx_ctl = 0x01;
memset(hashes, 0x00, DM_MCAST_SIZE);
hashes[DM_MCAST_SIZE - 1] |= 0x80; /* broadcast address */
if (net->flags & IFF_PROMISC) {
rx_ctl |= 0x02;
} else if (net->flags & IFF_ALLMULTI || net->mc_count > DM_MAX_MCAST) {
rx_ctl |= 0x04;
} else if (net->mc_count) {
struct dev_mc_list *mc_list = net->mc_list;
int i;
for (i = 0; i < net->mc_count; i++) {
u32 crc = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26;
hashes[crc >> 3] |= 1 << (crc & 0x7);
}
}
dm_write_async(dev, DM_MCAST_ADDR, DM_MCAST_SIZE, hashes);
dm_write_reg_async(dev, DM_RX_CTRL, rx_ctl);
}
static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf)
{
int ret;
ret = usbnet_get_endpoints(dev, intf);
if (ret)
goto out;
dev->net->do_ioctl = dm9601_ioctl;
dev->net->set_multicast_list = dm9601_set_multicast;
dev->net->ethtool_ops = &dm9601_ethtool_ops;
dev->net->hard_header_len += DM_TX_OVERHEAD;
dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
dev->rx_urb_size = dev->net->mtu + DM_RX_OVERHEAD;
dev->mii.dev = dev->net;
dev->mii.mdio_read = dm9601_mdio_read;
dev->mii.mdio_write = dm9601_mdio_write;
dev->mii.phy_id_mask = 0x1f;
dev->mii.reg_num_mask = 0x1f;
/* reset */
ret = dm_write_reg(dev, DM_NET_CTRL, 1);
udelay(20);
/* read MAC */
ret = dm_read(dev, DM_PHY_ADDR, ETH_ALEN, dev->net->dev_addr);
if (ret < 0) {
printk(KERN_ERR "Error reading MAC address\n");
ret = -ENODEV;
goto out;
}
/* power up phy */
dm_write_reg(dev, DM_GPR_CTRL, 1);
dm_write_reg(dev, DM_GPR_DATA, 0);
/* receive broadcast packets */
dm9601_set_multicast(dev->net);
dm9601_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
dm9601_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
mii_nway_restart(&dev->mii);
out:
return ret;
}
static int dm9601_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->len < DM_RX_OVERHEAD)) {
dev_err(&dev->udev->dev, "unexpected tiny rx frame\n");
return 0;
}
status = skb->data[0];
len = (skb->data[1] | (skb->data[2] << 8)) - 4;
if (unlikely(status & 0xbf)) {
if (status & 0x01) dev->stats.rx_fifo_errors++;
if (status & 0x02) dev->stats.rx_crc_errors++;
if (status & 0x04) dev->stats.rx_frame_errors++;
if (status & 0x20) dev->stats.rx_missed_errors++;
if (status & 0x90) dev->stats.rx_length_errors++;
return 0;
}
skb_pull(skb, 3);
skb_trim(skb, len);
return 1;
}
static struct sk_buff *dm9601_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
*/
if (skb_headroom(skb) < DM_TX_OVERHEAD) {
struct sk_buff *skb2;
skb2 = skb_copy_expand(skb, DM_TX_OVERHEAD, 0, flags);
dev_kfree_skb_any(skb);
skb = skb2;
if (!skb)
return NULL;
}
__skb_push(skb, DM_TX_OVERHEAD);
len = skb->len;
/* usbnet adds padding if length is a multiple of packet size
if so, adjust length value in header */
if ((len % dev->maxpacket) == 0)
len++;
skb->data[0] = len;
skb->data[1] = len >> 8;
return skb;
}
static void dm9601_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->actual_length < 8)
return;
buf = urb->transfer_buffer;
link = !!(buf[0] & 0x40);
if (netif_carrier_ok(dev->net) != link) {
if (link) {
netif_carrier_on(dev->net);
usbnet_defer_kevent (dev, EVENT_LINK_RESET);
}
else
netif_carrier_off(dev->net);
devdbg(dev, "Link Status is: %d", link);
}
}
static int dm9601_link_reset(struct usbnet *dev)
{
struct ethtool_cmd ecmd;
mii_check_media(&dev->mii, 1, 1);
mii_ethtool_gset(&dev->mii, &ecmd);
devdbg(dev, "link_reset() speed: %d duplex: %d",
ecmd.speed, ecmd.duplex);
return 0;
}
static const struct driver_info dm9601_info = {
.description = "Davicom DM9601 USB Ethernet",
.flags = FLAG_ETHER,
.bind = dm9601_bind,
.rx_fixup = dm9601_rx_fixup,
.tx_fixup = dm9601_tx_fixup,
.status = dm9601_status,
.link_reset = dm9601_link_reset,
.reset = dm9601_link_reset,
};
static const struct usb_device_id products[] = {
{
USB_DEVICE(0x07aa, 0x9601), /* Corega FEther USB-TXC */
.driver_info = (unsigned long)&dm9601_info,
},
{
USB_DEVICE(0x0a46, 0x9601), /* Davicom USB-100 */
.driver_info = (unsigned long)&dm9601_info,
},
{
USB_DEVICE(0x0a46, 0x6688), /* ZT6688 USB NIC */
.driver_info = (unsigned long)&dm9601_info,
},
{
USB_DEVICE(0x0a46, 0x0268), /* ShanTou ST268 USB NIC */
.driver_info = (unsigned long)&dm9601_info,
},
{}, // END
};
MODULE_DEVICE_TABLE(usb, products);
static struct usb_driver dm9601_driver = {
.name = "dm9601",
.id_table = products,
.probe = usbnet_probe,
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
};
static int __init dm9601_init(void)
{
return usb_register(&dm9601_driver);
}
static void __exit dm9601_exit(void)
{
usb_deregister(&dm9601_driver);
}
module_init(dm9601_init);
module_exit(dm9601_exit);
MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
MODULE_DESCRIPTION("Davicom DM9601 USB 1.1 ethernet devices");
MODULE_LICENSE("GPL");

245
drivers/net/usb/gl620a.c 一般檔案
查看文件

@@ -0,0 +1,245 @@
/*
* GeneSys GL620USB-A based links
* Copyright (C) 2001 by Jiun-Jie Huang <huangjj@genesyslogic.com.tw>
* Copyright (C) 2001 by Stanislav Brabec <utx@penguin.cz>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// #define DEBUG // error path messages, extra info
// #define VERBOSE // more; success messages
#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/workqueue.h>
#include <linux/mii.h>
#include <linux/usb.h>
#include "usbnet.h"
/*
* GeneSys GL620USB-A (www.genesyslogic.com.tw)
*
* ... should partially interop with the Win32 driver for this hardware.
* The GeneSys docs imply there's some NDIS issue motivating this framing.
*
* Some info from GeneSys:
* - GL620USB-A is full duplex; GL620USB is only half duplex for bulk.
* (Some cables, like the BAFO-100c, use the half duplex version.)
* - For the full duplex model, the low bit of the version code says
* which side is which ("left/right").
* - For the half duplex type, a control/interrupt handshake settles
* the transfer direction. (That's disabled here, partially coded.)
* A control URB would block until other side writes an interrupt.
*
* Original code from Jiun-Jie Huang <huangjj@genesyslogic.com.tw>
* and merged into "usbnet" by Stanislav Brabec <utx@penguin.cz>.
*/
// control msg write command
#define GENELINK_CONNECT_WRITE 0xF0
// interrupt pipe index
#define GENELINK_INTERRUPT_PIPE 0x03
// interrupt read buffer size
#define INTERRUPT_BUFSIZE 0x08
// interrupt pipe interval value
#define GENELINK_INTERRUPT_INTERVAL 0x10
// max transmit packet number per transmit
#define GL_MAX_TRANSMIT_PACKETS 32
// max packet length
#define GL_MAX_PACKET_LEN 1514
// max receive buffer size
#define GL_RCV_BUF_SIZE \
(((GL_MAX_PACKET_LEN + 4) * GL_MAX_TRANSMIT_PACKETS) + 4)
struct gl_packet {
__le32 packet_length;
char packet_data [1];
};
struct gl_header {
__le32 packet_count;
struct gl_packet packets;
};
static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
struct gl_header *header;
struct gl_packet *packet;
struct sk_buff *gl_skb;
u32 size;
u32 count;
header = (struct gl_header *) skb->data;
// get the packet count of the received skb
count = le32_to_cpu(header->packet_count);
if (count > GL_MAX_TRANSMIT_PACKETS) {
dbg("genelink: invalid received packet count %u", count);
return 0;
}
// set the current packet pointer to the first packet
packet = &header->packets;
// decrement the length for the packet count size 4 bytes
skb_pull(skb, 4);
while (count > 1) {
// get the packet length
size = le32_to_cpu(packet->packet_length);
// this may be a broken packet
if (size > GL_MAX_PACKET_LEN) {
dbg("genelink: invalid rx length %d", size);
return 0;
}
// allocate the skb for the individual packet
gl_skb = alloc_skb(size, GFP_ATOMIC);
if (gl_skb) {
// copy the packet data to the new skb
memcpy(skb_put(gl_skb, size),
packet->packet_data, size);
usbnet_skb_return(dev, gl_skb);
}
// advance to the next packet
packet = (struct gl_packet *)&packet->packet_data[size];
count--;
// shift the data pointer to the next gl_packet
skb_pull(skb, size + 4);
}
// skip the packet length field 4 bytes
skb_pull(skb, 4);
if (skb->len > GL_MAX_PACKET_LEN) {
dbg("genelink: invalid rx length %d", skb->len);
return 0;
}
return 1;
}
static struct sk_buff *
genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
{
int padlen;
int length = skb->len;
int headroom = skb_headroom(skb);
int tailroom = skb_tailroom(skb);
__le32 *packet_count;
__le32 *packet_len;
// FIXME: magic numbers, bleech
padlen = ((skb->len + (4 + 4*1)) % 64) ? 0 : 1;
if ((!skb_cloned(skb))
&& ((headroom + tailroom) >= (padlen + (4 + 4*1)))) {
if ((headroom < (4 + 4*1)) || (tailroom < padlen)) {
skb->data = memmove(skb->head + (4 + 4*1),
skb->data, skb->len);
skb_set_tail_pointer(skb, skb->len);
}
} else {
struct sk_buff *skb2;
skb2 = skb_copy_expand(skb, (4 + 4*1) , padlen, flags);
dev_kfree_skb_any(skb);
skb = skb2;
if (!skb)
return NULL;
}
// attach the packet count to the header
packet_count = (__le32 *) skb_push(skb, (4 + 4*1));
packet_len = packet_count + 1;
*packet_count = cpu_to_le32(1);
*packet_len = cpu_to_le32(length);
// add padding byte
if ((skb->len % dev->maxpacket) == 0)
skb_put(skb, 1);
return skb;
}
static int genelink_bind(struct usbnet *dev, struct usb_interface *intf)
{
dev->hard_mtu = GL_RCV_BUF_SIZE;
dev->net->hard_header_len += 4;
dev->in = usb_rcvbulkpipe(dev->udev, dev->driver_info->in);
dev->out = usb_sndbulkpipe(dev->udev, dev->driver_info->out);
return 0;
}
static const struct driver_info genelink_info = {
.description = "Genesys GeneLink",
.flags = FLAG_FRAMING_GL | FLAG_NO_SETINT,
.bind = genelink_bind,
.rx_fixup = genelink_rx_fixup,
.tx_fixup = genelink_tx_fixup,
.in = 1, .out = 2,
#ifdef GENELINK_ACK
.check_connect =genelink_check_connect,
#endif
};
static const struct usb_device_id products [] = {
{
USB_DEVICE(0x05e3, 0x0502), // GL620USB-A
.driver_info = (unsigned long) &genelink_info,
},
/* NOT: USB_DEVICE(0x05e3, 0x0501), // GL620USB
* that's half duplex, not currently supported
*/
{ }, // END
};
MODULE_DEVICE_TABLE(usb, products);
static struct usb_driver gl620a_driver = {
.name = "gl620a",
.id_table = products,
.probe = usbnet_probe,
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
};
static int __init usbnet_init(void)
{
return usb_register(&gl620a_driver);
}
module_init(usbnet_init);
static void __exit usbnet_exit(void)
{
usb_deregister(&gl620a_driver);
}
module_exit(usbnet_exit);
MODULE_AUTHOR("Jiun-Jie Huang");
MODULE_DESCRIPTION("GL620-USB-A Host-to-Host Link cables");
MODULE_LICENSE("GPL");

1337
drivers/net/usb/kaweth.c 一般檔案

檔案差異因為檔案過大而無法顯示 載入差異

557
drivers/net/usb/kawethfw.h 一般檔案
查看文件

@@ -0,0 +1,557 @@
/******************************************/
/* NOTE: B6/C3 is data header signature */
/* 0xAA/0xBB is data length = total */
/* bytes - 7, 0xCC is type, 0xDD is */
/* interrupt to use. */
/******************************************/
/****************************************************************
* kaweth_trigger_code
****************************************************************/
static __u8 kaweth_trigger_code[] =
{
0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD,
0xc8, 0x07, 0xa0, 0x00, 0xf0, 0x07, 0x5e, 0x00,
0x06, 0x00, 0xf0, 0x07, 0x0a, 0x00, 0x08, 0x00,
0xf0, 0x09, 0x00, 0x00, 0x02, 0x00, 0xe7, 0x07,
0x36, 0x00, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00,
0x04, 0x00, 0xe7, 0x07, 0x50, 0xc3, 0x10, 0xc0,
0xf0, 0x09, 0x0e, 0xc0, 0x00, 0x00, 0xe7, 0x87,
0x01, 0x00, 0x0e, 0xc0, 0x97, 0xcf, 0xd7, 0x09,
0x00, 0xc0, 0x17, 0x02, 0xc8, 0x07, 0xa0, 0x00,
0xe7, 0x17, 0x50, 0xc3, 0x10, 0xc0, 0x30, 0xd8,
0x04, 0x00, 0x30, 0x5c, 0x08, 0x00, 0x04, 0x00,
0xb0, 0xc0, 0x06, 0x00, 0xc8, 0x05, 0xe7, 0x05,
0x00, 0xc0, 0xc0, 0xdf, 0x97, 0xcf, 0x49, 0xaf,
0xc0, 0x07, 0x00, 0x00, 0x60, 0xaf, 0x4a, 0xaf,
0x00, 0x0c, 0x0c, 0x00, 0x40, 0xd2, 0x00, 0x1c,
0x0c, 0x00, 0x40, 0xd2, 0x30, 0x00, 0x08, 0x00,
0xf0, 0x07, 0x00, 0x00, 0x04, 0x00, 0xf0, 0x07,
0x86, 0x00, 0x06, 0x00, 0x67, 0xcf, 0x27, 0x0c,
0x02, 0x00, 0x00, 0x00, 0x27, 0x0c, 0x00, 0x00,
0x0e, 0xc0, 0x49, 0xaf, 0x64, 0xaf, 0xc0, 0x07,
0x00, 0x00, 0x4b, 0xaf, 0x4a, 0xaf, 0x5a, 0xcf,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x94, 0x00, 0x05, 0x00,
0x00, 0x00
};
/****************************************************************
* kaweth_trigger_code_fix
****************************************************************/
static __u8 kaweth_trigger_code_fix[] =
{
0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD,
0x02, 0x00, 0x06, 0x00, 0x18, 0x00, 0x3e, 0x00,
0x80, 0x00, 0x98, 0x00, 0xaa, 0x00,
0x00, 0x00
};
/****************************************************************
* kaweth_new_code
****************************************************************/
static __u8 kaweth_new_code[] =
{
0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD,
0x9f, 0xcf, 0xde, 0x06, 0xe7, 0x57, 0x00, 0x00,
0xc4, 0x06, 0x97, 0xc1, 0xe7, 0x67, 0xff, 0x1f,
0x28, 0xc0, 0xe7, 0x87, 0x00, 0x04, 0x24, 0xc0,
0xe7, 0x67, 0xff, 0xf9, 0x22, 0xc0, 0x97, 0xcf,
0xd7, 0x09, 0x00, 0xc0, 0xe7, 0x09, 0xa2, 0xc0,
0xbe, 0x06, 0x9f, 0xaf, 0x36, 0x00, 0xe7, 0x05,
0x00, 0xc0, 0xa7, 0xcf, 0xbc, 0x06, 0x97, 0xcf,
0xe7, 0x57, 0x00, 0x00, 0xb8, 0x06, 0xa7, 0xa1,
0xb8, 0x06, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00,
0x14, 0x08, 0x0a, 0xc0, 0xe7, 0x57, 0x00, 0x00,
0xa4, 0xc0, 0xa7, 0xc0, 0x7a, 0x06, 0x9f, 0xaf,
0x92, 0x07, 0xe7, 0x07, 0x00, 0x00, 0x14, 0x08,
0xe7, 0x57, 0xff, 0xff, 0xba, 0x06, 0x9f, 0xa0,
0x38, 0x00, 0xe7, 0x59, 0xba, 0x06, 0xbe, 0x06,
0x9f, 0xa0, 0x38, 0x00, 0xc8, 0x09, 0xca, 0x06,
0x08, 0x62, 0x9f, 0xa1, 0x36, 0x08, 0xc0, 0x09,
0x76, 0x06, 0x00, 0x60, 0xa7, 0xc0, 0x7a, 0x06,
0x9f, 0xaf, 0xcc, 0x02, 0xe7, 0x57, 0x00, 0x00,
0xb8, 0x06, 0xa7, 0xc1, 0x7a, 0x06, 0x9f, 0xaf,
0x04, 0x00, 0xe7, 0x57, 0x00, 0x00, 0x8e, 0x06,
0x0a, 0xc1, 0xe7, 0x09, 0x20, 0xc0, 0x10, 0x08,
0xe7, 0xd0, 0x10, 0x08, 0xe7, 0x67, 0x40, 0x00,
0x10, 0x08, 0x9f, 0xaf, 0x92, 0x0c, 0xc0, 0x09,
0xd0, 0x06, 0x00, 0x60, 0x05, 0xc4, 0xc0, 0x59,
0xbe, 0x06, 0x02, 0xc0, 0x9f, 0xaf, 0xec, 0x00,
0x9f, 0xaf, 0x34, 0x02, 0xe7, 0x57, 0x00, 0x00,
0xa6, 0x06, 0x9f, 0xa0, 0x7a, 0x02, 0xa7, 0xcf,
0x7a, 0x06, 0x48, 0x02, 0xe7, 0x09, 0xbe, 0x06,
0xd0, 0x06, 0xc8, 0x37, 0x04, 0x00, 0x9f, 0xaf,
0x08, 0x03, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00,
0xce, 0x06, 0x97, 0xc0, 0xd7, 0x09, 0x00, 0xc0,
0xc1, 0xdf, 0xc8, 0x09, 0xc6, 0x06, 0x08, 0x62,
0x14, 0xc0, 0x27, 0x04, 0xc6, 0x06, 0x10, 0x94,
0xf0, 0x07, 0x10, 0x08, 0x02, 0x00, 0xc1, 0x07,
0x01, 0x00, 0x70, 0x00, 0x04, 0x00, 0xf0, 0x07,
0x30, 0x01, 0x06, 0x00, 0x50, 0xaf, 0xe7, 0x07,
0xff, 0xff, 0xd0, 0x06, 0xe7, 0x07, 0x00, 0x00,
0xce, 0x06, 0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf,
0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf, 0x48, 0x02,
0xd0, 0x09, 0xc6, 0x06, 0x27, 0x02, 0xc6, 0x06,
0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf, 0x48, 0x02,
0xc8, 0x37, 0x04, 0x00, 0x00, 0x0c, 0x0c, 0x00,
0x00, 0x60, 0x21, 0xc0, 0xc0, 0x37, 0x3e, 0x00,
0x23, 0xc9, 0xc0, 0x57, 0xb4, 0x05, 0x1b, 0xc8,
0xc0, 0x17, 0x3f, 0x00, 0xc0, 0x67, 0xc0, 0xff,
0x30, 0x00, 0x08, 0x00, 0xf0, 0x07, 0x00, 0x00,
0x04, 0x00, 0x00, 0x02, 0xc0, 0x17, 0x4c, 0x00,
0x30, 0x00, 0x06, 0x00, 0xf0, 0x07, 0xa0, 0x01,
0x0a, 0x00, 0x48, 0x02, 0xc1, 0x07, 0x02, 0x00,
0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf, 0x51, 0xaf,
0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf, 0x9f, 0xaf,
0x08, 0x03, 0x9f, 0xaf, 0x7a, 0x02, 0x97, 0xcf,
0x9f, 0xaf, 0x7a, 0x02, 0xc9, 0x37, 0x04, 0x00,
0xc1, 0xdf, 0xc8, 0x09, 0xa2, 0x06, 0x50, 0x02,
0x67, 0x02, 0xa2, 0x06, 0xd1, 0x07, 0x00, 0x00,
0x27, 0xd8, 0xaa, 0x06, 0xc0, 0xdf, 0x9f, 0xaf,
0xc4, 0x01, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00,
0xd2, 0x06, 0x97, 0xc1, 0xe7, 0x57, 0x01, 0x00,
0xa8, 0x06, 0x97, 0xc0, 0xc8, 0x09, 0xa0, 0x06,
0x08, 0x62, 0x97, 0xc0, 0x00, 0x02, 0xc0, 0x17,
0x0e, 0x00, 0x27, 0x00, 0x34, 0x01, 0x27, 0x0c,
0x0c, 0x00, 0x36, 0x01, 0xe7, 0x07, 0x50, 0xc3,
0x12, 0xc0, 0xe7, 0x07, 0xcc, 0x0b, 0x02, 0x00,
0xe7, 0x07, 0x01, 0x00, 0xa8, 0x06, 0xe7, 0x07,
0x05, 0x00, 0x90, 0xc0, 0x97, 0xcf, 0xc8, 0x09,
0xa4, 0x06, 0x08, 0x62, 0x02, 0xc0, 0x10, 0x64,
0x07, 0xc1, 0xe7, 0x07, 0x00, 0x00, 0x9e, 0x06,
0xe7, 0x07, 0x72, 0x04, 0x24, 0x00, 0x97, 0xcf,
0x27, 0x04, 0xa4, 0x06, 0xc8, 0x17, 0x0e, 0x00,
0x27, 0x02, 0x9e, 0x06, 0xe7, 0x07, 0x80, 0x04,
0x24, 0x00, 0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0,
0xc1, 0xdf, 0xe7, 0x57, 0x00, 0x00, 0x90, 0x06,
0x13, 0xc1, 0x9f, 0xaf, 0x06, 0x02, 0xe7, 0x57,
0x00, 0x00, 0x9e, 0x06, 0x13, 0xc0, 0xe7, 0x09,
0x9e, 0x06, 0x30, 0x01, 0xe7, 0x07, 0xf2, 0x05,
0x32, 0x01, 0xe7, 0x07, 0x10, 0x00, 0x96, 0xc0,
0xe7, 0x09, 0x9e, 0x06, 0x90, 0x06, 0x04, 0xcf,
0xe7, 0x57, 0x00, 0x00, 0x9e, 0x06, 0x02, 0xc1,
0x9f, 0xaf, 0x06, 0x02, 0xe7, 0x05, 0x00, 0xc0,
0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf,
0x08, 0x92, 0xe7, 0x57, 0x02, 0x00, 0xaa, 0x06,
0x02, 0xc3, 0xc8, 0x09, 0xa4, 0x06, 0x27, 0x02,
0xa6, 0x06, 0x08, 0x62, 0x03, 0xc1, 0xe7, 0x05,
0x00, 0xc0, 0x97, 0xcf, 0x27, 0x04, 0xa4, 0x06,
0xe7, 0x05, 0x00, 0xc0, 0xf0, 0x07, 0x40, 0x00,
0x08, 0x00, 0xf0, 0x07, 0x00, 0x00, 0x04, 0x00,
0x00, 0x02, 0xc0, 0x17, 0x0c, 0x00, 0x30, 0x00,
0x06, 0x00, 0xf0, 0x07, 0x46, 0x01, 0x0a, 0x00,
0xc8, 0x17, 0x04, 0x00, 0xc1, 0x07, 0x02, 0x00,
0x51, 0xaf, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00,
0x96, 0x06, 0x97, 0xc0, 0xc1, 0xdf, 0xc8, 0x09,
0x96, 0x06, 0x27, 0x04, 0x96, 0x06, 0x27, 0x52,
0x98, 0x06, 0x03, 0xc1, 0xe7, 0x07, 0x96, 0x06,
0x98, 0x06, 0xc0, 0xdf, 0x17, 0x02, 0xc8, 0x17,
0x0e, 0x00, 0x9f, 0xaf, 0xba, 0x03, 0xc8, 0x05,
0x00, 0x60, 0x03, 0xc0, 0x9f, 0xaf, 0x24, 0x03,
0x97, 0xcf, 0x9f, 0xaf, 0x08, 0x03, 0x97, 0xcf,
0x57, 0x02, 0xc9, 0x07, 0xa4, 0x06, 0xd7, 0x09,
0x00, 0xc0, 0xc1, 0xdf, 0x08, 0x62, 0x1b, 0xc0,
0x50, 0x04, 0x11, 0x02, 0xe7, 0x05, 0x00, 0xc0,
0xc9, 0x05, 0x97, 0xcf, 0x97, 0x02, 0xca, 0x09,
0xd6, 0x06, 0xf2, 0x17, 0x01, 0x00, 0x04, 0x00,
0xf2, 0x27, 0x00, 0x00, 0x06, 0x00, 0xca, 0x17,
0x2c, 0x00, 0xf8, 0x77, 0x01, 0x00, 0x0e, 0x00,
0x06, 0xc0, 0xca, 0xd9, 0xf8, 0x57, 0xff, 0x00,
0x0e, 0x00, 0x01, 0xc1, 0xca, 0xd9, 0x22, 0x1c,
0x0c, 0x00, 0xe2, 0x27, 0x00, 0x00, 0xe2, 0x17,
0x01, 0x00, 0xe2, 0x27, 0x00, 0x00, 0xca, 0x05,
0x00, 0x0c, 0x0c, 0x00, 0xc0, 0x17, 0x41, 0x00,
0xc0, 0x67, 0xc0, 0xff, 0x30, 0x00, 0x08, 0x00,
0x00, 0x02, 0xc0, 0x17, 0x0c, 0x00, 0x30, 0x00,
0x06, 0x00, 0xf0, 0x07, 0xda, 0x00, 0x0a, 0x00,
0xf0, 0x07, 0x00, 0x00, 0x04, 0x00, 0x00, 0x0c,
0x08, 0x00, 0x40, 0xd1, 0x01, 0x00, 0xc0, 0x19,
0xce, 0x06, 0xc0, 0x59, 0xc2, 0x06, 0x04, 0xc9,
0x49, 0xaf, 0x9f, 0xaf, 0xec, 0x00, 0x4a, 0xaf,
0x67, 0x10, 0xce, 0x06, 0xc8, 0x17, 0x04, 0x00,
0xc1, 0x07, 0x01, 0x00, 0xd7, 0x09, 0x00, 0xc0,
0xc1, 0xdf, 0x50, 0xaf, 0xe7, 0x05, 0x00, 0xc0,
0x97, 0xcf, 0xc0, 0x07, 0x01, 0x00, 0xc1, 0x09,
0xac, 0x06, 0xc1, 0x77, 0x01, 0x00, 0x97, 0xc1,
0xd8, 0x77, 0x01, 0x00, 0x12, 0xc0, 0xc9, 0x07,
0x6a, 0x06, 0x9f, 0xaf, 0x08, 0x04, 0x04, 0xc1,
0xc1, 0x77, 0x08, 0x00, 0x13, 0xc0, 0x97, 0xcf,
0xc1, 0x77, 0x02, 0x00, 0x97, 0xc1, 0xc1, 0x77,
0x10, 0x00, 0x0c, 0xc0, 0x9f, 0xaf, 0x2c, 0x04,
0x97, 0xcf, 0xc1, 0x77, 0x04, 0x00, 0x06, 0xc0,
0xc9, 0x07, 0x70, 0x06, 0x9f, 0xaf, 0x08, 0x04,
0x97, 0xc0, 0x00, 0xcf, 0x00, 0x90, 0x97, 0xcf,
0x50, 0x54, 0x97, 0xc1, 0x70, 0x5c, 0x02, 0x00,
0x02, 0x00, 0x97, 0xc1, 0x70, 0x5c, 0x04, 0x00,
0x04, 0x00, 0x97, 0xcf, 0x80, 0x01, 0xc0, 0x00,
0x60, 0x00, 0x30, 0x00, 0x18, 0x00, 0x0c, 0x00,
0x06, 0x00, 0x00, 0x00, 0xcb, 0x09, 0xb2, 0x06,
0xcc, 0x09, 0xb4, 0x06, 0x0b, 0x53, 0x11, 0xc0,
0xc9, 0x02, 0xca, 0x07, 0x1c, 0x04, 0x9f, 0xaf,
0x08, 0x04, 0x97, 0xc0, 0x0a, 0xc8, 0x82, 0x08,
0x0a, 0xcf, 0x82, 0x08, 0x9f, 0xaf, 0x08, 0x04,
0x97, 0xc0, 0x05, 0xc2, 0x89, 0x30, 0x82, 0x60,
0x78, 0xc1, 0x00, 0x90, 0x97, 0xcf, 0x89, 0x10,
0x09, 0x53, 0x79, 0xc2, 0x89, 0x30, 0x82, 0x08,
0x7a, 0xcf, 0xc0, 0xdf, 0x97, 0xcf, 0xc0, 0xdf,
0x97, 0xcf, 0xe7, 0x09, 0x96, 0xc0, 0x92, 0x06,
0xe7, 0x09, 0x98, 0xc0, 0x94, 0x06, 0x0f, 0xcf,
0xe7, 0x09, 0x96, 0xc0, 0x92, 0x06, 0xe7, 0x09,
0x98, 0xc0, 0x94, 0x06, 0xe7, 0x09, 0x9e, 0x06,
0x30, 0x01, 0xe7, 0x07, 0xf2, 0x05, 0x32, 0x01,
0xe7, 0x07, 0x10, 0x00, 0x96, 0xc0, 0xd7, 0x09,
0x00, 0xc0, 0x17, 0x02, 0xc8, 0x09, 0x90, 0x06,
0xc8, 0x37, 0x0e, 0x00, 0xe7, 0x77, 0x2a, 0x00,
0x92, 0x06, 0x30, 0xc0, 0x97, 0x02, 0xca, 0x09,
0xd6, 0x06, 0xe7, 0x77, 0x20, 0x00, 0x92, 0x06,
0x0e, 0xc0, 0xf2, 0x17, 0x01, 0x00, 0x10, 0x00,
0xf2, 0x27, 0x00, 0x00, 0x12, 0x00, 0xe7, 0x77,
0x0a, 0x00, 0x92, 0x06, 0xca, 0x05, 0x1e, 0xc0,
0x97, 0x02, 0xca, 0x09, 0xd6, 0x06, 0xf2, 0x17,
0x01, 0x00, 0x0c, 0x00, 0xf2, 0x27, 0x00, 0x00,
0x0e, 0x00, 0xe7, 0x77, 0x02, 0x00, 0x92, 0x06,
0x07, 0xc0, 0xf2, 0x17, 0x01, 0x00, 0x44, 0x00,
0xf2, 0x27, 0x00, 0x00, 0x46, 0x00, 0x06, 0xcf,
0xf2, 0x17, 0x01, 0x00, 0x60, 0x00, 0xf2, 0x27,
0x00, 0x00, 0x62, 0x00, 0xca, 0x05, 0x9f, 0xaf,
0x08, 0x03, 0x0f, 0xcf, 0x57, 0x02, 0x09, 0x02,
0xf1, 0x09, 0x94, 0x06, 0x0c, 0x00, 0xf1, 0xda,
0x0c, 0x00, 0xc8, 0x09, 0x98, 0x06, 0x50, 0x02,
0x67, 0x02, 0x98, 0x06, 0xd1, 0x07, 0x00, 0x00,
0xc9, 0x05, 0xe7, 0x09, 0x9e, 0x06, 0x90, 0x06,
0xe7, 0x57, 0x00, 0x00, 0x90, 0x06, 0x02, 0xc0,
0x9f, 0xaf, 0x06, 0x02, 0xc8, 0x05, 0xe7, 0x05,
0x00, 0xc0, 0xc0, 0xdf, 0x97, 0xcf, 0xd7, 0x09,
0x00, 0xc0, 0x17, 0x00, 0x17, 0x02, 0x97, 0x02,
0xc0, 0x09, 0x92, 0xc0, 0xe7, 0x07, 0x04, 0x00,
0x90, 0xc0, 0xca, 0x09, 0xd6, 0x06, 0xe7, 0x07,
0x00, 0x00, 0xa8, 0x06, 0xe7, 0x07, 0x6a, 0x04,
0x02, 0x00, 0xc0, 0x77, 0x02, 0x00, 0x08, 0xc0,
0xf2, 0x17, 0x01, 0x00, 0x50, 0x00, 0xf2, 0x27,
0x00, 0x00, 0x52, 0x00, 0x9f, 0xcf, 0x24, 0x06,
0xc0, 0x77, 0x10, 0x00, 0x06, 0xc0, 0xf2, 0x17,
0x01, 0x00, 0x58, 0x00, 0xf2, 0x27, 0x00, 0x00,
0x5a, 0x00, 0xc0, 0x77, 0x80, 0x00, 0x06, 0xc0,
0xf2, 0x17, 0x01, 0x00, 0x70, 0x00, 0xf2, 0x27,
0x00, 0x00, 0x72, 0x00, 0xc0, 0x77, 0x08, 0x00,
0x1d, 0xc1, 0xf2, 0x17, 0x01, 0x00, 0x08, 0x00,
0xf2, 0x27, 0x00, 0x00, 0x0a, 0x00, 0xc0, 0x77,
0x00, 0x02, 0x06, 0xc0, 0xf2, 0x17, 0x01, 0x00,
0x64, 0x00, 0xf2, 0x27, 0x00, 0x00, 0x66, 0x00,
0xc0, 0x77, 0x40, 0x00, 0x06, 0xc0, 0xf2, 0x17,
0x01, 0x00, 0x5c, 0x00, 0xf2, 0x27, 0x00, 0x00,
0x5e, 0x00, 0xc0, 0x77, 0x01, 0x00, 0x01, 0xc0,
0x1b, 0xcf, 0x1a, 0xcf, 0xf2, 0x17, 0x01, 0x00,
0x00, 0x00, 0xf2, 0x27, 0x00, 0x00, 0x02, 0x00,
0xc8, 0x09, 0x34, 0x01, 0xca, 0x17, 0x14, 0x00,
0xd8, 0x77, 0x01, 0x00, 0x05, 0xc0, 0xca, 0xd9,
0xd8, 0x57, 0xff, 0x00, 0x01, 0xc0, 0xca, 0xd9,
0xe2, 0x19, 0x94, 0xc0, 0xe2, 0x27, 0x00, 0x00,
0xe2, 0x17, 0x01, 0x00, 0xe2, 0x27, 0x00, 0x00,
0x9f, 0xaf, 0x40, 0x06, 0x9f, 0xaf, 0xc4, 0x01,
0xe7, 0x57, 0x00, 0x00, 0xd2, 0x06, 0x9f, 0xa1,
0x0e, 0x0a, 0xca, 0x05, 0xc8, 0x05, 0xc0, 0x05,
0xe7, 0x05, 0x00, 0xc0, 0xc0, 0xdf, 0x97, 0xcf,
0xc8, 0x09, 0xa0, 0x06, 0x08, 0x62, 0x97, 0xc0,
0x27, 0x04, 0xa0, 0x06, 0x27, 0x52, 0xa2, 0x06,
0x03, 0xc1, 0xe7, 0x07, 0xa0, 0x06, 0xa2, 0x06,
0x9f, 0xaf, 0x08, 0x03, 0xe7, 0x57, 0x00, 0x00,
0xaa, 0x06, 0x02, 0xc0, 0x27, 0xda, 0xaa, 0x06,
0x97, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xfb, 0x13, 0xe7, 0x57,
0x00, 0x80, 0xb2, 0x00, 0x06, 0xc2, 0xe7, 0x07,
0xee, 0x0b, 0x12, 0x00, 0xe7, 0x07, 0x34, 0x0c,
0xb2, 0x00, 0xe7, 0x07, 0xc6, 0x07, 0xf2, 0x02,
0xc8, 0x09, 0xb4, 0x00, 0xf8, 0x07, 0x02, 0x00,
0x0d, 0x00, 0xd7, 0x09, 0x0e, 0xc0, 0xe7, 0x07,
0x00, 0x00, 0x0e, 0xc0, 0xc8, 0x09, 0xde, 0x00,
0xc8, 0x17, 0x09, 0x00, 0xc9, 0x07, 0xda, 0x06,
0xc0, 0x07, 0x04, 0x00, 0x68, 0x0a, 0x00, 0xda,
0x7d, 0xc1, 0xe7, 0x09, 0xc0, 0x00, 0x7c, 0x06,
0xe7, 0x09, 0xbe, 0x00, 0x78, 0x06, 0xe7, 0x09,
0x10, 0x00, 0xbc, 0x06, 0xc8, 0x07, 0xd6, 0x07,
0x9f, 0xaf, 0xae, 0x07, 0x9f, 0xaf, 0x00, 0x0a,
0xc8, 0x09, 0xde, 0x00, 0x00, 0x0e, 0x0f, 0x00,
0x41, 0x90, 0x9f, 0xde, 0x06, 0x00, 0x44, 0xaf,
0x27, 0x00, 0xb2, 0x06, 0x27, 0x00, 0xb4, 0x06,
0x27, 0x00, 0xb6, 0x06, 0xc0, 0x07, 0x74, 0x00,
0x44, 0xaf, 0x27, 0x00, 0xd6, 0x06, 0x08, 0x00,
0x00, 0x90, 0xc1, 0x07, 0x3a, 0x00, 0x20, 0x00,
0x01, 0xda, 0x7d, 0xc1, 0x9f, 0xaf, 0xba, 0x09,
0xc0, 0x07, 0x44, 0x00, 0x48, 0xaf, 0x27, 0x00,
0x7a, 0x06, 0x9f, 0xaf, 0x96, 0x0a, 0xe7, 0x07,
0x01, 0x00, 0xc0, 0x06, 0xe7, 0x05, 0x0e, 0xc0,
0x97, 0xcf, 0x49, 0xaf, 0xe7, 0x87, 0x43, 0x00,
0x0e, 0xc0, 0xe7, 0x07, 0xff, 0xff, 0xbe, 0x06,
0x9f, 0xaf, 0xae, 0x0a, 0xc0, 0x07, 0x01, 0x00,
0x60, 0xaf, 0x4a, 0xaf, 0x97, 0xcf, 0x00, 0x08,
0x09, 0x08, 0x11, 0x08, 0x00, 0xda, 0x7c, 0xc1,
0x97, 0xcf, 0x67, 0x04, 0xcc, 0x02, 0xc0, 0xdf,
0x51, 0x94, 0xb1, 0xaf, 0x06, 0x00, 0xc1, 0xdf,
0xc9, 0x09, 0xcc, 0x02, 0x49, 0x62, 0x75, 0xc1,
0xc0, 0xdf, 0xa7, 0xcf, 0xd6, 0x02, 0x0e, 0x00,
0x24, 0x00, 0x80, 0x04, 0x22, 0x00, 0x4e, 0x05,
0xd0, 0x00, 0x0e, 0x0a, 0xaa, 0x00, 0x30, 0x08,
0xbe, 0x00, 0x4a, 0x0a, 0x10, 0x00, 0x20, 0x00,
0x04, 0x00, 0x6e, 0x04, 0x02, 0x00, 0x6a, 0x04,
0x06, 0x00, 0x00, 0x00, 0x24, 0xc0, 0x04, 0x04,
0x28, 0xc0, 0xfe, 0xfb, 0x1e, 0xc0, 0x00, 0x04,
0x22, 0xc0, 0xff, 0xf4, 0xc0, 0x00, 0x90, 0x09,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x56, 0x08,
0x60, 0x08, 0xd0, 0x08, 0xda, 0x08, 0x00, 0x09,
0x04, 0x09, 0x08, 0x09, 0x32, 0x09, 0x42, 0x09,
0x50, 0x09, 0x52, 0x09, 0x5a, 0x09, 0x5a, 0x09,
0x27, 0x02, 0xca, 0x06, 0x97, 0xcf, 0xe7, 0x07,
0x00, 0x00, 0xca, 0x06, 0x0a, 0x0e, 0x01, 0x00,
0xca, 0x57, 0x0e, 0x00, 0x9f, 0xc3, 0x5a, 0x09,
0xca, 0x37, 0x00, 0x00, 0x9f, 0xc2, 0x5a, 0x09,
0x0a, 0xd2, 0xb2, 0xcf, 0x16, 0x08, 0xc8, 0x09,
0xde, 0x00, 0x07, 0x06, 0x9f, 0xcf, 0x6c, 0x09,
0x17, 0x02, 0xc8, 0x09, 0xde, 0x00, 0x00, 0x0e,
0x0f, 0x00, 0x41, 0x90, 0x9f, 0xde, 0x06, 0x00,
0xc8, 0x05, 0x30, 0x50, 0x06, 0x00, 0x9f, 0xc8,
0x5a, 0x09, 0x27, 0x0c, 0x02, 0x00, 0xb0, 0x06,
0xc0, 0x09, 0xb2, 0x06, 0x27, 0x00, 0xb4, 0x06,
0xe7, 0x07, 0x00, 0x00, 0xae, 0x06, 0x27, 0x00,
0x80, 0x06, 0x00, 0x1c, 0x06, 0x00, 0x27, 0x00,
0xb6, 0x06, 0x41, 0x90, 0x67, 0x50, 0xb0, 0x06,
0x0d, 0xc0, 0x67, 0x00, 0x7e, 0x06, 0x27, 0x0c,
0x06, 0x00, 0x82, 0x06, 0xe7, 0x07, 0xbc, 0x08,
0x84, 0x06, 0xc8, 0x07, 0x7e, 0x06, 0x41, 0x90,
0x51, 0xaf, 0x97, 0xcf, 0x9f, 0xaf, 0x48, 0x0c,
0xe7, 0x09, 0xb6, 0x06, 0xb4, 0x06, 0xe7, 0x09,
0xb0, 0x06, 0xae, 0x06, 0x59, 0xaf, 0x97, 0xcf,
0x27, 0x0c, 0x02, 0x00, 0xac, 0x06, 0x59, 0xaf,
0x97, 0xcf, 0x09, 0x0c, 0x02, 0x00, 0x09, 0xda,
0x49, 0xd2, 0xc9, 0x19, 0xd6, 0x06, 0xc8, 0x07,
0x7e, 0x06, 0xe0, 0x07, 0x00, 0x00, 0x60, 0x02,
0xe0, 0x07, 0x04, 0x00, 0xd0, 0x07, 0xcc, 0x08,
0x48, 0xdb, 0x41, 0x90, 0x50, 0xaf, 0x97, 0xcf,
0x59, 0xaf, 0x97, 0xcf, 0x59, 0xaf, 0x97, 0xcf,
0xf0, 0x57, 0x06, 0x00, 0x06, 0x00, 0x25, 0xc1,
0xe7, 0x07, 0x70, 0x06, 0x80, 0x06, 0x41, 0x90,
0x67, 0x00, 0x7e, 0x06, 0x27, 0x0c, 0x06, 0x00,
0x82, 0x06, 0xe7, 0x07, 0x8c, 0x09, 0x84, 0x06,
0xc8, 0x07, 0x7e, 0x06, 0x41, 0x90, 0x51, 0xaf,
0x97, 0xcf, 0x07, 0x0c, 0x06, 0x00, 0xc7, 0x57,
0x06, 0x00, 0x0f, 0xc1, 0xc8, 0x07, 0x70, 0x06,
0x15, 0xcf, 0x00, 0x0c, 0x02, 0x00, 0x00, 0xda,
0x40, 0xd1, 0x27, 0x00, 0xc2, 0x06, 0x1e, 0xcf,
0x1d, 0xcf, 0x27, 0x0c, 0x02, 0x00, 0xcc, 0x06,
0x19, 0xcf, 0x27, 0x02, 0x20, 0x01, 0xe7, 0x07,
0x08, 0x00, 0x22, 0x01, 0xe7, 0x07, 0x13, 0x00,
0xb0, 0xc0, 0x97, 0xcf, 0x41, 0x90, 0x67, 0x00,
0x7e, 0x06, 0xe7, 0x01, 0x82, 0x06, 0x27, 0x02,
0x80, 0x06, 0xe7, 0x07, 0x8c, 0x09, 0x84, 0x06,
0xc8, 0x07, 0x7e, 0x06, 0xc1, 0x07, 0x00, 0x80,
0x50, 0xaf, 0x97, 0xcf, 0x59, 0xaf, 0x97, 0xcf,
0x00, 0x60, 0x05, 0xc0, 0xe7, 0x07, 0x00, 0x00,
0xc4, 0x06, 0xa7, 0xcf, 0x7c, 0x06, 0x9f, 0xaf,
0x00, 0x0a, 0xe7, 0x07, 0x01, 0x00, 0xc4, 0x06,
0x49, 0xaf, 0xd7, 0x09, 0x00, 0xc0, 0x07, 0xaf,
0xe7, 0x05, 0x00, 0xc0, 0x4a, 0xaf, 0xa7, 0xcf,
0x7c, 0x06, 0xc0, 0x07, 0xfe, 0x7f, 0x44, 0xaf,
0x40, 0x00, 0xc0, 0x37, 0x00, 0x01, 0x41, 0x90,
0xc0, 0x37, 0x08, 0x00, 0xdf, 0xde, 0x50, 0x06,
0xc0, 0x57, 0x10, 0x00, 0x02, 0xc2, 0xc0, 0x07,
0x10, 0x00, 0x27, 0x00, 0x9a, 0x06, 0x41, 0x90,
0x9f, 0xde, 0x40, 0x06, 0x44, 0xaf, 0x27, 0x00,
0x9c, 0x06, 0xc0, 0x09, 0x9a, 0x06, 0x41, 0x90,
0x00, 0xd2, 0x00, 0xd8, 0x9f, 0xde, 0x08, 0x00,
0x44, 0xaf, 0x27, 0x00, 0xc8, 0x06, 0x97, 0xcf,
0xe7, 0x87, 0x00, 0x84, 0x28, 0xc0, 0xe7, 0x67,
0xff, 0xfb, 0x24, 0xc0, 0x97, 0xcf, 0xe7, 0x87,
0x01, 0x00, 0xd2, 0x06, 0xe7, 0x57, 0x00, 0x00,
0xa8, 0x06, 0x97, 0xc1, 0x9f, 0xaf, 0x00, 0x0a,
0xe7, 0x87, 0x00, 0x06, 0x22, 0xc0, 0xe7, 0x07,
0x00, 0x00, 0x90, 0xc0, 0xe7, 0x67, 0xfe, 0xff,
0x3e, 0xc0, 0xe7, 0x07, 0x26, 0x00, 0x0a, 0xc0,
0xe7, 0x87, 0x01, 0x00, 0x3e, 0xc0, 0xe7, 0x07,
0xff, 0xff, 0xbe, 0x06, 0x9f, 0xaf, 0x10, 0x0b,
0x97, 0xcf, 0x17, 0x00, 0xa7, 0xaf, 0x78, 0x06,
0xc0, 0x05, 0x27, 0x00, 0x76, 0x06, 0xe7, 0x87,
0x01, 0x00, 0xd2, 0x06, 0x9f, 0xaf, 0x00, 0x0a,
0xe7, 0x07, 0x0c, 0x00, 0x40, 0xc0, 0x9f, 0xaf,
0x10, 0x0b, 0x00, 0x90, 0x27, 0x00, 0xa6, 0x06,
0x27, 0x00, 0xaa, 0x06, 0xe7, 0x09, 0xb2, 0x06,
0xb4, 0x06, 0x27, 0x00, 0xae, 0x06, 0x27, 0x00,
0xac, 0x06, 0x9f, 0xaf, 0xae, 0x0a, 0xc0, 0x07,
0x00, 0x00, 0x27, 0x00, 0xb2, 0x02, 0x27, 0x00,
0xb4, 0x02, 0x27, 0x00, 0x8e, 0x06, 0xc0, 0x07,
0x06, 0x00, 0xc8, 0x09, 0xde, 0x00, 0xc8, 0x17,
0x03, 0x00, 0xc9, 0x07, 0x70, 0x06, 0x29, 0x0a,
0x00, 0xda, 0x7d, 0xc1, 0x97, 0xcf, 0xd7, 0x09,
0x00, 0xc0, 0xc1, 0xdf, 0x00, 0x90, 0x27, 0x00,
0x96, 0x06, 0xe7, 0x07, 0x96, 0x06, 0x98, 0x06,
0x27, 0x00, 0xa0, 0x06, 0xe7, 0x07, 0xa0, 0x06,
0xa2, 0x06, 0x27, 0x00, 0xa6, 0x06, 0x27, 0x00,
0x90, 0x06, 0x27, 0x00, 0x9e, 0x06, 0xc8, 0x09,
0x9c, 0x06, 0xc1, 0x09, 0x9a, 0x06, 0xc9, 0x07,
0xa4, 0x06, 0x11, 0x02, 0x09, 0x02, 0xc8, 0x17,
0x40, 0x06, 0x01, 0xda, 0x7a, 0xc1, 0x51, 0x94,
0xc8, 0x09, 0xc8, 0x06, 0xc9, 0x07, 0xc6, 0x06,
0xc1, 0x09, 0x9a, 0x06, 0x11, 0x02, 0x09, 0x02,
0xc8, 0x17, 0x08, 0x00, 0x01, 0xda, 0x7a, 0xc1,
0x51, 0x94, 0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf,
0xe7, 0x57, 0x00, 0x00, 0x76, 0x06, 0x97, 0xc0,
0x9f, 0xaf, 0x04, 0x00, 0xe7, 0x09, 0xbe, 0x06,
0xba, 0x06, 0xe7, 0x57, 0xff, 0xff, 0xba, 0x06,
0x04, 0xc1, 0xe7, 0x07, 0x10, 0x0b, 0xb8, 0x06,
0x97, 0xcf, 0xe7, 0x17, 0x32, 0x00, 0xba, 0x06,
0xe7, 0x67, 0xff, 0x07, 0xba, 0x06, 0xe7, 0x07,
0x46, 0x0b, 0xb8, 0x06, 0x97, 0xcf, 0xe7, 0x57,
0x00, 0x00, 0xc0, 0x06, 0x23, 0xc0, 0xe7, 0x07,
0x04, 0x00, 0x90, 0xc0, 0xe7, 0x07, 0x00, 0x80,
0x80, 0xc0, 0xe7, 0x07, 0x00, 0x00, 0x80, 0xc0,
0xe7, 0x07, 0x00, 0x80, 0x80, 0xc0, 0xc0, 0x07,
0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0xc0, 0x07,
0x00, 0x00, 0xe7, 0x07, 0x00, 0x00, 0x80, 0xc0,
0xe7, 0x07, 0x00, 0x80, 0x80, 0xc0, 0xe7, 0x07,
0x00, 0x80, 0x40, 0xc0, 0xc0, 0x07, 0x00, 0x00,
0xe7, 0x07, 0x00, 0x00, 0x40, 0xc0, 0xe7, 0x07,
0x00, 0x00, 0x80, 0xc0, 0xe7, 0x07, 0x04, 0x00,
0x90, 0xc0, 0xe7, 0x07, 0x00, 0x02, 0x40, 0xc0,
0xe7, 0x07, 0x0c, 0x02, 0x40, 0xc0, 0xe7, 0x07,
0x00, 0x00, 0xc0, 0x06, 0xe7, 0x07, 0x00, 0x00,
0xb8, 0x06, 0xe7, 0x07, 0x00, 0x00, 0xd2, 0x06,
0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf, 0x9f, 0xaf,
0x34, 0x02, 0xe7, 0x05, 0x00, 0xc0, 0x9f, 0xaf,
0xc4, 0x01, 0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0,
0x17, 0x00, 0x17, 0x02, 0x97, 0x02, 0xe7, 0x57,
0x00, 0x00, 0xa8, 0x06, 0x06, 0xc0, 0xc0, 0x09,
0x92, 0xc0, 0xc0, 0x77, 0x09, 0x02, 0x9f, 0xc1,
0x5c, 0x05, 0x9f, 0xcf, 0x32, 0x06, 0xd7, 0x09,
0x0e, 0xc0, 0xe7, 0x07, 0x00, 0x00, 0x0e, 0xc0,
0x9f, 0xaf, 0x02, 0x0c, 0xe7, 0x05, 0x0e, 0xc0,
0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0, 0x17, 0x02,
0xc8, 0x09, 0xb0, 0xc0, 0xe7, 0x67, 0xfe, 0x7f,
0xb0, 0xc0, 0xc8, 0x77, 0x00, 0x20, 0x9f, 0xc1,
0x64, 0xeb, 0xe7, 0x57, 0x00, 0x00, 0xc8, 0x02,
0x9f, 0xc1, 0x80, 0xeb, 0xc8, 0x99, 0xca, 0x02,
0xc8, 0x67, 0x04, 0x00, 0x9f, 0xc1, 0x96, 0xeb,
0x9f, 0xcf, 0x4c, 0xeb, 0xe7, 0x07, 0x00, 0x00,
0xa6, 0xc0, 0xe7, 0x09, 0xb0, 0xc0, 0xc8, 0x02,
0xe7, 0x07, 0x03, 0x00, 0xb0, 0xc0, 0x97, 0xcf,
0xc0, 0x09, 0xb0, 0x06, 0xc0, 0x37, 0x01, 0x00,
0x97, 0xc9, 0xc9, 0x09, 0xb2, 0x06, 0x02, 0x00,
0x41, 0x90, 0x48, 0x02, 0xc9, 0x17, 0x06, 0x00,
0x9f, 0xaf, 0x08, 0x04, 0x9f, 0xa2, 0x72, 0x0c,
0x02, 0xda, 0x77, 0xc1, 0x41, 0x60, 0x71, 0xc1,
0x97, 0xcf, 0x17, 0x02, 0x57, 0x02, 0x43, 0x04,
0x21, 0x04, 0xe0, 0x00, 0x43, 0x04, 0x21, 0x04,
0xe0, 0x00, 0x43, 0x04, 0x21, 0x04, 0xe0, 0x00,
0xc1, 0x07, 0x01, 0x00, 0xc9, 0x05, 0xc8, 0x05,
0x97, 0xcf, 0xe7, 0x07, 0x01, 0x00, 0x8e, 0x06,
0xc8, 0x07, 0x86, 0x06, 0xe7, 0x07, 0x00, 0x00,
0x86, 0x06, 0xe7, 0x07, 0x10, 0x08, 0x88, 0x06,
0xe7, 0x07, 0x04, 0x00, 0x8a, 0x06, 0xe7, 0x07,
0xbc, 0x0c, 0x8c, 0x06, 0xc1, 0x07, 0x03, 0x80,
0x50, 0xaf, 0x97, 0xcf, 0xe7, 0x07, 0x00, 0x00,
0x8e, 0x06, 0x97, 0xcf,
0x00, 0x00
};
/****************************************************************
* kaweth_new_code_fix
****************************************************************/
static __u8 kaweth_new_code_fix[] =
{
0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD,
0x02, 0x00, 0x08, 0x00, 0x28, 0x00, 0x2c, 0x00,
0x34, 0x00, 0x3c, 0x00, 0x40, 0x00, 0x48, 0x00,
0x54, 0x00, 0x58, 0x00, 0x5e, 0x00, 0x64, 0x00,
0x68, 0x00, 0x6e, 0x00, 0x6c, 0x00, 0x72, 0x00,
0x76, 0x00, 0x7c, 0x00, 0x80, 0x00, 0x86, 0x00,
0x8a, 0x00, 0x90, 0x00, 0x94, 0x00, 0x98, 0x00,
0x9e, 0x00, 0xa6, 0x00, 0xaa, 0x00, 0xb0, 0x00,
0xb4, 0x00, 0xb8, 0x00, 0xc0, 0x00, 0xc6, 0x00,
0xca, 0x00, 0xd0, 0x00, 0xd4, 0x00, 0xd8, 0x00,
0xe0, 0x00, 0xde, 0x00, 0xe8, 0x00, 0xf0, 0x00,
0xfc, 0x00, 0x04, 0x01, 0x0a, 0x01, 0x18, 0x01,
0x22, 0x01, 0x28, 0x01, 0x3a, 0x01, 0x3e, 0x01,
0x7e, 0x01, 0x98, 0x01, 0x9c, 0x01, 0xa2, 0x01,
0xac, 0x01, 0xb2, 0x01, 0xba, 0x01, 0xc0, 0x01,
0xc8, 0x01, 0xd0, 0x01, 0xd6, 0x01, 0xf4, 0x01,
0xfc, 0x01, 0x08, 0x02, 0x16, 0x02, 0x1a, 0x02,
0x22, 0x02, 0x2a, 0x02, 0x2e, 0x02, 0x3e, 0x02,
0x44, 0x02, 0x4a, 0x02, 0x50, 0x02, 0x64, 0x02,
0x62, 0x02, 0x6c, 0x02, 0x72, 0x02, 0x86, 0x02,
0x8c, 0x02, 0x90, 0x02, 0x9e, 0x02, 0xbc, 0x02,
0xd0, 0x02, 0xd8, 0x02, 0xdc, 0x02, 0xe0, 0x02,
0xe8, 0x02, 0xe6, 0x02, 0xf4, 0x02, 0xfe, 0x02,
0x04, 0x03, 0x0c, 0x03, 0x28, 0x03, 0x7c, 0x03,
0x90, 0x03, 0x94, 0x03, 0x9c, 0x03, 0xa2, 0x03,
0xc0, 0x03, 0xd0, 0x03, 0xd4, 0x03, 0xee, 0x03,
0xfa, 0x03, 0xfe, 0x03, 0x2e, 0x04, 0x32, 0x04,
0x3c, 0x04, 0x40, 0x04, 0x4e, 0x04, 0x76, 0x04,
0x7c, 0x04, 0x84, 0x04, 0x8a, 0x04, 0x8e, 0x04,
0xa6, 0x04, 0xb0, 0x04, 0xb8, 0x04, 0xbe, 0x04,
0xd2, 0x04, 0xdc, 0x04, 0xee, 0x04, 0x10, 0x05,
0x1a, 0x05, 0x24, 0x05, 0x2a, 0x05, 0x36, 0x05,
0x34, 0x05, 0x3c, 0x05, 0x42, 0x05, 0x64, 0x05,
0x6a, 0x05, 0x6e, 0x05, 0x86, 0x05, 0x22, 0x06,
0x26, 0x06, 0x2c, 0x06, 0x30, 0x06, 0x42, 0x06,
0x4a, 0x06, 0x4e, 0x06, 0x56, 0x06, 0x54, 0x06,
0x5a, 0x06, 0x60, 0x06, 0x66, 0x06, 0xe8, 0x06,
0xee, 0x06, 0xf4, 0x06, 0x16, 0x07, 0x26, 0x07,
0x2c, 0x07, 0x32, 0x07, 0x36, 0x07, 0x3a, 0x07,
0x3e, 0x07, 0x52, 0x07, 0x56, 0x07, 0x5a, 0x07,
0x64, 0x07, 0x76, 0x07, 0x7a, 0x07, 0x80, 0x07,
0x84, 0x07, 0x8a, 0x07, 0x9e, 0x07, 0xa2, 0x07,
0xda, 0x07, 0xde, 0x07, 0xe2, 0x07, 0xe6, 0x07,
0xea, 0x07, 0xee, 0x07, 0xf2, 0x07, 0xf6, 0x07,
0x0e, 0x08, 0x16, 0x08, 0x18, 0x08, 0x1a, 0x08,
0x1c, 0x08, 0x1e, 0x08, 0x20, 0x08, 0x22, 0x08,
0x24, 0x08, 0x26, 0x08, 0x28, 0x08, 0x2a, 0x08,
0x2c, 0x08, 0x2e, 0x08, 0x32, 0x08, 0x3a, 0x08,
0x46, 0x08, 0x4e, 0x08, 0x54, 0x08, 0x5e, 0x08,
0x78, 0x08, 0x7e, 0x08, 0x82, 0x08, 0x86, 0x08,
0x8c, 0x08, 0x90, 0x08, 0x98, 0x08, 0x9e, 0x08,
0xa4, 0x08, 0xaa, 0x08, 0xb0, 0x08, 0xae, 0x08,
0xb4, 0x08, 0xbe, 0x08, 0xc4, 0x08, 0xc2, 0x08,
0xca, 0x08, 0xc8, 0x08, 0xd4, 0x08, 0xe4, 0x08,
0xe8, 0x08, 0xf6, 0x08, 0x14, 0x09, 0x12, 0x09,
0x1a, 0x09, 0x20, 0x09, 0x26, 0x09, 0x24, 0x09,
0x2a, 0x09, 0x3e, 0x09, 0x4c, 0x09, 0x56, 0x09,
0x70, 0x09, 0x74, 0x09, 0x78, 0x09, 0x7e, 0x09,
0x7c, 0x09, 0x82, 0x09, 0x98, 0x09, 0x9c, 0x09,
0xa0, 0x09, 0xa6, 0x09, 0xb8, 0x09, 0xdc, 0x09,
0xe8, 0x09, 0xec, 0x09, 0xfc, 0x09, 0x12, 0x0a,
0x18, 0x0a, 0x1e, 0x0a, 0x42, 0x0a, 0x46, 0x0a,
0x4e, 0x0a, 0x54, 0x0a, 0x5a, 0x0a, 0x5e, 0x0a,
0x68, 0x0a, 0x6e, 0x0a, 0x72, 0x0a, 0x78, 0x0a,
0x76, 0x0a, 0x7c, 0x0a, 0x80, 0x0a, 0x84, 0x0a,
0x94, 0x0a, 0xa4, 0x0a, 0xb8, 0x0a, 0xbe, 0x0a,
0xbc, 0x0a, 0xc2, 0x0a, 0xc8, 0x0a, 0xc6, 0x0a,
0xcc, 0x0a, 0xd0, 0x0a, 0xd4, 0x0a, 0xd8, 0x0a,
0xdc, 0x0a, 0xe0, 0x0a, 0xf2, 0x0a, 0xf6, 0x0a,
0xfa, 0x0a, 0x14, 0x0b, 0x1a, 0x0b, 0x20, 0x0b,
0x1e, 0x0b, 0x26, 0x0b, 0x2e, 0x0b, 0x2c, 0x0b,
0x36, 0x0b, 0x3c, 0x0b, 0x42, 0x0b, 0x40, 0x0b,
0x4a, 0x0b, 0xaa, 0x0b, 0xb0, 0x0b, 0xb6, 0x0b,
0xc0, 0x0b, 0xc8, 0x0b, 0xda, 0x0b, 0xe8, 0x0b,
0xec, 0x0b, 0xfa, 0x0b, 0x4a, 0x0c, 0x54, 0x0c,
0x62, 0x0c, 0x66, 0x0c, 0x96, 0x0c, 0x9a, 0x0c,
0xa0, 0x0c, 0xa6, 0x0c, 0xa4, 0x0c, 0xac, 0x0c,
0xb2, 0x0c, 0xb0, 0x0c, 0xc0, 0x0c,
0x00, 0x00
};
static const int len_kaweth_trigger_code = sizeof(kaweth_trigger_code);
static const int len_kaweth_trigger_code_fix = sizeof(kaweth_trigger_code_fix);
static const int len_kaweth_new_code = sizeof(kaweth_new_code);
static const int len_kaweth_new_code_fix = sizeof(kaweth_new_code_fix);

534
drivers/net/usb/mcs7830.c 一般檔案
查看文件

@@ -0,0 +1,534 @@
/*
* MosChips MCS7830 based USB 2.0 Ethernet Devices
*
* based on usbnet.c, asix.c and the vendor provided mcs7830 driver
*
* Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>
* Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
* Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
* Copyright (c) 2002-2003 TiVo Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/crc32.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/init.h>
#include <linux/mii.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/usb.h>
#include "usbnet.h"
/* requests */
#define MCS7830_RD_BMREQ (USB_DIR_IN | USB_TYPE_VENDOR | \
USB_RECIP_DEVICE)
#define MCS7830_WR_BMREQ (USB_DIR_OUT | USB_TYPE_VENDOR | \
USB_RECIP_DEVICE)
#define MCS7830_RD_BREQ 0x0E
#define MCS7830_WR_BREQ 0x0D
#define MCS7830_CTRL_TIMEOUT 1000
#define MCS7830_MAX_MCAST 64
#define MCS7830_VENDOR_ID 0x9710
#define MCS7830_PRODUCT_ID 0x7830
#define MCS7830_MII_ADVERTISE (ADVERTISE_PAUSE_CAP | ADVERTISE_100FULL | \
ADVERTISE_100HALF | ADVERTISE_10FULL | \
ADVERTISE_10HALF | ADVERTISE_CSMA)
/* HIF_REG_XX coressponding index value */
enum {
HIF_REG_MULTICAST_HASH = 0x00,
HIF_REG_PACKET_GAP1 = 0x08,
HIF_REG_PACKET_GAP2 = 0x09,
HIF_REG_PHY_DATA = 0x0a,
HIF_REG_PHY_CMD1 = 0x0c,
HIF_REG_PHY_CMD1_READ = 0x40,
HIF_REG_PHY_CMD1_WRITE = 0x20,
HIF_REG_PHY_CMD1_PHYADDR = 0x01,
HIF_REG_PHY_CMD2 = 0x0d,
HIF_REG_PHY_CMD2_PEND_FLAG_BIT = 0x80,
HIF_REG_PHY_CMD2_READY_FLAG_BIT = 0x40,
HIF_REG_CONFIG = 0x0e,
HIF_REG_CONFIG_CFG = 0x80,
HIF_REG_CONFIG_SPEED100 = 0x40,
HIF_REG_CONFIG_FULLDUPLEX_ENABLE = 0x20,
HIF_REG_CONFIG_RXENABLE = 0x10,
HIF_REG_CONFIG_TXENABLE = 0x08,
HIF_REG_CONFIG_SLEEPMODE = 0x04,
HIF_REG_CONFIG_ALLMULTICAST = 0x02,
HIF_REG_CONFIG_PROMISCIOUS = 0x01,
HIF_REG_ETHERNET_ADDR = 0x0f,
HIF_REG_22 = 0x15,
HIF_REG_PAUSE_THRESHOLD = 0x16,
HIF_REG_PAUSE_THRESHOLD_DEFAULT = 0,
};
struct mcs7830_data {
u8 multi_filter[8];
u8 config;
};
static const char driver_name[] = "MOSCHIP usb-ethernet driver";
static int mcs7830_get_reg(struct usbnet *dev, u16 index, u16 size, void *data)
{
struct usb_device *xdev = dev->udev;
int ret;
ret = usb_control_msg(xdev, usb_rcvctrlpipe(xdev, 0), MCS7830_RD_BREQ,
MCS7830_RD_BMREQ, 0x0000, index, data,
size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT));
return ret;
}
static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, void *data)
{
struct usb_device *xdev = dev->udev;
int ret;
ret = usb_control_msg(xdev, usb_sndctrlpipe(xdev, 0), MCS7830_WR_BREQ,
MCS7830_WR_BMREQ, 0x0000, index, data,
size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT));
return ret;
}
static void mcs7830_async_cmd_callback(struct urb *urb)
{
struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;
if (urb->status < 0)
printk(KERN_DEBUG "mcs7830_async_cmd_callback() failed with %d",
urb->status);
kfree(req);
usb_free_urb(urb);
}
static void mcs7830_set_reg_async(struct usbnet *dev, u16 index, u16 size, void *data)
{
struct usb_ctrlrequest *req;
int ret;
struct urb *urb;
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
dev_dbg(&dev->udev->dev, "Error allocating URB "
"in write_cmd_async!");
return;
}
req = kmalloc(sizeof *req, GFP_ATOMIC);
if (!req) {
dev_err(&dev->udev->dev, "Failed to allocate memory for "
"control request");
goto out;
}
req->bRequestType = MCS7830_WR_BMREQ;
req->bRequest = MCS7830_WR_BREQ;
req->wValue = 0;
req->wIndex = cpu_to_le16(index);
req->wLength = cpu_to_le16(size);
usb_fill_control_urb(urb, dev->udev,
usb_sndctrlpipe(dev->udev, 0),
(void *)req, data, size,
mcs7830_async_cmd_callback, req);
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret < 0) {
dev_err(&dev->udev->dev, "Error submitting the control "
"message: ret=%d", ret);
goto out;
}
return;
out:
kfree(req);
usb_free_urb(urb);
}
static int mcs7830_get_address(struct usbnet *dev)
{
int ret;
ret = mcs7830_get_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN,
dev->net->dev_addr);
if (ret < 0)
return ret;
return 0;
}
static int mcs7830_read_phy(struct usbnet *dev, u8 index)
{
int ret;
int i;
__le16 val;
u8 cmd[2] = {
HIF_REG_PHY_CMD1_READ | HIF_REG_PHY_CMD1_PHYADDR,
HIF_REG_PHY_CMD2_PEND_FLAG_BIT | index,
};
mutex_lock(&dev->phy_mutex);
/* write the MII command */
ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
if (ret < 0)
goto out;
/* wait for the data to become valid, should be within < 1ms */
for (i = 0; i < 10; i++) {
ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT))
break;
ret = -EIO;
msleep(1);
}
if (ret < 0)
goto out;
/* read actual register contents */
ret = mcs7830_get_reg(dev, HIF_REG_PHY_DATA, 2, &val);
if (ret < 0)
goto out;
ret = le16_to_cpu(val);
dev_dbg(&dev->udev->dev, "read PHY reg %02x: %04x (%d tries)\n",
index, val, i);
out:
mutex_unlock(&dev->phy_mutex);
return ret;
}
static int mcs7830_write_phy(struct usbnet *dev, u8 index, u16 val)
{
int ret;
int i;
__le16 le_val;
u8 cmd[2] = {
HIF_REG_PHY_CMD1_WRITE | HIF_REG_PHY_CMD1_PHYADDR,
HIF_REG_PHY_CMD2_PEND_FLAG_BIT | (index & 0x1F),
};
mutex_lock(&dev->phy_mutex);
/* write the new register contents */
le_val = cpu_to_le16(val);
ret = mcs7830_set_reg(dev, HIF_REG_PHY_DATA, 2, &le_val);
if (ret < 0)
goto out;
/* write the MII command */
ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
if (ret < 0)
goto out;
/* wait for the command to be accepted by the PHY */
for (i = 0; i < 10; i++) {
ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT))
break;
ret = -EIO;
msleep(1);
}
if (ret < 0)
goto out;
ret = 0;
dev_dbg(&dev->udev->dev, "write PHY reg %02x: %04x (%d tries)\n",
index, val, i);
out:
mutex_unlock(&dev->phy_mutex);
return ret;
}
/*
* This algorithm comes from the original mcs7830 version 1.4 driver,
* not sure if it is needed.
*/
static int mcs7830_set_autoneg(struct usbnet *dev, int ptrUserPhyMode)
{
int ret;
/* Enable all media types */
ret = mcs7830_write_phy(dev, MII_ADVERTISE, MCS7830_MII_ADVERTISE);
/* First reset BMCR */
if (!ret)
ret = mcs7830_write_phy(dev, MII_BMCR, 0x0000);
/* Enable Auto Neg */
if (!ret)
ret = mcs7830_write_phy(dev, MII_BMCR, BMCR_ANENABLE);
/* Restart Auto Neg (Keep the Enable Auto Neg Bit Set) */
if (!ret)
ret = mcs7830_write_phy(dev, MII_BMCR,
BMCR_ANENABLE | BMCR_ANRESTART );
return ret < 0 ? : 0;
}
/*
* if we can read register 22, the chip revision is C or higher
*/
static int mcs7830_get_rev(struct usbnet *dev)
{
u8 dummy[2];
int ret;
ret = mcs7830_get_reg(dev, HIF_REG_22, 2, dummy);
if (ret > 0)
return 2; /* Rev C or later */
return 1; /* earlier revision */
}
/*
* On rev. C we need to set the pause threshold
*/
static void mcs7830_rev_C_fixup(struct usbnet *dev)
{
u8 pause_threshold = HIF_REG_PAUSE_THRESHOLD_DEFAULT;
int retry;
for (retry = 0; retry < 2; retry++) {
if (mcs7830_get_rev(dev) == 2) {
dev_info(&dev->udev->dev, "applying rev.C fixup\n");
mcs7830_set_reg(dev, HIF_REG_PAUSE_THRESHOLD,
1, &pause_threshold);
}
msleep(1);
}
}
static int mcs7830_init_dev(struct usbnet *dev)
{
int ret;
int retry;
/* Read MAC address from EEPROM */
ret = -EINVAL;
for (retry = 0; retry < 5 && ret; retry++)
ret = mcs7830_get_address(dev);
if (ret) {
dev_warn(&dev->udev->dev, "Cannot read MAC address\n");
goto out;
}
/* Set up PHY */
ret = mcs7830_set_autoneg(dev, 0);
if (ret) {
dev_info(&dev->udev->dev, "Cannot set autoneg\n");
goto out;
}
mcs7830_rev_C_fixup(dev);
ret = 0;
out:
return ret;
}
static int mcs7830_mdio_read(struct net_device *netdev, int phy_id,
int location)
{
struct usbnet *dev = netdev->priv;
return mcs7830_read_phy(dev, location);
}
static void mcs7830_mdio_write(struct net_device *netdev, int phy_id,
int location, int val)
{
struct usbnet *dev = netdev->priv;
mcs7830_write_phy(dev, location, val);
}
static int mcs7830_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
{
struct usbnet *dev = netdev_priv(net);
return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
}
/* credits go to asix_set_multicast */
static void mcs7830_set_multicast(struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
struct mcs7830_data *data = (struct mcs7830_data *)&dev->data;
data->config = HIF_REG_CONFIG_TXENABLE;
/* this should not be needed, but it doesn't work otherwise */
data->config |= HIF_REG_CONFIG_ALLMULTICAST;
if (net->flags & IFF_PROMISC) {
data->config |= HIF_REG_CONFIG_PROMISCIOUS;
} else if (net->flags & IFF_ALLMULTI
|| net->mc_count > MCS7830_MAX_MCAST) {
data->config |= HIF_REG_CONFIG_ALLMULTICAST;
} else if (net->mc_count == 0) {
/* just broadcast and directed */
} else {
/* We use the 20 byte dev->data
* for our 8 byte filter buffer
* to avoid allocating memory that
* is tricky to free later */
struct dev_mc_list *mc_list = net->mc_list;
u32 crc_bits;
int i;
memset(data->multi_filter, 0, sizeof data->multi_filter);
/* Build the multicast hash filter. */
for (i = 0; i < net->mc_count; i++) {
crc_bits = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26;
data->multi_filter[crc_bits >> 3] |= 1 << (crc_bits & 7);
mc_list = mc_list->next;
}
mcs7830_set_reg_async(dev, HIF_REG_MULTICAST_HASH,
sizeof data->multi_filter,
data->multi_filter);
}
mcs7830_set_reg_async(dev, HIF_REG_CONFIG, 1, &data->config);
}
static int mcs7830_get_regs_len(struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
switch (mcs7830_get_rev(dev)) {
case 1:
return 21;
case 2:
return 32;
}
return 0;
}
static void mcs7830_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *drvinfo)
{
usbnet_get_drvinfo(net, drvinfo);
drvinfo->regdump_len = mcs7830_get_regs_len(net);
}
static void mcs7830_get_regs(struct net_device *net, struct ethtool_regs *regs, void *data)
{
struct usbnet *dev = netdev_priv(net);
regs->version = mcs7830_get_rev(dev);
mcs7830_get_reg(dev, 0, regs->len, data);
}
static struct ethtool_ops mcs7830_ethtool_ops = {
.get_drvinfo = mcs7830_get_drvinfo,
.get_regs_len = mcs7830_get_regs_len,
.get_regs = mcs7830_get_regs,
/* common usbnet calls */
.get_link = usbnet_get_link,
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
.get_settings = usbnet_get_settings,
.set_settings = usbnet_set_settings,
.nway_reset = usbnet_nway_reset,
};
static int mcs7830_bind(struct usbnet *dev, struct usb_interface *udev)
{
struct net_device *net = dev->net;
int ret;
ret = mcs7830_init_dev(dev);
if (ret)
goto out;
net->do_ioctl = mcs7830_ioctl;
net->ethtool_ops = &mcs7830_ethtool_ops;
net->set_multicast_list = mcs7830_set_multicast;
mcs7830_set_multicast(net);
/* reserve space for the status byte on rx */
dev->rx_urb_size = ETH_FRAME_LEN + 1;
dev->mii.mdio_read = mcs7830_mdio_read;
dev->mii.mdio_write = mcs7830_mdio_write;
dev->mii.dev = net;
dev->mii.phy_id_mask = 0x3f;
dev->mii.reg_num_mask = 0x1f;
dev->mii.phy_id = *((u8 *) net->dev_addr + 1);
ret = usbnet_get_endpoints(dev, udev);
out:
return ret;
}
/* The chip always appends a status bytes that we need to strip */
static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
u8 status;
if (skb->len == 0) {
dev_err(&dev->udev->dev, "unexpected empty rx frame\n");
return 0;
}
skb_trim(skb, skb->len - 1);
status = skb->data[skb->len];
if (status != 0x20)
dev_dbg(&dev->udev->dev, "rx fixup status %x\n", status);
return skb->len > 0;
}
static const struct driver_info moschip_info = {
.description = "MOSCHIP 7830 usb-NET adapter",
.bind = mcs7830_bind,
.rx_fixup = mcs7830_rx_fixup,
.flags = FLAG_ETHER,
.in = 1,
.out = 2,
};
static const struct usb_device_id products[] = {
{
USB_DEVICE(MCS7830_VENDOR_ID, MCS7830_PRODUCT_ID),
.driver_info = (unsigned long) &moschip_info,
},
{},
};
MODULE_DEVICE_TABLE(usb, products);
static struct usb_driver mcs7830_driver = {
.name = driver_name,
.id_table = products,
.probe = usbnet_probe,
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
};
static int __init mcs7830_init(void)
{
return usb_register(&mcs7830_driver);
}
module_init(mcs7830_init);
static void __exit mcs7830_exit(void)
{
usb_deregister(&mcs7830_driver);
}
module_exit(mcs7830_exit);
MODULE_DESCRIPTION("USB to network adapter MCS7830)");
MODULE_LICENSE("GPL");

615
drivers/net/usb/net1080.c 一般檔案
查看文件

@@ -0,0 +1,615 @@
/*
* Net1080 based USB host-to-host cables
* Copyright (C) 2000-2005 by David Brownell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// #define DEBUG // error path messages, extra info
// #define VERBOSE // more; success messages
#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/workqueue.h>
#include <linux/mii.h>
#include <linux/usb.h>
#include <asm/unaligned.h>
#include "usbnet.h"
/*
* Netchip 1080 driver ... http://www.netchip.com
* (Sept 2004: End-of-life announcement has been sent.)
* Used in (some) LapLink cables
*/
#define frame_errors data[1]
/*
* NetChip framing of ethernet packets, supporting additional error
* checks for links that may drop bulk packets from inside messages.
* Odd USB length == always short read for last usb packet.
* - nc_header
* - Ethernet header (14 bytes)
* - payload
* - (optional padding byte, if needed so length becomes odd)
* - nc_trailer
*
* This framing is to be avoided for non-NetChip devices.
*/
struct nc_header { // packed:
__le16 hdr_len; // sizeof nc_header (LE, all)
__le16 packet_len; // payload size (including ethhdr)
__le16 packet_id; // detects dropped packets
#define MIN_HEADER 6
// all else is optional, and must start with:
// __le16 vendorId; // from usb-if
// __le16 productId;
} __attribute__((__packed__));
#define PAD_BYTE ((unsigned char)0xAC)
struct nc_trailer {
__le16 packet_id;
} __attribute__((__packed__));
// packets may use FLAG_FRAMING_NC and optional pad
#define FRAMED_SIZE(mtu) (sizeof (struct nc_header) \
+ sizeof (struct ethhdr) \
+ (mtu) \
+ 1 \
+ sizeof (struct nc_trailer))
#define MIN_FRAMED FRAMED_SIZE(0)
/* packets _could_ be up to 64KB... */
#define NC_MAX_PACKET 32767
/*
* Zero means no timeout; else, how long a 64 byte bulk packet may be queued
* before the hardware drops it. If that's done, the driver will need to
* frame network packets to guard against the dropped USB packets. The win32
* driver sets this for both sides of the link.
*/
#define NC_READ_TTL_MS ((u8)255) // ms
/*
* We ignore most registers and EEPROM contents.
*/
#define REG_USBCTL ((u8)0x04)
#define REG_TTL ((u8)0x10)
#define REG_STATUS ((u8)0x11)
/*
* Vendor specific requests to read/write data
*/
#define REQUEST_REGISTER ((u8)0x10)
#define REQUEST_EEPROM ((u8)0x11)
static int
nc_vendor_read(struct usbnet *dev, u8 req, u8 regnum, u16 *retval_ptr)
{
int status = usb_control_msg(dev->udev,
usb_rcvctrlpipe(dev->udev, 0),
req,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, regnum,
retval_ptr, sizeof *retval_ptr,
USB_CTRL_GET_TIMEOUT);
if (status > 0)
status = 0;
if (!status)
le16_to_cpus(retval_ptr);
return status;
}
static inline int
nc_register_read(struct usbnet *dev, u8 regnum, u16 *retval_ptr)
{
return nc_vendor_read(dev, REQUEST_REGISTER, regnum, retval_ptr);
}
// no retval ... can become async, usable in_interrupt()
static void
nc_vendor_write(struct usbnet *dev, u8 req, u8 regnum, u16 value)
{
usb_control_msg(dev->udev,
usb_sndctrlpipe(dev->udev, 0),
req,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value, regnum,
NULL, 0, // data is in setup packet
USB_CTRL_SET_TIMEOUT);
}
static inline void
nc_register_write(struct usbnet *dev, u8 regnum, u16 value)
{
nc_vendor_write(dev, REQUEST_REGISTER, regnum, value);
}
#if 0
static void nc_dump_registers(struct usbnet *dev)
{
u8 reg;
u16 *vp = kmalloc(sizeof (u16));
if (!vp) {
dbg("no memory?");
return;
}
dbg("%s registers:", dev->net->name);
for (reg = 0; reg < 0x20; reg++) {
int retval;
// reading some registers is trouble
if (reg >= 0x08 && reg <= 0xf)
continue;
if (reg >= 0x12 && reg <= 0x1e)
continue;
retval = nc_register_read(dev, reg, vp);
if (retval < 0)
dbg("%s reg [0x%x] ==> error %d",
dev->net->name, reg, retval);
else
dbg("%s reg [0x%x] = 0x%x",
dev->net->name, reg, *vp);
}
kfree(vp);
}
#endif
/*-------------------------------------------------------------------------*/
/*
* Control register
*/
#define USBCTL_WRITABLE_MASK 0x1f0f
// bits 15-13 reserved, r/o
#define USBCTL_ENABLE_LANG (1 << 12)
#define USBCTL_ENABLE_MFGR (1 << 11)
#define USBCTL_ENABLE_PROD (1 << 10)
#define USBCTL_ENABLE_SERIAL (1 << 9)
#define USBCTL_ENABLE_DEFAULTS (1 << 8)
// bits 7-4 reserved, r/o
#define USBCTL_FLUSH_OTHER (1 << 3)
#define USBCTL_FLUSH_THIS (1 << 2)
#define USBCTL_DISCONN_OTHER (1 << 1)
#define USBCTL_DISCONN_THIS (1 << 0)
static inline void nc_dump_usbctl(struct usbnet *dev, u16 usbctl)
{
if (!netif_msg_link(dev))
return;
devdbg(dev, "net1080 %s-%s usbctl 0x%x:%s%s%s%s%s;"
" this%s%s;"
" other%s%s; r/o 0x%x",
dev->udev->bus->bus_name, dev->udev->devpath,
usbctl,
(usbctl & USBCTL_ENABLE_LANG) ? " lang" : "",
(usbctl & USBCTL_ENABLE_MFGR) ? " mfgr" : "",
(usbctl & USBCTL_ENABLE_PROD) ? " prod" : "",
(usbctl & USBCTL_ENABLE_SERIAL) ? " serial" : "",
(usbctl & USBCTL_ENABLE_DEFAULTS) ? " defaults" : "",
(usbctl & USBCTL_FLUSH_OTHER) ? " FLUSH" : "",
(usbctl & USBCTL_DISCONN_OTHER) ? " DIS" : "",
(usbctl & USBCTL_FLUSH_THIS) ? " FLUSH" : "",
(usbctl & USBCTL_DISCONN_THIS) ? " DIS" : "",
usbctl & ~USBCTL_WRITABLE_MASK
);
}
/*-------------------------------------------------------------------------*/
/*
* Status register
*/
#define STATUS_PORT_A (1 << 15)
#define STATUS_CONN_OTHER (1 << 14)
#define STATUS_SUSPEND_OTHER (1 << 13)
#define STATUS_MAILBOX_OTHER (1 << 12)
#define STATUS_PACKETS_OTHER(n) (((n) >> 8) & 0x03)
#define STATUS_CONN_THIS (1 << 6)
#define STATUS_SUSPEND_THIS (1 << 5)
#define STATUS_MAILBOX_THIS (1 << 4)
#define STATUS_PACKETS_THIS(n) (((n) >> 0) & 0x03)
#define STATUS_UNSPEC_MASK 0x0c8c
#define STATUS_NOISE_MASK ((u16)~(0x0303|STATUS_UNSPEC_MASK))
static inline void nc_dump_status(struct usbnet *dev, u16 status)
{
if (!netif_msg_link(dev))
return;
devdbg(dev, "net1080 %s-%s status 0x%x:"
" this (%c) PKT=%d%s%s%s;"
" other PKT=%d%s%s%s; unspec 0x%x",
dev->udev->bus->bus_name, dev->udev->devpath,
status,
// XXX the packet counts don't seem right
// (1 at reset, not 0); maybe UNSPEC too
(status & STATUS_PORT_A) ? 'A' : 'B',
STATUS_PACKETS_THIS(status),
(status & STATUS_CONN_THIS) ? " CON" : "",
(status & STATUS_SUSPEND_THIS) ? " SUS" : "",
(status & STATUS_MAILBOX_THIS) ? " MBOX" : "",
STATUS_PACKETS_OTHER(status),
(status & STATUS_CONN_OTHER) ? " CON" : "",
(status & STATUS_SUSPEND_OTHER) ? " SUS" : "",
(status & STATUS_MAILBOX_OTHER) ? " MBOX" : "",
status & STATUS_UNSPEC_MASK
);
}
/*-------------------------------------------------------------------------*/
/*
* TTL register
*/
#define TTL_THIS(ttl) (0x00ff & ttl)
#define TTL_OTHER(ttl) (0x00ff & (ttl >> 8))
#define MK_TTL(this,other) ((u16)(((other)<<8)|(0x00ff&(this))))
static inline void nc_dump_ttl(struct usbnet *dev, u16 ttl)
{
if (netif_msg_link(dev))
devdbg(dev, "net1080 %s-%s ttl 0x%x this = %d, other = %d",
dev->udev->bus->bus_name, dev->udev->devpath,
ttl, TTL_THIS(ttl), TTL_OTHER(ttl));
}
/*-------------------------------------------------------------------------*/
static int net1080_reset(struct usbnet *dev)
{
u16 usbctl, status, ttl;
u16 *vp = kmalloc(sizeof (u16), GFP_KERNEL);
int retval;
if (!vp)
return -ENOMEM;
// nc_dump_registers(dev);
if ((retval = nc_register_read(dev, REG_STATUS, vp)) < 0) {
dbg("can't read %s-%s status: %d",
dev->udev->bus->bus_name, dev->udev->devpath, retval);
goto done;
}
status = *vp;
nc_dump_status(dev, status);
if ((retval = nc_register_read(dev, REG_USBCTL, vp)) < 0) {
dbg("can't read USBCTL, %d", retval);
goto done;
}
usbctl = *vp;
nc_dump_usbctl(dev, usbctl);
nc_register_write(dev, REG_USBCTL,
USBCTL_FLUSH_THIS | USBCTL_FLUSH_OTHER);
if ((retval = nc_register_read(dev, REG_TTL, vp)) < 0) {
dbg("can't read TTL, %d", retval);
goto done;
}
ttl = *vp;
// nc_dump_ttl(dev, ttl);
nc_register_write(dev, REG_TTL,
MK_TTL(NC_READ_TTL_MS, TTL_OTHER(ttl)) );
dbg("%s: assigned TTL, %d ms", dev->net->name, NC_READ_TTL_MS);
if (netif_msg_link(dev))
devinfo(dev, "port %c, peer %sconnected",
(status & STATUS_PORT_A) ? 'A' : 'B',
(status & STATUS_CONN_OTHER) ? "" : "dis"
);
retval = 0;
done:
kfree(vp);
return retval;
}
static int net1080_check_connect(struct usbnet *dev)
{
int retval;
u16 status;
u16 *vp = kmalloc(sizeof (u16), GFP_KERNEL);
if (!vp)
return -ENOMEM;
retval = nc_register_read(dev, REG_STATUS, vp);
status = *vp;
kfree(vp);
if (retval != 0) {
dbg("%s net1080_check_conn read - %d", dev->net->name, retval);
return retval;
}
if ((status & STATUS_CONN_OTHER) != STATUS_CONN_OTHER)
return -ENOLINK;
return 0;
}
static void nc_flush_complete(struct urb *urb)
{
kfree(urb->context);
usb_free_urb(urb);
}
static void nc_ensure_sync(struct usbnet *dev)
{
dev->frame_errors++;
if (dev->frame_errors > 5) {
struct urb *urb;
struct usb_ctrlrequest *req;
int status;
/* Send a flush */
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb)
return;
req = kmalloc(sizeof *req, GFP_ATOMIC);
if (!req) {
usb_free_urb(urb);
return;
}
req->bRequestType = USB_DIR_OUT
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE;
req->bRequest = REQUEST_REGISTER;
req->wValue = cpu_to_le16(USBCTL_FLUSH_THIS
| USBCTL_FLUSH_OTHER);
req->wIndex = cpu_to_le16(REG_USBCTL);
req->wLength = cpu_to_le16(0);
/* queue an async control request, we don't need
* to do anything when it finishes except clean up.
*/
usb_fill_control_urb(urb, dev->udev,
usb_sndctrlpipe(dev->udev, 0),
(unsigned char *) req,
NULL, 0,
nc_flush_complete, req);
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
kfree(req);
usb_free_urb(urb);
return;
}
if (netif_msg_rx_err(dev))
devdbg(dev, "flush net1080; too many framing errors");
dev->frame_errors = 0;
}
}
static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
struct nc_header *header;
struct nc_trailer *trailer;
u16 hdr_len, packet_len;
if (!(skb->len & 0x01)) {
#ifdef DEBUG
struct net_device *net = dev->net;
dbg("rx framesize %d range %d..%d mtu %d", skb->len,
net->hard_header_len, dev->hard_mtu, net->mtu);
#endif
dev->stats.rx_frame_errors++;
nc_ensure_sync(dev);
return 0;
}
header = (struct nc_header *) skb->data;
hdr_len = le16_to_cpup(&header->hdr_len);
packet_len = le16_to_cpup(&header->packet_len);
if (FRAMED_SIZE(packet_len) > NC_MAX_PACKET) {
dev->stats.rx_frame_errors++;
dbg("packet too big, %d", packet_len);
nc_ensure_sync(dev);
return 0;
} else if (hdr_len < MIN_HEADER) {
dev->stats.rx_frame_errors++;
dbg("header too short, %d", hdr_len);
nc_ensure_sync(dev);
return 0;
} else if (hdr_len > MIN_HEADER) {
// out of band data for us?
dbg("header OOB, %d bytes", hdr_len - MIN_HEADER);
nc_ensure_sync(dev);
// switch (vendor/product ids) { ... }
}
skb_pull(skb, hdr_len);
trailer = (struct nc_trailer *)
(skb->data + skb->len - sizeof *trailer);
skb_trim(skb, skb->len - sizeof *trailer);
if ((packet_len & 0x01) == 0) {
if (skb->data [packet_len] != PAD_BYTE) {
dev->stats.rx_frame_errors++;
dbg("bad pad");
return 0;
}
skb_trim(skb, skb->len - 1);
}
if (skb->len != packet_len) {
dev->stats.rx_frame_errors++;
dbg("bad packet len %d (expected %d)",
skb->len, packet_len);
nc_ensure_sync(dev);
return 0;
}
if (header->packet_id != get_unaligned(&trailer->packet_id)) {
dev->stats.rx_fifo_errors++;
dbg("(2+ dropped) rx packet_id mismatch 0x%x 0x%x",
le16_to_cpu(header->packet_id),
le16_to_cpu(trailer->packet_id));
return 0;
}
#if 0
devdbg(dev, "frame <rx h %d p %d id %d", header->hdr_len,
header->packet_len, header->packet_id);
#endif
dev->frame_errors = 0;
return 1;
}
static struct sk_buff *
net1080_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
{
struct sk_buff *skb2;
struct nc_header *header = NULL;
struct nc_trailer *trailer = NULL;
int padlen = sizeof (struct nc_trailer);
int len = skb->len;
if (!((len + padlen + sizeof (struct nc_header)) & 0x01))
padlen++;
if (!skb_cloned(skb)) {
int headroom = skb_headroom(skb);
int tailroom = skb_tailroom(skb);
if (padlen <= tailroom &&
sizeof(struct nc_header) <= headroom)
/* There's enough head and tail room */
goto encapsulate;
if ((sizeof (struct nc_header) + padlen) <
(headroom + tailroom)) {
/* There's enough total room, so just readjust */
skb->data = memmove(skb->head
+ sizeof (struct nc_header),
skb->data, skb->len);
skb_set_tail_pointer(skb, len);
goto encapsulate;
}
}
/* Create a new skb to use with the correct size */
skb2 = skb_copy_expand(skb,
sizeof (struct nc_header),
padlen,
flags);
dev_kfree_skb_any(skb);
if (!skb2)
return skb2;
skb = skb2;
encapsulate:
/* header first */
header = (struct nc_header *) skb_push(skb, sizeof *header);
header->hdr_len = cpu_to_le16(sizeof (*header));
header->packet_len = cpu_to_le16(len);
header->packet_id = cpu_to_le16((u16)dev->xid++);
/* maybe pad; then trailer */
if (!((skb->len + sizeof *trailer) & 0x01))
*skb_put(skb, 1) = PAD_BYTE;
trailer = (struct nc_trailer *) skb_put(skb, sizeof *trailer);
put_unaligned(header->packet_id, &trailer->packet_id);
#if 0
devdbg(dev, "frame >tx h %d p %d id %d",
header->hdr_len, header->packet_len,
header->packet_id);
#endif
return skb;
}
static int net1080_bind(struct usbnet *dev, struct usb_interface *intf)
{
unsigned extra = sizeof (struct nc_header)
+ 1
+ sizeof (struct nc_trailer);
dev->net->hard_header_len += extra;
dev->rx_urb_size = dev->net->hard_header_len + dev->net->mtu;
dev->hard_mtu = NC_MAX_PACKET;
return usbnet_get_endpoints (dev, intf);
}
static const struct driver_info net1080_info = {
.description = "NetChip TurboCONNECT",
.flags = FLAG_FRAMING_NC,
.bind = net1080_bind,
.reset = net1080_reset,
.check_connect = net1080_check_connect,
.rx_fixup = net1080_rx_fixup,
.tx_fixup = net1080_tx_fixup,
};
static const struct usb_device_id products [] = {
{
USB_DEVICE(0x0525, 0x1080), // NetChip ref design
.driver_info = (unsigned long) &net1080_info,
}, {
USB_DEVICE(0x06D0, 0x0622), // Laplink Gold
.driver_info = (unsigned long) &net1080_info,
},
{ }, // END
};
MODULE_DEVICE_TABLE(usb, products);
static struct usb_driver net1080_driver = {
.name = "net1080",
.id_table = products,
.probe = usbnet_probe,
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
};
static int __init net1080_init(void)
{
return usb_register(&net1080_driver);
}
module_init(net1080_init);
static void __exit net1080_exit(void)
{
usb_deregister(&net1080_driver);
}
module_exit(net1080_exit);
MODULE_AUTHOR("David Brownell");
MODULE_DESCRIPTION("NetChip 1080 based USB Host-to-Host Links");
MODULE_LICENSE("GPL");

1504
drivers/net/usb/pegasus.c 一般檔案

檔案差異因為檔案過大而無法顯示 載入差異

307
drivers/net/usb/pegasus.h 一般檔案
查看文件

@@ -0,0 +1,307 @@
/*
* Copyright (c) 1999-2003 Petko Manolov - Petkan (petkan@users.sourceforge.net)
*
* 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.
*/
#ifndef PEGASUS_DEV
#define PEGASUS_II 0x80000000
#define HAS_HOME_PNA 0x40000000
#define PEGASUS_MTU 1536
#define RX_SKBS 4
#define EPROM_WRITE 0x01
#define EPROM_READ 0x02
#define EPROM_DONE 0x04
#define EPROM_WR_ENABLE 0x10
#define EPROM_LOAD 0x20
#define PHY_DONE 0x80
#define PHY_READ 0x40
#define PHY_WRITE 0x20
#define DEFAULT_GPIO_RESET 0x24
#define DEFAULT_GPIO_SET 0x26
#define PEGASUS_PRESENT 0x00000001
#define PEGASUS_TX_BUSY 0x00000004
#define PEGASUS_RX_BUSY 0x00000008
#define CTRL_URB_RUNNING 0x00000010
#define CTRL_URB_SLEEP 0x00000020
#define PEGASUS_UNPLUG 0x00000040
#define PEGASUS_RX_URB_FAIL 0x00000080
#define ETH_REGS_CHANGE 0x40000000
#define ETH_REGS_CHANGED 0x80000000
#define RX_MULTICAST 2
#define RX_PROMISCUOUS 4
#define REG_TIMEOUT (HZ)
#define PEGASUS_TX_TIMEOUT (HZ*10)
#define TX_UNDERRUN 0x80
#define EXCESSIVE_COL 0x40
#define LATE_COL 0x20
#define NO_CARRIER 0x10
#define LOSS_CARRIER 0x08
#define JABBER_TIMEOUT 0x04
#define LINK_STATUS 0x01
#define PEGASUS_REQT_READ 0xc0
#define PEGASUS_REQT_WRITE 0x40
#define PEGASUS_REQ_GET_REGS 0xf0
#define PEGASUS_REQ_SET_REGS 0xf1
#define PEGASUS_REQ_SET_REG PEGASUS_REQ_SET_REGS
enum pegasus_registers {
EthCtrl0 = 0,
EthCtrl1 = 1,
EthCtrl2 = 2,
EthID = 0x10,
Reg1d = 0x1d,
EpromOffset = 0x20,
EpromData = 0x21, /* 0x21 low, 0x22 high byte */
EpromCtrl = 0x23,
PhyAddr = 0x25,
PhyData = 0x26, /* 0x26 low, 0x27 high byte */
PhyCtrl = 0x28,
UsbStst = 0x2a,
EthTxStat0 = 0x2b,
EthTxStat1 = 0x2c,
EthRxStat = 0x2d,
WakeupControl = 0x78,
Reg7b = 0x7b,
Gpio0 = 0x7e,
Gpio1 = 0x7f,
Reg81 = 0x81,
};
typedef struct pegasus {
struct usb_device *usb;
struct usb_interface *intf;
struct net_device *net;
struct net_device_stats stats;
struct mii_if_info mii;
unsigned flags;
unsigned features;
u32 msg_enable;
u32 wolopts;
int dev_index;
int intr_interval;
struct tasklet_struct rx_tl;
struct delayed_work carrier_check;
struct urb *ctrl_urb, *rx_urb, *tx_urb, *intr_urb;
struct sk_buff *rx_pool[RX_SKBS];
struct sk_buff *rx_skb;
struct usb_ctrlrequest dr;
wait_queue_head_t ctrl_wait;
spinlock_t rx_pool_lock;
int chip;
unsigned char intr_buff[8];
__u8 tx_buff[PEGASUS_MTU];
__u8 eth_regs[4];
__u8 phy;
__u8 gpio_res;
} pegasus_t;
struct usb_eth_dev {
char *name;
__u16 vendor;
__u16 device;
__u32 private; /* LSB is gpio reset value */
};
#define VENDOR_3COM 0x0506
#define VENDOR_ABOCOM 0x07b8
#define VENDOR_ACCTON 0x083a
#define VENDOR_ADMTEK 0x07a6
#define VENDOR_AEILAB 0x3334
#define VENDOR_ALLIEDTEL 0x07c9
#define VENDOR_ATEN 0x0557
#define VENDOR_BELKIN 0x050d
#define VENDOR_BILLIONTON 0x08dd
#define VENDOR_COMPAQ 0x049f
#define VENDOR_COREGA 0x07aa
#define VENDOR_DLINK 0x2001
#define VENDOR_ELCON 0x0db7
#define VENDOR_ELECOM 0x056e
#define VENDOR_ELSA 0x05cc
#define VENDOR_GIGABYTE 0x1044
#define VENDOR_HAWKING 0x0e66
#define VENDOR_HP 0x03f0
#define VENDOR_IODATA 0x04bb
#define VENDOR_KINGSTON 0x0951
#define VENDOR_LANEED 0x056e
#define VENDOR_LINKSYS 0x066b
#define VENDOR_LINKSYS2 0x077b
#define VENDOR_MELCO 0x0411
#define VENDOR_MICROSOFT 0x045e
#define VENDOR_MOBILITY 0x1342
#define VENDOR_NETGEAR 0x0846
#define VENDOR_OCT 0x0b39
#define VENDOR_SMARTBRIDGES 0x08d1
#define VENDOR_SMC 0x0707
#define VENDOR_SOHOWARE 0x15e8
#define VENDOR_SIEMENS 0x067c
#else /* PEGASUS_DEV */
PEGASUS_DEV( "3Com USB Ethernet 3C460B", VENDOR_3COM, 0x4601,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "ATEN USB Ethernet UC-110T", VENDOR_ATEN, 0x2007,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x110c,
DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA )
PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4104,
DEFAULT_GPIO_RESET | HAS_HOME_PNA )
PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4004,
DEFAULT_GPIO_RESET | HAS_HOME_PNA )
PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4007,
DEFAULT_GPIO_RESET | HAS_HOME_PNA )
PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x4102,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x4002,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400b,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400c,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0xabc1,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x200c,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Philips USB 10/100 Ethernet", VENDOR_ACCTON, 0xb004,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
VENDOR_ADMTEK, 0x8511,
DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA )
PEGASUS_DEV( "ADMtek ADM8513 \"Pegasus II\" USB Ethernet",
VENDOR_ADMTEK, 0x8513,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "ADMtek ADM8515 \"Pegasus II\" USB-2.0 Ethernet",
VENDOR_ADMTEK, 0x8515,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (evaluation board)",
VENDOR_ADMTEK, 0x0986,
DEFAULT_GPIO_RESET | HAS_HOME_PNA )
PEGASUS_DEV( "AN986A USB MAC", VENDOR_ADMTEK, 1986,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "AEI USB Fast Ethernet Adapter", VENDOR_AEILAB, 0x1701,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Allied Telesyn Int. AT-USB100", VENDOR_ALLIEDTEL, 0xb100,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Belkin F5D5050 USB Ethernet", VENDOR_BELKIN, 0x0121,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Billionton USB-100", VENDOR_BILLIONTON, 0x0986,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "Billionton USBLP-100", VENDOR_BILLIONTON, 0x0987,
DEFAULT_GPIO_RESET | HAS_HOME_PNA )
PEGASUS_DEV( "iPAQ Networking 10/100 USB", VENDOR_COMPAQ, 0x8511,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Billionton USBEL-100", VENDOR_BILLIONTON, 0x0988,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "Billionton USBE-100", VENDOR_BILLIONTON, 0x8511,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Corega FEther USB-TX", VENDOR_COREGA, 0x0004,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "Corega FEther USB-TXS", VENDOR_COREGA, 0x000d,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4001,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4002,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4102,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x400b,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x200c,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "D-Link DSB-650TX(PNA)", VENDOR_DLINK, 0x4003,
DEFAULT_GPIO_RESET | HAS_HOME_PNA )
PEGASUS_DEV( "D-Link DSB-650", VENDOR_DLINK, 0xabc1,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "GOLDPFEIL USB Adapter", VENDOR_ELCON, 0x0002,
DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA )
PEGASUS_DEV( "ELECOM USB Ethernet LD-USB20", VENDOR_ELECOM, 0x4010,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "EasiDock Ethernet", VENDOR_MOBILITY, 0x0304,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "GIGABYTE GN-BR402W Wireless Router", VENDOR_GIGABYTE, 0x8002,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "Hawking UF100 10/100 Ethernet", VENDOR_HAWKING, 0x400c,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "HP hn210c Ethernet USB", VENDOR_HP, 0x811c,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "IO DATA USB ET/TX", VENDOR_IODATA, 0x0904,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "IO DATA USB ET/TX-S", VENDOR_IODATA, 0x0913,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Kingston KNU101TX Ethernet", VENDOR_KINGSTON, 0x000a,
DEFAULT_GPIO_RESET)
PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x4002,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "LANEED USB Ethernet LD-USBL/TX", VENDOR_LANEED, 0x4005,
DEFAULT_GPIO_RESET | PEGASUS_II)
PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x400b,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "LANEED USB Ethernet LD-USB/T", VENDOR_LANEED, 0xabc1,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x200c,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x2202,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2203,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2204,
DEFAULT_GPIO_RESET | HAS_HOME_PNA )
PEGASUS_DEV( "Linksys USB10T Ethernet Adapter", VENDOR_LINKSYS, 0x2206,
DEFAULT_GPIO_RESET | PEGASUS_II)
PEGASUS_DEV( "Linksys USBVPN1", VENDOR_LINKSYS2, 0x08b4,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "Linksys USB USB100TX", VENDOR_LINKSYS, 0x400b,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x200c,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0001,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0005,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "MELCO/BUFFALO LUA2-TX", VENDOR_MELCO, 0x0009,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Microsoft MN-110", VENDOR_MICROSOFT, 0x007a,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "NETGEAR FA101", VENDOR_NETGEAR, 0x1020,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "OCT Inc.", VENDOR_OCT, 0x0109,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "OCT USB TO Ethernet", VENDOR_OCT, 0x0901,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "smartNIC 2 PnP Adapter", VENDOR_SMARTBRIDGES, 0x0003,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "SMC 2206 USB Ethernet", VENDOR_SMC, 0x0201,
DEFAULT_GPIO_RESET | PEGASUS_II)
PEGASUS_DEV( "SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "SOHOware NUB110 Ethernet", VENDOR_SOHOWARE, 0x9110,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001,
DEFAULT_GPIO_RESET | PEGASUS_II )
#endif /* PEGASUS_DEV */

150
drivers/net/usb/plusb.c 一般檔案
查看文件

@@ -0,0 +1,150 @@
/*
* PL-2301/2302 USB host-to-host link cables
* Copyright (C) 2000-2005 by David Brownell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// #define DEBUG // error path messages, extra info
// #define VERBOSE // more; success messages
#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/workqueue.h>
#include <linux/mii.h>
#include <linux/usb.h>
#include "usbnet.h"
/*
* Prolific PL-2301/PL-2302 driver ... http://www.prolifictech.com
*
* The protocol and handshaking used here should be bug-compatible
* with the Linux 2.2 "plusb" driver, by Deti Fliegl.
*
* HEADS UP: this handshaking isn't all that robust. This driver
* gets confused easily if you unplug one end of the cable then
* try to connect it again; you'll need to restart both ends. The
* "naplink" software (used by some PlayStation/2 deveopers) does
* the handshaking much better! Also, sometimes this hardware
* seems to get wedged under load. Prolific docs are weak, and
* don't identify differences between PL2301 and PL2302, much less
* anything to explain the different PL2302 versions observed.
*/
/*
* Bits 0-4 can be used for software handshaking; they're set from
* one end, cleared from the other, "read" with the interrupt byte.
*/
#define PL_S_EN (1<<7) /* (feature only) suspend enable */
/* reserved bit -- rx ready (6) ? */
#define PL_TX_READY (1<<5) /* (interrupt only) transmit ready */
#define PL_RESET_OUT (1<<4) /* reset output pipe */
#define PL_RESET_IN (1<<3) /* reset input pipe */
#define PL_TX_C (1<<2) /* transmission complete */
#define PL_TX_REQ (1<<1) /* transmission received */
#define PL_PEER_E (1<<0) /* peer exists */
static inline int
pl_vendor_req(struct usbnet *dev, u8 req, u8 val, u8 index)
{
return usb_control_msg(dev->udev,
usb_rcvctrlpipe(dev->udev, 0),
req,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
val, index,
NULL, 0,
USB_CTRL_GET_TIMEOUT);
}
static inline int
pl_clear_QuickLink_features(struct usbnet *dev, int val)
{
return pl_vendor_req(dev, 1, (u8) val, 0);
}
static inline int
pl_set_QuickLink_features(struct usbnet *dev, int val)
{
return pl_vendor_req(dev, 3, (u8) val, 0);
}
static int pl_reset(struct usbnet *dev)
{
/* some units seem to need this reset, others reject it utterly.
* FIXME be more like "naplink" or windows drivers.
*/
(void) pl_set_QuickLink_features(dev,
PL_S_EN|PL_RESET_OUT|PL_RESET_IN|PL_PEER_E);
return 0;
}
static const struct driver_info prolific_info = {
.description = "Prolific PL-2301/PL-2302",
.flags = FLAG_NO_SETINT,
/* some PL-2302 versions seem to fail usb_set_interface() */
.reset = pl_reset,
};
/*-------------------------------------------------------------------------*/
/*
* Proilific's name won't normally be on the cables, and
* may not be on the device.
*/
static const struct usb_device_id products [] = {
{
USB_DEVICE(0x067b, 0x0000), // PL-2301
.driver_info = (unsigned long) &prolific_info,
}, {
USB_DEVICE(0x067b, 0x0001), // PL-2302
.driver_info = (unsigned long) &prolific_info,
},
{ }, // END
};
MODULE_DEVICE_TABLE(usb, products);
static struct usb_driver plusb_driver = {
.name = "plusb",
.id_table = products,
.probe = usbnet_probe,
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
};
static int __init plusb_init(void)
{
return usb_register(&plusb_driver);
}
module_init(plusb_init);
static void __exit plusb_exit(void)
{
usb_deregister(&plusb_driver);
}
module_exit(plusb_exit);
MODULE_AUTHOR("David Brownell");
MODULE_DESCRIPTION("Prolific PL-2301/2302 USB Host to Host Link Driver");
MODULE_LICENSE("GPL");

727
drivers/net/usb/rndis_host.c 一般檔案
查看文件

@@ -0,0 +1,727 @@
/*
* Host Side support for RNDIS Networking Links
* Copyright (C) 2005 by David Brownell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// #define DEBUG // error path messages, extra info
// #define VERBOSE // more; success messages
#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/workqueue.h>
#include <linux/mii.h>
#include <linux/usb.h>
#include <linux/usb/cdc.h>
#include "usbnet.h"
/*
* RNDIS is NDIS remoted over USB. It's a MSFT variant of CDC ACM ... of
* course ACM was intended for modems, not Ethernet links! USB's standard
* for Ethernet links is "CDC Ethernet", which is significantly simpler.
*
* NOTE that Microsoft's "RNDIS 1.0" specification is incomplete. Issues
* include:
* - Power management in particular relies on information that's scattered
* through other documentation, and which is incomplete or incorrect even
* there.
* - There are various undocumented protocol requirements, such as the
* need to send unused garbage in control-OUT messages.
* - In some cases, MS-Windows will emit undocumented requests; this
* matters more to peripheral implementations than host ones.
*
* Moreover there's a no-open-specs variant of RNDIS called "ActiveSync".
*
* For these reasons and others, ** USE OF RNDIS IS STRONGLY DISCOURAGED ** in
* favor of such non-proprietary alternatives as CDC Ethernet or the newer (and
* currently rare) "Ethernet Emulation Model" (EEM).
*/
/*
* CONTROL uses CDC "encapsulated commands" with funky notifications.
* - control-out: SEND_ENCAPSULATED
* - interrupt-in: RESPONSE_AVAILABLE
* - control-in: GET_ENCAPSULATED
*
* We'll try to ignore the RESPONSE_AVAILABLE notifications.
*
* REVISIT some RNDIS implementations seem to have curious issues still
* to be resolved.
*/
struct rndis_msg_hdr {
__le32 msg_type; /* RNDIS_MSG_* */
__le32 msg_len;
// followed by data that varies between messages
__le32 request_id;
__le32 status;
// ... and more
} __attribute__ ((packed));
/* MS-Windows uses this strange size, but RNDIS spec says 1024 minimum */
#define CONTROL_BUFFER_SIZE 1025
/* RNDIS defines an (absurdly huge) 10 second control timeout,
* but ActiveSync seems to use a more usual 5 second timeout
* (which matches the USB 2.0 spec).
*/
#define RNDIS_CONTROL_TIMEOUT_MS (5 * 1000)
#define ccpu2 __constant_cpu_to_le32
#define RNDIS_MSG_COMPLETION ccpu2(0x80000000)
/* codes for "msg_type" field of rndis messages;
* only the data channel uses packet messages (maybe batched);
* everything else goes on the control channel.
*/
#define RNDIS_MSG_PACKET ccpu2(0x00000001) /* 1-N packets */
#define RNDIS_MSG_INIT ccpu2(0x00000002)
#define RNDIS_MSG_INIT_C (RNDIS_MSG_INIT|RNDIS_MSG_COMPLETION)
#define RNDIS_MSG_HALT ccpu2(0x00000003)
#define RNDIS_MSG_QUERY ccpu2(0x00000004)
#define RNDIS_MSG_QUERY_C (RNDIS_MSG_QUERY|RNDIS_MSG_COMPLETION)
#define RNDIS_MSG_SET ccpu2(0x00000005)
#define RNDIS_MSG_SET_C (RNDIS_MSG_SET|RNDIS_MSG_COMPLETION)
#define RNDIS_MSG_RESET ccpu2(0x00000006)
#define RNDIS_MSG_RESET_C (RNDIS_MSG_RESET|RNDIS_MSG_COMPLETION)
#define RNDIS_MSG_INDICATE ccpu2(0x00000007)
#define RNDIS_MSG_KEEPALIVE ccpu2(0x00000008)
#define RNDIS_MSG_KEEPALIVE_C (RNDIS_MSG_KEEPALIVE|RNDIS_MSG_COMPLETION)
/* codes for "status" field of completion messages */
#define RNDIS_STATUS_SUCCESS ccpu2(0x00000000)
#define RNDIS_STATUS_FAILURE ccpu2(0xc0000001)
#define RNDIS_STATUS_INVALID_DATA ccpu2(0xc0010015)
#define RNDIS_STATUS_NOT_SUPPORTED ccpu2(0xc00000bb)
#define RNDIS_STATUS_MEDIA_CONNECT ccpu2(0x4001000b)
#define RNDIS_STATUS_MEDIA_DISCONNECT ccpu2(0x4001000c)
struct rndis_data_hdr {
__le32 msg_type; /* RNDIS_MSG_PACKET */
__le32 msg_len; // rndis_data_hdr + data_len + pad
__le32 data_offset; // 36 -- right after header
__le32 data_len; // ... real packet size
__le32 oob_data_offset; // zero
__le32 oob_data_len; // zero
__le32 num_oob; // zero
__le32 packet_data_offset; // zero
__le32 packet_data_len; // zero
__le32 vc_handle; // zero
__le32 reserved; // zero
} __attribute__ ((packed));
struct rndis_init { /* OUT */
// header and:
__le32 msg_type; /* RNDIS_MSG_INIT */
__le32 msg_len; // 24
__le32 request_id;
__le32 major_version; // of rndis (1.0)
__le32 minor_version;
__le32 max_transfer_size;
} __attribute__ ((packed));
struct rndis_init_c { /* IN */
// header and:
__le32 msg_type; /* RNDIS_MSG_INIT_C */
__le32 msg_len;
__le32 request_id;
__le32 status;
__le32 major_version; // of rndis (1.0)
__le32 minor_version;
__le32 device_flags;
__le32 medium; // zero == 802.3
__le32 max_packets_per_message;
__le32 max_transfer_size;
__le32 packet_alignment; // max 7; (1<<n) bytes
__le32 af_list_offset; // zero
__le32 af_list_size; // zero
} __attribute__ ((packed));
struct rndis_halt { /* OUT (no reply) */
// header and:
__le32 msg_type; /* RNDIS_MSG_HALT */
__le32 msg_len;
__le32 request_id;
} __attribute__ ((packed));
struct rndis_query { /* OUT */
// header and:
__le32 msg_type; /* RNDIS_MSG_QUERY */
__le32 msg_len;
__le32 request_id;
__le32 oid;
__le32 len;
__le32 offset;
/*?*/ __le32 handle; // zero
} __attribute__ ((packed));
struct rndis_query_c { /* IN */
// header and:
__le32 msg_type; /* RNDIS_MSG_QUERY_C */
__le32 msg_len;
__le32 request_id;
__le32 status;
__le32 len;
__le32 offset;
} __attribute__ ((packed));
struct rndis_set { /* OUT */
// header and:
__le32 msg_type; /* RNDIS_MSG_SET */
__le32 msg_len;
__le32 request_id;
__le32 oid;
__le32 len;
__le32 offset;
/*?*/ __le32 handle; // zero
} __attribute__ ((packed));
struct rndis_set_c { /* IN */
// header and:
__le32 msg_type; /* RNDIS_MSG_SET_C */
__le32 msg_len;
__le32 request_id;
__le32 status;
} __attribute__ ((packed));
struct rndis_reset { /* IN */
// header and:
__le32 msg_type; /* RNDIS_MSG_RESET */
__le32 msg_len;
__le32 reserved;
} __attribute__ ((packed));
struct rndis_reset_c { /* OUT */
// header and:
__le32 msg_type; /* RNDIS_MSG_RESET_C */
__le32 msg_len;
__le32 status;
__le32 addressing_lost;
} __attribute__ ((packed));
struct rndis_indicate { /* IN (unrequested) */
// header and:
__le32 msg_type; /* RNDIS_MSG_INDICATE */
__le32 msg_len;
__le32 status;
__le32 length;
__le32 offset;
/**/ __le32 diag_status;
__le32 error_offset;
/**/ __le32 message;
} __attribute__ ((packed));
struct rndis_keepalive { /* OUT (optionally IN) */
// header and:
__le32 msg_type; /* RNDIS_MSG_KEEPALIVE */
__le32 msg_len;
__le32 request_id;
} __attribute__ ((packed));
struct rndis_keepalive_c { /* IN (optionally OUT) */
// header and:
__le32 msg_type; /* RNDIS_MSG_KEEPALIVE_C */
__le32 msg_len;
__le32 request_id;
__le32 status;
} __attribute__ ((packed));
/* NOTE: about 30 OIDs are "mandatory" for peripherals to support ... and
* there are gobs more that may optionally be supported. We'll avoid as much
* of that mess as possible.
*/
#define OID_802_3_PERMANENT_ADDRESS ccpu2(0x01010101)
#define OID_GEN_MAXIMUM_FRAME_SIZE ccpu2(0x00010106)
#define OID_GEN_CURRENT_PACKET_FILTER ccpu2(0x0001010e)
/*
* RNDIS notifications from device: command completion; "reverse"
* keepalives; etc
*/
static void rndis_status(struct usbnet *dev, struct urb *urb)
{
devdbg(dev, "rndis status urb, len %d stat %d",
urb->actual_length, urb->status);
// FIXME for keepalives, respond immediately (asynchronously)
// if not an RNDIS status, do like cdc_status(dev,urb) does
}
/*
* RPC done RNDIS-style. Caller guarantees:
* - message is properly byteswapped
* - there's no other request pending
* - buf can hold up to 1KB response (required by RNDIS spec)
* On return, the first few entries are already byteswapped.
*
* Call context is likely probe(), before interface name is known,
* which is why we won't try to use it in the diagnostics.
*/
static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
{
struct cdc_state *info = (void *) &dev->data;
int master_ifnum;
int retval;
unsigned count;
__le32 rsp;
u32 xid = 0, msg_len, request_id;
/* REVISIT when this gets called from contexts other than probe() or
* disconnect(): either serialize, or dispatch responses on xid
*/
/* Issue the request; xid is unique, don't bother byteswapping it */
if (likely(buf->msg_type != RNDIS_MSG_HALT
&& buf->msg_type != RNDIS_MSG_RESET)) {
xid = dev->xid++;
if (!xid)
xid = dev->xid++;
buf->request_id = (__force __le32) xid;
}
master_ifnum = info->control->cur_altsetting->desc.bInterfaceNumber;
retval = usb_control_msg(dev->udev,
usb_sndctrlpipe(dev->udev, 0),
USB_CDC_SEND_ENCAPSULATED_COMMAND,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, master_ifnum,
buf, le32_to_cpu(buf->msg_len),
RNDIS_CONTROL_TIMEOUT_MS);
if (unlikely(retval < 0 || xid == 0))
return retval;
// FIXME Seems like some devices discard responses when
// we time out and cancel our "get response" requests...
// so, this is fragile. Probably need to poll for status.
/* ignore status endpoint, just poll the control channel;
* the request probably completed immediately
*/
rsp = buf->msg_type | RNDIS_MSG_COMPLETION;
for (count = 0; count < 10; count++) {
memset(buf, 0, CONTROL_BUFFER_SIZE);
retval = usb_control_msg(dev->udev,
usb_rcvctrlpipe(dev->udev, 0),
USB_CDC_GET_ENCAPSULATED_RESPONSE,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, master_ifnum,
buf, CONTROL_BUFFER_SIZE,
RNDIS_CONTROL_TIMEOUT_MS);
if (likely(retval >= 8)) {
msg_len = le32_to_cpu(buf->msg_len);
request_id = (__force u32) buf->request_id;
if (likely(buf->msg_type == rsp)) {
if (likely(request_id == xid)) {
if (unlikely(rsp == RNDIS_MSG_RESET_C))
return 0;
if (likely(RNDIS_STATUS_SUCCESS
== buf->status))
return 0;
dev_dbg(&info->control->dev,
"rndis reply status %08x\n",
le32_to_cpu(buf->status));
return -EL3RST;
}
dev_dbg(&info->control->dev,
"rndis reply id %d expected %d\n",
request_id, xid);
/* then likely retry */
} else switch (buf->msg_type) {
case RNDIS_MSG_INDICATE: { /* fault */
// struct rndis_indicate *msg = (void *)buf;
dev_info(&info->control->dev,
"rndis fault indication\n");
}
break;
case RNDIS_MSG_KEEPALIVE: { /* ping */
struct rndis_keepalive_c *msg = (void *)buf;
msg->msg_type = RNDIS_MSG_KEEPALIVE_C;
msg->msg_len = ccpu2(sizeof *msg);
msg->status = RNDIS_STATUS_SUCCESS;
retval = usb_control_msg(dev->udev,
usb_sndctrlpipe(dev->udev, 0),
USB_CDC_SEND_ENCAPSULATED_COMMAND,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, master_ifnum,
msg, sizeof *msg,
RNDIS_CONTROL_TIMEOUT_MS);
if (unlikely(retval < 0))
dev_dbg(&info->control->dev,
"rndis keepalive err %d\n",
retval);
}
break;
default:
dev_dbg(&info->control->dev,
"unexpected rndis msg %08x len %d\n",
le32_to_cpu(buf->msg_type), msg_len);
}
} else {
/* device probably issued a protocol stall; ignore */
dev_dbg(&info->control->dev,
"rndis response error, code %d\n", retval);
}
msleep(2);
}
dev_dbg(&info->control->dev, "rndis response timeout\n");
return -ETIMEDOUT;
}
/*
* rndis_query:
*
* Performs a query for @oid along with 0 or more bytes of payload as
* specified by @in_len. If @reply_len is not set to -1 then the reply
* length is checked against this value, resulting in an error if it
* doesn't match.
*
* NOTE: Adding a payload exactly or greater than the size of the expected
* response payload is an evident requirement MSFT added for ActiveSync.
*
* The only exception is for OIDs that return a variably sized response,
* in which case no payload should be added. This undocumented (and
* nonsensical!) issue was found by sniffing protocol requests from the
* ActiveSync 4.1 Windows driver.
*/
static int rndis_query(struct usbnet *dev, struct usb_interface *intf,
void *buf, u32 oid, u32 in_len,
void **reply, int *reply_len)
{
int retval;
union {
void *buf;
struct rndis_msg_hdr *header;
struct rndis_query *get;
struct rndis_query_c *get_c;
} u;
u32 off, len;
u.buf = buf;
memset(u.get, 0, sizeof *u.get + in_len);
u.get->msg_type = RNDIS_MSG_QUERY;
u.get->msg_len = cpu_to_le32(sizeof *u.get + in_len);
u.get->oid = oid;
u.get->len = cpu_to_le32(in_len);
u.get->offset = ccpu2(20);
retval = rndis_command(dev, u.header);
if (unlikely(retval < 0)) {
dev_err(&intf->dev, "RNDIS_MSG_QUERY(0x%08x) failed, %d\n",
oid, retval);
return retval;
}
off = le32_to_cpu(u.get_c->offset);
len = le32_to_cpu(u.get_c->len);
if (unlikely((8 + off + len) > CONTROL_BUFFER_SIZE))
goto response_error;
if (*reply_len != -1 && len != *reply_len)
goto response_error;
*reply = (unsigned char *) &u.get_c->request_id + off;
*reply_len = len;
return retval;
response_error:
dev_err(&intf->dev, "RNDIS_MSG_QUERY(0x%08x) "
"invalid response - off %d len %d\n",
oid, off, len);
return -EDOM;
}
static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
{
int retval;
struct net_device *net = dev->net;
struct cdc_state *info = (void *) &dev->data;
union {
void *buf;
struct rndis_msg_hdr *header;
struct rndis_init *init;
struct rndis_init_c *init_c;
struct rndis_query *get;
struct rndis_query_c *get_c;
struct rndis_set *set;
struct rndis_set_c *set_c;
} u;
u32 tmp;
int reply_len;
unsigned char *bp;
/* we can't rely on i/o from stack working, or stack allocation */
u.buf = kmalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
if (!u.buf)
return -ENOMEM;
retval = usbnet_generic_cdc_bind(dev, intf);
if (retval < 0)
goto fail;
u.init->msg_type = RNDIS_MSG_INIT;
u.init->msg_len = ccpu2(sizeof *u.init);
u.init->major_version = ccpu2(1);
u.init->minor_version = ccpu2(0);
/* max transfer (in spec) is 0x4000 at full speed, but for
* TX we'll stick to one Ethernet packet plus RNDIS framing.
* For RX we handle drivers that zero-pad to end-of-packet.
* Don't let userspace change these settings.
*
* NOTE: there still seems to be wierdness here, as if we need
* to do some more things to make sure WinCE targets accept this.
* They default to jumbograms of 8KB or 16KB, which is absurd
* for such low data rates and which is also more than Linux
* can usually expect to allocate for SKB data...
*/
net->hard_header_len += sizeof (struct rndis_data_hdr);
dev->hard_mtu = net->mtu + net->hard_header_len;
dev->rx_urb_size = dev->hard_mtu + (dev->maxpacket + 1);
dev->rx_urb_size &= ~(dev->maxpacket - 1);
u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size);
net->change_mtu = NULL;
retval = rndis_command(dev, u.header);
if (unlikely(retval < 0)) {
/* it might not even be an RNDIS device!! */
dev_err(&intf->dev, "RNDIS init failed, %d\n", retval);
goto fail_and_release;
}
tmp = le32_to_cpu(u.init_c->max_transfer_size);
if (tmp < dev->hard_mtu) {
dev_err(&intf->dev,
"dev can't take %u byte packets (max %u)\n",
dev->hard_mtu, tmp);
goto fail_and_release;
}
/* REVISIT: peripheral "alignment" request is ignored ... */
dev_dbg(&intf->dev,
"hard mtu %u (%u from dev), rx buflen %Zu, align %d\n",
dev->hard_mtu, tmp, dev->rx_urb_size,
1 << le32_to_cpu(u.init_c->packet_alignment));
/* Get designated host ethernet address */
reply_len = ETH_ALEN;
retval = rndis_query(dev, intf, u.buf, OID_802_3_PERMANENT_ADDRESS,
48, (void **) &bp, &reply_len);
if (unlikely(retval< 0)) {
dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval);
goto fail_and_release;
}
memcpy(net->dev_addr, bp, ETH_ALEN);
/* set a nonzero filter to enable data transfers */
memset(u.set, 0, sizeof *u.set);
u.set->msg_type = RNDIS_MSG_SET;
u.set->msg_len = ccpu2(4 + sizeof *u.set);
u.set->oid = OID_GEN_CURRENT_PACKET_FILTER;
u.set->len = ccpu2(4);
u.set->offset = ccpu2((sizeof *u.set) - 8);
*(__le32 *)(u.buf + sizeof *u.set) = ccpu2(DEFAULT_FILTER);
retval = rndis_command(dev, u.header);
if (unlikely(retval < 0)) {
dev_err(&intf->dev, "rndis set packet filter, %d\n", retval);
goto fail_and_release;
}
retval = 0;
kfree(u.buf);
return retval;
fail_and_release:
usb_set_intfdata(info->data, NULL);
usb_driver_release_interface(driver_of(intf), info->data);
info->data = NULL;
fail:
kfree(u.buf);
return retval;
}
static void rndis_unbind(struct usbnet *dev, struct usb_interface *intf)
{
struct rndis_halt *halt;
/* try to clear any rndis state/activity (no i/o from stack!) */
halt = kzalloc(sizeof *halt, GFP_KERNEL);
if (halt) {
halt->msg_type = RNDIS_MSG_HALT;
halt->msg_len = ccpu2(sizeof *halt);
(void) rndis_command(dev, (void *)halt);
kfree(halt);
}
return usbnet_cdc_unbind(dev, intf);
}
/*
* DATA -- host must not write zlps
*/
static int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
/* peripheral may have batched packets to us... */
while (likely(skb->len)) {
struct rndis_data_hdr *hdr = (void *)skb->data;
struct sk_buff *skb2;
u32 msg_len, data_offset, data_len;
msg_len = le32_to_cpu(hdr->msg_len);
data_offset = le32_to_cpu(hdr->data_offset);
data_len = le32_to_cpu(hdr->data_len);
/* don't choke if we see oob, per-packet data, etc */
if (unlikely(hdr->msg_type != RNDIS_MSG_PACKET
|| skb->len < msg_len
|| (data_offset + data_len + 8) > msg_len)) {
dev->stats.rx_frame_errors++;
devdbg(dev, "bad rndis message %d/%d/%d/%d, len %d",
le32_to_cpu(hdr->msg_type),
msg_len, data_offset, data_len, skb->len);
return 0;
}
skb_pull(skb, 8 + data_offset);
/* at most one packet left? */
if (likely((data_len - skb->len) <= sizeof *hdr)) {
skb_trim(skb, data_len);
break;
}
/* try to return all the packets in the batch */
skb2 = skb_clone(skb, GFP_ATOMIC);
if (unlikely(!skb2))
break;
skb_pull(skb, msg_len - sizeof *hdr);
skb_trim(skb2, data_len);
usbnet_skb_return(dev, skb2);
}
/* caller will usbnet_skb_return the remaining packet */
return 1;
}
static struct sk_buff *
rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
{
struct rndis_data_hdr *hdr;
struct sk_buff *skb2;
unsigned len = skb->len;
if (likely(!skb_cloned(skb))) {
int room = skb_headroom(skb);
/* enough head room as-is? */
if (unlikely((sizeof *hdr) <= room))
goto fill;
/* enough room, but needs to be readjusted? */
room += skb_tailroom(skb);
if (likely((sizeof *hdr) <= room)) {
skb->data = memmove(skb->head + sizeof *hdr,
skb->data, len);
skb_set_tail_pointer(skb, len);
goto fill;
}
}
/* create a new skb, with the correct size (and tailpad) */
skb2 = skb_copy_expand(skb, sizeof *hdr, 1, flags);
dev_kfree_skb_any(skb);
if (unlikely(!skb2))
return skb2;
skb = skb2;
/* fill out the RNDIS header. we won't bother trying to batch
* packets; Linux minimizes wasted bandwidth through tx queues.
*/
fill:
hdr = (void *) __skb_push(skb, sizeof *hdr);
memset(hdr, 0, sizeof *hdr);
hdr->msg_type = RNDIS_MSG_PACKET;
hdr->msg_len = cpu_to_le32(skb->len);
hdr->data_offset = ccpu2(sizeof(*hdr) - 8);
hdr->data_len = cpu_to_le32(len);
/* FIXME make the last packet always be short ... */
return skb;
}
static const struct driver_info rndis_info = {
.description = "RNDIS device",
.flags = FLAG_ETHER | FLAG_FRAMING_RN | FLAG_NO_SETINT,
.bind = rndis_bind,
.unbind = rndis_unbind,
.status = rndis_status,
.rx_fixup = rndis_rx_fixup,
.tx_fixup = rndis_tx_fixup,
};
#undef ccpu2
/*-------------------------------------------------------------------------*/
static const struct usb_device_id products [] = {
{
/* RNDIS is MSFT's un-official variant of CDC ACM */
USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
.driver_info = (unsigned long) &rndis_info,
}, {
/* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */
USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1),
.driver_info = (unsigned long) &rndis_info,
},
{ }, // END
};
MODULE_DEVICE_TABLE(usb, products);
static struct usb_driver rndis_driver = {
.name = "rndis_host",
.id_table = products,
.probe = usbnet_probe,
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
};
static int __init rndis_init(void)
{
return usb_register(&rndis_driver);
}
module_init(rndis_init);
static void __exit rndis_exit(void)
{
usb_deregister(&rndis_driver);
}
module_exit(rndis_exit);
MODULE_AUTHOR("David Brownell");
MODULE_DESCRIPTION("USB Host side RNDIS driver");
MODULE_LICENSE("GPL");

1004
drivers/net/usb/rtl8150.c 一般檔案

檔案差異因為檔案過大而無法顯示 載入差異

1304
drivers/net/usb/usbnet.c 一般檔案

檔案差異因為檔案過大而無法顯示 載入差異

200
drivers/net/usb/usbnet.h 一般檔案
查看文件

@@ -0,0 +1,200 @@
/*
* USB Networking Link Interface
*
* Copyright (C) 2000-2005 by David Brownell <dbrownell@users.sourceforge.net>
* Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __USBNET_H
#define __USBNET_H
/* interface from usbnet core to each USB networking link we handle */
struct usbnet {
/* housekeeping */
struct usb_device *udev;
struct driver_info *driver_info;
const char *driver_name;
wait_queue_head_t *wait;
struct mutex phy_mutex;
/* i/o info: pipes etc */
unsigned in, out;
struct usb_host_endpoint *status;
unsigned maxpacket;
struct timer_list delay;
/* protocol/interface state */
struct net_device *net;
struct net_device_stats stats;
int msg_enable;
unsigned long data [5];
u32 xid;
u32 hard_mtu; /* count any extra framing */
size_t rx_urb_size; /* size for rx urbs */
struct mii_if_info mii;
/* various kinds of pending driver work */
struct sk_buff_head rxq;
struct sk_buff_head txq;
struct sk_buff_head done;
struct urb *interrupt;
struct tasklet_struct bh;
struct work_struct kevent;
unsigned long flags;
# define EVENT_TX_HALT 0
# define EVENT_RX_HALT 1
# define EVENT_RX_MEMORY 2
# define EVENT_STS_SPLIT 3
# define EVENT_LINK_RESET 4
};
static inline struct usb_driver *driver_of(struct usb_interface *intf)
{
return to_usb_driver(intf->dev.driver);
}
/* interface from the device/framing level "minidriver" to core */
struct driver_info {
char *description;
int flags;
/* framing is CDC Ethernet, not writing ZLPs (hw issues), or optionally: */
#define FLAG_FRAMING_NC 0x0001 /* guard against device dropouts */
#define FLAG_FRAMING_GL 0x0002 /* genelink batches packets */
#define FLAG_FRAMING_Z 0x0004 /* zaurus adds a trailer */
#define FLAG_FRAMING_RN 0x0008 /* RNDIS batches, plus huge header */
#define FLAG_NO_SETINT 0x0010 /* device can't set_interface() */
#define FLAG_ETHER 0x0020 /* maybe use "eth%d" names */
#define FLAG_FRAMING_AX 0x0040 /* AX88772/178 packets */
/* init device ... can sleep, or cause probe() failure */
int (*bind)(struct usbnet *, struct usb_interface *);
/* cleanup device ... can sleep, but can't fail */
void (*unbind)(struct usbnet *, struct usb_interface *);
/* reset device ... can sleep */
int (*reset)(struct usbnet *);
/* see if peer is connected ... can sleep */
int (*check_connect)(struct usbnet *);
/* for status polling */
void (*status)(struct usbnet *, struct urb *);
/* link reset handling, called from defer_kevent */
int (*link_reset)(struct usbnet *);
/* fixup rx packet (strip framing) */
int (*rx_fixup)(struct usbnet *dev, struct sk_buff *skb);
/* fixup tx packet (add framing) */
struct sk_buff *(*tx_fixup)(struct usbnet *dev,
struct sk_buff *skb, gfp_t flags);
/* for new devices, use the descriptor-reading code instead */
int in; /* rx endpoint */
int out; /* tx endpoint */
unsigned long data; /* Misc driver specific data */
};
/* Minidrivers are just drivers using the "usbnet" core as a powerful
* network-specific subroutine library ... that happens to do pretty
* much everything except custom framing and chip-specific stuff.
*/
extern int usbnet_probe(struct usb_interface *, const struct usb_device_id *);
extern int usbnet_suspend (struct usb_interface *, pm_message_t );
extern int usbnet_resume (struct usb_interface *);
extern void usbnet_disconnect(struct usb_interface *);
/* Drivers that reuse some of the standard USB CDC infrastructure
* (notably, using multiple interfaces according to the CDC
* union descriptor) get some helper code.
*/
struct cdc_state {
struct usb_cdc_header_desc *header;
struct usb_cdc_union_desc *u;
struct usb_cdc_ether_desc *ether;
struct usb_interface *control;
struct usb_interface *data;
};
extern int usbnet_generic_cdc_bind (struct usbnet *, struct usb_interface *);
extern void usbnet_cdc_unbind (struct usbnet *, struct usb_interface *);
/* CDC and RNDIS support the same host-chosen packet filters for IN transfers */
#define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \
|USB_CDC_PACKET_TYPE_ALL_MULTICAST \
|USB_CDC_PACKET_TYPE_PROMISCUOUS \
|USB_CDC_PACKET_TYPE_DIRECTED)
/* we record the state for each of our queued skbs */
enum skb_state {
illegal = 0,
tx_start, tx_done,
rx_start, rx_done, rx_cleanup
};
struct skb_data { /* skb->cb is one of these */
struct urb *urb;
struct usbnet *dev;
enum skb_state state;
size_t length;
};
extern int usbnet_get_endpoints(struct usbnet *, struct usb_interface *);
extern void usbnet_defer_kevent (struct usbnet *, int);
extern void usbnet_skb_return (struct usbnet *, struct sk_buff *);
extern void usbnet_unlink_rx_urbs(struct usbnet *);
extern int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd);
extern int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd);
extern u32 usbnet_get_link (struct net_device *net);
extern u32 usbnet_get_msglevel (struct net_device *);
extern void usbnet_set_msglevel (struct net_device *, u32);
extern void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *);
extern int usbnet_nway_reset(struct net_device *net);
/* messaging support includes the interface name, so it must not be
* used before it has one ... notably, in minidriver bind() calls.
*/
#ifdef DEBUG
#define devdbg(usbnet, fmt, arg...) \
printk(KERN_DEBUG "%s: " fmt "\n" , (usbnet)->net->name , ## arg)
#else
#define devdbg(usbnet, fmt, arg...) do {} while(0)
#endif
#define deverr(usbnet, fmt, arg...) \
printk(KERN_ERR "%s: " fmt "\n" , (usbnet)->net->name , ## arg)
#define devwarn(usbnet, fmt, arg...) \
printk(KERN_WARNING "%s: " fmt "\n" , (usbnet)->net->name , ## arg)
#define devinfo(usbnet, fmt, arg...) \
printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net->name , ## arg); \
#endif /* __USBNET_H */

385
drivers/net/usb/zaurus.c 一般檔案
查看文件

@@ -0,0 +1,385 @@
/*
* Copyright (C) 2002 Pavel Machek <pavel@ucw.cz>
* Copyright (C) 2002-2005 by David Brownell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// #define DEBUG // error path messages, extra info
// #define VERBOSE // more; success messages
#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/ethtool.h>
#include <linux/workqueue.h>
#include <linux/mii.h>
#include <linux/crc32.h>
#include <linux/usb.h>
#include <linux/usb/cdc.h>
#include "usbnet.h"
/*
* All known Zaurii lie about their standards conformance. At least
* the earliest SA-1100 models lie by saying they support CDC Ethernet.
* Some later models (especially PXA-25x and PXA-27x based ones) lie
* and say they support CDC MDLM (for access to cell phone modems).
*
* There are non-Zaurus products that use these same protocols too.
*
* The annoying thing is that at the same time Sharp was developing
* that annoying standards-breaking software, the Linux community had
* a simple "CDC Subset" working reliably on the same SA-1100 hardware.
* That is, the same functionality but not violating standards.
*
* The CDC Ethernet nonconformance points are troublesome to hosts
* with a true CDC Ethernet implementation:
* - Framing appends a CRC, which the spec says drivers "must not" do;
* - Transfers data in altsetting zero, instead of altsetting 1;
* - All these peripherals use the same ethernet address.
*
* The CDC MDLM nonconformance is less immediately troublesome, since all
* MDLM implementations are quasi-proprietary anyway.
*/
static struct sk_buff *
zaurus_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
{
int padlen;
struct sk_buff *skb2;
padlen = 2;
if (!skb_cloned(skb)) {
int tailroom = skb_tailroom(skb);
if ((padlen + 4) <= tailroom)
goto done;
}
skb2 = skb_copy_expand(skb, 0, 4 + padlen, flags);
dev_kfree_skb_any(skb);
skb = skb2;
if (skb) {
u32 fcs;
done:
fcs = crc32_le(~0, skb->data, skb->len);
fcs = ~fcs;
*skb_put (skb, 1) = fcs & 0xff;
*skb_put (skb, 1) = (fcs>> 8) & 0xff;
*skb_put (skb, 1) = (fcs>>16) & 0xff;
*skb_put (skb, 1) = (fcs>>24) & 0xff;
}
return skb;
}
static int zaurus_bind(struct usbnet *dev, struct usb_interface *intf)
{
/* Belcarra's funky framing has other options; mostly
* TRAILERS (!) with 4 bytes CRC, and maybe 2 pad bytes.
*/
dev->net->hard_header_len += 6;
dev->rx_urb_size = dev->net->hard_header_len + dev->net->mtu;
return usbnet_generic_cdc_bind(dev, intf);
}
/* PDA style devices are always connected if present */
static int always_connected (struct usbnet *dev)
{
return 0;
}
static const struct driver_info zaurus_sl5x00_info = {
.description = "Sharp Zaurus SL-5x00",
.flags = FLAG_FRAMING_Z,
.check_connect = always_connected,
.bind = zaurus_bind,
.unbind = usbnet_cdc_unbind,
.tx_fixup = zaurus_tx_fixup,
};
#define ZAURUS_STRONGARM_INFO ((unsigned long)&zaurus_sl5x00_info)
static const struct driver_info zaurus_pxa_info = {
.description = "Sharp Zaurus, PXA-2xx based",
.flags = FLAG_FRAMING_Z,
.check_connect = always_connected,
.bind = zaurus_bind,
.unbind = usbnet_cdc_unbind,
.tx_fixup = zaurus_tx_fixup,
};
#define ZAURUS_PXA_INFO ((unsigned long)&zaurus_pxa_info)
static const struct driver_info olympus_mxl_info = {
.description = "Olympus R1000",
.flags = FLAG_FRAMING_Z,
.check_connect = always_connected,
.bind = zaurus_bind,
.unbind = usbnet_cdc_unbind,
.tx_fixup = zaurus_tx_fixup,
};
#define OLYMPUS_MXL_INFO ((unsigned long)&olympus_mxl_info)
/* Some more recent products using Lineo/Belcarra code will wrongly claim
* CDC MDLM conformance. They aren't conformant: data endpoints live
* in the control interface, there's no data interface, and it's not used
* to talk to a cell phone radio. But at least we can detect these two
* pseudo-classes, rather than growing this product list with entries for
* each new nonconformant product (sigh).
*/
static const u8 safe_guid[16] = {
0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6,
0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f,
};
static const u8 blan_guid[16] = {
0x74, 0xf0, 0x3d, 0xbd, 0x1e, 0xc1, 0x44, 0x70,
0xa3, 0x67, 0x71, 0x34, 0xc9, 0xf5, 0x54, 0x37,
};
static int blan_mdlm_bind(struct usbnet *dev, struct usb_interface *intf)
{
u8 *buf = intf->cur_altsetting->extra;
int len = intf->cur_altsetting->extralen;
struct usb_cdc_mdlm_desc *desc = NULL;
struct usb_cdc_mdlm_detail_desc *detail = NULL;
while (len > 3) {
if (buf [1] != USB_DT_CS_INTERFACE)
goto next_desc;
/* use bDescriptorSubType, and just verify that we get a
* "BLAN" (or "SAFE") descriptor.
*/
switch (buf [2]) {
case USB_CDC_MDLM_TYPE:
if (desc) {
dev_dbg(&intf->dev, "extra MDLM\n");
goto bad_desc;
}
desc = (void *) buf;
if (desc->bLength != sizeof *desc) {
dev_dbg(&intf->dev, "MDLM len %u\n",
desc->bLength);
goto bad_desc;
}
/* expect bcdVersion 1.0, ignore */
if (memcmp(&desc->bGUID, blan_guid, 16)
&& memcmp(&desc->bGUID, safe_guid, 16) ) {
/* hey, this one might _really_ be MDLM! */
dev_dbg(&intf->dev, "MDLM guid\n");
goto bad_desc;
}
break;
case USB_CDC_MDLM_DETAIL_TYPE:
if (detail) {
dev_dbg(&intf->dev, "extra MDLM detail\n");
goto bad_desc;
}
detail = (void *) buf;
switch (detail->bGuidDescriptorType) {
case 0: /* "SAFE" */
if (detail->bLength != (sizeof *detail + 2))
goto bad_detail;
break;
case 1: /* "BLAN" */
if (detail->bLength != (sizeof *detail + 3))
goto bad_detail;
break;
default:
goto bad_detail;
}
/* assuming we either noticed BLAN already, or will
* find it soon, there are some data bytes here:
* - bmNetworkCapabilities (unused)
* - bmDataCapabilities (bits, see below)
* - bPad (ignored, for PADAFTER -- BLAN-only)
* bits are:
* - 0x01 -- Zaurus framing (add CRC)
* - 0x02 -- PADBEFORE (CRC includes some padding)
* - 0x04 -- PADAFTER (some padding after CRC)
* - 0x08 -- "fermat" packet mangling (for hw bugs)
* the PADBEFORE appears not to matter; we interop
* with devices that use it and those that don't.
*/
if ((detail->bDetailData[1] & ~0x02) != 0x01) {
/* bmDataCapabilities == 0 would be fine too,
* but framing is minidriver-coupled for now.
*/
bad_detail:
dev_dbg(&intf->dev,
"bad MDLM detail, %d %d %d\n",
detail->bLength,
detail->bDetailData[0],
detail->bDetailData[2]);
goto bad_desc;
}
/* same extra framing as for non-BLAN mode */
dev->net->hard_header_len += 6;
dev->rx_urb_size = dev->net->hard_header_len
+ dev->net->mtu;
break;
}
next_desc:
len -= buf [0]; /* bLength */
buf += buf [0];
}
if (!desc || !detail) {
dev_dbg(&intf->dev, "missing cdc mdlm %s%sdescriptor\n",
desc ? "" : "func ",
detail ? "" : "detail ");
goto bad_desc;
}
/* There's probably a CDC Ethernet descriptor there, but we can't
* rely on the Ethernet address it provides since not all vendors
* bother to make it unique. Likewise there's no point in tracking
* of the CDC event notifications.
*/
return usbnet_get_endpoints(dev, intf);
bad_desc:
dev_info(&dev->udev->dev, "unsupported MDLM descriptors\n");
return -ENODEV;
}
static const struct driver_info bogus_mdlm_info = {
.description = "pseudo-MDLM (BLAN) device",
.flags = FLAG_FRAMING_Z,
.check_connect = always_connected,
.tx_fixup = zaurus_tx_fixup,
.bind = blan_mdlm_bind,
};
static const struct usb_device_id products [] = {
#define ZAURUS_MASTER_INTERFACE \
.bInterfaceClass = USB_CLASS_COMM, \
.bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, \
.bInterfaceProtocol = USB_CDC_PROTO_NONE
/* SA-1100 based Sharp Zaurus ("collie"), or compatible. */
{
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x8004,
ZAURUS_MASTER_INTERFACE,
.driver_info = ZAURUS_STRONGARM_INFO,
},
/* PXA-2xx based models are also lying-about-cdc. If you add any
* more devices that claim to be CDC Ethernet, make sure they get
* added to the blacklist in cdc_ether too.
*
* NOTE: OpenZaurus versions with 2.6 kernels won't use these entries,
* unlike the older ones with 2.4 "embedix" kernels.
*/
{
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x8005, /* A-300 */
ZAURUS_MASTER_INTERFACE,
.driver_info = ZAURUS_PXA_INFO,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x8006, /* B-500/SL-5600 */
ZAURUS_MASTER_INTERFACE,
.driver_info = ZAURUS_PXA_INFO,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x8007, /* C-700 */
ZAURUS_MASTER_INTERFACE,
.driver_info = ZAURUS_PXA_INFO,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x9031, /* C-750 C-760 */
ZAURUS_MASTER_INTERFACE,
.driver_info = ZAURUS_PXA_INFO,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
.idProduct = 0x9032, /* SL-6000 */
ZAURUS_MASTER_INTERFACE,
.driver_info = ZAURUS_PXA_INFO,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD,
/* reported with some C860 units */
.idProduct = 0x9050, /* C-860 */
ZAURUS_MASTER_INTERFACE,
.driver_info = ZAURUS_PXA_INFO,
},
/* At least some of the newest PXA units have very different lies about
* their standards support: they claim to be cell phones offering
* direct access to their radios! (No, they don't conform to CDC MDLM.)
*/
{
USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM,
USB_CDC_PROTO_NONE),
.driver_info = (unsigned long) &bogus_mdlm_info,
},
/* Olympus has some models with a Zaurus-compatible option.
* R-1000 uses a FreeScale i.MXL cpu (ARMv4T)
*/
{
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x07B4,
.idProduct = 0x0F02, /* R-1000 */
ZAURUS_MASTER_INTERFACE,
.driver_info = OLYMPUS_MXL_INFO,
},
{ }, // END
};
MODULE_DEVICE_TABLE(usb, products);
static struct usb_driver zaurus_driver = {
.name = "zaurus",
.id_table = products,
.probe = usbnet_probe,
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
};
static int __init zaurus_init(void)
{
return usb_register(&zaurus_driver);
}
module_init(zaurus_init);
static void __exit zaurus_exit(void)
{
usb_deregister(&zaurus_driver);
}
module_exit(zaurus_exit);
MODULE_AUTHOR("Pavel Machek, David Brownell");
MODULE_DESCRIPTION("Sharp Zaurus PDA, and compatible products");
MODULE_LICENSE("GPL");