| The Intel MID PTI project is HW implemented in Intel Atom |
| system-on-a-chip designs based on the Parallel Trace |
| Interface for MIPI P1149.7 cJTAG standard. The kernel solution |
| for this platform involves the following files: |
| |
| ./include/linux/pti.h |
| ./drivers/.../n_tracesink.h |
| ./drivers/.../n_tracerouter.c |
| ./drivers/.../n_tracesink.c |
| ./drivers/.../pti.c |
| |
| pti.c is the driver that enables various debugging features |
| popular on platforms from certain mobile manufacturers. |
| n_tracerouter.c and n_tracesink.c allow extra system information to |
| be collected and routed to the pti driver, such as trace |
| debugging data from a modem. Although n_tracerouter |
| and n_tracesink are a part of the complete PTI solution, |
| these two line disciplines can work separately from |
| pti.c and route any data stream from one /dev/tty node |
| to another /dev/tty node via kernel-space. This provides |
| a stable, reliable connection that will not break unless |
| the user-space application shuts down (plus avoids |
| kernel->user->kernel context switch overheads of routing |
| data). |
| |
| An example debugging usage for this driver system: |
| *Hook /dev/ttyPTI0 to syslogd. Opening this port will also start |
| a console device to further capture debugging messages to PTI. |
| *Hook /dev/ttyPTI1 to modem debugging data to write to PTI HW. |
| This is where n_tracerouter and n_tracesink are used. |
| *Hook /dev/pti to a user-level debugging application for writing |
| to PTI HW. |
| *Use mipi_* Kernel Driver API in other device drivers for |
| debugging to PTI by first requesting a PTI write address via |
| mipi_request_masterchannel(1). |
| |
| Below is example pseudo-code on how a 'privileged' application |
| can hook up n_tracerouter and n_tracesink to any tty on |
| a system. 'Privileged' means the application has enough |
| privileges to successfully manipulate the ldisc drivers |
| but is not just blindly executing as 'root'. Keep in mind |
| the use of ioctl(,TIOCSETD,) is not specific to the n_tracerouter |
| and n_tracesink line discpline drivers but is a generic |
| operation for a program to use a line discpline driver |
| on a tty port other than the default n_tty. |
| |
| /////////// To hook up n_tracerouter and n_tracesink ///////// |
| |
| // Note that n_tracerouter depends on n_tracesink. |
| #include <errno.h> |
| #define ONE_TTY "/dev/ttyOne" |
| #define TWO_TTY "/dev/ttyTwo" |
| |
| // needed global to hand onto ldisc connection |
| static int g_fd_source = -1; |
| static int g_fd_sink = -1; |
| |
| // these two vars used to grab LDISC values from loaded ldisc drivers |
| // in OS. Look at /proc/tty/ldiscs to get the right numbers from |
| // the ldiscs loaded in the system. |
| int source_ldisc_num, sink_ldisc_num = -1; |
| int retval; |
| |
| g_fd_source = open(ONE_TTY, O_RDWR); // must be R/W |
| g_fd_sink = open(TWO_TTY, O_RDWR); // must be R/W |
| |
| if (g_fd_source <= 0) || (g_fd_sink <= 0) { |
| // doubt you'll want to use these exact error lines of code |
| printf("Error on open(). errno: %d\n",errno); |
| return errno; |
| } |
| |
| retval = ioctl(g_fd_sink, TIOCSETD, &sink_ldisc_num); |
| if (retval < 0) { |
| printf("Error on ioctl(). errno: %d\n", errno); |
| return errno; |
| } |
| |
| retval = ioctl(g_fd_source, TIOCSETD, &source_ldisc_num); |
| if (retval < 0) { |
| printf("Error on ioctl(). errno: %d\n", errno); |
| return errno; |
| } |
| |
| /////////// To disconnect n_tracerouter and n_tracesink //////// |
| |
| // First make sure data through the ldiscs has stopped. |
| |
| // Second, disconnect ldiscs. This provides a |
| // little cleaner shutdown on tty stack. |
| sink_ldisc_num = 0; |
| source_ldisc_num = 0; |
| ioctl(g_fd_uart, TIOCSETD, &sink_ldisc_num); |
| ioctl(g_fd_gadget, TIOCSETD, &source_ldisc_num); |
| |
| // Three, program closes connection, and cleanup: |
| close(g_fd_uart); |
| close(g_fd_gadget); |
| g_fd_uart = g_fd_gadget = NULL; |