Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
n_tracesink.c
Go to the documentation of this file.
1 /*
2  * n_tracesink.c - Trace data router and sink path through tty space.
3  *
4  * Copyright (C) Intel 2011
5  *
6  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
18  *
19  * The trace sink uses the Linux line discipline framework to receive
20  * trace data coming from the PTI source line discipline driver
21  * to a user-desired tty port, like USB.
22  * This is to provide a way to extract modem trace data on
23  * devices that do not have a PTI HW module, or just need modem
24  * trace data to come out of a different HW output port.
25  * This is part of a solution for the P1149.7, compact JTAG, standard.
26  */
27 
28 #include <linux/init.h>
29 #include <linux/kernel.h>
30 #include <linux/module.h>
31 #include <linux/types.h>
32 #include <linux/ioctl.h>
33 #include <linux/tty.h>
34 #include <linux/tty_ldisc.h>
35 #include <linux/errno.h>
36 #include <linux/string.h>
37 #include <asm-generic/bug.h>
38 #include "n_tracesink.h"
39 
40 /*
41  * Other ldisc drivers use 65536 which basically means,
42  * 'I can always accept 64k' and flow control is off.
43  * This number is deemed appropriate for this driver.
44  */
45 #define RECEIVE_ROOM 65536
46 #define DRIVERNAME "n_tracesink"
47 
48 /*
49  * there is a quirk with this ldisc is he can write data
50  * to a tty from anyone calling his kernel API, which
51  * meets customer requirements in the drivers/misc/pti.c
52  * project. So he needs to know when he can and cannot write when
53  * the API is called. In theory, the API can be called
54  * after an init() but before a successful open() which
55  * would crash the system if tty is not checked.
56  */
57 static struct tty_struct *this_tty;
58 static DEFINE_MUTEX(writelock);
59 
74 static int n_tracesink_open(struct tty_struct *tty)
75 {
76  int retval = -EEXIST;
77 
78  mutex_lock(&writelock);
79  if (this_tty == NULL) {
80  this_tty = tty_kref_get(tty);
81  if (this_tty == NULL) {
82  retval = -EFAULT;
83  } else {
84  tty->disc_data = this_tty;
86  retval = 0;
87  }
88  }
89  mutex_unlock(&writelock);
90 
91  return retval;
92 }
93 
100 static void n_tracesink_close(struct tty_struct *tty)
101 {
102  mutex_lock(&writelock);
104  tty_kref_put(this_tty);
105  this_tty = NULL;
106  tty->disc_data = NULL;
107  mutex_unlock(&writelock);
108 }
109 
127 static ssize_t n_tracesink_read(struct tty_struct *tty, struct file *file,
128  unsigned char __user *buf, size_t nr) {
129  return -EINVAL;
130 }
131 
151 static ssize_t n_tracesink_write(struct tty_struct *tty, struct file *file,
152  const unsigned char *buf, size_t nr) {
153  return -EINVAL;
154 }
155 
172 {
173  mutex_lock(&writelock);
174 
175  if ((buf != NULL) && (count > 0) && (this_tty != NULL))
176  this_tty->ops->write(this_tty, buf, count);
177 
178  mutex_unlock(&writelock);
179 }
181 
182 /*
183  * Flush buffer is not impelemented as the ldisc has no internal buffering
184  * so the tty_driver_flush_buffer() is sufficient for this driver's needs.
185  */
186 
187 /*
188  * tty_ldisc function operations for this driver.
189  */
190 static struct tty_ldisc_ops tty_n_tracesink = {
191  .owner = THIS_MODULE,
192  .magic = TTY_LDISC_MAGIC,
193  .name = DRIVERNAME,
194  .open = n_tracesink_open,
195  .close = n_tracesink_close,
196  .read = n_tracesink_read,
197  .write = n_tracesink_write
198 };
199 
208 static int __init n_tracesink_init(void)
209 {
210  /* Note N_TRACESINK is defined in linux/tty.h */
211  int retval = tty_register_ldisc(N_TRACESINK, &tty_n_tracesink);
212 
213  if (retval < 0)
214  pr_err("%s: Registration failed: %d\n", __func__, retval);
215 
216  return retval;
217 }
218 
224 static void __exit n_tracesink_exit(void)
225 {
226  int retval = tty_unregister_ldisc(N_TRACESINK);
227 
228  if (retval < 0)
229  pr_err("%s: Unregistration failed: %d\n", __func__, retval);
230 }
231 
232 module_init(n_tracesink_init);
233 module_exit(n_tracesink_exit);
234 
235 MODULE_LICENSE("GPL");
236 MODULE_AUTHOR("Jay Freyensee");
238 MODULE_DESCRIPTION("Trace sink ldisc driver");