tty: add SPDX identifiers to all remaining files in drivers/tty/
[linux-2.6-block.git] / drivers / tty / n_tracerouter.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  n_tracerouter.c - Trace data router through tty space
4  *
5  *  Copyright (C) Intel 2011
6  *
7  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License version 2
11  *  as published by the Free Software Foundation.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19  *
20  * This trace router uses the Linux line discipline framework to route
21  * trace data coming from a HW Modem to a PTI (Parallel Trace Module) port.
22  * The solution is not specific to a HW modem and this line disciple can
23  * be used to route any stream of data in kernel space.
24  * This is part of a solution for the P1149.7, compact JTAG, standard.
25  */
26
27 #include <linux/init.h>
28 #include <linux/kernel.h>
29 #include <linux/module.h>
30 #include <linux/types.h>
31 #include <linux/ioctl.h>
32 #include <linux/tty.h>
33 #include <linux/tty_ldisc.h>
34 #include <linux/errno.h>
35 #include <linux/string.h>
36 #include <linux/mutex.h>
37 #include <linux/slab.h>
38 #include <linux/bug.h>
39 #include "n_tracesink.h"
40
41 /*
42  * Other ldisc drivers use 65536 which basically means,
43  * 'I can always accept 64k' and flow control is off.
44  * This number is deemed appropriate for this driver.
45  */
46 #define RECEIVE_ROOM    65536
47 #define DRIVERNAME      "n_tracerouter"
48
49 /*
50  * struct to hold private configuration data for this ldisc.
51  * opencalled is used to hold if this ldisc has been opened.
52  * kref_tty holds the tty reference the ldisc sits on top of.
53  */
54 struct tracerouter_data {
55         u8 opencalled;
56         struct tty_struct *kref_tty;
57 };
58 static struct tracerouter_data *tr_data;
59
60 /* lock for when tty reference is being used */
61 static DEFINE_MUTEX(routelock);
62
63 /**
64  * n_tracerouter_open() - Called when a tty is opened by a SW entity.
65  * @tty: terminal device to the ldisc.
66  *
67  * Return:
68  *      0 for success.
69  *
70  * Caveats: This should only be opened one time per SW entity.
71  */
72 static int n_tracerouter_open(struct tty_struct *tty)
73 {
74         int retval = -EEXIST;
75
76         mutex_lock(&routelock);
77         if (tr_data->opencalled == 0) {
78
79                 tr_data->kref_tty = tty_kref_get(tty);
80                 if (tr_data->kref_tty == NULL) {
81                         retval = -EFAULT;
82                 } else {
83                         tr_data->opencalled = 1;
84                         tty->disc_data      = tr_data;
85                         tty->receive_room   = RECEIVE_ROOM;
86                         tty_driver_flush_buffer(tty);
87                         retval = 0;
88                 }
89         }
90         mutex_unlock(&routelock);
91         return retval;
92 }
93
94 /**
95  * n_tracerouter_close() - close connection
96  * @tty: terminal device to the ldisc.
97  *
98  * Called when a software entity wants to close a connection.
99  */
100 static void n_tracerouter_close(struct tty_struct *tty)
101 {
102         struct tracerouter_data *tptr = tty->disc_data;
103
104         mutex_lock(&routelock);
105         WARN_ON(tptr->kref_tty != tr_data->kref_tty);
106         tty_driver_flush_buffer(tty);
107         tty_kref_put(tr_data->kref_tty);
108         tr_data->kref_tty = NULL;
109         tr_data->opencalled = 0;
110         tty->disc_data = NULL;
111         mutex_unlock(&routelock);
112 }
113
114 /**
115  * n_tracerouter_read() - read request from user space
116  * @tty:  terminal device passed into the ldisc.
117  * @file: pointer to open file object.
118  * @buf:  pointer to the data buffer that gets eventually returned.
119  * @nr:   number of bytes of the data buffer that is returned.
120  *
121  * function that allows read() functionality in userspace. By default if this
122  * is not implemented it returns -EIO. This module is functioning like a
123  * router via n_tracerouter_receivebuf(), and there is no real requirement
124  * to implement this function. However, an error return value other than
125  * -EIO should be used just to show that there was an intent not to have
126  * this function implemented.  Return value based on read() man pages.
127  *
128  * Return:
129  *       -EINVAL
130  */
131 static ssize_t n_tracerouter_read(struct tty_struct *tty, struct file *file,
132                                   unsigned char __user *buf, size_t nr) {
133         return -EINVAL;
134 }
135
136 /**
137  * n_tracerouter_write() - Function that allows write() in userspace.
138  * @tty:  terminal device passed into the ldisc.
139  * @file: pointer to open file object.
140  * @buf:  pointer to the data buffer that gets eventually returned.
141  * @nr:   number of bytes of the data buffer that is returned.
142  *
143  * By default if this is not implemented, it returns -EIO.
144  * This should not be implemented, ever, because
145  * 1. this driver is functioning like a router via
146  *    n_tracerouter_receivebuf()
147  * 2. No writes to HW will ever go through this line discpline driver.
148  * However, an error return value other than -EIO should be used
149  * just to show that there was an intent not to have this function
150  * implemented.  Return value based on write() man pages.
151  *
152  * Return:
153  *      -EINVAL
154  */
155 static ssize_t n_tracerouter_write(struct tty_struct *tty, struct file *file,
156                                    const unsigned char *buf, size_t nr) {
157         return -EINVAL;
158 }
159
160 /**
161  * n_tracerouter_receivebuf() - Routing function for driver.
162  * @tty: terminal device passed into the ldisc.  It's assumed
163  *       tty will never be NULL.
164  * @cp:  buffer, block of characters to be eventually read by
165  *       someone, somewhere (user read() call or some kernel function).
166  * @fp:  flag buffer.
167  * @count: number of characters (aka, bytes) in cp.
168  *
169  * This function takes the input buffer, cp, and passes it to
170  * an external API function for processing.
171  */
172 static void n_tracerouter_receivebuf(struct tty_struct *tty,
173                                         const unsigned char *cp,
174                                         char *fp, int count)
175 {
176         mutex_lock(&routelock);
177         n_tracesink_datadrain((u8 *) cp, count);
178         mutex_unlock(&routelock);
179 }
180
181 /*
182  * Flush buffer is not impelemented as the ldisc has no internal buffering
183  * so the tty_driver_flush_buffer() is sufficient for this driver's needs.
184  */
185
186 static struct tty_ldisc_ops tty_ptirouter_ldisc = {
187         .owner          = THIS_MODULE,
188         .magic          = TTY_LDISC_MAGIC,
189         .name           = DRIVERNAME,
190         .open           = n_tracerouter_open,
191         .close          = n_tracerouter_close,
192         .read           = n_tracerouter_read,
193         .write          = n_tracerouter_write,
194         .receive_buf    = n_tracerouter_receivebuf
195 };
196
197 /**
198  * n_tracerouter_init - module initialisation
199  *
200  * Registers this module as a line discipline driver.
201  *
202  * Return:
203  *      0 for success, any other value error.
204  */
205 static int __init n_tracerouter_init(void)
206 {
207         int retval;
208
209         tr_data = kzalloc(sizeof(struct tracerouter_data), GFP_KERNEL);
210         if (tr_data == NULL)
211                 return -ENOMEM;
212
213
214         /* Note N_TRACEROUTER is defined in linux/tty.h */
215         retval = tty_register_ldisc(N_TRACEROUTER, &tty_ptirouter_ldisc);
216         if (retval < 0) {
217                 pr_err("%s: Registration failed: %d\n", __func__, retval);
218                 kfree(tr_data);
219         }
220         return retval;
221 }
222
223 /**
224  * n_tracerouter_exit - module unload
225  *
226  * Removes this module as a line discipline driver.
227  */
228 static void __exit n_tracerouter_exit(void)
229 {
230         int retval = tty_unregister_ldisc(N_TRACEROUTER);
231
232         if (retval < 0)
233                 pr_err("%s: Unregistration failed: %d\n", __func__,  retval);
234         else
235                 kfree(tr_data);
236 }
237
238 module_init(n_tracerouter_init);
239 module_exit(n_tracerouter_exit);
240
241 MODULE_LICENSE("GPL");
242 MODULE_AUTHOR("Jay Freyensee");
243 MODULE_ALIAS_LDISC(N_TRACEROUTER);
244 MODULE_DESCRIPTION("Trace router ldisc driver");