static int gs_console_setup (struct console *cons, char *options) { struct gs_port *port; int status = 0; /* * If this is called we are about to become the active console. (?) * * That is not what this hook is for, but it serves our purposes. * * Since there is no actual tty yet, we have to do some of what is * normally done in gs_open. */ port = container_of(cons, struct gs_port, port_console); spin_lock_irq(&port->port_lock); if (port->port_write_buf.buf_buf == NULL) { spin_unlock_irq(&port->port_lock); status = gs_buf_alloc_atomic(&port->port_write_buf, WRITE_BUF_SIZE); spin_lock_irq(&port->port_lock); } /* Start the I/O stream */ if (port->port_usb) { struct gserial *gser = port->port_usb; gs_start_io(port); if (gser->connect) gser->connect(gser); } spin_unlock_irq(&port->port_lock); return status; }
/** * gserial_connect - notify TTY I/O glue that USB link is active * @gser: the function, set up with endpoints and descriptors * @port_num: which port is active * Context: any (usually from irq) * * This is called activate endpoints and let the TTY layer know that * the connection is active ... not unlike "carrier detect". It won't * necessarily start I/O queues; unless the TTY is held open by any * task, there would be no point. However, the endpoints will be * activated so the USB host can perform I/O, subject to basic USB * hardware flow control. * * Caller needs to have set up the endpoints and USB function in @dev * before calling this, as well as the appropriate (speed-specific) * endpoint descriptors, and also have set up the TTY driver by calling * @gserial_setup(). * * Returns negative errno or zero. * On success, ep->driver_data will be overwritten. */ int gserial_connect(struct gserial *gser, u8 port_num) { struct gs_port *port; unsigned long flags; int status; if (!gs_tty_driver || port_num >= n_ports) return -ENXIO; /* we "know" gserial_cleanup() hasn't been called */ port = ports[port_num].port; /* activate the endpoints */ status = usb_ep_enable(gser->in, gser->in_desc); if (status < 0) return status; gser->in->driver_data = port; status = usb_ep_enable(gser->out, gser->out_desc); if (status < 0) goto fail_out; gser->out->driver_data = port; /* then tell the tty glue that I/O can work */ spin_lock_irqsave(&port->port_lock, flags); gser->ioport = port; port->port_usb = gser; port->rx_qcnt = 0; /* REVISIT unclear how best to handle this state... * we don't really couple it with the Linux TTY. */ gser->port_line_coding = port->port_line_coding; /* REVISIT if waiting on "carrier detect", signal. */ /* if it's already open, start I/O ... and notify the serial * protocol about open/close status (connect/disconnect). */ if (port->open_count) { pr_debug("gserial_connect: start ttyGS%d\n", port->port_num); gs_start_io(port); if (gser->connect) gser->connect(gser); } else { if (gser->disconnect) gser->disconnect(gser); } spin_unlock_irqrestore(&port->port_lock, flags); return status; fail_out: usb_ep_disable(gser->in); gser->in->driver_data = NULL; return status; }
int gserial_connect(struct gserial *gser, u8 port_num) { struct gs_port *port; unsigned long flags; int status; if (!gs_tty_driver || port_num >= n_ports) return -ENXIO; port = ports[port_num].port; status = usb_ep_enable(gser->in, gser->in_desc); if (status < 0) return status; gser->in->driver_data = port; status = usb_ep_enable(gser->out, gser->out_desc); if (status < 0) goto fail_out; gser->out->driver_data = port; spin_lock_irqsave(&port->port_lock, flags); gser->ioport = port; port->port_usb = gser; gser->port_line_coding = port->port_line_coding; if (port->open_count) { pr_debug("gserial_connect: start ttyGS%d\n", port->port_num); gs_start_io(port); if (gser->connect) gser->connect(gser); } else { if (gser->disconnect) gser->disconnect(gser); } spin_unlock_irqrestore(&port->port_lock, flags); return status; fail_out: usb_ep_disable(gser->in); gser->in->driver_data = NULL; 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; }
/** * gserial_connect - notify TTY I/O glue that USB link is active * @gser: the function, set up with endpoints and descriptors * @port_num: which port is active * Context: any (usually from irq) * * This is called activate endpoints and let the TTY layer know that * the connection is active ... not unlike "carrier detect". It won't * necessarily start I/O queues; unless the TTY is held open by any * task, there would be no point. However, the endpoints will be * activated so the USB host can perform I/O, subject to basic USB * hardware flow control. * * Caller needs to have set up the endpoints and USB function in @dev * before calling this, as well as the appropriate (speed-specific) * endpoint descriptors, and also have allocate @port_num by calling * @gserial_alloc_line(). * * Returns negative errno or zero. * On success, ep->driver_data will be overwritten. */ int gserial_connect(struct gserial *gser, u8 port_num) { struct gs_port *port; unsigned long flags; int status; if (port_num >= MAX_U_SERIAL_PORTS) return -ENXIO; port = ports[port_num].port; if (!port) { pr_err("serial line %d not allocated.\n", port_num); return -EINVAL; } if (port->port_usb) { pr_err("serial line %d is in use.\n", port_num); return -EBUSY; } /* activate the endpoints */ status = usb_ep_enable(gser->in); if (status < 0) return status; gser->in->driver_data = port; status = usb_ep_enable(gser->out); if (status < 0) goto fail_out; gser->out->driver_data = port; /* then tell the tty glue that I/O can work */ spin_lock_irqsave(&port->port_lock, flags); gser->ioport = port; port->port_usb = gser; /* REVISIT unclear how best to handle this state... * we don't really couple it with the Linux TTY. */ gser->port_line_coding = port->port_line_coding; /* REVISIT if waiting on "carrier detect", signal. */ /* if it's already open, start I/O ... and notify the serial * protocol about open/close status (connect/disconnect). */ if (port->port.count) { pr_debug("gserial_connect: start ttyGS%d\n", port->port_num); gs_start_io(port); if (gser->connect) gser->connect(gser); } else { if (gser->disconnect) gser->disconnect(gser); } spin_unlock_irqrestore(&port->port_lock, flags); return status; fail_out: usb_ep_disable(gser->in); gser->in->driver_data = NULL; 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; }
/** * gserial_connect - notify TTY I/O glue that USB link is active * @gser: the function, set up with endpoints and descriptors * @port_num: which port is active * Context: any (usually from irq) * * This is called activate endpoints and let the TTY layer know that * the connection is active ... not unlike "carrier detect". It won't * necessarily start I/O queues; unless the TTY is held open by any * task, there would be no point. However, the endpoints will be * activated so the USB host can perform I/O, subject to basic USB * hardware flow control. * * Caller needs to have set up the endpoints and USB function in @dev * before calling this, as well as the appropriate (speed-specific) * endpoint descriptors, and also have set up the TTY driver by calling * @gserial_setup(). * * Returns negative errno or zero. * On success, ep->driver_data will be overwritten. */ int gserial_connect(struct gserial *gser, u8 port_num) { struct gs_port *port; unsigned long flags; int status; /* port 0 is console tty dirver */ if (0 == port_num) { if (!gs_console_tty_driver) return -ENXIO; } else { if (!gs_tty_driver || port_num >= n_ports) return -ENXIO; } /* we "know" gserial_cleanup() hasn't been called */ port = ports[port_num].port; /* mask the not ready interrupt for usb netcard class function driver */ gser->out->enable_xfer_in_progress = 1; /* activate the endpoints */ status = usb_ep_enable(gser->in); if (status < 0) return status; gser->in->driver_data = port; status = usb_ep_enable(gser->out); if (status < 0) goto fail_out; gser->out->driver_data = port; /* then tell the tty glue that I/O can work */ spin_lock_irqsave(&port->port_lock, flags); gser->ioport = (void*)port; port->port_usb = gser; /* REVISIT unclear how best to handle this state... * we don't really couple it with the Linux TTY. */ gser->port_line_coding = port->port_line_coding; /* REVISIT if waiting on "carrier detect", signal. */ /* if it's already open, start I/O ... and notify the serial * protocol about open/close status (connect/disconnect). */ gs_start_io(port);/* usb rx fifo is shared, so must submit rx req at any time */ #if ACM_TTY_SUPPORT_NOTIFY if (port->open_count) { pr_vdebug("gserial_connect: start ttyGS%d\n", port->port_num); //gs_start_io(port); if (gser->connect) gser->connect(gser); } else { if (gser->disconnect) gser->disconnect(gser); } #endif spin_unlock_irqrestore(&port->port_lock, flags); port->in_name = (char*)gser->in->name; port->out_name = (char*)gser->out->name; port->stat_port_is_connect = 1; return status; fail_out: usb_ep_disable(gser->in); gser->in->driver_data = NULL; port->stat_port_is_connect = 0; 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; }