Welcome to the Linux Foundation Forum!

Line discipline register and unregister in new kernels

Posts: 1
edited August 2015 in Kernel Development

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?

Welcome!

It looks like you're new here. Sign in or register to get started.
Sign In

Welcome!

It looks like you're new here. Sign in or register to get started.
Sign In

Categories

Upcoming Training