See also:
- https://lwn.net/Articles/735887/
- https://stackoverflow.com/questions/
53839625
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);
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)
{
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;
}
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);
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);
{
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);
}
-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;
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);