1 /* drivers/tty/serial/msm_smd_tty.c
3 * Copyright (C) 2007 Google, Inc.
4 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
5 * Author: Brian Swetland <swetland@google.com>
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
18 #include <linux/module.h>
20 #include <linux/cdev.h>
21 #include <linux/device.h>
22 #include <linux/wait.h>
24 #include <linux/tty.h>
25 #include <linux/tty_driver.h>
26 #include <linux/tty_flip.h>
28 #include <mach/msm_smd.h>
30 #define MAX_SMD_TTYS 32
37 struct smd_tty_channel_desc
{
42 static struct smd_tty_info smd_tty
[MAX_SMD_TTYS
];
44 static const struct smd_tty_channel_desc smd_default_tty_channels
[] = {
45 { .id
= 0, .name
= "SMD_DS" },
46 { .id
= 27, .name
= "SMD_GPSNMEA" },
49 static const struct smd_tty_channel_desc
*smd_tty_channels
=
50 smd_default_tty_channels
;
51 static int smd_tty_channels_len
= ARRAY_SIZE(smd_default_tty_channels
);
53 static void smd_tty_notify(void *priv
, unsigned event
)
57 struct smd_tty_info
*info
= priv
;
58 struct tty_struct
*tty
;
60 if (event
!= SMD_EVENT_DATA
)
63 tty
= tty_port_tty_get(&info
->port
);
68 if (test_bit(TTY_THROTTLED
, &tty
->flags
))
70 avail
= smd_read_avail(info
->ch
);
74 avail
= tty_prepare_flip_string(tty
, &ptr
, avail
);
76 if (smd_read(info
->ch
, ptr
, avail
) != avail
) {
77 /* shouldn't be possible since we're in interrupt
78 ** context here and nobody else could 'steal' our
81 pr_err("OOPS - smd_tty_buffer mismatch?!");
84 tty_flip_buffer_push(tty
);
87 /* XXX only when writable and necessary */
92 static int smd_tty_port_activate(struct tty_port
*tport
, struct tty_struct
*tty
)
96 const char *name
= NULL
;
97 struct smd_tty_info
*info
= smd_tty
+ n
;
99 for (i
= 0; i
< smd_tty_channels_len
; i
++) {
100 if (smd_tty_channels
[i
].id
== n
) {
101 name
= smd_tty_channels
[i
].name
;
111 res
= smd_open(name
, &info
->ch
, info
, smd_tty_notify
);
114 tty
->driver_data
= info
;
119 static void smd_tty_port_shutdown(struct tty_port
*tport
)
121 struct smd_tty_info
*info
;
122 struct tty_struct
*tty
= tty_port_tty_get(tport
);
124 info
= tty
->driver_data
;
130 tty
->driver_data
= 0;
134 static int smd_tty_open(struct tty_struct
*tty
, struct file
*f
)
136 struct smd_tty_info
*info
= smd_tty
+ tty
->index
;
138 return tty_port_open(&info
->port
, tty
, f
);
141 static void smd_tty_close(struct tty_struct
*tty
, struct file
*f
)
143 struct smd_tty_info
*info
= tty
->driver_data
;
145 tty_port_close(&info
->port
, tty
, f
);
148 static int smd_tty_write(struct tty_struct
*tty
,
149 const unsigned char *buf
, int len
)
151 struct smd_tty_info
*info
= tty
->driver_data
;
154 /* if we're writing to a packet channel we will
155 ** never be able to write more data than there
156 ** is currently space for
158 avail
= smd_write_avail(info
->ch
);
162 return smd_write(info
->ch
, buf
, len
);
165 static int smd_tty_write_room(struct tty_struct
*tty
)
167 struct smd_tty_info
*info
= tty
->driver_data
;
168 return smd_write_avail(info
->ch
);
171 static int smd_tty_chars_in_buffer(struct tty_struct
*tty
)
173 struct smd_tty_info
*info
= tty
->driver_data
;
174 return smd_read_avail(info
->ch
);
177 static void smd_tty_unthrottle(struct tty_struct
*tty
)
179 struct smd_tty_info
*info
= tty
->driver_data
;
183 static const struct tty_port_operations smd_tty_port_ops
= {
184 .shutdown
= smd_tty_port_shutdown
,
185 .activate
= smd_tty_port_activate
,
188 static const struct tty_operations smd_tty_ops
= {
189 .open
= smd_tty_open
,
190 .close
= smd_tty_close
,
191 .write
= smd_tty_write
,
192 .write_room
= smd_tty_write_room
,
193 .chars_in_buffer
= smd_tty_chars_in_buffer
,
194 .unthrottle
= smd_tty_unthrottle
,
197 static struct tty_driver
*smd_tty_driver
;
199 static int __init
smd_tty_init(void)
203 smd_tty_driver
= alloc_tty_driver(MAX_SMD_TTYS
);
204 if (smd_tty_driver
== 0)
207 smd_tty_driver
->owner
= THIS_MODULE
;
208 smd_tty_driver
->driver_name
= "smd_tty_driver";
209 smd_tty_driver
->name
= "smd";
210 smd_tty_driver
->major
= 0;
211 smd_tty_driver
->minor_start
= 0;
212 smd_tty_driver
->type
= TTY_DRIVER_TYPE_SERIAL
;
213 smd_tty_driver
->subtype
= SERIAL_TYPE_NORMAL
;
214 smd_tty_driver
->init_termios
= tty_std_termios
;
215 smd_tty_driver
->init_termios
.c_iflag
= 0;
216 smd_tty_driver
->init_termios
.c_oflag
= 0;
217 smd_tty_driver
->init_termios
.c_cflag
= B38400
| CS8
| CREAD
;
218 smd_tty_driver
->init_termios
.c_lflag
= 0;
219 smd_tty_driver
->flags
= TTY_DRIVER_RESET_TERMIOS
|
220 TTY_DRIVER_REAL_RAW
| TTY_DRIVER_DYNAMIC_DEV
;
221 tty_set_operations(smd_tty_driver
, &smd_tty_ops
);
223 ret
= tty_register_driver(smd_tty_driver
);
227 for (i
= 0; i
< smd_tty_channels_len
; i
++) {
228 tty_port_init(&smd_tty
[smd_tty_channels
[i
].id
].port
);
229 smd_tty
[smd_tty_channels
[i
].id
].port
.ops
= &smd_tty_port_ops
;
230 tty_register_device(smd_tty_driver
, smd_tty_channels
[i
].id
, 0);
236 module_init(smd_tty_init
);