Transplantation of Linux-2.6.32.2 Kernel on mini2440 (18th) --- converting uart2 into a common serial port driver
Port Environment (Bold font in redIs the modified content,Blue bold ChineseFor special attention)
1. host environment: centos 5.5 and 1 GB memory in vmare.
2. Integrated Development Environment: Elipse ide
3. compiling environment: Arm-Linux-GCC v4.4.3 and arm-None-Linux-gnueabi-GCC v4.5.1.
4. Development Board: mini2440, 2 m nor flash, 128 m nand Flash.
5, U-boot version: u-boot-2009.08
6, Linux: linux-2.6.32.2
7. References:
Complete embedded Linux application development manual, edited by Wei Dongshan.
Mini2440 Linux porting Development Practice Guide
[1] hardware principles
S3C2440 chip has three serial ports: uart0, 1, 2, we download the Linux-2.6.32.2 has a sound uart0, 1 driver, but the uart2 is used for infrared communication (IRDA ), therefore, we need to slightly adjust the uart2 driver for use as a common serial port.
First, let's take a look at the descriptions of some registers of the S3C2440 serial port, such:
[2] modify the platform configuration code
Next we modify the uart2 configuration in the kernel, open the ARCH/ARM/mach-s3c2440/mach-mini2440.c file, locate near line 112, find mini2440_uartcfgs [], the following red code is modified:
Static struct s3c2410_uartcfg mini2440_uartcfgs [] _ initdata = {
[0] = {
. Hwport = 0,
. Flags = 0,
. Ucon = 0x3c5,
. Ulcon = 0x03,
. Ufcon = 0x51,
},
[1] = {
. Hwport = 1,
. Flags = 0,
. Ucon = 0x3c5,
. Ulcon = 0x03,
. Ufcon = 0x51,
},
/* IR port */
[2] = {
. Hwport = 2,
. Flags = 0,
. Ucon = 0x3c5,
.Ulcon = 0x03,// 0x43,/* Change uart2 to a common serial port */
. Ufcon = 0x51,
}
};
Modify the port initialization used by the serial port, open the linux-2.6.32.2/Drivers/serial/Samsung. C, locate to 55 lines, first add the required header file, as shown below:
# Include <Mach/hardware. h>
# Include <Mach/map. h>
# Include <plat/regs-serial.h>
// Header file to be added
# Include <Linux/gpio. h>
# Include <Mach/regs-gpio.h>
# Include "Samsung. H"
/* UART name and device Definitions */
Then, locate row 435 and add the following red code:
Dbg ("s3c24xx_serial_startup OK \ n ");
/* The port reset code shoshould have done the correct
* Register setup for the port controls */
// Initialize the port corresponding to serial port 2
If (Port-> line = 2)
{
S3c2410_gpio_cfgpin (s3c2410_gph (6), s3c2410_gph6_txd2 );
S3c2410_gpio_pullup (s3c2410_gph (6), 1 );
S3c2410_gpio_cfgpin (s3c2410_gph (7), s3c2410_gph7_rxd2 );
S3c2410_gpio_pullup (s3c2410_gph (7), 1 );
}
Return ret;
Err:
S3c24xx_serial_shutdown (port );
Return ret;
}
In this way, the uart2 modification is completed.
[3] test the serial port
Run make uimage in the root directory of the kernel source code to copy the generated uimage to/nfsboot/kernel, and then restart the Development Board.
To test the driver, we also need to compile a simple test program. the source code of the test program has been provided on the CDs provided by the friendly official website, it is located in the \ Linux sample code \ examples \ comtest directory, with the file name: comtest. c. Copy it to the host/root/Linux-test/codetest directory. The following code is used:
# Include <stdio. h>
# Include <stdlib. h>
# Include <termio. h>
# Include <unistd. h>
# Include <fcntl. h>
# Include <getopt. h>
# Include <time. h>
# Include <errno. h>
# Include <string. h>
Static void error (const char * MSG)
{
Fprintf (stderr, "% s \ n", MSG );
Fprintf (stderr, "strerror () is % s \ n", strerror (errno ));
Exit (1 );
}
Static void warning (const char * MSG)
{
Fprintf (stderr, "Warning: % s \ n", MSG );
}
Static int serialspeed (const char * speedstring)
{
Int speednumber = atoi (speedstring );
# Define testspeed (speed) if (speednumber = speed) return B # speed
Testspeed( 1200 );
Testspeed( 2400 );
Testspeed( 4800 );
Testspeed( 9600 );
Testspeed( 19200 );
Testspeed( 38400 );
Testspeed( 57600 );
Testspeed( 115200 );
Testspeed( 230400 );
Error ("bad speed ");
Return-1;
}
Static void printusage (void)
{
Fprintf (stderr, "comtest-interactive program of COMM port \ n ");
Fprintf (stderr, "press [ESC] 3 times to quit \ n ");
Fprintf (stderr, "Usage: comtest [-D device] [-T tty] [-s speed] [-7] [-C] [-x] [-O] [-H] \ n ");
Fprintf (stderr, "-7 7 bit \ n ");
Fprintf (stderr, "-x hex mode \ n ");
Fprintf (stderr, "-O output to stdout too \ n ");
Fprintf (stderr, "-C stdout output use color \ n ");
Fprintf (stderr, "-H print this help \ n ");
Exit (-1 );
}
Static inline void waitfdwriteable (int fd)
{
Fd_set writesetfd;
Fd_zero (& writesetfd );
Fd_set (FD, & writesetfd );
If (select (FD + 1, null, & writesetfd, null, null) <0 ){
Error (strerror (errno ));
}
}
Int main (INT argc, char ** argv)
{
Int commfd, ttyfd;
Struct termios ttyattr;
Struct termios backupttyattr;
Int devicespeed = b115200;
Int ttyspeed = b115200;
Int bytebits = cs8;
Const char * devicename = "/dev/ttysac1 ";
Const char * ttyname = "/dev/tty ";
Int outputhex = 0;
Int outputtostdout = 0;
Int usecolor = 0;
Opterr = 0;
For (;;)
{
Int c = getopt (argc, argv, "d: S: T: 7 xoch ");
If (C =-1)
Break;
Switch (c)
{
Case 'D ':
Devicename = optarg;
Break;
Case 'T ':
Ttyname = optarg;
Break;
Case's ':
If (optarg [0] = 'D ')
{
Devicespeed = serialspeed (optarg + 1 );
}
Else if (optarg [0] = 'T ')
{
Ttyspeed = serialspeed (optarg + 1 );
}
Else
Ttyspeed = devicespeed = serialspeed (optarg );
Break;
Case 'O ':
Outputtostdout = 1;
Break;
Case '7 ':
Bytebits = cs7;
Break;
Case 'X ':
Outputhex = 1;
Break;
Case 'C ':
Usecolor = 1;
Break;
Case '? ':
Case 'H ':
Default:
Printusage ();
}
}
If (optind! = Argc)
Printusage ();
Commfd = open (devicename, o_rdwr, 0 );
If (commfd <0)
Error ("unable to open device ");
If (fcntl (commfd, f_setfl, o_nonblock) <0)
Error ("Unable set to nonblock mode ");
Memset (& ttyattr, 0, sizeof (struct termios ));
Ttyattr. c_iflag = ignpar;
Ttyattr. c_cflag = devicespeed | hupcl | bytebits | cread | clocal;
Ttyattr. c_cc [Vmin] = 1;
If (tcsetattr (commfd, tcsanow, & ttyattr) <0)
Warning ("unable to set COMM port ");
Ttyfd = open (ttyname, o_rdwr | o_ndelay, 0 );
If (ttyfd <0)
Error ("unable to open tty ");
Ttyattr. c_cflag = ttyspeed | hupcl | bytebits | cread | clocal;
If (tcgetattr (ttyfd, & backupttyattr) <0)
Error ("unable to get tty ");
If (tcsetattr (ttyfd, tcsanow, & ttyattr) <0)
Error ("unable to set tty ");
For (;;)
{
Unsigned char = 0;
Fd_set readsetfd;
Void outputstdchar (File * file)
{
Char buffer [10];
Int Len = sprintf (buffer, outputhex? "%. 2x": "% C", char );
Fwrite (buffer, 1, Len, file );
}
Fd_zero (& readsetfd );
Fd_set (commfd, & readsetfd );
Fd_set (ttyfd, & readsetfd );
# Define max (x, y) (x)> = (y ))? (X): (y ))
If (select (max (commfd, ttyfd) + 1, & readsetfd, null) <0)
{
Error (strerror (errno ));
}
# UNDEF Max
If (fd_isset (commfd, & readsetfd ))
{
While (read (commfd, & char, 1) = 1)
{
Waitfdwriteable (ttyfd );
If (write (ttyfd, & char, 1) <0)
{
Error (strerror (errno ));
}
If (outputtostdout)
{
If (usecolor)
Fwrite ("\ x1b [01; 34 m", 1, 8, stdout );
Outputstdchar (stdout );
If (usecolor)
Fwrite ("\ x1b [00 m", 1, 8, stdout );
Fflush (stdout );
}
}
}
If (fd_isset (ttyfd, & readsetfd ))
{
While (read (ttyfd, & char, 1) = 1)
{
Static int esckeycount = 0;
Waitfdwriteable (commfd );
If (write (commfd, & char, 1) <0)
{
Error (strerror (errno ));
}
If (outputtostdout)
{
If (usecolor)
Fwrite ("\ x1b [01; 31 m", 1, 8, stderr );
Outputstdchar (stderr );
If (usecolor)
Fwrite ("\ x1b [00 m", 1, 8, stderr );
Fflush (stderr );
}
If (char = '\ x1b ')
{
Esckeycount ++;
If (esckeycount> = 3)
Goto exitlabel;
} Else
Esckeycount = 0;
}
}
}
Exitlabel:
If (tcsetattr (ttyfd, tcsanow, & backupttyattr) <0)
Error ("unable to set tty ");
Return 0;
}
Note the following before testing on the Development Board:
(1) the device under the kernel/dev/corresponding to the serial port is executed on the serial port terminal:
[Root @ mini2440/] # ls/dev
S3c2410_serial0Ttyt3
S3c2410_serial1Ttyt4
S3c2410_serial
You can see that the devices corresponding to uart0, uart1, and uart2 areS3c2410_serial0, s3c2410_seria10, and s3c2410_serial.
(2) uart0, The mini2440 Development Board, is used as the communication interface of the serial port terminal, which has been obtained from the RS232 interface, but uart1 and uart2 are not obtained from the RS232 port, instead, the corresponding COM1 and con3 pins are obtained respectively. During the test, the RS232 conversion circuit is required.
Therefore, you need to modify the above Code to enable the corresponding device. Modify as follows:
Int devicespeed = b115200;
Int ttyspeed = b115200;
Int bytebits = cs8;
Const char * devicename = "/dev/s3c2410_serial1 ";// Mini2440's uart1 <---> s3c2410_serial1
Const char * ttyname = "/dev/tty ";
Enter the codetest directory in the terminal, and then execute:
[Root @ localhost codetest] # ls
Adc_test backlight_test buttons_test.c led pwm_test.c
Adc_test.c backlight_test.cComtest. cLed. c tstest
Adc_test.c ~ Buttons_test I2C pwm_test tstest. c
[Root @ localhost codetest] # arm-Linux-gcc-O comtest. c
[Root @ localhost codetest] # cp comtest/nfsboot/nfs
Copy the generated executable target file pwm_test to the nfsboot/nfs shared with the Development Board, after the COM1 port is connected to the host COM port, you can enter the/mnt/NFS directory on the command line terminal of the Development Board and execute :. /comtest.
[Root @ mini2440 NFS] # ls
Adc_test buttons_test led tstest
Backlight_testComtestPwm_test yesterday.pdf
Bigworld.wav I2C test1.wav
[Root @ mini2440 NFS] #./comtest
The study and research on Kernel transplantation is coming to an end, and the actual test will be conducted after the connected hardware is ready.