| 1 | |
| 2 | |
| 3 | * f_serial.c - generic USB serial function driver
|
| 4 | *
|
| 5 | * Copyright (C) 2003 Al Borchers ([email protected])
|
| 6 | * Copyright (C) 2008 by David Brownell
|
| 7 | * Copyright (C) 2008 by Nokia Corporation
|
| 8 |
|
| 9 |
|
| 10 | #include <linux/slab.h>
|
| 11 | #include <linux/kernel.h>
|
| 12 | #include <linux/module.h>
|
| 13 | #include <linux/device.h>
|
| 14 |
|
| 15 | #include "u_serial.h"
|
| 16 |
|
| 17 |
|
| 18 | |
| 19 | * This function packages a simple "generic serial" port with no real
|
| 20 | * control mechanisms, just raw data transfer over two bulk endpoints.
|
| 21 | *
|
| 22 | * Because it's not standardized, this isn't as interoperable as the
|
| 23 | * CDC ACM driver. However, for many purposes it's just as functional
|
| 24 | * if you can arrange appropriate host side drivers.
|
| 25 |
|
| 26 |
|
| 27 | struct f_gser {
|
| 28 | struct gserial port;
|
| 29 | u8 data_id;
|
| 30 | u8 port_num;
|
| 31 | };
|
| 32 |
|
| 33 | static inline struct f_gser *func_to_gser(struct usb_function *f)
|
| 34 | {
|
| 35 | return container_of(f, struct f_gser, port.func);
|
| 36 | }
|
| 37 |
|
| 38 |
|
| 39 |
|
| 40 |
|
| 41 |
|
| 42 | static struct usb_interface_descriptor gser_interface_desc = {
|
| 43 | .bLength = USB_DT_INTERFACE_SIZE,
|
| 44 | .bDescriptorType = USB_DT_INTERFACE,
|
| 45 |
|
| 46 | .bNumEndpoints = 2,
|
| 47 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
|
| 48 | .bInterfaceSubClass = 0,
|
| 49 | .bInterfaceProtocol = 0,
|
| 50 |
|
| 51 | };
|
| 52 |
|
| 53 |
|
| 54 |
|
| 55 | static struct usb_endpoint_descriptor gser_fs_in_desc = {
|
| 56 | .bLength = USB_DT_ENDPOINT_SIZE,
|
| 57 | .bDescriptorType = USB_DT_ENDPOINT,
|
| 58 | .bEndpointAddress = USB_DIR_IN,
|
| 59 | .bmAttributes = USB_ENDPOINT_XFER_BULK,
|
| 60 | };
|
| 61 |
|
| 62 | static struct usb_endpoint_descriptor gser_fs_out_desc = {
|
| 63 | .bLength = USB_DT_ENDPOINT_SIZE,
|
| 64 | .bDescriptorType = USB_DT_ENDPOINT,
|
| 65 | .bEndpointAddress = USB_DIR_OUT,
|
| 66 | .bmAttributes = USB_ENDPOINT_XFER_BULK,
|
| 67 | };
|
| 68 |
|
| 69 | static struct usb_descriptor_header *gser_fs_function[] = {
|
| 70 | (struct usb_descriptor_header *) &gser_interface_desc,
|
| 71 | (struct usb_descriptor_header *) &gser_fs_in_desc,
|
| 72 | (struct usb_descriptor_header *) &gser_fs_out_desc,
|
| 73 | NULL,
|
| 74 | };
|
| 75 |
|
| 76 |
|
| 77 |
|
| 78 | static struct usb_endpoint_descriptor gser_hs_in_desc = {
|
| 79 | .bLength = USB_DT_ENDPOINT_SIZE,
|
| 80 | .bDescriptorType = USB_DT_ENDPOINT,
|
| 81 | .bmAttributes = USB_ENDPOINT_XFER_BULK,
|
| 82 | .wMaxPacketSize = cpu_to_le16(512),
|
| 83 | };
|
| 84 |
|
| 85 | static struct usb_endpoint_descriptor gser_hs_out_desc = {
|
| 86 | .bLength = USB_DT_ENDPOINT_SIZE,
|
| 87 | .bDescriptorType = USB_DT_ENDPOINT,
|
| 88 | .bmAttributes = USB_ENDPOINT_XFER_BULK,
|
| 89 | .wMaxPacketSize = cpu_to_le16(512),
|
| 90 | };
|
| 91 |
|
| 92 | static struct usb_descriptor_header *gser_hs_function[] = {
|
| 93 | (struct usb_descriptor_header *) &gser_interface_desc,
|
| 94 | (struct usb_descriptor_header *) &gser_hs_in_desc,
|
| 95 | (struct usb_descriptor_header *) &gser_hs_out_desc,
|
| 96 | NULL,
|
| 97 | };
|
| 98 |
|
| 99 | static struct usb_endpoint_descriptor gser_ss_in_desc = {
|
| 100 | .bLength = USB_DT_ENDPOINT_SIZE,
|
| 101 | .bDescriptorType = USB_DT_ENDPOINT,
|
| 102 | .bmAttributes = USB_ENDPOINT_XFER_BULK,
|
| 103 | .wMaxPacketSize = cpu_to_le16(1024),
|
| 104 | };
|
| 105 |
|
| 106 | static struct usb_endpoint_descriptor gser_ss_out_desc = {
|
| 107 | .bLength = USB_DT_ENDPOINT_SIZE,
|
| 108 | .bDescriptorType = USB_DT_ENDPOINT,
|
| 109 | .bmAttributes = USB_ENDPOINT_XFER_BULK,
|
| 110 | .wMaxPacketSize = cpu_to_le16(1024),
|
| 111 | };
|
| 112 |
|
| 113 | static struct usb_ss_ep_comp_descriptor gser_ss_bulk_comp_desc = {
|
| 114 | .bLength = sizeof gser_ss_bulk_comp_desc,
|
| 115 | .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
|
| 116 | };
|
| 117 |
|
| 118 | static struct usb_descriptor_header *gser_ss_function[] = {
|
| 119 | (struct usb_descriptor_header *) &gser_interface_desc,
|
| 120 | (struct usb_descriptor_header *) &gser_ss_in_desc,
|
| 121 | (struct usb_descriptor_header *) &gser_ss_bulk_comp_desc,
|
| 122 | (struct usb_descriptor_header *) &gser_ss_out_desc,
|
| 123 | (struct usb_descriptor_header *) &gser_ss_bulk_comp_desc,
|
| 124 | NULL,
|
| 125 | };
|
| 126 |
|
| 127 |
|
| 128 |
|
| 129 | static struct usb_string gser_string_defs[] = {
|
| 130 | [0].s = "Generic Serial",
|
| 131 | { }
|
| 132 | };
|
| 133 |
|
| 134 | static struct usb_gadget_strings gser_string_table = {
|
| 135 | .language = 0x0409,
|
| 136 | .strings = gser_string_defs,
|
| 137 | };
|
| 138 |
|
| 139 | static struct usb_gadget_strings *gser_strings[] = {
|
| 140 | &gser_string_table,
|
| 141 | NULL,
|
| 142 | };
|
| 143 |
|
| 144 |
|
| 145 |
|
| 146 | static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
| 147 | {
|
| 148 | struct f_gser *gser = func_to_gser(f);
|
| 149 | struct usb_composite_dev *cdev = f->config->cdev;
|
| 150 |
|
| 151 |
|
| 152 |
|
| 153 | if (gser->port.in->enabled) {
|
| 154 | dev_dbg(&cdev->gadget->dev,
|
| 155 | "reset generic ttyGS%d\n", gser->port_num);
|
| 156 | gserial_disconnect(&gser->port);
|
| 157 | }
|
| 158 | if (!gser->port.in->desc || !gser->port.out->desc) {
|
| 159 | dev_dbg(&cdev->gadget->dev,
|
| 160 | "activate generic ttyGS%d\n", gser->port_num);
|
| 161 | if (config_ep_by_speed(cdev->gadget, f, gser->port.in) ||
|
| 162 | config_ep_by_speed(cdev->gadget, f, gser->port.out)) {
|
| 163 | gser->port.in->desc = NULL;
|
| 164 | gser->port.out->desc = NULL;
|
| 165 | return -EINVAL;
|
| 166 | }
|
| 167 | }
|
| 168 | gserial_connect(&gser->port, gser->port_num);
|
| 169 | return 0;
|
| 170 | }
|
| 171 |
|
| 172 | static void gser_disable(struct usb_function *f)
|
| 173 | {
|
| 174 | struct f_gser *gser = func_to_gser(f);
|
| 175 | struct usb_composite_dev *cdev = f->config->cdev;
|
| 176 |
|
| 177 | dev_dbg(&cdev->gadget->dev,
|
| 178 | "generic ttyGS%d deactivated\n", gser->port_num);
|
| 179 | gserial_disconnect(&gser->port);
|
| 180 | }
|
| 181 |
|
| 182 |
|
| 183 |
|
| 184 |
|
| 185 |
|
| 186 | static int gser_bind(struct usb_configuration *c, struct usb_function *f)
|
| 187 | {
|
| 188 | struct usb_composite_dev *cdev = c->cdev;
|
| 189 | struct f_gser *gser = func_to_gser(f);
|
| 190 | int status;
|
| 191 | struct usb_ep *ep;
|
| 192 |
|
| 193 | |
| 194 | * distinguish instances ...
|
| 195 |
|
| 196 |
|
| 197 |
|
| 198 | if (gser_string_defs[0].id == 0) {
|
| 199 | status = usb_string_id(c->cdev);
|
| 200 | if (status < 0)
|
| 201 | return status;
|
| 202 | gser_string_defs[0].id = status;
|
| 203 | }
|
| 204 |
|
| 205 |
|
| 206 | status = usb_interface_id(c, f);
|
| 207 | if (status < 0)
|
| 208 | goto fail;
|
| 209 | gser->data_id = status;
|
| 210 | gser_interface_desc.bInterfaceNumber = status;
|
| 211 |
|
| 212 | status = -ENODEV;
|
| 213 |
|
| 214 |
|
| 215 | ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_in_desc);
|
| 216 | if (!ep)
|
| 217 | goto fail;
|
| 218 | gser->port.in = ep;
|
| 219 |
|
| 220 | ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_out_desc);
|
| 221 | if (!ep)
|
| 222 | goto fail;
|
| 223 | gser->port.out = ep;
|
| 224 |
|
| 225 | |
| 226 | * hardware is dual speed, all bulk-capable endpoints work at
|
| 227 | * both speeds
|
| 228 |
|
| 229 | gser_hs_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress;
|
| 230 | gser_hs_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress;
|
| 231 |
|
| 232 | gser_ss_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress;
|
| 233 | gser_ss_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress;
|
| 234 |
|
| 235 | status = usb_assign_descriptors(f, gser_fs_function, gser_hs_function,
|
| 236 | gser_ss_function, gser_ss_function);
|
| 237 | if (status)
|
| 238 | goto fail;
|
| 239 | dev_dbg(&cdev->gadget->dev, "generic ttyGS%d: IN/%s OUT/%s\n",
|
| 240 | gser->port_num,
|
| 241 | gser->port.in->name, gser->port.out->name);
|
| 242 | return 0;
|
| 243 |
|
| 244 | fail:
|
| 245 | ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
|
| 246 |
|
| 247 | return status;
|
| 248 | }
|
| 249 |
|
| 250 | static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
|
| 251 | {
|
| 252 | return container_of(to_config_group(item), struct f_serial_opts,
|
| 253 | func_inst.group);
|
| 254 | }
|
| 255 |
|
| 256 | static void serial_attr_release(struct config_item *item)
|
| 257 | {
|
| 258 | struct f_serial_opts *opts = to_f_serial_opts(item);
|
| 259 |
|
| 260 | usb_put_function_instance(&opts->func_inst);
|
| 261 | }
|
| 262 |
|
| 263 | static const struct configfs_item_operations serial_item_ops = {
|
| 264 | .release = serial_attr_release,
|
| 265 | };
|
| 266 |
|
| 267 | #ifdef CONFIG_U_SERIAL_CONSOLE
|
| 268 |
|
| 269 | static ssize_t f_serial_console_store(struct config_item *item,
|
| 270 | const char *page, size_t count)
|
| 271 | {
|
| 272 | return gserial_set_console(to_f_serial_opts(item)->port_num,
|
| 273 | page, count);
|
| 274 | }
|
| 275 |
|
| 276 | static ssize_t f_serial_console_show(struct config_item *item, char *page)
|
| 277 | {
|
| 278 | return gserial_get_console(to_f_serial_opts(item)->port_num, page);
|
| 279 | }
|
| 280 |
|
| 281 | CONFIGFS_ATTR(f_serial_, console);
|
| 282 |
|
| 283 | #endif
|
| 284 |
|
| 285 | static ssize_t f_serial_port_num_show(struct config_item *item, char *page)
|
| 286 | {
|
| 287 | return sprintf(page, "%u\n", to_f_serial_opts(item)->port_num);
|
| 288 | }
|
| 289 |
|
| 290 | CONFIGFS_ATTR_RO(f_serial_, port_num);
|
| 291 |
|
| 292 | static struct configfs_attribute *acm_attrs[] = {
|
| 293 | #ifdef CONFIG_U_SERIAL_CONSOLE
|
| 294 | &f_serial_attr_console,
|
| 295 | #endif
|
| 296 | &f_serial_attr_port_num,
|
| 297 | NULL,
|
| 298 | };
|
| 299 |
|
| 300 | static const struct config_item_type serial_func_type = {
|
| 301 | .ct_item_ops = &serial_item_ops,
|
| 302 | .ct_attrs = acm_attrs,
|
| 303 | .ct_owner = THIS_MODULE,
|
| 304 | };
|
| 305 |
|
| 306 | static void gser_free_inst(struct usb_function_instance *f)
|
| 307 | {
|
| 308 | struct f_serial_opts *opts;
|
| 309 |
|
| 310 | opts = container_of(f, struct f_serial_opts, func_inst);
|
| 311 | gserial_free_line(opts->port_num);
|
| 312 | kfree(opts);
|
| 313 | }
|
| 314 |
|
| 315 | static struct usb_function_instance *gser_alloc_inst(void)
|
| 316 | {
|
| 317 | struct f_serial_opts *opts;
|
| 318 | int ret;
|
| 319 |
|
| 320 | opts = kzalloc_obj(*opts);
|
| 321 | if (!opts)
|
| 322 | return ERR_PTR(-ENOMEM);
|
| 323 |
|
| 324 | opts->func_inst.free_func_inst = gser_free_inst;
|
| 325 | ret = gserial_alloc_line(&opts->port_num);
|
| 326 | if (ret) {
|
| 327 | kfree(opts);
|
| 328 | return ERR_PTR(ret);
|
| 329 | }
|
| 330 | config_group_init_type_name(&opts->func_inst.group, "",
|
| 331 | &serial_func_type);
|
| 332 |
|
| 333 | return &opts->func_inst;
|
| 334 | }
|
| 335 |
|
| 336 | static void gser_free(struct usb_function *f)
|
| 337 | {
|
| 338 | struct f_gser *serial;
|
| 339 |
|
| 340 | serial = func_to_gser(f);
|
| 341 | kfree(serial);
|
| 342 | }
|
| 343 |
|
| 344 | static void gser_unbind(struct usb_configuration *c, struct usb_function *f)
|
| 345 | {
|
| 346 | struct f_gser *gser = func_to_gser(f);
|
| 347 |
|
| 348 |
|
| 349 | gserial_disconnect(&gser->port);
|
| 350 | usb_free_all_descriptors(f);
|
| 351 | }
|
| 352 |
|
| 353 | static void gser_resume(struct usb_function *f)
|
| 354 | {
|
| 355 | struct f_gser *gser = func_to_gser(f);
|
| 356 |
|
| 357 | gserial_resume(&gser->port);
|
| 358 | }
|
| 359 |
|
| 360 | static void gser_suspend(struct usb_function *f)
|
| 361 | {
|
| 362 | struct f_gser *gser = func_to_gser(f);
|
| 363 |
|
| 364 | gserial_suspend(&gser->port);
|
| 365 | }
|
| 366 |
|
| 367 | static int gser_get_status(struct usb_function *f)
|
| 368 | {
|
| 369 | return (f->func_wakeup_armed ? USB_INTRF_STAT_FUNC_RW : 0) |
|
| 370 | USB_INTRF_STAT_FUNC_RW_CAP;
|
| 371 | }
|
| 372 |
|
| 373 | static struct usb_function *gser_alloc(struct usb_function_instance *fi)
|
| 374 | {
|
| 375 | struct f_gser *gser;
|
| 376 | struct f_serial_opts *opts;
|
| 377 |
|
| 378 |
|
| 379 | gser = kzalloc_obj(*gser);
|
| 380 | if (!gser)
|
| 381 | return ERR_PTR(-ENOMEM);
|
| 382 |
|
| 383 | opts = container_of(fi, struct f_serial_opts, func_inst);
|
| 384 |
|
| 385 | gser->port_num = opts->port_num;
|
| 386 |
|
| 387 | gser->port.func.name = "gser";
|
| 388 | gser->port.func.strings = gser_strings;
|
| 389 | gser->port.func.bind = gser_bind;
|
| 390 | gser->port.func.unbind = gser_unbind;
|
| 391 | gser->port.func.set_alt = gser_set_alt;
|
| 392 | gser->port.func.disable = gser_disable;
|
| 393 | gser->port.func.free_func = gser_free;
|
| 394 | gser->port.func.resume = gser_resume;
|
| 395 | gser->port.func.suspend = gser_suspend;
|
| 396 | gser->port.func.get_status = gser_get_status;
|
| 397 |
|
| 398 | return &gser->port.func;
|
| 399 | }
|
| 400 |
|
| 401 | DECLARE_USB_FUNCTION_INIT(gser, gser_alloc_inst, gser_alloc);
|
| 402 | MODULE_DESCRIPTION("generic USB serial function driver");
|
| 403 | MODULE_LICENSE("GPL");
|
| 404 | MODULE_AUTHOR("Al Borchers");
|
| 405 | MODULE_AUTHOR("David Brownell");
|