1 #include <linux/module.h>
2 #include <linux/types.h>
3 #include <linux/slab.h>
5 #include <linux/tty_flip.h>
6 #include <linux/kernel.h>
7 #include <linux/string.h>
9 #include "ts27010_mux.h"
10 #include "ts27010_ringbuf.h"
12 struct ts27010_tty_channel_data {
14 struct tty_struct *tty;
17 struct ts27010_tty_data {
18 struct ts27010_tty_channel_data chan[NR_MUXS];
21 /* TODO: find a good place to put this */
22 struct tty_driver *driver;
24 /* TODO: should request a major */
25 #define TS0710MUX_MAJOR 245
26 #define TS0710MUX_MINOR_START 0
28 int ts27010_tty_send(int line, u8 *data, int len)
30 struct ts27010_tty_data *td = driver->driver_state;
31 struct tty_struct *tty = td->chan[line].tty;
34 pr_info("ts27010: mux%d no open. discarding %d bytes\n",
39 BUG_ON(tty_insert_flip_string(tty, data, len) != len);
40 tty_flip_buffer_push(tty);
44 int ts27010_tty_send_rbuf(int line, struct ts27010_ringbuf *rbuf,
45 int data_idx, int len)
47 struct ts27010_tty_data *td = driver->driver_state;
48 struct tty_struct *tty = td->chan[line].tty;
51 pr_info("ts27010: mux%d no open. discarding %d bytes\n",
57 char c = ts27010_ringbuf_peek(rbuf, data_idx++);
58 tty_insert_flip_char(tty, c, TTY_NORMAL);
60 tty_flip_buffer_push(tty);
64 static int ts27010_tty_open(struct tty_struct *tty, struct file *filp)
66 struct ts27010_tty_data *td = tty->driver->driver_state;
70 if (!ts27010_mux_active()) {
71 pr_err("ts27010: tty open when line discipline not active.\n");
77 if ((line < 0) || (line >= NR_MUXS)) {
78 pr_err("ts27010: tty index out of range.\n");
83 atomic_inc(&td->chan[line].ref_count);
85 td->chan[line].tty = tty;
87 err = ts27010_mux_line_open(line);
98 static void ts27010_tty_close(struct tty_struct *tty, struct file *filp)
100 struct ts27010_tty_data *td = tty->driver->driver_state;
102 if (atomic_dec_and_test(&td->chan[tty->index].ref_count)) {
103 ts27010_mux_line_close(tty->index);
105 td->chan[tty->index].tty = NULL;
109 * wake_up_interruptible(&tty->read_wait);
110 * wake_up_interruptible(&tty->write_wait);
112 * I belive this is unecessary
117 static int ts27010_tty_write(struct tty_struct *tty,
118 const unsigned char *buf, int count)
120 return ts27010_mux_line_write(tty->index, buf, count);
124 static int ts27010_tty_write_room(struct tty_struct *tty)
126 return ts27010_mux_line_write_room(tty->index);
129 static void ts27010_tty_flush_buffer(struct tty_struct *tty)
131 pr_warning("ts27010: flush_buffer not implemented on line %d\n",
135 static int ts27010_tty_chars_in_buffer(struct tty_struct *tty)
137 return ts27010_mux_line_chars_in_buffer(tty->index);
140 static void ts27010_tty_throttle(struct tty_struct *tty)
142 pr_warning("ts27010: throttle not implemented on line %d\n",
146 static void ts27010_tty_unthrottle(struct tty_struct *tty)
148 pr_warning("ts27010: unthrottle not implemented on line %d\n",
152 static int ts27010_tty_ioctl(struct tty_struct *tty, struct file *file,
153 unsigned int cmd, unsigned long arg)
158 if ((line < 0) || (line >= NR_MUXS))
162 case TS0710MUX_IO_MSC_HANGUP:
163 pr_warning("ts27010: ioctl msc_hangup not implemented\n");
166 case TS0710MUX_IO_TEST_CMD:
167 pr_warning("ts27010: ioctl msc_hangup not implemented\n");
177 static const struct tty_operations ts27010_tty_ops = {
178 .open = ts27010_tty_open,
179 .close = ts27010_tty_close,
180 .write = ts27010_tty_write,
181 .write_room = ts27010_tty_write_room,
182 .flush_buffer = ts27010_tty_flush_buffer,
183 .chars_in_buffer = ts27010_tty_chars_in_buffer,
184 .throttle = ts27010_tty_throttle,
185 .unthrottle = ts27010_tty_unthrottle,
186 .ioctl = ts27010_tty_ioctl,
189 int ts27010_tty_init(void)
191 struct ts27010_tty_data *td;
195 driver = alloc_tty_driver(NR_MUXS);
196 if (driver == NULL) {
201 td = kzalloc(sizeof(*td), GFP_KERNEL);
207 for (i = 0; i < NR_MUXS; i++)
208 atomic_set(&td->chan[i].ref_count, 0);
210 driver->driver_state = td;
212 driver->driver_name = "ts0710mux";
213 driver->name = "ts0710mux";
214 driver->major = TS0710MUX_MAJOR;
216 driver->minor_start = TS0710MUX_MINOR_START;
217 driver->type = TTY_DRIVER_TYPE_SERIAL;
218 driver->subtype = SERIAL_TYPE_NORMAL;
219 driver->init_termios = tty_std_termios;
220 driver->init_termios.c_iflag = 0;
221 driver->init_termios.c_oflag = 0;
222 driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
223 driver->init_termios.c_lflag = 0;
224 driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
226 driver->other = NULL;
227 driver->owner = THIS_MODULE;
229 tty_set_operations(driver, &ts27010_tty_ops);
231 if (tty_register_driver(driver)) {
232 pr_err("ts27010: can't register tty driver\n");
242 put_tty_driver(driver);
247 void ts27010_tty_remove(void)
249 struct ts27010_tty_data *td = driver->driver_state;
250 tty_unregister_driver(driver);
252 put_tty_driver(driver);