diff options
-rw-r--r-- | drivers/hid/hid-led.c | 23 |
1 files changed, 19 insertions, 4 deletions
diff --git a/drivers/hid/hid-led.c b/drivers/hid/hid-led.c index d8d55f37b4f5..d3e1ab162f7c 100644 --- a/drivers/hid/hid-led.c +++ b/drivers/hid/hid-led.c | |||
@@ -100,6 +100,7 @@ struct hidled_device { | |||
100 | const struct hidled_config *config; | 100 | const struct hidled_config *config; |
101 | struct hid_device *hdev; | 101 | struct hid_device *hdev; |
102 | struct hidled_rgb *rgb; | 102 | struct hidled_rgb *rgb; |
103 | u8 *buf; | ||
103 | struct mutex lock; | 104 | struct mutex lock; |
104 | }; | 105 | }; |
105 | 106 | ||
@@ -118,13 +119,19 @@ static int hidled_send(struct hidled_device *ldev, __u8 *buf) | |||
118 | 119 | ||
119 | mutex_lock(&ldev->lock); | 120 | mutex_lock(&ldev->lock); |
120 | 121 | ||
122 | /* | ||
123 | * buffer provided to hid_hw_raw_request must not be on the stack | ||
124 | * and must not be part of a data structure | ||
125 | */ | ||
126 | memcpy(ldev->buf, buf, ldev->config->report_size); | ||
127 | |||
121 | if (ldev->config->report_type == RAW_REQUEST) | 128 | if (ldev->config->report_type == RAW_REQUEST) |
122 | ret = hid_hw_raw_request(ldev->hdev, buf[0], buf, | 129 | ret = hid_hw_raw_request(ldev->hdev, buf[0], ldev->buf, |
123 | ldev->config->report_size, | 130 | ldev->config->report_size, |
124 | HID_FEATURE_REPORT, | 131 | HID_FEATURE_REPORT, |
125 | HID_REQ_SET_REPORT); | 132 | HID_REQ_SET_REPORT); |
126 | else if (ldev->config->report_type == OUTPUT_REPORT) | 133 | else if (ldev->config->report_type == OUTPUT_REPORT) |
127 | ret = hid_hw_output_report(ldev->hdev, buf, | 134 | ret = hid_hw_output_report(ldev->hdev, ldev->buf, |
128 | ldev->config->report_size); | 135 | ldev->config->report_size); |
129 | else | 136 | else |
130 | ret = -EINVAL; | 137 | ret = -EINVAL; |
@@ -147,17 +154,21 @@ static int hidled_recv(struct hidled_device *ldev, __u8 *buf) | |||
147 | 154 | ||
148 | mutex_lock(&ldev->lock); | 155 | mutex_lock(&ldev->lock); |
149 | 156 | ||
150 | ret = hid_hw_raw_request(ldev->hdev, buf[0], buf, | 157 | memcpy(ldev->buf, buf, ldev->config->report_size); |
158 | |||
159 | ret = hid_hw_raw_request(ldev->hdev, buf[0], ldev->buf, | ||
151 | ldev->config->report_size, | 160 | ldev->config->report_size, |
152 | HID_FEATURE_REPORT, | 161 | HID_FEATURE_REPORT, |
153 | HID_REQ_SET_REPORT); | 162 | HID_REQ_SET_REPORT); |
154 | if (ret < 0) | 163 | if (ret < 0) |
155 | goto err; | 164 | goto err; |
156 | 165 | ||
157 | ret = hid_hw_raw_request(ldev->hdev, buf[0], buf, | 166 | ret = hid_hw_raw_request(ldev->hdev, buf[0], ldev->buf, |
158 | ldev->config->report_size, | 167 | ldev->config->report_size, |
159 | HID_FEATURE_REPORT, | 168 | HID_FEATURE_REPORT, |
160 | HID_REQ_GET_REPORT); | 169 | HID_REQ_GET_REPORT); |
170 | |||
171 | memcpy(buf, ldev->buf, ldev->config->report_size); | ||
161 | err: | 172 | err: |
162 | mutex_unlock(&ldev->lock); | 173 | mutex_unlock(&ldev->lock); |
163 | 174 | ||
@@ -447,6 +458,10 @@ static int hidled_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
447 | if (!ldev) | 458 | if (!ldev) |
448 | return -ENOMEM; | 459 | return -ENOMEM; |
449 | 460 | ||
461 | ldev->buf = devm_kmalloc(&hdev->dev, MAX_REPORT_SIZE, GFP_KERNEL); | ||
462 | if (!ldev->buf) | ||
463 | return -ENOMEM; | ||
464 | |||
450 | ret = hid_parse(hdev); | 465 | ret = hid_parse(hdev); |
451 | if (ret) | 466 | if (ret) |
452 | return ret; | 467 | return ret; |