Skip to content

Commit 1ffb3c4

Browse files
bentissJiri Kosina
authored andcommitted
HID: cp2112: make transfer buffers DMA capable
Kernel v4.9 strictly enforces DMA capable buffers, so we need to remove buffers allocated on the stack. Use a spinlock to prevent concurrent accesses to the buffer. Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
1 parent 4c4480a commit 1ffb3c4

1 file changed

Lines changed: 79 additions & 36 deletions

File tree

drivers/hid/hid-cp2112.c

Lines changed: 79 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@
3232
#include <linux/usb/ch9.h>
3333
#include "hid-ids.h"
3434

35+
#define CP2112_REPORT_MAX_LENGTH 64
36+
#define CP2112_GPIO_CONFIG_LENGTH 5
37+
#define CP2112_GPIO_GET_LENGTH 2
38+
#define CP2112_GPIO_SET_LENGTH 3
39+
3540
enum {
3641
CP2112_GPIO_CONFIG = 0x02,
3742
CP2112_GPIO_GET = 0x03,
@@ -161,6 +166,8 @@ struct cp2112_device {
161166
atomic_t read_avail;
162167
atomic_t xfer_avail;
163168
struct gpio_chip gc;
169+
u8 *in_out_buffer;
170+
spinlock_t lock;
164171
};
165172

166173
static int gpio_push_pull = 0xFF;
@@ -171,97 +178,131 @@ static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
171178
{
172179
struct cp2112_device *dev = gpiochip_get_data(chip);
173180
struct hid_device *hdev = dev->hdev;
174-
u8 buf[5];
181+
u8 *buf = dev->in_out_buffer;
182+
unsigned long flags;
175183
int ret;
176184

185+
spin_lock_irqsave(&dev->lock, flags);
186+
177187
ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf,
178-
sizeof(buf), HID_FEATURE_REPORT,
179-
HID_REQ_GET_REPORT);
180-
if (ret != sizeof(buf)) {
188+
CP2112_GPIO_CONFIG_LENGTH, HID_FEATURE_REPORT,
189+
HID_REQ_GET_REPORT);
190+
if (ret != CP2112_GPIO_CONFIG_LENGTH) {
181191
hid_err(hdev, "error requesting GPIO config: %d\n", ret);
182-
return ret;
192+
goto exit;
183193
}
184194

185195
buf[1] &= ~(1 << offset);
186196
buf[2] = gpio_push_pull;
187197

188-
ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf, sizeof(buf),
189-
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
198+
ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf,
199+
CP2112_GPIO_CONFIG_LENGTH, HID_FEATURE_REPORT,
200+
HID_REQ_SET_REPORT);
190201
if (ret < 0) {
191202
hid_err(hdev, "error setting GPIO config: %d\n", ret);
192-
return ret;
203+
goto exit;
193204
}
194205

195-
return 0;
206+
ret = 0;
207+
208+
exit:
209+
spin_unlock_irqrestore(&dev->lock, flags);
210+
return ret <= 0 ? ret : -EIO;
196211
}
197212

