int blan_start_recv_endpoint(struct usbd_function_instance *function_instance, int endpoint_index, otg_atomic_t *recv_urbs_started, char *msg) { struct usb_network_private *npd = function_instance->privdata; int i; int hs = usbd_high_speed(function_instance); int alloc_length = usbd_endpoint_transferSize(function_instance, endpoint_index, hs); if (TRACE_VERBOSE) TRACE_MSG4(NTT, "endpoint_index: %d recv_urbs_started: %d alloc_length: %d %s", endpoint_index, otg_atomic_read(recv_urbs_started), alloc_length, msg); while (otg_atomic_read(recv_urbs_started) < npd->max_recv_urbs ) { u8 *os_buffer = NULL; void *os_data = NULL; struct usbd_urb *urb; #ifdef DEBUG_CRC_SEEN if (npd->seen_crc_error) { TRACE_MSG0(NTT, "CRC ERROR NOT RESTARTING"); break; } #endif /* DEBUG_CRC_SEEN */ /* get os buffer - os_buffer is data, os_data is the os data structure */ os_data = net_os_alloc_buffer(function_instance, &os_buffer, alloc_length); /* allocate urb with no buffer */ /*allocate urb without buffer */ urb = usbd_alloc_urb(function_instance, endpoint_index, 0, net_fd_recv_urb2); /* start urb with buffer pointing at the os_buffer in os_data structure */ if (os_buffer && urb) { urb->function_privdata = os_data; urb->buffer = os_buffer; urb->flags |= npd->recv_urb_flags; urb->alloc_length = urb->buffer_length = alloc_length; if (usbd_start_out_urb(urb)) { net_os_dealloc_buffer(function_instance, os_data, os_buffer); urb->function_privdata = NULL; urb->buffer = NULL; usbd_free_urb(urb); } otg_atomic_inc(recv_urbs_started); continue; } TRACE_MSG1(NTT, "recv_urbs_started: %d FAILED EARLY", otg_atomic_read(recv_urbs_started)); if (os_buffer || os_data) net_os_dealloc_buffer(function_instance, os_data, os_buffer); if (urb) urb->buffer = NULL; usbd_free_urb(urb); break; } if (TRACE_VERBOSE) TRACE_MSG1(NTT, "recv_urbs_started: %d", otg_atomic_read(recv_urbs_started)); return 0; }
/*! net_fd_start_recv_ecm - start recv urb(s) * * @param function_instance - pointer to this function instance * @return none */ int net_fd_start_recv_ecm(struct usbd_function_instance *function_instance) { struct usb_network_private *npd = function_instance->privdata; int i; int network_start_urbs = NETWORK_START_URBS; int hs = usbd_high_speed(function_instance); int endpoint_index = BULK_OUT_A; if (hs) network_start_urbs = NETWORK_START_URBS * 3; for (i = 0; i < network_start_urbs; i++) { struct usbd_urb *urb; BREAK_IF(!(urb = usbd_alloc_urb(function_instance, endpoint_index, usbd_endpoint_transferSize(function_instance, endpoint_index, hs), net_fd_recv_urb))); TRACE_MSG5(NTT,"i: %d urb: %p priv: %p npd: %p function: %p", i, urb, urb->function_privdata, npd, function_instance); //urb->function_privdata = npd; if (usbd_start_out_urb(urb)) { urb->function_privdata = NULL; usbd_free_urb(urb); } } return 0; }
/*! net_fd_recv_urb2 - 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_urb2(struct usbd_urb *urb, int rc) { struct usbd_function_instance *function_instance = urb->function_instance; struct usb_network_private *npd = function_instance->privdata; int hs = usbd_high_speed(function_instance); int endpoint_index = urb->endpoint_index; #ifndef CONFIG_OTG_NETWORK_DOUBLE_OUT int recv_index = 0; #else /* CONFIG_OTG_NETWORK_DOUBLE_OUT */ int recv_index = (endpoint_index == BULK_OUT_A) ? 0 : 1; #endif /* CONFIG_OTG_NETWORK_DOUBLE_OUT */ int alloc_length = usbd_endpoint_transferSize(function_instance, endpoint_index, hs); int status = urb->status; void *os_data; u8 *os_buffer; if (TRACE_VERY_VERBOSE) { TRACE_MSG4(NTT, "status: %d actual_length: %d bus status: %d device_state: %d", urb->status, urb->actual_length, usbd_get_device_status(function_instance), usbd_get_device_state(function_instance) ); TRACE_NRECV(NTT, 32, urb->buffer); TRACE_MSG0(NTT, "--"); TRACE_RECV(NTT, urb->actual_length, urb->buffer); } otg_atomic_dec(&npd->recv_urbs_started[recv_index]); /* process the data */ if (urb->status == USBD_URB_OK) npd->net_recv_urb(urb, rc); if (urb->status == USBD_URB_CANCELLED) net_os_dealloc_buffer(function_instance, urb->function_privdata, urb->buffer); /* disconnect os_data buffer from urb */ urb->function_privdata = NULL; urb->buffer = NULL; urb->function_instance = NULL; urb->status = USBD_URB_OK; usbd_free_urb(urb); if ((USBD_OK == usbd_get_device_status(function_instance)) && (STATE_CONFIGURED == usbd_get_device_state(function_instance))) { blan_start_recv(function_instance); } else { TRACE_MSG0(NTT, "NOT RESTARTING"); } return 0; }
/*! net_fd_start_xmit_nocrc * @brief - start sending a buffer * * @param function_instance - pointer to this function instance * @param buffer buffer containing data to send * @param len - length of data to send * @param data instance 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_nocrc (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; int in_pkt_sz; u8 *cp; u32 crc; #ifndef CONFIG_OTG_NETWORK_DOUBLE_IN int xmit_index = 0; int endpoint_index = BULK_IN_A; #else /* CONFIG_OTG_NETWORK_DOUBLE_IN */ int xmit_index = (otg_atomic_read(&npd->xmit_urbs_started[0]) <= otg_atomic_read(&npd->xmit_urbs_started[1])) ? 0 : 1; int endpoint_index = (xmit_index) ? BULK_IN_B : BULK_IN_A; #endif /* CONFIG_OTG_NETWORK_DOUBLE_IN */ TRACE_MSG7(NTT,"npd: %p function: %p flags: %04x len: %d endpoint_index: %d xmit_started: %d %d", npd, function_instance, npd->flags, len, endpoint_index, otg_atomic_read(&npd->xmit_urbs_started[0]), otg_atomic_read(&npd->xmit_urbs_started[1])); in_pkt_sz = usbd_endpoint_wMaxPacketSize(function_instance, endpoint_index, usbd_high_speed(function_instance)); /* allocate urb 5 bytes larger than required */ if (!(urb = usbd_alloc_urb (function_instance, endpoint_index, len + 5 + in_pkt_sz, net_fd_urb_sent_bulk ))) { u8 epa = usbd_endpoint_bEndpointAddress(function_instance, endpoint_index, usbd_high_speed(function_instance)); TRACE_MSG2(NTT,"urb alloc failed len: %d endpoint: %02x", len, epa); printk(KERN_ERR"%s: urb alloc failed len: %d endpoint: %02x\n", __FUNCTION__, len, epa); return -ENOMEM; } urb->actual_length = len; memcpy (urb->buffer, buffer, len); urb->function_privdata = data; urb->actual_length = len; otg_atomic_add(urb->actual_length, &npd->queued_bytes); otg_atomic_inc(&npd->xmit_urbs_started[xmit_index]); if ((rc = usbd_start_in_urb (urb))) { TRACE_MSG1(NTT,"FAILED: %d", rc); printk(KERN_ERR"%s: FAILED: %d\n", __FUNCTION__, rc); urb->function_privdata = NULL; otg_atomic_sub(urb->actual_length, &npd->queued_bytes); otg_atomic_dec(&npd->xmit_urbs_started[xmit_index]); usbd_free_urb (urb); return rc; } return 0; }
/* Comment : Must be called before any other devi_hid... function */ void devi_unregister_usb_client(void * h) { int rc; pModule_data_t pModule = (pModule_data_t)h; struct timespec t; assert(pModule); if(pModule -> ep_int) { usbd_reset_pipe(pModule -> ep_int); usbd_abort_pipe(pModule -> ep_int); } if(pModule -> ep_cntl) usbd_abort_pipe(pModule -> ep_cntl); if(pModule -> urb) usbd_free_urb(pModule -> urb); if(pModule -> ep_int_buf) usbd_free(pModule -> ep_int_buf); if(pModule -> ep_cnt_buf) usbd_free(pModule -> ep_cnt_buf); sleep(1); if(EOK != (rc = usbd_detach(pModule -> pDevice))) { if(verbosity) fprintf(stderr, "Detach device: error %i\n", rc); } clock_gettime(CLOCK_REALTIME, &t); t.tv_sec += MAX_TIME_WAIT; if(EOK != pthread_mutex_timedlock(&mod_mutex, &t)) return ; LIST_REMOVE(pModule, lst_conn); pthread_mutex_unlock(&mod_mutex); free(pModule); }
/* Return : None */ void removal( struct usbd_connection * pConnection, usbd_device_instance_t * pInstance ) { struct usbd_device * pDevice; pModule_data_t pModule; int rc; if(NULL != ( pDevice = usbd_device_lookup( pConnection, pInstance ))) { pModule = usbd_device_extra( pDevice ); if( pModule -> ep_int ) { // Stop the Interrupt In endpoint usbd_abort_pipe( pModule -> ep_int ); // Abort pipe usbd_free_urb( pModule -> urb ); // Free request block usbd_free( pModule -> ep_int_buf ); if( rc = usbd_detach( pModule -> pDevice ) ) fprintf( stderr, "usbd_detach %i\n", rc ); } } }
/* Return : EOK if ok, error code on error */ int devi_output_control(void * pHandle, pControlRequest pRequest, void * data, int nLen) { int rc = EOK; struct usbd_urb * pUrb; void * pLocalData = NULL; pModule_data_t pModule = (pModule_data_t)pHandle; if(NULL == pModule -> ep_cntl) return EINVAL; if((pRequest -> dir & URB_DIR_OUT) && (nLen > pModule -> ep_cnt_size)) // Too big buffer return EINVAL; if( pUrb = usbd_alloc_urb( NULL ) ) // Allocate request block { if((pRequest -> dir & URB_DIR_OUT) && (NULL != data) && (nLen > 0) ) memcpy(pModule -> ep_cnt_buf, data, nLen); // Take data to USB -allocated buffer // Setup vendor request block usbd_setup_vendor( pUrb, pRequest -> dir, // Direction pRequest -> req, // Device specific request pRequest -> type | pRequest -> rec, // Type | recipient pRequest -> value, // Request specific pRequest -> index, // Request specific pModule -> ep_cnt_buf, nLen ); rc = usbd_io( pUrb, pModule -> ep_cntl, NULL, pModule, USBD_TIME_INFINITY ) ; // Delete request block usbd_free_urb( pUrb ); if((pRequest -> dir & URB_DIR_IN) && (EOK == rc)) // Take data from USB -allocated buffer memcpy(data, pLocalData, min(nLen, pModule -> ep_cnt_size)); } else rc = ENOMEM; return( rc ); }
/*! blan_fd_device_request * @brief 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 this function instance * @param request - received request to interface or endpoint * @return non-zero for failure. */ int blan_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))); /* Determine the request direction and process accordingly */ switch (request->bmRequestType & (USB_REQ_DIRECTION_MASK | USB_REQ_TYPE_MASK)) { case USB_REQ_HOST2DEVICE | USB_REQ_TYPE_VENDOR: switch (request->bRequest) { case MCCI_ENABLE_CRC: //if (make_crc_table()) // return -EINVAL; //npd->encapsulation = simple_crc; return 0; case BELCARRA_PING: TRACE_MSG1(NTT,"H2D VENDOR IP: %08x", npd->ip_addr); if ((npd->network_type == network_blan)) net_os_send_notification_later(function_instance); break; #if !defined(CONFIG_OTG_NETWORK_BLAN_DO_NOT_SETTIME) || !defined(CONFIG_OTG_NETWORK_SAFE_DO_NOT_SETTIME) case BELCARRA_SETTIME: npd->rfc868time = ntohl( request->wValue << 16 | request->wIndex); net_os_settime(function_instance, npd->rfc868time); break; #endif case BELCARRA_SETIP: #ifdef OTG_BIG_ENDIAN npd->ip_addr = ntohl( request->wValue | request->wIndex<< 16 ); #else /* OTG_BIG_ENDIAN */ npd->ip_addr = ntohl( request->wValue << 16 | request->wIndex); #endif /* OTG_BIG_ENDIAN */ TRACE_MSG1(NTT, "npd->ip_addr: %08x", npd->ip_addr); // XXX need to get in correct order here // XXX what about locally set mac addr // XXX UNLESS(npd->local_dev_set) { if (!(npd->override_MAC)) { npd->local_dev_addr[0] = 0xfe | 0x02; /* locally administered */ npd->local_dev_addr[1] = 0x00; npd->local_dev_addr[2] = (npd->ip_addr >> 24) & 0xff; npd->local_dev_addr[3] = (npd->ip_addr >> 16) & 0xff; npd->local_dev_addr[4] = (npd->ip_addr >> 8) & 0xff; npd->local_dev_addr[5] = (npd->ip_addr >> 0) & 0xff; } // XXX } break; case BELCARRA_SETMSK: #ifdef OTG_BIG_ENDIAN npd->network_mask = ntohl( request->wValue | request->wIndex << 16); #else /* OTG_BIG_ENDIAN */ npd->network_mask = ntohl( request->wValue << 16 | request->wIndex); #endif /* OTG_BIG_ENDIAN */ TRACE_MSG1(NTT, "npd->network_mask: %08x", npd->network_mask); break; case BELCARRA_SETROUTER: #ifdef OTG_BIG_ENDIAN npd->router_ip = ntohl( request->wValue | request->wIndex << 16); #else /* OTG_BIG_ENDIAN */ npd->router_ip = ntohl( request->wValue << 16 | request->wIndex); #endif /* OTG_BIG_ENDIAN */ TRACE_MSG1(NTT, "npd->router_ip: %08x", npd->router_ip); break; case BELCARRA_SETDNS: #ifdef OTG_BIG_ENDIAN npd->dns_server_ip = ntohl( request->wValue | request->wIndex < 16); #else /* OTG_BIG_ENDIAN */ npd->dns_server_ip = ntohl( request->wValue << 16 | request->wIndex); #endif /* OTG_BIG_ENDIAN */ break; #ifdef CONFIG_OTG_NETWORK_BLAN_FERMAT case BELCARRA_SETFERMAT: npd->fermat = 1; break; #endif #ifdef CONFIG_OTG_NETWORK_BLAN_HOSTNAME case BELCARRA_HOSTNAME: TRACE_MSG0(NTT,"HOSTNAME"); RETURN_EINVAL_IF(!(urb = usbd_alloc_urb_ep0(function_instance, le16_to_cpu(request->wLength), blant_fd_urb_received_ep0) )); RETURN_ZERO_IF(!usbd_start_out_urb(urb)); // return if no error usbd_free_urb(urb); // de-alloc if error return -EINVAL; #endif #ifdef CONFIG_OTG_NETWORK_BLAN_DATA_NOTIFY_OK case BELCARRA_DATA_NOTIFY: TRACE_MSG0(NTT,"DATA NOTIFY"); npd->data_notify = 1; return -EINVAL; #endif } switch (request->bRequest) { case BELCARRA_SETIP: case BELCARRA_SETMSK: case BELCARRA_SETROUTER: TRACE_MSG5(NTT, "npd->network_mask: %08x npd->ip_addr: %08x npd->router_ip: %08x flags: %08x %s", npd->network_mask, npd->ip_addr, npd->router_ip, npd->flags, (npd->flags & NETWORK_CONFIGURED) ? "CONFIGURED" : ""); BREAK_UNLESS (npd->network_mask && npd->ip_addr && npd->router_ip && (npd->flags & NETWORK_CONFIGURED)); // let the os layer know, if it's interested. #ifdef CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG net_os_config(function_instance); net_os_hotplug(function_instance); #endif /* CONFIG_OTG_NETWORK_BLAN_AUTO_CONFIG */ break; } return 0; default: break; }
/*! net_fd_start_xmit_mdlm * @brief - start sending a buffer * * @param function_instance - function instance pointer * @param buffer * @param len * @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_mdlm (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; u32 crc; #ifndef CONFIG_OTG_NETWORK_DOUBLE_IN int xmit_index = 0; int endpoint_index = BULK_IN_A; #else /* CONFIG_OTG_NETWORK_DOUBLE_IN */ int xmit_index = (otg_atomic_read(&npd->xmit_urbs_started[0]) <= otg_atomic_read(&npd->xmit_urbs_started[1])) ? 0 : 1; int endpoint_index = (xmit_index) ? BULK_IN_B : BULK_IN_A; #endif /* CONFIG_OTG_NETWORK_DOUBLE_IN */ int in_pkt_sz = usbd_endpoint_wMaxPacketSize(function_instance, xmit_index, usbd_high_speed(function_instance)); if (TRACE_VERBOSE) TRACE_MSG8(NTT,"npd: %p flags: %04x len: %d endpoint_index: %d " "xmit_index: %d xmit_started: %d %d in_pkt_sz: %d", npd, npd->flags, len, endpoint_index, xmit_index, otg_atomic_read(&npd->xmit_urbs_started[0]), otg_atomic_read(&npd->xmit_urbs_started[1]), in_pkt_sz); #if defined(CONFIG_OTG_NETWORK_BLAN_CRC) || defined(CONFIG_OTG_NETWORK_SAFE_CRC) /* allocate urb 5 bytes larger than required */ if (!(urb = usbd_alloc_urb (function_instance, endpoint_index, len + 5 + 4 + in_pkt_sz, net_fd_urb_sent_bulk ))) { u8 epa = usbd_endpoint_bEndpointAddress(function_instance, endpoint_index, usbd_high_speed(function_instance)); TRACE_MSG2(NTT,"urb alloc failed len: %d endpoint: %02x", len, epa); return -ENOMEM; } urb->actual_length = len; /* copy and crc len bytes */ crc = crc32_copy(urb->buffer, buffer, len, CRC32_INIT); if ((urb->actual_length % in_pkt_sz) == (in_pkt_sz - 4)) { /* no longer in Kconfig - change undef to define to active padbyte */ #undef CONFIG_OTG_NETWORK_PADBYTE #ifdef CONFIG_OTG_NETWORK_PADBYTE // add a pad byte if required to ensure a short packet, usbdnet driver // will correctly handle pad byte before or after CRC, but the MCCI driver // wants it before the CRC. crc = crc32_pad(urb->buffer + urb->actual_length, 1, crc); urb->actual_length++; #else /* CONFIG_OTG_NETWORK_PADBYTE */ urb->flags |= USBD_URB_SENDZLP; TRACE_MSG2(NTT,"setting ZLP: urb: %p flags: %x", urb, urb->flags); #endif /* CONFIG_OTG_NETWORK_PADBYTE */ } crc = ~crc; urb->buffer[urb->actual_length++] = crc & 0xff; urb->buffer[urb->actual_length++] = (crc >> 8) & 0xff; urb->buffer[urb->actual_length++] = (crc >> 16) & 0xff; urb->buffer[urb->actual_length++] = (crc >> 24) & 0xff; #if defined(CONFIG_OTG_NETWORK_BLAN_FERMAT) if (npd->fermat) fermat_encode(urb->buffer, urb->actual_length); #endif #else /* defined(CONFIG_OTG_NETWORK_BLAN_CRC) ...*/ /* allocate urb with no buffer */ #ifdef CONFIG_OTG_NETWORK_XMIT_OS if (!(urb = usbd_alloc_urb (function_instance, endpoint_index, 0, net_fd_urb_sent_bulk ))) { u8 epa = usbd_endpoint_bEndpointAddress(function_instance, endpoint_index, usbd_high_speed(function_instance)); TRACE_MSG2(NTT,"urb alloc failed len: %d endpoint: %02x", len, epa); return -ENOMEM; } urb->actual_length = len; urb->buffer = buffer; #else /* CONFIG_OTG_NETWORK_XMIT_OS */ if (!(urb = usbd_alloc_urb (function_instance, endpoint_index, len + 5 + 4 + in_pkt_sz, net_fd_urb_sent_bulk ))) { u8 epa = usbd_endpoint_bEndpointAddress(function_instance, endpoint_index, usbd_high_speed(function_instance)); TRACE_MSG2(NTT,"urb alloc failed len: %d endpoint: %02x", len, epa); printk(KERN_ERR"%s: urb alloc failed len: %d endpoint: %02x\n", __FUNCTION__, len, epa); return -ENOMEM; } urb->actual_length = len; memcpy (urb->buffer, buffer, len); #endif /* CONFIG_OTG_NETWORK_XMIT_OS */ urb->flags |= ((urb->actual_length % in_pkt_sz) == 0) ? USBD_URB_SENDZLP : 0; #endif /* defined(CONFIG_OTG_NETWORK_BLAN_CRC) ...*/ if (TRACE_VERBOSE) TRACE_MSG3(NTT,"urb: %p buf: %p priv: %p", urb, data, urb->function_privdata); urb->function_privdata = data; otg_atomic_add(urb->actual_length, &npd->queued_bytes); otg_atomic_inc(&npd->xmit_urbs_started[xmit_index]); if ((rc = usbd_start_in_urb (urb))) { TRACE_MSG1(NTT,"FAILED: %d", rc); printk(KERN_ERR"%s: FAILED: %d\n", __FUNCTION__, rc); urb->function_privdata = NULL; otg_atomic_sub(urb->actual_length, &npd->queued_bytes); otg_atomic_dec(&npd->xmit_urbs_started[xmit_index]); usbd_free_urb (urb); return rc; } return 0; }