blob: 5f841ffcce2d18d8fed8999d88b16dd38cb9ba5a [file] [log] [blame]
/*
* f_rdp.c -- USB ramdump driver
* (C) Copyright 2017 ASR Microelectronics (Shanghai) Co., Ltd.
* All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <errno.h>
#include <common.h>
#include <malloc.h>
#include <version.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/composite.h>
#include <linux/compiler.h>
#include <asm/sizes.h>
#ifdef CONFIG_RAMDUMP
#include <../../../board/Marvell/common/ramdump.h>
#endif
#define DATA_BLOCK_LEN (512 * 7)
#define USB_REG_BUF_LEN (256)
#define DWC3_USB_REG_BUF_LEN (512)
struct rd_ram_desc {
unsigned signature;
unsigned long textsize;
unsigned long addr;
unsigned long datasize;
};
struct rdp_dev {
struct usb_gadget *gadget;
struct usb_request *req;
struct usb_ep *in_ep, *out_ep;
struct usb_request *in_req, *out_req;
unsigned char configuration_done;
unsigned char rxdata;
unsigned char txdata;
};
struct f_rdp {
struct usb_function usb_function;
struct rdp_dev *dev;
};
static struct usb_interface_descriptor rdp_intf_data = {
.bLength = sizeof(rdp_intf_data),
.bDescriptorType = USB_DT_INTERFACE,
.bNumEndpoints = 2,
.bInterfaceClass = 0xff,
.bInterfaceSubClass = 0xff,
.bInterfaceProtocol = 0xff,
};
static struct usb_endpoint_descriptor fs_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
static struct usb_endpoint_descriptor fs_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
static struct usb_endpoint_descriptor hs_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = __constant_cpu_to_le16(512),
};
static struct usb_endpoint_descriptor hs_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = __constant_cpu_to_le16(512),
};
static const struct usb_descriptor_header *hs_rdp_data_function[] = {
(struct usb_descriptor_header *)&rdp_intf_data,
(struct usb_descriptor_header *)&hs_in_desc,
(struct usb_descriptor_header *)&hs_out_desc,
NULL,
};
static const struct usb_descriptor_header *fs_rdp_data_function[] = {
(struct usb_descriptor_header *)&rdp_intf_data,
(struct usb_descriptor_header *)&fs_in_desc,
(struct usb_descriptor_header *)&fs_out_desc,
NULL,
};
static struct f_rdp *rdp_func;
static inline struct f_rdp *func_to_rdp(struct usb_function *f)
{
return container_of(f, struct f_rdp, usb_function);
}
static inline struct usb_endpoint_descriptor *
ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
struct usb_endpoint_descriptor *fs)
{
printf("dualspeed(g): %d, g->speed: 0x%x\n",
gadget_is_dualspeed(g), g->speed);
if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
return hs;
return fs;
}
//#define RDP_DEBUG_MODE
#ifdef RDP_DEBUG_MODE
#define log_debug(fmt,args...) printf(fmt ,##args)
#else
#define log_debug(fmt,args...) do {}while(0)
#endif
/*-------------------------------------------------------------------------*/
__weak int host_os_is_linux(void) {return true;}
__weak int host_os_is_known(void) {return false;}
static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
{
struct usb_request *req;
req = usb_ep_alloc_request(ep, 0);
if (!req)
return req;
req->length = length;
req->buf = memalign(64, length);
if (!req->buf) {
usb_ep_free_request(ep, req);
req = NULL;
}
return req;
}
static int rdp_rx_data(void)
{
struct rdp_dev *dev = rdp_func->dev;
int rx_data_len, status;
/* int delay_us = (2000 * 1000 / 50); */
#if defined(CONFIG_USB_DWC3) || defined(CONFIG_USB_GADGET_DWC2_OTG)
rx_data_len = dev->out_req->length = DWC3_USB_REG_BUF_LEN;
#else
rx_data_len = dev->out_req->length = USB_REG_BUF_LEN;
#endif
log_debug("dev->out_req->length:%d dev->rxdata:%d, dev->out_req->buf: 0x%x\n",
dev->out_req->length, dev->rxdata, (u32)dev->out_req->buf);
status = usb_ep_queue(dev->out_ep, dev->out_req, 0);
if (status) {
error("kill %s: resubmit %d bytes --> %d",
dev->out_ep->name, dev->out_req->length, status);
usb_ep_set_halt(dev->out_ep);
return -EAGAIN;
}
while (!dev->rxdata/* && (delay_us--) */) {
udelay(50);
#ifdef CONFIG_USB_DWC3
dwc3_uboot_handle_interrupt(0);
#else
usb_gadget_handle_interrupts();
#endif
if (ctrlc())
return -1;
}
/*
if (delay_us <= 0) {
printf("waiting for Host request timeout\n");
return -1;
}
*/
dev->rxdata = 0;
printf("usb rcv %d bytes\n", dev->out_req->actual);
return 0;
}
void rdp_tx_data(unsigned char *data, int len)
{
struct rdp_dev *dev = rdp_func->dev;
unsigned char *ptr = dev->in_req->buf;
int status;
memcpy(ptr, data, len);
dev->in_req->length = len;
log_debug("%s: dev->in_req->length:%d to_cpy:%d\n", __func__,
dev->in_req->length, sizeof(data));
status = usb_ep_queue(dev->in_ep, dev->in_req, 0);
if (status) {
error("kill %s: resubmit %d bytes --> %d",
dev->in_ep->name, dev->in_req->length, status);
usb_ep_set_halt(dev->in_ep);
}
/* Wait until tx interrupt received */
while (!dev->txdata) {
#ifdef CONFIG_USB_DWC3
dwc3_uboot_handle_interrupt(0);
#else
usb_gadget_handle_interrupts();
#endif
}
dev->txdata = 0;
}
void rdp_tx_data_ptr(unsigned char *data, int len)
{
struct rdp_dev *dev = rdp_func->dev;
unsigned char *ptr = dev->in_req->buf;
unsigned length = dev->in_req->length;
int status;
dev->in_req->length = len;
dev->in_req->buf = data;
log_debug("%s: buf: 0x%x, len: %d\n", __func__,
dev->in_req->buf, dev->in_req->length);
status = usb_ep_queue(dev->in_ep, dev->in_req, 0);
if (status) {
error("kill %s: resubmit %d bytes --> %d",
dev->in_ep->name, dev->in_req->length, status);
usb_ep_set_halt(dev->in_ep);
}
/* Wait until tx interrupt received */
while (!dev->txdata) {
#ifdef CONFIG_USB_DWC3
dwc3_uboot_handle_interrupt(0);
#else
usb_gadget_handle_interrupts();
#endif
}
dev->txdata = 0;
dev->in_req->buf = ptr;
dev->in_req->length = length;
}
static void rdp_rx_tx_complete(struct usb_ep *ep, struct usb_request *req)
{
struct rdp_dev *dev = rdp_func->dev;
int status = req->status;
log_debug("%s: ep_ptr:%p, req_ptr:%p\n", __func__, ep, req);
switch (status) {
case 0:
if (ep == dev->out_ep)
dev->rxdata = 1;
else
dev->txdata = 1;
break;
/* this endpoint is normally active while we're configured */
case -ECONNABORTED: /* hardware forced ep reset */
case -ECONNRESET: /* request dequeued */
case -ESHUTDOWN: /* disconnect from host */
case -EREMOTEIO: /* short read */
case -EOVERFLOW:
error("ERROR:%d", status);
break;
}
log_debug("%s complete --> %d, %d/%d\n", ep->name,
status, req->actual, req->length);
}
static struct usb_request *rdp_start_ep(struct usb_ep *ep)
{
struct usb_request *req;
#if defined(CONFIG_USB_DWC3) || defined(CONFIG_USB_GADGET_DWC2_OTG)
req = alloc_ep_req(ep, DWC3_USB_REG_BUF_LEN);
#else
req = alloc_ep_req(ep, USB_REG_BUF_LEN);
#endif
log_debug("%s: ep:%p req:%p\n", __func__, ep, req);
if (!req)
return NULL;
memset(req->buf, 0, req->length);
req->complete = rdp_rx_tx_complete;
return req;
}
static void rdp_setup_complete(struct usb_ep *ep, struct usb_request *req)
{
if (req->status || req->actual != req->length)
log_debug("setup complete --> %d, %d/%d\n",
req->status, req->actual, req->length);
}
static int
rdp_func_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
{
struct rdp_dev *dev = rdp_func->dev;
struct usb_request *req = dev->req;
struct usb_gadget *gadget = dev->gadget;
int value = 0;
u16 len = le16_to_cpu(ctrl->wLength);
log_debug("Req_Type: 0x%x Req: 0x%x wValue: 0x%x wIndex: 0x%x wLen: 0x%x\n",
ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, ctrl->wIndex,
ctrl->wLength);
return value;
}
int rdp_init(int rdp_type)
{
int timeout;
int loops = 1;
struct rdp_dev *dev = rdp_func->dev;
struct usb_gadget *gadget = dev->gadget;
#ifdef CONFIG_DUMP2PC_IN_UBOOT
printf("ramdump: CONFIG_DUMP2PC_IN_UBOOT enabled\n");
#endif
if (!usb_vbus_is_online()) {
udc_disconnect();
printf("vbus offline, return and boot to linux\n");
return 0;
}
/* Wait for a device enumeration and configuration settings */
printf("waiting for enum done....\n");
timeout = (2500 * 1000 / 50); //waiting for 3s
while (!dev->configuration_done && (timeout--)) {
#ifdef CONFIG_USB_DWC3
dwc3_uboot_handle_interrupt(0);
#else
usb_gadget_handle_interrupts();
#endif
udelay(50);
/*
* do not wait for handshaking with non-linux os, as handshake is
* is only needed with CPE version rdp_transfer
*/
if (!host_os_is_linux() && host_os_is_known()) {
udc_disconnect();
printf("returns to rdp for non-linux os\n");
return 0;
}
}
if (timeout <= 0) {
printf("waiting for enum done2....\n");
while(loops--) {
usb_gadget_disconnect(gadget);
udelay(50);
usb_gadget_connect(gadget);
timeout = (5000 * 1000 / 50); //waiting for 3s
while (!dev->configuration_done && (timeout--)) {
#ifdef CONFIG_USB_DWC3
dwc3_uboot_handle_interrupt(0);
#else
usb_gadget_handle_interrupts();
#endif
udelay(50);
/*
* do not wait for handshaking with non-linux os, as handshake is
* is only needed with CPE version rdp_transfer
*/
if (!host_os_is_linux() && host_os_is_known()) {
udc_disconnect();
printf("returns with non-linux os\n");
return 0;
}
}
if (timeout > 0)
break;
/* force to quit the while loop if linux is detected */
if (host_os_is_linux() && timeout <= 0) {
timeout = 1;
break;
}
if (ctrlc())
return -1;
}
}
if (timeout <= 0) {
printf("usb enum timeout\n");
return -1;
}
printf("usb enum done....\n");
if (!host_os_is_linux()) {
udc_disconnect();
printf("returns with non-linux os\n");
return 0;
}
/* wait for HOST request */
if (rdp_rx_data() < 0) {
printf("%s: rdp_rx_data failed!\n", __func__);
return -1;
}
if (!strncmp((char *)dev->out_req->buf, "rdp_upload", strlen("rdp_upload"))) {
puts("get rdp_upload\n");
udelay(30 * 1000); /* 30 ms */
} else {
puts("err reply\n");
return -1;
}
if (rdp_type == RDP_RAMDUMP) {
printf("send rdp_ramdump to AP\n");
//send text to host
rdp_tx_data("rdp_ramdump", 11);
} else {
printf("send rdp_cpassert to AP\n");
//send text to host
rdp_tx_data("rdp_cpassert", 12);
}
return 0;
}
int rdp_process_data(struct rd_ram_desc *desc)
{
unsigned char * addr = desc->addr;
struct rdp_dev *dev = rdp_func->dev;
u32 data_len = desc->datasize;
u32 data_in_len = 0, idx = 0;
u32 total_data_len = 0;
int need_zero_pkt = 0;
printf("send rdp_done to AP\n");
//send text to host
rdp_tx_data("rdp_done", 8);
/* wait for HOST to request text */
printf("getting rdp_text\n");
if (rdp_rx_data() < 0) {
printf("%s: rdp_rx_data err!\n", __func__);
return -1;
}
if (!strncmp((char *)dev->out_req->buf, "rdp_text", strlen("rdp_text"))) {
puts("get rdp_text\n");
udelay(30 * 1000); /* 30 ms */
} else {
puts("Wrong reply\n");
return -1;
}
printf("data addr: 0x%x %d\n", addr, desc->textsize);
rdp_tx_data(addr, desc->textsize);
total_data_len += desc->textsize;
/* wait for HOST to request data */
printf("Getting rdp_data\n");
if (rdp_rx_data() < 0) {
printf("%s: rdp_rx_data err!\n", __func__);
return -1;
}
if (!strncmp((char *)dev->out_req->buf, "rdp_data", strlen("rdp_data"))) {
puts("get rdp_data\n");
udelay(30 * 1000); /* 30 ms */
} else {
puts("Wrong reply\n");
return -1;
}
//rdp_tx_data(&data_len, sizeof(data_len));
need_zero_pkt = ((data_len % DATA_BLOCK_LEN) == 0);
addr = addr + desc->textsize;
printf("data addr: 0x%x\n", addr);
while(data_len) {
if (data_len >= DATA_BLOCK_LEN) {
rdp_tx_data_ptr(addr + data_in_len, DATA_BLOCK_LEN);
data_in_len += DATA_BLOCK_LEN;
data_len -= DATA_BLOCK_LEN;
total_data_len += DATA_BLOCK_LEN;
} else {
rdp_tx_data_ptr(addr + data_in_len, data_len);
data_in_len += data_len;
total_data_len += data_len;
data_len = 0;
}
idx++;
if ((idx % 3000) == 0)
printf("sending 0x%x bytes now\n", idx * DATA_BLOCK_LEN);
}
if (need_zero_pkt) {
printf("zero pkt\n");
rdp_tx_data_ptr(addr, 0);
}
printf("!! tx data done - total: 0x%x bytes, left: 0x%x bytes\n\n",
total_data_len, data_len);
udc_disconnect();
mdelay(3000);
return 0;
}
int rdp_process_cpassert_data(u8 *data_addr, int size)
{
unsigned char * addr = data_addr;
u32 data_len = size;
struct rdp_dev *dev = rdp_func->dev;
u32 data_in_len = 0, idx = 0, total_data_len = 0;
int need_zero_pkt = 0;
printf("send rdp_cp_done to AP\n");
//send text to host
rdp_tx_data("rdp_cp_done", 11);
need_zero_pkt = ((size % DATA_BLOCK_LEN) == 0);
/* wait for HOST to request text */
printf("Getting rdp_cpassert\n");
if (rdp_rx_data() < 0) {
printf("%s: rdp_rx_data err!\n", __func__);
return -1;
}
if (!strncmp((char *)dev->out_req->buf, "rdp_cpassert", strlen("rdp_cpassert"))) {
puts("get rdp_cpassert\n");
udelay(30 * 1000); /* 30 ms */
} else {
puts("Wrong reply\n");
return -1;
}
printf("cpassert data addr: 0x%x, size: 0x%x\n", addr, data_len);
while(data_len) {
if (data_len >= DATA_BLOCK_LEN) {
rdp_tx_data_ptr(addr + data_in_len, DATA_BLOCK_LEN);
data_in_len += DATA_BLOCK_LEN;
data_len -= DATA_BLOCK_LEN;
total_data_len += DATA_BLOCK_LEN;
} else {
rdp_tx_data_ptr(addr + data_in_len, data_len);
data_in_len += data_len;
total_data_len += data_len;
data_len = 0;
}
idx++;
if ((idx % 3000) == 0)
printf("sending 0x%x bytes now\n", idx * DATA_BLOCK_LEN);
}
if (need_zero_pkt) {
printf("zero pkt\n");
rdp_tx_data_ptr(addr, 0);
}
printf("!! CPASSERT tx data done - total: 0x%x bytes, left: 0x%x bytes\n\n",
total_data_len, data_len);
udelay(10000);
return 0;
}
int rdp_give_cpassert_extra_files(u8 *data_addr, int size)
{
unsigned char * addr = data_addr;
u32 data_len = size;
struct rdp_dev *dev = rdp_func->dev;
u32 data_in_len = 0, idx = 0, total_data_len = 0;
int need_zero_pkt = 0;
need_zero_pkt = ((size % DATA_BLOCK_LEN) == 0);
/* wait for HOST to request text */
printf("Getting cpassert ext dump req\n");
if (rdp_rx_data() < 0) {
printf("%s: rdp_rx_data err!\n", __func__);
return -1;
}
if (!strncmp((char *)dev->out_req->buf, "cpassert_extra_dump", strlen("cpassert_extra_dump"))) {
puts("get cpassert_extra_dump\n");
udelay(30 * 1000); /* 30 ms */
} else {
puts("Wrong request, check rdp_transfer tool version\n");
return -1;
}
printf("cpassert extra data hdr: 0x%x, size: 0x%x\n", addr, data_len);
while(data_len) {
if (data_len >= DATA_BLOCK_LEN) {
rdp_tx_data_ptr(addr + data_in_len, DATA_BLOCK_LEN);
data_in_len += DATA_BLOCK_LEN;
data_len -= DATA_BLOCK_LEN;
total_data_len += DATA_BLOCK_LEN;
} else {
rdp_tx_data_ptr(addr + data_in_len, data_len);
data_in_len += data_len;
total_data_len += data_len;
data_len = 0;
}
idx++;
if ((idx % 3000) == 0)
printf("sending 0x%x bytes now\n", idx * DATA_BLOCK_LEN);
}
if (need_zero_pkt) {
printf("zero pkt\n");
rdp_tx_data_ptr(addr, 0);
}
printf("!! cpassert extra data done - total: 0x%x bytes, left: 0x%x bytes\n\n",
total_data_len, data_len);
udelay(10000);
return 0;
}
static int rdp_func_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_gadget *gadget = c->cdev->gadget;
struct f_rdp *f_rdp = func_to_rdp(f);
struct rdp_dev *dev;
struct usb_ep *ep;
int status;
rdp_func = f_rdp;
//dev = memalign(64, sizeof(*dev));
dev = malloc(sizeof(*dev));
if (!dev)
return -ENOMEM;
memset(dev, 0, sizeof(*dev));
dev->gadget = gadget;
f_rdp->dev = dev;
log_debug("%s: usb_configuration: 0x%p usb_function: 0x%p\n",
__func__, c, f);
log_debug("f_rdp: 0x%p dev: 0x%p\n", f_rdp, dev);
dev->req = usb_ep_alloc_request(gadget->ep0, 0);
if (!dev->req) {
status = -ENOMEM;
goto fail;
}
#if defined(CONFIG_USB_DWC3) || defined(CONFIG_USB_GADGET_DWC2_OTG)
dev->req->buf = memalign(64, DWC3_USB_REG_BUF_LEN);
#else
dev->req->buf = memalign(64, USB_REG_BUF_LEN);
#endif
if (!dev->req->buf) {
status = -ENOMEM;
goto fail;
}
dev->req->complete = rdp_setup_complete;
status = usb_interface_id(c, f);
if (status < 0)
goto fail;
rdp_intf_data.bInterfaceNumber = status;
usb_ep_autoconfig_reset(gadget);
/* allocate instance-specific endpoints */
ep = usb_ep_autoconfig(gadget, &fs_in_desc);
if (!ep) {
status = -ENODEV;
goto fail;
}
if (gadget_is_dualspeed(gadget)) {
log_debug("%s: gadget is dualspeed, fs_in_desc.bEndpointAddress: 0x%x\n",
__func__, (u32)fs_in_desc.bEndpointAddress);
hs_in_desc.bEndpointAddress =
fs_in_desc.bEndpointAddress;
}
dev->in_ep = ep;
ep->driver_data = ep; /* claim */
ep = usb_ep_autoconfig(gadget, &fs_out_desc);
if (!ep) {
status = -ENODEV;
goto fail;
}
if (gadget_is_dualspeed(gadget))
hs_out_desc.bEndpointAddress =
fs_out_desc.bEndpointAddress;
dev->out_ep = ep;
ep->driver_data = ep; /* claim */
if (gadget_is_dualspeed(gadget)) {
f->hs_descriptors = (struct usb_descriptor_header **)
&hs_rdp_data_function;
if (!f->hs_descriptors)
goto fail;
f->descriptors = (struct usb_descriptor_header **)
&fs_rdp_data_function;
if (!f->descriptors)
goto fail;
}
log_debug("%s: in_ep:%p in_req:%p\n", __func__,
dev->in_ep, dev->in_req);
log_debug("%s: out_ep:%p out_req:%p\n", __func__,
dev->out_ep, dev->out_req);
return 0;
fail:
log_debug("%s: failed\n", __func__);
free(dev);
return status;
}
static void free_ep_req(struct usb_ep *ep, struct usb_request *req)
{
free(req->buf);
usb_ep_free_request(ep, req);
}
static void rdp_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct f_rdp *f_rdp = func_to_rdp(f);
struct rdp_dev *dev = f_rdp->dev;
free(dev);
memset(rdp_func, 0, sizeof(*rdp_func));
rdp_func = NULL;
}
static void rdp_func_disable(struct usb_function *f)
{
struct f_rdp *f_rdp = func_to_rdp(f);
struct rdp_dev *dev = f_rdp->dev;
log_debug("%s:\n", __func__);
/* Avoid freeing memory when ep is still claimed */
if (dev->in_ep->driver_data) {
free_ep_req(dev->in_ep, dev->in_req);
usb_ep_disable(dev->in_ep);
dev->in_ep->driver_data = NULL;
}
if (dev->out_ep->driver_data) {
dev->out_req->buf = NULL;
usb_ep_free_request(dev->out_ep, dev->out_req);
usb_ep_disable(dev->out_ep);
dev->out_ep->driver_data = NULL;
}
}
static int rdp_eps_setup(struct usb_function *f)
{
struct usb_composite_dev *cdev = f->config->cdev;
struct usb_gadget *gadget = cdev->gadget;
struct rdp_dev *dev = rdp_func->dev;
struct usb_endpoint_descriptor *d;
struct usb_request *req;
struct usb_ep *ep;
int result;
ep = dev->in_ep;
d = ep_desc(gadget, &hs_in_desc, &fs_in_desc);
log_debug("in bEndpointAddress: 0x%x\n", d->bEndpointAddress);
result = usb_ep_enable(ep, d);
if (result)
goto exit;
ep->driver_data = cdev; /* claim */
req = rdp_start_ep(ep);
if (!req) {
usb_ep_disable(ep);
result = -EIO;
goto exit;
}
dev->in_req = req;
ep = dev->out_ep;
d = ep_desc(gadget, &hs_out_desc, &fs_out_desc);
log_debug("bEndpointAddress: 0x%x\n", d->bEndpointAddress);
result = usb_ep_enable(ep, d);
if (result)
goto exit;
ep->driver_data = cdev; /* claim */
req = rdp_start_ep(ep);
if (!req) {
usb_ep_disable(ep);
result = -EIO;
goto exit;
}
dev->out_req = req;
exit:
return result;
}
static int rdp_func_set_alt(struct usb_function *f,
unsigned intf, unsigned alt)
{
struct rdp_dev *dev = rdp_func->dev;
int result;
log_debug("%s: func: %s intf: %d alt: %d\n",
__func__, f->name, intf, alt);
switch (intf) {
case 0:
log_debug("%s: intf == 0\n", __func__);
result = rdp_eps_setup(f);
if (result)
error("%s: EPs setup failed!", __func__);
dev->configuration_done = 1;
break;
default:
printf("%s: error interface!", __func__);
}
return 0;
}
static int rdp_func_init(struct usb_configuration *c)
{
struct f_rdp *f_rdp;
int status;
log_debug("%s: cdev: 0x%p\n", __func__, c->cdev);
//f_rdp = memalign(64, sizeof(*f_rdp));
f_rdp = malloc(sizeof(*f_rdp));
if (!f_rdp) {
printf("%s: alloc f_rdp failed\n", __func__);
return -ENOMEM;
}
memset(f_rdp, 0, sizeof(*f_rdp));
f_rdp->usb_function.name = "f_rdp";
f_rdp->usb_function.bind = rdp_func_bind;
f_rdp->usb_function.unbind = rdp_unbind;
f_rdp->usb_function.setup = rdp_func_setup;
f_rdp->usb_function.set_alt = rdp_func_set_alt;
f_rdp->usb_function.disable = rdp_func_disable;
status = usb_add_function(c, &f_rdp->usb_function);
if (status)
free(f_rdp);
return status;
}
int rdp_add(struct usb_configuration *c)
{
log_debug("%s:\n", __func__);
return rdp_func_init(c);
}