1*4882a593Smuzhiyun.. SPDX-License-Identifier: GPL-2.0 2*4882a593Smuzhiyun 3*4882a593Smuzhiyun============= 4*4882a593SmuzhiyunIntel MID PTI 5*4882a593Smuzhiyun============= 6*4882a593Smuzhiyun 7*4882a593SmuzhiyunThe Intel MID PTI project is HW implemented in Intel Atom 8*4882a593Smuzhiyunsystem-on-a-chip designs based on the Parallel Trace 9*4882a593SmuzhiyunInterface for MIPI P1149.7 cJTAG standard. The kernel solution 10*4882a593Smuzhiyunfor this platform involves the following files:: 11*4882a593Smuzhiyun 12*4882a593Smuzhiyun ./include/linux/pti.h 13*4882a593Smuzhiyun ./drivers/.../n_tracesink.h 14*4882a593Smuzhiyun ./drivers/.../n_tracerouter.c 15*4882a593Smuzhiyun ./drivers/.../n_tracesink.c 16*4882a593Smuzhiyun ./drivers/.../pti.c 17*4882a593Smuzhiyun 18*4882a593Smuzhiyunpti.c is the driver that enables various debugging features 19*4882a593Smuzhiyunpopular on platforms from certain mobile manufacturers. 20*4882a593Smuzhiyunn_tracerouter.c and n_tracesink.c allow extra system information to 21*4882a593Smuzhiyunbe collected and routed to the pti driver, such as trace 22*4882a593Smuzhiyundebugging data from a modem. Although n_tracerouter 23*4882a593Smuzhiyunand n_tracesink are a part of the complete PTI solution, 24*4882a593Smuzhiyunthese two line disciplines can work separately from 25*4882a593Smuzhiyunpti.c and route any data stream from one /dev/tty node 26*4882a593Smuzhiyunto another /dev/tty node via kernel-space. This provides 27*4882a593Smuzhiyuna stable, reliable connection that will not break unless 28*4882a593Smuzhiyunthe user-space application shuts down (plus avoids 29*4882a593Smuzhiyunkernel->user->kernel context switch overheads of routing 30*4882a593Smuzhiyundata). 31*4882a593Smuzhiyun 32*4882a593SmuzhiyunAn example debugging usage for this driver system: 33*4882a593Smuzhiyun 34*4882a593Smuzhiyun * Hook /dev/ttyPTI0 to syslogd. Opening this port will also start 35*4882a593Smuzhiyun a console device to further capture debugging messages to PTI. 36*4882a593Smuzhiyun * Hook /dev/ttyPTI1 to modem debugging data to write to PTI HW. 37*4882a593Smuzhiyun This is where n_tracerouter and n_tracesink are used. 38*4882a593Smuzhiyun * Hook /dev/pti to a user-level debugging application for writing 39*4882a593Smuzhiyun to PTI HW. 40*4882a593Smuzhiyun * `Use mipi_` Kernel Driver API in other device drivers for 41*4882a593Smuzhiyun debugging to PTI by first requesting a PTI write address via 42*4882a593Smuzhiyun mipi_request_masterchannel(1). 43*4882a593Smuzhiyun 44*4882a593SmuzhiyunBelow is example pseudo-code on how a 'privileged' application 45*4882a593Smuzhiyuncan hook up n_tracerouter and n_tracesink to any tty on 46*4882a593Smuzhiyuna system. 'Privileged' means the application has enough 47*4882a593Smuzhiyunprivileges to successfully manipulate the ldisc drivers 48*4882a593Smuzhiyunbut is not just blindly executing as 'root'. Keep in mind 49*4882a593Smuzhiyunthe use of ioctl(,TIOCSETD,) is not specific to the n_tracerouter 50*4882a593Smuzhiyunand n_tracesink line discpline drivers but is a generic 51*4882a593Smuzhiyunoperation for a program to use a line discpline driver 52*4882a593Smuzhiyunon a tty port other than the default n_tty: 53*4882a593Smuzhiyun 54*4882a593Smuzhiyun.. code-block:: c 55*4882a593Smuzhiyun 56*4882a593Smuzhiyun /////////// To hook up n_tracerouter and n_tracesink ///////// 57*4882a593Smuzhiyun 58*4882a593Smuzhiyun // Note that n_tracerouter depends on n_tracesink. 59*4882a593Smuzhiyun #include <errno.h> 60*4882a593Smuzhiyun #define ONE_TTY "/dev/ttyOne" 61*4882a593Smuzhiyun #define TWO_TTY "/dev/ttyTwo" 62*4882a593Smuzhiyun 63*4882a593Smuzhiyun // needed global to hand onto ldisc connection 64*4882a593Smuzhiyun static int g_fd_source = -1; 65*4882a593Smuzhiyun static int g_fd_sink = -1; 66*4882a593Smuzhiyun 67*4882a593Smuzhiyun // these two vars used to grab LDISC values from loaded ldisc drivers 68*4882a593Smuzhiyun // in OS. Look at /proc/tty/ldiscs to get the right numbers from 69*4882a593Smuzhiyun // the ldiscs loaded in the system. 70*4882a593Smuzhiyun int source_ldisc_num, sink_ldisc_num = -1; 71*4882a593Smuzhiyun int retval; 72*4882a593Smuzhiyun 73*4882a593Smuzhiyun g_fd_source = open(ONE_TTY, O_RDWR); // must be R/W 74*4882a593Smuzhiyun g_fd_sink = open(TWO_TTY, O_RDWR); // must be R/W 75*4882a593Smuzhiyun 76*4882a593Smuzhiyun if (g_fd_source <= 0) || (g_fd_sink <= 0) { 77*4882a593Smuzhiyun // doubt you'll want to use these exact error lines of code 78*4882a593Smuzhiyun printf("Error on open(). errno: %d\n",errno); 79*4882a593Smuzhiyun return errno; 80*4882a593Smuzhiyun } 81*4882a593Smuzhiyun 82*4882a593Smuzhiyun retval = ioctl(g_fd_sink, TIOCSETD, &sink_ldisc_num); 83*4882a593Smuzhiyun if (retval < 0) { 84*4882a593Smuzhiyun printf("Error on ioctl(). errno: %d\n", errno); 85*4882a593Smuzhiyun return errno; 86*4882a593Smuzhiyun } 87*4882a593Smuzhiyun 88*4882a593Smuzhiyun retval = ioctl(g_fd_source, TIOCSETD, &source_ldisc_num); 89*4882a593Smuzhiyun if (retval < 0) { 90*4882a593Smuzhiyun printf("Error on ioctl(). errno: %d\n", errno); 91*4882a593Smuzhiyun return errno; 92*4882a593Smuzhiyun } 93*4882a593Smuzhiyun 94*4882a593Smuzhiyun /////////// To disconnect n_tracerouter and n_tracesink //////// 95*4882a593Smuzhiyun 96*4882a593Smuzhiyun // First make sure data through the ldiscs has stopped. 97*4882a593Smuzhiyun 98*4882a593Smuzhiyun // Second, disconnect ldiscs. This provides a 99*4882a593Smuzhiyun // little cleaner shutdown on tty stack. 100*4882a593Smuzhiyun sink_ldisc_num = 0; 101*4882a593Smuzhiyun source_ldisc_num = 0; 102*4882a593Smuzhiyun ioctl(g_fd_uart, TIOCSETD, &sink_ldisc_num); 103*4882a593Smuzhiyun ioctl(g_fd_gadget, TIOCSETD, &source_ldisc_num); 104*4882a593Smuzhiyun 105*4882a593Smuzhiyun // Three, program closes connection, and cleanup: 106*4882a593Smuzhiyun close(g_fd_uart); 107*4882a593Smuzhiyun close(g_fd_gadget); 108*4882a593Smuzhiyun g_fd_uart = g_fd_gadget = NULL; 109