Updated host/linvcons.c to use new timer API introduced in Linux 4.14.0.
authorAaron Taylor <ataylor@subgeniuskitty.com>
Wed, 28 Apr 2021 08:01:31 +0000 (01:01 -0700)
committerAaron Taylor <ataylor@subgeniuskitty.com>
Wed, 28 Apr 2021 08:10:15 +0000 (01:10 -0700)
See also:

  - https://lwn.net/Articles/735887/

  - https://stackoverflow.com/questions/53839625

host/linvcons.c

index 556a9b5..7c3e58d 100644 (file)
@@ -43,7 +43,7 @@ static int micvcons_write(struct tty_struct * tty, const unsigned char *buf,
                                                                int count);
 static int micvcons_write_room(struct tty_struct *tty);
 static void micvcons_set_termios(struct tty_struct *tty, struct ktermios * old);
                                                                int count);
 static int micvcons_write_room(struct tty_struct *tty);
 static void micvcons_set_termios(struct tty_struct *tty, struct ktermios * old);
-static void micvcons_timeout(unsigned long);
+static void micvcons_timeout(struct timer_list *);
 static void micvcons_throttle(struct tty_struct *tty);
 static void micvcons_unthrottle(struct tty_struct *tty);
 static void micvcons_wakeup_readbuf(struct work_struct *work);
 static void micvcons_throttle(struct tty_struct *tty);
 static void micvcons_unthrottle(struct tty_struct *tty);
 static void micvcons_wakeup_readbuf(struct work_struct *work);
@@ -62,10 +62,19 @@ static struct tty_operations micvcons_tty_ops = {
 static struct tty_driver *micvcons_tty = NULL;
 static u16 extra_timeout = 0;
 static u8 restart_timer_flag = MICVCONS_TIMER_RESTART;
 static struct tty_driver *micvcons_tty = NULL;
 static u16 extra_timeout = 0;
 static u8 restart_timer_flag = MICVCONS_TIMER_RESTART;
-static struct timer_list vcons_timer;
-static struct list_head timer_list_head;
 static spinlock_t timer_list_lock;
 
 static spinlock_t timer_list_lock;
 
+// The timer API introduced in Linux 4.14.0 includes a from_timer() macro built
+// atop the container_of() macro. As the kernel moves away from using
+// timer_list.data, it quasi-assumes that the timer_list struct will be
+// contained in some larger struct that also contains the data, hence this
+// timer_wrapper struct since it allows us to avoid any serious code changes to
+// the driver.
+static struct timer_wrapper {
+       struct timer_list vcons_timer;
+       struct list_head timer_list_head;
+} timer_wrapper ;
+
 int
 micvcons_create(int num_bds)
 {
 int
 micvcons_create(int num_bds)
 {
@@ -75,7 +84,7 @@ micvcons_create(int num_bds)
        char wq_name[14];
        struct device *dev;
 
        char wq_name[14];
        struct device *dev;
 
-       INIT_LIST_HEAD(&timer_list_head);
+       INIT_LIST_HEAD(&timer_wrapper.timer_list_head);
 
        if (micvcons_tty)
                goto exit;
 
        if (micvcons_tty)
                goto exit;
@@ -145,9 +154,7 @@ micvcons_create(int num_bds)
                }
                INIT_WORK(&port->dp_wakeup_read_buf, micvcons_wakeup_readbuf);
        }
                }
                INIT_WORK(&port->dp_wakeup_read_buf, micvcons_wakeup_readbuf);
        }
-       vcons_timer.function = micvcons_timeout;
-       vcons_timer.data = (unsigned long)(&timer_list_head);
-       init_timer(&vcons_timer);
+       timer_setup(&timer_wrapper.vcons_timer, micvcons_timeout, 0);
 exit:
        return ret;
 }
 exit:
        return ret;
 }
@@ -215,10 +222,10 @@ micvcons_open(struct tty_struct * tty, struct file * filp)
                if (ret != 0)
                        goto exit_locked;
                spin_lock(&timer_list_lock);
                if (ret != 0)
                        goto exit_locked;
                spin_lock(&timer_list_lock);
-               list_add_tail_rcu(&port->list_member, &timer_list_head);
-               if (list_is_singular(&timer_list_head)) {
+               list_add_tail_rcu(&port->list_member, &timer_wrapper.timer_list_head);
+               if (list_is_singular(&timer_wrapper.timer_list_head)) {
                        restart_timer_flag = MICVCONS_TIMER_RESTART;
                        restart_timer_flag = MICVCONS_TIMER_RESTART;
-                       mod_timer(&vcons_timer, jiffies + 
+                       mod_timer(&timer_wrapper.vcons_timer, jiffies +
                                msecs_to_jiffies(MICVCONS_SHORT_TIMEOUT));
                }
                spin_unlock(&timer_list_lock);
                                msecs_to_jiffies(MICVCONS_SHORT_TIMEOUT));
                }
                spin_unlock(&timer_list_lock);
@@ -235,10 +242,10 @@ micvcons_del_timer_entry(micvcons_port_t *port)
 {
        spin_lock(&timer_list_lock);
        list_del_rcu(&port->list_member);
 {
        spin_lock(&timer_list_lock);
        list_del_rcu(&port->list_member);
-       if (list_empty(&timer_list_head)) {
+       if (list_empty(&timer_wrapper.timer_list_head)) {
                restart_timer_flag = MICVCONS_TIMER_SHUTDOWN;
                spin_unlock(&timer_list_lock);
                restart_timer_flag = MICVCONS_TIMER_SHUTDOWN;
                spin_unlock(&timer_list_lock);
-               del_timer_sync(&vcons_timer);
+               del_timer_sync(&timer_wrapper.vcons_timer);
        } else {
                spin_unlock(&timer_list_lock);
        }
        } else {
                spin_unlock(&timer_list_lock);
        }
@@ -499,9 +506,10 @@ micvcons_wakeup_readbuf(struct work_struct *work)
 }
 
 static void
 }
 
 static void
-micvcons_timeout(unsigned long data)
+micvcons_timeout(struct timer_list *t)
 {
 {
-       struct list_head *timer_list_ptr = (struct list_head *)data;
+       struct timer_wrapper *tm_wrap = from_timer(tm_wrap, t, vcons_timer);
+       struct list_head *timer_list_ptr = &tm_wrap->timer_list_head;
        micvcons_port_t *port;
        u8 console_active = 0;
        int num_chars_read = 0;
        micvcons_port_t *port;
        u8 console_active = 0;
        int num_chars_read = 0;
@@ -519,7 +527,7 @@ micvcons_timeout(unsigned long data)
                extra_timeout = (console_active ? 0 :
                                extra_timeout + MICVCONS_SHORT_TIMEOUT);
                extra_timeout = min(extra_timeout, (u16)MICVCONS_MAX_TIMEOUT);
                extra_timeout = (console_active ? 0 :
                                extra_timeout + MICVCONS_SHORT_TIMEOUT);
                extra_timeout = min(extra_timeout, (u16)MICVCONS_MAX_TIMEOUT);
-               mod_timer(&vcons_timer, jiffies + 
+               mod_timer(&timer_wrapper.vcons_timer, jiffies +
                        msecs_to_jiffies(MICVCONS_SHORT_TIMEOUT+extra_timeout));
        }
        spin_unlock(&timer_list_lock);
                        msecs_to_jiffies(MICVCONS_SHORT_TIMEOUT+extra_timeout));
        }
        spin_unlock(&timer_list_lock);