diff options
author | Richard Zhu <r65037@freescale.com> | 2014-06-26 03:56:24 -0400 |
---|---|---|
committer | Richard Zhu <r65037@freescale.com> | 2014-06-30 21:33:35 -0400 |
commit | 58ad81506e01e6a9625bc096595113f1f6bbe521 (patch) | |
tree | f53548e416f4ff241bf96ea0d811fca39c77cdc6 | |
parent | 3c16fd041fa430bd4b601964b944daa2bc474c20 (diff) |
ENGR00320327 mcc: mcc posix pty interface demo driver
- /dev/ttyMCCp0 can be created.
- use schedule delayed work to kick off the demo
- one simple test app(mxc_mcc_tty_test.out) used to do
the mcc pty interface demo tests.
- m4 part of the mcc pingpong demo is required to be run
on m4.
- up to now, only the unsigned int decimal number is used
in the tests.
test how-to by the simple test app:
./mxc_mcc_tty_test.out /dev/ttyMCCp0 115200 R 1 512 &
echo <your input> > /dev/ttyMCCp0
then
<your input + 1> would be received the test app.
Signed-off-by: Richard Zhu <r65037@freescale.com>
-rw-r--r-- | drivers/char/imx_mcc/Kconfig | 8 | ||||
-rw-r--r-- | drivers/char/imx_mcc/Makefile | 1 | ||||
-rw-r--r-- | drivers/char/imx_mcc/imx_mcc_tty.c | 253 |
3 files changed, 262 insertions, 0 deletions
diff --git a/drivers/char/imx_mcc/Kconfig b/drivers/char/imx_mcc/Kconfig index d60cf66cd8fd..9625efa2df7f 100644 --- a/drivers/char/imx_mcc/Kconfig +++ b/drivers/char/imx_mcc/Kconfig | |||
@@ -13,3 +13,11 @@ config IMX_MCC_DEMO | |||
13 | depends on SOC_IMX6SX && IMX_SEMA4 | 13 | depends on SOC_IMX6SX && IMX_SEMA4 |
14 | help | 14 | help |
15 | Support for IMX MCC DEMO, most people should say N here. | 15 | Support for IMX MCC DEMO, most people should say N here. |
16 | |||
17 | config IMX_MCC_TTY | ||
18 | bool "imx pty for mcc interface" | ||
19 | depends on SOC_IMX6SX && IMX_SEMA4 | ||
20 | help | ||
21 | This enables a pty node for imx6sx mcc interface. | ||
22 | |||
23 | #end imx mcc | ||
diff --git a/drivers/char/imx_mcc/Makefile b/drivers/char/imx_mcc/Makefile index a0d60f341d07..f5bda928e23c 100644 --- a/drivers/char/imx_mcc/Makefile +++ b/drivers/char/imx_mcc/Makefile | |||
@@ -4,3 +4,4 @@ | |||
4 | # | 4 | # |
5 | obj-$(CONFIG_IMX_SEMA4) += imx_sema4.o | 5 | obj-$(CONFIG_IMX_SEMA4) += imx_sema4.o |
6 | obj-$(CONFIG_IMX_MCC_DEMO) += imx_mcc_demo.o | 6 | obj-$(CONFIG_IMX_MCC_DEMO) += imx_mcc_demo.o |
7 | obj-$(CONFIG_IMX_MCC_TTY) += imx_mcc_tty.o | ||
diff --git a/drivers/char/imx_mcc/imx_mcc_tty.c b/drivers/char/imx_mcc/imx_mcc_tty.c new file mode 100644 index 000000000000..843b5fcbd010 --- /dev/null +++ b/drivers/char/imx_mcc/imx_mcc_tty.c | |||
@@ -0,0 +1,253 @@ | |||
1 | /* | ||
2 | * imx_mcc_tty.c - pty demo driver used to test imx mcc | ||
3 | * posix pty interface. | ||
4 | * | ||
5 | * Copyright (C) 2014 Freescale Semiconductor, Inc. | ||
6 | */ | ||
7 | |||
8 | /* | ||
9 | * The code contained herein is licensed under the GNU General Public | ||
10 | * License. You may obtain a copy of the GNU General Public License | ||
11 | * Version 2 or later at the following locations: | ||
12 | * | ||
13 | * http://www.opensource.org/licenses/gpl-license.html | ||
14 | * http://www.gnu.org/copyleft/gpl.html | ||
15 | */ | ||
16 | |||
17 | #include <linux/delay.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/tty.h> | ||
22 | #include <linux/tty_driver.h> | ||
23 | #include <linux/tty_flip.h> | ||
24 | #include <linux/mcc_common.h> | ||
25 | #include <linux/mcc_api.h> | ||
26 | |||
27 | /** | ||
28 | * struct mcctty_port - Wrapper struct for imx mcc pty port. | ||
29 | * @port: TTY port data | ||
30 | * @rx_lock: Lock for rx_buf. | ||
31 | * @rx_buf: Read buffer | ||
32 | */ | ||
33 | struct mcctty_port { | ||
34 | struct delayed_work read; | ||
35 | struct tty_port port; | ||
36 | spinlock_t rx_lock; | ||
37 | char *rx_buf; | ||
38 | }; | ||
39 | |||
40 | static struct mcctty_port mcc_tty_port; | ||
41 | |||
42 | enum { | ||
43 | MCC_NODE_A9 = 0, | ||
44 | MCC_NODE_M4 = 0, | ||
45 | |||
46 | MCC_A9_PORT = 1, | ||
47 | MCC_M4_PORT = 2, | ||
48 | }; | ||
49 | |||
50 | /* mcc tty/pingpong demo */ | ||
51 | static MCC_ENDPOINT mcc_endpoint_a9_pingpong = {0, MCC_NODE_A9, MCC_A9_PORT}; | ||
52 | static MCC_ENDPOINT mcc_endpoint_m4_pingpong = {1, MCC_NODE_M4, MCC_M4_PORT}; | ||
53 | struct mcc_pp_msg { | ||
54 | unsigned int data; | ||
55 | }; | ||
56 | |||
57 | static void mcctty_delay_work(struct work_struct *work) | ||
58 | { | ||
59 | struct mcctty_port *cport = &mcc_tty_port; | ||
60 | int ret, space; | ||
61 | unsigned char *cbuf; | ||
62 | struct mcc_pp_msg pp_msg; | ||
63 | MCC_MEM_SIZE num_of_received_bytes; | ||
64 | MCC_INFO_STRUCT mcc_info; | ||
65 | |||
66 | /* start mcc tty recv here */ | ||
67 | ret = mcc_initialize(MCC_NODE_A9); | ||
68 | if (ret) | ||
69 | pr_err("failed to initialize mcc.\n"); | ||
70 | |||
71 | ret = mcc_get_info(MCC_NODE_A9, &mcc_info); | ||
72 | if (ret) | ||
73 | pr_err("failed to get mcc info.\n"); | ||
74 | pr_info("\nA9 mcc prepares run, MCC version is %s\n", | ||
75 | mcc_info.version_string); | ||
76 | |||
77 | pr_info("imx mcc tty/pingpong demo begin.\n"); | ||
78 | ret = mcc_create_endpoint(&mcc_endpoint_a9_pingpong, | ||
79 | MCC_A9_PORT); | ||
80 | if (ret) | ||
81 | pr_err("failed to create a9 mcc ep.\n"); | ||
82 | |||
83 | while (1) { | ||
84 | ret = mcc_recv_copy(&mcc_endpoint_a9_pingpong, &pp_msg, | ||
85 | sizeof(struct mcc_pp_msg), | ||
86 | &num_of_received_bytes, 0xffffffff); | ||
87 | |||
88 | if (MCC_SUCCESS != ret) { | ||
89 | pr_err("A9 Main task receive error: %d\n", ret); | ||
90 | } else { | ||
91 | /* flush the recv-ed data to tty node */ | ||
92 | spin_lock_bh(&cport->rx_lock); | ||
93 | space = tty_prepare_flip_string(&cport->port, &cbuf, | ||
94 | num_of_received_bytes); | ||
95 | if ((space <= 0) || (cport->rx_buf == NULL)) | ||
96 | goto pp_unlock; | ||
97 | |||
98 | memcpy(cport->rx_buf, &pp_msg.data, | ||
99 | num_of_received_bytes); | ||
100 | memcpy(cbuf, cport->rx_buf, space); | ||
101 | tty_flip_buffer_push(&cport->port); | ||
102 | pp_unlock: | ||
103 | spin_unlock_bh(&cport->rx_lock); | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | |||
108 | static struct tty_port_operations mcctty_port_ops = { }; | ||
109 | |||
110 | static int mcctty_install(struct tty_driver *driver, struct tty_struct *tty) | ||
111 | { | ||
112 | return tty_port_install(&mcc_tty_port.port, driver, tty); | ||
113 | } | ||
114 | |||
115 | static int mcctty_open(struct tty_struct *tty, struct file *filp) | ||
116 | { | ||
117 | return tty_port_open(tty->port, tty, filp); | ||
118 | } | ||
119 | |||
120 | static void mcctty_close(struct tty_struct *tty, struct file *filp) | ||
121 | { | ||
122 | return tty_port_close(tty->port, tty, filp); | ||
123 | } | ||
124 | |||
125 | static int mcctty_write(struct tty_struct *tty, const unsigned char *buf, | ||
126 | int total) | ||
127 | { | ||
128 | int i, ret = 0; | ||
129 | struct mcc_pp_msg pp_msg; | ||
130 | |||
131 | if (NULL == buf) | ||
132 | return 0; | ||
133 | |||
134 | for (i = 0; i < total; i++) { | ||
135 | pp_msg.data = (unsigned int)buf[i]; | ||
136 | |||
137 | /* | ||
138 | * wait until the remote endpoint is created by | ||
139 | * the other core | ||
140 | */ | ||
141 | ret = mcc_send(&mcc_endpoint_m4_pingpong, &pp_msg, | ||
142 | sizeof(struct mcc_pp_msg), | ||
143 | 0xffffffff); | ||
144 | |||
145 | while (MCC_ERR_ENDPOINT == ret) { | ||
146 | pr_err("\n send err ret %d, re-send\n", ret); | ||
147 | ret = mcc_send(&mcc_endpoint_m4_pingpong, &pp_msg, | ||
148 | sizeof(struct mcc_pp_msg), | ||
149 | 0xffffffff); | ||
150 | msleep(5000); | ||
151 | } | ||
152 | } | ||
153 | |||
154 | return total; | ||
155 | } | ||
156 | |||
157 | static int mcctty_write_room(struct tty_struct *tty) | ||
158 | { | ||
159 | int room; | ||
160 | |||
161 | /* report the space in the mcc buffer */ | ||
162 | room = MCC_ATTR_BUFFER_SIZE_IN_BYTES; | ||
163 | |||
164 | return room; | ||
165 | } | ||
166 | |||
167 | static const struct tty_operations imxmcctty_ops = { | ||
168 | .install = mcctty_install, | ||
169 | .open = mcctty_open, | ||
170 | .close = mcctty_close, | ||
171 | .write = mcctty_write, | ||
172 | .write_room = mcctty_write_room, | ||
173 | }; | ||
174 | |||
175 | static struct tty_driver *mcctty_driver; | ||
176 | |||
177 | static int __init imxmcctty_init(void) | ||
178 | { | ||
179 | int ret; | ||
180 | struct mcctty_port *cport = &mcc_tty_port; | ||
181 | |||
182 | mcctty_driver = tty_alloc_driver(1, | ||
183 | TTY_DRIVER_RESET_TERMIOS | | ||
184 | TTY_DRIVER_UNNUMBERED_NODE); | ||
185 | if (IS_ERR(mcctty_driver)) | ||
186 | return PTR_ERR(mcctty_driver); | ||
187 | |||
188 | mcctty_driver->driver_name = "mcc_tty"; | ||
189 | mcctty_driver->name = "ttyMCC"; | ||
190 | mcctty_driver->major = TTYAUX_MAJOR; | ||
191 | mcctty_driver->minor_start = 3; | ||
192 | mcctty_driver->type = TTY_DRIVER_TYPE_PTY; | ||
193 | mcctty_driver->init_termios = tty_std_termios; | ||
194 | mcctty_driver->init_termios.c_cflag |= CLOCAL; | ||
195 | |||
196 | tty_set_operations(mcctty_driver, &imxmcctty_ops); | ||
197 | |||
198 | tty_port_init(&cport->port); | ||
199 | cport->port.ops = &mcctty_port_ops; | ||
200 | spin_lock_init(&cport->rx_lock); | ||
201 | spin_lock_init(&cport->tx_lock); | ||
202 | |||
203 | ret = tty_register_driver(mcctty_driver); | ||
204 | if (ret < 0) { | ||
205 | pr_err("Couldn't install mcc tty driver: err %d\n", ret); | ||
206 | goto error; | ||
207 | } else | ||
208 | pr_info("Install mcc tty driver!\n"); | ||
209 | |||
210 | /* Allocate the buffer we use for reading data */ | ||
211 | cport->rx_buf = kzalloc(MCC_ATTR_BUFFER_SIZE_IN_BYTES, | ||
212 | GFP_KERNEL); | ||
213 | if (!cport->rx_buf) { | ||
214 | ret = -ENOMEM; | ||
215 | goto error; | ||
216 | } | ||
217 | |||
218 | INIT_DELAYED_WORK(&cport->read, mcctty_delay_work); | ||
219 | schedule_delayed_work(&cport->read, HZ/100); | ||
220 | return 0; | ||
221 | |||
222 | error: | ||
223 | tty_unregister_driver(mcctty_driver); | ||
224 | put_tty_driver(mcctty_driver); | ||
225 | tty_port_destroy(&cport->port); | ||
226 | mcctty_driver = NULL; | ||
227 | |||
228 | return ret; | ||
229 | } | ||
230 | |||
231 | static void imxmcctty_exit(void) | ||
232 | { | ||
233 | int ret = 0; | ||
234 | struct mcctty_port *cport = &mcc_tty_port; | ||
235 | |||
236 | /* stop reading, null the read buffer. */ | ||
237 | kfree(cport->rx_buf); | ||
238 | cport->rx_buf = NULL; | ||
239 | |||
240 | /* destory the mcc tty endpoint here */ | ||
241 | ret = mcc_destroy_endpoint(&mcc_endpoint_a9_pingpong); | ||
242 | if (ret) | ||
243 | pr_err("failed to destory a9 mcc ep.\n"); | ||
244 | else | ||
245 | pr_info("destory a9 mcc ep.\n"); | ||
246 | |||
247 | tty_unregister_driver(mcctty_driver); | ||
248 | tty_port_destroy(&cport->port); | ||
249 | put_tty_driver(mcctty_driver); | ||
250 | } | ||
251 | |||
252 | module_init(imxmcctty_init); | ||
253 | module_exit(imxmcctty_exit); | ||