diff options
Diffstat (limited to 'drivers/hid/hid-debug.c')
-rw-r--r-- | drivers/hid/hid-debug.c | 120 |
1 files changed, 47 insertions, 73 deletions
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index c530476edba6..ac9fda1b5a72 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c | |||
@@ -30,6 +30,7 @@ | |||
30 | 30 | ||
31 | #include <linux/debugfs.h> | 31 | #include <linux/debugfs.h> |
32 | #include <linux/seq_file.h> | 32 | #include <linux/seq_file.h> |
33 | #include <linux/kfifo.h> | ||
33 | #include <linux/sched/signal.h> | 34 | #include <linux/sched/signal.h> |
34 | #include <linux/export.h> | 35 | #include <linux/export.h> |
35 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
@@ -661,17 +662,12 @@ EXPORT_SYMBOL_GPL(hid_dump_device); | |||
661 | /* enqueue string to 'events' ring buffer */ | 662 | /* enqueue string to 'events' ring buffer */ |
662 | void hid_debug_event(struct hid_device *hdev, char *buf) | 663 | void hid_debug_event(struct hid_device *hdev, char *buf) |
663 | { | 664 | { |
664 | unsigned i; | ||
665 | struct hid_debug_list *list; | 665 | struct hid_debug_list *list; |
666 | unsigned long flags; | 666 | unsigned long flags; |
667 | 667 | ||
668 | spin_lock_irqsave(&hdev->debug_list_lock, flags); | 668 | spin_lock_irqsave(&hdev->debug_list_lock, flags); |
669 | list_for_each_entry(list, &hdev->debug_list, node) { | 669 | list_for_each_entry(list, &hdev->debug_list, node) |
670 | for (i = 0; buf[i]; i++) | 670 | kfifo_in(&list->hid_debug_fifo, buf, strlen(buf)); |
671 | list->hid_debug_buf[(list->tail + i) % HID_DEBUG_BUFSIZE] = | ||
672 | buf[i]; | ||
673 | list->tail = (list->tail + i) % HID_DEBUG_BUFSIZE; | ||
674 | } | ||
675 | spin_unlock_irqrestore(&hdev->debug_list_lock, flags); | 671 | spin_unlock_irqrestore(&hdev->debug_list_lock, flags); |
676 | 672 | ||
677 | wake_up_interruptible(&hdev->debug_wait); | 673 | wake_up_interruptible(&hdev->debug_wait); |
@@ -722,8 +718,7 @@ void hid_dump_input(struct hid_device *hdev, struct hid_usage *usage, __s32 valu | |||
722 | hid_debug_event(hdev, buf); | 718 | hid_debug_event(hdev, buf); |
723 | 719 | ||
724 | kfree(buf); | 720 | kfree(buf); |
725 | wake_up_interruptible(&hdev->debug_wait); | 721 | wake_up_interruptible(&hdev->debug_wait); |
726 | |||
727 | } | 722 | } |
728 | EXPORT_SYMBOL_GPL(hid_dump_input); | 723 | EXPORT_SYMBOL_GPL(hid_dump_input); |
729 | 724 | ||
@@ -1083,8 +1078,8 @@ static int hid_debug_events_open(struct inode *inode, struct file *file) | |||
1083 | goto out; | 1078 | goto out; |
1084 | } | 1079 | } |
1085 | 1080 | ||
1086 | if (!(list->hid_debug_buf = kzalloc(HID_DEBUG_BUFSIZE, GFP_KERNEL))) { | 1081 | err = kfifo_alloc(&list->hid_debug_fifo, HID_DEBUG_FIFOSIZE, GFP_KERNEL); |
1087 | err = -ENOMEM; | 1082 | if (err) { |
1088 | kfree(list); | 1083 | kfree(list); |
1089 | goto out; | 1084 | goto out; |
1090 | } | 1085 | } |
@@ -1104,77 +1099,57 @@ static ssize_t hid_debug_events_read(struct file *file, char __user *buffer, | |||
1104 | size_t count, loff_t *ppos) | 1099 | size_t count, loff_t *ppos) |
1105 | { | 1100 | { |
1106 | struct hid_debug_list *list = file->private_data; | 1101 | struct hid_debug_list *list = file->private_data; |
1107 | int ret = 0, len; | 1102 | int ret = 0, copied; |
1108 | DECLARE_WAITQUEUE(wait, current); | 1103 | DECLARE_WAITQUEUE(wait, current); |
1109 | 1104 | ||
1110 | mutex_lock(&list->read_mutex); | 1105 | mutex_lock(&list->read_mutex); |
1111 | while (ret == 0) { | 1106 | if (kfifo_is_empty(&list->hid_debug_fifo)) { |
1112 | if (list->head == list->tail) { | 1107 | add_wait_queue(&list->hdev->debug_wait, &wait); |
1113 | add_wait_queue(&list->hdev->debug_wait, &wait); | 1108 | set_current_state(TASK_INTERRUPTIBLE); |
1114 | set_current_state(TASK_INTERRUPTIBLE); | 1109 | |
1115 | 1110 | while (kfifo_is_empty(&list->hid_debug_fifo)) { | |
1116 | while (list->head == list->tail) { | 1111 | if (file->f_flags & O_NONBLOCK) { |
1117 | if (file->f_flags & O_NONBLOCK) { | 1112 | ret = -EAGAIN; |
1118 | ret = -EAGAIN; | 1113 | break; |
1119 | break; | 1114 | } |
1120 | } | ||
1121 | if (signal_pending(current)) { | ||
1122 | ret = -ERESTARTSYS; | ||
1123 | break; | ||
1124 | } | ||
1125 | 1115 | ||
1126 | if (!list->hdev || !list->hdev->debug) { | 1116 | if (signal_pending(current)) { |
1127 | ret = -EIO; | 1117 | ret = -ERESTARTSYS; |
1128 | set_current_state(TASK_RUNNING); | 1118 | break; |
1129 | goto out; | 1119 | } |
1130 | } | ||
1131 | 1120 | ||
1132 | /* allow O_NONBLOCK from other threads */ | 1121 | /* if list->hdev is NULL we cannot remove_wait_queue(). |
1133 | mutex_unlock(&list->read_mutex); | 1122 | * if list->hdev->debug is 0 then hid_debug_unregister() |
1134 | schedule(); | 1123 | * was already called and list->hdev is being destroyed. |
1135 | mutex_lock(&list->read_mutex); | 1124 | * if we add remove_wait_queue() here we can hit a race. |
1136 | set_current_state(TASK_INTERRUPTIBLE); | 1125 | */ |
1126 | if (!list->hdev || !list->hdev->debug) { | ||
1127 | ret = -EIO; | ||
1128 | set_current_state(TASK_RUNNING); | ||
1129 | goto out; | ||
1137 | } | 1130 | } |
1138 | 1131 | ||
1139 | set_current_state(TASK_RUNNING); | 1132 | /* allow O_NONBLOCK from other threads */ |
1140 | remove_wait_queue(&list->hdev->debug_wait, &wait); | 1133 | mutex_unlock(&list->read_mutex); |
1134 | schedule(); | ||
1135 | mutex_lock(&list->read_mutex); | ||
1136 | set_current_state(TASK_INTERRUPTIBLE); | ||
1141 | } | 1137 | } |
1142 | 1138 | ||
1143 | if (ret) | 1139 | __set_current_state(TASK_RUNNING); |
1144 | goto out; | 1140 | remove_wait_queue(&list->hdev->debug_wait, &wait); |
1145 | 1141 | ||
1146 | /* pass the ringbuffer contents to userspace */ | 1142 | if (ret) |
1147 | copy_rest: | ||
1148 | if (list->tail == list->head) | ||
1149 | goto out; | 1143 | goto out; |
1150 | if (list->tail > list->head) { | ||
1151 | len = list->tail - list->head; | ||
1152 | if (len > count) | ||
1153 | len = count; | ||
1154 | |||
1155 | if (copy_to_user(buffer + ret, &list->hid_debug_buf[list->head], len)) { | ||
1156 | ret = -EFAULT; | ||
1157 | goto out; | ||
1158 | } | ||
1159 | ret += len; | ||
1160 | list->head += len; | ||
1161 | } else { | ||
1162 | len = HID_DEBUG_BUFSIZE - list->head; | ||
1163 | if (len > count) | ||
1164 | len = count; | ||
1165 | |||
1166 | if (copy_to_user(buffer, &list->hid_debug_buf[list->head], len)) { | ||
1167 | ret = -EFAULT; | ||
1168 | goto out; | ||
1169 | } | ||
1170 | list->head = 0; | ||
1171 | ret += len; | ||
1172 | count -= len; | ||
1173 | if (count > 0) | ||
1174 | goto copy_rest; | ||
1175 | } | ||
1176 | |||
1177 | } | 1144 | } |
1145 | |||
1146 | /* pass the fifo content to userspace, locking is not needed with only | ||
1147 | * one concurrent reader and one concurrent writer | ||
1148 | */ | ||
1149 | ret = kfifo_to_user(&list->hid_debug_fifo, buffer, count, &copied); | ||
1150 | if (ret) | ||
1151 | goto out; | ||
1152 | ret = copied; | ||
1178 | out: | 1153 | out: |
1179 | mutex_unlock(&list->read_mutex); | 1154 | mutex_unlock(&list->read_mutex); |
1180 | return ret; | 1155 | return ret; |
@@ -1185,7 +1160,7 @@ static __poll_t hid_debug_events_poll(struct file *file, poll_table *wait) | |||
1185 | struct hid_debug_list *list = file->private_data; | 1160 | struct hid_debug_list *list = file->private_data; |
1186 | 1161 | ||
1187 | poll_wait(file, &list->hdev->debug_wait, wait); | 1162 | poll_wait(file, &list->hdev->debug_wait, wait); |
1188 | if (list->head != list->tail) | 1163 | if (!kfifo_is_empty(&list->hid_debug_fifo)) |
1189 | return EPOLLIN | EPOLLRDNORM; | 1164 | return EPOLLIN | EPOLLRDNORM; |
1190 | if (!list->hdev->debug) | 1165 | if (!list->hdev->debug) |
1191 | return EPOLLERR | EPOLLHUP; | 1166 | return EPOLLERR | EPOLLHUP; |
@@ -1200,7 +1175,7 @@ static int hid_debug_events_release(struct inode *inode, struct file *file) | |||
1200 | spin_lock_irqsave(&list->hdev->debug_list_lock, flags); | 1175 | spin_lock_irqsave(&list->hdev->debug_list_lock, flags); |
1201 | list_del(&list->node); | 1176 | list_del(&list->node); |
1202 | spin_unlock_irqrestore(&list->hdev->debug_list_lock, flags); | 1177 | spin_unlock_irqrestore(&list->hdev->debug_list_lock, flags); |
1203 | kfree(list->hid_debug_buf); | 1178 | kfifo_free(&list->hid_debug_fifo); |
1204 | kfree(list); | 1179 | kfree(list); |
1205 | 1180 | ||
1206 | return 0; | 1181 | return 0; |
@@ -1246,4 +1221,3 @@ void hid_debug_exit(void) | |||
1246 | { | 1221 | { |
1247 | debugfs_remove_recursive(hid_debug_root); | 1222 | debugfs_remove_recursive(hid_debug_root); |
1248 | } | 1223 | } |
1249 | |||