static int acm_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_cdc_union_desc *union_header = NULL; struct usb_cdc_country_functional_desc *cfd = NULL; unsigned char *buffer = intf->altsetting->extra; int buflen = intf->altsetting->extralen; struct usb_interface *control_interface; struct usb_interface *data_interface; struct usb_endpoint_descriptor *epctrl = NULL; struct usb_endpoint_descriptor *epread = NULL; struct usb_endpoint_descriptor *epwrite = NULL; struct usb_device *usb_dev = interface_to_usbdev(intf); struct acm *acm; int minor; int ctrlsize, readsize; u8 *buf; u8 ac_management_function = 0; u8 call_management_function = 0; int call_interface_num = -1; int data_interface_num = -1; unsigned long quirks; int num_rx_buf; int i; int combined_interfaces = 0; quirks = (unsigned long)id->driver_info; num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR; if (quirks == NO_UNION_NORMAL) { data_interface = usb_ifnum_to_if(usb_dev, 1); control_interface = usb_ifnum_to_if(usb_dev, 0); goto skip_normal_probe; } if (!buffer) { dev_err(&intf->dev, "Weird descriptor references\n"); return -EINVAL; } if (!buflen) { if (intf->cur_altsetting->endpoint && intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) { dev_dbg(&intf->dev, "Seeking extra descriptors on endpoint\n"); buflen = intf->cur_altsetting->endpoint->extralen; buffer = intf->cur_altsetting->endpoint->extra; } else { dev_err(&intf->dev, "Zero length descriptor references\n"); return -EINVAL; } } while (buflen > 0) { if (buffer[1] != USB_DT_CS_INTERFACE) { dev_err(&intf->dev, "skipping garbage\n"); goto next_desc; } switch (buffer[2]) { case USB_CDC_UNION_TYPE: if (union_header) { dev_err(&intf->dev, "More than one " "union descriptor, skipping ...\n"); goto next_desc; } union_header = (struct usb_cdc_union_desc *)buffer; break; case USB_CDC_COUNTRY_TYPE: cfd = (struct usb_cdc_country_functional_desc *)buffer; break; case USB_CDC_HEADER_TYPE: break; case USB_CDC_ACM_TYPE: ac_management_function = buffer[3]; break; case USB_CDC_CALL_MANAGEMENT_TYPE: call_management_function = buffer[3]; call_interface_num = buffer[4]; if ( (quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3) dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n"); break; default: dev_dbg(&intf->dev, "Ignoring descriptor: " "type %02x, length %d\n", buffer[2], buffer[0]); break; } next_desc: buflen -= buffer[0]; buffer += buffer[0]; } if (!union_header) { if (call_interface_num > 0) { dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n"); if (quirks & NO_DATA_INTERFACE) data_interface = usb_ifnum_to_if(usb_dev, 0); else data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num)); control_interface = intf; } else { if (intf->cur_altsetting->desc.bNumEndpoints != 3) { dev_dbg(&intf->dev,"No union descriptor, giving up\n"); return -ENODEV; } else { dev_warn(&intf->dev,"No union descriptor, testing for castrated device\n"); combined_interfaces = 1; control_interface = data_interface = intf; goto look_for_collapsed_interface; } } } else { control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); if (!control_interface || !data_interface) { dev_dbg(&intf->dev, "no interfaces\n"); return -ENODEV; } } if (data_interface_num != call_interface_num) dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n"); if (control_interface == data_interface) { dev_warn(&intf->dev,"Control and data interfaces are not separated!\n"); combined_interfaces = 1; quirks |= NO_CAP_LINE; if (data_interface->cur_altsetting->desc.bNumEndpoints != 3) { dev_err(&intf->dev, "This needs exactly 3 endpoints\n"); return -EINVAL; } look_for_collapsed_interface: for (i = 0; i < 3; i++) { struct usb_endpoint_descriptor *ep; ep = &data_interface->cur_altsetting->endpoint[i].desc; if (usb_endpoint_is_int_in(ep)) epctrl = ep; else if (usb_endpoint_is_bulk_out(ep)) epwrite = ep; else if (usb_endpoint_is_bulk_in(ep)) epread = ep; else return -EINVAL; } if (!epctrl || !epread || !epwrite) return -ENODEV; else goto made_compressed_probe; } skip_normal_probe: if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) { if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) { struct usb_interface *t; dev_dbg(&intf->dev, "Your device has switched interfaces.\n"); t = control_interface; control_interface = data_interface; data_interface = t; } else { return -EINVAL; } } if (!combined_interfaces && intf != control_interface) return -ENODEV; if (!combined_interfaces && usb_interface_claimed(data_interface)) { dev_dbg(&intf->dev, "The data interface isn't available\n"); return -EBUSY; } if (data_interface->cur_altsetting->desc.bNumEndpoints < 2) return -EINVAL; epctrl = &control_interface->cur_altsetting->endpoint[0].desc; epread = &data_interface->cur_altsetting->endpoint[0].desc; epwrite = &data_interface->cur_altsetting->endpoint[1].desc; if (!usb_endpoint_dir_in(epread)) { struct usb_endpoint_descriptor *t; dev_dbg(&intf->dev, "The data interface has switched endpoints\n"); t = epread; epread = epwrite; epwrite = t; } made_compressed_probe: dev_dbg(&intf->dev, "interfaces are valid\n"); acm = kzalloc(sizeof(struct acm), GFP_KERNEL); if (acm == NULL) { dev_err(&intf->dev, "out of memory (acm kzalloc)\n"); goto alloc_fail; } minor = acm_alloc_minor(acm); if (minor == ACM_TTY_MINORS) { dev_err(&intf->dev, "no more free acm devices\n"); kfree(acm); return -ENODEV; } ctrlsize = usb_endpoint_maxp(epctrl); readsize = usb_endpoint_maxp(epread) * (quirks == SINGLE_RX_URB ? 1 : 2); acm->combined_interfaces = combined_interfaces; acm->writesize = usb_endpoint_maxp(epwrite) * 20; acm->control = control_interface; acm->data = data_interface; acm->minor = minor; acm->dev = usb_dev; acm->ctrl_caps = ac_management_function; if (quirks & NO_CAP_LINE) acm->ctrl_caps &= ~USB_CDC_CAP_LINE; acm->ctrlsize = ctrlsize; acm->readsize = readsize; acm->rx_buflimit = num_rx_buf; INIT_WORK(&acm->work, acm_softint); spin_lock_init(&acm->write_lock); spin_lock_init(&acm->read_lock); mutex_init(&acm->mutex); acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); acm->is_int_ep = usb_endpoint_xfer_int(epread); if (acm->is_int_ep) acm->bInterval = epread->bInterval; tty_port_init(&acm->port); acm->port.ops = &acm_port_ops; buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); if (!buf) { dev_err(&intf->dev, "out of memory (ctrl buffer alloc)\n"); goto alloc_fail2; } acm->ctrl_buffer = buf; if (acm_write_buffers_alloc(acm) < 0) { dev_err(&intf->dev, "out of memory (write buffer alloc)\n"); goto alloc_fail4; } acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL); if (!acm->ctrlurb) { dev_err(&intf->dev, "out of memory (ctrlurb kmalloc)\n"); goto alloc_fail5; } for (i = 0; i < num_rx_buf; i++) { struct acm_rb *rb = &(acm->read_buffers[i]); struct urb *urb; rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL, &rb->dma); if (!rb->base) { dev_err(&intf->dev, "out of memory " "(read bufs usb_alloc_coherent)\n"); goto alloc_fail6; } rb->index = i; rb->instance = acm; urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) { dev_err(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n"); goto alloc_fail6; } urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; urb->transfer_dma = rb->dma; if (acm->is_int_ep) { usb_fill_int_urb(urb, acm->dev, acm->rx_endpoint, rb->base, acm->readsize, acm_read_bulk_callback, rb, acm->bInterval); } else { usb_fill_bulk_urb(urb, acm->dev, acm->rx_endpoint, rb->base, acm->readsize, acm_read_bulk_callback, rb); } acm->read_urbs[i] = urb; __set_bit(i, &acm->read_urbs_free); } for (i = 0; i < ACM_NW; i++) { struct acm_wb *snd = &(acm->wb[i]); snd->urb = usb_alloc_urb(0, GFP_KERNEL); if (snd->urb == NULL) { dev_err(&intf->dev, "out of memory (write urbs usb_alloc_urb)\n"); goto alloc_fail7; } if (usb_endpoint_xfer_int(epwrite)) usb_fill_int_urb(snd->urb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), NULL, acm->writesize, acm_write_bulk, snd, epwrite->bInterval); else usb_fill_bulk_urb(snd->urb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), NULL, acm->writesize, acm_write_bulk, snd); snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; snd->instance = acm; } usb_set_intfdata(intf, acm); i = device_create_file(&intf->dev, &dev_attr_bmCapabilities); if (i < 0) goto alloc_fail7; if (cfd) { acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL); if (!acm->country_codes) goto skip_countries; acm->country_code_size = cfd->bLength - 4; memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, cfd->bLength - 4); acm->country_rel_date = cfd->iCountryCodeRelDate; i = device_create_file(&intf->dev, &dev_attr_wCountryCodes); if (i < 0) { kfree(acm->country_codes); acm->country_codes = NULL; acm->country_code_size = 0; goto skip_countries; } i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate); if (i < 0) { device_remove_file(&intf->dev, &dev_attr_wCountryCodes); kfree(acm->country_codes); acm->country_codes = NULL; acm->country_code_size = 0; goto skip_countries; } } skip_countries: usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress), acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval ? epctrl->bInterval : 0xff); acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; acm->ctrlurb->transfer_dma = acm->ctrl_dma; dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); acm_set_control(acm, acm->ctrlout); acm->line.dwDTERate = cpu_to_le32(9600); acm->line.bDataBits = 8; acm_set_line(acm, &acm->line); usb_driver_claim_interface(&acm_driver, data_interface, acm); usb_set_intfdata(data_interface, acm); usb_get_intf(control_interface); tty_register_device(acm_tty_driver, minor, &control_interface->dev); return 0; alloc_fail7: for (i = 0; i < ACM_NW; i++) usb_free_urb(acm->wb[i].urb); alloc_fail6: for (i = 0; i < num_rx_buf; i++) usb_free_urb(acm->read_urbs[i]); acm_read_buffers_free(acm); usb_free_urb(acm->ctrlurb); alloc_fail5: acm_write_buffers_free(acm); alloc_fail4: usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); alloc_fail2: acm_release_minor(acm); kfree(acm); alloc_fail: return -ENOMEM; }
/** * gserial_setup - initialize TTY driver for one or more ports * @g: gadget to associate with these ports * @count: how many ports to support * Context: may sleep * * The TTY stack needs to know in advance how many devices it should * plan to manage. Use this call to set up the ports you will be * exporting through USB. Later, connect them to functions based * on what configuration is activated by the USB host; and disconnect * them as appropriate. * * An example would be a two-configuration device in which both * configurations expose port 0, but through different functions. * One configuration could even expose port 1 while the other * one doesn't. * * Returns negative errno or zero. */ int gserial_setup(struct usb_gadget *g, unsigned count) { unsigned i; struct usb_cdc_line_coding coding; int status; if (count == 0 || count > N_PORTS) return -EINVAL; gs_tty_driver = alloc_tty_driver(count); if (!gs_tty_driver) return -ENOMEM; gs_tty_driver->owner = THIS_MODULE; gs_tty_driver->driver_name = "g_serial"; gs_tty_driver->name = PREFIX; /* uses dynamically assigned dev_t values */ gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; gs_tty_driver->subtype = SERIAL_TYPE_NORMAL; gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_RESET_TERMIOS; gs_tty_driver->init_termios = tty_std_termios; /* 9600-8-N-1 ... matches defaults expected by "usbser.sys" on * MS-Windows. Otherwise, most of these flags shouldn't affect * anything unless we were to actually hook up to a serial line. */ gs_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; gs_tty_driver->init_termios.c_ispeed = 9600; gs_tty_driver->init_termios.c_ospeed = 9600; coding.dwDTERate = cpu_to_le32(9600); coding.bCharFormat = 8; coding.bParityType = USB_CDC_NO_PARITY; coding.bDataBits = USB_CDC_1_STOP_BITS; tty_set_operations(gs_tty_driver, &gs_tty_ops); gserial_wq = create_singlethread_workqueue("k_gserial"); if (!gserial_wq) { status = -ENOMEM; goto fail; } /* make devices be openable */ for (i = 0; i < count; i++) { mutex_init(&ports[i].lock); status = gs_port_alloc(i, &coding); if (status) { count = i; goto fail; } } n_ports = count; /* export the driver ... */ status = tty_register_driver(gs_tty_driver); if (status) { put_tty_driver(gs_tty_driver); pr_err("%s: cannot register, err %d\n", __func__, status); goto fail; } /* ... and sysfs class devices, so mdev/udev make /dev/ttyGS* */ for (i = 0; i < count; i++) { struct device *tty_dev; tty_dev = tty_register_device(gs_tty_driver, i, &g->dev); if (IS_ERR(tty_dev)) pr_warning("%s: no classdev for port %d, err %ld\n", __func__, i, PTR_ERR(tty_dev)); } pr_debug("%s: registered %d ttyGS* device%s\n", __func__, count, (count == 1) ? "" : "s"); return status; fail: while (count--) kfree(ports[count].port); destroy_workqueue(gserial_wq); put_tty_driver(gs_tty_driver); gs_tty_driver = NULL; return status; }
/** * gserial_setup - initialize TTY driver for one or more ports * @g: gadget to associate with these ports * @count: how many ports to support * Context: may sleep * * The TTY stack needs to know in advance how many devices it should * plan to manage. Use this call to set up the ports you will be * exporting through USB. Later, connect them to functions based * on what configuration is activated by the USB host; and disconnect * them as appropriate. * * An example would be a two-configuration device in which both * configurations expose port 0, but through different functions. * One configuration could even expose port 1 while the other * one doesn't. * * Returns negative errno or zero. */ int gserial_setup(struct usb_gadget *g, unsigned count) { unsigned i; struct usb_cdc_line_coding coding; int status; struct device *tty_dev; if (count == 0 || count > ACM_TTY_COUNT) return -EINVAL; /* count:0 is init in the bsp_usb_console_init */ if (count > 1) { gs_tty_driver = alloc_tty_driver(count-1); if (!gs_tty_driver) return -ENOMEM; gs_tty_driver->driver_name = "g_serial"; gs_tty_driver->name = PREFIX; /* uses dynamically assigned dev_t values */ gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; gs_tty_driver->subtype = SERIAL_TYPE_NORMAL; gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; gs_tty_driver->init_termios = tty_std_termios; /* 9600-8-N-1 ... matches defaults expected by "usbser.sys" on * MS-Windows. Otherwise, most of these flags shouldn't affect * anything unless we were to actually hook up to a serial line. */ gs_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; gs_tty_driver->init_termios.c_ispeed = 9600; gs_tty_driver->init_termios.c_ospeed = 9600; gs_tty_driver->num = 1; coding.dwDTERate = cpu_to_le32(9600); coding.bCharFormat = 8; coding.bParityType = USB_CDC_NO_PARITY; coding.bDataBits = USB_CDC_1_STOP_BITS; tty_set_operations(gs_tty_driver, &gs_tty_ops); /* export the driver ... */ status = tty_register_driver(gs_tty_driver); if (status) { pr_err("%s: cannot register, err %d\n", __func__, status); goto fail; } } /* make devices be openable */ for (i = 1; i < count; i++) { mutex_init(&ports[i].lock); status = gs_port_alloc(i, &coding); if (status) { count = i; goto fail; } } n_ports = count; /* 1. reg tty device for console tty */ tty_dev = tty_register_device(gs_console_tty_driver, 0, &g->dev); if (IS_ERR(tty_dev)) pr_warning("%s: no classdev for port %d, err %ld\n", __func__, 0, PTR_ERR(tty_dev)); /* 2. reg other tty ... */ /* ... and sysfs class devices, so mdev/udev make /dev/ttyGS* */ for (i = 1; i < count; i++) { //struct device *tty_dev; /* i-1 means index start from 0 */ tty_dev = tty_register_device(gs_tty_driver, i-1, &g->dev); if (IS_ERR(tty_dev)) pr_warning("%s: no classdev for port %d, err %ld\n", __func__, i, PTR_ERR(tty_dev)); } pr_vdebug("%s: registered %d ttyGS* device%s\n", __func__, count, (count == 1) ? "" : "s"); return status;/* [false alarm]:fortify disable */ fail: /* never free console tty port */ while (count-- > 1) kfree(ports[count].port); put_tty_driver(gs_tty_driver); gs_tty_driver = NULL; return status; }
static int acm_probe (struct usb_interface *intf, const struct usb_device_id *id) { struct usb_cdc_union_desc *union_header = NULL; struct usb_cdc_country_functional_desc *cfd = NULL; char *buffer = intf->altsetting->extra; int buflen = intf->altsetting->extralen; struct usb_interface *control_interface; struct usb_interface *data_interface; struct usb_endpoint_descriptor *epctrl; struct usb_endpoint_descriptor *epread; struct usb_endpoint_descriptor *epwrite; struct usb_device *usb_dev = interface_to_usbdev(intf); struct acm *acm; int minor; int ctrlsize,readsize; u8 *buf; u8 ac_management_function = 0; u8 call_management_function = 0; int call_interface_num = -1; int data_interface_num; unsigned long quirks; int num_rx_buf; int i; /* normal quirks */ quirks = (unsigned long)id->driver_info; num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR; /* handle quirks deadly to normal probing*/ if (quirks == NO_UNION_NORMAL) { data_interface = usb_ifnum_to_if(usb_dev, 1); control_interface = usb_ifnum_to_if(usb_dev, 0); goto skip_normal_probe; } /* normal probing*/ if (!buffer) { err("Wierd descriptor references\n"); return -EINVAL; } if (!buflen) { if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) { dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint"); buflen = intf->cur_altsetting->endpoint->extralen; buffer = intf->cur_altsetting->endpoint->extra; } else { err("Zero length descriptor references\n"); return -EINVAL; } } while (buflen > 0) { if (buffer [1] != USB_DT_CS_INTERFACE) { err("skipping garbage\n"); goto next_desc; } switch (buffer [2]) { case USB_CDC_UNION_TYPE: /* we've found it */ if (union_header) { err("More than one union descriptor, skipping ..."); goto next_desc; } union_header = (struct usb_cdc_union_desc *) buffer; break; case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/ cfd = (struct usb_cdc_country_functional_desc *)buffer; break; case USB_CDC_HEADER_TYPE: /* maybe check version */ break; /* for now we ignore it */ case USB_CDC_ACM_TYPE: ac_management_function = buffer[3]; break; case USB_CDC_CALL_MANAGEMENT_TYPE: call_management_function = buffer[3]; call_interface_num = buffer[4]; if ((call_management_function & 3) != 3) err("This device cannot do calls on its own. It is no modem."); break; default: err("Ignoring extra header, type %d, length %d", buffer[2], buffer[0]); break; } next_desc: buflen -= buffer[0]; buffer += buffer[0]; } if (!union_header) { if (call_interface_num > 0) { dev_dbg(&intf->dev,"No union descriptor, using call management descriptor"); data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num)); control_interface = intf; } else { dev_dbg(&intf->dev,"No union descriptor, giving up"); return -ENODEV; } } else { control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); if (!control_interface || !data_interface) { dev_dbg(&intf->dev,"no interfaces"); return -ENODEV; } } if (data_interface_num != call_interface_num) dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported."); skip_normal_probe: /*workaround for switched interfaces */ if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) { if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) { struct usb_interface *t; dev_dbg(&intf->dev,"Your device has switched interfaces."); t = control_interface; control_interface = data_interface; data_interface = t; } else { return -EINVAL; } } /* Accept probe requests only for the control interface */ if (intf != control_interface) return -ENODEV; if (usb_interface_claimed(data_interface)) { /* valid in this context */ dev_dbg(&intf->dev,"The data interface isn't available"); return -EBUSY; } if (data_interface->cur_altsetting->desc.bNumEndpoints < 2) return -EINVAL; epctrl = &control_interface->cur_altsetting->endpoint[0].desc; epread = &data_interface->cur_altsetting->endpoint[0].desc; epwrite = &data_interface->cur_altsetting->endpoint[1].desc; /* workaround for switched endpoints */ if (!usb_endpoint_dir_in(epread)) { /* descriptors are swapped */ struct usb_endpoint_descriptor *t; dev_dbg(&intf->dev,"The data interface has switched endpoints"); t = epread; epread = epwrite; epwrite = t; } dbg("interfaces are valid"); for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++); if (minor == ACM_TTY_MINORS) { err("no more free acm devices"); return -ENODEV; } if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) { dev_dbg(&intf->dev, "out of memory (acm kzalloc)"); goto alloc_fail; } ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize); readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2); acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize); acm->control = control_interface; acm->data = data_interface; acm->minor = minor; acm->dev = usb_dev; acm->ctrl_caps = ac_management_function; acm->ctrlsize = ctrlsize; acm->readsize = readsize; acm->rx_buflimit = num_rx_buf; acm->urb_task.func = acm_rx_tasklet; acm->urb_task.data = (unsigned long) acm; INIT_WORK(&acm->work, acm_softint); spin_lock_init(&acm->throttle_lock); spin_lock_init(&acm->write_lock); spin_lock_init(&acm->read_lock); acm->write_ready = 1; acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); if (!buf) { dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)"); goto alloc_fail2; } acm->ctrl_buffer = buf; if (acm_write_buffers_alloc(acm) < 0) { dev_dbg(&intf->dev, "out of memory (write buffer alloc)"); goto alloc_fail4; } acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL); if (!acm->ctrlurb) { dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)"); goto alloc_fail5; } for (i = 0; i < num_rx_buf; i++) { struct acm_ru *rcv = &(acm->ru[i]); if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) { dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)"); goto alloc_fail7; } rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; rcv->instance = acm; } for (i = 0; i < num_rx_buf; i++) { struct acm_rb *buf = &(acm->rb[i]); if (!(buf->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &buf->dma))) { dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)"); goto alloc_fail7; } } acm->writeurb = usb_alloc_urb(0, GFP_KERNEL); if (!acm->writeurb) { dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)"); goto alloc_fail7; } usb_set_intfdata (intf, acm); i = device_create_file(&intf->dev, &dev_attr_bmCapabilities); if (i < 0) goto alloc_fail8; if (cfd) { /* export the country data */ acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL); if (!acm->country_codes) goto skip_countries; acm->country_code_size = cfd->bLength - 4; memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, cfd->bLength - 4); acm->country_rel_date = cfd->iCountryCodeRelDate; i = device_create_file(&intf->dev, &dev_attr_wCountryCodes); if (i < 0) { kfree(acm->country_codes); goto skip_countries; } i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate); if (i < 0) { kfree(acm->country_codes); goto skip_countries; } } skip_countries: usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress), acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval); acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; acm->ctrlurb->transfer_dma = acm->ctrl_dma; usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), NULL, acm->writesize, acm_write_bulk, acm); acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP; dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); acm_set_control(acm, acm->ctrlout); acm->line.dwDTERate = cpu_to_le32(9600); acm->line.bDataBits = 8; acm_set_line(acm, &acm->line); usb_driver_claim_interface(&acm_driver, data_interface, acm); usb_get_intf(control_interface); tty_register_device(acm_tty_driver, minor, &control_interface->dev); acm_table[minor] = acm; return 0; alloc_fail8: usb_free_urb(acm->writeurb); alloc_fail7: for (i = 0; i < num_rx_buf; i++) usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); for (i = 0; i < num_rx_buf; i++) usb_free_urb(acm->ru[i].urb); usb_free_urb(acm->ctrlurb); alloc_fail5: acm_write_buffers_free(acm); alloc_fail4: usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); alloc_fail2: kfree(acm); alloc_fail: return -ENOMEM; }
static int __init smd_tty_init(void) { int ret; int n; int idx; smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS); if (smd_tty_driver == 0) return -ENOMEM; smd_tty_driver->owner = THIS_MODULE; smd_tty_driver->driver_name = "smd_tty_driver"; smd_tty_driver->name = "smd"; smd_tty_driver->major = 0; smd_tty_driver->minor_start = 0; smd_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; smd_tty_driver->subtype = SERIAL_TYPE_NORMAL; smd_tty_driver->init_termios = tty_std_termios; smd_tty_driver->init_termios.c_iflag = 0; smd_tty_driver->init_termios.c_oflag = 0; smd_tty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; smd_tty_driver->init_termios.c_lflag = 0; smd_tty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty_set_operations(smd_tty_driver, &smd_tty_ops); ret = tty_register_driver(smd_tty_driver); if (ret) { put_tty_driver(smd_tty_driver); pr_err("%s: driver registration failed %d\n", __func__, ret); return ret; } for (n = 0; n < ARRAY_SIZE(smd_configs); ++n) { idx = smd_configs[n].tty_dev_index; if (smd_configs[n].dev_name == NULL) smd_configs[n].dev_name = smd_configs[n].port_name; #if 0 if (idx == DS_IDX) { /* * DS port uses the kernel API starting with * 8660 Fusion. Only register the userspace * platform device for older targets. */ int legacy_ds = 0; legacy_ds |= cpu_is_msm7x01() || cpu_is_msm7x25(); legacy_ds |= cpu_is_msm7x27() || cpu_is_msm7x30(); legacy_ds |= cpu_is_qsd8x50() || cpu_is_msm8x55(); /* * use legacy mode for 8660 Standalone (subtype 0) */ legacy_ds |= cpu_is_msm8x60() && (socinfo_get_platform_subtype() == 0x0); if (!legacy_ds) continue; } #endif tty_register_device(smd_tty_driver, idx, 0); init_completion(&smd_tty[idx].ch_allocated); /* register platform device */ smd_tty[idx].driver.probe = smd_tty_dummy_probe; smd_tty[idx].driver.driver.name = smd_configs[n].dev_name; smd_tty[idx].driver.driver.owner = THIS_MODULE; spin_lock_init(&smd_tty[idx].reset_lock); smd_tty[idx].is_open = 0; setup_timer(&smd_tty[idx].buf_req_timer, buf_req_retry, (unsigned long)&smd_tty[idx]); init_waitqueue_head(&smd_tty[idx].ch_opened_wait_queue); ret = platform_driver_register(&smd_tty[idx].driver); if (ret) { pr_err("%s: init failed %d (%d)\n", __func__, idx, ret); smd_tty[idx].driver.probe = NULL; goto out; } smd_tty[idx].smd = &smd_configs[n]; } INIT_DELAYED_WORK(&loopback_work, loopback_probe_worker); return 0; out: /* unregister platform devices */ for (n = 0; n < ARRAY_SIZE(smd_configs); ++n) { idx = smd_configs[n].tty_dev_index; if (smd_tty[idx].driver.probe) { platform_driver_unregister(&smd_tty[idx].driver); tty_unregister_device(smd_tty_driver, idx); } } tty_unregister_driver(smd_tty_driver); put_tty_driver(smd_tty_driver); return ret; }
static int __init lge_dm_tty_init(void) { int ret = 0; struct device *tty_dev; struct dm_tty *lge_dm_tty_drv; #ifdef CONFIG_TTY_PORT tty_port_init(&dm_tty_port); #endif /* CONFIG_TTY_PORT */ pr_info(DM_TTY_MODULE_NAME ": %s\n", __func__); if(lge_dm_tty != NULL) { lge_dm_tty_drv = lge_dm_tty; } else { lge_dm_tty_drv = kzalloc(sizeof(struct dm_tty), GFP_KERNEL); if (lge_dm_tty_drv == NULL) { pr_info(DM_TTY_MODULE_NAME "%s:" "failed to allocate lge_dm_tty", __func__); return 0; } lge_dm_tty = lge_dm_tty_drv; } lge_dm_tty_drv->tty_drv = alloc_tty_driver(MAX_DM_TTY_DRV); if (!lge_dm_tty_drv->tty_drv) { pr_info(DM_TTY_MODULE_NAME ": %s - tty_drv is NULL", __func__); kfree(lge_dm_tty_drv); return 0; } lge_dm_tty_drv->tty_drv->name = "lge_dm_tty"; lge_dm_tty_drv->tty_drv->owner = THIS_MODULE; lge_dm_tty_drv->tty_drv->driver_name = "lge_dm_tty"; /* uses dynamically assigned dev_t values */ lge_dm_tty_drv->tty_drv->type = TTY_DRIVER_TYPE_SERIAL; lge_dm_tty_drv->tty_drv->subtype = SERIAL_TYPE_NORMAL; lge_dm_tty_drv->tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_RESET_TERMIOS; /* initializing the tty driver */ lge_dm_tty_drv->tty_drv->init_termios = tty_std_termios; lge_dm_tty_drv->tty_drv->init_termios.c_iflag = IGNBRK | IGNPAR; lge_dm_tty_drv->tty_drv->init_termios.c_oflag = 0; lge_dm_tty_drv->tty_drv->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; lge_dm_tty_drv->tty_drv->init_termios.c_lflag = 0; tty_set_operations(lge_dm_tty_drv->tty_drv, &lge_dm_tty_ops); #ifdef CONFIG_TTY_PORT tty_port_link_device(&dm_tty_port, lge_dm_tty_drv->tty_drv, 0); #endif /* CONFIG_TTY_PORT */ ret = tty_register_driver(lge_dm_tty_drv->tty_drv); if (ret) { put_tty_driver(lge_dm_tty_drv->tty_drv); #ifdef CONFIG_TTY_PORT tty_port_destroy(&dm_tty_port); #endif /* CONFIG_TTY_PORT */ pr_info(DM_TTY_MODULE_NAME ": %s:" "tty_register_driver() ""failed\n", __func__); lge_dm_tty_drv->tty_drv = NULL; kfree(lge_dm_tty_drv); return 0; } tty_dev = tty_register_device(lge_dm_tty_drv->tty_drv, 0, NULL); if (IS_ERR(tty_dev)) { pr_info(DM_TTY_MODULE_NAME ": %s:" "tty_register_device() " "failed\n", __func__); tty_unregister_driver(lge_dm_tty_drv->tty_drv); put_tty_driver(lge_dm_tty_drv->tty_drv); #ifdef CONFIG_TTY_PORT tty_port_destroy(&dm_tty_port); #endif /* CONFIG_TTY_PORT */ kfree(lge_dm_tty_drv); return 0; } init_waitqueue_head(&lge_dm_tty_drv->waitq); lge_dm_tty_drv->tty_state = DM_TTY_REGISTERED; /* data initialization */ dm_modem_response = kzalloc(DM_TTY_TX_MAX_PACKET_SIZE, GFP_KERNEL); if (dm_modem_response == NULL) pr_info(DM_TTY_MODULE_NAME ": %s: dm_modem_response ""failed\n", __func__); dm_modem_request = kzalloc(DM_TTY_RX_MAX_PACKET_SIZE, GFP_KERNEL); if (dm_modem_request == NULL) pr_info(DM_TTY_MODULE_NAME ": %s: dm_modem_request ""failed\n", __func__); dm_modem_response_header_length = sizeof(struct dm_router_header); dm_modem_response_header = kzalloc(dm_modem_response_header_length, GFP_KERNEL); if (dm_modem_response_header == NULL) pr_info(DM_TTY_MODULE_NAME ": %s: dm_modem_response_header " "failed\n", __func__); dm_modem_request_header_length = sizeof(struct dm_router_header); dm_modem_request_header = kzalloc(dm_modem_request_header_length, GFP_KERNEL); if (dm_modem_request_header == NULL) pr_info(DM_TTY_MODULE_NAME ": %s: dm_modem_request_header " "failed\n", __func__); dm_modem_response_body_length = sizeof(struct dm_router_modem_response_body); dm_modem_response_body = kzalloc(dm_modem_response_body_length, GFP_KERNEL); if (dm_modem_response_body == NULL) pr_info(DM_TTY_MODULE_NAME ": %s: dm_modem_response_body " "failed\n", __func__); return 0; }
static int acm_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_cdc_union_desc *union_header = NULL; struct usb_cdc_country_functional_desc *cfd = NULL; unsigned char *buffer = intf->altsetting->extra; int buflen = intf->altsetting->extralen; struct usb_interface *control_interface; struct usb_interface *data_interface; struct usb_endpoint_descriptor *epctrl = NULL; struct usb_endpoint_descriptor *epread = NULL; struct usb_endpoint_descriptor *epwrite = NULL; struct usb_device *usb_dev = interface_to_usbdev(intf); struct acm *acm; int minor; int ctrlsize, readsize; u8 *buf; u8 ac_management_function = 0; u8 call_management_function = 0; int call_interface_num = -1; int data_interface_num; unsigned long quirks; int num_rx_buf; int i; int combined_interfaces = 0; /* normal quirks */ quirks = (unsigned long)id->driver_info; num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR; /* handle quirks deadly to normal probing*/ if (quirks == NO_UNION_NORMAL) { data_interface = usb_ifnum_to_if(usb_dev, 1); control_interface = usb_ifnum_to_if(usb_dev, 0); goto skip_normal_probe; } /* normal probing*/ if (!buffer) { dev_err(&intf->dev, "Weird descriptor references\n"); return -EINVAL; } if (!buflen) { if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) { dev_dbg(&intf->dev, "Seeking extra descriptors on endpoint\n"); buflen = intf->cur_altsetting->endpoint->extralen; buffer = intf->cur_altsetting->endpoint->extra; } else { dev_err(&intf->dev, "Zero length descriptor references\n"); return -EINVAL; } } while (buflen > 0) { if (buffer[1] != USB_DT_CS_INTERFACE) { dev_err(&intf->dev, "skipping garbage\n"); goto next_desc; } switch (buffer[2]) { case USB_CDC_UNION_TYPE: /* we've found it */ if (union_header) { dev_err(&intf->dev, "More than one " "union descriptor, skipping ...\n"); goto next_desc; } union_header = (struct usb_cdc_union_desc *)buffer; break; case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/ cfd = (struct usb_cdc_country_functional_desc *)buffer; break; case USB_CDC_HEADER_TYPE: /* maybe check version */ break; /* for now we ignore it */ case USB_CDC_ACM_TYPE: ac_management_function = buffer[3]; break; case USB_CDC_CALL_MANAGEMENT_TYPE: call_management_function = buffer[3]; call_interface_num = buffer[4]; if ((call_management_function & 3) != 3) dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n"); break; default: /* there are LOTS more CDC descriptors that * could legitimately be found here. */ dev_dbg(&intf->dev, "Ignoring descriptor: " "type %02x, length %d\n", buffer[2], buffer[0]); break; } next_desc: buflen -= buffer[0]; buffer += buffer[0]; } if (!union_header) { if (call_interface_num > 0) { dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n"); data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num)); control_interface = intf; } else { if (intf->cur_altsetting->desc.bNumEndpoints != 3) { dev_dbg(&intf->dev,"No union descriptor, giving up\n"); return -ENODEV; } else { dev_warn(&intf->dev,"No union descriptor, testing for castrated device\n"); combined_interfaces = 1; control_interface = data_interface = intf; goto look_for_collapsed_interface; } } } else { control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); if (!control_interface || !data_interface) { dev_dbg(&intf->dev, "no interfaces\n"); return -ENODEV; } } if (data_interface_num != call_interface_num) dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n"); if (control_interface == data_interface) { /* some broken devices designed for windows work this way */ dev_warn(&intf->dev,"Control and data interfaces are not separated!\n"); combined_interfaces = 1; /* a popular other OS doesn't use it */ quirks |= NO_CAP_LINE; if (data_interface->cur_altsetting->desc.bNumEndpoints != 3) { dev_err(&intf->dev, "This needs exactly 3 endpoints\n"); return -EINVAL; } look_for_collapsed_interface: for (i = 0; i < 3; i++) { struct usb_endpoint_descriptor *ep; ep = &data_interface->cur_altsetting->endpoint[i].desc; if (usb_endpoint_is_int_in(ep)) epctrl = ep; else if (usb_endpoint_is_bulk_out(ep)) epwrite = ep; else if (usb_endpoint_is_bulk_in(ep)) epread = ep; else return -EINVAL; } if (!epctrl || !epread || !epwrite) return -ENODEV; else goto made_compressed_probe; } skip_normal_probe: /*workaround for switched interfaces */ if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) { if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) { struct usb_interface *t; dev_dbg(&intf->dev, "Your device has switched interfaces.\n"); t = control_interface; control_interface = data_interface; data_interface = t; } else { return -EINVAL; } } /* Accept probe requests only for the control interface */ if (!combined_interfaces && intf != control_interface) return -ENODEV; if (!combined_interfaces && usb_interface_claimed(data_interface)) { /* valid in this context */ dev_dbg(&intf->dev, "The data interface isn't available\n"); return -EBUSY; } if (data_interface->cur_altsetting->desc.bNumEndpoints < 2) return -EINVAL; epctrl = &control_interface->cur_altsetting->endpoint[0].desc; epread = &data_interface->cur_altsetting->endpoint[0].desc; epwrite = &data_interface->cur_altsetting->endpoint[1].desc; /* workaround for switched endpoints */ if (!usb_endpoint_dir_in(epread)) { /* descriptors are swapped */ struct usb_endpoint_descriptor *t; dev_dbg(&intf->dev, "The data interface has switched endpoints\n"); t = epread; epread = epwrite; epwrite = t; } made_compressed_probe: dbg("interfaces are valid"); for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++); if (minor == ACM_TTY_MINORS) { dev_err(&intf->dev, "no more free acm devices\n"); return -ENODEV; } acm = kzalloc(sizeof(struct acm), GFP_KERNEL); if (acm == NULL) { dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n"); goto alloc_fail; } ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize); readsize = le16_to_cpu(epread->wMaxPacketSize) * (quirks == SINGLE_RX_URB ? 1 : 2); acm->combined_interfaces = combined_interfaces; acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20; acm->control = control_interface; acm->data = data_interface; acm->minor = minor; acm->dev = usb_dev; acm->ctrl_caps = ac_management_function; if (quirks & NO_CAP_LINE) acm->ctrl_caps &= ~USB_CDC_CAP_LINE; acm->ctrlsize = ctrlsize; acm->readsize = readsize; acm->rx_buflimit = num_rx_buf; acm->urb_task.func = acm_rx_tasklet; acm->urb_task.data = (unsigned long) acm; INIT_WORK(&acm->work, acm_softint); INIT_WORK(&acm->waker, acm_waker); init_waitqueue_head(&acm->drain_wait); spin_lock_init(&acm->throttle_lock); spin_lock_init(&acm->write_lock); spin_lock_init(&acm->read_lock); mutex_init(&acm->mutex); acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); acm->is_int_ep = usb_endpoint_xfer_int(epread); if (acm->is_int_ep) acm->bInterval = epread->bInterval; tty_port_init(&acm->port); acm->port.ops = &acm_port_ops; buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); if (!buf) { dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)\n"); goto alloc_fail2; } acm->ctrl_buffer = buf; if (acm_write_buffers_alloc(acm) < 0) { dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n"); goto alloc_fail4; } acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL); if (!acm->ctrlurb) { dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n"); goto alloc_fail5; } for (i = 0; i < num_rx_buf; i++) { struct acm_ru *rcv = &(acm->ru[i]); rcv->urb = usb_alloc_urb(0, GFP_KERNEL); if (rcv->urb == NULL) { dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n"); goto alloc_fail7; } rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; rcv->instance = acm; } for (i = 0; i < num_rx_buf; i++) { struct acm_rb *rb = &(acm->rb[i]); rb->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &rb->dma); if (!rb->base) { dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n"); goto alloc_fail7; } } for (i = 0; i < ACM_NW; i++) { struct acm_wb *snd = &(acm->wb[i]); snd->urb = usb_alloc_urb(0, GFP_KERNEL); if (snd->urb == NULL) { dev_dbg(&intf->dev, "out of memory (write urbs usb_alloc_urb)"); goto alloc_fail7; } if (usb_endpoint_xfer_int(epwrite)) usb_fill_int_urb(snd->urb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), NULL, acm->writesize, acm_write_bulk, snd, epwrite->bInterval); else usb_fill_bulk_urb(snd->urb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), NULL, acm->writesize, acm_write_bulk, snd); snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; snd->instance = acm; } usb_set_intfdata(intf, acm); i = device_create_file(&intf->dev, &dev_attr_bmCapabilities); if (i < 0) goto alloc_fail8; if (cfd) { /* export the country data */ acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL); if (!acm->country_codes) goto skip_countries; acm->country_code_size = cfd->bLength - 4; memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, cfd->bLength - 4); acm->country_rel_date = cfd->iCountryCodeRelDate; i = device_create_file(&intf->dev, &dev_attr_wCountryCodes); if (i < 0) { kfree(acm->country_codes); goto skip_countries; } i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate); if (i < 0) { kfree(acm->country_codes); goto skip_countries; } } skip_countries: usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress), acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, /* works around buggy devices */ epctrl->bInterval ? epctrl->bInterval : 0xff); acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; acm->ctrlurb->transfer_dma = acm->ctrl_dma; dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); acm_set_control(acm, acm->ctrlout); acm->line.dwDTERate = cpu_to_le32(9600); acm->line.bDataBits = 8; acm_set_line(acm, &acm->line); usb_driver_claim_interface(&acm_driver, data_interface, acm); usb_set_intfdata(data_interface, acm); usb_get_intf(control_interface); tty_register_device(acm_tty_driver, minor, &control_interface->dev); acm_table[minor] = acm; return 0; alloc_fail8: for (i = 0; i < ACM_NW; i++) usb_free_urb(acm->wb[i].urb); alloc_fail7: acm_read_buffers_free(acm); for (i = 0; i < num_rx_buf; i++) usb_free_urb(acm->ru[i].urb); usb_free_urb(acm->ctrlurb); alloc_fail5: acm_write_buffers_free(acm); alloc_fail4: usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); alloc_fail2: kfree(acm); alloc_fail: return -ENOMEM; }
static int __init spi_tty_init(void) { int retval; struct spi_tty_s *spi_tty; SPI_IPC_INFO("%s\n", __func__); tx_size = 0L; tx_time = 0L; tx_count = 0L; write_count = 0L; spi_tty_gbl = kmalloc(sizeof(*spi_tty), GFP_KERNEL); if (spi_tty_gbl == NULL) { pr_err("%s: Cannot malloc mem!\n", __func__); return -ENOMEM; } memset(spi_tty_gbl, 0x0, sizeof(*spi_tty)); spi_tty = spi_tty_gbl; spi_tty->write_buf = spi_tty_buf_alloc(); if (!spi_tty->write_buf) { kfree(spi_tty_gbl); pr_err("failed to malloc spi_tty write buf!\n"); return -ENOMEM; } spi_tty->throttle = 0; spi_tty->open_count = 0; spi_tty->tx_null = 0; spin_lock_init(&spi_tty->port_lock); mutex_init(&spi_tty->work_lock); INIT_WORK(&spi_tty->write_work, spi_tty_write_worker); wake_lock_init(&spi_tty->wakelock, WAKE_LOCK_SUSPEND, "spi_tty_wakelock"); init_waitqueue_head(&spi_tty->write_wait); spi_tty->write_buf_full = 0; spi_tty->work_queue = create_singlethread_workqueue("spi_tty_wq"); if (spi_tty->work_queue == NULL) { kfree(spi_tty); kfree(spi_big_trans.tx_buf); pr_err("Failed to create work queue\n"); return -ESRCH; } spi_message_init(&spi_big_msg); spi_big_trans.tx_buf = kmalloc(SPI_TRANSACTION_LEN*2, GFP_KERNEL); if (!spi_big_trans.tx_buf) { kfree(spi_tty); pr_err("%s: Cannot malloc mem!\n", __func__); return -ENOMEM; } spi_big_trans.rx_buf = (char*)spi_big_trans.tx_buf + SPI_TRANSACTION_LEN; spi_message_add_tail(&spi_big_trans, &spi_big_msg); spi_tty_driver = alloc_tty_driver(SPI_TTY_MINORS); if (!spi_tty_driver) return -ENOMEM; spi_tty_driver->owner = THIS_MODULE; spi_tty_driver->driver_name = "spi_modem"; spi_tty_driver->name = "ttySPI"; spi_tty_driver->major = SPI_TTY_MAJOR; spi_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; spi_tty_driver->subtype = SERIAL_TYPE_NORMAL; spi_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; spi_tty_driver->init_termios = tty_std_termios; spi_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; tty_set_operations(spi_tty_driver, &serial_ops); retval = tty_register_driver(spi_tty_driver); if (retval) { pr_err("failed to register spi_tty tty driver"); put_tty_driver(spi_tty_driver); return retval; } tty_register_device(spi_tty_driver, 0, NULL); /* * If spi_tty_register_device() was called before spi_tty_init(), fill * in the blanks. Yeah, it's ugly. */ if (spi_tty_dev) spi_tty_dev->callback_context = spi_tty; return retval; }
static int __init lge_tty_atcmd_init(void) { int ret; printk(KERN_INFO"%s: initialize atcmd-ttys\n", __func__); /* allocate and initialize downstream buffers */ down_stream_buffer.buf_addr = kmalloc(BUF_SIZE, GFP_KERNEL); if (down_stream_buffer.buf_addr == NULL) goto down_stream_buf_alloc_error; down_stream_buffer.head = 0; down_stream_buffer.tail = 0; down_stream_buffer.fifo_mask = BUF_SIZE - 1; down_stream_buffer.size = BUF_SIZE; down_stream_buffer.count = 0; down_stream_buffer.lock = &atcmd_ds_buf_lock; /* allocate and initialize upstream buffers */ up_stream_buffer.buf_addr = kmalloc(BUF_SIZE, GFP_KERNEL); if (up_stream_buffer.buf_addr == NULL) goto up_stream_buf_alloc_error; up_stream_buffer.head = 0; up_stream_buffer.tail = 0; up_stream_buffer.fifo_mask = BUF_SIZE - 1; up_stream_buffer.size = BUF_SIZE; up_stream_buffer.count = 0; up_stream_buffer.lock = &atcmd_us_buf_lock; /* allocate tty driver */ atcmd_tty_driver = alloc_tty_driver(MAX_ATCMD_TTYS); if (atcmd_tty_driver == 0) goto tty_alloc_error; /* setting tty */ atcmd_tty_driver->owner = THIS_MODULE; atcmd_tty_driver->driver_name = "atcmd-tty-driver"; atcmd_tty_driver->name = "atcmd-tty"; atcmd_tty_driver->major = 0; atcmd_tty_driver->minor_start = 0; atcmd_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; atcmd_tty_driver->subtype = SERIAL_TYPE_NORMAL; atcmd_tty_driver->init_termios = tty_std_termios; atcmd_tty_driver->init_termios.c_iflag = 0; atcmd_tty_driver->init_termios.c_oflag = 0; atcmd_tty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; atcmd_tty_driver->init_termios.c_lflag = 0; atcmd_tty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty_set_operations(atcmd_tty_driver, &atcmd_tty_ops); ret = tty_register_driver(atcmd_tty_driver); if (ret) return ret; /* this should be dynamic */ tty_register_device(atcmd_tty_driver, 0, 0); tty_register_device(atcmd_tty_driver, 1, 0); return 0; tty_alloc_error: kfree(up_stream_buffer.buf_addr); up_stream_buf_alloc_error: kfree(down_stream_buffer.buf_addr); down_stream_buf_alloc_error: return -ENOMEM; }
static int __init hsic_tty_init(void) { int ret; int n; unsigned port_num; pr_debug("%s\n", __func__); hsic_tty_driver = alloc_tty_driver(MAX_HSIC_TTYS); if (hsic_tty_driver == 0) return -ENOMEM; hsic_tty_driver->owner = THIS_MODULE; hsic_tty_driver->driver_name = "hsic_tty_driver"; hsic_tty_driver->name = "hsic"; hsic_tty_driver->major = 0; hsic_tty_driver->minor_start = 0; hsic_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; hsic_tty_driver->subtype = SERIAL_TYPE_NORMAL; hsic_tty_driver->init_termios = tty_std_termios; hsic_tty_driver->init_termios.c_iflag = 0; hsic_tty_driver->init_termios.c_oflag = 0; hsic_tty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; hsic_tty_driver->init_termios.c_lflag = 0; hsic_tty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty_set_operations(hsic_tty_driver, &hsic_tty_ops); ret = tty_register_driver(hsic_tty_driver); if (ret) { put_tty_driver(hsic_tty_driver); pr_err("%s: driver registration failed %d\n", __func__, ret); return ret; } port_num = hsic_tty_data_setup(1, HSIC_TTY_SERIAL); if (port_num < 0) { pr_err("%s: hsic_tty_data_setup failed\n", __func__); goto out; } ret = hsic_tty_ctrl_setup(1, HSIC_TTY_SERIAL); if (ret < 0) { pr_err("%s: hsic_tty_ctrl_setup failed\n", __func__); goto out; } hsic_tty.client_port_num = port_num; #ifdef CONFIG_MODEM_SUPPORT spin_lock_init(&hsic_tty.lock); spin_lock_init(&hsic_tty.reset_lock); hsic_tty.connect = hsic_tty_connect; hsic_tty.get_dtr = hsic_tty_get_dtr; hsic_tty.get_rts = hsic_tty_get_rts; hsic_tty.send_carrier_detect = hsic_tty_send_carrier_detect; hsic_tty.send_ring_indicator = hsic_tty_send_ring_indicator; hsic_tty.send_modem_ctrl_bits = hsic_tty_send_modem_ctrl_bits; hsic_tty.disconnect = hsic_tty_disconnect; hsic_tty.send_break = hsic_tty_send_break;; #endif hsic_tty.tty = NULL; ret = hsic_tty_ctrl_connect(&hsic_tty, port_num); if (ret) { pr_err("%s: hsic_tty_ctrl_connect failed: err:%d\n", __func__, ret); goto out; } ret = hsic_tty_data_connect(&hsic_tty, port_num); if (ret) { pr_err("%s: hsic_tty_data_connect failed: err:%d\n", __func__, ret); hsic_tty_ctrl_disconnect(&hsic_tty, port_num); goto out; } for (n = 0; n < MAX_HSIC_TTYS; ++n) { pr_info("%s: %d\n", __func__, n); tty_register_device(hsic_tty_driver, n, 0); } return 0; out: tty_unregister_driver(hsic_tty_driver); put_tty_driver(hsic_tty_driver); return ret; }