aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget/function/f_mtp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/function/f_mtp.c')
-rw-r--r--drivers/usb/gadget/function/f_mtp.c97
1 files changed, 85 insertions, 12 deletions
diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c
index 4e04c84..6930f8a 100644
--- a/drivers/usb/gadget/function/f_mtp.c
+++ b/drivers/usb/gadget/function/f_mtp.c
@@ -125,6 +125,16 @@ static struct usb_interface_descriptor mtp_interface_desc = {
.bInterfaceProtocol = 0,
};
+static struct usb_interface_descriptor ptp_interface_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 3,
+ .bInterfaceClass = USB_CLASS_STILL_IMAGE,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 1,
+};
+
static struct usb_endpoint_descriptor mtp_ss_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -225,6 +235,33 @@ static struct usb_descriptor_header *ss_mtp_descs[] = {
NULL,
};
+static struct usb_descriptor_header *fs_ptp_descs[] = {
+ (struct usb_descriptor_header *) &ptp_interface_desc,
+ (struct usb_descriptor_header *) &mtp_fullspeed_in_desc,
+ (struct usb_descriptor_header *) &mtp_fullspeed_out_desc,
+ (struct usb_descriptor_header *) &mtp_intr_desc,
+ NULL,
+};
+
+static struct usb_descriptor_header *hs_ptp_descs[] = {
+ (struct usb_descriptor_header *) &ptp_interface_desc,
+ (struct usb_descriptor_header *) &mtp_highspeed_in_desc,
+ (struct usb_descriptor_header *) &mtp_highspeed_out_desc,
+ (struct usb_descriptor_header *) &mtp_intr_desc,
+ NULL,
+};
+
+static struct usb_descriptor_header *ss_ptp_descs[] = {
+ (struct usb_descriptor_header *) &ptp_interface_desc,
+ (struct usb_descriptor_header *) &mtp_ss_in_desc,
+ (struct usb_descriptor_header *) &mtp_ss_in_comp_desc,
+ (struct usb_descriptor_header *) &mtp_ss_out_desc,
+ (struct usb_descriptor_header *) &mtp_ss_out_comp_desc,
+ (struct usb_descriptor_header *) &mtp_intr_desc,
+ (struct usb_descriptor_header *) &mtp_intr_ss_comp_desc,
+ NULL,
+};
+
static struct usb_string mtp_string_defs[] = {
/* Naming interface "MTP" so libmtp will recognize us */
[INTERFACE_STRING_INDEX].s = "MTP",
@@ -1383,7 +1420,7 @@ static void mtp_free_inst(struct usb_function_instance *fi)
kfree(fi_mtp);
}
-static struct usb_function_instance *mtp_alloc_inst(void)
+struct usb_function_instance *alloc_inst_mtp_ptp(bool mtp_config)
{
struct mtp_instance *fi_mtp;
int ret = 0;
@@ -1401,12 +1438,15 @@ static struct usb_function_instance *mtp_alloc_inst(void)
descs[0] = &fi_mtp->mtp_os_desc;
names[0] = "MTP";
- ret = mtp_setup(fi_mtp);
- if (ret) {
- kfree(fi_mtp);
- pr_err("Error setting MTP\n");
- return ERR_PTR(ret);
- }
+ if (mtp_config) {
+ ret = mtp_setup(fi_mtp);
+ if (ret) {
+ kfree(fi_mtp);
+ pr_err("Error setting MTP\n");
+ return ERR_PTR(ret);
+ }
+ } else
+ fi_mtp->dev = _mtp_dev;
config_group_init_type_name(&fi_mtp->func_inst.group,
"", &mtp_func_type);
@@ -1415,6 +1455,12 @@ static struct usb_function_instance *mtp_alloc_inst(void)
return &fi_mtp->func_inst;
}
+EXPORT_SYMBOL_GPL(alloc_inst_mtp_ptp);
+
+static struct usb_function_instance *mtp_alloc_inst(void)
+{
+ return alloc_inst_mtp_ptp(true);
+}
static int mtp_ctrlreq_configfs(struct usb_function *f,
const struct usb_ctrlrequest *ctrl)
@@ -1427,16 +1473,37 @@ static void mtp_free(struct usb_function *f)
/*NO-OP: no function specific resource allocation in mtp_alloc*/
}
-static struct usb_function *mtp_alloc(struct usb_function_instance *fi)
+struct usb_function *function_alloc_mtp_ptp(struct usb_function_instance *fi,
+ bool mtp_config)
{
struct mtp_instance *fi_mtp = to_fi_mtp(fi);
- struct mtp_dev *dev = fi_mtp->dev;
+ struct mtp_dev *dev;
+
+ /*
+ * PTP piggybacks on MTP function so make sure we have
+ * created MTP function before we associate this PTP
+ * function with a gadget configuration.
+ */
+ if (fi_mtp->dev == NULL) {
+ pr_err("Error: Create MTP func before linking PTP func\n");
+ pr_err("\t1: Delete existing PTP function if any\n");
+ pr_err("\t2: Create MTP function\n");
+ pr_err("\t3: Create & symlink PTP func with a gadget config\n");
+ return ERR_PTR(-EINVAL); /* Invalid Configuration */
+ }
+ dev = fi_mtp->dev;
dev->function.name = DRIVER_NAME;
dev->function.strings = mtp_strings;
- dev->function.fs_descriptors = fs_mtp_descs;
- dev->function.hs_descriptors = hs_mtp_descs;
- dev->function.ss_descriptors = ss_mtp_descs;
+ if (mtp_config) {
+ dev->function.fs_descriptors = fs_mtp_descs;
+ dev->function.hs_descriptors = hs_mtp_descs;
+ dev->function.ss_descriptors = ss_mtp_descs;
+ } else {
+ dev->function.fs_descriptors = fs_ptp_descs;
+ dev->function.hs_descriptors = hs_ptp_descs;
+ dev->function.ss_descriptors = ss_ptp_descs;
+ }
dev->function.bind = mtp_function_bind;
dev->function.unbind = mtp_function_unbind;
dev->function.set_alt = mtp_function_set_alt;
@@ -1446,6 +1513,12 @@ static struct usb_function *mtp_alloc(struct usb_function_instance *fi)
return &dev->function;
}
+EXPORT_SYMBOL_GPL(function_alloc_mtp_ptp);
+
+static struct usb_function *mtp_alloc(struct usb_function_instance *fi)
+{
+ return function_alloc_mtp_ptp(fi, true);
+}
DECLARE_USB_FUNCTION_INIT(mtp, mtp_alloc_inst, mtp_alloc);
MODULE_LICENSE("GPL");