Find the answer to your Linux question:
Results 1 to 5 of 5
Enjoy an ad free experience by logging in. Not a member yet? Register.
  1. #1

    TTY Driver "driving" me crazy.

    Ok. So I have the task of writing a driver that is a tty on the top and interfaces to our proprietary system on the bottom. No problem. Simple. I'm thinking. So, I wrote it as a module.

    When I run it with minicom it was crashing the app. It looked like it was doing some writes (minicom modem initialization) and then doing a select() and crashing.

    Then I ran in with minicom --noinit. I thought the write()s were doing something bad maybe. But no. It still crashes. Then I wrote a small app to open it and do a select(), which is essentially what minicom --noinit does.

    My little app worked, but I noticed that minicom includes fd 0 1 and 2 (stdin, stdout, stderr) in the select() list. And thats the magic that makes the select() crash. I'm perplexed.

    I have no idea what is wrong. I stripped down the driver to the ridiculously small module that I have shown below and I can still make it crash by doing an open() and do a select() on it along with fd 0 1 and 2. I am running kernel

    I have also included the output of the crash.

    Can anybody help. Maybe shed some light on this. Thanks so much for the help.

    - Mike

    #include <linux/init.h>
    #include <linux/errno.h>
    #include <linux/sched.h>
    #include <linux/tty.h>
    #include <linux/tty_flip.h>
    #include <linux/major.h>
    #include <linux/fcntl.h>
    #include <linux/mm.h>
    #include <linux/slab.h>
    #include <linux/capability.h>
    #include <linux/console.h>
    #include <linux/module.h>
    #include <linux/serial.h>
    #include <linux/serialP.h>
    #include <linux/sysrq.h>
    #include <asm/uaccess.h>
    #include <asm/io.h>

    #ifdef CONFIG_KDB
    # include <linux/kdb.h>

    static struct tty_driver *my_tty_driver;

    static int my_open(struct tty_struct *tty, struct file * filp)
    tty->driver_data = NULL;
    return 0;

    static void my_close(struct tty_struct *tty, struct file * filp)

    static int my_write(struct tty_struct * tty, const unsigned char *buf, int count)
    return count;

    static int my_write_room(struct tty_struct *tty)
    return 1000;

    static const struct tty_operations my_ops = {
    .open = my_open,
    .close = my_close,
    .write = my_write,
    .write_room = my_write_room,


    static int __init my_init (void)
    int i;

    my_tty_driver = alloc_tty_driver(4);

    if (!my_tty_driver)
    return -ENOMEM;

    /* Initialize the tty_driver structure */

    my_tty_driver->owner = THIS_MODULE;
    my_tty_driver->driver_name = "/dev/my";
    my_tty_driver->name = "my";
    my_tty_driver->major = 99;
    my_tty_driver->minor_start = 0;
    my_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
    my_tty_driver->subtype = SERIAL_TYPE_NORMAL;
    my_tty_driver->init_termios = tty_std_termios;
    my_tty_driver->init_termios.c_cflag =
    B9600 | CS8 | CREAD | HUPCL | CLOCAL;
    my_tty_driver->flags = TTY_DRIVER_REAL_RAW;

    tty_set_operations(my_tty_driver, &my_ops);

    if((i = tty_register_driver(my_tty_driver)))
    printk(KERN_INFO "tty_register_driver returned 0x%x\n", i);

    return 0;

    static void __exit my_exit(void)


    Crash output:
    BUG: unable to handle kernel NULL pointer dereference at virtual address 00000000
    printing eip:
    *pde = 00000000
    Oops: 0000 [#1]
    Modules linked in: cygnus_lic cygnus_sys cygnus_local cygnus_pcm cygnus_serial_dma cygnus_reg cygnus_dma
    CPU: 0
    EIP: 0060:[<00000000>] Not tainted VLI
    EFLAGS: 00010246 ( #7)
    EIP is at _stext+0x3fefff50/0x19
    eax: cdbf1400 ebx: cdbf1400 ecx: 00000000 edx: ce43b600
    esi: 00000000 edi: cdb28440 ebp: cd4d3b60 esp: cd4d3b4c
    ds: 007b es: 007b fs: 0000 gs: 0033 ss: 0068
    Process select (pid: 2256, ti=cd4d2000 task=c1242570 task.ti=cd4d2000)
    Stack: c021c66c 0021846f cdbf1400 c021c579 cdb28440 cd4d3b80 c021905d 00000000
    cdbf140c 00000000 00000100 cdb28440 00000003 cd4d3e2c c01597fc cd4d3f9c
    cd4d3f48 00000000 cd4d3e54 cd4d3e58 cd4d3e5c cd4d3e48 cd4d3e4c cd4d3e50
    Call Trace:
    [<c01034fa>] show_trace_log_lvl+0x1a/0x2f
    [<c01035aa>] show_stack_log_lvl+0x9b/0xa3
    [<c0103799>] show_registers+0x1e7/0x328
    [<c01039d7>] die+0xfd/0x1e0
    [<c011022e>] do_page_fault+0x495/0x563
    [<c03417d2>] error_code+0x6a/0x70
    [<c021905d>] tty_poll+0x4a/0x62
    [<c01597fc>] do_select+0x2d5/0x4c3
    [<c0159c80>] core_sys_select+0x296/0x2b3
    [<c0159fc6>] sys_select+0x95/0x165
    [<c0102652>] syscall_call+0x7/0xb
    Code: Bad EIP value.
    EIP: [<00000000>] _stext+0x3fefff50/0x19 SS:ESP 0068:cd4d3b4c

    Strace output of my little select() app:

    execve("./select", ["./select"], [/* 24 vars */]) = 0
    brk(0) = 0x804a000
    access("/etc/", F_OK) = -1 ENOENT (No such file or directory)
    mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f82000
    access("/etc/", R_OK) = -1 ENOENT (No such file or directory)
    open("/etc/", O_RDONLY) = 3
    fstat64(3, {st_mode=S_IFREG|0644, st_size=9582, ...}) = 0
    mmap2(NULL, 9582, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7f7f000
    close(3) = 0
    access("/etc/", F_OK) = -1 ENOENT (No such file or directory)
    open("/lib/", O_RDONLY) = 3
    read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\0 `\1\000"..., 512) = 512
    fstat64(3, {st_mode=S_IFREG|0755, st_size=1216808, ...}) = 0
    mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f7e000
    mmap2(NULL, 1226148, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7e52000
    mmap2(0xb7f78000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x125) = 0xb7f78000
    mmap2(0xb7f7b000, 9636, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7f7b000
    close(3) = 0
    mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7e51000
    set_thread_area({entry_number:-1 -> 6, base_addr:0xb7e516c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
    mprotect(0xb7f78000, 4096, PROT_READ) = 0
    munmap(0xb7f7f000, 9582) = 0
    open("/dev/my", O_RDWR) = 3
    select(4, [0 1 2 3], NULL, NULL, {5, 0}

  2. #2
    Did you figure this out? I'm running into the same problem.


  3. #3
    Hi Russell,
    Yes, I've had a few problems with it, but I think this one was due to the fact that, apparently, a tty driver needs a .chars_in_buffer tty_operation function. I think that was the problem with this. If not, it may be just good to know that you need one. Good Luck. Let me (us) know how you make out.
    - /\/\

  4. $spacer_open
  5. #4
    Thanks Q, this did fix the kernel crash. Now I've moved along to another issue.

    I was close to adding this, but figured it wasn't related because it is supposedly used to determine if there are chars in the tx buffer. Not sure how they are related.

    Thanks for your help!


  6. #5
    My last problem was an error in the LDD code. _write() was returning -EINVAL all the time.

    Thanks again for all of your help.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts