<HTML ><HEAD ><TITLE >Replacing Printks</TITLE ><META NAME="GENERATOR" CONTENT="Modular DocBook HTML Stylesheet Version 1.7"><LINK REL="HOME" TITLE="The Linux Kernel Module Programming Guide" HREF="book1.htm"><LINK REL="PREVIOUS" TITLE="Blocking Processes" HREF="c1043.htm"><LINK REL="NEXT" TITLE="Flashing keyboard LEDs" HREF="x1181.htm"></HEAD ><BODY CLASS="CHAPTER" BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#840084" ALINK="#0000FF" ><DIV CLASS="NAVHEADER" ><TABLE SUMMARY="Header navigation table" WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0" ><TR ><TH COLSPAN="3" ALIGN="center" >The Linux Kernel Module Programming Guide</TH ></TR ><TR ><TD WIDTH="10%" ALIGN="left" VALIGN="bottom" ><A HREF="c1043.htm" ACCESSKEY="P" >Prev</A ></TD ><TD WIDTH="80%" ALIGN="center" VALIGN="bottom" ></TD ><TD WIDTH="10%" ALIGN="right" VALIGN="bottom" ><A HREF="x1181.htm" ACCESSKEY="N" >Next</A ></TD ></TR ></TABLE ><HR ALIGN="LEFT" WIDTH="100%"></DIV ><DIV CLASS="CHAPTER" ><H1 ><A NAME="AEN1146" ></A >Chapter 10. Replacing Printks</H1 ><DIV CLASS="TOC" ><DL ><DT ><B >Table of Contents</B ></DT ><DT ><A HREF="c1146.htm#AEN1148" >Replacing <TT CLASS="FUNCTION" >printk</TT ></A ></DT ><DT ><A HREF="x1181.htm" >Flashing keyboard LEDs</A ></DT ></DL ></DIV ><DIV CLASS="SECT1" ><H1 CLASS="SECT1" ><A NAME="AEN1148" ></A >Replacing <TT CLASS="FUNCTION" >printk</TT ></H1 ><A NAME="AEN1151" ></A ><P >In <A HREF="x49.htm#USINGX" >the Section called <I >Using X</I > in Chapter 1</A >, I said that X and kernel module programming don't mix. That's true for developing kernel modules, but in actual use, you want to be able to send messages to whichever tty<A NAME="AEN1156" HREF="#FTN.AEN1156" ><SPAN CLASS="footnote" >[1]</SPAN ></A > the command to load the module came from.</P ><A NAME="AEN1160" ></A ><A NAME="AEN1162" ></A ><A NAME="AEN1165" ></A ><A NAME="AEN1167" ></A ><P >The way this is done is by using <TT CLASS="VARNAME" >current</TT >, a pointer to the currently running task, to get the current task's <SPAN CLASS="STRUCTNAME" >tty</SPAN > structure. Then, we look inside that <SPAN CLASS="STRUCTNAME" >tty</SPAN > structure to find a pointer to a string write function, which we use to write a string to the tty.</P ><A NAME="AEN1174" ></A ><DIV CLASS="EXAMPLE" ><A NAME="AEN1177" ></A ><P ><B >Example 10-1. print_string.c</B ></P ><PRE CLASS="PROGRAMLISTING" >/* * print_string.c - Send output to the tty we're running on, regardless if it's * through X11, telnet, etc. We do this by printing the string to the tty * associated with the current task. */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/sched.h> /* For current */ #include <linux/tty.h> /* For the tty declarations */ #include <linux/version.h> /* For LINUX_VERSION_CODE */ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Peter Jay Salzman"); static void print_string(char *str) { struct tty_struct *my_tty; /* * tty struct went into signal struct in 2.6.6 */ #if ( LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,5) ) /* * The tty for the current task */ my_tty = current->tty; #else /* * The tty for the current task, for 2.6.6+ kernels */ my_tty = current->signal->tty; #endif /* * If my_tty is NULL, the current task has no tty you can print to * (ie, if it's a daemon). If so, there's nothing we can do. */ if (my_tty != NULL) { /* * my_tty->driver is a struct which holds the tty's functions, * one of which (write) is used to write strings to the tty. * It can be used to take a string either from the user's or * kernel's memory segment. * * The function's 1st parameter is the tty to write to, * because the same function would normally be used for all * tty's of a certain type. The 2nd parameter controls whether * the function receives a string from kernel memory (false, 0) * or from user memory (true, non zero). The 3rd parameter is * a pointer to a string. The 4th parameter is the length of * the string. */ ((my_tty->driver)->write) (my_tty, /* The tty itself */ 0, /* Don't take the string from user space */ str, /* String */ strlen(str)); /* Length */ /* * ttys were originally hardware devices, which (usually) * strictly followed the ASCII standard. In ASCII, to move to * a new line you need two characters, a carriage return and a * line feed. On Unix, the ASCII line feed is used for both * purposes - so we can't just use \n, because it wouldn't have * a carriage return and the next line will start at the * column right after the line feed. * * This is why text files are different between Unix and * MS Windows. In CP/M and derivatives, like MS-DOS and * MS Windows, the ASCII standard was strictly adhered to, * and therefore a newline requirs both a LF and a CR. */ ((my_tty->driver)->write) (my_tty, 0, "\015\012", 2); } } static int __init print_string_init(void) { print_string("The module has been inserted. Hello world!"); return 0; } static void __exit print_string_exit(void) { print_string("The module has been removed. Farewell world!"); } module_init(print_string_init); module_exit(print_string_exit);</PRE ></DIV ></DIV ></DIV ><H3 CLASS="FOOTNOTES" >Notes</H3 ><TABLE BORDER="0" CLASS="FOOTNOTES" WIDTH="100%" ><TR ><TD ALIGN="LEFT" VALIGN="TOP" WIDTH="5%" ><A NAME="FTN.AEN1156" HREF="c1146.htm#AEN1156" ><SPAN CLASS="footnote" >[1]</SPAN ></A ></TD ><TD ALIGN="LEFT" VALIGN="TOP" WIDTH="95%" ><P ><SPAN CLASS="emphasis" ><I CLASS="EMPHASIS" >T</I ></SPAN >ele<SPAN CLASS="emphasis" ><I CLASS="EMPHASIS" >ty</I ></SPAN >pe, originally a combination keyboard-printer used to communicate with a Unix system, and today an abstraction for the text stream used for a Unix program, whether it's a physical terminal, an xterm on an X display, a network connection used with telnet, etc.</P ></TD ></TR ></TABLE ><DIV CLASS="NAVFOOTER" ><HR ALIGN="LEFT" WIDTH="100%"><TABLE SUMMARY="Footer navigation table" WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0" ><TR ><TD WIDTH="33%" ALIGN="left" VALIGN="top" ><A HREF="c1043.htm" ACCESSKEY="P" >Prev</A ></TD ><TD WIDTH="34%" ALIGN="center" VALIGN="top" ><A HREF="book1.htm" ACCESSKEY="H" >Home</A ></TD ><TD WIDTH="33%" ALIGN="right" VALIGN="top" ><A HREF="x1181.htm" ACCESSKEY="N" >Next</A ></TD ></TR ><TR ><TD WIDTH="33%" ALIGN="left" VALIGN="top" >Blocking Processes</TD ><TD WIDTH="34%" ALIGN="center" VALIGN="top" > </TD ><TD WIDTH="33%" ALIGN="right" VALIGN="top" >Flashing keyboard LEDs</TD ></TR ></TABLE ></DIV ></BODY ></HTML >