|  | 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; |