diff options
Diffstat (limited to 'drivers/otg/functions/network/net-fd.c')
-rw-r--r-- | drivers/otg/functions/network/net-fd.c | 906 |
1 files changed, 906 insertions, 0 deletions
diff --git a/drivers/otg/functions/network/net-fd.c b/drivers/otg/functions/network/net-fd.c new file mode 100644 index 000000000000..7c93d555db62 --- /dev/null +++ b/drivers/otg/functions/network/net-fd.c @@ -0,0 +1,906 @@ +/* + * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +/* + * otg/functions/network/net-fd.c - Network Function Driver + * @(#) sl@belcarra.com/whiskey.enposte.net|otg/functions/network/net-fd.c|20070814184652|40728 + * + * Copyright (c) 2002-2006 Belcarra Technologies Corp + * Copyright (c) 2005-2006 Belcarra Technologies 2005 Corp + * + * By: + * Chris Lynne <cl@belcarra.com> + * Stuart Lynne <sl@belcarra.com> + * Bruce Balden <balden@belcarra.com> + * + */ +/*! + * @file otg/functions/network/net-fd.c + * @brief The lower edge (USB Device Function) implementation of + * the Network Function Driver. This performs the core protocol + * handling and data encpasulation. + * + * This implements the lower edge (USB Device) layer of the Network Function + * Driver. Specifically the data encapsulation, envent and protocol handlers. + * + * This network function driver intended to interoperate with + * Belcarra's USBLAN Class drivers. + * + * These are available for Windows, Linux and Mac OSX. For more + * information and to download a copy for testing: + * + * http://www.belcarra.com/usblan/ + * + * Alternately it should be compatible with any CDC-ECM or CDC-EEM + * Class driver. + * + * Experimental Streaming mode is available for EEM. This simply sends + * all frames padded so that they do not terminate the transfer at the + * receiving end. The bulk sent callback will send a ZLE frame IFF there + * is not pending traffic. This will terminate the transfer at the host. + * + * The host should attempt to match it's receiving buffer to a size that + * optimizes the amount of data without unduly impacting latency. For a + * full speed host, something around 35*64 or 2240 bytes would be 1.9mS of + * data and allow for about .1mS for servicing. + * + * @ingroup NetworkFunction + */ + + +#include <otg/otg-compat.h> +#include <otg/otg-module.h> +//#include <linux/list.h> +//#include <linux/ctype.h> + +#include <otg/usbp-chap9.h> +#include <otg/usbp-cdc.h> +#include <otg/usbp-func.h> + +#include <otg/otg-trace.h> +#include <otg/otg-api.h> + +#include "network.h" +#include "net-os.h" +#ifdef CONFIG_OTG_NETWORK_BLAN_FERMAT +#include "fermat.h" +#endif + +#define TRACE_VERBOSE_SEND 0 +#define TRACE_VERBOSE_RECV 0 +#define TRACE_VERY_VERBOSE 0 + +static char * local_dev_addr_str; +static char * remote_dev_addr_str; +static BOOL override_MAC; +static int infrastructure_device; + +/* ********************************************************************************************** */ +#if !defined (CONFIG_OTG_NETWORK_INTERVAL) +#define CONFIG_OTG_NETWORK_INTERVAL 1 +#endif /* !defined (CONFIG_OTG_NETWORK_INTERVAL) */ + +/*! Endpoint Request List + */ + +#if !defined(CONFIG_OTG_NETWORK_DOUBLE_IN) && !defined(CONFIG_OTG_NETWORK_DOUBLE_OUT) +struct usbd_endpoint_request net_fd_endpoint_requests[ENDPOINTS+1] = { + { BULK_OUT_A, 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, 0, }, + { BULK_IN_A, 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, 0, }, + { INT_IN, 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT, 16, 64, CONFIG_OTG_NETWORK_INTERVAL, }, + { 0, }, +}; +u8 net_fd_endpoint_index[ENDPOINTS] = { BULK_OUT_A, BULK_IN_A, INT_IN, }; + +#elif defined(CONFIG_OTG_NETWORK_DOUBLE_IN) && !defined(CONFIG_OTG_NETWORK_DOUBLE_OUT) +struct usbd_endpoint_request net_fd_endpoint_requests[ENDPOINTS+1] = { + { BULK_OUT_A, 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, 0, }, + { BULK_IN_A, 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, 0, }, + { BULK_IN_B, 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, 0, }, + { INT_IN, 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT, 16, 64, CONFIG_OTG_NETWORK_INTERVAL, }, + { 0, }, +}; +u8 net_fd_endpoint_index[ENDPOINTS] = { BULK_OUT_A, BULK_IN_A, BULK_OUT_B, BULK_IN_B, INT_IN, }; + + +#elif !defined(CONFIG_OTG_NETWORK_DOUBLE_IN) && defined(CONFIG_OTG_NETWORK_DOUBLE_OUT) +struct usbd_endpoint_request net_fd_endpoint_requests[ENDPOINTS+1] = { + { BULK_OUT_A, 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, 0, }, + { BULK_IN_A, 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, 0, }, + { BULK_OUT_B, 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, 0, }, + { INT_IN, 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT, 16, 64, CONFIG_OTG_NETWORK_INTERVAL, }, + { 0, }, +}; +u8 net_fd_endpoint_index[ENDPOINTS] = { BULK_OUT_A, BULK_IN_A, BULK_OUT_B, BULK_IN_B, INT_IN, }; + + +#elif defined(CONFIG_OTG_NETWORK_DOUBLE_IN) && defined(CONFIG_OTG_NETWORK_DOUBLE_OUT) +struct usbd_endpoint_request net_fd_endpoint_requests[ENDPOINTS+1] = { + { BULK_OUT_A, 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, 0, }, + { BULK_IN_A, 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, 0, }, + { BULK_OUT_B, 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, 0, }, + { BULK_IN_B, 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, 0, }, + { INT_IN, 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT, 16, 64, CONFIG_OTG_NETWORK_INTERVAL, }, + { 0, }, +}; +u8 net_fd_endpoint_index[ENDPOINTS] = { BULK_OUT_A, BULK_IN_A, BULK_OUT_B, BULK_IN_B, INT_IN, }; + +#endif /* defined(CONFIG_OTG_NETWORK_DOUBLE_IN) && defined(CONFIG_OTG_NETWORK_DOUBLE_OUT) */ + + +/*! Endpoint Request List + */ +struct usbd_endpoint_request cdc_data_endpoint_requests[2+1] = { + { BULK_OUT_A, 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, 0, }, + { BULK_IN_A, 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, 0, }, + { 0, }, +}; +u8 cdc_data_endpoint_index[2] = { BULK_OUT_A, BULK_IN_A, }; + +/*! Endpoint Request List + */ +struct usbd_endpoint_request cdc_int_endpoint_requests[1+1] = { + { INT_IN, 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT, 16, 64, CONFIG_OTG_NETWORK_INTERVAL, }, + { 0, }, +}; + +u8 cdc_int_endpoint_index[1] = { INT_IN, }; + + +/* ********************************************************************************************** */ + +u32 *network_crc32_table; + +/*! make_crc_table + * @brief Generate the crc32 table + * + * @return non-zero if malloc fails + */ +STATIC int make_crc_table(void) +{ + u32 n; + RETURN_ZERO_IF(network_crc32_table); + RETURN_ENOMEM_IF(!(network_crc32_table = (u32 *)ckmalloc(256*4))); + for (n = 0; n < 256; n++) { + int k; + u32 c = n; + for (k = 0; k < 8; k++) { + c = (c & 1) ? (CRC32_POLY ^ (c >> 1)) : (c >> 1); + } + network_crc32_table[n] = c; + } + return 0; +} + +/* ********************************************************************************************** */ + +/*! net_fd_urb_sent_int - callback for completed INT URB + * + * Handles notification that an urb has been sent (successfully or otherwise). + * + * @param urb - pointer to urb to send + * @param urb_rc + * + * @return non-zero for failure. + */ +STATIC int net_fd_urb_sent_int (struct usbd_urb *urb, int urb_rc) +{ + //int rc = -EINVAL; + struct usbd_function_instance *function_instance = urb->function_instance; + struct usb_network_private *npd = function_instance->privdata; + + //TRACE_MSG3(NTT,"urb: %p npd: %p urb_rc: %d", urb, npd, urb_rc); + + npd->int_urb = NULL; + usbd_free_urb (urb); + return 0; +} + +/*! net_fd_send_int_notification - send an interrupt notification response + * + * Generates a response urb on the notification (INTERRUPT) endpoint. + * + * This is called from either a scheduled task or from the process context + * that calls network_open() or network_close(). + * This must be called with interrupts locked out as net_fd_event_handler can + * change the NETWORK_CONFIGURED status + * + * @param function_instance - pointer to function instance + * @param connected - connect status + * @param data - + * + * @return none + * + */ +void net_fd_send_int_notification(struct usbd_function_instance *function_instance, int connected, int data) +{ + struct usb_network_private *npd = function_instance ? function_instance->privdata : NULL; + struct usbd_urb *urb; + struct cdc_notification_descriptor *cdc; + int rc; + + //TRACE_MSG3(NTT,"npd: %p function: %p flags: %04x", npd, function_instance, npd->flags); + + do { + BREAK_IF(!function_instance); + + BREAK_IF(npd->network_type != network_blan); + BREAK_IF(!npd->have_interrupt); + + BREAK_IF(!(npd->flags & NETWORK_CONFIGURED)); + + TRACE_MSG3(NTT,"connected: %d network: %d %d", connected, + npd->network_type, network_blan); + + BREAK_IF(usbd_get_device_status(function_instance) != USBD_OK); + + BREAK_IF(!(urb = usbd_alloc_urb (function_instance, INT_IN, + sizeof(struct cdc_notification_descriptor), net_fd_urb_sent_int))); + + urb->actual_length = sizeof(struct cdc_notification_descriptor); + memset(urb->buffer, 0, sizeof(struct cdc_notification_descriptor)); + + cdc = (struct cdc_notification_descriptor *)urb->buffer; + + cdc->bmRequestType = 0xa1; + + if (data) { + cdc->bNotification = 0xf0; + cdc->wValue = 1; + } + else { + cdc->bNotification = 0x00; + cdc->wValue = connected ? 0x01 : 0x00; + } + cdc->wIndex = 0x00; // XXX interface - check that this is correct + + + npd->int_urb = urb; + TRACE_MSG1(NTT,"int_urb: %p", urb); + BREAK_IF (!(rc = usbd_start_in_urb (urb))); + + TRACE_MSG1(NTT,"usbd_start_in_urb failed err: %x", rc); + npd->int_urb = NULL; + usbd_free_urb (urb); + + } while(0); +} + +/* ********************************************************************************************** */ + +/*! net_fd_start_xmit - start sending a buffer + * + * Called with net_os_mutex_enter()d. + * + * @param function_instance - pointer to function instance + * @param buffer - container to data to transmit + * @param len - data length + * @param data + * + * @return: 0 if all OK + * -EINVAL, -EUNATCH, -ENOMEM + * rc from usbd_start_in_urb() if that fails (is != 0, may be one of err values above) + * Note: -ECOMM is interpreted by calling routine as signal to leave IF stopped. + */ +int net_fd_start_xmit (struct usbd_function_instance *function_instance, u8 *buffer, int len, void *data) +{ + struct usb_network_private *npd = function_instance->privdata; + struct usbd_urb *urb = NULL; + int rc; + + if (TRACE_VERBOSE_SEND) + TRACE_MSG4(NTT, "os: %p buffer: %p len: %d flags: %04x", data, buffer, len, npd->flags); + RETURN_EUNATCH_UNLESS(npd->flags & NETWORK_CONFIGURED); + RETURN_EINVAL_IF(usbd_get_device_status(function_instance) != USBD_OK); + + //TRACE_MSG2(NTT, "queued: %d bytes: %d", npd->queued_frames, npd->queued_bytes); + + if (TRACE_VERBOSE_SEND) { + TRACE_NSEND(NTT, 32, buffer); + if (TRACE_VERY_VERBOSE) { + TRACE_SEND(NTT, len, buffer); + } + } + + UNLESS ((rc = npd->net_start_xmit (function_instance, buffer, len, data))) + otg_atomic_inc(&npd->queued_frames); + + return rc; +} + +/* ********************************************************************************************** */ + +int net_fd_check_tp_response(struct usbd_function_instance *function_instance, u8 *buffer, int length); +int net_fd_check_rarp_response(struct usbd_function_instance *function_instance, u8 *buffer, int length); + +/*! net_fd_recv_buffer - forward a received URB, or clean up after a bad one. + * + * Common point for transmitting data to net-fd upper OS layer for pushing + * to Host OS Network Layer. + * + * @param function_instance - pointer to functionn instance + * @param os_buffer - pointer to os buffer + * @param length - os buffer length + * @param os_data - + * @param crc_bad + * @param trim + * @return 0 for exception + */ +int net_fd_recv_buffer(struct usbd_function_instance *function_instance, u8 *os_buffer, int length, + void *os_data, int crc_bad, int trim) +{ + struct usb_network_private *npd = function_instance->privdata; + + if (TRACE_VERBOSE_RECV) { + + TRACE_MSG6(NTT, "os_buffer: %x length: %d os_data: %x crc_bad: %d trim: %d flags: %04x", + os_buffer, length, os_data, crc_bad, trim, npd->flags); + + TRACE_NRECV(NTT, 32, os_buffer); + TRACE_MSG0(NTT, "--"); + if (TRACE_VERY_VERBOSE) { + TRACE_RECV(NTT, length, os_buffer); + } + } + + #if defined(CONFIG_OTG_NETWORK_RARPD_AUTO_CONFIG) + /* check for RARPD request */ + if (net_fd_check_rarpd_request(function_instance, os_buffer, length)) { + + TRACE_MSG0(NTT, "RARPD REQUEST"); + + /* send reply or ignore and send our own request */ + ((npd->flags & NETWORK_INFRASTRUCTURE) ? + net_fd_send_rarpd_reply : net_fd_send_rarpd_request) (function_instance); + + THROW(handled); + } + + /* check for rarpd response IFF not infrastruture */ + UNLESS ((npd->flags & NETWORK_INFRASTRUCTURE) || !net_fd_check_rarpd_reply(function_instance, os_buffer, length)) { + TRACE_MSG0(NTT, "RARPD REPLY RESPONSE"); + + /* configure */ + net_os_config(function_instance); + net_os_hotplug(function_instance); + + #if defined(CONFIG_OTG_NETWORK_RFC868_AUTO_CONFIG) + net_fd_send_tp_request(function_instance); + #endif /* defined(CONFIG_OTG_NETWORK_RFC868_AUTO_CONFIG) */ + THROW(handled); + } + + #if defined(CONFIG_OTG_NETWORK_RFC868_AUTO_CONFIG) + UNLESS ((npd->flags & NETWORK_INFRASTRUCTURE) || !net_fd_check_tp_response(function_instance, os_buffer, length)) { + TRACE_MSG0(NTT, "TIME PROTOCOL RESPONSE"); + + /* set time */ + net_os_settime(function_instance, ntohl(npd->rfc868time)); + THROW( handled); + } + + #endif /* defined(CONFIG_OTG_NETWORK_RFC868_AUTO_CONFIG) */ + #endif /* defined(CONFIG_OTG_NETWORK_RARPD_AUTO_CONFIG) */ + + return (net_os_recv_buffer(function_instance, os_data, os_buffer, crc_bad, length, trim)); + + CATCH(handled) { + /* de-allocate os buffer */ + net_os_dealloc_buffer(function_instance, os_data, os_buffer); + return 0; + } +} + +/* ********************************************************************************************** */ + +/*! net_fd_recv_urb - callback to process a received URB + * + * @param urb - pointer to copy of received urb, + * @param rc - receiving urb result code + * + * @return non-zero for failure. + */ +int net_fd_recv_urb(struct usbd_urb *urb, int rc) +{ + struct usbd_function_instance *function_instance = urb->function_instance; + struct usb_network_private *npd = function_instance->privdata; + + TRACE_MSG2(NTT, "status: %d actual_length: %d", urb->status, urb->actual_length); + +#ifdef CONFIG_OTG_LATENCY_CHECK + otg_get_ocd_info(NULL, &urb->bh_start_ticks, NULL); + //urb->bh_start_ticks=__raw_readl(MXC_GPT_GPTCNT); + //LTRACE_MSG2(NTT, "Callback urb pointer:%x, ticks:%x",urb,urb->bh_start_ticks); + +#endif + #if 0 + TRACE_MSG8(NTT, "[%02x %02x %02x %02x %02x %02x %02x %02x]", + urb->buffer[0], urb->buffer[1], + urb->buffer[2], urb->buffer[3], + urb->buffer[4], urb->buffer[5], + urb->buffer[6], urb->buffer[7] + ); + TRACE_MSG8(NTT, "[%02x %02x %02x %02x %02x %02x %02x %02x]", + urb->buffer[0+8], urb->buffer[1+8], + urb->buffer[2+8], urb->buffer[3+8], + urb->buffer[4+8], urb->buffer[5+8], + urb->buffer[6+8], urb->buffer[7+8] + ); + #endif + + if (TRACE_VERBOSE_RECV) + TRACE_NRECV(NTT, MIN(32, urb->actual_length), urb->buffer); + + if (urb->status == USBD_URB_OK) + npd->net_recv_urb(urb, rc); + + urb->status = USBD_OK; + return usbd_start_out_urb (urb); +} + +/* ********************************************************************************************** */ + +/*! net_fd_device_request - process a received SETUP URB + * + * Processes a received setup packet and CONTROL WRITE data. + * Results for a CONTROL READ are placed in urb->buffer. + * + * @param function_instance - pointer to function instance + * @param request - pointer to usbd_device_request + * + * @return non-zero for failure. + */ +int net_fd_device_request (struct usbd_function_instance *function_instance, struct usbd_device_request *request) +{ + //struct usb_network_private *npd = function_instance->privdata; + //struct usbd_urb *urb; + //int index; + + /* Verify that this is a USB Class request per CDC specification or a vendor request. + */ + RETURN_ZERO_IF (!(request->bmRequestType & (USB_REQ_TYPE_CLASS | USB_REQ_TYPE_VENDOR))); + + return -EINVAL; +} + + +/* ********************************************************************************************** */ + + +/*! net_fd_endpoint_cleared - + */ +void net_fd_endpoint_cleared (struct usbd_function_instance *function_instance, int bEndpointAddress) +{ + //TRACE_MSG1(NTT, "bEndpointAddress: %02x", bEndpointAddress); +} + + +/*! net_fd_urb_sent_bulk - callback for completed BULK xmit URB + * + * Handles notification that an urb has been sent (successfully or otherwise). + * + * @param urb Pointer to the urb that has been sent. + * @param urb_rc Result code from the send operation. + * + * @return non-zero for failure. + */ +int net_fd_urb_sent_bulk (struct usbd_urb *urb, int urb_rc) +{ + struct usbd_function_instance *function_instance = urb->function_instance; + struct usb_network_private *npd = function_instance->privdata; + void *buf; + int rc = -EINVAL; + int endpoint_index = urb->endpoint_index; + + + npd->avg_queue_frames += otg_atomic_read(&npd->queued_frames); + npd->samples++; + + //TRACE_MSG6(NTT,"urb: %p urb_rc: %d length: %d queue: %d avg: %d samples: %d", + // urb, urb_rc, urb->actual_length, + // npd->queued_frames, + // npd->avg_queue_frames / npd->samples, + // npd->samples); + + otg_atomic_dec(&npd->queued_frames); + otg_atomic_sub(urb->actual_length, &npd->queued_bytes); + #ifndef CONFIG_OTG_NETWORK_DOUBLE_IN + #else /* CONFIG_OTG_NETWORK_DOUBLE_IN */ + //otg_atomic_dec(&npd->xmit_urbs_started[endpoint_index]); + #endif /* CONFIG_OTG_NETWORK_DOUBLE_IN */ + do { + + BREAK_IF(!urb); + buf = urb->function_privdata; + urb->function_privdata = NULL; + + #ifndef CONFIG_OTG_NETWORK_DOUBLE_IN + TRACE_MSG6(NTT,"urb: %p buf: %p endpoint_index: %d buffer: %d alloc: %d actual: %d", + urb, buf, endpoint_index, + urb->buffer_length, + urb->alloc_length, + urb->actual_length + ); + #else /* CONFIG_OTG_NETWORK_DOUBLE_IN */ + TRACE_MSG7(NTT,"urb: %p buf: %p endpoint_index: %d started: %d buffer: %d alloc: %d actual: %d", + urb, buf, endpoint_index, + otg_atomic_read(&npd->xmit_urbs_started[endpoint_index]), + urb->buffer_length, + urb->alloc_length, + urb->actual_length + ); + #endif /* CONFIG_OTG_NETWORK_DOUBLE_IN */ + + net_os_xmit_done(urb->function_instance, buf, urb_rc); + #if defined(CONFIG_OTG_NETWORK_BLAN_CRC) || defined(CONFIG_OTG_NETWORK_SAFE_CRC) + #else /* defined(CONFIG_OTG_NETWORK_BLAN_CRC) || defined(CONFIG_OTG_NETWORK_SAFE_CRC) */ + #ifdef CONFIG_OTG_NETWORK_XMIT_OS + urb->buffer = NULL; + #endif /* CONFIG_OTG_NETWORK_XMIT_OS */ + #endif /* defined(CONFIG_OTG_NETWORK_BLAN_CRC) || defined(CONFIG_OTG_NETWORK_SAFE_CRC) */ + /* Now urb has it's own buffer*/ + usbd_free_urb (urb); + rc = 0; + + } while (0); + + return rc; +} + + +/* ********************************************************************************************** */ + +/*! hexdigit - + * + * Converts characters in [0-9A-F] to 0..15, characters in [a-f] to 42..47, and all others to 0. + * + * @param c - character to convert + * @return the converted decimal value + */ + u8 hexdigit (char c) +{ + return isxdigit (c) ? (isdigit (c) ? (c - '0') : (c - 'A' + 10)) : 0; +} + +/*! set_address -generate a device address from mac-address_str + * @param mac_address_str - sting used to generate device address + * @param dev_addr - pointer to generated device address + */ +void set_address(char *mac_address_str, u8 *dev_addr) +{ + int i; + if (mac_address_str && strlen(mac_address_str)) { + for (i = 0; i < NET_ETH_ALEN; i++) { + dev_addr[i] = + hexdigit (mac_address_str[i * 3]) << 4 | + hexdigit (mac_address_str[i * 3 + 1]); + } + } + else { + otg_get_random_bytes(dev_addr, NET_ETH_ALEN); + dev_addr[0] = (dev_addr[0] & 0xfe) | 0x02; + mac_address_str = "RANDOM"; + } + TRACE_MSG7(NTT, "net addr: %02x:%02x:%02x:%02x:%02x:%02x %s", + dev_addr[0], dev_addr[1], dev_addr[2], + dev_addr[3], dev_addr[4], dev_addr[5], + mac_address_str); +} + +/*! net_fd_function_enable - enable the function driver + * + * Called for usbd_function_enable() from usbd_register_device() + * + * @param function_instance - pointer to this function instance + * @param network_type + * @param net_recv_urb + * @param net_start_xmit + * @param net_start_recv + * @param recv_urb_flags + * + * @return int - non-zero for exception + */ + +int net_fd_function_enable (struct usbd_function_instance * function_instance, network_type_t network_type, + net_recv_urb_proc_t net_recv_urb, + net_start_xmit_proc_t net_start_xmit, + net_start_recv_proc_t net_start_recv, + u32 recv_urb_flags + ) +{ + struct usb_network_private *npd = NULL; + + /* This will link the usb_network_private structure into function_instance->privdata */ + net_os_enable(function_instance); + npd = function_instance->privdata; + + npd->network_type = network_type; + npd->net_recv_urb = net_recv_urb; + npd->net_start_xmit = net_start_xmit; + npd->net_start_recv = net_start_recv; + npd->recv_urb_flags = recv_urb_flags; + npd->override_MAC = override_MAC; + + net_os_mutex_enter(function_instance); + + #if 1 + set_address(local_dev_addr_str, npd->local_dev_addr); + + TRACE_MSG7(NTT, "net npd->local_ addr: %02x:%02x:%02x:%02x:%02x:%02x org MAC string:%s", + npd->local_dev_addr[0], npd->local_dev_addr[1], npd->local_dev_addr[2], + npd->local_dev_addr[3], npd->local_dev_addr[4], npd->local_dev_addr[5], + local_dev_addr_str); + npd->local_dev_set = TRUE; + #else + if (local_dev_addr_str && strlen(local_dev_addr_str)) { + set_address(local_dev_addr_str, npd->local_dev_addr); + npd->local_dev_set = TRUE; + } + #endif + if (remote_dev_addr_str && strlen(remote_dev_addr_str)) { + set_address(remote_dev_addr_str, npd->remote_dev_addr); + npd->remote_dev_set = TRUE; + } + + npd->have_interrupt = usbd_endpoint_bEndpointAddress(function_instance, INT_IN, + usbd_high_speed(function_instance)) ? 1 : 0; + + npd->flags |= NETWORK_ENABLED | (infrastructure_device ? NETWORK_INFRASTRUCTURE : 0); + + net_os_mutex_exit(function_instance); + CATCH(error) { + // XXX MODULE UNLOCK HERE + return -EINVAL; + } + return 0; +} + +/*! net_fd_function_disable - disable the function driver + * + * @param function_instance - pointer to function instance + * + * @return none + * + */ +void net_fd_function_disable (struct usbd_function_instance *function_instance) +{ + struct usb_network_private *npd = function_instance->privdata; + net_os_mutex_enter(function_instance); + npd->flags &= ~NETWORK_ENABLED; + net_os_mutex_exit(function_instance); + + TRACE_MSG0(NTT,"--"); + net_fd_stop (function_instance); + + if (npd->eem_os_buffer) + net_os_dealloc_buffer(function_instance, npd->eem_os_data, npd->eem_os_buffer); + + /* this will disconnect function_instance->privdata */ + net_os_disable(function_instance); + +} + +/* ********************************************************************************************** */ + +extern void net_fd_send_rarp_request(struct usbd_function_instance *function_instance); + +/*! + * net_fd_start - start network + * @param function_instance + * @return int + */ +int net_fd_start (struct usbd_function_instance *function_instance) +{ + struct usb_network_private *npd = function_instance->privdata; + int numm; + TRACE_MSG0(NTT,"entered"); + npd->flags |= NETWORK_CONFIGURED; + + if ((npd->network_type == network_blan) && (npd->flags & NETWORK_OPEN)) + net_os_send_notification_later(function_instance); + + net_os_carrier_on(function_instance); + + + /* Let the OS layer know, if it's interested. */ + net_os_config(function_instance); + net_os_hotplug(function_instance); + + /* send RARPD request if not an infrastructure device */ + #if 0 + #if defined(CONFIG_OTG_NETWORK_RARPD_AUTO_CONFIG) + UNLESS(infrastructure_device) + net_fd_send_rarp_request(function_instance); + #endif /* defined(CONFIG_OTG_NETWORK_RARPD_AUTO_CONFIG) */ + #endif + TRACE_MSG1(NTT, "CONFIGURED npd->flags: %04x", npd->flags); + return 0; +} + +/*! + * @brief net_fd_stop - stop network + * @param function_instance + * @return int + */ +int net_fd_stop (struct usbd_function_instance *function_instance) +{ + struct usb_network_private *npd = function_instance->privdata; + + TRACE_MSG0(NTT,"entered"); + + // Return if argument is null. + + // XXX flush + + npd->flags &= ~NETWORK_CONFIGURED; + npd->int_urb = NULL; + + // Disable our net-device. + // Apparently it doesn't matter if we should do this more than once. + + net_os_carrier_off(function_instance); + + // If we aren't already tearing things down, do it now. + if (!(npd->flags & NETWORK_DESTROYING)) { + npd->flags |= NETWORK_DESTROYING; + //npd->device = NULL; + } + + npd->seen_crc = 0; + + // Let the OS layer know, if it's interested. + net_os_config(function_instance); + net_os_hotplug(function_instance); + + // XXX flush + // Release any queued urbs + TRACE_MSG1(NTT, "RESET npd->flags: %04x", npd->flags); + return 0; +} + +/*! + * net_fd_set_configuration - called to indicate set configuration request was received + * @param function_instance + * @param configuration + * @return int + */ +int net_fd_set_configuration (struct usbd_function_instance *function_instance, int configuration) +{ + struct usb_network_private *npd = function_instance->privdata; + int hs = usbd_high_speed(function_instance); + + TRACE_MSG2(NTT, "CONFIGURED: %d ip_addr: %08x", configuration, npd->ip_addr); + + if (npd->eem_os_buffer) + net_os_dealloc_buffer(function_instance, npd->eem_os_data, npd->eem_os_buffer); + + npd->eem_os_data = npd->eem_os_buffer = NULL; + //npd->flags |= NETWORK_CONFIGURED; + npd->altsetting = 0; + npd->ip_addr = 0; + npd->max_recv_urbs = hs ? NETWORK_START_URBS * 3 : NETWORK_START_URBS; + + return net_fd_start(function_instance); +} + +/*! + * @brief net_fd_reset - called to indicate bus has been reset + * @param function_instance + * @return int + */ +int net_fd_reset (struct usbd_function_instance *function_instance) +{ + struct usb_network_private *npd = function_instance->privdata; + + #ifndef CONFIG_OTG_NETWORK_DOUBLE_OUT + int numm = 0; + numm = usbd_endpoint_urb_num (function_instance, BULK_OUT_A); + TRACE_MSG2(NTT,"RESET %08x urb_number: %d",npd->ip_addr, numm); + #else /* CONFIG_OTG_NETWORK_DOUBLE_OUT */ + int numm_a = 0; + int numm_b = 0; + numm_a = usbd_endpoint_urb_num (function_instance, BULK_OUT_A); + numm_b = usbd_endpoint_urb_num (function_instance, BULK_OUT_B); + TRACE_MSG3(NTT,"RESET %08x urb_number: %d:%d",npd->ip_addr, numm_a, numm_b); + #endif /* CONFIG_OTG_NETWORK_DOUBLE_OUT */ + npd->ip_addr = 0; + return net_fd_stop (function_instance); +} + + +/*! + * @brief net_fd_suspended - called to indicate bus has been suspended + * @param function_instance + * @return int + */ +int net_fd_suspended (struct usbd_function_instance *function_instance) +{ + + TRACE_MSG0(NTT, "SUSPENDED"); + return net_fd_stop (function_instance); +} + + +/*! + * net_fd_resumed - called to indicate bus has been resumed + * @param function_instance + * @return int + */ +int net_fd_resumed (struct usbd_function_instance *function_instance) +{ + //struct usbd_interface_instance *interface_instance = (struct usbd_interface_instance *)function_instance; + + TRACE_MSG0(NTT, "RESUMED"); + return net_fd_start(function_instance); +} + + + +/* ********************************************************************************************** */ + +#if 0 +/*! macstrtest - + */ +static int macstrtest(char *mac_address_str) +{ + int l = 0; + + if (mac_address_str) { + l = strlen(mac_address_str); + } + return ((l != 0) && (l != 12)); +} +#endif + +/*! + * @brief net_fd_init - function driver usb part intialization + * + * @param info_str + * @param local + * @param remote + * @param override_mac + * @param override_personal + * @param override_infrastructure + * @return non-zero for failure. + */ +int net_fd_init(char *info_str, char *local, char *remote, BOOL override_mac, BOOL override_personal, BOOL override_infrastructure) +{ + local_dev_addr_str = local; + remote_dev_addr_str = remote; + if (override_mac) override_MAC= TRUE; + #if defined(OTG_NETWORK_INFRASTRUCTURE) + infrastructure_device = !override_personal; + #else /* defined(OTG_NETWORK_INFRASTRUCTURE) */ + infrastructure_device = override_infrastructure; + #endif /* defined(OTG_NETWORK_INFRASTRUCTURE) */ + + TRACE_MSG3(NTT, "local: %s remote: %s Mode; %s Device", + local_dev_addr_str ? local_dev_addr_str : "", + remote_dev_addr_str ? remote_dev_addr_str : "", + infrastructure_device ? "Infrastructure" : "Personal" + ); + + return make_crc_table(); +} + +/*! + * @brief net_fd_exit - driver exit + * + * Cleans up the module. Deregisters the function driver and destroys the network object. + */ +void net_fd_exit(void) +{ + if (network_crc32_table) { + lkfree(network_crc32_table); + network_crc32_table = NULL; + } +} |