^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/tty.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/tty_flip.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include "chan.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <os.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <irq_kern.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #ifdef CONFIG_NOCONFIG_CHAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) static void *not_configged_init(char *str, int device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) const struct chan_opts *opts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) printk(KERN_ERR "Using a channel type which is configured out of "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) "UML\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) static int not_configged_open(int input, int output, int primary, void *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) char **dev_out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) printk(KERN_ERR "Using a channel type which is configured out of "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) "UML\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) static void not_configged_close(int fd, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) printk(KERN_ERR "Using a channel type which is configured out of "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) "UML\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static int not_configged_read(int fd, char *c_out, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) printk(KERN_ERR "Using a channel type which is configured out of "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) "UML\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static int not_configged_write(int fd, const char *buf, int len, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) printk(KERN_ERR "Using a channel type which is configured out of "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) "UML\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) static int not_configged_console_write(int fd, const char *buf, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) printk(KERN_ERR "Using a channel type which is configured out of "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) "UML\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) static int not_configged_window_size(int fd, void *data, unsigned short *rows,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) unsigned short *cols)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) printk(KERN_ERR "Using a channel type which is configured out of "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) "UML\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static void not_configged_free(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) printk(KERN_ERR "Using a channel type which is configured out of "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) "UML\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) static const struct chan_ops not_configged_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) .init = not_configged_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) .open = not_configged_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) .close = not_configged_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) .read = not_configged_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) .write = not_configged_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) .console_write = not_configged_console_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) .window_size = not_configged_window_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) .free = not_configged_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) .winch = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) #endif /* CONFIG_NOCONFIG_CHAN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) static int open_one_chan(struct chan *chan)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) int fd, err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (chan->opened)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (chan->ops->open == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) fd = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) else fd = (*chan->ops->open)(chan->input, chan->output, chan->primary,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) chan->data, &chan->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (fd < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) err = os_set_fd_block(fd, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) (*chan->ops->close)(fd, chan->data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) chan->fd = fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) chan->opened = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) static int open_chan(struct list_head *chans)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) struct list_head *ele;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) struct chan *chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) int ret, err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) list_for_each(ele, chans) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) chan = list_entry(ele, struct chan, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) ret = open_one_chan(chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) if (chan->primary)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) err = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) void chan_enable_winch(struct chan *chan, struct tty_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) if (chan && chan->primary && chan->ops->winch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) register_winch(chan->fd, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) static void line_timer_cb(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) struct line *line = container_of(work, struct line, task.work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (!line->throttled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) chan_interrupt(line, line->driver->read_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) int enable_chan(struct line *line)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) struct list_head *ele;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) struct chan *chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) INIT_DELAYED_WORK(&line->task, line_timer_cb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) list_for_each(ele, &line->chan_list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) chan = list_entry(ele, struct chan, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) err = open_one_chan(chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (chan->primary)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) goto out_close;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (chan->enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) err = line_setup_irq(chan->fd, chan->input, chan->output, line,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) goto out_close;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) chan->enabled = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) out_close:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) close_chan(line);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) /* Items are added in IRQ context, when free_irq can't be called, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) * removed in process context, when it can.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) * This handles interrupt sources which disappear, and which need to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) * be permanently disabled. This is discovered in IRQ context, but
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) * the freeing of the IRQ must be done later.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) static DEFINE_SPINLOCK(irqs_to_free_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) static LIST_HEAD(irqs_to_free);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) void free_irqs(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) struct chan *chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) LIST_HEAD(list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) struct list_head *ele;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) spin_lock_irqsave(&irqs_to_free_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) list_splice_init(&irqs_to_free, &list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) spin_unlock_irqrestore(&irqs_to_free_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) list_for_each(ele, &list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) chan = list_entry(ele, struct chan, free_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) if (chan->input && chan->enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) um_free_irq(chan->line->driver->read_irq, chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) if (chan->output && chan->enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) um_free_irq(chan->line->driver->write_irq, chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) chan->enabled = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) static void close_one_chan(struct chan *chan, int delay_free_irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) if (!chan->opened)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) if (delay_free_irq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) spin_lock_irqsave(&irqs_to_free_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) list_add(&chan->free_list, &irqs_to_free);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) spin_unlock_irqrestore(&irqs_to_free_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) if (chan->input && chan->enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) um_free_irq(chan->line->driver->read_irq, chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) if (chan->output && chan->enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) um_free_irq(chan->line->driver->write_irq, chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) chan->enabled = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) if (chan->ops->close != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) (*chan->ops->close)(chan->fd, chan->data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) chan->opened = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) chan->fd = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) void close_chan(struct line *line)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) struct chan *chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) /* Close in reverse order as open in case more than one of them
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) * refers to the same device and they save and restore that device's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) * state. Then, the first one opened will have the original state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) * so it must be the last closed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) list_for_each_entry_reverse(chan, &line->chan_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) close_one_chan(chan, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) void deactivate_chan(struct chan *chan, int irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) if (chan && chan->enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) deactivate_fd(chan->fd, irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) int write_chan(struct chan *chan, const char *buf, int len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) int write_irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) int n, ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) if (len == 0 || !chan || !chan->ops->write)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) n = chan->ops->write(chan->fd, buf, len, chan->data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) if (chan->primary) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) ret = n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) int console_write_chan(struct chan *chan, const char *buf, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) int n, ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) if (!chan || !chan->ops->console_write)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) n = chan->ops->console_write(chan->fd, buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) if (chan->primary)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) ret = n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) int console_open_chan(struct line *line, struct console *co)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) err = open_chan(&line->chan_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) printk(KERN_INFO "Console initialized on /dev/%s%d\n", co->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) co->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) int chan_window_size(struct line *line, unsigned short *rows_out,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) unsigned short *cols_out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) struct chan *chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) chan = line->chan_in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) if (chan && chan->primary) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) if (chan->ops->window_size == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) return chan->ops->window_size(chan->fd, chan->data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) rows_out, cols_out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) chan = line->chan_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) if (chan && chan->primary) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) if (chan->ops->window_size == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) return chan->ops->window_size(chan->fd, chan->data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) rows_out, cols_out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) static void free_one_chan(struct chan *chan)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) list_del(&chan->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) close_one_chan(chan, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) if (chan->ops->free != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) (*chan->ops->free)(chan->data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) if (chan->primary && chan->output)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) ignore_sigio_fd(chan->fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) kfree(chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) static void free_chan(struct list_head *chans)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) struct list_head *ele, *next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) struct chan *chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) list_for_each_safe(ele, next, chans) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) chan = list_entry(ele, struct chan, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) free_one_chan(chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) static int one_chan_config_string(struct chan *chan, char *str, int size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) char **error_out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) int n = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) if (chan == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) CONFIG_CHUNK(str, size, n, "none", 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) return n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) CONFIG_CHUNK(str, size, n, chan->ops->type, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) if (chan->dev == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) CONFIG_CHUNK(str, size, n, "", 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) return n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) CONFIG_CHUNK(str, size, n, ":", 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) CONFIG_CHUNK(str, size, n, chan->dev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) return n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) static int chan_pair_config_string(struct chan *in, struct chan *out,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) char *str, int size, char **error_out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) int n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) n = one_chan_config_string(in, str, size, error_out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) str += n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) size -= n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) if (in == out) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) CONFIG_CHUNK(str, size, n, "", 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) return n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) CONFIG_CHUNK(str, size, n, ",", 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) n = one_chan_config_string(out, str, size, error_out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) str += n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) size -= n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) CONFIG_CHUNK(str, size, n, "", 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) return n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) int chan_config_string(struct line *line, char *str, int size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) char **error_out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) struct chan *in = line->chan_in, *out = line->chan_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) if (in && !in->primary)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) in = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) if (out && !out->primary)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) out = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) return chan_pair_config_string(in, out, str, size, error_out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) struct chan_type {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) char *key;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) const struct chan_ops *ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) static const struct chan_type chan_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) { "fd", &fd_ops },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) #ifdef CONFIG_NULL_CHAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) { "null", &null_ops },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) { "null", ¬_configged_ops },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) #ifdef CONFIG_PORT_CHAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) { "port", &port_ops },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) { "port", ¬_configged_ops },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) #ifdef CONFIG_PTY_CHAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) { "pty", &pty_ops },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) { "pts", &pts_ops },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) { "pty", ¬_configged_ops },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) { "pts", ¬_configged_ops },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) #ifdef CONFIG_TTY_CHAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) { "tty", &tty_ops },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) { "tty", ¬_configged_ops },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) #ifdef CONFIG_XTERM_CHAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) { "xterm", &xterm_ops },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) { "xterm", ¬_configged_ops },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) static struct chan *parse_chan(struct line *line, char *str, int device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) const struct chan_opts *opts, char **error_out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) const struct chan_type *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) const struct chan_ops *ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) struct chan *chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) void *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) ops = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) data = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) for(i = 0; i < ARRAY_SIZE(chan_table); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) entry = &chan_table[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) if (!strncmp(str, entry->key, strlen(entry->key))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) ops = entry->ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) str += strlen(entry->key);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) if (ops == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) *error_out = "No match for configured backends";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) data = (*ops->init)(str, device, opts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) if (data == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) *error_out = "Configuration failed";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) chan = kmalloc(sizeof(*chan), GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) if (chan == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) *error_out = "Memory allocation failed";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) *chan = ((struct chan) { .list = LIST_HEAD_INIT(chan->list),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) .free_list =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) LIST_HEAD_INIT(chan->free_list),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) .line = line,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) .primary = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) .input = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) .output = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) .opened = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) .enabled = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) .fd = -1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) .ops = ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) .data = data });
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) return chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) int parse_chan_pair(char *str, struct line *line, int device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) const struct chan_opts *opts, char **error_out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) struct list_head *chans = &line->chan_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) struct chan *new;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) char *in, *out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) if (!list_empty(chans)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) line->chan_in = line->chan_out = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) free_chan(chans);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) INIT_LIST_HEAD(chans);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) if (!str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) out = strchr(str, ',');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) if (out != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) in = str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) *out = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) out++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) new = parse_chan(line, in, device, opts, error_out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) if (new == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) new->input = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) list_add(&new->list, chans);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) line->chan_in = new;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) new = parse_chan(line, out, device, opts, error_out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) if (new == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) list_add(&new->list, chans);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) new->output = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) line->chan_out = new;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) new = parse_chan(line, str, device, opts, error_out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) if (new == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) list_add(&new->list, chans);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) new->input = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) new->output = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) line->chan_in = line->chan_out = new;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) void chan_interrupt(struct line *line, int irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) struct tty_port *port = &line->port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) struct chan *chan = line->chan_in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) char c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) if (!chan || !chan->ops->read)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) if (!tty_buffer_request_room(port, 1)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) schedule_delayed_work(&line->task, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) err = chan->ops->read(chan->fd, &c, chan->data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) if (err > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) tty_insert_flip_char(port, c, TTY_NORMAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) } while (err > 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) if (err == -EIO) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) if (chan->primary) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) tty_port_tty_hangup(&line->port, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) if (line->chan_out != chan)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) close_one_chan(line->chan_out, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) close_one_chan(chan, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) if (chan->primary)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) tty_flip_buffer_push(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) }