static int gs_console_setup(struct console *co, char *options) { if (ports[ACM_CONSOLE_IDX].port) { if (gs_buf_alloc(&gs_console_ctx.buf_info, CONSOLE_BUFFER_SIZE)) { return -ENOMEM; } spin_lock_init(&gs_console_ctx.lock); INIT_DELAYED_WORK(&gs_console_ctx.write_work, gs_console_write_work); return 0; } return -ENODEV; }
/* *alloc circular buffer for write * */ static int Gserial_console_setup(struct console *co, char *options) { int status; int port_num = 0; struct gs_port *port; mutex_lock(&ports[port_num].lock); port = ports[port_num].port; mutex_unlock(&ports[port_num].lock); pr_devel("enter:%s\n",__func__); spin_lock_irq(&port->port_lock); /* allocate circular buffer on first open */ if (port->port_write_buf.buf_buf == NULL) { spin_unlock_irq(&port->port_lock); status = gs_buf_alloc(&port->port_write_buf, WRITE_BUF_SIZE); spin_lock_irq(&port->port_lock); if (status) { pr_debug("Gserial_console_setup: gs_port%d no buffer\n",port->port_num); //port->openclose = false; goto exit_unlock_port; } } /* if connected, start the I/O stream */ if (port->port_usb) { struct gserial *gser = port->port_usb; pr_debug("gs_open: start gserial%d\n", port->port_num); gs_start_io_mine(port); if (gser->connect) gser->connect(gser); } status = 0; pr_devel("exit Gserial_console_setup\n"); exit_unlock_port: spin_unlock_irq(&port->port_lock); return status; }
/* * gs_open sets up the link between a gs_port and its associated TTY. * That link is broken *only* by TTY close(), and all driver methods * know that. */ static int gs_open(struct tty_struct *tty, struct file *file) { int port_num = tty->index; struct gs_port *port; int status; do { mutex_lock(&ports[port_num].lock); port = ports[port_num].port; if (!port) status = -ENODEV; else { spin_lock_irq(&port->port_lock); /* already open? Great. */ if (port->open_count) { status = 0; port->open_count++; /* currently opening/closing? wait ... */ } else if (port->openclose) { status = -EBUSY; /* ... else we do the work */ } else { status = -EAGAIN; port->openclose = true; } spin_unlock_irq(&port->port_lock); } mutex_unlock(&ports[port_num].lock); switch (status) { default: /* fully handled */ return status; case -EAGAIN: /* must do the work */ break; case -EBUSY: /* wait for EAGAIN task to finish */ msleep(1); /* REVISIT could have a waitchannel here, if * concurrent open performance is important */ break; } } while (status != -EAGAIN); /* Do the "real open" */ spin_lock_irq(&port->port_lock); /* allocate circular buffer on first open */ if (port->port_write_buf.buf_buf == NULL) { spin_unlock_irq(&port->port_lock); status = gs_buf_alloc(&port->port_write_buf, WRITE_BUF_SIZE); spin_lock_irq(&port->port_lock); if (status) { pr_debug("gs_open: ttyGS%d (%p,%p) no buffer\n", port->port_num, tty, file); port->openclose = false; goto exit_unlock_port; } } /* REVISIT if REMOVED (ports[].port NULL), abort the open * to let rmmod work faster (but this way isn't wrong). */ /* REVISIT maybe wait for "carrier detect" */ tty->driver_data = port; port->port_tty = tty; port->open_count = 1; port->openclose = false; /* if connected, start the I/O stream */ if (port->port_usb) { struct gserial *gser = port->port_usb; pr_debug("gs_open: start ttyGS%d\n", port->port_num); gs_start_io(port); if (gser->connect) gser->connect(gser); } pr_debug("gs_open: ttyGS%d (%p,%p)\n", port->port_num, tty, file); status = 0; exit_unlock_port: spin_unlock_irq(&port->port_lock); return status; }
static int gs_open(struct tty_struct *tty, struct file *file) { int port_num = tty->index; struct gs_port *port; int status; if (port_num < 0 || port_num >= n_ports) return -ENXIO; do { mutex_lock(&ports[port_num].lock); port = ports[port_num].port; if (!port) status = -ENODEV; else { spin_lock_irq(&port->port_lock); if (port->open_count) { status = 0; port->open_count++; } else if (port->openclose) { status = -EBUSY; } else { status = -EAGAIN; port->openclose = true; } spin_unlock_irq(&port->port_lock); } mutex_unlock(&ports[port_num].lock); switch (status) { default: return status; case -EAGAIN: break; case -EBUSY: msleep(1); break; } } while (status != -EAGAIN); spin_lock_irq(&port->port_lock); if (port->port_write_buf.buf_buf == NULL) { spin_unlock_irq(&port->port_lock); status = gs_buf_alloc(&port->port_write_buf, WRITE_BUF_SIZE); spin_lock_irq(&port->port_lock); if (status) { pr_debug("gs_open: ttyGS%d (%p,%p) no buffer\n", port->port_num, tty, file); port->openclose = false; goto exit_unlock_port; } } tty->driver_data = port; port->port_tty = tty; port->open_count = 1; port->openclose = false; tty->low_latency = 1; if (port->port_usb) { struct gserial *gser = port->port_usb; pr_debug("gs_open: start ttyGS%d\n", port->port_num); gs_start_io(port); if (gser->connect) gser->connect(gser); } pr_debug("gs_open: ttyGS%d (%p,%p)\n", port->port_num, tty, file); status = 0; exit_unlock_port: spin_unlock_irq(&port->port_lock); return status; }
/* * gs_open sets up the link between a gs_port and its associated TTY. * That link is broken *only* by TTY close(), and all driver methods * know that. */ static int gs_open(struct tty_struct *tty, struct file *file) { int port_num = tty->index; struct gs_port *port; int status; if (port_num < 0 || port_num >= n_ports) return -ENXIO; do { mutex_lock(&ports[port_num].lock); port = ports[port_num].port; if (!port) status = -ENODEV; else { spin_lock_irq(&port->port_lock); /* already open? Great. */ if (port->open_count) { #ifdef CONFIG_USB_ANDROID_SH_SERIALS /* already opened ... must return EBUSY after unlock */ status = -ENOTSUPP; #else /* CONFIG_USB_ANDROID_SH_SERIALS */ status = 0; #endif /* CONFIG_USB_ANDROID_SH_SERIALS */ port->open_count++; #ifdef CONFIG_USB_ANDROID_SH_DTFER if(port_num == D_SH_DTFER_PORT_NUM){ status = 0; } #endif /* CONFIG_USB_ANDROID_SH_DTFER */ /* currently opening/closing? wait ... */ } else if (port->openclose) { status = -EBUSY; /* ... else we do the work */ } else { status = -EAGAIN; port->openclose = true; } spin_unlock_irq(&port->port_lock); } mutex_unlock(&ports[port_num].lock); switch (status) { default: /* fully handled */ return status; #ifdef CONFIG_USB_ANDROID_SH_SERIALS case -ENOTSUPP: return -EBUSY; #endif /* CONFIG_USB_ANDROID_SH_SERIALS */ case -EAGAIN: /* must do the work */ break; case -EBUSY: /* wait for EAGAIN task to finish */ msleep(1); /* REVISIT could have a waitchannel here, if * concurrent open performance is important */ break; } } while (status != -EAGAIN); /* Do the "real open" */ spin_lock_irq(&port->port_lock); /* allocate circular buffer on first open */ if (port->port_write_buf.buf_buf == NULL) { spin_unlock_irq(&port->port_lock); status = gs_buf_alloc(&port->port_write_buf, WRITE_BUF_SIZE); spin_lock_irq(&port->port_lock); if (status) { pr_debug("gs_open: ttyGS%d (%p,%p) no buffer\n", port->port_num, tty, file); port->openclose = false; goto exit_unlock_port; } } /* REVISIT if REMOVED (ports[].port NULL), abort the open * to let rmmod work faster (but this way isn't wrong). */ /* REVISIT maybe wait for "carrier detect" */ tty->driver_data = port; port->port_tty = tty; port->open_count = 1; port->openclose = false; /* low_latency means ldiscs work is carried in the same context * of tty_flip_buffer_push. The same can be called from IRQ with * low_latency = 0. But better to use a dedicated worker thread * to push the data. */ tty->low_latency = 1; /* if connected, start the I/O stream */ if (port->port_usb) { struct gserial *gser = port->port_usb; pr_debug("gs_open: start ttyGS%d\n", port->port_num); gs_start_io(port); if (gser->connect) gser->connect(gser); } pr_debug("gs_open: ttyGS%d (%p,%p)\n", port->port_num, tty, file); status = 0; exit_unlock_port: spin_unlock_irq(&port->port_lock); return status; }
/* * gs_open sets up the link between a gs_port and its associated TTY. * That link is broken *only* by TTY close(), and all driver methods * know that. */ static int gs_open(struct tty_struct *tty, struct file *file) { int port_num = tty->index; struct gs_port *port; int status; if (port_num < 0 || port_num >= n_ports) return -ENXIO; do { mutex_lock(&ports[port_num].lock); port = ports[port_num].port; if (!port) status = -ENODEV; else { spin_lock_irq(&port->port_lock); /* already open? Great. */ if (port->open_count) { status = 0; port->open_count++; /* currently opening/closing? wait ... */ } else if (port->openclose) { status = -EBUSY; /* ... else we do the work */ } else { status = -EAGAIN; port->openclose = true; } spin_unlock_irq(&port->port_lock); } mutex_unlock(&ports[port_num].lock); switch (status) { default: /* fully handled */ return status; case -EAGAIN: /* must do the work */ break; case -EBUSY: /* wait for EAGAIN task to finish */ msleep(1); /* REVISIT could have a waitchannel here, if * concurrent open performance is important */ break; } } while (status != -EAGAIN); /* Do the "real open" */ spin_lock_irq(&port->port_lock); /* allocate circular buffer on first open */ if (port->port_write_buf.buf_buf == NULL) { spin_unlock_irq(&port->port_lock); status = gs_buf_alloc(&port->port_write_buf, WRITE_BUF_SIZE); spin_lock_irq(&port->port_lock); if (status) { pr_debug("gs_open: ttyGS%d (%p,%p) no buffer\n", port->port_num, tty, file); port->openclose = false; goto exit_unlock_port; } } /* REVISIT if REMOVED (ports[].port NULL), abort the open * to let rmmod work faster (but this way isn't wrong). */ /* REVISIT maybe wait for "carrier detect" */ tty->driver_data = port; port->port_tty = tty; port->open_count = 1; port->openclose = false; #if defined(USB_G_SERIAL_LOW_LATENCY) /* this setting make kernel bug below * BUG: sleeping function called from invalid context at kernel/mutex.c */ /* low_latency means ldiscs work in tasklet context, without * needing a workqueue schedule ... easier to keep up. */ tty->low_latency = 1; #endif /* if connected, start the I/O stream */ if (port->port_usb) { struct gserial *gser = port->port_usb; pr_debug("gs_open: start ttyGS%d\n", port->port_num); gs_start_io(port); if (gser->connect) gser->connect(gser); } pr_debug("gs_open: ttyGS%d (%p,%p)\n", port->port_num, tty, file); status = 0; exit_unlock_port: spin_unlock_irq(&port->port_lock); return status; }
static int gs_init_port(int port_num) { struct gs_port *port; int status, index; struct tty_struct *tty; pr_info("Davis: gs_init_port port_num %d\n", port_num); if (port_num < 0 || port_num >= n_ports) return -ENXIO; do { mutex_lock(&ports[port_num].lock); port = ports[port_num].port; if (!port) status = -ENODEV; else { spin_lock_irq(&port->port_lock); /* already open? Great. */ if (port->open_count) { status = 0; port->open_count++; /* currently opening/closing? wait ... */ } else if (port->openclose) { status = -EBUSY; /* ... else we do the work */ } else { status = -EAGAIN; port->openclose = true; } spin_unlock_irq(&port->port_lock); } mutex_unlock(&ports[port_num].lock); switch (status) { default: /* fully handled */ return status; case -EAGAIN: /* must do the work */ break; case -EBUSY: /* wait for EAGAIN task to finish */ msleep(1); /* REVISIT could have a waitchannel here, if * concurrent open performance is important */ break; } } while (status != -EAGAIN); /* Do the "real open" */ spin_lock_irq(&port->port_lock); /* allocate circular buffer on first open */ if (port->port_write_buf.buf_buf == NULL) { spin_unlock_irq(&port->port_lock); status = gs_buf_alloc(&port->port_write_buf, WRITE_BUF_SIZE); spin_lock_irq(&port->port_lock); if (status) { pr_debug("gs_init_port: ttyGS%d (%p) no buffer\n", port->port_num, gs_tty_driver->ttys[0]); port->openclose = false; goto exit_unlock_port; } } /* REVISIT if REMOVED (ports[].port NULL), abort the open * to let rmmod work faster (but this way isn't wrong). */ /* REVISIT maybe wait for "carrier detect" */ get_tty_driver_wrap(gs_tty_driver->cdev.dev, &index); if(gs_tty_driver->ttys[index] == NULL) { gs_tty_driver->ttys[index] = tty_init_dev_wrap(gs_tty_driver, index, 0); } tty = gs_tty_driver->ttys[index]; tty->driver_data = port; port->port_tty = tty; port->open_count = 1; port->openclose = false; /* low_latency means ldiscs not work in tasklet context, * needing a workqueue schedule ... easier to keep up. */ gs_tty_driver->ttys[0]->low_latency = 0; /* if connected, start the I/O stream */ if (port->port_usb) { struct gserial *gser = port->port_usb; pr_info("Davis: gs_init_port: start ttyGS%d\n", port->port_num); gs_start_io(port); if (gser->connect) gser->connect(gser); } pr_info("gs_init_port: ttyGS%d (%p)\n", port->port_num, gs_tty_driver->ttys[0]); tty_port_relay_register_gs(gs_tty_driver); // Set the line discipline (Browse the N_MOUSE) status = tiocsetd_wrap(tty, N_MOUSE); exit_unlock_port: spin_unlock_irq(&port->port_lock); return status; }