|
@@ -12,6 +12,7 @@
|
|
|
|
|
|
#include <linux/slab.h>
|
|
|
#include <linux/kernel.h>
|
|
|
+#include <linux/module.h>
|
|
|
#include <linux/device.h>
|
|
|
|
|
|
#include "u_serial.h"
|
|
@@ -42,7 +43,7 @@ static inline struct f_gser *func_to_gser(struct usb_function *f)
|
|
|
|
|
|
/* interface descriptor: */
|
|
|
|
|
|
-static struct usb_interface_descriptor gser_interface_desc __initdata = {
|
|
|
+static struct usb_interface_descriptor gser_interface_desc = {
|
|
|
.bLength = USB_DT_INTERFACE_SIZE,
|
|
|
.bDescriptorType = USB_DT_INTERFACE,
|
|
|
/* .bInterfaceNumber = DYNAMIC */
|
|
@@ -55,21 +56,21 @@ static struct usb_interface_descriptor gser_interface_desc __initdata = {
|
|
|
|
|
|
/* full speed support: */
|
|
|
|
|
|
-static struct usb_endpoint_descriptor gser_fs_in_desc __initdata = {
|
|
|
+static struct usb_endpoint_descriptor gser_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 gser_fs_out_desc __initdata = {
|
|
|
+static struct usb_endpoint_descriptor gser_fs_out_desc = {
|
|
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
|
|
.bDescriptorType = USB_DT_ENDPOINT,
|
|
|
.bEndpointAddress = USB_DIR_OUT,
|
|
|
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
|
|
};
|
|
|
|
|
|
-static struct usb_descriptor_header *gser_fs_function[] __initdata = {
|
|
|
+static struct usb_descriptor_header *gser_fs_function[] = {
|
|
|
(struct usb_descriptor_header *) &gser_interface_desc,
|
|
|
(struct usb_descriptor_header *) &gser_fs_in_desc,
|
|
|
(struct usb_descriptor_header *) &gser_fs_out_desc,
|
|
@@ -78,47 +79,47 @@ static struct usb_descriptor_header *gser_fs_function[] __initdata = {
|
|
|
|
|
|
/* high speed support: */
|
|
|
|
|
|
-static struct usb_endpoint_descriptor gser_hs_in_desc __initdata = {
|
|
|
+static struct usb_endpoint_descriptor gser_hs_in_desc = {
|
|
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
|
|
.bDescriptorType = USB_DT_ENDPOINT,
|
|
|
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
|
|
.wMaxPacketSize = cpu_to_le16(512),
|
|
|
};
|
|
|
|
|
|
-static struct usb_endpoint_descriptor gser_hs_out_desc __initdata = {
|
|
|
+static struct usb_endpoint_descriptor gser_hs_out_desc = {
|
|
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
|
|
.bDescriptorType = USB_DT_ENDPOINT,
|
|
|
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
|
|
.wMaxPacketSize = cpu_to_le16(512),
|
|
|
};
|
|
|
|
|
|
-static struct usb_descriptor_header *gser_hs_function[] __initdata = {
|
|
|
+static struct usb_descriptor_header *gser_hs_function[] = {
|
|
|
(struct usb_descriptor_header *) &gser_interface_desc,
|
|
|
(struct usb_descriptor_header *) &gser_hs_in_desc,
|
|
|
(struct usb_descriptor_header *) &gser_hs_out_desc,
|
|
|
NULL,
|
|
|
};
|
|
|
|
|
|
-static struct usb_endpoint_descriptor gser_ss_in_desc __initdata = {
|
|
|
+static struct usb_endpoint_descriptor gser_ss_in_desc = {
|
|
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
|
|
.bDescriptorType = USB_DT_ENDPOINT,
|
|
|
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
|
|
.wMaxPacketSize = cpu_to_le16(1024),
|
|
|
};
|
|
|
|
|
|
-static struct usb_endpoint_descriptor gser_ss_out_desc __initdata = {
|
|
|
+static struct usb_endpoint_descriptor gser_ss_out_desc = {
|
|
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
|
|
.bDescriptorType = USB_DT_ENDPOINT,
|
|
|
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
|
|
.wMaxPacketSize = cpu_to_le16(1024),
|
|
|
};
|
|
|
|
|
|
-static struct usb_ss_ep_comp_descriptor gser_ss_bulk_comp_desc __initdata = {
|
|
|
+static struct usb_ss_ep_comp_descriptor gser_ss_bulk_comp_desc = {
|
|
|
.bLength = sizeof gser_ss_bulk_comp_desc,
|
|
|
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
|
|
|
};
|
|
|
|
|
|
-static struct usb_descriptor_header *gser_ss_function[] __initdata = {
|
|
|
+static struct usb_descriptor_header *gser_ss_function[] = {
|
|
|
(struct usb_descriptor_header *) &gser_interface_desc,
|
|
|
(struct usb_descriptor_header *) &gser_ss_in_desc,
|
|
|
(struct usb_descriptor_header *) &gser_ss_bulk_comp_desc,
|
|
@@ -183,14 +184,25 @@ static void gser_disable(struct usb_function *f)
|
|
|
|
|
|
/* serial function driver setup/binding */
|
|
|
|
|
|
-static int __init
|
|
|
-gser_bind(struct usb_configuration *c, struct usb_function *f)
|
|
|
+static int gser_bind(struct usb_configuration *c, struct usb_function *f)
|
|
|
{
|
|
|
struct usb_composite_dev *cdev = c->cdev;
|
|
|
struct f_gser *gser = func_to_gser(f);
|
|
|
int status;
|
|
|
struct usb_ep *ep;
|
|
|
|
|
|
+ /* REVISIT might want instance-specific strings to help
|
|
|
+ * distinguish instances ...
|
|
|
+ */
|
|
|
+
|
|
|
+ /* maybe allocate device-global string ID */
|
|
|
+ if (gser_string_defs[0].id == 0) {
|
|
|
+ status = usb_string_id(c->cdev);
|
|
|
+ if (status < 0)
|
|
|
+ return status;
|
|
|
+ gser_string_defs[0].id = status;
|
|
|
+ }
|
|
|
+
|
|
|
/* allocate instance-specific interface IDs */
|
|
|
status = usb_interface_id(c, f);
|
|
|
if (status < 0)
|
|
@@ -246,8 +258,10 @@ fail:
|
|
|
return status;
|
|
|
}
|
|
|
|
|
|
+#ifdef USB_FSERIAL_INCLUDED
|
|
|
+
|
|
|
static void
|
|
|
-gser_unbind(struct usb_configuration *c, struct usb_function *f)
|
|
|
+gser_old_unbind(struct usb_configuration *c, struct usb_function *f)
|
|
|
{
|
|
|
usb_free_all_descriptors(f);
|
|
|
kfree(func_to_gser(f));
|
|
@@ -266,18 +280,6 @@ int __init gser_bind_config(struct usb_configuration *c, u8 port_num)
|
|
|
struct f_gser *gser;
|
|
|
int status;
|
|
|
|
|
|
- /* REVISIT might want instance-specific strings to help
|
|
|
- * distinguish instances ...
|
|
|
- */
|
|
|
-
|
|
|
- /* maybe allocate device-global string ID */
|
|
|
- if (gser_string_defs[0].id == 0) {
|
|
|
- status = usb_string_id(c->cdev);
|
|
|
- if (status < 0)
|
|
|
- return status;
|
|
|
- gser_string_defs[0].id = status;
|
|
|
- }
|
|
|
-
|
|
|
/* allocate and initialize one new instance */
|
|
|
gser = kzalloc(sizeof *gser, GFP_KERNEL);
|
|
|
if (!gser)
|
|
@@ -288,7 +290,7 @@ int __init gser_bind_config(struct usb_configuration *c, u8 port_num)
|
|
|
gser->port.func.name = "gser";
|
|
|
gser->port.func.strings = gser_strings;
|
|
|
gser->port.func.bind = gser_bind;
|
|
|
- gser->port.func.unbind = gser_unbind;
|
|
|
+ gser->port.func.unbind = gser_old_unbind;
|
|
|
gser->port.func.set_alt = gser_set_alt;
|
|
|
gser->port.func.disable = gser_disable;
|
|
|
|
|
@@ -297,3 +299,78 @@ int __init gser_bind_config(struct usb_configuration *c, u8 port_num)
|
|
|
kfree(gser);
|
|
|
return status;
|
|
|
}
|
|
|
+
|
|
|
+#else
|
|
|
+
|
|
|
+static void gser_free_inst(struct usb_function_instance *f)
|
|
|
+{
|
|
|
+ struct f_serial_opts *opts;
|
|
|
+
|
|
|
+ opts = container_of(f, struct f_serial_opts, func_inst);
|
|
|
+ gserial_free_line(opts->port_num);
|
|
|
+ kfree(opts);
|
|
|
+}
|
|
|
+
|
|
|
+static struct usb_function_instance *gser_alloc_inst(void)
|
|
|
+{
|
|
|
+ struct f_serial_opts *opts;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ opts = kzalloc(sizeof(*opts), GFP_KERNEL);
|
|
|
+ if (!opts)
|
|
|
+ return ERR_PTR(-ENOMEM);
|
|
|
+
|
|
|
+ opts->func_inst.free_func_inst = gser_free_inst;
|
|
|
+ ret = gserial_alloc_line(&opts->port_num);
|
|
|
+ if (ret) {
|
|
|
+ kfree(opts);
|
|
|
+ return ERR_PTR(ret);
|
|
|
+ }
|
|
|
+
|
|
|
+ return &opts->func_inst;
|
|
|
+}
|
|
|
+
|
|
|
+static void gser_free(struct usb_function *f)
|
|
|
+{
|
|
|
+ struct f_gser *serial;
|
|
|
+
|
|
|
+ serial = func_to_gser(f);
|
|
|
+ kfree(serial);
|
|
|
+}
|
|
|
+
|
|
|
+static void gser_unbind(struct usb_configuration *c, struct usb_function *f)
|
|
|
+{
|
|
|
+ usb_free_all_descriptors(f);
|
|
|
+}
|
|
|
+
|
|
|
+struct usb_function *gser_alloc(struct usb_function_instance *fi)
|
|
|
+{
|
|
|
+ struct f_gser *gser;
|
|
|
+ struct f_serial_opts *opts;
|
|
|
+
|
|
|
+ /* allocate and initialize one new instance */
|
|
|
+ gser = kzalloc(sizeof(*gser), GFP_KERNEL);
|
|
|
+ if (!gser)
|
|
|
+ return ERR_PTR(-ENOMEM);
|
|
|
+
|
|
|
+ opts = container_of(fi, struct f_serial_opts, func_inst);
|
|
|
+
|
|
|
+ gser->port_num = opts->port_num;
|
|
|
+
|
|
|
+ gser->port.func.name = "gser";
|
|
|
+ gser->port.func.strings = gser_strings;
|
|
|
+ gser->port.func.bind = gser_bind;
|
|
|
+ gser->port.func.unbind = gser_unbind;
|
|
|
+ gser->port.func.set_alt = gser_set_alt;
|
|
|
+ gser->port.func.disable = gser_disable;
|
|
|
+ gser->port.func.free_func = gser_free;
|
|
|
+
|
|
|
+ return &gser->port.func;
|
|
|
+}
|
|
|
+
|
|
|
+DECLARE_USB_FUNCTION_INIT(gser, gser_alloc_inst, gser_alloc);
|
|
|
+MODULE_LICENSE("GPL");
|
|
|
+MODULE_AUTHOR("Al Borchers");
|
|
|
+MODULE_AUTHOR("David Brownell");
|
|
|
+
|
|
|
+#endif
|