1 /* arch/arm/mach-msm/smd_tty.c
3 * Copyright (C) 2007 Google, Inc.
4 * Author: Brian Swetland <swetland@google.com>
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
17 #include <linux/module.h>
19 #include <linux/cdev.h>
20 #include <linux/device.h>
21 #include <linux/wait.h>
23 #include <linux/tty.h>
24 #include <linux/tty_driver.h>
25 #include <linux/tty_flip.h>
27 #include <mach/msm_smd.h>
29 #define MAX_SMD_TTYS 32
31 static DEFINE_MUTEX(smd_tty_lock);
35 struct tty_struct *tty;
39 static struct smd_tty_info smd_tty[MAX_SMD_TTYS];
42 static void smd_tty_notify(void *priv, unsigned event)
46 struct smd_tty_info *info = priv;
47 struct tty_struct *tty = info->tty;
52 if (event != SMD_EVENT_DATA)
56 if (test_bit(TTY_THROTTLED, &tty->flags)) break;
57 avail = smd_read_avail(info->ch);
58 if (avail == 0) break;
60 avail = tty_prepare_flip_string(tty, &ptr, avail);
62 if (smd_read(info->ch, ptr, avail) != avail) {
63 /* shouldn't be possible since we're in interrupt
64 ** context here and nobody else could 'steal' our
67 printk(KERN_ERR "OOPS - smd_tty_buffer mismatch?!");
70 tty_flip_buffer_push(tty);
73 /* XXX only when writable and necessary */
77 static int smd_tty_open(struct tty_struct *tty, struct file *f)
81 struct smd_tty_info *info;
94 mutex_lock(&smd_tty_lock);
95 tty->driver_data = info;
97 if (info->open_count++ == 0) {
102 res = smd_open(name, &info->ch, info, smd_tty_notify);
105 mutex_unlock(&smd_tty_lock);
110 static void smd_tty_close(struct tty_struct *tty, struct file *f)
112 struct smd_tty_info *info = tty->driver_data;
117 mutex_lock(&smd_tty_lock);
118 if (--info->open_count == 0) {
120 tty->driver_data = 0;
126 mutex_unlock(&smd_tty_lock);
129 static int smd_tty_write(struct tty_struct *tty, const unsigned char *buf, int len)
131 struct smd_tty_info *info = tty->driver_data;
134 /* if we're writing to a packet channel we will
135 ** never be able to write more data than there
136 ** is currently space for
138 avail = smd_write_avail(info->ch);
142 return smd_write(info->ch, buf, len);
145 static int smd_tty_write_room(struct tty_struct *tty)
147 struct smd_tty_info *info = tty->driver_data;
148 return smd_write_avail(info->ch);
151 static int smd_tty_chars_in_buffer(struct tty_struct *tty)
153 struct smd_tty_info *info = tty->driver_data;
154 return smd_read_avail(info->ch);
157 static void smd_tty_unthrottle(struct tty_struct *tty)
159 struct smd_tty_info *info = tty->driver_data;
163 static struct tty_operations smd_tty_ops = {
164 .open = smd_tty_open,
165 .close = smd_tty_close,
166 .write = smd_tty_write,
167 .write_room = smd_tty_write_room,
168 .chars_in_buffer = smd_tty_chars_in_buffer,
169 .unthrottle = smd_tty_unthrottle,
172 static struct tty_driver *smd_tty_driver;
174 static int __init smd_tty_init(void)
178 smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS);
179 if (smd_tty_driver == 0)
182 smd_tty_driver->owner = THIS_MODULE;
183 smd_tty_driver->driver_name = "smd_tty_driver";
184 smd_tty_driver->name = "smd";
185 smd_tty_driver->major = 0;
186 smd_tty_driver->minor_start = 0;
187 smd_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
188 smd_tty_driver->subtype = SERIAL_TYPE_NORMAL;
189 smd_tty_driver->init_termios = tty_std_termios;
190 smd_tty_driver->init_termios.c_iflag = 0;
191 smd_tty_driver->init_termios.c_oflag = 0;
192 smd_tty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
193 smd_tty_driver->init_termios.c_lflag = 0;
194 smd_tty_driver->flags = TTY_DRIVER_RESET_TERMIOS |
195 TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
196 tty_set_operations(smd_tty_driver, &smd_tty_ops);
198 ret = tty_register_driver(smd_tty_driver);
201 /* this should be dynamic */
202 tty_register_device(smd_tty_driver, 0, 0);
203 tty_register_device(smd_tty_driver, 27, 0);
208 module_init(smd_tty_init);