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(tty
, &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(tty
);
86 /* XXX only when writable and necessary */
91 static int smd_tty_port_activate(struct tty_port
*tport
, struct tty_struct
*tty
)
95 const char *name
= NULL
;
96 struct smd_tty_info
*info
= smd_tty
+ n
;
98 for (i
= 0; i
< smd_tty_channels_len
; i
++) {
99 if (smd_tty_channels
[i
].id
== n
) {
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
;
121 struct tty_struct
*tty
= tty_port_tty_get(tport
);
123 info
= tty
->driver_data
;
129 tty
->driver_data
= 0;
133 static int smd_tty_open(struct tty_struct
*tty
, struct file
*f
)
135 struct smd_tty_info
*info
= smd_tty
+ tty
->index
;
137 return tty_port_open(&info
->port
, tty
, f
);
140 static void smd_tty_close(struct tty_struct
*tty
, struct file
*f
)
142 struct smd_tty_info
*info
= tty
->driver_data
;
144 tty_port_close(&info
->port
, tty
, f
);
147 static int smd_tty_write(struct tty_struct
*tty
,
148 const unsigned char *buf
, int len
)
150 struct smd_tty_info
*info
= tty
->driver_data
;
153 /* if we're writing to a packet channel we will
154 ** never be able to write more data than there
155 ** is currently space for
157 avail
= smd_write_avail(info
->ch
);
161 return smd_write(info
->ch
, buf
, len
);
164 static int smd_tty_write_room(struct tty_struct
*tty
)
166 struct smd_tty_info
*info
= tty
->driver_data
;
167 return smd_write_avail(info
->ch
);
170 static int smd_tty_chars_in_buffer(struct tty_struct
*tty
)
172 struct smd_tty_info
*info
= tty
->driver_data
;
173 return smd_read_avail(info
->ch
);
176 static void smd_tty_unthrottle(struct tty_struct
*tty
)
178 struct smd_tty_info
*info
= tty
->driver_data
;
182 static const struct tty_port_operations smd_tty_port_ops
= {
183 .shutdown
= smd_tty_port_shutdown
,
184 .activate
= smd_tty_port_activate
,
187 static const struct tty_operations smd_tty_ops
= {
188 .open
= smd_tty_open
,
189 .close
= smd_tty_close
,
190 .write
= smd_tty_write
,
191 .write_room
= smd_tty_write_room
,
192 .chars_in_buffer
= smd_tty_chars_in_buffer
,
193 .unthrottle
= smd_tty_unthrottle
,
196 static struct tty_driver
*smd_tty_driver
;
198 static int __init
smd_tty_init(void)
202 smd_tty_driver
= alloc_tty_driver(MAX_SMD_TTYS
);
203 if (smd_tty_driver
== 0)
206 smd_tty_driver
->driver_name
= "smd_tty_driver";
207 smd_tty_driver
->name
= "smd";
208 smd_tty_driver
->major
= 0;
209 smd_tty_driver
->minor_start
= 0;
210 smd_tty_driver
->type
= TTY_DRIVER_TYPE_SERIAL
;
211 smd_tty_driver
->subtype
= SERIAL_TYPE_NORMAL
;
212 smd_tty_driver
->init_termios
= tty_std_termios
;
213 smd_tty_driver
->init_termios
.c_iflag
= 0;
214 smd_tty_driver
->init_termios
.c_oflag
= 0;
215 smd_tty_driver
->init_termios
.c_cflag
= B38400
| CS8
| CREAD
;
216 smd_tty_driver
->init_termios
.c_lflag
= 0;
217 smd_tty_driver
->flags
= TTY_DRIVER_RESET_TERMIOS
|
218 TTY_DRIVER_REAL_RAW
| TTY_DRIVER_DYNAMIC_DEV
;
219 tty_set_operations(smd_tty_driver
, &smd_tty_ops
);
221 ret
= tty_register_driver(smd_tty_driver
);
225 for (i
= 0; i
< smd_tty_channels_len
; i
++) {
226 tty_port_init(&smd_tty
[smd_tty_channels
[i
].id
].port
);
227 smd_tty
[smd_tty_channels
[i
].id
].port
.ops
= &smd_tty_port_ops
;
228 tty_register_device(smd_tty_driver
, smd_tty_channels
[i
].id
, 0);
234 module_init(smd_tty_init
);