/* * Try to start the next IO and wake up processes waiting on the tty. */ static void raw3215_next_io(struct raw3215_info *raw, struct tty_struct *tty) { raw3215_mk_write_req(raw); raw3215_try_io(raw); if (tty && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE) tasklet_schedule(&raw->tlet); }
/* * Wait until length bytes are available int the output buffer. * Has to be called with the s390irq lock held. Can be called * disabled. */ static void raw3215_make_room(struct raw3215_info *raw, unsigned int length) { while (RAW3215_BUFFER_SIZE - raw->count < length) { /* While console is frozen for suspend we have no other * choice but to drop message from the buffer to make * room for even more messages. */ if (raw->port.flags & ASYNC_SUSPENDED) { raw3215_drop_line(raw); continue; } /* there might be a request pending */ raw->flags |= RAW3215_FLUSHING; raw3215_mk_write_req(raw); raw3215_try_io(raw); raw->flags &= ~RAW3215_FLUSHING; #ifdef CONFIG_TN3215_CONSOLE ccw_device_wait_idle(raw->cdev); #endif /* Enough room freed up ? */ if (RAW3215_BUFFER_SIZE - raw->count >= length) break; /* there might be another cpu waiting for the lock */ spin_unlock(get_ccwdev_lock(raw->cdev)); udelay(100); spin_lock(get_ccwdev_lock(raw->cdev)); } }
/* * The bottom half handler routine for 3215 devices. It tries to start * the next IO and wakes up processes waiting on the tty. */ static void raw3215_softint(void *data) { raw3215_info *raw; struct tty_struct *tty; unsigned long flags; raw = (raw3215_info *) data; s390irq_spin_lock_irqsave(raw->irq, flags); raw3215_mk_write_req(raw); raw3215_try_io(raw); raw->flags &= ~RAW3215_BH_PENDING; s390irq_spin_unlock_irqrestore(raw->irq, flags); /* Check for pending message from raw3215_irq */ if (raw->message != NULL) { printk(raw->message, raw->irq, raw->msg_dstat, raw->msg_cstat); raw->message = NULL; } tty = raw->tty; if (tty != NULL && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE) { if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); wake_up_interruptible(&tty->write_wait); } }
/* * Put character routine for 3215 devices */ static void raw3215_putchar(struct raw3215_info *raw, unsigned char ch) { unsigned long flags; unsigned int length, i; spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); if (ch == '\t') { length = TAB_STOP_SIZE - (raw->line_pos%TAB_STOP_SIZE); raw->line_pos += length; ch = ' '; } else if (ch == '\n') { length = 1; raw->line_pos = 0; } else { length = 1; raw->line_pos++; } raw3215_make_room(raw, length); for (i = 0; i < length; i++) { raw->buffer[raw->head] = (char) _ascebc[(int) ch]; raw->head = (raw->head + 1) & (RAW3215_BUFFER_SIZE - 1); raw->count++; } if (!(raw->flags & RAW3215_WORKING)) { raw3215_mk_write_req(raw); /* start or queue request */ raw3215_try_io(raw); } spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); }
/* * Flush routine, it simply sets the flush flag and tries to start * pending IO. */ static void raw3215_flush_buffer(raw3215_info *raw) { unsigned long flags; s390irq_spin_lock_irqsave(raw->irq, flags); if (raw->count > 0) { raw->flags |= RAW3215_FLUSHING; raw3215_try_io(raw); raw->flags &= ~RAW3215_FLUSHING; } s390irq_spin_unlock_irqrestore(raw->irq, flags); }
/* * Try to start the next IO and wake up processes waiting on the tty. */ static void raw3215_next_io(struct raw3215_info *raw) { struct tty_struct *tty; raw3215_mk_write_req(raw); raw3215_try_io(raw); tty = raw->tty; if (tty != NULL && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE) { tty_wakeup(tty); } }
/* * Flush routine, it simply sets the flush flag and tries to start * pending IO. */ static void raw3215_flush_buffer(struct raw3215_info *raw) { unsigned long flags; spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); if (raw->count > 0) { raw->flags |= RAW3215_FLUSHING; raw3215_try_io(raw); raw->flags &= ~RAW3215_FLUSHING; } spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); }
/* * Enable writing to a 3215 tty */ static void tty3215_start(struct tty_struct *tty) { raw3215_info *raw; unsigned long flags; raw = (raw3215_info *) tty->driver_data; if (raw->flags & RAW3215_STOPPED) { s390irq_spin_lock_irqsave(raw->irq, flags); raw->flags &= ~RAW3215_STOPPED; raw3215_try_io(raw); s390irq_spin_unlock_irqrestore(raw->irq, flags); } }
/* * Enable writing to a 3215 tty */ static void tty3215_start(struct tty_struct *tty) { struct raw3215_info *raw; unsigned long flags; raw = (struct raw3215_info *) tty->driver_data; if (raw->flags & RAW3215_STOPPED) { spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); raw->flags &= ~RAW3215_STOPPED; raw3215_try_io(raw); spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); } }
/* * Fire up a 3215 device. */ static int raw3215_startup(struct raw3215_info *raw) { unsigned long flags; if (raw->port.flags & ASYNC_INITIALIZED) return 0; raw->line_pos = 0; raw->port.flags |= ASYNC_INITIALIZED; spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); raw3215_try_io(raw); spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); return 0; }
/* * Fire up a 3215 device. */ static int raw3215_startup(struct raw3215_info *raw) { unsigned long flags; if (tty_port_initialized(&raw->port)) return 0; raw->line_pos = 0; tty_port_set_initialized(&raw->port, 1); spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); raw3215_try_io(raw); spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); return 0; }
/* * Enable reading from a 3215 tty */ static void tty3215_unthrottle(struct tty_struct * tty) { struct raw3215_info *raw; unsigned long flags; raw = (struct raw3215_info *) tty->driver_data; if (raw->flags & RAW3215_THROTTLED) { spin_lock_irqsave(raw->lock, flags); raw->flags &= ~RAW3215_THROTTLED; raw3215_try_io(raw); spin_unlock_irqrestore(raw->lock, flags); } }
/* * Fire up a 3215 device. */ static int raw3215_startup(struct raw3215_info *raw) { unsigned long flags; if (raw->flags & RAW3215_ACTIVE) return 0; raw->line_pos = 0; raw->flags |= RAW3215_ACTIVE; spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); raw3215_try_io(raw); spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); return 0; }
static int raw3215_pm_start(struct ccw_device *cdev) { struct raw3215_info *raw; unsigned long flags; /* Allow I/O again and flush output buffer. */ raw = dev_get_drvdata(&cdev->dev); spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); raw->port.flags &= ~ASYNC_SUSPENDED; raw->flags |= RAW3215_FLUSHING; raw3215_try_io(raw); raw->flags &= ~RAW3215_FLUSHING; spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); return 0; }
/* * Fire up a 3215 device. */ static int raw3215_startup(raw3215_info *raw) { unsigned long flags; if (raw->flags & RAW3215_ACTIVE) return 0; if (request_irq(raw->irq, raw3215_irq, SA_INTERRUPT, "3215 terminal driver", &raw->devstat) != 0) return -1; raw->line_pos = 0; raw->flags |= RAW3215_ACTIVE; s390irq_spin_lock_irqsave(raw->irq, flags); set_cons_dev(raw->irq); raw3215_try_io(raw); s390irq_spin_unlock_irqrestore(raw->irq, flags); return 0; }
/* * Wait until length bytes are available int the output buffer. * Has to be called with the s390irq lock held. Can be called * disabled. */ static void raw3215_make_room(struct raw3215_info *raw, unsigned int length) { while (RAW3215_BUFFER_SIZE - raw->count < length) { /* there might be a request pending */ raw->flags |= RAW3215_FLUSHING; raw3215_mk_write_req(raw); raw3215_try_io(raw); raw->flags &= ~RAW3215_FLUSHING; #ifdef CONFIG_TN3215_CONSOLE wait_cons_dev(); #endif /* Enough room freed up ? */ if (RAW3215_BUFFER_SIZE - raw->count >= length) break; /* there might be another cpu waiting for the lock */ spin_unlock(raw->lock); udelay(100); spin_lock(raw->lock); } }
/* * Wait until length bytes are available int the output buffer. * Has to be called with the s390irq lock held. Can be called * disabled. */ void raw3215_make_room(raw3215_info *raw, unsigned int length) { while (RAW3215_BUFFER_SIZE - raw->count < length) { /* there might be a request pending */ raw->flags |= RAW3215_FLUSHING; raw3215_mk_write_req(raw); raw3215_try_io(raw); raw->flags &= ~RAW3215_FLUSHING; if (wait_cons_dev(raw->irq) != 0) { /* that shouldn't happen */ raw->count = 0; raw->written = 0; } /* Enough room freed up ? */ if (RAW3215_BUFFER_SIZE - raw->count >= length) break; /* there might be another cpu waiting for the lock */ s390irq_spin_unlock(raw->irq); udelay(100); s390irq_spin_lock(raw->irq); } }
/* * The bottom half handler routine for 3215 devices. It tries to start * the next IO and wakes up processes waiting on the tty. */ static void raw3215_tasklet(void *data) { struct raw3215_info *raw; struct tty_struct *tty; unsigned long flags; raw = (struct raw3215_info *) data; spin_lock_irqsave(raw->lock, flags); raw3215_mk_write_req(raw); raw3215_try_io(raw); spin_unlock_irqrestore(raw->lock, flags); /* Check for pending message from raw3215_irq */ if (raw->message != NULL) { printk(raw->message, raw->msg_dstat, raw->msg_cstat); raw->message = NULL; } tty = raw->tty; if (tty != NULL && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE) { tty_wakeup(tty); } }
/* * String write routine for 3215 devices */ static void raw3215_write(struct raw3215_info *raw, const char *str, unsigned int length) { unsigned long flags; int c, count; while (length > 0) { spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); count = (length > RAW3215_BUFFER_SIZE) ? RAW3215_BUFFER_SIZE : length; length -= count; raw3215_make_room(raw, count); /* copy string to output buffer and convert it to EBCDIC */ while (1) { c = min_t(int, count, min(RAW3215_BUFFER_SIZE - raw->count, RAW3215_BUFFER_SIZE - raw->head)); if (c <= 0) break; memcpy(raw->buffer + raw->head, str, c); ASCEBC(raw->buffer + raw->head, c); raw->head = (raw->head + c) & (RAW3215_BUFFER_SIZE - 1); raw->count += c; raw->line_pos += c; str += c; count -= c; } if (!(raw->flags & RAW3215_WORKING)) { raw3215_mk_write_req(raw); /* start or queue request */ raw3215_try_io(raw); } spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); } }
/* * String write routine for 3215 devices */ static int raw3215_write(raw3215_info *raw, const char *str, int from_user, unsigned int length) { unsigned long flags; int ret, c; int count; ret = 0; while (length > 0) { s390irq_spin_lock_irqsave(raw->irq, flags); count = (length > RAW3215_BUFFER_SIZE) ? RAW3215_BUFFER_SIZE : length; length -= count; raw3215_make_room(raw, count); /* copy string to output buffer and convert it to EBCDIC */ if (from_user) { while (1) { c = MIN(count, MIN(RAW3215_BUFFER_SIZE - raw->count, RAW3215_BUFFER_SIZE - raw->head)); if (c <= 0) break; c -= copy_from_user(raw->buffer + raw->head, str, c); if (c == 0) { if (!ret) ret = -EFAULT; break; } ASCEBC(raw->buffer + raw->head, c); raw->head = (raw->head + c) & (RAW3215_BUFFER_SIZE - 1); raw->count += c; raw->line_pos += c; str += c; count -= c; ret += c; } } else { while (1) { c = MIN(count, MIN(RAW3215_BUFFER_SIZE - raw->count, RAW3215_BUFFER_SIZE - raw->head)); if (c <= 0) break; memcpy(raw->buffer + raw->head, str, c); ASCEBC(raw->buffer + raw->head, c); raw->head = (raw->head + c) & (RAW3215_BUFFER_SIZE - 1); raw->count += c; raw->line_pos += c; str += c; count -= c; ret += c; } } if (!(raw->flags & RAW3215_WORKING)) { raw3215_mk_write_req(raw); /* start or queue request */ raw3215_try_io(raw); } s390irq_spin_unlock_irqrestore(raw->irq, flags); } return ret; }