blob: fca88d80a08f7cbcd26758324565483b1314631b [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
Krishna Kondaad3f0f72011-08-29 14:41:21 -0700173 if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
174 pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
175 __func__, sdio_tty_drv->sdio_tty_state);
176 return -EPERM;
177 }
178
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700179 write_avail = sdio_write_avail(sdio_tty_drv->ch);
180 DEBUG_MSG(sdio_tty_drv,
181 SDIO_TTY_MODULE_NAME ": %s: write_avail=%d",
182 __func__, write_avail);
183
184 return write_avail;
185}
186
187/**
188 * sdio_tty_write_callback
189 * this is the write callback of the tty driver.
190 *
191 * @tty: pointer to tty struct.
192 * @buf: buffer to write from.
193 * @count: number of bytes to write.
194 * @return bytes written or negative value on error.
195 *
196 * if destination buffer has not enough room for the incoming
197 * data, writes the possible amount of bytes .
198 */
199static int sdio_tty_write_callback(struct tty_struct *tty,
200 const unsigned char *buf, int count)
201{
202 int write_avail = 0;
203 int len = count;
204 int ret = 0;
205 struct sdio_tty *sdio_tty_drv = NULL;
206
207 if (!tty) {
208 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty",
209 __func__);
210 return -ENODEV;
211 }
212 sdio_tty_drv = tty->driver_data;
213 if (!sdio_tty_drv) {
214 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
215 __func__);
216 return -ENODEV;
217 }
218
219 if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
220 pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
221 __func__, sdio_tty_drv->sdio_tty_state);
222 return -EPERM;
223 }
224
225 DEBUG_MSG(sdio_tty_drv,
226 SDIO_TTY_MODULE_NAME ": %s: WRITING CALLBACK CALLED WITH "
227 "%d bytes\n",
228 __func__, count);
229 write_avail = sdio_write_avail(sdio_tty_drv->ch);
230 if (write_avail == 0) {
231 DEBUG_MSG(sdio_tty_drv,
232 SDIO_TTY_MODULE_NAME ": %s: write_avail is 0\n",
233 __func__);
234 return 0;
235 }
236 if (write_avail > SDIO_TTY_MAX_PACKET_SIZE) {
237 DEBUG_MSG(sdio_tty_drv,
238 SDIO_TTY_MODULE_NAME ": %s: write_avail(%d) is "
239 "bigger than max packet size,(%d), setting to "
240 "max_packet_size\n",
241 __func__, write_avail, SDIO_TTY_MAX_PACKET_SIZE);
242 write_avail = SDIO_TTY_MAX_PACKET_SIZE;
243 }
244 if (write_avail < count) {
245 DEBUG_MSG(sdio_tty_drv,
246 SDIO_TTY_MODULE_NAME ": %s: write_avail(%d) is "
247 "smaller than "
248 "required(%d), writing only %d bytes\n",
249 __func__, write_avail, count, write_avail);
250 len = write_avail;
251 }
252 ret = sdio_write(sdio_tty_drv->ch, buf, len);
253 if (ret) {
254 pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_write failed, ret=%d\n",
255 __func__, ret);
256 return 0;
257 }
258
259 DEBUG_MSG(sdio_tty_drv,
260 SDIO_TTY_MODULE_NAME ": %s: End of function, len=%d bytes\n",
261 __func__, len);
262
263 return len;
264}
265
266static void sdio_tty_notify(void *priv, unsigned event)
267{
268 struct sdio_tty *sdio_tty_drv = priv;
269
270 if (!sdio_tty_drv) {
271 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
272 __func__);
273 }
274
275 if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
276 pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
277 __func__, sdio_tty_drv->sdio_tty_state);
278 return;
279 }
280
281 DEBUG_MSG(sdio_tty_drv,
282 SDIO_TTY_MODULE_NAME ": %s: event %d received\n", __func__,
283 event);
284
285 if (event == SDIO_EVENT_DATA_READ_AVAIL)
286 queue_work(sdio_tty_drv->workq, &sdio_tty_drv->work_read);
287}
288
289/**
290 * sdio_tty_open
291 * This is the open callback of the tty driver. it opens
292 * the sdio channel, and creates the workqueue.
293 *
294 * @tty: a pointer to the tty struct.
295 * @file: file descriptor.
296 * @return 0 on success or negative value on error.
297 */
298static int sdio_tty_open(struct tty_struct *tty, struct file *file)
299{
300 int ret = 0;
301 struct sdio_tty *sdio_tty_drv = NULL;
302
303 if (!tty) {
304 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty",
305 __func__);
306 return -ENODEV;
307 }
308 sdio_tty_drv = sdio_tty;
309 if (!sdio_tty_drv) {
310 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
311 __func__);
312 return -ENODEV;
313 }
314
315 tty->driver_data = sdio_tty_drv;
316
317 sdio_tty_drv->tty_str = tty;
318 sdio_tty_drv->tty_str->low_latency = 1;
319 sdio_tty_drv->tty_str->icanon = 0;
320 set_bit(TTY_NO_WRITE_SPLIT, &sdio_tty_drv->tty_str->flags);
321
322 sdio_tty_drv->read_buf = kzalloc(SDIO_TTY_MAX_PACKET_SIZE, GFP_KERNEL);
323 if (sdio_tty_drv->read_buf == NULL) {
324 pr_err(SDIO_TTY_MODULE_NAME ": %s: failed to allocate read_buf",
325 __func__);
326 return -ENOMEM;
327 }
328
329 sdio_tty_drv->workq = create_singlethread_workqueue("sdio_tty_read");
330 if (!sdio_tty_drv->workq) {
331 pr_err(SDIO_TTY_MODULE_NAME ": %s: failed to create workq",
332 __func__);
333 return -ENOMEM;
334 }
335
336 if (sdio_tty_drv->sdio_tty_state == TTY_OPENED) {
337 pr_err(SDIO_TTY_MODULE_NAME ": %s: tty is already open",
338 __func__);
339 return -EBUSY;
340 }
341
342 if (!sdio_tty_drv->is_sdio_open) {
343 ret = sdio_open(sdio_tty_drv->sdio_ch_name, &sdio_tty_drv->ch,
344 sdio_tty_drv, sdio_tty_notify);
345 if (ret < 0) {
346 pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_open err=%d\n",
347 __func__, ret);
348 destroy_workqueue(sdio_tty_drv->workq);
349 return ret;
350 }
351
352 pr_info(SDIO_TTY_MODULE_NAME ": %s: SDIO_TTY channel opened\n",
353 __func__);
354
355 sdio_tty_drv->is_sdio_open = 1;
356 } else {
357 /* If SDIO channel is already open try to read the data
358 * from the modem
359 */
360 queue_work(sdio_tty_drv->workq, &sdio_tty_drv->work_read);
361
362 }
363
364 sdio_tty_drv->sdio_tty_state = TTY_OPENED;
365
366 pr_info(SDIO_TTY_MODULE_NAME ": %s: TTY device opened\n",
367 __func__);
368
369 return ret;
370}
371
372/**
373 * sdio_tty_close
374 * This is the close callback of the tty driver. it requests
375 * the main thread to exit, and waits for notification of it.
376 * it also de-allocates the buffers, and unregisters the tty
377 * driver and device.
378 *
379 * @tty: a pointer to the tty struct.
380 * @file: file descriptor.
381 * @return None.
382 */
383static void sdio_tty_close(struct tty_struct *tty, struct file *file)
384{
385 struct sdio_tty *sdio_tty_drv = NULL;
386
387 if (!tty) {
388 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty",
389 __func__);
390 return;
391 }
392 sdio_tty_drv = tty->driver_data;
393 if (!sdio_tty_drv) {
394 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
395 __func__);
396 return;
397 }
398 if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
399 pr_err(SDIO_TTY_MODULE_NAME ": %s: trying to close a "
400 "TTY device that was not opened\n",
401 __func__);
402 return;
403 }
404
405 flush_workqueue(sdio_tty_drv->workq);
406 destroy_workqueue(sdio_tty_drv->workq);
407
408 kfree(sdio_tty_drv->read_buf);
409 sdio_tty_drv->read_buf = NULL;
410
411 sdio_tty_drv->sdio_tty_state = TTY_CLOSED;
412
413 pr_info(SDIO_TTY_MODULE_NAME ": %s: SDIO_TTY channel closed\n",
414 __func__);
415}
416
417static void sdio_tty_unthrottle(struct tty_struct *tty)
418{
419 struct sdio_tty *sdio_tty_drv = NULL;
420
421 if (!tty) {
422 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty",
423 __func__);
424 return;
425 }
426 sdio_tty_drv = tty->driver_data;
427 if (!sdio_tty_drv) {
428 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
429 __func__);
430 return;
431 }
432
433 if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
434 pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
435 __func__, sdio_tty_drv->sdio_tty_state);
436 return;
437 }
438
439 queue_work(sdio_tty_drv->workq, &sdio_tty_drv->work_read);
440 return;
441}
442
443static const struct tty_operations sdio_tty_ops = {
444 .open = sdio_tty_open,
445 .close = sdio_tty_close,
446 .write = sdio_tty_write_callback,
447 .write_room = sdio_tty_write_room,
448 .unthrottle = sdio_tty_unthrottle,
449};
450
451void *sdio_tty_init_tty(char *tty_name, char *sdio_ch_name)
452{
453 int ret = 0;
454 struct device *tty_dev;
455 struct sdio_tty *sdio_tty_drv;
456
457 pr_info(SDIO_TTY_MODULE_NAME ": %s\n", __func__);
458
459 sdio_tty_drv = kzalloc(sizeof(struct sdio_tty), GFP_KERNEL);
460 if (sdio_tty_drv == NULL) {
461 pr_err(SDIO_TTY_MODULE_NAME "%s: failed to allocate sdio_tty",
462 __func__);
463 return NULL;
464 }
465
466 sdio_tty = sdio_tty_drv;
467 sdio_tty_drv->sdio_ch_name = sdio_ch_name;
468
469 INIT_WORK(&sdio_tty_drv->work_read, sdio_tty_read);
470
471 sdio_tty_drv->tty_drv = alloc_tty_driver(MAX_SDIO_TTY_DRV);
472
473 if (!sdio_tty_drv->tty_drv) {
474 pr_err(SDIO_TTY_MODULE_NAME ": %s - tty_drv is NULL",
475 __func__);
476 kfree(sdio_tty_drv);
477 return NULL;
478 }
479
480 sdio_tty_drv->tty_drv->name = tty_name;
481 sdio_tty_drv->tty_drv->owner = THIS_MODULE;
482 sdio_tty_drv->tty_drv->driver_name = "SDIO_tty";
483 /* uses dynamically assigned dev_t values */
484 sdio_tty_drv->tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
485 sdio_tty_drv->tty_drv->subtype = SERIAL_TYPE_NORMAL;
486 sdio_tty_drv->tty_drv->flags = TTY_DRIVER_REAL_RAW
487 | TTY_DRIVER_DYNAMIC_DEV
488 | TTY_DRIVER_RESET_TERMIOS;
489
490 /* initializing the tty driver */
491 sdio_tty_drv->tty_drv->init_termios = tty_std_termios;
492 sdio_tty_drv->tty_drv->init_termios.c_cflag =
493 B4800 | CS8 | CREAD | HUPCL | CLOCAL;
494 sdio_tty_drv->tty_drv->init_termios.c_ispeed = INPUT_SPEED;
495 sdio_tty_drv->tty_drv->init_termios.c_ospeed = OUTPUT_SPEED;
496
497 tty_set_operations(sdio_tty_drv->tty_drv, &sdio_tty_ops);
498
499 ret = tty_register_driver(sdio_tty_drv->tty_drv);
500 if (ret) {
501 put_tty_driver(sdio_tty_drv->tty_drv);
502 pr_err(SDIO_TTY_MODULE_NAME ": %s: tty_register_driver() "
503 "failed\n", __func__);
504
505 sdio_tty_drv->tty_drv = NULL;
506 kfree(sdio_tty_drv);
507 return NULL;
508 }
509
510 tty_dev = tty_register_device(sdio_tty_drv->tty_drv, 0, NULL);
511 if (IS_ERR(tty_dev)) {
512 pr_err(SDIO_TTY_MODULE_NAME ": %s: tty_register_device() "
513 "failed\n", __func__);
514 tty_unregister_driver(sdio_tty_drv->tty_drv);
515 put_tty_driver(sdio_tty_drv->tty_drv);
516 kfree(sdio_tty_drv);
517 return NULL;
518 }
519
520 sdio_tty_drv->sdio_tty_state = TTY_REGISTERED;
521 return sdio_tty_drv;
522}
523EXPORT_SYMBOL(sdio_tty_init_tty);
524
525int sdio_tty_uninit_tty(void *sdio_tty_handle)
526{
527 int ret = 0;
528 struct sdio_tty *sdio_tty_drv = sdio_tty_handle;
529
530 if (!sdio_tty_drv) {
531 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
532 __func__);
533 return -ENODEV;
534 }
Maya Erez06e3cdb2011-09-08 16:18:07 +0300535 if (sdio_tty_drv->sdio_tty_state == TTY_OPENED) {
536 flush_workqueue(sdio_tty_drv->workq);
537 destroy_workqueue(sdio_tty_drv->workq);
538
539 kfree(sdio_tty_drv->read_buf);
540 sdio_tty_drv->read_buf = NULL;
541 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700542
543 if (sdio_tty_drv->sdio_tty_state != TTY_INITIAL) {
544 tty_unregister_device(sdio_tty_drv->tty_drv, 0);
545
546 ret = tty_unregister_driver(sdio_tty_drv->tty_drv);
547 if (ret) {
548 pr_err(SDIO_TTY_MODULE_NAME ": %s: "
549 "tty_unregister_driver() failed\n", __func__);
550 }
551 put_tty_driver(sdio_tty_drv->tty_drv);
552 sdio_tty_drv->sdio_tty_state = TTY_INITIAL;
553 sdio_tty_drv->tty_drv = NULL;
554 }
555
556 pr_info(SDIO_TTY_MODULE_NAME ": %s: Freeing sdio_tty structure",
557 __func__);
558 kfree(sdio_tty_drv);
559
560 return 0;
561}
562EXPORT_SYMBOL(sdio_tty_uninit_tty);
563
564
565void sdio_tty_enable_debug_msg(void *sdio_tty_handle, int enable)
566{
567 struct sdio_tty *sdio_tty_drv = sdio_tty_handle;
568
569 if (!sdio_tty_drv) {
570 pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
571 __func__);
572 return;
573 }
574 pr_info(SDIO_TTY_MODULE_NAME ": %s: setting debug_msg_on to %d",
575 __func__, enable);
576 sdio_tty_drv->debug_msg_on = enable;
577}
578EXPORT_SYMBOL(sdio_tty_enable_debug_msg);
579
580
581static int __init sdio_tty_init(void)
582{
583 return 0;
584};
585
586/*
587 * Module Exit.
588 *
589 * Unregister SDIO driver.
590 *
591 */
592static void __exit sdio_tty_exit(void)
593{
594}
595
596module_init(sdio_tty_init);
597module_exit(sdio_tty_exit);
598
599MODULE_DESCRIPTION("SDIO TTY");
600MODULE_LICENSE("GPL v2");
601MODULE_AUTHOR("Maya Erez <merez@codeaurora.org>");