Results 1 to 5 of 5
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 ...
- 02-15-2008 #1Just Joined!
- Join Date
- May 2006
- Posts
- 4
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 2.6.23.8
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>
#endif
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,
};
MODULE_AUTHOR("Me");
MODULE_DESCRIPTION("TTY driver");
MODULE_LICENSE("GPL");
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)
{
}
module_init(my_init);
module_exit(my_exit);
---------------------------------------------------------------------
Crash output:
BUG: unable to handle kernel NULL pointer dereference at virtual address 00000000
printing eip:
00000000
*pde = 00000000
Oops: 0000 [#1]
PREEMPT
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 (2.6.23.8 #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/ld.so.nohwcap", 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/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", 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/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/libc.so.6", 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}
- 12-02-2008 #2Just Joined!
- Join Date
- Dec 2008
- Posts
- 3
Mike,
Did you figure this out? I'm running into the same problem.
Thanks,
Russell
- 12-02-2008 #3Just Joined!
- Join Date
- May 2006
- Posts
- 4
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.
- /\/\
- 12-02-2008 #4Just Joined!
- Join Date
- Dec 2008
- Posts
- 3
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!
Russell
- 12-03-2008 #5Just Joined!
- Join Date
- Dec 2008
- Posts
- 3
My last problem was an error in the LDD code. _write() was returning -EINVAL all the time.
Thanks again for all of your help.


Reply With Quote
