📄 ecos_usbeth.c
字号:
usbeth->tx_buffer[i+4], usbeth->tx_buffer[i+5], usbeth->tx_buffer[i+6], usbeth->tx_buffer[i+7]);
}
printk("--------------------------------------------------------------\n");
}
#endif
res = usb_submit_urb(&(usbeth->tx_urb));
if (0 == res) {
netif_stop_queue(net);
net->trans_start = jiffies;
usbeth->stats.tx_packets++;
usbeth->stats.tx_bytes += skb->len;
} else {
printk("ecos_usbeth: failed to start USB packet transmission, %d\n", res);
usbeth->stats.tx_errors++;
}
spin_unlock(&usbeth->usb_lock);
dev_kfree_skb(skb);
return 0;
}
// set_rx_mode()
// Invoked by the network stack to enable/disable promiscuous mode or
// for multicasting. The latter is not yet supported on the target
// side. The former involves a USB control message. The main call
// is not allowed to block.
static void
ecos_usbeth_set_rx_mode_callback(struct urb* urb)
{
kfree(urb->setup_packet);
usb_free_urb(urb);
}
static void
ecos_usbeth_set_rx_mode(struct net_device* net)
{
ecos_usbeth* usbeth = (ecos_usbeth*) net->priv;
__u16 promiscuous = net->flags & IFF_PROMISC;
int res;
if (promiscuous != usbeth->target_promiscuous) {
devrequest* req;
urb_t* urb;
urb = usb_alloc_urb(0);
if ((urb_t*)0 == urb) {
return;
}
req = kmalloc(sizeof(devrequest), GFP_KERNEL);
if ((devrequest*)0 == req) {
usb_free_urb(urb);
return;
}
req->requesttype = USB_TYPE_CLASS | USB_RECIP_DEVICE;
req->request = ECOS_USBETH_CONTROL_SET_PROMISCUOUS_MODE;
req->value = cpu_to_le16p(&promiscuous);
req->index = 0;
req->length = 0;
FILL_CONTROL_URB(urb,
usbeth->usb_dev,
usb_sndctrlpipe(usbeth->usb_dev, 0),
(unsigned char*) req,
(void*) 0,
0,
&ecos_usbeth_set_rx_mode_callback,
(void*) usbeth);
res = usb_submit_urb(urb);
if (0 != res) {
kfree(req);
usb_free_urb(urb);
} else {
usbeth->target_promiscuous = promiscuous;
}
}
}
// netdev_stats()
// Supply the current network statistics. These are held in
// the stats field of the ecos_usbeth structure
static struct net_device_stats*
ecos_usbeth_netdev_stats(struct net_device* net)
{
ecos_usbeth* usbeth = (ecos_usbeth*) net->priv;
return &(usbeth->stats);
}
// ioctl()
// Currently none of the network ioctl()'s are supported
static int
ecos_usbeth_ioctl(struct net_device* net, struct ifreq* request, int command)
{
return -EINVAL;
}
// probe().
// This is invoked by the generic USB code when a new device has
// been detected and its configuration details have been extracted
// and stored in the usbdev structure. The interface_id specifies
// a specific USB interface, to cope with multifunction peripherals.
//
// FIXME; right now this code only copes with simple enumeration data.
// OK, to be really honest it just looks for the vendor and device ids
// in the simple test cases and ignores everything else.
//
// On success it should return a non-NULL pointer, which happens to be
// a newly allocated ecos_usbeth structure. This will get passed to
// the disconnect function. Filling in the ecos_usbeth structure will,
// amongst other things, register this as a network device driver.
// The MAC address is obtained from the peripheral via a control
// request.
static void*
ecos_usbeth_probe(struct usb_device* usbdev, unsigned int interface_id)
{
struct net_device* net;
ecos_usbeth* usbeth;
int res;
unsigned char MAC[6];
unsigned char dummy[1];
int tx_endpoint = -1;
int rx_endpoint = -1;
const ecos_usbeth_impl* impl;
int found_impl = 0;
// See if this is the correct driver for this USB peripheral.
impl = ecos_usbeth_implementations;
while (impl->name != NULL) {
if ((usbdev->descriptor.idVendor != impl->vendor) ||
(usbdev->descriptor.idProduct != impl->id)) {
found_impl = 1;
break;
}
impl++;
}
if (! found_impl) {
return (void*) 0;
}
// For now only support USB-ethernet peripherals consisting of a single
// configuration, with a single interface, with two bulk endpoints.
if ((1 != usbdev->descriptor.bNumConfigurations) ||
(1 != usbdev->config[0].bNumInterfaces) ||
(2 != usbdev->config[0].interface[0].altsetting->bNumEndpoints)) {
return (void*) 0;
}
if ((0 == (usbdev->config[0].interface[0].altsetting->endpoint[0].bEndpointAddress & USB_DIR_IN)) &&
(0 != (usbdev->config[0].interface[0].altsetting->endpoint[1].bEndpointAddress & USB_DIR_IN))) {
tx_endpoint = usbdev->config[0].interface[0].altsetting->endpoint[0].bEndpointAddress;
rx_endpoint = usbdev->config[0].interface[0].altsetting->endpoint[1].bEndpointAddress & ~USB_DIR_IN;
}
if ((0 != (usbdev->config[0].interface[0].altsetting->endpoint[0].bEndpointAddress & USB_DIR_IN)) &&
(0 == (usbdev->config[0].interface[0].altsetting->endpoint[1].bEndpointAddress & USB_DIR_IN))) {
tx_endpoint = usbdev->config[0].interface[0].altsetting->endpoint[1].bEndpointAddress;
rx_endpoint = usbdev->config[0].interface[0].altsetting->endpoint[0].bEndpointAddress & ~USB_DIR_IN;
}
if (-1 == tx_endpoint) {
return (void*) 0;
}
res = usb_set_configuration(usbdev, usbdev->config[0].bConfigurationValue);
if (0 != res) {
printk("ecos_usbeth: failed to set configuration, %d\n", res);
return (void*) 0;
}
res = usb_control_msg(usbdev,
usb_rcvctrlpipe(usbdev, 0),
ECOS_USBETH_CONTROL_GET_MAC_ADDRESS,
USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN,
0,
0,
(void*) MAC,
6,
5 * HZ);
if (6 != res) {
printk("ecos_usbeth: failed to get MAC address, %d\n", res);
return (void*) 0;
}
res = usb_control_msg(usbdev,
usb_sndctrlpipe(usbdev, 0), // pipe
ECOS_USBETH_CONTROL_SET_PROMISCUOUS_MODE, // request
USB_TYPE_CLASS | USB_RECIP_DEVICE, // requesttype
0, // value
0, // index
(void*) dummy, // data
0, // size
5 * HZ); // timeout
if (0 != res) {
printk("ecos_usbeth: failed to disable promiscous mode, %d\n", res);
}
usbeth = (ecos_usbeth*) kmalloc(sizeof(ecos_usbeth), GFP_KERNEL);
if ((ecos_usbeth*)0 == usbeth) {
printk("ecos_usbeth: failed to allocate memory for usbeth data structure\n");
return (void*) 0;
}
memset(usbeth, 0, sizeof(ecos_usbeth));
net = init_etherdev(0, 0);
if ((struct net_device*) 0 == net) {
kfree(usbeth);
printk("ecos_usbeth: failed to allocate memory for net data structure\n");
return (void*) 0;
}
usbeth->usb_lock = SPIN_LOCK_UNLOCKED;
usbeth->usb_dev = usbdev;
FILL_BULK_URB(&(usbeth->tx_urb), usbdev, usb_sndbulkpipe(usbdev, tx_endpoint),
usbeth->tx_buffer, ECOS_USBETH_MAXTU, &ecos_usbeth_tx_callback, (void*) usbeth);
FILL_BULK_URB(&(usbeth->rx_urb), usbdev, usb_rcvbulkpipe(usbdev, rx_endpoint),
usbeth->rx_buffer, ECOS_USBETH_MAXTU, &ecos_usbeth_rx_callback, (void*) usbeth);
usbeth->net_dev = net;
usbeth->target_promiscuous = 0;
net->priv = (void*) usbeth;
net->open = &ecos_usbeth_open;
net->stop = &ecos_usbeth_close;
net->do_ioctl = &ecos_usbeth_ioctl;
net->hard_start_xmit = &ecos_usbeth_start_tx;
net->set_multicast_list = &ecos_usbeth_set_rx_mode;
net->get_stats = &ecos_usbeth_netdev_stats;
net->mtu = 1500; // ECOS_USBETH_MAXTU - 2;
memcpy(net->dev_addr, MAC, 6);
printk("eCos-based USB ethernet peripheral active at %s\n", net->name);
MOD_INC_USE_COUNT;
return (void*) usbeth;
}
// disconnect().
// Invoked after probe() has recognized a device but that device
// has gone away.
static void
ecos_usbeth_disconnect(struct usb_device* usbdev, void* data)
{
ecos_usbeth* usbeth = (ecos_usbeth*) data;
if (!usbeth) {
printk("ecos_usbeth: warning, disconnecting unconnected device\n");
return;
}
if (0 != netif_running(usbeth->net_dev)) {
ecos_usbeth_close(usbeth->net_dev);
}
unregister_netdev(usbeth->net_dev);
if (-EINPROGRESS == usbeth->rx_urb.status) {
usb_unlink_urb(&(usbeth->rx_urb));
}
if (-EINPROGRESS == usbeth->tx_urb.status) {
usb_unlink_urb(&(usbeth->tx_urb));
}
kfree(usbeth);
MOD_DEC_USE_COUNT;
}
static struct usb_driver ecos_usbeth_driver = {
name: "ecos_usbeth",
probe: ecos_usbeth_probe,
disconnect: ecos_usbeth_disconnect,
};
// init()
// Called when the module is loaded. It just registers the device with
// the generic USB code. Nothing else can really be done until
// the USB code detects that a device has been attached.
int __init
ecos_usbeth_init(void)
{
printk("eCos USB-ethernet device driver\n");
return usb_register(&ecos_usbeth_driver);
}
// exit()
// Called when the module is unloaded. disconnect() will be
// invoked if appropriate.
void __exit
ecos_usbeth_exit(void)
{
usb_deregister(&ecos_usbeth_driver);
}
module_init(ecos_usbeth_init);
module_exit(ecos_usbeth_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -