I have a linux kernel driver for serial device, which uses line discipline and char device. Driver works with all old kernels, starting from 3.8 this driver still works, but when I unload it and load again to the memory (modprobe -r bpsctl_mod, after modprobe bpsctl_mod), it crashes the kernel. It can't unregister line discipline, because this line discipline is busy. I use system device, i.e., ttyS0. Here is problematic code: static struct file* bps_file_open(const char* path, int flags, int rights) { struct file* filp = NULL; mm_segment_t oldfs; oldfs = get_fs(); set_fs(get_ds()); filp = filp_open(path, flags, rights); set_fs(oldfs); if (IS_ERR(filp)) return NULL; return filp; } int register_ldisc(void) { int status; // Fill in our line protocol discipline, and register it extbp_drv.ebtty_ldisc.magic = TTY_LDISC_MAGIC; extbp_drv.ebtty_ldisc.name = BP_LDISC_NAME; extbp_drv.ebtty_ldisc.flags = 0; extbp_drv.ebtty_ldisc.open = ebtty_open; extbp_drv.ebtty_ldisc.close = ebtty_close; extbp_drv.ebtty_ldisc.read = NULL; extbp_drv.ebtty_ldisc.write = NULL; extbp_drv.ebtty_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *, unsigned int, unsigned long)) ebtty_ioctl; extbp_drv.ebtty_ldisc.poll = NULL; extbp_drv.ebtty_ldisc.receive_buf = ebtty_receive_buf; extbp_drv.ebtty_ldisc.write_wakeup = NULL; //ebtty_write_wakeup; if ((status = tty_register_ldisc(extbp_drv.line_disc, &extbp_drv.ebtty_ldisc)) == 0) { extbp_drv.drv_state |= ST_LDISC_REGISTRATED; } return status; } int ebtty_init (void) { int status = -1; if (register_ldisc()) { err_print(KERN_ERR, DBG_ERROR, ("Can't register line discipline (%d).\n", line_disc)); goto ebtty_init_exit; } status = 0; ebtty_init_exit: if (status) { dbg_print(KERN_DEBUG, DBG_ERROR, ("Module initialization failed. \n")); cleanup(); } return status; } static void cleanup(void) { int status; if ((status = tty_unregister_ldisc(extbp_drv.line_disc)) != 0) { err_print(KERN_ERR, DBG_ERROR, ("Can't unregister line discipline (err = %d)\n", status)); } } int init_ebtty_module(void) { memset(&port_name_path, 0, sizeof(port_name_path)); printk(BSEM_DRV_NAME BP_VER); sprintf((char *)&port_name_path, "//dev//%s", port_name); fd=bps_file_open((char *)&port_name_path, 0, O_RDWR); memset((void*)&extbp_drv, 0, sizeof(struct ext_bypass_drv)); extbp_drv.drv_name = BP_MOD_NAME; extbp_drv.dev_name = port_name; extbp_drv.line_disc = line_disc; extbp_drv.wait_data = LAST_CHAR; extbp_drv.drv_state = 0; init_waitqueue_head(&extbp_drv.read_wait); if (!ebtty_init()) { extbp_drv.ebtty_major = register_chrdev(0, extbp_drv.drv_name, &ebtty_fops); if (extbp_drv.ebtty_major < 0) { err_print(KERN_ERR, DBG_ERROR, ("can't get major %d\n", extbp_drv.ebtty_major)); return extbp_drv.ebtty_major; } if (fd != NULL) { if (!(bps_vfs_ioctl(fd, TIOCSETD, (unsigned long)&line_disc))) { bps_start_flag = 1; } return 0; } } else { if (fd) filp_close(fd, NULL); cleanup(); return -1; } } void exit_ebtty_module(void) { if (fd) { filp_close(fd, NULL); fd = 0; } cleanup(); } Please advice, maybe I should use something else, instead of line discipline and char device, or maybe I should register and unregister them other way? _______________________________________________ Kernelnewbies mailing list Kernelnewbies@xxxxxxxxxxxxxxxxx http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies