* Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
* Copyright (C) 2008 Nokia Corporation
*
- * 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
+ * SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <linux/usb/cdc.h>
#include <linux/usb/gadget.h>
#include <net.h>
+#include <usb.h>
#include <malloc.h>
+#include <memalign.h>
#include <linux/ctype.h>
#include "gadget_chips.h"
#define atomic_read
extern struct platform_data brd;
-#define spin_lock(x)
-#define spin_unlock(x)
unsigned packet_received, packet_sent;
-#define DEV_CONFIG_CDC 1
-#define GFP_ATOMIC ((gfp_t) 0)
-#define GFP_KERNEL ((gfp_t) 0)
-
/*
* Ethernet gadget driver -- with CDC and non-CDC options
* Builds on hardware support for a full duplex link.
#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */
#define ETH_DATA_LEN 1500 /* Max. octets in payload */
#define ETH_FRAME_LEN PKTSIZE_ALIGN /* Max. octets in frame sans FCS */
-#define ETH_FCS_LEN 4 /* Octets in the FCS */
#define DRIVER_DESC "Ethernet Gadget"
/* Based on linux 2.6.27 version */
/* "main" config is either CDC, or its simple subset */
static inline int is_cdc(struct eth_dev *dev)
{
-#if !defined(DEV_CONFIG_SUBSET)
+#if !defined(CONFIG_USB_ETH_SUBSET)
return 1; /* only cdc possible */
-#elif !defined(DEV_CONFIG_CDC)
+#elif !defined(CONFIG_USB_ETH_CDC)
return 0; /* only subset possible */
#else
return dev->cdc; /* depends on what hardware we found */
* get those drivers from MCCI, or bundled with various products.
*/
-#ifdef DEV_CONFIG_CDC
+#ifdef CONFIG_USB_ETH_CDC
static struct usb_interface_descriptor
control_intf = {
.bLength = sizeof control_intf,
.bcdCDC = __constant_cpu_to_le16(0x0110),
};
-#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS)
static const struct usb_cdc_union_desc union_desc = {
.bLength = sizeof union_desc,
#endif
-#ifndef DEV_CONFIG_CDC
+#ifndef CONFIG_USB_ETH_CDC
/*
* "SAFE" loosely follows CDC WMC MDLM, violating the spec in various
.bNumberPowerFilters = 0,
};
-#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS)
/*
* include the status endpoint if we can, even where it's optional.
};
#endif
-#ifdef DEV_CONFIG_CDC
+#ifdef CONFIG_USB_ETH_CDC
/* the default data interface has no endpoints ... */
#endif
-#ifdef DEV_CONFIG_SUBSET
+#ifdef CONFIG_USB_ETH_SUBSET
/*
* "Simple" CDC-subset option is a simple vendor-neutral model that most
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = __constant_cpu_to_le16(64),
};
static struct usb_endpoint_descriptor
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = __constant_cpu_to_le16(64),
};
static const struct usb_descriptor_header *fs_eth_function[11] = {
(struct usb_descriptor_header *) &otg_descriptor,
-#ifdef DEV_CONFIG_CDC
+#ifdef CONFIG_USB_ETH_CDC
/* "cdc" mode descriptors */
(struct usb_descriptor_header *) &control_intf,
(struct usb_descriptor_header *) &header_desc,
(struct usb_descriptor_header *) &fs_source_desc,
(struct usb_descriptor_header *) &fs_sink_desc,
NULL,
-#endif /* DEV_CONFIG_CDC */
+#endif /* CONFIG_USB_ETH_CDC */
};
static inline void fs_subset_descriptors(void)
{
-#ifdef DEV_CONFIG_SUBSET
+#ifdef CONFIG_USB_ETH_SUBSET
/* behavior is "CDC Subset"; extra descriptors say "SAFE" */
fs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
fs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
* descriptors, unless they only run at full speed.
*/
-#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS)
static struct usb_endpoint_descriptor
hs_status_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.wMaxPacketSize = __constant_cpu_to_le16(STATUS_BYTECOUNT),
.bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
};
-#endif /* DEV_CONFIG_CDC */
+#endif /* CONFIG_USB_ETH_CDC */
static struct usb_endpoint_descriptor
hs_source_desc = {
static const struct usb_descriptor_header *hs_eth_function[11] = {
(struct usb_descriptor_header *) &otg_descriptor,
-#ifdef DEV_CONFIG_CDC
+#ifdef CONFIG_USB_ETH_CDC
/* "cdc" mode descriptors */
(struct usb_descriptor_header *) &control_intf,
(struct usb_descriptor_header *) &header_desc,
(struct usb_descriptor_header *) &hs_source_desc,
(struct usb_descriptor_header *) &hs_sink_desc,
NULL,
-#endif /* DEV_CONFIG_CDC */
+#endif /* CONFIG_USB_ETH_CDC */
};
static inline void hs_subset_descriptors(void)
{
-#ifdef DEV_CONFIG_SUBSET
+#ifdef CONFIG_USB_ETH_SUBSET
/* behavior is "CDC Subset"; extra descriptors say "SAFE" */
hs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
hs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
{ STRING_SERIALNUMBER, serial_number, },
{ STRING_DATA, "Ethernet Data", },
{ STRING_ETHADDR, ethaddr, },
-#ifdef DEV_CONFIG_CDC
+#ifdef CONFIG_USB_ETH_CDC
{ STRING_CDC, "CDC Ethernet", },
{ STRING_CONTROL, "CDC Communications Control", },
#endif
-#ifdef DEV_CONFIG_SUBSET
+#ifdef CONFIG_USB_ETH_SUBSET
{ STRING_SUBSET, "CDC Ethernet Subset", },
#endif
#ifdef CONFIG_USB_ETH_RNDIS
};
/*============================================================================*/
-static u8 control_req[USB_BUFSIZ];
-static u8 status_req[STATUS_BYTECOUNT] __attribute__ ((aligned(4)));
-
-
-/**
- * strlcpy - Copy a %NUL terminated string into a sized buffer
- * @dest: Where to copy the string to
- * @src: Where to copy the string from
- * @size: size of destination buffer
- *
- * Compatible with *BSD: the result is always a valid
- * NUL-terminated string that fits in the buffer (unless,
- * of course, the buffer size is zero). It does not pad
- * out the result like strncpy() does.
- */
-size_t strlcpy(char *dest, const char *src, size_t size)
-{
- size_t ret = strlen(src);
+DEFINE_CACHE_ALIGN_BUFFER(u8, control_req, USB_BUFSIZ);
- if (size) {
- size_t len = (ret >= size) ? size - 1 : ret;
- memcpy(dest, src, len);
- dest[len] = '\0';
- }
- return ret;
-}
+#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+DEFINE_CACHE_ALIGN_BUFFER(u8, status_req, STATUS_BYTECOUNT);
+#endif
/*============================================================================*/
int result = 0;
struct usb_gadget *gadget = dev->gadget;
-#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS)
/* status endpoint used for RNDIS and (optionally) CDC */
if (!subset_active(dev) && dev->status_ep) {
dev->status = ep_desc(gadget, &hs_status_desc,
/*-------------------------------------------------------------------------*/
-#ifdef DEV_CONFIG_CDC
+#ifdef CONFIG_USB_ETH_CDC
/*
* The interrupt endpoint is used in CDC networking models (Ethernet, ATM)
switch (wValue >> 8) {
case USB_DT_DEVICE:
+ device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
value = min(wLength, (u16) sizeof device_desc);
memcpy(req->buf, &device_desc, value);
break;
if (gadget_is_pxa(gadget)) {
value = eth_set_config(dev, DEV_CONFIG_VALUE,
GFP_ATOMIC);
+ /*
+ * PXA25x driver use non-CDC ethernet gadget.
+ * But only _CDC and _RNDIS code can signalize
+ * that network is working. So we signalize it
+ * here.
+ */
+ l_ethdev.network_started = 1;
+ debug("USB network up!\n");
goto done_set_intf;
}
-#ifdef DEV_CONFIG_CDC
+#ifdef CONFIG_USB_ETH_CDC
switch (wIndex) {
case 0: /* control/master intf */
if (wValue != 0)
* all non-PXA hardware talks real CDC ...
*/
debug("set_interface ignored!\n");
-#endif /* DEV_CONFIG_CDC */
+#endif /* CONFIG_USB_ETH_CDC */
done_set_intf:
break;
value = min(wLength, (u16) 1);
break;
-#ifdef DEV_CONFIG_CDC
+#ifdef CONFIG_USB_ETH_CDC
case USB_CDC_SET_ETHERNET_PACKET_FILTER:
/*
* see 6.2.30: no data, wIndex = interface,
* case USB_CDC_GET_ETHERNET_STATISTIC:
*/
-#endif /* DEV_CONFIG_CDC */
+#endif /* CONFIG_USB_ETH_CDC */
#ifdef CONFIG_USB_ETH_RNDIS
/*
*/
debug("%s\n", __func__);
+ if (!req)
+ return -EINVAL;
size = (ETHER_HDR_SIZE + dev->mtu + RX_EXTRA);
size += dev->out_ep->maxpacket - 1;
* RNDIS headers involve variable numbers of LE32 values.
*/
- req->buf = (u8 *) NetRxPackets[0];
+ req->buf = (u8 *)net_rx_packets[0];
req->length = size;
req->complete = rx_complete;
if (!eth_is_promisc (dev)) {
u8 *dest = skb->data;
- if (is_multicast_ether_addr(dest)) {
+ if (is_multicast_ethaddr(dest)) {
u16 type;
/* ignores USB_CDC_PACKET_TYPE_MULTICAST and host
* SET_ETHERNET_MULTICAST_FILTERS requests
*/
- if (is_broadcast_ether_addr(dest))
+ if (is_broadcast_ethaddr(dest))
type = USB_CDC_PACKET_TYPE_BROADCAST;
else
type = USB_CDC_PACKET_TYPE_ALL_MULTICAST;
/* Wait until host receives OID_GEN_MEDIA_CONNECT_STATUS */
ts = get_timer(0);
while (get_timer(ts) < timeout)
- usb_gadget_handle_interrupts();
+ usb_gadget_handle_interrupts(0);
#endif
rndis_uninit(dev->rndis_config);
p = q;
}
- if (i == 6) /* it looks ok */
- return 1;
+ /* Now check the contents. */
+ return is_valid_ethaddr(ea);
}
return 0;
}
num |= (nibble(*str++));
dev_addr[i] = num;
}
- if (is_valid_ether_addr(dev_addr))
+ if (is_valid_ethaddr(dev_addr))
return 0;
}
return 1;
u8 tmp[7];
/* these flags are only ever cleared; compiler take note */
-#ifndef DEV_CONFIG_CDC
+#ifndef CONFIG_USB_ETH_CDC
cdc = 0;
#endif
#ifndef CONFIG_USB_ETH_RNDIS
goto autoconf_fail;
out_ep->driver_data = out_ep; /* claim */
-#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS)
/*
* CDC Ethernet control interface doesn't require a status endpoint.
* Since some hosts expect one, try to allocate one anyway.
} else if (rndis) {
error("can't run RNDIS on %s", gadget->name);
return -ENODEV;
-#ifdef DEV_CONFIG_CDC
+#ifdef CONFIG_USB_ETH_CDC
} else if (cdc) {
control_intf.bNumEndpoints = 0;
/* FIXME remove endpoint from descriptor list */
hs_subset_descriptors();
}
- device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
usb_gadget_set_selfpowered(gadget);
/* For now RNDIS is always a second config */
fs_source_desc.bEndpointAddress;
hs_sink_desc.bEndpointAddress =
fs_sink_desc.bEndpointAddress;
-#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS)
if (status_ep)
hs_status_desc.bEndpointAddress =
fs_status_desc.bEndpointAddress;
dev->req->complete = eth_setup_complete;
/* ... and maybe likewise for status transfer */
-#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS)
if (dev->status_ep) {
dev->stat_req = usb_ep_alloc_request(dev->status_ep,
GFP_KERNEL);
goto fail;
}
+ board_usb_init(0, USB_INIT_DEVICE);
+
/* Configure default mac-addresses for the USB ethernet device */
#ifdef CONFIG_USBNET_DEV_ADDR
strlcpy(dev_addr, CONFIG_USBNET_DEV_ADDR, sizeof(dev_addr));
error("The remote end did not respond in time.");
goto fail;
}
- usb_gadget_handle_interrupts();
+ usb_gadget_handle_interrupts(0);
}
packet_received = 0;
return -1;
}
-static int usb_eth_send(struct eth_device *netdev,
- volatile void *packet, int length)
+static int usb_eth_send(struct eth_device *netdev, void *packet, int length)
{
int retval;
void *rndis_pkt = NULL;
}
rndis_add_hdr(rndis_pkt, length);
memcpy(rndis_pkt + sizeof(struct rndis_packet_msg_type),
- (void *)packet, length);
+ packet, length);
packet = rndis_pkt;
length += sizeof(struct rndis_packet_msg_type);
}
- req->buf = (void *)packet;
+ req->buf = packet;
req->context = NULL;
req->complete = tx_complete;
printf("timeout sending packets to usb ethernet\n");
return -1;
}
- usb_gadget_handle_interrupts();
+ usb_gadget_handle_interrupts(0);
}
if (rndis_pkt)
free(rndis_pkt);
{
struct eth_dev *dev = &l_ethdev;
- usb_gadget_handle_interrupts();
+ usb_gadget_handle_interrupts(0);
if (packet_received) {
debug("%s: packet received\n", __func__);
if (dev->rx_req) {
- NetReceive(NetRxPackets[0], dev->rx_req->length);
+ net_process_received_packet(net_rx_packets[0],
+ dev->rx_req->length);
packet_received = 0;
rx_submit(dev, dev->rx_req, 0);
/* Clear pending interrupt */
if (dev->network_started) {
- usb_gadget_handle_interrupts();
+ usb_gadget_handle_interrupts(0);
dev->network_started = 0;
}
usb_gadget_unregister_driver(ð_driver);
+ board_usb_cleanup(0, USB_INIT_DEVICE);
}
static struct usb_gadget_driver eth_driver = {
.unbind = eth_unbind,
.setup = eth_setup,
+ .reset = eth_disconnect,
.disconnect = eth_disconnect,
.suspend = eth_suspend,