blob: d1254e647df906185c4f74d987c2d28e3c968861 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/slab.h>
14#include <linux/sched.h>
15#include <linux/wait.h>
16#include <linux/workqueue.h>
17#include <linux/platform_device.h>
18#include <linux/tty.h>
19#include <linux/tty_flip.h>
20#include <mach/sdio_al.h>
21
22#define INPUT_SPEED 4800
23#define OUTPUT_SPEED 4800
24#define SDIO_TTY_MODULE_NAME "sdio_tty"
25#define SDIO_TTY_MAX_PACKET_SIZE 4096
26#define MAX_SDIO_TTY_DRV 1
27
28enum sdio_tty_state {
29 TTY_INITIAL = 0,
30 TTY_REGISTERED = 1,
31 TTY_OPENED = 2,
32 TTY_CLOSED = 3,
33};
34
35struct sdio_tty {
36 struct sdio_channel *ch;
37 char *sdio_ch_name;
38 struct workqueue_struct *workq;
39 struct work_struct work_read;
40 wait_queue_head_t waitq;
41 struct tty_driver *tty_drv;
42 struct tty_struct *tty_str;
43 int debug_msg_on;
44 char *read_buf;
45 enum sdio_tty_state sdio_tty_state;
46 int is_sdio_open;
47};
48
49static struct sdio_tty *sdio_tty;
50
51#define DEBUG_MSG(sdio_tty, x...) if (sdio_tty->debug_msg_on) pr_info(x)
52
53static void sdio_tty_read(struct work_struct *work)
54{
55 int ret = 0;
56 int read_avail = 0;
57 int left = 0;
58 int total_push = 0;
59 int num_push = 0;
60 struct sdio_tty *sdio_tty_drv = NULL;
61
62 sdio_tty_drv = container_of(work, struct sdio_tty, work_read);
63
64 if (!sdio_tty_drv) {
65 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty",
66 __func__);
67 return ;
68 }
69
70 if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
71 pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
72 __func__, sdio_tty_drv->sdio_tty_state);
73 return;
74 }
75
76 if (!sdio_tty_drv->read_buf) {
77 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL read_buf", __func__);
78 return;
79 }
80
81 /* Read the data from teh SDIO channel as long as there is available
82 data */
83 while (1) {
84 if (test_bit(TTY_THROTTLED, &sdio_tty_drv->tty_str->flags)) {
85 DEBUG_MSG(sdio_tty_drv,
86 SDIO_TTY_MODULE_NAME ": %s: TTY_THROTTLED bit"
87 " is set, exit",
88 __func__);
89 return;
90 }
91
92 total_push = 0;
93 read_avail = sdio_read_avail(sdio_tty_drv->ch);
94
95 DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME
96 ": %s: read_avail is %d", __func__,
97 read_avail);
98
99 if (read_avail == 0) {
100 DEBUG_MSG(sdio_tty_drv,
101 SDIO_TTY_MODULE_NAME ": %s: read_avail is 0",
102 __func__);
103 return;
104 }
105
106 if (read_avail > SDIO_TTY_MAX_PACKET_SIZE) {
107 pr_err(SDIO_TTY_MODULE_NAME ": %s: read_avail(%d) is "
108 "bigger than SDIO_TTY_MAX_PACKET_SIZE(%d)",
109 __func__, read_avail, SDIO_TTY_MAX_PACKET_SIZE);
110 return;
111 }
112
113 ret = sdio_read(sdio_tty_drv->ch,
114 sdio_tty_drv->read_buf,
115 read_avail);
116 if (ret < 0) {
117 pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_read error(%d)",
118 __func__, ret);
119 return;
120 }
121
122 left = read_avail;
123 do {
124 num_push = tty_insert_flip_string(
125 sdio_tty_drv->tty_str,
126 sdio_tty_drv->read_buf+total_push,
127 left);
128 total_push += num_push;
129 left -= num_push;
130 tty_flip_buffer_push(sdio_tty_drv->tty_str);
131 } while (left != 0);
132
133 if (total_push != read_avail) {
134 pr_err(SDIO_TTY_MODULE_NAME ": %s: failed, total_push"
135 "(%d) != read_avail(%d)\n",
136 __func__, total_push, read_avail);
137 }
138
139 tty_flip_buffer_push(sdio_tty_drv->tty_str);
140
141 DEBUG_MSG(sdio_tty_drv,
142 SDIO_TTY_MODULE_NAME ": %s: End of read %d bytes",
143 __func__, read_avail);
144 }
145}
146
147/**
148 * sdio_tty_write_room
149 *
150 * This is the write_room function of the tty driver.
151 *
152 * @tty: pointer to tty struct.
153 * @return free bytes for write.
154 *
155 */
156static int sdio_tty_write_room(struct tty_struct *tty)
157{
158 int write_avail = 0;
159 struct sdio_tty *sdio_tty_drv = NULL;
160
161 if (!tty) {
162 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty",
163 __func__);
164 return -ENODEV;
165 }
166 sdio_tty_drv = tty->driver_data;
167 if (!sdio_tty_drv) {
168 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
169 __func__);
170 return -ENODEV;
171 }
172
173 write_avail = sdio_write_avail(sdio_tty_drv->ch);
174 DEBUG_MSG(sdio_tty_drv,
175 SDIO_TTY_MODULE_NAME ": %s: write_avail=%d",
176 __func__, write_avail);
177
178 return write_avail;
179}
180
181/**
182 * sdio_tty_write_callback
183 * this is the write callback of the tty driver.
184 *
185 * @tty: pointer to tty struct.
186 * @buf: buffer to write from.
187 * @count: number of bytes to write.
188 * @return bytes written or negative value on error.
189 *
190 * if destination buffer has not enough room for the incoming
191 * data, writes the possible amount of bytes .
192 */
193static int sdio_tty_write_callback(struct tty_struct *tty,
194 const unsigned char *buf, int count)
195{
196 int write_avail = 0;
197 int len = count;
198 int ret = 0;
199 struct sdio_tty *sdio_tty_drv = NULL;
200
201 if (!tty) {
202 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty",
203 __func__);
204 return -ENODEV;
205 }
206 sdio_tty_drv = tty->driver_data;
207 if (!sdio_tty_drv) {
208 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
209 __func__);
210 return -ENODEV;
211 }
212
213 if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
214 pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
215 __func__, sdio_tty_drv->sdio_tty_state);
216 return -EPERM;
217 }
218
219 DEBUG_MSG(sdio_tty_drv,
220 SDIO_TTY_MODULE_NAME ": %s: WRITING CALLBACK CALLED WITH "
221 "%d bytes\n",
222 __func__, count);
223 write_avail = sdio_write_avail(sdio_tty_drv->ch);
224 if (write_avail == 0) {
225 DEBUG_MSG(sdio_tty_drv,
226 SDIO_TTY_MODULE_NAME ": %s: write_avail is 0\n",
227 __func__);
228 return 0;
229 }
230 if (write_avail > SDIO_TTY_MAX_PACKET_SIZE) {
231 DEBUG_MSG(sdio_tty_drv,
232 SDIO_TTY_MODULE_NAME ": %s: write_avail(%d) is "
233 "bigger than max packet size,(%d), setting to "
234 "max_packet_size\n",
235 __func__, write_avail, SDIO_TTY_MAX_PACKET_SIZE);
236 write_avail = SDIO_TTY_MAX_PACKET_SIZE;
237 }
238 if (write_avail < count) {
239 DEBUG_MSG(sdio_tty_drv,
240 SDIO_TTY_MODULE_NAME ": %s: write_avail(%d) is "
241 "smaller than "
242 "required(%d), writing only %d bytes\n",
243 __func__, write_avail, count, write_avail);
244 len = write_avail;
245 }
246 ret = sdio_write(sdio_tty_drv->ch, buf, len);
247 if (ret) {
248 pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_write failed, ret=%d\n",
249 __func__, ret);
250 return 0;
251 }
252
253 DEBUG_MSG(sdio_tty_drv,
254 SDIO_TTY_MODULE_NAME ": %s: End of function, len=%d bytes\n",
255 __func__, len);
256
257 return len;
258}
259
260static void sdio_tty_notify(void *priv, unsigned event)
261{
262 struct sdio_tty *sdio_tty_drv = priv;
263
264 if (!sdio_tty_drv) {
265 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
266 __func__);
267 }
268
269 if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
270 pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
271 __func__, sdio_tty_drv->sdio_tty_state);
272 return;
273 }
274
275 DEBUG_MSG(sdio_tty_drv,
276 SDIO_TTY_MODULE_NAME ": %s: event %d received\n", __func__,
277 event);
278
279 if (event == SDIO_EVENT_DATA_READ_AVAIL)
280 queue_work(sdio_tty_drv->workq, &sdio_tty_drv->work_read);
281}
282
283/**
284 * sdio_tty_open
285 * This is the open callback of the tty driver. it opens
286 * the sdio channel, and creates the workqueue.
287 *
288 * @tty: a pointer to the tty struct.
289 * @file: file descriptor.
290 * @return 0 on success or negative value on error.
291 */
292static int sdio_tty_open(struct tty_struct *tty, struct file *file)
293{
294 int ret = 0;
295 struct sdio_tty *sdio_tty_drv = NULL;
296
297 if (!tty) {
298 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty",
299 __func__);
300 return -ENODEV;
301 }
302 sdio_tty_drv = sdio_tty;
303 if (!sdio_tty_drv) {
304 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
305 __func__);
306 return -ENODEV;
307 }
308
309 tty->driver_data = sdio_tty_drv;
310
311 sdio_tty_drv->tty_str = tty;
312 sdio_tty_drv->tty_str->low_latency = 1;
313 sdio_tty_drv->tty_str->icanon = 0;
314 set_bit(TTY_NO_WRITE_SPLIT, &sdio_tty_drv->tty_str->flags);
315
316 sdio_tty_drv->read_buf = kzalloc(SDIO_TTY_MAX_PACKET_SIZE, GFP_KERNEL);
317 if (sdio_tty_drv->read_buf == NULL) {
318 pr_err(SDIO_TTY_MODULE_NAME ": %s: failed to allocate read_buf",
319 __func__);
320 return -ENOMEM;
321 }
322
323 sdio_tty_drv->workq = create_singlethread_workqueue("sdio_tty_read");
324 if (!sdio_tty_drv->workq) {
325 pr_err(SDIO_TTY_MODULE_NAME ": %s: failed to create workq",
326 __func__);
327 return -ENOMEM;
328 }
329
330 if (sdio_tty_drv->sdio_tty_state == TTY_OPENED) {
331 pr_err(SDIO_TTY_MODULE_NAME ": %s: tty is already open",
332 __func__);
333 return -EBUSY;
334 }
335
336 if (!sdio_tty_drv->is_sdio_open) {
337 ret = sdio_open(sdio_tty_drv->sdio_ch_name, &sdio_tty_drv->ch,
338 sdio_tty_drv, sdio_tty_notify);
339 if (ret < 0) {
340 pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_open err=%d\n",
341 __func__, ret);
342 destroy_workqueue(sdio_tty_drv->workq);
343 return ret;
344 }
345
346 pr_info(SDIO_TTY_MODULE_NAME ": %s: SDIO_TTY channel opened\n",
347 __func__);
348
349 sdio_tty_drv->is_sdio_open = 1;
350 } else {
351 /* If SDIO channel is already open try to read the data
352 * from the modem
353 */
354 queue_work(sdio_tty_drv->workq, &sdio_tty_drv->work_read);
355
356 }
357
358 sdio_tty_drv->sdio_tty_state = TTY_OPENED;
359
360 pr_info(SDIO_TTY_MODULE_NAME ": %s: TTY device opened\n",
361 __func__);
362
363 return ret;
364}
365
366/**
367 * sdio_tty_close
368 * This is the close callback of the tty driver. it requests
369 * the main thread to exit, and waits for notification of it.
370 * it also de-allocates the buffers, and unregisters the tty
371 * driver and device.
372 *
373 * @tty: a pointer to the tty struct.
374 * @file: file descriptor.
375 * @return None.
376 */
377static void sdio_tty_close(struct tty_struct *tty, struct file *file)
378{
379 struct sdio_tty *sdio_tty_drv = NULL;
380
381 if (!tty) {
382 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty",
383 __func__);
384 return;
385 }
386 sdio_tty_drv = tty->driver_data;
387 if (!sdio_tty_drv) {
388 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
389 __func__);
390 return;
391 }
392 if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
393 pr_err(SDIO_TTY_MODULE_NAME ": %s: trying to close a "
394 "TTY device that was not opened\n",
395 __func__);
396 return;
397 }
398
399 flush_workqueue(sdio_tty_drv->workq);
400 destroy_workqueue(sdio_tty_drv->workq);
401
402 kfree(sdio_tty_drv->read_buf);
403 sdio_tty_drv->read_buf = NULL;
404
405 sdio_tty_drv->sdio_tty_state = TTY_CLOSED;
406
407 pr_info(SDIO_TTY_MODULE_NAME ": %s: SDIO_TTY channel closed\n",
408 __func__);
409}
410
411static void sdio_tty_unthrottle(struct tty_struct *tty)
412{
413 struct sdio_tty *sdio_tty_drv = NULL;
414
415 if (!tty) {
416 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty",
417 __func__);
418 return;
419 }
420 sdio_tty_drv = tty->driver_data;
421 if (!sdio_tty_drv) {
422 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
423 __func__);
424 return;
425 }
426
427 if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
428 pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
429 __func__, sdio_tty_drv->sdio_tty_state);
430 return;
431 }
432
433 queue_work(sdio_tty_drv->workq, &sdio_tty_drv->work_read);
434 return;
435}
436
437static const struct tty_operations sdio_tty_ops = {
438 .open = sdio_tty_open,
439 .close = sdio_tty_close,
440 .write = sdio_tty_write_callback,
441 .write_room = sdio_tty_write_room,
442 .unthrottle = sdio_tty_unthrottle,
443};
444
445void *sdio_tty_init_tty(char *tty_name, char *sdio_ch_name)
446{
447 int ret = 0;
448 struct device *tty_dev;
449 struct sdio_tty *sdio_tty_drv;
450
451 pr_info(SDIO_TTY_MODULE_NAME ": %s\n", __func__);
452
453 sdio_tty_drv = kzalloc(sizeof(struct sdio_tty), GFP_KERNEL);
454 if (sdio_tty_drv == NULL) {
455 pr_err(SDIO_TTY_MODULE_NAME "%s: failed to allocate sdio_tty",
456 __func__);
457 return NULL;
458 }
459
460 sdio_tty = sdio_tty_drv;
461 sdio_tty_drv->sdio_ch_name = sdio_ch_name;
462
463 INIT_WORK(&sdio_tty_drv->work_read, sdio_tty_read);
464
465 sdio_tty_drv->tty_drv = alloc_tty_driver(MAX_SDIO_TTY_DRV);
466
467 if (!sdio_tty_drv->tty_drv) {
468 pr_err(SDIO_TTY_MODULE_NAME ": %s - tty_drv is NULL",
469 __func__);
470 kfree(sdio_tty_drv);
471 return NULL;
472 }
473
474 sdio_tty_drv->tty_drv->name = tty_name;
475 sdio_tty_drv->tty_drv->owner = THIS_MODULE;
476 sdio_tty_drv->tty_drv->driver_name = "SDIO_tty";
477 /* uses dynamically assigned dev_t values */
478 sdio_tty_drv->tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
479 sdio_tty_drv->tty_drv->subtype = SERIAL_TYPE_NORMAL;
480 sdio_tty_drv->tty_drv->flags = TTY_DRIVER_REAL_RAW
481 | TTY_DRIVER_DYNAMIC_DEV
482 | TTY_DRIVER_RESET_TERMIOS;
483
484 /* initializing the tty driver */
485 sdio_tty_drv->tty_drv->init_termios = tty_std_termios;
486 sdio_tty_drv->tty_drv->init_termios.c_cflag =
487 B4800 | CS8 | CREAD | HUPCL | CLOCAL;
488 sdio_tty_drv->tty_drv->init_termios.c_ispeed = INPUT_SPEED;
489 sdio_tty_drv->tty_drv->init_termios.c_ospeed = OUTPUT_SPEED;
490
491 tty_set_operations(sdio_tty_drv->tty_drv, &sdio_tty_ops);
492
493 ret = tty_register_driver(sdio_tty_drv->tty_drv);
494 if (ret) {
495 put_tty_driver(sdio_tty_drv->tty_drv);
496 pr_err(SDIO_TTY_MODULE_NAME ": %s: tty_register_driver() "
497 "failed\n", __func__);
498
499 sdio_tty_drv->tty_drv = NULL;
500 kfree(sdio_tty_drv);
501 return NULL;
502 }
503
504 tty_dev = tty_register_device(sdio_tty_drv->tty_drv, 0, NULL);
505 if (IS_ERR(tty_dev)) {
506 pr_err(SDIO_TTY_MODULE_NAME ": %s: tty_register_device() "
507 "failed\n", __func__);
508 tty_unregister_driver(sdio_tty_drv->tty_drv);
509 put_tty_driver(sdio_tty_drv->tty_drv);
510 kfree(sdio_tty_drv);
511 return NULL;
512 }
513
514 sdio_tty_drv->sdio_tty_state = TTY_REGISTERED;
515 return sdio_tty_drv;
516}
517EXPORT_SYMBOL(sdio_tty_init_tty);
518
519int sdio_tty_uninit_tty(void *sdio_tty_handle)
520{
521 int ret = 0;
522 struct sdio_tty *sdio_tty_drv = sdio_tty_handle;
523
524 if (!sdio_tty_drv) {
525 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
526 __func__);
527 return -ENODEV;
528 }
529
530 if (sdio_tty_drv->sdio_tty_state != TTY_INITIAL) {
531 tty_unregister_device(sdio_tty_drv->tty_drv, 0);
532
533 ret = tty_unregister_driver(sdio_tty_drv->tty_drv);
534 if (ret) {
535 pr_err(SDIO_TTY_MODULE_NAME ": %s: "
536 "tty_unregister_driver() failed\n", __func__);
537 }
538 put_tty_driver(sdio_tty_drv->tty_drv);
539 sdio_tty_drv->sdio_tty_state = TTY_INITIAL;
540 sdio_tty_drv->tty_drv = NULL;
541 }
542
543 pr_info(SDIO_TTY_MODULE_NAME ": %s: Freeing sdio_tty structure",
544 __func__);
545 kfree(sdio_tty_drv);
546
547 return 0;
548}
549EXPORT_SYMBOL(sdio_tty_uninit_tty);
550
551
552void sdio_tty_enable_debug_msg(void *sdio_tty_handle, int enable)
553{
554 struct sdio_tty *sdio_tty_drv = sdio_tty_handle;
555
556 if (!sdio_tty_drv) {
557 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
558 __func__);
559 return;
560 }
561 pr_info(SDIO_TTY_MODULE_NAME ": %s: setting debug_msg_on to %d",
562 __func__, enable);
563 sdio_tty_drv->debug_msg_on = enable;
564}
565EXPORT_SYMBOL(sdio_tty_enable_debug_msg);
566
567
568static int __init sdio_tty_init(void)
569{
570 return 0;
571};
572
573/*
574 * Module Exit.
575 *
576 * Unregister SDIO driver.
577 *
578 */
579static void __exit sdio_tty_exit(void)
580{
581}
582
583module_init(sdio_tty_init);
584module_exit(sdio_tty_exit);
585
586MODULE_DESCRIPTION("SDIO TTY");
587MODULE_LICENSE("GPL v2");
588MODULE_AUTHOR("Maya Erez <merez@codeaurora.org>");