Commit 5cc0710f authored by Tao Ren's avatar Tao Ren Committed by Felipe Balbi

usb: gadget: aspeed: support multiple language strings

This patch introduces a link list to store string descriptors with
different languages, and "ast_vhub_rep_string" function is also improved
to support multiple language usb strings.
Signed-off-by: default avatarTao Ren <rentao.bupt@gmail.com>
Signed-off-by: default avatarFelipe Balbi <balbi@kernel.org>
parent a23be4ed
...@@ -408,7 +408,9 @@ static int ast_vhub_probe(struct platform_device *pdev) ...@@ -408,7 +408,9 @@ static int ast_vhub_probe(struct platform_device *pdev)
goto err; goto err;
/* Init hub emulation */ /* Init hub emulation */
ast_vhub_init_hub(vhub); rc = ast_vhub_init_hub(vhub);
if (rc)
goto err;
/* Initialize HW */ /* Initialize HW */
ast_vhub_init_hw(vhub); ast_vhub_init_hw(vhub);
......
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#define KERNEL_VER bin2bcd(((LINUX_VERSION_CODE >> 8) & 0x0ff)) #define KERNEL_VER bin2bcd(((LINUX_VERSION_CODE >> 8) & 0x0ff))
enum { enum {
AST_VHUB_STR_INDEX_MAX = 4,
AST_VHUB_STR_MANUF = 3, AST_VHUB_STR_MANUF = 3,
AST_VHUB_STR_PRODUCT = 2, AST_VHUB_STR_PRODUCT = 2,
AST_VHUB_STR_SERIAL = 1, AST_VHUB_STR_SERIAL = 1,
...@@ -310,23 +311,77 @@ static int ast_vhub_rep_desc(struct ast_vhub_ep *ep, ...@@ -310,23 +311,77 @@ static int ast_vhub_rep_desc(struct ast_vhub_ep *ep,
return ast_vhub_reply(ep, NULL, len); return ast_vhub_reply(ep, NULL, len);
} }
static struct usb_gadget_strings*
ast_vhub_str_of_container(struct usb_gadget_string_container *container)
{
return (struct usb_gadget_strings *)container->stash;
}
static int ast_vhub_collect_languages(struct ast_vhub *vhub, void *buf,
size_t size)
{
int rc, hdr_len, nlangs, max_langs;
struct usb_gadget_strings *lang_str;
struct usb_gadget_string_container *container;
struct usb_string_descriptor *sdesc = buf;
nlangs = 0;
hdr_len = sizeof(struct usb_descriptor_header);
max_langs = (size - hdr_len) / sizeof(sdesc->wData[0]);
list_for_each_entry(container, &vhub->vhub_str_desc, list) {
if (nlangs >= max_langs)
break;
lang_str = ast_vhub_str_of_container(container);
sdesc->wData[nlangs++] = cpu_to_le16(lang_str->language);
}
rc = hdr_len + nlangs * sizeof(sdesc->wData[0]);
sdesc->bLength = rc;
sdesc->bDescriptorType = USB_DT_STRING;
return rc;
}
static struct usb_gadget_strings *ast_vhub_lookup_string(struct ast_vhub *vhub,
u16 lang_id)
{
struct usb_gadget_strings *lang_str;
struct usb_gadget_string_container *container;
list_for_each_entry(container, &vhub->vhub_str_desc, list) {
lang_str = ast_vhub_str_of_container(container);
if (lang_str->language == lang_id)
return lang_str;
}
return NULL;
}
static int ast_vhub_rep_string(struct ast_vhub_ep *ep, static int ast_vhub_rep_string(struct ast_vhub_ep *ep,
u8 string_id, u16 lang_id, u8 string_id, u16 lang_id,
u16 len) u16 len)
{ {
int rc = usb_gadget_get_string(&ep->vhub->vhub_str_desc, int rc;
string_id, ep->buf); u8 buf[256];
struct ast_vhub *vhub = ep->vhub;
struct usb_gadget_strings *lang_str;
/* if (string_id == 0) {
* This should never happen unless we put too big strings in rc = ast_vhub_collect_languages(vhub, buf, sizeof(buf));
* the array above } else {
*/ lang_str = ast_vhub_lookup_string(vhub, lang_id);
BUG_ON(rc >= AST_VHUB_EP0_MAX_PACKET); if (!lang_str)
return std_req_stall;
rc = usb_gadget_get_string(lang_str, string_id, buf);
}
if (rc < 0) if (rc < 0 || rc >= AST_VHUB_EP0_MAX_PACKET)
return std_req_stall; return std_req_stall;
/* Shoot it from the EP buffer */ /* Shoot it from the EP buffer */
memcpy(ep->buf, buf, rc);
return ast_vhub_reply(ep, NULL, min_t(u16, rc, len)); return ast_vhub_reply(ep, NULL, min_t(u16, rc, len));
} }
...@@ -832,8 +887,64 @@ void ast_vhub_hub_reset(struct ast_vhub *vhub) ...@@ -832,8 +887,64 @@ void ast_vhub_hub_reset(struct ast_vhub *vhub)
writel(0, vhub->regs + AST_VHUB_EP1_STS_CHG); writel(0, vhub->regs + AST_VHUB_EP1_STS_CHG);
} }
static void ast_vhub_init_desc(struct ast_vhub *vhub) static struct usb_gadget_string_container*
ast_vhub_str_container_alloc(struct ast_vhub *vhub)
{
unsigned int size;
struct usb_string *str_array;
struct usb_gadget_strings *lang_str;
struct usb_gadget_string_container *container;
size = sizeof(*container);
size += sizeof(struct usb_gadget_strings);
size += sizeof(struct usb_string) * AST_VHUB_STR_INDEX_MAX;
container = devm_kzalloc(&vhub->pdev->dev, size, GFP_KERNEL);
if (!container)
return ERR_PTR(-ENOMEM);
lang_str = ast_vhub_str_of_container(container);
str_array = (struct usb_string *)(lang_str + 1);
lang_str->strings = str_array;
return container;
}
static void ast_vhub_str_deep_copy(struct usb_gadget_strings *dest,
const struct usb_gadget_strings *src)
{
struct usb_string *src_array = src->strings;
struct usb_string *dest_array = dest->strings;
dest->language = src->language;
if (src_array && dest_array) {
do {
*dest_array = *src_array;
dest_array++;
src_array++;
} while (src_array->s);
}
}
static int ast_vhub_str_alloc_add(struct ast_vhub *vhub,
const struct usb_gadget_strings *src_str)
{ {
struct usb_gadget_strings *dest_str;
struct usb_gadget_string_container *container;
container = ast_vhub_str_container_alloc(vhub);
if (IS_ERR(container))
return PTR_ERR(container);
dest_str = ast_vhub_str_of_container(container);
ast_vhub_str_deep_copy(dest_str, src_str);
list_add_tail(&container->list, &vhub->vhub_str_desc);
return 0;
}
static int ast_vhub_init_desc(struct ast_vhub *vhub)
{
int ret;
/* Initialize vhub Device Descriptor. */ /* Initialize vhub Device Descriptor. */
memcpy(&vhub->vhub_dev_desc, &ast_vhub_dev_desc, memcpy(&vhub->vhub_dev_desc, &ast_vhub_dev_desc,
sizeof(vhub->vhub_dev_desc)); sizeof(vhub->vhub_dev_desc));
...@@ -848,15 +959,16 @@ static void ast_vhub_init_desc(struct ast_vhub *vhub) ...@@ -848,15 +959,16 @@ static void ast_vhub_init_desc(struct ast_vhub *vhub)
vhub->vhub_hub_desc.bNbrPorts = vhub->max_ports; vhub->vhub_hub_desc.bNbrPorts = vhub->max_ports;
/* Initialize vhub String Descriptors. */ /* Initialize vhub String Descriptors. */
memcpy(&vhub->vhub_str_desc, &ast_vhub_strings, INIT_LIST_HEAD(&vhub->vhub_str_desc);
sizeof(vhub->vhub_str_desc)); ret = ast_vhub_str_alloc_add(vhub, &ast_vhub_strings);
return ret;
} }
void ast_vhub_init_hub(struct ast_vhub *vhub) int ast_vhub_init_hub(struct ast_vhub *vhub)
{ {
vhub->speed = USB_SPEED_UNKNOWN; vhub->speed = USB_SPEED_UNKNOWN;
INIT_WORK(&vhub->wake_work, ast_vhub_wake_work); INIT_WORK(&vhub->wake_work, ast_vhub_wake_work);
ast_vhub_init_desc(vhub); return ast_vhub_init_desc(vhub);
} }
...@@ -421,7 +421,7 @@ struct ast_vhub { ...@@ -421,7 +421,7 @@ struct ast_vhub {
struct usb_device_descriptor vhub_dev_desc; struct usb_device_descriptor vhub_dev_desc;
struct ast_vhub_full_cdesc vhub_conf_desc; struct ast_vhub_full_cdesc vhub_conf_desc;
struct usb_hub_descriptor vhub_hub_desc; struct usb_hub_descriptor vhub_hub_desc;
struct usb_gadget_strings vhub_str_desc; struct list_head vhub_str_desc;
}; };
/* Standard request handlers result codes */ /* Standard request handlers result codes */
...@@ -531,7 +531,7 @@ int __ast_vhub_simple_reply(struct ast_vhub_ep *ep, int len, ...); ...@@ -531,7 +531,7 @@ int __ast_vhub_simple_reply(struct ast_vhub_ep *ep, int len, ...);
__VA_ARGS__) __VA_ARGS__)
/* hub.c */ /* hub.c */
void ast_vhub_init_hub(struct ast_vhub *vhub); int ast_vhub_init_hub(struct ast_vhub *vhub);
enum std_req_rc ast_vhub_std_hub_request(struct ast_vhub_ep *ep, enum std_req_rc ast_vhub_std_hub_request(struct ast_vhub_ep *ep,
struct usb_ctrlrequest *crq); struct usb_ctrlrequest *crq);
enum std_req_rc ast_vhub_class_hub_request(struct ast_vhub_ep *ep, enum std_req_rc ast_vhub_class_hub_request(struct ast_vhub_ep *ep,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment