From 3304b13a2b2e7388ebf076c2bcb7f02cd0b6800f Mon Sep 17 00:00:00 2001 Message-ID: <3304b13a2b2e7388ebf076c2bcb7f02cd0b6800f.1776940528.git.fritsche.markus@gmail.com> In-Reply-To: References: From: Markus Fritsche Date: Wed, 22 Apr 2026 12:55:18 +0200 Subject: [PATCH 5/7] bes2600: remove userspace /dev/bes2600 character device interface bes_chardev.c implemented a custom character device at /dev/bes2600 with its own parser and command-dispatch table, exposing operations such as 'wifi on|off', 'bt on|off', 'change_fw_type ', 'bt_wakeup', 'bt_sleep', and 'wakeup_read_flag'. None of these surfaces are used by the in-tree driver - every kernel call site consumes the internal state accessors (bes2600_chrdev_is_signal_mode, bes2600_chrdev_get_fw_type, etc) directly, not through the cdev. The cdev interface is a standing upstream blocker for two reasons: 1. Drivers under drivers/staging/ and drivers/net/wireless/ are expected to expose tuning via the firmware/nl80211/debugfs infrastructure rather than a private /dev node with an ad-hoc parser. 2. The cdev handlers keep a global bes_cdev singleton alive whose ->cdev, ->dev_id, ->class and ->device pointers exist only to be torn down; they add no functionality that nl80211 or rfkill do not already provide (wifi/bt on-off, module_param for fw_type). Remove the userspace interface: - open / read / write / release file_operations handlers and the bes2600_chardev_fops instance - bes2600_op_* command handlers and bes2600_op_map_tab dispatcher - bes2600_get_cmd_and_ifname / bes2600_recyle_cmd_and_ifname_mem string helpers - bes2600_load_uevent (its only caller was bes2600_chrdev_wifi_force_close_work informing userspace of a state it already gates via rfkill; that snprintf + kobject_uevent_env block is gone too, the kernel-side halt_device + switch_wifi(0) + chrdev_check_system_close sequence remains) - alloc_chrdev_region / cdev_init / cdev_add / class_create / device_create in bes2600_chrdev_init plus the fail1/fail2/fail3 unwind labels - cdev_del / unregister_chrdev_region / device_destroy / class_destroy in bes2600_chrdev_free - cdev/dev_id/major/minor/class/device fields in struct bes_cdev What remains (unchanged behaviour): - fw_type module parameter - the primary user-facing knob for signal/no-signal/BT mode switch - All in-kernel bes2600_chrdev_* accessor functions called from bes2600_sdio.c, bes_pwr.c, sta.c, bh.c, main.c, wsm.c, and wifi_testmode_cmd.c (13 call sites) - bes2600_chrdev_init / bes2600_chrdev_free as state-init / teardown for the remaining bes_cdev state (waitqueues, workqueues, flags) - DPD management (bes2600_chrdev_get_dpd_buffer / update / free) - wifi_force_close worker, system-close logic, bus-probe state machine Tested-on: PineTab2 (BES2600WM + RK3566) running linux-pinetab2 6.19.10-danctnix1-1. Driver continues to associate and pass traffic; no kernel messages related to the cdev absence. Users that previously wrote to /dev/bes2600 should switch to the fw_type module parameter or (future patch c4) nl80211 testmode commands. Follow-ups: - c3.1: thread struct device * through bes2600_chrdev_is_signal_mode and friends so the global bes2600_cdev singleton can be dropped and the accessors scale to multi-device scenarios. - c4: enable CONFIG_BES2600_TESTMODE and route nl80211 testmode commands to the firmware's patch_wifi_testMode entry. Signed-off-by: Markus Fritsche --- drivers/staging/bes2600/bes_chardev.c | 519 ------------------------------------------ 1 file changed, 519 deletions(-) diff --git a/drivers/staging/bes2600/bes_chardev.c b/bes2600/bes_chardev.c index 9038e48..e2e4f1b 100644 --- a/drivers/staging/bes2600/bes_chardev.c +++ b/drivers/staging/bes2600/bes_chardev.c @@ -43,12 +43,6 @@ enum bus_probe_state { }; struct bes_cdev { - struct cdev cdev; - dev_t dev_id; - int major; - int minor; - struct class *class; - struct device *device; atomic_t num_proc; wait_queue_head_t open_wq; spinlock_t status_lock; @@ -249,351 +243,18 @@ int bes2600_switch_bt(bool on) return ret; } -static int bes2600_get_cmd_and_ifname(const char *str, char **result) -{ - int cmd_len = 0; - int ifname_len = 0; - char *sp = NULL; - char *tmp_ptr = NULL; - char *cmd_ptr = NULL; - - /* check if input arguments is valid */ - if (!str || strncmp(str, "ifname:", 7) != 0) - return -1; - - sp = strchr(str, ' '); - if (strncmp(sp + 1, "cmd:", 4) != 0) - return -1; - - /* extract interface name */ - ifname_len = sp - str - 7; - tmp_ptr = kmalloc(ifname_len + 1, GFP_KERNEL); - if (!tmp_ptr) { - return -2; - } - - strncpy(tmp_ptr, str+7, ifname_len); - tmp_ptr[ifname_len] = '\0'; - result[0] = tmp_ptr; - - /* get command length */ - cmd_ptr = strstr(str, "cmd:"); - cmd_ptr += 4; - sp = strchr(cmd_ptr, ' '); - if (!sp) { /* the command don't have any parameter */ - cmd_len = strlen(cmd_ptr); - if (cmd_ptr[cmd_len - 1] == '\n') - --cmd_len; - } else { /* the command have one or more parameter */ - cmd_len = sp - cmd_ptr; - } - - /* copy command to out buffer */ - tmp_ptr = kmalloc( cmd_len + 1, GFP_KERNEL); - if (!tmp_ptr) { - kfree(result[0]); - result[0] = NULL; - return -3; - } - - strncpy(tmp_ptr, cmd_ptr, cmd_len); - tmp_ptr[cmd_len] = '\0'; - result[1] = tmp_ptr; - - return 0; -} - -static void bes2600_recyle_cmd_and_ifname_mem(char **info) -{ - if (info[0]) { - kfree(info[0]); - info[0] = NULL; - } - - if (info[1]) { - kfree(info[1]); - info[1] = NULL; - } - -} - -static int bes2600_op_default_handler(const char *str) -{ - char *info[2] = {0}; - - if (bes2600_get_cmd_and_ifname(str, info) == 0) { - bes_devel("cmd(%s) on %s not handled\n", info[1], info[0]); - } else { - bes_err("%s get command fail, the origin string is %s\n", __func__, str); - } - - bes2600_recyle_cmd_and_ifname_mem(info); - - return 0; -} - -static int bes2600_op_wifi_bt_on_off(const char *str) -{ - char *info[2] = {0}; - int ret = 0; - enum wait_state wait_state; - enum bus_probe_state probe_state; - unsigned long status = 0; - - spin_lock(&bes2600_cdev.status_lock); - probe_state = bes2600_cdev.bus_probe; - wait_state = bes2600_cdev.wait_state; - spin_unlock(&bes2600_cdev.status_lock); - - /* only work for wifi signal mode */ - if (bes2600_cdev.fw_type != BES2600_FW_TYPE_WIFI_SIGNAL) - return -EFAULT; - - /* wait bus probe operation end */ - if (probe_state == BES2600_BUS_PROBE_START) { - bes_devel("wait bus probe operation end\n"); - status = wait_event_timeout(bes2600_cdev.probe_done_wq, - (bes2600_cdev.bus_probe > BES2600_BUS_PROBE_START), - HZ); - WARN_ON(status <= 0); - } - - /* must wait previous operation end in critical section */ - if (wait_state != BES2600_BOOT_WAIT_NONE) { - bes_devel("wait previous operation end\n"); - status = wait_event_timeout(bes2600_cdev.probe_done_wq, - (bes2600_cdev.wait_state == BES2600_BOOT_WAIT_NONE), - HZ * 8); - WARN_ON(status <= 0); - } - - /* if dpd calibration is doing, modify wifi and bt state directly */ - spin_lock(&bes2600_cdev.status_lock); - if (bes2600_cdev.bus_probe == BES2600_BUS_PROBE_OK && !bes2600_cdev.dpd_calied) { - if (bes2600_get_cmd_and_ifname(str, info) == 0) { - if (strncmp(info[1], "WIFI_ON", 7) == 0) { - bes2600_cdev.wifi_opened = true; - } else if (strncmp(info[1], "WIFI_OFF", 8) == 0) { - bes2600_cdev.wifi_opened = false; - } else if (strncmp(info[1], "BT_ON", 5) == 0) { - bes2600_cdev.bt_opened = true; - bes2600_cdev.bton_pending = true; - } else if (strncmp(info[1], "BT_OFF", 6) == 0) { - bes2600_cdev.bt_opened = false; - bes2600_cdev.bton_pending = false; - } - } - bes2600_recyle_cmd_and_ifname_mem(info); - spin_unlock(&bes2600_cdev.status_lock); - - /* wait probe done event */ - status = wait_event_timeout(bes2600_cdev.probe_done_wq, - bes2600_bootup_end(), HZ * 8); - WARN_ON(status <= 0); - - return (status <= 0 || bes2600_chrdev_is_bus_error()) ? -EFAULT : 0; - } - spin_unlock(&bes2600_cdev.status_lock); - - /* process wifi/bt on/off operation */ - if (bes2600_get_cmd_and_ifname(str, info) == 0) { - if (strncmp(info[1], "WIFI_ON", 7) == 0) { - ret = bes2600_switch_wifi(1); - } else if (strncmp(info[1], "WIFI_OFF", 8) == 0) { - ret = bes2600_switch_wifi(0); - } else if (strncmp(info[1], "BT_ON", 5) == 0) { - ret = bes2600_switch_bt(1); - } else if (strncmp(info[1], "BT_OFF", 6) == 0) { - ret = bes2600_switch_bt(0); - } - } - - if (!ret && bes2600_chrdev_check_system_close()) - ret = bes2600_chrdev_do_system_close(bes2600_cdev.sbus_ops, - bes2600_cdev.sbus_priv); - - bes2600_recyle_cmd_and_ifname_mem(info); - - return ret ; -} - - -static int bes2600_op_change_fw_type(const char *str) -{ - int ret = 0; - int temp = 0; - long status = 0; - char *cmd_ptr = NULL; - char fw_type[5] = {0}; - bool sys_closed = bes2600_chrdev_check_system_close(); - - bes_devel("%s is called, arg:%s\n", __func__, str); - - if (!bes2600_cdev.sbus_ops->power_switch && !bes2600_cdev.sbus_ops->reboot) - return -EPERM; - - /* check if user input is valid */ - cmd_ptr = strstr(str, "CHANGE_FW_TYPE "); - if (strlen(str) < 16 || !cmd_ptr) { - bes_err("the format of \"%s\" is error\n", str); - return -EINVAL; - } - - /* convert fw_type from string to int */ - strncpy(fw_type, cmd_ptr + 14, 4); - fw_type[0] = '+'; - ret = kstrtoint(fw_type, 10, &temp); - if (ret < 0) { - bes_err("%s parse error\n", __func__); - return -EINVAL; - } - - /* no need to realod firmware if new fw_type is equal to the old */ - if (temp == bes2600_cdev.fw_type ) { - bes_devel("fw type is equal\n"); - return 0; - } - - /* close wifi net device */ - if (bes2600_cdev.sbus_priv - && bes2600_is_net_dev_created(bes2600_cdev.sbus_priv)) { - bes2600_unregister_net_dev(bes2600_cdev.sbus_priv); - } - - /* update firmware type */ - bes2600_cdev.fw_type = temp; - bes2600_chrdev_update_signal_mode(); - - if (!sys_closed) { - /* close device to call disconnect function */ - if (bes2600_cdev.sbus_ops->power_switch) - bes2600_cdev.sbus_ops->power_switch(bes2600_cdev.sbus_priv, 0); - else if (bes2600_cdev.sbus_ops->reboot) - bes2600_cdev.sbus_ops->reboot(bes2600_cdev.sbus_priv); - } - - if (bes2600_cdev.sbus_ops->reboot) - bes2600_chrdev_start_bus_probe(); - - /* wait disconnect event */ - status = wait_event_timeout(bes2600_cdev.probe_done_wq, (bes2600_cdev.sbus_priv == NULL), HZ * 10); - WARN_ON(status <= 0); - - if (bes2600_cdev.dpd_calied - && bes2600_chrdev_check_system_close()) { - bes_devel("no need to reload firmware\n"); - return 0; - } - - bes_devel("reload firmware...\n"); - /* power on device to call probe function */ - if (bes2600_cdev.sbus_ops->power_switch) - bes2600_cdev.sbus_ops->power_switch(NULL, 1); - - /* wait probe done event */ - status = wait_event_timeout(bes2600_cdev.probe_done_wq, - bes2600_bootup_end(), HZ * 10); - WARN_ON(status <= 0); - - ret = (status <= 0 || bes2600_chrdev_is_bus_error()) ? -1 : 0; - return ret; -} - -static int bes2600_op_bt_wakeup(const char *str) -{ - int ret = 0; - unsigned long status = 0; - - spin_lock(&bes2600_cdev.status_lock); - if (!bes2600_cdev.bt_opened) { - spin_unlock(&bes2600_cdev.status_lock); - return -EFAULT; - } - spin_unlock(&bes2600_cdev.status_lock); - /* wait probe done event */ - status = wait_event_timeout(bes2600_cdev.probe_done_wq, - bes2600_bootup_end(), HZ * 8); - if (status <= 0 || bes2600_chrdev_is_bus_error()) - return -EFAULT; - - bes_devel("bes2600 wakeup bt.\n"); - ret = bes2600_chrdev_switch_subsys(GPIO_WAKE_FLAG_BT_LP_ON, SUBSYSTEM_BT_LP, true); - - return ret; -} - -static int bes2600_op_bt_sleep(const char *str) -{ - int ret = 0; - unsigned long status = 0; - - spin_lock(&bes2600_cdev.status_lock); - if (!bes2600_cdev.bt_opened) { - spin_unlock(&bes2600_cdev.status_lock); - return -EFAULT; - } - spin_unlock(&bes2600_cdev.status_lock); - /* wait probe done event */ - status = wait_event_timeout(bes2600_cdev.probe_done_wq, - bes2600_bootup_end(), HZ * 8); - if (status <= 0 || bes2600_chrdev_is_bus_error()) - return -EFAULT; - bes_devel("bes2600 allow bt sleep.\n"); - ret = bes2600_chrdev_switch_subsys(GPIO_WAKE_FLAG_BT_LP_OFF, SUBSYSTEM_BT_LP, false); - return ret; -} -static int bes2600_op_set_wakeup_read_flag(const char *str) -{ - bes_devel("%s is called, arg:%s\n", __func__, str); - spin_lock(&bes2600_cdev.status_lock); - bes2600_cdev.read_flag = BES_CDEV_READ_WAKEUP_STATE; - spin_unlock(&bes2600_cdev.status_lock); - return 0; -} #ifdef FW_DOWNLOAD_UART_DAEMON -int bes2600_load_uevent(char *env[]) -{ - return kobject_uevent_env(&bes2600_cdev.device->kobj, KOBJ_CHANGE, env); -} #endif -static struct bes2600_op_map bes2600_op_map_tab[] ={ - /*op op_len handler */ - {"P2P_SET_NOA", 11, bes2600_op_default_handler}, - {"P2P_SET_PS", 10, bes2600_op_default_handler}, - {"SET_AP_WPS_P2P_IE", 17, bes2600_op_default_handler}, - {"LINKSPEED", 9, bes2600_op_default_handler}, - {"RSSI", 4, bes2600_op_default_handler}, - {"GETBAND", 7, bes2600_op_default_handler}, - {"WLS_BATCHING", 12, bes2600_op_default_handler}, - {"MACADDR", 7, bes2600_op_default_handler}, - {"RXFILTER-START", 14, bes2600_op_default_handler}, - {"RXFILTER-STOP", 13, bes2600_op_default_handler}, - {"RXFILTER-ADD", 12, bes2600_op_default_handler}, - {"RXFILTER-REMOVE", 15, bes2600_op_default_handler}, - {"BTCOEXMODE", 10, bes2600_op_default_handler}, - {"BTCOEXSCAN-START", 16, bes2600_op_default_handler}, - {"BTCOEXSCAN-STOP", 15, bes2600_op_default_handler}, - {"SETSUSPENDMODE", 14, bes2600_op_default_handler}, - {"COUNTRY", 7, bes2600_op_default_handler}, - {"WIFI_ON", 7, bes2600_op_wifi_bt_on_off}, - {"WIFI_OFF", 8, bes2600_op_wifi_bt_on_off}, - {"BT_ON", 5, bes2600_op_wifi_bt_on_off}, - {"BT_OFF", 6, bes2600_op_wifi_bt_on_off}, - {"CHANGE_FW_TYPE", 14, bes2600_op_change_fw_type}, - {"BT_WAKEUP", 9, bes2600_op_bt_wakeup}, - {"BT_SLEEP", 8, bes2600_op_bt_sleep}, - {"WAKEUP_STATE", 12, bes2600_op_set_wakeup_read_flag}, -}; static int bes2600_chrdev_check_system_close_internal(void) { @@ -603,123 +264,10 @@ static int bes2600_chrdev_check_system_close_internal(void) && (bes2600_cdev.wifi_opened == false); } -static int bes2600_chrdev_open(struct inode *inode, struct file *filp) -{ - if (atomic_read(&bes2600_cdev.num_proc) > 0) { - wait_event_timeout(bes2600_cdev.open_wq, - (atomic_read(&bes2600_cdev.num_proc) == 0), - MAX_SCHEDULE_TIMEOUT); - } - bes_devel("bes2600 char device is opened\n"); - atomic_inc(&bes2600_cdev.num_proc); - return 0; -} -static ssize_t bes2600_chrdev_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - char buf[64] = {0}; - unsigned int len; - long status = 0; - switch (bes2600_cdev.read_flag) { - case BES_CDEV_READ_WAKEUP_STATE: - if (bes2600_chrdev_wakeup_by_event_get() > WAKEUP_EVENT_NONE) { - status = wait_event_timeout(bes2600_cdev.wakeup_reason_wq, - bes2600_chrdev_wakeup_by_event_get() == WAKEUP_EVENT_NONE, HZ * 2); - WARN_ON(status <= 0); - } - len = sprintf(buf, "wakeup_reason: %u, src_port: %u\n", - bes2600_cdev.wakeup_state, bes2600_cdev.src_port); - break; - default: - len = sprintf(buf, "dpd_calied:%d wifi_opened:%d bt_opened:%d fw_type:%d\n", - bes2600_cdev.dpd_calied, - bes2600_cdev.wifi_opened, - bes2600_cdev.bt_opened, - bes2600_cdev.fw_type); - break; - } - - len = sizeof(buf); - /* reset read flag */ - spin_lock(&bes2600_cdev.status_lock); - bes2600_cdev.read_flag = BES_CDEV_READ_NUM_MAX; - spin_unlock(&bes2600_cdev.status_lock); - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t bes2600_chrdev_write(struct file *file, - const char __user *user_buf, size_t count, loff_t *ppos) -{ - int i = 0; - int cmd_num = ARRAY_SIZE(bes2600_op_map_tab); - int cmd_len = 0; - int ret = 0; - char *info[2] = {0}; - char *buf = NULL; - - /* copy content from user space to kernel */ - /* message format:"ifname:wlanx cmd:xxx arg1 arg2 ..." */ - buf = kmalloc(count + 1, GFP_KERNEL); - if (copy_from_user(buf, user_buf, count)) - return -EFAULT; - - /* add terminal character */ - buf[count] = '\0'; - - /* extract comand and interface */ - if (bes2600_get_cmd_and_ifname(buf, info) != 0) { - bes_err("%s get command fail, the origin string is %s\n", __func__, buf); - kfree(buf); - return -EINVAL; - } - - /* match operation item and execure its handler */ - cmd_len = strlen(info[1]); - for (i = 0; i < cmd_num; i++) { - if (cmd_len < bes2600_op_map_tab[i].op_len) - continue; - - if (strncasecmp(info[1], bes2600_op_map_tab[i].op, bes2600_op_map_tab[i].op_len) == 0) { - ret = bes2600_op_map_tab[i].handler(buf); - break; - } - } - - /* operation item mismatch */ - if (i == cmd_num) { - bes_err("cmd(%s) mismatch\n", info[1]); - } - - bes2600_recyle_cmd_and_ifname_mem(info); - kfree(buf); - - return (ret == 0) ? count : ret; -} - -static int bes2600_chrdev_release (struct inode *inode, struct file *file) -{ - if (atomic_dec_and_test(&bes2600_cdev.num_proc)) { - wake_up(&bes2600_cdev.open_wq); - } - - bes_devel("bes2600 char device is closed\n"); - - return 0; -} - -static struct file_operations bes2600_chardev_fops = -{ - .owner = THIS_MODULE, - .open = bes2600_chrdev_open, - .read = bes2600_chrdev_read, - .write = bes2600_chrdev_write, - .release = bes2600_chrdev_release, -}; #ifdef BES2600_WRITE_DPD_TO_FILE static int bes2600_chrdev_write_dpd_data_to_file(const char *path, void *buffer, int size) @@ -1124,12 +672,6 @@ void bes2600_chrdev_update_signal_mode(void) static void bes2600_chrdev_wifi_force_close_work(struct work_struct *work) { - char wifi_state[15]; - char bt_state[15]; - char fw_type[15]; - char *env[] = { wifi_state, bt_state, fw_type, NULL }; - int ret; - if (bes2600_chrdev_is_wifi_opened()) { bes_devel("system exeception, force wifi down\n"); @@ -1146,14 +688,6 @@ static void bes2600_chrdev_wifi_force_close_work(struct work_struct *work) bes2600_chrdev_do_system_close(bes2600_cdev.sbus_ops, bes2600_cdev.sbus_priv); } - - /* notify userspace */ - snprintf(wifi_state, sizeof(wifi_state), "WIFI_OPENED=%d", bes2600_cdev.wifi_opened); - snprintf(bt_state, sizeof(bt_state), "BT_OPENED=%d", bes2600_cdev.bt_opened); - snprintf(fw_type, sizeof(fw_type), "FW_TYPE=%d", bes2600_cdev.fw_type); - ret = kobject_uevent_env(&bes2600_cdev.device->kobj, KOBJ_CHANGE, env); - if (!ret) - bes_err("bes2600 notify userspace failed\n"); } } @@ -1247,46 +781,6 @@ int bes2600_chrdev_wakeup_by_event_get(void) int bes2600_chrdev_init(struct sbus_ops *ops) { - int ret = 0; - - /* allocate devide id */ - ret = alloc_chrdev_region(&bes2600_cdev.dev_id, 0, 1, "bes2600_chrdev"); - if (ret < 0){ - bes_err("bes2600 alloc device id fail\n"); - ret = -EFAULT; - goto fail; - } - - /* extract major and minor device id */ - bes2600_cdev.major = MAJOR(bes2600_cdev.dev_id); - bes2600_cdev.minor = MINOR(bes2600_cdev.dev_id); - - /* add char device and bind operation function */ - bes2600_cdev.cdev.owner = THIS_MODULE; - cdev_init(&bes2600_cdev.cdev, &bes2600_chardev_fops); - ret = cdev_add(&bes2600_cdev.cdev, bes2600_cdev.dev_id, 1); - if (ret < 0){ - bes_err("bes2600 char device add fail\n"); - ret = -EFAULT; - goto fail1; - } - - /* create class for creating device node */ - bes2600_cdev.class = class_create("bes2600_chrdev"); - if (IS_ERR(bes2600_cdev.class)){ - bes_err("bes2600 char device add fail\n"); - ret = -EFAULT; - goto fail2; - } - - /* get char device pointer */ - bes2600_cdev.device = device_create(bes2600_cdev.class, NULL, bes2600_cdev.dev_id, NULL, "bes2600"); - if (IS_ERR(bes2600_cdev.device)){ - bes_err("bes2600 char device create fail\n"); - ret = -EFAULT; - goto fail3; - } - /* initialise global variable */ atomic_set(&bes2600_cdev.num_proc, 0); init_waitqueue_head(&bes2600_cdev.open_wq); @@ -1318,15 +812,6 @@ int bes2600_chrdev_init(struct sbus_ops *ops) bes_devel("%s done\n", __func__); return 0; - -fail3: - class_destroy(bes2600_cdev.class); -fail2: - cdev_del(&bes2600_cdev.cdev); -fail1: - unregister_chrdev_region(bes2600_cdev.dev_id, 1); -fail: - return ret; } void bes2600_chrdev_free(void) @@ -1336,9 +821,5 @@ void bes2600_chrdev_free(void) bes2600_free_dpd_log_buffer(); #endif bes2600_chrdev_free_dpd_data(); - cdev_del(&bes2600_cdev.cdev); - unregister_chrdev_region(bes2600_cdev.dev_id, 1); - device_destroy(bes2600_cdev.class, bes2600_cdev.dev_id); - class_destroy(bes2600_cdev.class); bes_devel("%s done\n", __func__); } -- 2.53.0