Kernel panics : trying to write / read on tiny tty driver -
i'm beginner linux programming , trying hands on device driver examples while practising. below code (a trimmed down version of tiny_tty.c
) loads using insmod , i'm able see in /proc/tty/drivers
, /proc/modules
, device nodes getting created under /dev. when try write device file echo "abcd" > /dev/ttyms0
(i hope fine) or read cat /dev/ttyms0
, kernel panics call trace on screen. i'm on kernel 3.5.0 under ubuntu. unfortunately i'm not able capture trace , when panics i'm left no option reboot using power button. believe issue timer here, trace shows line on top saying : "*kernel bug @ /build/buildd/linux-3.5.0/kernel/timer.c:901*
", call trace , followed "*eip @ add_timer+0x18/0x20*"
below full code. guidance appreciated in anticipation.
10may2013 : tried initializing timer in open function , time below call trace "kernel panic - not syncing : fatal exception in interrupt panic occurred, switching text console":
update_sd_lb_stats+0xcd/0x4b0 find_busiest_group+0x2e/0x420 enqueue_entity+0xcb/0x510 load_balance+0x7e/0x5e0 rebalance_domains+0xed/0x150 __do_softirq+0xdb/0x180 local_bh_enable_ip+0x90/0x90 <irq> copy_to_user0x41/0x60 sys_gettimeofday+0x2a/0x70 sysenter_do_call0x12/0x20 #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/kdev_t.h> #include <linux/wait.h> #include <linux/errno.h> #include <linux/slab.h> /* kmalloc() */ #include <linux/tty_driver.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/mutex.h> #include <linux/serial.h> #include <linux/sched.h> #include <asm/uaccess.h> #include <asm/termios.h> module_license("gpl"); #define ms_tty_major 250 //test value #define ms_tty_num_dev 2 #define delay_time hz * 2 /* 2 seconds per character */ #define tiny_data_character 't' static int major_num; //static int minor_num=0; //static int num_tty_dev=2; /* below structure wrapper device specific fields */ struct ms_tty_serial { struct tty_struct *tty; /* pointer tty device */ int open_count; /* number of times port has been opened */ struct semaphore sem; /* locks structure */ struct timer_list *timer; }; static struct ms_tty_serial *ms_tty_table[ms_tty_num_dev]; /* null */ static void ms_tty_timer(unsigned long timer_data) { struct ms_tty_serial *ms_ptr = (struct ms_tty_serial *)timer_data; struct tty_struct *tty; char data[1] = {tiny_data_character}; int data_size = 1; if (!ms_ptr) return; tty = ms_ptr->tty; tty->low_latency=1; /* send data tty layer users read. doesn't * push data through unless tty->low_latency set */ tty_buffer_request_room (tty, data_size); tty_insert_flip_string(tty, data, data_size); tty_flip_buffer_push(tty); /* resubmit timer again */ ms_ptr->timer->expires = jiffies + delay_time; add_timer(ms_ptr->timer); } //// define open function //// static int tty_ms_open(struct tty_struct *tty_this, struct file *file_this) { printk(kern_alert "tty_ms driver: opened ...\n"); struct ms_tty_serial *ms_ptr; struct timer_list *timer; int index; /* initialize pointer in case fails */ tty_this->driver_data = null; /* serial object associated tty pointer */ index = tty_this->index; ms_ptr = ms_tty_table[index]; if (ms_ptr == null) { /* first time accessing device, create */ ms_ptr = kmalloc(sizeof(*ms_ptr), gfp_kernel); if (!ms_ptr) return -enomem; // init_mutex(&ms_ptr->sem); /* didn't work kernel version 3.5.0 */ #ifndef init_mutex /* sema_init used kernel 2.6.37 , above */ sema_init(&ms_ptr->sem,1); #else init_mutex(&ms_ptr->sem); #endif ms_ptr->open_count = 0; ms_ptr->timer = null; ms_tty_table[index] = ms_ptr; } down(&ms_ptr->sem); /* save our structure within tty structure */ tty_this->driver_data = ms_ptr; ms_ptr->tty = tty_this; ms_ptr->filp = file_this; // tried ++ms_ptr->open_count; if (ms_ptr->open_count == 1) { /* first time port opened */ /* hardware initialization needed here */ /* create timer , submit */ if (!ms_ptr->timer) { timer = kmalloc(sizeof(*timer), gfp_kernel); if (!timer) { up(&ms_ptr->sem); return -enomem; } ms_ptr->timer = timer; } init_timer (ms_ptr->timer); // tried ms_ptr->timer->data = (unsigned long )ms_ptr; ms_ptr->timer->expires = jiffies + delay_time; ms_ptr->timer->function = ms_tty_timer; add_timer(ms_ptr->timer); } up(&ms_ptr->sem); return 0; } //// define close function //// static void do_close(struct ms_tty_serial *ms_ptr) { down(&ms_ptr->sem); if (!ms_ptr->open_count) { /* port never opened */ goto exit; } --ms_ptr->open_count; if (ms_ptr->open_count <= 0) { /* port being closed last user. */ /* hardware specific stuff here */ /* shut down our timer */ del_timer(ms_ptr->timer); } exit: up(&ms_ptr->sem); } static void tty_ms_close(struct tty_struct *tty_this, struct file *file_this) { printk(kern_alert "tty_ms driver: closing ...\n"); struct ms_tty_serial *ms_ptr = tty_this->driver_data; if (ms_ptr) do_close(ms_ptr); } //// define write function //// static int tty_ms_write(struct tty_struct *tty_this, const unsigned char *tty_buff, int count) { printk(kern_alert "tty_ms driver: writing ...\n"); struct ms_tty_serial *ms_ptr = tty_this->driver_data; int i; int retval = -einval; if (!ms_ptr) return -enodev; down(&ms_ptr->sem); if (!ms_ptr->open_count) /* port not opened */ { up(&ms_ptr->sem); return retval; } /* fake sending data out hardware port * writing kernel debug log. */ printk(kern_debug "%s - ", __function__); (i = 0; < count; ++i) printk("%02x ", tty_buff[i]); printk("\n"); return 0; } // define operations tty driver in tty_operations struct // static struct tty_operations tty_ms_ops = { .open = tty_ms_open, .close = tty_ms_close, .write = tty_ms_write, //.set_termios = tty_ms_set_termios, }; ///////////////////////////////////////// module initialization starts //////////////////////////////////// static struct tty_driver *tty_ms_driver; static int tty_ms_init(void) { // static int result; static int retval,iter; // allocate tty_driver struct driver // tty_ms_driver = alloc_tty_driver(ms_tty_num_dev); if (!tty_ms_driver) return -enomem; // error no memory , allocation failed else printk(kern_info "tty_driver structure allocated..!!"); //debug line // initialize allocated tty_driver structure // tty_ms_driver->magic=tty_driver_magic; tty_ms_driver->owner = this_module; tty_ms_driver->driver_name = "tty_ms"; tty_ms_driver->name = "ttyms"; tty_ms_driver->major = ms_tty_major, tty_ms_driver->type = tty_driver_type_serial, tty_ms_driver->subtype = serial_type_normal, tty_ms_driver->flags = tty_driver_real_raw | tty_driver_dynamic_dev, tty_ms_driver->init_termios = tty_std_termios; tty_ms_driver->init_termios.c_cflag = b9600 | cs8 | cread | hupcl | clocal; tty_set_operations(tty_ms_driver, &tty_ms_ops); printk(kern_info "allocated tty_driver structure -initialized."); //debug line //// register driver tty core //// retval = tty_register_driver(tty_ms_driver); if (retval) { printk(kern_err "failed register tty_ms driver\n tty registration returned %d", retval); put_tty_driver(tty_ms_driver); return retval; } //// register tty devices(nodes) tty core //// (iter = 0; iter < ms_tty_num_dev ; ++iter) tty_register_device(tty_ms_driver, iter, null); return 0; // initializations done } // init func ends ///////////////////////////////////////// module initialization ends //////////////////////////////////// ///////////////////////////////////////// module cleanup starts //////////////////////////////////// static void tty_ms_terminate(void) { static int iter; struct ms_tty_serial *tty_ser; printk(kern_alert "tty_ms driver: unloading...\n"); for(iter=1;iter<=ms_tty_num_dev;iter++) tty_unregister_device(tty_ms_driver,iter); //unregister devices, tty layer tty_unregister_driver(tty_ms_driver); // unregister driver tty layer /* shut down of timers , free memory */ (iter = 0; iter < ms_tty_num_dev; ++iter) { tty_ser = ms_tty_table[iter]; if (tty_ser) { /* close port */ while (tty_ser->open_count) do_close(tty_ser); /* shut down our timer , free memory */ del_timer(tty_ser->timer); kfree(tty_ser->timer); kfree(tty_ser); ms_tty_table[iter] = null; } } dev_t devno=mkdev(major_num,0); // wrap major/minor numbers in dev_t structure , pass deassigning. unregister_chrdev_region(devno,ms_tty_num_dev); } ///////////////////////////////////////// module cleanup ends //////////////////////////////////// module_init(tty_ms_init); module_exit(tty_ms_terminate);
Comments
Post a Comment