diff options
| author | Benjamin Tissoires <benjamin.tissoires@redhat.com> | 2016-11-21 05:48:39 -0500 |
|---|---|---|
| committer | Jiri Kosina <jkosina@suse.cz> | 2016-11-23 11:38:12 -0500 |
| commit | 1ffb3c40ffb5c51bc39736409b11816c4260218e (patch) | |
| tree | 68eff7671b986b67cbcbab2b5c9f7739be0228dc /drivers/hid | |
| parent | 4c4480aad0d8eaf0d52b6f2c8c5dfbe0531cbbea (diff) | |
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>
Diffstat (limited to 'drivers/hid')
| -rw-r--r-- | drivers/hid/hid-cp2112.c | 115 |
1 files changed, 79 insertions, 36 deletions
diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c index 086d8a507157..60d30203a5fa 100644 --- a/drivers/hid/hid-cp2112.c +++ b/drivers/hid/hid-cp2112.c | |||
| @@ -32,6 +32,11 @@ | |||
| 32 | #include <linux/usb/ch9.h> | 32 | #include <linux/usb/ch9.h> |
| 33 | #include "hid-ids.h" | 33 | #include "hid-ids.h" |
| 34 | 34 | ||
| 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 | |||
| 35 | enum { | 40 | enum { |
| 36 | CP2112_GPIO_CONFIG = 0x02, | 41 | CP2112_GPIO_CONFIG = 0x02, |
| 37 | CP2112_GPIO_GET = 0x03, | 42 | CP2112_GPIO_GET = 0x03, |
| @@ -161,6 +166,8 @@ struct cp2112_device { | |||
| 161 | atomic_t read_avail; | 166 | atomic_t read_avail; |
| 162 | atomic_t xfer_avail; | 167 | atomic_t xfer_avail; |
| 163 | struct gpio_chip gc; | 168 | struct gpio_chip gc; |
| 169 | u8 *in_out_buffer; | ||
| 170 | spinlock_t lock; | ||
| 164 | }; | 171 | }; |
| 165 | 172 | ||
| 166 | static int gpio_push_pull = 0xFF; | 173 | static int gpio_push_pull = 0xFF; |
| @@ -171,62 +178,86 @@ static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | |||
| 171 | { | 178 | { |
| 172 | struct cp2112_device *dev = gpiochip_get_data(chip); | 179 | struct cp2112_device *dev = gpiochip_get_data(chip); |
| 173 | struct hid_device *hdev = dev->hdev; | 180 | struct hid_device *hdev = dev->hdev; |
| 174 | u8 buf[5]; | 181 | u8 *buf = dev->in_out_buffer; |
| 182 | unsigned long flags; | ||
| 175 | int ret; | 183 | int ret; |
| 176 | 184 | ||
| 185 | spin_lock_irqsave(&dev->lock, flags); | ||
| 186 | |||
| 177 | ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf, | 187 | ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf, |
| 178 | sizeof(buf), HID_FEATURE_REPORT, | 188 | CP2112_GPIO_CONFIG_LENGTH, HID_FEATURE_REPORT, |
| 179 | HID_REQ_GET_REPORT); | 189 | HID_REQ_GET_REPORT); |
| 180 | if (ret != sizeof(buf)) { | 190 | if (ret != CP2112_GPIO_CONFIG_LENGTH) { |
| 181 | hid_err(hdev, "error requesting GPIO config: %d\n", ret); | 191 | hid_err(hdev, "error requesting GPIO config: %d\n", ret); |
| 182 | return ret; | 192 | goto exit; |
| 183 | } | 193 | } |
| 184 | 194 | ||
| 185 | buf[1] &= ~(1 << offset); | 195 | buf[1] &= ~(1 << offset); |
| 186 | buf[2] = gpio_push_pull; | 196 | buf[2] = gpio_push_pull; |
| 187 | 197 | ||
| 188 | ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf, sizeof(buf), | 198 | ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf, |
| 189 | HID_FEATURE_REPORT, HID_REQ_SET_REPORT); | 199 | CP2112_GPIO_CONFIG_LENGTH, HID_FEATURE_REPORT, |
| 200 | HID_REQ_SET_REPORT); | ||
| 190 | if (ret < 0) { | 201 | if (ret < 0) { |
| 191 | hid_err(hdev, "error setting GPIO config: %d\n", ret); | 202 | hid_err(hdev, "error setting GPIO config: %d\n", ret); |
| 192 | return ret; | 203 | goto exit; |
| 193 | } | 204 | } |
| 194 | 205 | ||
| 195 | return 0; | 206 | ret = 0; |
| 207 | |||
| 208 | exit: | ||
| 209 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 210 | return ret <= 0 ? ret : -EIO; | ||
| 196 | } | 211 | } |
| 197 | 212 | ||
| 198 | static void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | 213 | static void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value) |
| 199 | { | 214 | { |
| 200 | struct cp2112_device *dev = gpiochip_get_data(chip); | 215 | struct cp2112_device *dev = gpiochip_get_data(chip); |
| 201 | struct hid_device *hdev = dev->hdev; | 216 | struct hid_device *hdev = dev->hdev; |
| 202 | u8 buf[3]; | 217 | u8 *buf = dev->in_out_buffer; |
| 218 | unsigned long flags; | ||
| 203 | int ret; | 219 | int ret; |
| 204 | 220 | ||
| 221 | spin_lock_irqsave(&dev->lock, flags); | ||
| 222 | |||
| 205 | buf[0] = CP2112_GPIO_SET; | 223 | buf[0] = CP2112_GPIO_SET; |
| 206 | buf[1] = value ? 0xff : 0; | 224 | buf[1] = value ? 0xff : 0; |
| 207 | buf[2] = 1 << offset; | 225 | buf[2] = 1 << offset; |
| 208 | 226 | ||
| 209 | ret = hid_hw_raw_request(hdev, CP2112_GPIO_SET, buf, sizeof(buf), | 227 | ret = hid_hw_raw_request(hdev, CP2112_GPIO_SET, buf, |
| 210 | HID_FEATURE_REPORT, HID_REQ_SET_REPORT); | 228 | CP2112_GPIO_SET_LENGTH, HID_FEATURE_REPORT, |
| 229 | HID_REQ_SET_REPORT); | ||
| 211 | if (ret < 0) | 230 | if (ret < 0) |
| 212 | hid_err(hdev, "error setting GPIO values: %d\n", ret); | 231 | hid_err(hdev, "error setting GPIO values: %d\n", ret); |
| 232 | |||
| 233 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 213 | } | 234 | } |
| 214 | 235 | ||
| 215 | static int cp2112_gpio_get(struct gpio_chip *chip, unsigned offset) | 236 | static int cp2112_gpio_get(struct gpio_chip *chip, unsigned offset) |
| 216 | { | 237 | { |
| 217 | struct cp2112_device *dev = gpiochip_get_data(chip); | 238 | struct cp2112_device *dev = gpiochip_get_data(chip); |
| 218 | struct hid_device *hdev = dev->hdev; | 239 | struct hid_device *hdev = dev->hdev; |
| 219 | u8 buf[2]; | 240 | u8 *buf = dev->in_out_buffer; |
| 241 | unsigned long flags; | ||
| 220 | int ret; | 242 | int ret; |
| 221 | 243 | ||
| 222 | ret = hid_hw_raw_request(hdev, CP2112_GPIO_GET, buf, sizeof(buf), | 244 | spin_lock_irqsave(&dev->lock, flags); |
| 223 | HID_FEATURE_REPORT, HID_REQ_GET_REPORT); | 245 | |
| 224 | if (ret != sizeof(buf)) { | 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) { | ||
| 225 | hid_err(hdev, "error requesting GPIO values: %d\n", ret); | 250 | hid_err(hdev, "error requesting GPIO values: %d\n", ret); |
| 226 | return ret; | 251 | ret = ret < 0 ? ret : -EIO; |
| 252 | goto exit; | ||
| 227 | } | 253 | } |
| 228 | 254 | ||
| 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; | ||
| 230 | } | 261 | } |
| 231 | 262 | ||
| 232 | static int cp2112_gpio_direction_output(struct gpio_chip *chip, | 263 | static int cp2112_gpio_direction_output(struct gpio_chip *chip, |
| @@ -234,27 +265,33 @@ static int cp2112_gpio_direction_output(struct gpio_chip *chip, | |||
| 234 | { | 265 | { |
| 235 | struct cp2112_device *dev = gpiochip_get_data(chip); | 266 | struct cp2112_device *dev = gpiochip_get_data(chip); |
| 236 | struct hid_device *hdev = dev->hdev; | 267 | struct hid_device *hdev = dev->hdev; |
| 237 | u8 buf[5]; | 268 | u8 *buf = dev->in_out_buffer; |
| 269 | unsigned long flags; | ||
| 238 | int ret; | 270 | int ret; |
| 239 | 271 | ||
| 272 | spin_lock_irqsave(&dev->lock, flags); | ||
| 273 | |||
| 240 | ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf, | 274 | ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf, |
| 241 | sizeof(buf), HID_FEATURE_REPORT, | 275 | CP2112_GPIO_CONFIG_LENGTH, HID_FEATURE_REPORT, |
| 242 | HID_REQ_GET_REPORT); | 276 | HID_REQ_GET_REPORT); |
| 243 | if (ret != sizeof(buf)) { | 277 | if (ret != CP2112_GPIO_CONFIG_LENGTH) { |
| 244 | hid_err(hdev, "error requesting GPIO config: %d\n", ret); | 278 | hid_err(hdev, "error requesting GPIO config: %d\n", ret); |
| 245 | return ret; | 279 | goto fail; |
| 246 | } | 280 | } |
| 247 | 281 | ||
| 248 | buf[1] |= 1 << offset; | 282 | buf[1] |= 1 << offset; |
| 249 | buf[2] = gpio_push_pull; | 283 | buf[2] = gpio_push_pull; |
| 250 | 284 | ||
| 251 | ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf, sizeof(buf), | 285 | ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf, |
| 252 | HID_FEATURE_REPORT, HID_REQ_SET_REPORT); | 286 | CP2112_GPIO_CONFIG_LENGTH, HID_FEATURE_REPORT, |
| 287 | HID_REQ_SET_REPORT); | ||
| 253 | if (ret < 0) { | 288 | if (ret < 0) { |
| 254 | hid_err(hdev, "error setting GPIO config: %d\n", ret); | 289 | hid_err(hdev, "error setting GPIO config: %d\n", ret); |
| 255 | return ret; | 290 | goto fail; |
| 256 | } | 291 | } |
| 257 | 292 | ||
| 293 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 294 | |||
| 258 | /* | 295 | /* |
| 259 | * Set gpio value when output direction is already set, | 296 | * Set gpio value when output direction is already set, |
| 260 | * as specified in AN495, Rev. 0.2, cpt. 4.4 | 297 | * as specified in AN495, Rev. 0.2, cpt. 4.4 |
| @@ -262,6 +299,10 @@ static int cp2112_gpio_direction_output(struct gpio_chip *chip, | |||
| 262 | cp2112_gpio_set(chip, offset, value); | 299 | cp2112_gpio_set(chip, offset, value); |
| 263 | 300 | ||
| 264 | return 0; | 301 | return 0; |
| 302 | |||
| 303 | fail: | ||
| 304 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 305 | return ret < 0 ? ret : -EIO; | ||
| 265 | } | 306 | } |
| 266 | 307 | ||
| 267 | static int cp2112_hid_get(struct hid_device *hdev, unsigned char report_number, | 308 | 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) | |||
| 1007 | struct cp2112_smbus_config_report config; | 1048 | struct cp2112_smbus_config_report config; |
| 1008 | int ret; | 1049 | int ret; |
| 1009 | 1050 | ||
| 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 | |||
| 1010 | ret = hid_parse(hdev); | 1062 | ret = hid_parse(hdev); |
| 1011 | if (ret) { | 1063 | if (ret) { |
| 1012 | hid_err(hdev, "parse failed\n"); | 1064 | hid_err(hdev, "parse failed\n"); |
| @@ -1063,12 +1115,6 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
| 1063 | goto err_power_normal; | 1115 | goto err_power_normal; |
| 1064 | } | 1116 | } |
| 1065 | 1117 | ||
| 1066 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
| 1067 | if (!dev) { | ||
| 1068 | ret = -ENOMEM; | ||
| 1069 | goto err_power_normal; | ||
| 1070 | } | ||
| 1071 | |||
| 1072 | hid_set_drvdata(hdev, (void *)dev); | 1118 | hid_set_drvdata(hdev, (void *)dev); |
| 1073 | dev->hdev = hdev; | 1119 | dev->hdev = hdev; |
| 1074 | dev->adap.owner = THIS_MODULE; | 1120 | dev->adap.owner = THIS_MODULE; |
| @@ -1087,7 +1133,7 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
| 1087 | 1133 | ||
| 1088 | if (ret) { | 1134 | if (ret) { |
| 1089 | hid_err(hdev, "error registering i2c adapter\n"); | 1135 | hid_err(hdev, "error registering i2c adapter\n"); |
| 1090 | goto err_free_dev; | 1136 | goto err_power_normal; |
| 1091 | } | 1137 | } |
| 1092 | 1138 | ||
| 1093 | hid_dbg(hdev, "adapter registered\n"); | 1139 | hid_dbg(hdev, "adapter registered\n"); |
| @@ -1123,8 +1169,6 @@ err_gpiochip_remove: | |||
| 1123 | gpiochip_remove(&dev->gc); | 1169 | gpiochip_remove(&dev->gc); |
| 1124 | err_free_i2c: | 1170 | err_free_i2c: |
| 1125 | i2c_del_adapter(&dev->adap); | 1171 | i2c_del_adapter(&dev->adap); |
| 1126 | err_free_dev: | ||
| 1127 | kfree(dev); | ||
| 1128 | err_power_normal: | 1172 | err_power_normal: |
| 1129 | hid_hw_power(hdev, PM_HINT_NORMAL); | 1173 | hid_hw_power(hdev, PM_HINT_NORMAL); |
| 1130 | err_hid_close: | 1174 | err_hid_close: |
| @@ -1149,7 +1193,6 @@ static void cp2112_remove(struct hid_device *hdev) | |||
| 1149 | */ | 1193 | */ |
| 1150 | hid_hw_close(hdev); | 1194 | hid_hw_close(hdev); |
| 1151 | hid_hw_stop(hdev); | 1195 | hid_hw_stop(hdev); |
| 1152 | kfree(dev); | ||
| 1153 | } | 1196 | } |
| 1154 | 1197 | ||
| 1155 | static int cp2112_raw_event(struct hid_device *hdev, struct hid_report *report, | 1198 | static int cp2112_raw_event(struct hid_device *hdev, struct hid_report *report, |
