2 * Copyright (C) 2007 Google, Inc.
3 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
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
36 struct smd_tty_channel_desc
{
41 static struct smd_tty_info smd_tty
[MAX_SMD_TTYS
];
43 static const struct smd_tty_channel_desc smd_default_tty_channels
[] = {
44 { .id
= 0, .name
= "SMD_DS" },
45 { .id
= 27, .name
= "SMD_GPSNMEA" },
48 static const struct smd_tty_channel_desc
*smd_tty_channels
=
49 smd_default_tty_channels
;
50 static int smd_tty_channels_len
= ARRAY_SIZE(smd_default_tty_channels
);
52 static void smd_tty_notify(void *priv
, unsigned event
)
56 struct smd_tty_info
*info
= priv
;
57 struct tty_struct
*tty
;
59 if (event
!= SMD_EVENT_DATA
)
62 tty
= tty_port_tty_get(&info
->port
);
67 if (test_bit(TTY_THROTTLED
, &tty
->flags
))
69 avail
= smd_read_avail(info
->ch
);
73 avail
= tty_prepare_flip_string(&info
->port
, &ptr
, avail
);
75 if (smd_read(info
->ch
, ptr
, avail
) != avail
) {
76 /* shouldn't be possible since we're in interrupt
77 ** context here and nobody else could 'steal' our
80 pr_err("OOPS - smd_tty_buffer mismatch?!");
83 tty_flip_buffer_push(&info
->port
);
86 /* XXX only when writable and necessary */
91 static int smd_tty_port_activate(struct tty_port
*tport
, struct tty_struct
*tty
)
93 struct smd_tty_info
*info
= container_of(tport
, struct smd_tty_info
,
96 const char *name
= NULL
;
98 for (i
= 0; i
< smd_tty_channels_len
; i
++) {
99 if (smd_tty_channels
[i
].id
== tty
->index
) {
100 name
= smd_tty_channels
[i
].name
;
110 res
= smd_open(name
, &info
->ch
, info
, smd_tty_notify
);
113 tty
->driver_data
= info
;
118 static void smd_tty_port_shutdown(struct tty_port
*tport
)
120 struct smd_tty_info
*info
= container_of(tport
, struct smd_tty_info
,
129 static int smd_tty_open(struct tty_struct
*tty
, struct file
*f
)
131 struct smd_tty_info
*info
= smd_tty
+ tty
->index
;
133 return tty_port_open(&info
->port
, tty
, f
);
136 static void smd_tty_close(struct tty_struct
*tty
, struct file
*f
)
138 struct smd_tty_info
*info
= tty
->driver_data
;
140 tty_port_close(&info
->port
, tty
, f
);
143 static int smd_tty_write(struct tty_struct
*tty
,
144 const unsigned char *buf
, int len
)
146 struct smd_tty_info
*info
= tty
->driver_data
;
149 /* if we're writing to a packet channel we will
150 ** never be able to write more data than there
151 ** is currently space for
153 avail
= smd_write_avail(info
->ch
);
157 return smd_write(info
->ch
, buf
, len
);
160 static int smd_tty_write_room(struct tty_struct
*tty
)
162 struct smd_tty_info
*info
= tty
->driver_data
;
163 return smd_write_avail(info
->ch
);
166 static int smd_tty_chars_in_buffer(struct tty_struct
*tty
)
168 struct smd_tty_info
*info
= tty
->driver_data
;
169 return smd_read_avail(info
->ch
);
172 static void smd_tty_unthrottle(struct tty_struct
*tty
)
174 struct smd_tty_info
*info
= tty
->driver_data
;
178 static const struct tty_port_operations smd_tty_port_ops
= {
179 .shutdown
= smd_tty_port_shutdown
,
180 .activate
= smd_tty_port_activate
,
183 static const struct tty_operations smd_tty_ops
= {
184 .open
= smd_tty_open
,
185 .close
= smd_tty_close
,
186 .write
= smd_tty_write
,
187 .write_room
= smd_tty_write_room
,
188 .chars_in_buffer
= smd_tty_chars_in_buffer
,
189 .unthrottle
= smd_tty_unthrottle
,
192 static struct tty_driver
*smd_tty_driver
;
194 static int __init
smd_tty_init(void)
198 smd_tty_driver
= alloc_tty_driver(MAX_SMD_TTYS
);
199 if (smd_tty_driver
== 0)
202 smd_tty_driver
->driver_name
= "smd_tty_driver";
203 smd_tty_driver
->name
= "smd";
204 smd_tty_driver
->major
= 0;
205 smd_tty_driver
->minor_start
= 0;
206 smd_tty_driver
->type
= TTY_DRIVER_TYPE_SERIAL
;
207 smd_tty_driver
->subtype
= SERIAL_TYPE_NORMAL
;
208 smd_tty_driver
->init_termios
= tty_std_termios
;
209 smd_tty_driver
->init_termios
.c_iflag
= 0;
210 smd_tty_driver
->init_termios
.c_oflag
= 0;
211 smd_tty_driver
->init_termios
.c_cflag
= B38400
| CS8
| CREAD
;
212 smd_tty_driver
->init_termios
.c_lflag
= 0;
213 smd_tty_driver
->flags
= TTY_DRIVER_RESET_TERMIOS
|
214 TTY_DRIVER_REAL_RAW
| TTY_DRIVER_DYNAMIC_DEV
;
215 tty_set_operations(smd_tty_driver
, &smd_tty_ops
);
217 ret
= tty_register_driver(smd_tty_driver
);
221 for (i
= 0; i
< smd_tty_channels_len
; i
++) {
222 struct tty_port
*port
= &smd_tty
[smd_tty_channels
[i
].id
].port
;
224 port
->ops
= &smd_tty_port_ops
;
225 tty_port_register_device(port
, smd_tty_driver
,
226 smd_tty_channels
[i
].id
, NULL
);
232 module_init(smd_tty_init
);