/* FILE: serial_test.c -- A simple kernel module to demonstrate that * something fishy is going on with my Venus chipset. * AUTHOR: W. Michael Petullo * DATE: 3 Mar 2001 */ /* Before using this test module, please correctly define IOPORT below. * This value should be the modem's first I/O port base address, which can be * discovered using `lspci -vvv`. */ /* Compile with `gcc -c -O2 serial_test.c` and use with version 2.4.x * of the Linux kernel. */ /* Test one generally passes -- unless run right after a cold boot and before * anything else touches the chipset's IER. Test two fails more than 50% * of the time on my machine. Test three passes 99.99% of the time, though * in practice the kludge fails more often in the actual serial driver. */ /* Load the module and watch your logs -- or wherever your kernel messages * are sent! */ #define MODULE #define __KERNEL__ #define IOPORT 0xcc00 #define NUM_TESTS 10000 #include #include #include #include /* ============================ print_results () =========================== */ void print_results(char *header, int num_tests, int failure_count) { printk("\n%s\n", header); printk("%d iteration(s) were run, %d failed.\n", num_tests, failure_count); printk("This is a failure rate of %d percent.\n\n", (int) ((float) failure_count / num_tests * 100)); } /* ============================ test_one () ================================ */ void test_one (void) { unsigned char scratch; outb(0, IOPORT + 1); outb(0x0F, IOPORT + 1); scratch = inb(IOPORT + 1); udelay(10); print_results("Test one: simple test (I usually fail after a cold start):", 1, scratch == 0x0F); } /* ============================ test_two () ================================ */ void test_two (void) /* Simulation of serial driver in the Linux kernel. */ { int i, failure_count = 0; unsigned char scratch, scratch2, scratch3; for (i = 0; i < NUM_TESTS; i++) { scratch = inb(IOPORT + 1); outb(0, IOPORT + 1); outb(0xff, 0x080); scratch2 = inb(IOPORT + 1); outb(0x0F, IOPORT + 1); outb(0, 0x080); scratch3 = inb(IOPORT + 1); outb(scratch, IOPORT + 1); if (scratch2 || scratch3 != 0x0F) { failure_count++; } } print_results("Test two: straight serial driver fragment:", NUM_TESTS, failure_count); } /* ============================ test_three () ============================== */ void test_three (void) /* Simulation of a kludged serial driver in the Linux kernel. */ { int i, failure_count = 0; unsigned char scratch, scratch2, scratch3; for (i = 0; i < NUM_TESTS; i++) { scratch = inb(IOPORT + 1); outb(0, IOPORT + 1); outb(0xff, 0x080); scratch2 = inb(IOPORT + 1); outb(0x0F, IOPORT + 1); outb(0, 0x080); scratch3 = inb(IOPORT + 1); outb(scratch, IOPORT + 1); udelay(10); /* This is the kludge. */ if (scratch2 || scratch3 != 0x0F) { failure_count++; } } print_results("Test three: kludged serial driver fragment:", NUM_TESTS, failure_count); } /* ============================ init_module () ============================= */ int init_module(void) { test_one (); test_two (); test_three (); return 0; }