1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved. */
3
4 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
5
6 #include <linux/kernel.h>
7 #include <linux/errno.h>
8 #include <linux/tty.h>
9 #include <linux/tty_driver.h>
10 #include <linux/tty_flip.h>
11 #include <linux/module.h>
12 #include <linux/slab.h>
13 #include <linux/usb/cdc.h>
14 #include <linux/serial.h>
15 #include "gdm_tty.h"
16
17 #define GDM_TTY_MAJOR 0
18 #define GDM_TTY_MINOR 32
19
20 #define WRITE_SIZE 2048
21
22 #define MUX_TX_MAX_SIZE 2048
23
24 #define GDM_TTY_READY(gdm) (gdm && gdm->tty_dev && gdm->port.count)
25
26 static struct tty_driver *gdm_driver[TTY_MAX_COUNT];
27 static struct gdm *gdm_table[TTY_MAX_COUNT][GDM_TTY_MINOR];
28 static DEFINE_MUTEX(gdm_table_lock);
29
30 static const char *DRIVER_STRING[TTY_MAX_COUNT] = {"GCTATC", "GCTDM"};
31 static char *DEVICE_STRING[TTY_MAX_COUNT] = {"GCT-ATC", "GCT-DM"};
32
gdm_port_destruct(struct tty_port * port)33 static void gdm_port_destruct(struct tty_port *port)
34 {
35 struct gdm *gdm = container_of(port, struct gdm, port);
36
37 mutex_lock(&gdm_table_lock);
38 gdm_table[gdm->index][gdm->minor] = NULL;
39 mutex_unlock(&gdm_table_lock);
40
41 kfree(gdm);
42 }
43
44 static const struct tty_port_operations gdm_port_ops = {
45 .destruct = gdm_port_destruct,
46 };
47
gdm_tty_install(struct tty_driver * driver,struct tty_struct * tty)48 static int gdm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
49 {
50 struct gdm *gdm = NULL;
51 int ret;
52
53 ret = match_string(DRIVER_STRING, TTY_MAX_COUNT,
54 tty->driver->driver_name);
55 if (ret < 0)
56 return -ENODEV;
57
58 mutex_lock(&gdm_table_lock);
59 gdm = gdm_table[ret][tty->index];
60 if (!gdm) {
61 mutex_unlock(&gdm_table_lock);
62 return -ENODEV;
63 }
64
65 tty_port_get(&gdm->port);
66
67 ret = tty_standard_install(driver, tty);
68 if (ret) {
69 tty_port_put(&gdm->port);
70 mutex_unlock(&gdm_table_lock);
71 return ret;
72 }
73
74 tty->driver_data = gdm;
75 mutex_unlock(&gdm_table_lock);
76
77 return 0;
78 }
79
gdm_tty_open(struct tty_struct * tty,struct file * filp)80 static int gdm_tty_open(struct tty_struct *tty, struct file *filp)
81 {
82 struct gdm *gdm = tty->driver_data;
83
84 return tty_port_open(&gdm->port, tty, filp);
85 }
86
gdm_tty_cleanup(struct tty_struct * tty)87 static void gdm_tty_cleanup(struct tty_struct *tty)
88 {
89 struct gdm *gdm = tty->driver_data;
90
91 tty_port_put(&gdm->port);
92 }
93
gdm_tty_hangup(struct tty_struct * tty)94 static void gdm_tty_hangup(struct tty_struct *tty)
95 {
96 struct gdm *gdm = tty->driver_data;
97
98 tty_port_hangup(&gdm->port);
99 }
100
gdm_tty_close(struct tty_struct * tty,struct file * filp)101 static void gdm_tty_close(struct tty_struct *tty, struct file *filp)
102 {
103 struct gdm *gdm = tty->driver_data;
104
105 tty_port_close(&gdm->port, tty, filp);
106 }
107
gdm_tty_recv_complete(void * data,int len,int index,struct tty_dev * tty_dev,int complete)108 static int gdm_tty_recv_complete(void *data,
109 int len,
110 int index,
111 struct tty_dev *tty_dev,
112 int complete)
113 {
114 struct gdm *gdm = tty_dev->gdm[index];
115
116 if (!GDM_TTY_READY(gdm)) {
117 if (complete == RECV_PACKET_PROCESS_COMPLETE)
118 gdm->tty_dev->recv_func(gdm->tty_dev->priv_dev,
119 gdm_tty_recv_complete);
120 return TO_HOST_PORT_CLOSE;
121 }
122
123 if (data && len) {
124 if (tty_buffer_request_room(&gdm->port, len) == len) {
125 tty_insert_flip_string(&gdm->port, data, len);
126 tty_flip_buffer_push(&gdm->port);
127 } else {
128 return TO_HOST_BUFFER_REQUEST_FAIL;
129 }
130 }
131
132 if (complete == RECV_PACKET_PROCESS_COMPLETE)
133 gdm->tty_dev->recv_func(gdm->tty_dev->priv_dev,
134 gdm_tty_recv_complete);
135
136 return 0;
137 }
138
gdm_tty_send_complete(void * arg)139 static void gdm_tty_send_complete(void *arg)
140 {
141 struct gdm *gdm = arg;
142
143 if (!GDM_TTY_READY(gdm))
144 return;
145
146 tty_port_tty_wakeup(&gdm->port);
147 }
148
gdm_tty_write(struct tty_struct * tty,const unsigned char * buf,int len)149 static int gdm_tty_write(struct tty_struct *tty, const unsigned char *buf,
150 int len)
151 {
152 struct gdm *gdm = tty->driver_data;
153 int remain = len;
154 int sent_len = 0;
155 int sending_len = 0;
156
157 if (!GDM_TTY_READY(gdm))
158 return -ENODEV;
159
160 if (!len)
161 return 0;
162
163 while (1) {
164 sending_len = min(MUX_TX_MAX_SIZE, remain);
165 gdm->tty_dev->send_func(gdm->tty_dev->priv_dev,
166 (void *)(buf + sent_len),
167 sending_len,
168 gdm->index,
169 gdm_tty_send_complete,
170 gdm);
171 sent_len += sending_len;
172 remain -= sending_len;
173 if (remain <= 0)
174 break;
175 }
176
177 return len;
178 }
179
gdm_tty_write_room(struct tty_struct * tty)180 static unsigned int gdm_tty_write_room(struct tty_struct *tty)
181 {
182 struct gdm *gdm = tty->driver_data;
183
184 if (!GDM_TTY_READY(gdm))
185 return 0;
186
187 return WRITE_SIZE;
188 }
189
register_lte_tty_device(struct tty_dev * tty_dev,struct device * device)190 int register_lte_tty_device(struct tty_dev *tty_dev, struct device *device)
191 {
192 struct gdm *gdm;
193 int i;
194 int j;
195
196 for (i = 0; i < TTY_MAX_COUNT; i++) {
197 gdm = kmalloc(sizeof(*gdm), GFP_KERNEL);
198 if (!gdm)
199 return -ENOMEM;
200
201 mutex_lock(&gdm_table_lock);
202 for (j = 0; j < GDM_TTY_MINOR; j++) {
203 if (!gdm_table[i][j])
204 break;
205 }
206
207 if (j == GDM_TTY_MINOR) {
208 kfree(gdm);
209 mutex_unlock(&gdm_table_lock);
210 return -EINVAL;
211 }
212
213 gdm_table[i][j] = gdm;
214 mutex_unlock(&gdm_table_lock);
215
216 tty_dev->gdm[i] = gdm;
217 tty_port_init(&gdm->port);
218
219 gdm->port.ops = &gdm_port_ops;
220 gdm->index = i;
221 gdm->minor = j;
222 gdm->tty_dev = tty_dev;
223
224 tty_port_register_device(&gdm->port, gdm_driver[i],
225 gdm->minor, device);
226 }
227
228 for (i = 0; i < MAX_ISSUE_NUM; i++)
229 gdm->tty_dev->recv_func(gdm->tty_dev->priv_dev,
230 gdm_tty_recv_complete);
231
232 return 0;
233 }
234
unregister_lte_tty_device(struct tty_dev * tty_dev)235 void unregister_lte_tty_device(struct tty_dev *tty_dev)
236 {
237 struct gdm *gdm;
238 struct tty_struct *tty;
239 int i;
240
241 for (i = 0; i < TTY_MAX_COUNT; i++) {
242 gdm = tty_dev->gdm[i];
243 if (!gdm)
244 continue;
245
246 mutex_lock(&gdm_table_lock);
247 gdm_table[gdm->index][gdm->minor] = NULL;
248 mutex_unlock(&gdm_table_lock);
249
250 tty = tty_port_tty_get(&gdm->port);
251 if (tty) {
252 tty_vhangup(tty);
253 tty_kref_put(tty);
254 }
255
256 tty_unregister_device(gdm_driver[i], gdm->minor);
257 tty_port_put(&gdm->port);
258 }
259 }
260
261 static const struct tty_operations gdm_tty_ops = {
262 .install = gdm_tty_install,
263 .open = gdm_tty_open,
264 .close = gdm_tty_close,
265 .cleanup = gdm_tty_cleanup,
266 .hangup = gdm_tty_hangup,
267 .write = gdm_tty_write,
268 .write_room = gdm_tty_write_room,
269 };
270
register_lte_tty_driver(void)271 int register_lte_tty_driver(void)
272 {
273 struct tty_driver *tty_driver;
274 int i;
275 int ret;
276
277 for (i = 0; i < TTY_MAX_COUNT; i++) {
278 tty_driver = tty_alloc_driver(GDM_TTY_MINOR,
279 TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV);
280 if (IS_ERR(tty_driver))
281 return PTR_ERR(tty_driver);
282
283 tty_driver->owner = THIS_MODULE;
284 tty_driver->driver_name = DRIVER_STRING[i];
285 tty_driver->name = DEVICE_STRING[i];
286 tty_driver->major = GDM_TTY_MAJOR;
287 tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
288 tty_driver->subtype = SERIAL_TYPE_NORMAL;
289 tty_driver->init_termios = tty_std_termios;
290 tty_driver->init_termios.c_cflag = B9600 | CS8 | HUPCL | CLOCAL;
291 tty_driver->init_termios.c_lflag = ISIG | ICANON | IEXTEN;
292 tty_set_operations(tty_driver, &gdm_tty_ops);
293
294 ret = tty_register_driver(tty_driver);
295 if (ret) {
296 tty_driver_kref_put(tty_driver);
297 return ret;
298 }
299
300 gdm_driver[i] = tty_driver;
301 }
302
303 return ret;
304 }
305
unregister_lte_tty_driver(void)306 void unregister_lte_tty_driver(void)
307 {
308 struct tty_driver *tty_driver;
309 int i;
310
311 for (i = 0; i < TTY_MAX_COUNT; i++) {
312 tty_driver = gdm_driver[i];
313 if (tty_driver) {
314 tty_unregister_driver(tty_driver);
315 tty_driver_kref_put(tty_driver);
316 }
317 }
318 }
319
320