198213
static void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
199214
{
200215
struct cp2112_device *dev = gpiochip_get_data(chip);
201216
struct hid_device *hdev = dev->hdev;
202-
u8 buf[3];
217+
u8 *buf = dev->in_out_buffer;
218+
unsigned long flags;
203219
int ret;
204220

221+
spin_lock_irqsave(&dev->lock, flags);
222+
205223
buf[0] = CP2112_GPIO_SET;
206224
buf[1] = value ? 0xff : 0;
207225
buf[2] = 1 << offset;
208226

209-
ret = hid_hw_raw_request(hdev, CP2112_GPIO_SET, buf, sizeof(buf),
210-
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
227+
ret = hid_hw_raw_request(hdev, CP2112_GPIO_SET, buf,
228+
CP2112_GPIO_SET_LENGTH, HID_FEATURE_REPORT,
229+
HID_REQ_SET_REPORT);
211230
if (ret < 0)
212231
hid_err(hdev, "error setting GPIO values: %d\n", ret);
232+
233+
spin_unlock_irqrestore(&dev->lock, flags);
213234
}
214235

215236
static int cp2112_gpio_get(struct gpio_chip *chip, unsigned offset)
216237
{
217238
struct cp2112_device *dev = gpiochip_get_data(chip);
218239
struct hid_device *hdev = dev->hdev;
219-
u8 buf[2];
240+
u8 *buf = dev->in_out_buffer;
241+
unsigned long flags;
220242
int ret;
221243

222-
ret = hid_hw_raw_request(hdev, CP2112_GPIO_GET, buf, sizeof(buf),
223-
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
224-
if (ret != sizeof(buf)) {
244+
spin_lock_irqsave(&dev->lock, flags);
245+
246+
ret = hid_hw_raw_request(hdev, CP2112_GPIO_GET, buf,
247+
CP2112_GPIO_GET_LENGTH, HID_FEATURE_REPORT,
248+
HID_REQ_GET_REPORT);
249+
if (ret != CP2112_GPIO_GET_LENGTH) {
225250
hid_err(hdev, "error requesting GPIO values: %d\n", ret);
226-
return ret;
251+
ret = ret < 0 ? ret : -EIO;
252+
goto exit;
227253
}
228254

229-
return (buf[1] >> offset) & 1;
255+
ret = (buf[1] >> offset) & 1;
256+
257+
exit:
258+
spin_unlock_irqrestore(&dev->lock, flags);
259+
260+
return ret;
230261
}
231262

232263
static int cp2112_gpio_direction_output(struct gpio_chip *chip,
233264
unsigned offset, int value)
234265
{
235266
struct cp2112_device *dev = gpiochip_get_data(chip);
236267
struct hid_device *hdev = dev->hdev;
237-
u8 buf[5];
268+
u8 *buf = dev->in_out_buffer;
269+
unsigned long flags;
238270
int ret;
239271

272+
spin_lock_irqsave(&dev->lock, flags);
273+
240274
ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf,
241-
sizeof(buf), HID_FEATURE_REPORT,
242-
HID_REQ_GET_REPORT);
243-
if (ret != sizeof(buf)) {
275+
CP2112_GPIO_CONFIG_LENGTH, HID_FEATURE_REPORT,
276+
HID_REQ_GET_REPORT);
277+
if (ret != CP2112_GPIO_CONFIG_LENGTH) {
244278
hid_err(hdev, "error requesting GPIO config: %d\n", ret);
245-
return ret;
279+
goto fail;
246280
}
247281

248282
buf[1] |= 1 << offset;
249283
buf[2] = gpio_push_pull;
250284

251-
ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf, sizeof(buf),
252-
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
285+
ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf,
286+
CP2112_GPIO_CONFIG_LENGTH, HID_FEATURE_REPORT,
287+
HID_REQ_SET_REPORT);
253288
if (ret < 0) {
254289
hid_err(hdev, "error setting GPIO config: %d\n", ret);
255-
return ret;
290+
goto fail;
256291
}
257292

293+
spin_unlock_irqrestore(&dev->lock, flags);
294+
258295
/*
259296
* Set gpio value when output direction is already set,
260297
* as specified in AN495, Rev. 0.2, cpt. 4.4
261298
*/
262299
cp2112_gpio_set(chip, offset, value);
263300

264301
return 0;
302+
303+
fail:
304+
spin_unlock_irqrestore(&dev->lock, flags);
305+
return ret < 0 ? ret : -EIO;
265306
}
266307

267308
static int cp2112_hid_get(struct hid_device *hdev, unsigned char report_number,
@@ -1007,6 +1048,17 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
10071048
struct cp2112_smbus_config_report config;
10081049
int ret;
10091050

1051+
dev = devm_kzalloc(&hdev->dev, sizeof(*dev), GFP_KERNEL);
1052+
if (!dev)
1053+
return -ENOMEM;
1054+
1055+
dev->in_out_buffer = devm_kzalloc(&hdev->dev, CP2112_REPORT_MAX_LENGTH,
1056+
GFP_KERNEL);
1057+
if (!dev->in_out_buffer)
1058+
return -ENOMEM;
1059+
1060+
spin_lock_init(&dev->lock);
1061+
10101062
ret = hid_parse(hdev);
10111063
if (ret) {
10121064
hid_err(hdev, "parse failed\n");
@@ -1063,12 +1115,6 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
10631115
goto err_power_normal;
10641116
}
10651117

1066-
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1067-
if (!dev) {
1068-
ret = -ENOMEM;
1069-
goto err_power_normal;
1070-
}
1071-
10721118
hid_set_drvdata(hdev, (void *)dev);
10731119
dev->hdev = hdev;
10741120
dev->adap.owner = THIS_MODULE;
@@ -1087,7 +1133,7 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
10871133

10881134
if (ret) {
10891135
hid_err(hdev, "error registering i2c adapter\n");
1090-
goto err_free_dev;
1136+
goto err_power_normal;
10911137
}
10921138

10931139
hid_dbg(hdev, "adapter registered\n");
@@ -1123,8 +1169,6 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
11231169
gpiochip_remove(&dev->gc);
11241170
err_free_i2c:
11251171
i2c_del_adapter(&dev->adap);
1126-
err_free_dev:
1127-
kfree(dev);
11281172
err_power_normal:
11291173
hid_hw_power(hdev, PM_HINT_NORMAL);
11301174
err_hid_close:
@@ -1149,7 +1193,6 @@ static void cp2112_remove(struct hid_device *hdev)
11491193
*/
11501194
hid_hw_close(hdev);
11511195
hid_hw_stop(hdev);
1152-
kfree(dev);
11531196
}
11541197

11551198
static int cp2112_raw_event(struct hid_device *hdev, struct hid_report *report,

0 commit comments

Comments
 (0)