static void acm_tty_unregister(struct acm *acm) { int i, nr; nr = acm->rx_buflimit; tty_unregister_device(acm_tty_driver, acm->minor); usb_put_intf(acm->control); acm_table[acm->minor] = NULL; usb_free_urb(acm->ctrlurb); for (i = 0; i < ACM_NW; i++) usb_free_urb(acm->wb[i].urb); for (i = 0; i < nr; i++) usb_free_urb(acm->ru[i].urb); kfree(acm->country_codes); kfree(acm); }
void atcmd_cleanup(void) { if (!at_tty_driver) return; tty_unregister_device(at_tty_driver, 0); tty_unregister_driver(at_tty_driver); put_tty_driver(at_tty_driver); at_tty_driver = NULL; #ifdef ENABLE_DUMMY_HSIC_TTY hsic_cleanup(); #endif pr_debug("%s: cleaned up ttyGS0 support\n", __func__); }
void gserial_free_line(unsigned char port_num) { struct gs_port *port; mutex_lock(&ports[port_num].lock); if (WARN_ON(!ports[port_num].port)) { mutex_unlock(&ports[port_num].lock); return; } port = ports[port_num].port; ports[port_num].port = NULL; mutex_unlock(&ports[port_num].lock); gserial_free_port(port); tty_unregister_device(gs_tty_driver, port_num); }
/** * gserial_cleanup - remove TTY-over-USB driver and devices * Context: may sleep * * This is called to free all resources allocated by @gserial_setup(). * Accordingly, it may need to wait until some open /dev/ files have * closed. * * The caller must have issued @gserial_disconnect() for any ports * that had previously been connected, so that there is never any * I/O pending when it's called. */ void gserial_cleanup(void) { unsigned i; struct gs_port *port; int ret; if (!gs_tty_driver) return; /* start sysfs and /dev/ttyGS* node removal */ for (i = 0; i < n_ports; i++) tty_unregister_device(gs_tty_driver, i); for (i = 0; i < n_ports; i++) { /* prevent new opens */ mutex_lock(&ports[i].lock); port = ports[i].port; ports[i].port = NULL; mutex_unlock(&ports[i].lock); cancel_work_sync(&port->push); /* wait for old opens to finish */ /* * port-bridge application will hold one file descriptor to gserial after usb mode switch sometimes * so wait_event will never get out ,further block kernel thread "suspend" and block console_early_suspend * which makes the whole system hang. */ #if 0 wait_event(port->close_wait, gs_closed(port)); #else ret = wait_event_timeout(port->close_wait, gs_closed(port),HZ/10); pr_debug("%s timeout %d <\n",__func__,ret); #endif WARN_ON(port->port_usb != NULL); kfree(port); } n_ports = 0; destroy_workqueue(gserial_wq); tty_unregister_driver(gs_tty_driver); gs_tty_driver = NULL; pr_debug("%s: cleaned up ttyGS* support\n", __func__); }
static int goldfish_tty_remove(struct platform_device *pdev) { struct goldfish_tty *qtty = platform_get_drvdata(pdev); mutex_lock(&goldfish_tty_lock); unregister_console(&qtty->console); tty_unregister_device(goldfish_tty_driver, qtty->console.index); iounmap(qtty->base); qtty->base = NULL; free_irq(qtty->irq, pdev); goldfish_tty_current_line_count--; if (goldfish_tty_current_line_count == 0) goldfish_tty_delete_driver(); mutex_unlock(&goldfish_tty_lock); return 0; }
static void __ipoctal_remove(struct ipoctal *ipoctal) { int i; ipoctal->dev->bus->ops->free_irq(ipoctal->dev); for (i = 0; i < NR_CHANNELS; i++) { struct ipoctal_channel *channel = &ipoctal->channel[i]; tty_unregister_device(ipoctal->tty_drv, i); tty_port_free_xmit_buf(&channel->tty_port); tty_port_destroy(&channel->tty_port); } tty_unregister_driver(ipoctal->tty_drv); put_tty_driver(ipoctal->tty_drv); kfree(ipoctal); }
/** * gserial_cleanup - remove TTY-over-USB driver and devices * Context: may sleep * * This is called to free all resources allocated by @gserial_setup(). * Accordingly, it may need to wait until some open /dev/ files have * closed. * * The caller must have issued @gserial_disconnect() for any ports * that had previously been connected, so that there is never any * I/O pending when it's called. */ void gserial_cleanup(void) { unsigned i; struct gs_port *port; if (!gs_tty_driver) return; /* start sysfs and /dev/ttyGS* node removal */ pr_info("gs_cleanup: unregister tty!\n"); for (i = 0; i < n_ports; i++) tty_unregister_device(gs_tty_driver, i); pr_info("gs_cleanup: wait port close!\n"); for (i = 0; i < n_ports; i++) { /* prevent new opens */ mutex_lock(&ports[i].lock); port = ports[i].port; ports[i].port = NULL; mutex_unlock(&ports[i].lock); tasklet_kill(&port->push); pr_info("gs_cleanup: port%d++\n", i); /* wait for old opens to finish */ wait_event_timeout(port->close_wait, gs_closed(port), 2*HZ); if(!gs_closed(port)){ pr_info("%s: port %d still open, forcely close it!\n", __func__, i); gs_close_forcely(port); pr_info("%s: wait port %d close event again!\n", __func__, i); wait_event(port->close_wait, gs_closed(port)); pr_info("%s: wait port %d close event done!\n", __func__, i); } pr_info("gs_cleanup: port%d--\n", i); WARN_ON(port->port_usb != NULL); kfree(port); } n_ports = 0; tty_unregister_driver(gs_tty_driver); gs_tty_driver = NULL; pr_info("%s: cleaned up ttyGS* support\n", __func__); }
static void tty_exit(struct nozomi *dc) { unsigned int i; DBG1(" "); for (i = 0; i < MAX_PORT; ++i) tty_port_tty_hangup(&dc->port[i].port, false); /* Racy below - surely should wait for scheduled work to be done or complete off a hangup method ? */ while (dc->open_ttys) msleep(1); for (i = 0; i < MAX_PORT; ++i) { tty_unregister_device(ntty_driver, dc->index_start + i); tty_port_destroy(&dc->port[i].port); } }
void micvcons_destroy(int num_bds) { int bd, ret; micvcons_port_t *port; if (!micvcons_tty) return; for (bd = 0; bd < num_bds; bd++) { port = &mic_data.dd_ports[bd]; destroy_workqueue(port->dp_wq); tty_unregister_device(micvcons_tty, bd); } ret = tty_unregister_driver(micvcons_tty); put_tty_driver(micvcons_tty); micvcons_tty = NULL; if (ret) printk(KERN_ERR "tty unregister_driver failed with code %d\n", ret); }
/* Diag char driver no longer ready */ void tty_diag_channel_close(struct usb_diag_ch *diag_ch) { struct diag_tty_data *priv_usb = diag_ch->priv_usb; unsigned long flags; int i; if (diag_ch->priv_usb) { tty_insert_flip_char(&priv_usb->port, 0x00, TTY_BREAK); tty_flip_buffer_push(&priv_usb->port); } spin_lock_irqsave(&diag_tty_lock, flags); diag_ch->priv = NULL; diag_ch->notify = NULL; for (i = DIAG_TTY_MINOR_COUNT - 1; i >= 0; i--) tty_unregister_device(diag_tty_driver, i); spin_unlock_irqrestore(&diag_tty_lock, flags); }
/** * gserial_cleanup - remove TTY-over-USB driver and devices * Context: may sleep * * This is called to free all resources allocated by @gserial_setup(). * Accordingly, it may need to wait until some open /dev/ files have * closed. * * The caller must have issued @gserial_disconnect() for any ports * that had previously been connected, so that there is never any * I/O pending when it's called. */ void gserial_cleanup(void) { unsigned i; struct gs_port *port; int ret; if (!gs_tty_driver) return; /* start sysfs and /dev/ttyGS* node removal */ for (i = 0; i < n_ports; i++) tty_unregister_device(gs_tty_driver, i); for (i = 0; i < n_ports; i++) { /* prevent new opens */ mutex_lock(&ports[i].lock); port = ports[i].port; ports[i].port = NULL; mutex_unlock(&ports[i].lock); cancel_work_sync(&port->push); /* wait for old opens to finish */ #if 0 wait_event(port->close_wait, gs_closed(port)); #else ret = wait_event_timeout(port->close_wait, gs_closed(port),HZ/10); pr_debug("%s timeout %d <\n",__func__,ret); #endif WARN_ON(port->port_usb != NULL); kfree(port); } n_ports = 0; destroy_workqueue(gserial_wq); tty_unregister_driver(gs_tty_driver); put_tty_driver(gs_tty_driver); gs_tty_driver = NULL; pr_debug("%s: cleaned up ttyGS* support\n", __func__); }
/** * gserial_cleanup - remove TTY-over-USB driver and devices * Context: may sleep * * This is called to free all resources allocated by @gserial_setup(). * Accordingly, it may need to wait until some open /dev/ files have * closed. * * The caller must have issued @gserial_disconnect() for any ports * that had previously been connected, so that there is never any * I/O pending when it's called. */ void gserial_cleanup(void) { unsigned i; struct gs_port *port; if (!gs_tty_driver) return; /* start sysfs and /dev/ttyGS* node removal */ for (i = 0; i < n_ports; i++) tty_unregister_device(gs_tty_driver, i); for (i = 0; i < n_ports; i++) { /* prevent new opens */ mutex_lock(&ports[i].lock); port = ports[i].port; #ifdef CONFIG_USB_G_SERIAL_CONSOLE // unregister_console(&port->port_console); #endif ports[i].port = NULL; mutex_unlock(&ports[i].lock); cancel_work_sync(&port->push); /* wait for old opens to finish */ wait_event(port->close_wait, gs_closed(port)); WARN_ON(port->port_usb != NULL); kfree(port); } n_ports = 0; destroy_workqueue(gserial_wq); tty_unregister_driver(gs_tty_driver); put_tty_driver(gs_tty_driver); gs_tty_driver = NULL; pr_debug("%s: cleaned up ttyGS* support\n", __func__); }
static void __exit my_uart_exit(void) { /* TODO Auto-generated Function Stub */ int i; del_timer(&my_uart_timer); PINFO("EXIT\n"); for (i = 0; i < MY_UART_N_MINORS; i++) { del_timer(&devices[i].my_uart_timer1); tty_unregister_device(my_uart_tty, i); } tty_unregister_driver(my_uart_tty); put_tty_driver(my_uart_tty); }
static void __exit spi_tty_exit(void) { struct spi_tty_s *spi_tty; tty_unregister_device(spi_tty_driver, 0); tty_unregister_driver(spi_tty_driver); /* shut down all of the timers and free the memory */ spi_tty = spi_tty_gbl; if (spi_tty) { /* close the port */ while (spi_tty->open_count) do_close(spi_tty); spi_tty_buf_free(spi_tty->write_buf); wake_lock_destroy(&spi_tty->wakelock); //TODO: flush can destory work queue kfree(spi_tty); spi_tty_gbl = NULL; } }
static void __exit lge_dm_tty_exit(void) { int ret = 0; struct dm_tty *lge_dm_tty_drv = NULL; lge_dm_tty_drv = lge_dm_tty; if (!lge_dm_tty_drv) { pr_err(DM_TTY_MODULE_NAME ": %s:" "NULL lge_dm_tty_drv", __func__); return; } if (lge_dm_tty_drv->tty_state != DM_TTY_INITIAL) { tty_unregister_device(lge_dm_tty_drv->tty_drv, 0); ret = tty_unregister_driver(lge_dm_tty_drv->tty_drv); if (ret) { pr_err(DM_TTY_MODULE_NAME ": %s: " "tty_unregister_driver() failed\n", __func__); } put_tty_driver(lge_dm_tty_drv->tty_drv); lge_dm_tty_drv->tty_state = DM_TTY_INITIAL; lge_dm_tty_drv->tty_drv = NULL; } kfree(dm_modem_response); kfree(dm_modem_request); kfree(dm_modem_response_header); kfree(dm_modem_response_body); pr_info(DM_TTY_MODULE_NAME ": %s: Freeing dm_tty structure", __func__); kfree(lge_dm_tty_drv); return; }
/** * gserial_cleanup - remove TTY-over-USB driver and devices * Context: may sleep * * This is called to free all resources allocated by @gserial_setup(). * Accordingly, it may need to wait until some open /dev/ files have * closed. * * The caller must have issued @gserial_disconnect() for any ports * that had previously been connected, so that there is never any * I/O pending when it's called. */ void gserial_cleanup(void) { unsigned i; struct gs_port *port; if (!gs_tty_driver) return; /* start sysfs and /dev/ttyGS* node removal */ for (i = 0; i < n_ports; i++) tty_unregister_device(gs_tty_driver, i); for (i = 0; i < n_ports; i++) { /* prevent new opens */ mutex_lock(&ports[i].lock); port = ports[i].port; ports[i].port = NULL; mutex_unlock(&ports[i].lock); #ifndef CONFIG_USE_WORKQ_PUSH tasklet_kill(&port->push); #else flush_work_sync(&port->push); #endif /* wait for old opens to finish */ wait_event(port->close_wait, gs_closed(port)); WARN_ON(port->port_usb != NULL); kfree(port); } n_ports = 0; tty_unregister_driver(gs_tty_driver); put_tty_driver(gs_tty_driver); gs_tty_driver = NULL; pr_debug("%s: cleaned up ttyGS* support\n", __func__); }
void gserial_cleanup(void) { unsigned i; struct gs_port *port; if (!gs_tty_driver) return; for (i = 0; i < n_ports; i++) tty_unregister_device(gs_tty_driver, i); for (i = 0; i < n_ports; i++) { mutex_lock(&ports[i].lock); port = ports[i].port; ports[i].port = NULL; mutex_unlock(&ports[i].lock); cancel_work_sync(&port->push); wait_event(port->close_wait, gs_closed(port)); WARN_ON(port->port_usb != NULL); kfree(port); } n_ports = 0; usb_debugfs_remove(); destroy_workqueue(gserial_wq); tty_unregister_driver(gs_tty_driver); put_tty_driver(gs_tty_driver); gs_tty_driver = NULL; pr_debug("%s: cleaned up ttyGS* support\n", __func__); }
static void __exit nullmodem_exit(void) { int i; dprintf("%s - \n", __FUNCTION__); del_timer_sync(&nullmodem_timer); for (i = 0; i < NULLMODEM_PAIRS*2; ++i) { tty_unregister_device(nullmodem_tty_driver, i); tty_port_destroy(&tport[i]); } tty_unregister_driver(nullmodem_tty_driver); /* shut down all of the timers and free the memory */ for (i = 0; i < NULLMODEM_PAIRS; ++i) { pair_table[i].a.tty = NULL; pair_table[i].b.tty = NULL; } kfree(tport); }
/* * Must be called before ipwireless_network_free(). */ void ipwireless_tty_free(struct ipw_tty *tty) { int j; struct ipw_network *network = ttys[tty->index]->network; for (j = tty->index; j < IPWIRELESS_PCMCIA_MINORS; j += IPWIRELESS_PCMCIA_MINOR_RANGE) { struct ipw_tty *ttyj = ttys[j]; if (ttyj) { mutex_lock(&ttyj->ipw_tty_mutex); if (get_tty(j)) printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": deregistering %s device ttyIPWp%d\n", tty_type_name(ttyj->tty_type), j); ttyj->closing = 1; if (ttyj->port.tty != NULL) { mutex_unlock(&ttyj->ipw_tty_mutex); tty_vhangup(ttyj->port.tty); /* FIXME: Exactly how is the tty object locked here against a parallel ioctl etc */ /* FIXME2: hangup does not mean all processes * are gone */ mutex_lock(&ttyj->ipw_tty_mutex); } while (ttyj->port.count) do_ipw_close(ttyj); ipwireless_disassociate_network_ttys(network, ttyj->channel_idx); tty_unregister_device(ipw_tty_driver, j); tty_port_destroy(&ttyj->port); ttys[j] = NULL; mutex_unlock(&ttyj->ipw_tty_mutex); kfree(ttyj); } } }
void cbob_uart_exit(void) { struct cbob_uart *uart; int i; free_irq(IRQ_GPIOD(27), 0); for(i = 0;i < CBOB_UART_MINORS;i++) tty_unregister_device(cbob_uart_tty_driver, i); tty_unregister_driver(cbob_uart_tty_driver); for(i = 0;i < CBOB_UART_MINORS;i++) { uart = cbob_uarts[i]; if(uart) { while(uart->open_count) do_close(uart); kfree(uart); cbob_uarts[i] = NULL; } } flush_workqueue(cbob_uart_workqueue); destroy_workqueue(cbob_uart_workqueue); }
static int goldfish_tty_probe(struct platform_device *pdev) { int ret; int i; struct resource *r; struct device *ttydev; uint32_t base; uint32_t irq; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if(r == NULL) return -EINVAL; base = IO_ADDRESS(r->start - IO_START); r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if(r == NULL) return -EINVAL; irq = r->start; if(pdev->id >= goldfish_tty_line_count) return -EINVAL; mutex_lock(&goldfish_tty_lock); if(goldfish_tty_current_line_count == 0) { ret = goldfish_tty_create_driver(); if(ret) goto err_create_driver_failed; } goldfish_tty_current_line_count++; spin_lock_init(&goldfish_ttys[pdev->id].lock); goldfish_ttys[pdev->id].base = base; goldfish_ttys[pdev->id].irq = irq; writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_CMD); ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED, "goldfish_tty", pdev); if(ret) goto err_request_irq_failed; ttydev = tty_register_device(goldfish_tty_driver, pdev->id, NULL); if(IS_ERR(ttydev)) { ret = PTR_ERR(ttydev); goto err_tty_register_device_failed; } strcpy(goldfish_ttys[pdev->id].console.name, "ttyS"); goldfish_ttys[pdev->id].console.write = goldfish_tty_console_write; goldfish_ttys[pdev->id].console.device = goldfish_tty_console_device; goldfish_ttys[pdev->id].console.setup = goldfish_tty_console_setup; goldfish_ttys[pdev->id].console.flags = CON_PRINTBUFFER; goldfish_ttys[pdev->id].console.index = pdev->id; register_console(&goldfish_ttys[pdev->id].console); mutex_unlock(&goldfish_tty_lock); return 0; tty_unregister_device(goldfish_tty_driver, i); err_tty_register_device_failed: free_irq(irq, pdev); err_request_irq_failed: goldfish_tty_current_line_count--; if(goldfish_tty_current_line_count == 0) { goldfish_tty_delete_driver(); } err_create_driver_failed: mutex_unlock(&goldfish_tty_lock); return ret; }
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 (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; } 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; 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; }
void ec_tty_clear(ec_tty_t *tty) { del_timer_sync(&tty->timer); tty_unregister_device(tty_driver, tty->minor); }
/* Allocate memory for one device */ static int nozomi_card_init(struct pci_dev *pdev, const struct pci_device_id *ent) { resource_size_t start; int ret; struct nozomi *dc = NULL; int ndev_idx; int i; dev_dbg(&pdev->dev, "Init, new card found\n"); for (ndev_idx = 0; ndev_idx < ARRAY_SIZE(ndevs); ndev_idx++) if (!ndevs[ndev_idx]) break; if (ndev_idx >= ARRAY_SIZE(ndevs)) { dev_err(&pdev->dev, "no free tty range for this card left\n"); ret = -EIO; goto err; } dc = kzalloc(sizeof(struct nozomi), GFP_KERNEL); if (unlikely(!dc)) { dev_err(&pdev->dev, "Could not allocate memory\n"); ret = -ENOMEM; goto err_free; } dc->pdev = pdev; ret = pci_enable_device(dc->pdev); if (ret) { dev_err(&pdev->dev, "Failed to enable PCI Device\n"); goto err_free; } ret = pci_request_regions(dc->pdev, NOZOMI_NAME); if (ret) { dev_err(&pdev->dev, "I/O address 0x%04x already in use\n", (int) /* nozomi_private.io_addr */ 0); goto err_disable_device; } start = pci_resource_start(dc->pdev, 0); if (start == 0) { dev_err(&pdev->dev, "No I/O address for card detected\n"); ret = -ENODEV; goto err_rel_regs; } /* Find out what card type it is */ nozomi_get_card_type(dc); dc->base_addr = ioremap_nocache(start, dc->card_type); if (!dc->base_addr) { dev_err(&pdev->dev, "Unable to map card MMIO\n"); ret = -ENODEV; goto err_rel_regs; } dc->send_buf = kmalloc(SEND_BUF_MAX, GFP_KERNEL); if (!dc->send_buf) { dev_err(&pdev->dev, "Could not allocate send buffer?\n"); ret = -ENOMEM; goto err_free_sbuf; } for (i = PORT_MDM; i < MAX_PORT; i++) { if (kfifo_alloc(&dc->port[i].fifo_ul, FIFO_BUFFER_SIZE_UL, GFP_KERNEL)) { dev_err(&pdev->dev, "Could not allocate kfifo buffer\n"); ret = -ENOMEM; goto err_free_kfifo; } } spin_lock_init(&dc->spin_mutex); nozomi_setup_private_data(dc); /* Disable all interrupts */ dc->last_ier = 0; writew(dc->last_ier, dc->reg_ier); ret = request_irq(pdev->irq, &interrupt_handler, IRQF_SHARED, NOZOMI_NAME, dc); if (unlikely(ret)) { dev_err(&pdev->dev, "can't request irq %d\n", pdev->irq); goto err_free_kfifo; } DBG1("base_addr: %p", dc->base_addr); make_sysfs_files(dc); dc->index_start = ndev_idx * MAX_PORT; ndevs[ndev_idx] = dc; pci_set_drvdata(pdev, dc); /* Enable RESET interrupt */ dc->last_ier = RESET; iowrite16(dc->last_ier, dc->reg_ier); dc->state = NOZOMI_STATE_ENABLED; for (i = 0; i < MAX_PORT; i++) { struct device *tty_dev; struct port *port = &dc->port[i]; port->dc = dc; tty_port_init(&port->port); port->port.ops = &noz_tty_port_ops; tty_dev = tty_port_register_device(&port->port, ntty_driver, dc->index_start + i, &pdev->dev); if (IS_ERR(tty_dev)) { ret = PTR_ERR(tty_dev); dev_err(&pdev->dev, "Could not allocate tty?\n"); tty_port_destroy(&port->port); goto err_free_tty; } } return 0; err_free_tty: for (i = 0; i < MAX_PORT; ++i) { tty_unregister_device(ntty_driver, dc->index_start + i); tty_port_destroy(&dc->port[i].port); } err_free_kfifo: for (i = 0; i < MAX_PORT; i++) kfifo_free(&dc->port[i].fifo_ul); err_free_sbuf: kfree(dc->send_buf); iounmap(dc->base_addr); err_rel_regs: pci_release_regions(pdev); err_disable_device: pci_disable_device(pdev); err_free: kfree(dc); err: return ret; }
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 (idx == DS_IDX) { 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(); legacy_ds |= (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa()) && (board_mfg_mode() == 8); legacy_ds |= cpu_is_msm8x60() && (socinfo_get_platform_subtype() == 0x0); #ifdef CONFIG_MACH_DUMMY legacy_ds = 1; #endif if (!legacy_ds) continue; } tty_register_device(smd_tty_driver, idx, 0); init_completion(&smd_tty[idx].ch_allocated); 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: 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 ipoctal_install_all(void) { int i, j, t; int res = 0; struct tty_driver *tty; char name[20] = ""; ipoctal_installed = (struct ipoctal*) kzalloc(num_lun * sizeof(struct ipoctal), GFP_KERNEL); if (ipoctal_installed == NULL) { printk(KERN_ERR PFX "Unable to allocate memory for ipoctal's !\n"); res = -ENOMEM; goto out_err; } for (i=0; i<num_lun;i++) { tty = alloc_tty_driver(NR_CHANNELS); if(!tty) return -ENOMEM; tty->owner = THIS_MODULE; tty->driver_name = "ipoctal"; sprintf(name, "ipoctal.%d.", lun[i]); tty->name = name; tty->major = 0; tty->minor_start = 0; tty->type = TTY_DRIVER_TYPE_SERIAL; tty->subtype = SERIAL_TYPE_NORMAL; tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty->init_termios = tty_std_termios; tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; tty->init_termios.c_ispeed = 9600; tty->init_termios.c_ospeed = 9600; tty->init_termios.c_iflag = tty_std_termios.c_iflag | IGNBRK; tty_set_operations(tty, &ipoctalFops); res = tty_register_driver(tty); if(res) { printk(KERN_ERR PFX "Can't register tty driver.\n"); put_tty_driver(tty); goto out_uninst; } for(j = 0; j < NR_CHANNELS;j++) { tty_register_device(tty, j, NULL); ipoctal_installed[i].tty[j] = NULL; spin_lock_init(&ipoctal_installed[i].lock[j]); mutex_init(&ipoctal_installed[i].lock_write[j]); ipoctal_installed[i].pointer_read[j] = 0; ipoctal_installed[i].pointer_write[j] = 0; ipoctal_installed[i].nb_bytes[j] = 0; } ipoctal_installed[i].tty_drv = tty; ipoctal_installed[i].index = i; res = ipoctal_inst_slot(&ipoctal_installed[i], carrier_number[i], slot[i], irq[i], carrier[i]); if (res) { printk(KERN_ERR PFX "Error during IP octal install !\n"); goto out_uninst; } } return 0; out_uninst : for (j=0; j < i;j++){ for (t = 0; t < NR_CHANNELS; t++) tty_unregister_device(ipoctal_installed[j].tty_drv, t); tty_unregister_driver(ipoctal_installed[j].tty_drv); ipoctal_uninst_slot(&ipoctal_installed[j]); } kfree(ipoctal_installed); ipoctal_installed = NULL; printk(KERN_ERR PFX "Unregistered all IP octal devices\n"); out_err : return res; }
static int __init smd_tty_init(void) { int ret; int n; int idx; struct tty_port *port; smd_tty_log_init(); smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS); if (smd_tty_driver == 0) { SMD_TTY_ERR("%s - Driver allocation failed", __func__); 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); SMD_TTY_ERR("%s: driver registration failed %d", __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 (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); #ifdef CONFIG_MSM_SMD_TTY_DS_LEGACY legacy_ds |= cpu_is_msm8974(); #endif if (!legacy_ds) continue; } port = &smd_tty[idx].port; tty_port_init(port); port->ops = &smd_tty_port_ops; /* TODO: For kernel >= 3.7 use tty_port_register_device */ smd_tty[idx].device_ptr = tty_register_device(smd_tty_driver, idx, 0); if (device_create_file(smd_tty[idx].device_ptr, &dev_attr_open_timeout)) SMD_TTY_ERR( "%s: Unable to create device attributes for %s", __func__, smd_configs[n].port_name); init_completion(&smd_tty[idx].ch_allocated); /* register platform device */ smd_tty[idx].driver.probe = smd_tty_dummy_probe; #ifdef CONFIG_MSM_SMD_TTY_DS_LEGACY if (idx == DS_IDX) { /* register platform device for DS */ smd_tty[idx].driver.probe = smd_tty_ds_probe; smd_tty[idx].is_dsmodem_ready = 0; } #endif 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); spin_lock_init(&smd_tty[idx].ra_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) { SMD_TTY_ERR( "%s: init failed %d (%d)", __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; }
int micvcons_create(int num_bds) { micvcons_port_t *port; bd_info_t *bd_info; int bd, ret = 0; char wq_name[14]; struct device *dev; INIT_LIST_HEAD(&timer_list_head); if (micvcons_tty) goto exit; micvcons_tty = alloc_tty_driver(num_bds); if (!micvcons_tty) { ret = -ENOMEM; goto exit; } micvcons_tty->owner = THIS_MODULE; micvcons_tty->driver_name = MICVCONS_DEVICE_NAME; micvcons_tty->name = MICVCONS_DEVICE_NAME; micvcons_tty->major = 0; #if LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0) micvcons_tty->minor_num = num_bds; #endif micvcons_tty->minor_start = 0; micvcons_tty->type = TTY_DRIVER_TYPE_SERIAL; micvcons_tty->subtype = SERIAL_TYPE_NORMAL; micvcons_tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; micvcons_tty->init_termios = tty_std_termios; micvcons_tty->init_termios.c_iflag = IGNCR; micvcons_tty->init_termios.c_oflag = 0; micvcons_tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; micvcons_tty->init_termios.c_lflag = 0; tty_set_operations(micvcons_tty, &micvcons_tty_ops); if ((ret = tty_register_driver(micvcons_tty)) != 0) { printk("Failed to register vcons tty driver\n"); put_tty_driver(micvcons_tty); micvcons_tty = NULL; goto exit; } for (bd = 0; bd < num_bds; bd++) { port = &mic_data.dd_ports[bd]; port->dp_bdinfo = mic_data.dd_bi[bd]; spin_lock_init(&port->dp_lock); mutex_init (&port->dp_mutex); bd_info = (bd_info_t *)port->dp_bdinfo; bd_info->bi_port = port; dev = tty_register_device(micvcons_tty, bd, NULL); if (IS_ERR(dev)) { printk("Failed to register vcons tty device\n"); micvcons_destroy(bd); ret = PTR_ERR(dev); goto exit; } snprintf(wq_name, sizeof(wq_name), "VCONS MIC %d", bd); port->dp_wq = create_singlethread_workqueue(wq_name); if (!port->dp_wq) { printk(KERN_ERR "%s: create_singlethread_workqueue\n", __func__); tty_unregister_device(micvcons_tty, bd); micvcons_destroy(bd); ret = -ENOMEM; goto exit; } INIT_WORK(&port->dp_wakeup_read_buf, micvcons_wakeup_readbuf); } vcons_timer.function = micvcons_timeout; vcons_timer.data = (unsigned long)(&timer_list_head); init_timer(&vcons_timer); exit: return ret; }