Bug

[В начало]

Ошибка # 60

Показать/спрятать трассу ошибок
Error trace
Function bodies
Blocks
  • Others...
    Function bodies without model function calls
    Initialization function calls
    Initialization function bodies
    Entry point
    Entry point body
    Function calls
    Skipped function calls
    Formal parameter names
    Declarations
    Assumes
    Assume conditions
    Returns
    Return values
    DEG initialization
    DEG function calls
    Model function calls
    Model function bodies
    Model asserts
    Model state changes
    Model function function calls
    Model function function bodies
    Model returns
    Model others
    Identation
    Line numbers
    Expand signs
-entry_point
{
892 -ldv_s_lenovo_driver_hid_driver = 0;
LDV_IN_INTERRUPT = 1;
891 ldv_initialize() { /* Function call is skipped due to function is undefined */}
896 tmp___0 = nondet_int() { /* Function call is skipped due to function is undefined */}
896 assume(tmp___0 != 0);
900 tmp = nondet_int() { /* Function call is skipped due to function is undefined */}
902 assume(tmp == 0);
905 assume(ldv_s_lenovo_driver_hid_driver == 0);
913 +res_lenovo_probe_27 = lenovo_probe(var_group1 /* hdev */, var_lenovo_probe_27_p1 /* id */)
914 ldv_check_return_value(res_lenovo_probe_27) { /* Function call is skipped due to function is undefined */}
915 ldv_check_return_value_probe(res_lenovo_probe_27) { /* Function call is skipped due to function is undefined */}
916 assume(res_lenovo_probe_27 == 0);
918 ldv_s_lenovo_driver_hid_driver = ldv_s_lenovo_driver_hid_driver + 1;
896 tmp___0 = nondet_int() { /* Function call is skipped due to function is undefined */}
896 assume(tmp___0 != 0);
900 tmp = nondet_int() { /* Function call is skipped due to function is undefined */}
902 assume(tmp != 0);
925 assume(tmp == 1);
928 assume(ldv_s_lenovo_driver_hid_driver == 1);
936 ldv_handler_precall() { /* Function call is skipped due to function is undefined */}
937 -lenovo_remove(var_group1 /* hdev */)
{
754 assume(*(hdev).product != 24585);
757 assume(*(hdev).product == 24647);
759 -lenovo_remove_cptkbd(hdev /* hdev */)
{
747 -ldv_sysfs_remove_group_8(&(&(hdev)->dev)->kobj /* ldv_func_arg1 */, &(lenovo_attr_group_cptkbd) /* ldv_func_arg2 */)
{
117 -ldv_sysfs_remove_group(ldv_func_arg1 /* kobj */, ldv_func_arg2 /* grp */)
{
30 LDV_SYSFS_GROUPS = LDV_SYSFS_GROUPS + -1;
29 return ;
}
114 return ;
}
745 return ;
}
763 +hid_hw_stop(hdev /* hdev */)
751 return ;
}
938 ldv_s_lenovo_driver_hid_driver = 0;
896 tmp___0 = nondet_int() { /* Function call is skipped due to function is undefined */}
896 assume(tmp___0 == 0);
896 assume(ldv_s_lenovo_driver_hid_driver == 0);
996 +ldv_check_final_state()
}
Source code
1 2 /* 3 * HID driver for Lenovo: 4 * - ThinkPad USB Keyboard with TrackPoint (tpkbd) 5 * - ThinkPad Compact Bluetooth Keyboard with TrackPoint (cptkbd) 6 * - ThinkPad Compact USB Keyboard with TrackPoint (cptkbd) 7 * 8 * Copyright (c) 2012 Bernhard Seibold 9 * Copyright (c) 2014 Jamie Lentin <jm@lentin.co.uk> 10 */ 11 12 /* 13 * This program is free software; you can redistribute it and/or modify it 14 * under the terms of the GNU General Public License as published by the Free 15 * Software Foundation; either version 2 of the License, or (at your option) 16 * any later version. 17 */ 18 19 #include <linux/module.h> 20 #include <linux/sysfs.h> 21 #include <linux/device.h> 22 #include <linux/hid.h> 23 #include <linux/input.h> 24 #include <linux/leds.h> 25 26 #include "hid-ids.h" 27 28 struct lenovo_drvdata_tpkbd { 29 int led_state; 30 struct led_classdev led_mute; 31 struct led_classdev led_micmute; 32 int press_to_select; 33 int dragging; 34 int release_to_select; 35 int select_right; 36 int sensitivity; 37 int press_speed; 38 }; 39 40 struct lenovo_drvdata_cptkbd { 41 bool fn_lock; 42 int sensitivity; 43 }; 44 45 #define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) 46 47 static int lenovo_input_mapping_tpkbd(struct hid_device *hdev, 48 struct hid_input *hi, struct hid_field *field, 49 struct hid_usage *usage, unsigned long **bit, int *max) 50 { 51 if (usage->hid == (HID_UP_BUTTON | 0x0010)) { 52 /* This sub-device contains trackpoint, mark it */ 53 hid_set_drvdata(hdev, (void *)1); 54 map_key_clear(KEY_MICMUTE); 55 return 1; 56 } 57 return 0; 58 } 59 60 static int lenovo_input_mapping_cptkbd(struct hid_device *hdev, 61 struct hid_input *hi, struct hid_field *field, 62 struct hid_usage *usage, unsigned long **bit, int *max) 63 { 64 /* HID_UP_LNVENDOR = USB, HID_UP_MSVENDOR = BT */ 65 if ((usage->hid & HID_USAGE_PAGE) == HID_UP_MSVENDOR || 66 (usage->hid & HID_USAGE_PAGE) == HID_UP_LNVENDOR) { 67 switch (usage->hid & HID_USAGE) { 68 case 0x00f1: /* Fn-F4: Mic mute */ 69 map_key_clear(KEY_MICMUTE); 70 return 1; 71 case 0x00f2: /* Fn-F5: Brightness down */ 72 map_key_clear(KEY_BRIGHTNESSDOWN); 73 return 1; 74 case 0x00f3: /* Fn-F6: Brightness up */ 75 map_key_clear(KEY_BRIGHTNESSUP); 76 return 1; 77 case 0x00f4: /* Fn-F7: External display (projector) */ 78 map_key_clear(KEY_SWITCHVIDEOMODE); 79 return 1; 80 case 0x00f5: /* Fn-F8: Wireless */ 81 map_key_clear(KEY_WLAN); 82 return 1; 83 case 0x00f6: /* Fn-F9: Control panel */ 84 map_key_clear(KEY_CONFIG); 85 return 1; 86 case 0x00f8: /* Fn-F11: View open applications (3 boxes) */ 87 map_key_clear(KEY_SCALE); 88 return 1; 89 case 0x00f9: /* Fn-F12: Open My computer (6 boxes) USB-only */ 90 /* NB: This mapping is invented in raw_event below */ 91 map_key_clear(KEY_FILE); 92 return 1; 93 case 0x00fa: /* Fn-Esc: Fn-lock toggle */ 94 map_key_clear(KEY_FN_ESC); 95 return 1; 96 case 0x00fb: /* Middle mouse button (in native mode) */ 97 map_key_clear(BTN_MIDDLE); 98 return 1; 99 } 100 } 101 102 /* Compatibility middle/wheel mappings should be ignored */ 103 if (usage->hid == HID_GD_WHEEL) 104 return -1; 105 if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON && 106 (usage->hid & HID_USAGE) == 0x003) 107 return -1; 108 if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER && 109 (usage->hid & HID_USAGE) == 0x238) 110 return -1; 111 112 /* Map wheel emulation reports: 0xffa1 = USB, 0xff10 = BT */ 113 if ((usage->hid & HID_USAGE_PAGE) == 0xff100000 || 114 (usage->hid & HID_USAGE_PAGE) == 0xffa10000) { 115 field->flags |= HID_MAIN_ITEM_RELATIVE | HID_MAIN_ITEM_VARIABLE; 116 field->logical_minimum = -127; 117 field->logical_maximum = 127; 118 119 switch (usage->hid & HID_USAGE) { 120 case 0x0000: 121 hid_map_usage(hi, usage, bit, max, EV_REL, 0x06); 122 return 1; 123 case 0x0001: 124 hid_map_usage(hi, usage, bit, max, EV_REL, 0x08); 125 return 1; 126 default: 127 return -1; 128 } 129 } 130 131 return 0; 132 } 133 134 static int lenovo_input_mapping(struct hid_device *hdev, 135 struct hid_input *hi, struct hid_field *field, 136 struct hid_usage *usage, unsigned long **bit, int *max) 137 { 138 switch (hdev->product) { 139 case USB_DEVICE_ID_LENOVO_TPKBD: 140 return lenovo_input_mapping_tpkbd(hdev, hi, field, 141 usage, bit, max); 142 case USB_DEVICE_ID_LENOVO_CUSBKBD: 143 case USB_DEVICE_ID_LENOVO_CBTKBD: 144 return lenovo_input_mapping_cptkbd(hdev, hi, field, 145 usage, bit, max); 146 default: 147 return 0; 148 } 149 } 150 151 #undef map_key_clear 152 153 /* Send a config command to the keyboard */ 154 static int lenovo_send_cmd_cptkbd(struct hid_device *hdev, 155 unsigned char byte2, unsigned char byte3) 156 { 157 int ret; 158 unsigned char buf[] = {0x18, byte2, byte3}; 159 160 switch (hdev->product) { 161 case USB_DEVICE_ID_LENOVO_CUSBKBD: 162 ret = hid_hw_raw_request(hdev, 0x13, buf, sizeof(buf), 163 HID_FEATURE_REPORT, HID_REQ_SET_REPORT); 164 break; 165 case USB_DEVICE_ID_LENOVO_CBTKBD: 166 ret = hid_hw_output_report(hdev, buf, sizeof(buf)); 167 break; 168 default: 169 ret = -EINVAL; 170 break; 171 } 172 173 return ret < 0 ? ret : 0; /* BT returns 0, USB returns sizeof(buf) */ 174 } 175 176 static void lenovo_features_set_cptkbd(struct hid_device *hdev) 177 { 178 int ret; 179 struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev); 180 181 ret = lenovo_send_cmd_cptkbd(hdev, 0x05, cptkbd_data->fn_lock); 182 ret = lenovo_send_cmd_cptkbd(hdev, 0x02, cptkbd_data->sensitivity); 183 if (ret) 184 hid_err(hdev, "Fn-lock setting failed: %d\n", ret); 185 } 186 187 static ssize_t attr_fn_lock_show_cptkbd(struct device *dev, 188 struct device_attribute *attr, 189 char *buf) 190 { 191 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 192 struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev); 193 194 return snprintf(buf, PAGE_SIZE, "%u\n", cptkbd_data->fn_lock); 195 } 196 197 static ssize_t attr_fn_lock_store_cptkbd(struct device *dev, 198 struct device_attribute *attr, 199 const char *buf, 200 size_t count) 201 { 202 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 203 struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev); 204 int value; 205 206 if (kstrtoint(buf, 10, &value)) 207 return -EINVAL; 208 if (value < 0 || value > 1) 209 return -EINVAL; 210 211 cptkbd_data->fn_lock = !!value; 212 lenovo_features_set_cptkbd(hdev); 213 214 return count; 215 } 216 217 static ssize_t attr_sensitivity_show_cptkbd(struct device *dev, 218 struct device_attribute *attr, 219 char *buf) 220 { 221 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 222 struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev); 223 224 return snprintf(buf, PAGE_SIZE, "%u\n", 225 cptkbd_data->sensitivity); 226 } 227 228 static ssize_t attr_sensitivity_store_cptkbd(struct device *dev, 229 struct device_attribute *attr, 230 const char *buf, 231 size_t count) 232 { 233 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 234 struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev); 235 int value; 236 237 if (kstrtoint(buf, 10, &value) || value < 1 || value > 255) 238 return -EINVAL; 239 240 cptkbd_data->sensitivity = value; 241 lenovo_features_set_cptkbd(hdev); 242 243 return count; 244 } 245 246 247 static struct device_attribute dev_attr_fn_lock_cptkbd = 248 __ATTR(fn_lock, S_IWUSR | S_IRUGO, 249 attr_fn_lock_show_cptkbd, 250 attr_fn_lock_store_cptkbd); 251 252 static struct device_attribute dev_attr_sensitivity_cptkbd = 253 __ATTR(sensitivity, S_IWUSR | S_IRUGO, 254 attr_sensitivity_show_cptkbd, 255 attr_sensitivity_store_cptkbd); 256 257 258 static struct attribute *lenovo_attributes_cptkbd[] = { 259 &dev_attr_fn_lock_cptkbd.attr, 260 &dev_attr_sensitivity_cptkbd.attr, 261 NULL 262 }; 263 264 static const struct attribute_group lenovo_attr_group_cptkbd = { 265 .attrs = lenovo_attributes_cptkbd, 266 }; 267 268 static int lenovo_raw_event(struct hid_device *hdev, 269 struct hid_report *report, u8 *data, int size) 270 { 271 /* 272 * Compact USB keyboard's Fn-F12 report holds down many other keys, and 273 * its own key is outside the usage page range. Remove extra 274 * keypresses and remap to inside usage page. 275 */ 276 if (unlikely(hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD 277 && size == 3 278 && data[0] == 0x15 279 && data[1] == 0x94 280 && data[2] == 0x01)) { 281 data[1] = 0x00; 282 data[2] = 0x01; 283 } 284 285 return 0; 286 } 287 288 static int lenovo_features_set_tpkbd(struct hid_device *hdev) 289 { 290 struct hid_report *report; 291 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); 292 293 report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[4]; 294 295 report->field[0]->value[0] = data_pointer->press_to_select ? 0x01 : 0x02; 296 report->field[0]->value[0] |= data_pointer->dragging ? 0x04 : 0x08; 297 report->field[0]->value[0] |= data_pointer->release_to_select ? 0x10 : 0x20; 298 report->field[0]->value[0] |= data_pointer->select_right ? 0x80 : 0x40; 299 report->field[1]->value[0] = 0x03; // unknown setting, imitate windows driver 300 report->field[2]->value[0] = data_pointer->sensitivity; 301 report->field[3]->value[0] = data_pointer->press_speed; 302 303 hid_hw_request(hdev, report, HID_REQ_SET_REPORT); 304 return 0; 305 } 306 307 static ssize_t attr_press_to_select_show_tpkbd(struct device *dev, 308 struct device_attribute *attr, 309 char *buf) 310 { 311 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 312 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); 313 314 return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->press_to_select); 315 } 316 317 static ssize_t attr_press_to_select_store_tpkbd(struct device *dev, 318 struct device_attribute *attr, 319 const char *buf, 320 size_t count) 321 { 322 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 323 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); 324 int value; 325 326 if (kstrtoint(buf, 10, &value)) 327 return -EINVAL; 328 if (value < 0 || value > 1) 329 return -EINVAL; 330 331 data_pointer->press_to_select = value; 332 lenovo_features_set_tpkbd(hdev); 333 334 return count; 335 } 336 337 static ssize_t attr_dragging_show_tpkbd(struct device *dev, 338 struct device_attribute *attr, 339 char *buf) 340 { 341 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 342 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); 343 344 return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->dragging); 345 } 346 347 static ssize_t attr_dragging_store_tpkbd(struct device *dev, 348 struct device_attribute *attr, 349 const char *buf, 350 size_t count) 351 { 352 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 353 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); 354 int value; 355 356 if (kstrtoint(buf, 10, &value)) 357 return -EINVAL; 358 if (value < 0 || value > 1) 359 return -EINVAL; 360 361 data_pointer->dragging = value; 362 lenovo_features_set_tpkbd(hdev); 363 364 return count; 365 } 366 367 static ssize_t attr_release_to_select_show_tpkbd(struct device *dev, 368 struct device_attribute *attr, 369 char *buf) 370 { 371 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 372 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); 373 374 return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->release_to_select); 375 } 376 377 static ssize_t attr_release_to_select_store_tpkbd(struct device *dev, 378 struct device_attribute *attr, 379 const char *buf, 380 size_t count) 381 { 382 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 383 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); 384 int value; 385 386 if (kstrtoint(buf, 10, &value)) 387 return -EINVAL; 388 if (value < 0 || value > 1) 389 return -EINVAL; 390 391 data_pointer->release_to_select = value; 392 lenovo_features_set_tpkbd(hdev); 393 394 return count; 395 } 396 397 static ssize_t attr_select_right_show_tpkbd(struct device *dev, 398 struct device_attribute *attr, 399 char *buf) 400 { 401 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 402 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); 403 404 return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->select_right); 405 } 406 407 static ssize_t attr_select_right_store_tpkbd(struct device *dev, 408 struct device_attribute *attr, 409 const char *buf, 410 size_t count) 411 { 412 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 413 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); 414 int value; 415 416 if (kstrtoint(buf, 10, &value)) 417 return -EINVAL; 418 if (value < 0 || value > 1) 419 return -EINVAL; 420 421 data_pointer->select_right = value; 422 lenovo_features_set_tpkbd(hdev); 423 424 return count; 425 } 426 427 static ssize_t attr_sensitivity_show_tpkbd(struct device *dev, 428 struct device_attribute *attr, 429 char *buf) 430 { 431 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 432 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); 433 434 return snprintf(buf, PAGE_SIZE, "%u\n", 435 data_pointer->sensitivity); 436 } 437 438 static ssize_t attr_sensitivity_store_tpkbd(struct device *dev, 439 struct device_attribute *attr, 440 const char *buf, 441 size_t count) 442 { 443 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 444 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); 445 int value; 446 447 if (kstrtoint(buf, 10, &value) || value < 1 || value > 255) 448 return -EINVAL; 449 450 data_pointer->sensitivity = value; 451 lenovo_features_set_tpkbd(hdev); 452 453 return count; 454 } 455 456 static ssize_t attr_press_speed_show_tpkbd(struct device *dev, 457 struct device_attribute *attr, 458 char *buf) 459 { 460 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 461 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); 462 463 return snprintf(buf, PAGE_SIZE, "%u\n", 464 data_pointer->press_speed); 465 } 466 467 static ssize_t attr_press_speed_store_tpkbd(struct device *dev, 468 struct device_attribute *attr, 469 const char *buf, 470 size_t count) 471 { 472 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 473 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); 474 int value; 475 476 if (kstrtoint(buf, 10, &value) || value < 1 || value > 255) 477 return -EINVAL; 478 479 data_pointer->press_speed = value; 480 lenovo_features_set_tpkbd(hdev); 481 482 return count; 483 } 484 485 static struct device_attribute dev_attr_press_to_select_tpkbd = 486 __ATTR(press_to_select, S_IWUSR | S_IRUGO, 487 attr_press_to_select_show_tpkbd, 488 attr_press_to_select_store_tpkbd); 489 490 static struct device_attribute dev_attr_dragging_tpkbd = 491 __ATTR(dragging, S_IWUSR | S_IRUGO, 492 attr_dragging_show_tpkbd, 493 attr_dragging_store_tpkbd); 494 495 static struct device_attribute dev_attr_release_to_select_tpkbd = 496 __ATTR(release_to_select, S_IWUSR | S_IRUGO, 497 attr_release_to_select_show_tpkbd, 498 attr_release_to_select_store_tpkbd); 499 500 static struct device_attribute dev_attr_select_right_tpkbd = 501 __ATTR(select_right, S_IWUSR | S_IRUGO, 502 attr_select_right_show_tpkbd, 503 attr_select_right_store_tpkbd); 504 505 static struct device_attribute dev_attr_sensitivity_tpkbd = 506 __ATTR(sensitivity, S_IWUSR | S_IRUGO, 507 attr_sensitivity_show_tpkbd, 508 attr_sensitivity_store_tpkbd); 509 510 static struct device_attribute dev_attr_press_speed_tpkbd = 511 __ATTR(press_speed, S_IWUSR | S_IRUGO, 512 attr_press_speed_show_tpkbd, 513 attr_press_speed_store_tpkbd); 514 515 static struct attribute *lenovo_attributes_tpkbd[] = { 516 &dev_attr_press_to_select_tpkbd.attr, 517 &dev_attr_dragging_tpkbd.attr, 518 &dev_attr_release_to_select_tpkbd.attr, 519 &dev_attr_select_right_tpkbd.attr, 520 &dev_attr_sensitivity_tpkbd.attr, 521 &dev_attr_press_speed_tpkbd.attr, 522 NULL 523 }; 524 525 static const struct attribute_group lenovo_attr_group_tpkbd = { 526 .attrs = lenovo_attributes_tpkbd, 527 }; 528 529 static enum led_brightness lenovo_led_brightness_get_tpkbd( 530 struct led_classdev *led_cdev) 531 { 532 struct device *dev = led_cdev->dev->parent; 533 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 534 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); 535 int led_nr = 0; 536 537 if (led_cdev == &data_pointer->led_micmute) 538 led_nr = 1; 539 540 return data_pointer->led_state & (1 << led_nr) 541 ? LED_FULL 542 : LED_OFF; 543 } 544 545 static void lenovo_led_brightness_set_tpkbd(struct led_classdev *led_cdev, 546 enum led_brightness value) 547 { 548 struct device *dev = led_cdev->dev->parent; 549 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 550 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); 551 struct hid_report *report; 552 int led_nr = 0; 553 554 if (led_cdev == &data_pointer->led_micmute) 555 led_nr = 1; 556 557 if (value == LED_OFF) 558 data_pointer->led_state &= ~(1 << led_nr); 559 else 560 data_pointer->led_state |= 1 << led_nr; 561 562 report = hdev->report_enum[HID_OUTPUT_REPORT].report_id_hash[3]; 563 report->field[0]->value[0] = (data_pointer->led_state >> 0) & 1; 564 report->field[0]->value[1] = (data_pointer->led_state >> 1) & 1; 565 hid_hw_request(hdev, report, HID_REQ_SET_REPORT); 566 } 567 568 static int lenovo_probe_tpkbd(struct hid_device *hdev) 569 { 570 struct device *dev = &hdev->dev; 571 struct lenovo_drvdata_tpkbd *data_pointer; 572 size_t name_sz = strlen(dev_name(dev)) + 16; 573 char *name_mute, *name_micmute; 574 int i; 575 int ret; 576 577 /* 578 * Only register extra settings against subdevice where input_mapping 579 * set drvdata to 1, i.e. the trackpoint. 580 */ 581 if (!hid_get_drvdata(hdev)) 582 return 0; 583 584 hid_set_drvdata(hdev, NULL); 585 586 /* Validate required reports. */ 587 for (i = 0; i < 4; i++) { 588 if (!hid_validate_values(hdev, HID_FEATURE_REPORT, 4, i, 1)) 589 return -ENODEV; 590 } 591 if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 3, 0, 2)) 592 return -ENODEV; 593 594 ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_tpkbd); 595 if (ret) 596 hid_warn(hdev, "Could not create sysfs group: %d\n", ret); 597 598 data_pointer = devm_kzalloc(&hdev->dev, 599 sizeof(struct lenovo_drvdata_tpkbd), 600 GFP_KERNEL); 601 if (data_pointer == NULL) { 602 hid_err(hdev, "Could not allocate memory for driver data\n"); 603 return -ENOMEM; 604 } 605 606 // set same default values as windows driver 607 data_pointer->sensitivity = 0xa0; 608 data_pointer->press_speed = 0x38; 609 610 name_mute = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL); 611 name_micmute = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL); 612 if (name_mute == NULL || name_micmute == NULL) { 613 hid_err(hdev, "Could not allocate memory for led data\n"); 614 return -ENOMEM; 615 } 616 snprintf(name_mute, name_sz, "%s:amber:mute", dev_name(dev)); 617 snprintf(name_micmute, name_sz, "%s:amber:micmute", dev_name(dev)); 618 619 hid_set_drvdata(hdev, data_pointer); 620 621 data_pointer->led_mute.name = name_mute; 622 data_pointer->led_mute.brightness_get = lenovo_led_brightness_get_tpkbd; 623 data_pointer->led_mute.brightness_set = lenovo_led_brightness_set_tpkbd; 624 data_pointer->led_mute.dev = dev; 625 led_classdev_register(dev, &data_pointer->led_mute); 626 627 data_pointer->led_micmute.name = name_micmute; 628 data_pointer->led_micmute.brightness_get = 629 lenovo_led_brightness_get_tpkbd; 630 data_pointer->led_micmute.brightness_set = 631 lenovo_led_brightness_set_tpkbd; 632 data_pointer->led_micmute.dev = dev; 633 led_classdev_register(dev, &data_pointer->led_micmute); 634 635 lenovo_features_set_tpkbd(hdev); 636 637 return 0; 638 } 639 640 static int lenovo_probe_cptkbd(struct hid_device *hdev) 641 { 642 int ret; 643 struct lenovo_drvdata_cptkbd *cptkbd_data; 644 645 /* All the custom action happens on the USBMOUSE device for USB */ 646 if (hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD 647 && hdev->type != HID_TYPE_USBMOUSE) { 648 hid_dbg(hdev, "Ignoring keyboard half of device\n"); 649 return 0; 650 } 651 652 cptkbd_data = devm_kzalloc(&hdev->dev, 653 sizeof(*cptkbd_data), 654 GFP_KERNEL); 655 if (cptkbd_data == NULL) { 656 hid_err(hdev, "can't alloc keyboard descriptor\n"); 657 return -ENOMEM; 658 } 659 hid_set_drvdata(hdev, cptkbd_data); 660 661 /* 662 * Tell the keyboard a driver understands it, and turn F7, F9, F11 into 663 * regular keys 664 */ 665 ret = lenovo_send_cmd_cptkbd(hdev, 0x01, 0x03); 666 if (ret) 667 hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret); 668 669 /* Switch middle button to native mode */ 670 ret = lenovo_send_cmd_cptkbd(hdev, 0x09, 0x01); 671 if (ret) 672 hid_warn(hdev, "Failed to switch middle button: %d\n", ret); 673 674 /* Set keyboard settings to known state */ 675 cptkbd_data->fn_lock = true; 676 cptkbd_data->sensitivity = 0x05; 677 lenovo_features_set_cptkbd(hdev); 678 679 ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_cptkbd); 680 if (ret) 681 hid_warn(hdev, "Could not create sysfs group: %d\n", ret); 682 683 return 0; 684 } 685 686 static int lenovo_probe(struct hid_device *hdev, 687 const struct hid_device_id *id) 688 { 689 int ret; 690 691 ret = hid_parse(hdev); 692 if (ret) { 693 hid_err(hdev, "hid_parse failed\n"); 694 goto err; 695 } 696 697 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 698 if (ret) { 699 hid_err(hdev, "hid_hw_start failed\n"); 700 goto err; 701 } 702 703 switch (hdev->product) { 704 case USB_DEVICE_ID_LENOVO_TPKBD: 705 ret = lenovo_probe_tpkbd(hdev); 706 break; 707 case USB_DEVICE_ID_LENOVO_CUSBKBD: 708 case USB_DEVICE_ID_LENOVO_CBTKBD: 709 ret = lenovo_probe_cptkbd(hdev); 710 break; 711 default: 712 ret = 0; 713 break; 714 } 715 if (ret) 716 goto err_hid; 717 718 return 0; 719 err_hid: 720 hid_hw_stop(hdev); 721 err: 722 return ret; 723 } 724 725 static void lenovo_remove_tpkbd(struct hid_device *hdev) 726 { 727 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); 728 729 /* 730 * Only the trackpoint half of the keyboard has drvdata and stuff that 731 * needs unregistering. 732 */ 733 if (data_pointer == NULL) 734 return; 735 736 sysfs_remove_group(&hdev->dev.kobj, 737 &lenovo_attr_group_tpkbd); 738 739 led_classdev_unregister(&data_pointer->led_micmute); 740 led_classdev_unregister(&data_pointer->led_mute); 741 742 hid_set_drvdata(hdev, NULL); 743 } 744 745 static void lenovo_remove_cptkbd(struct hid_device *hdev) 746 { 747 sysfs_remove_group(&hdev->dev.kobj, 748 &lenovo_attr_group_cptkbd); 749 } 750 751 static void lenovo_remove(struct hid_device *hdev) 752 { 753 switch (hdev->product) { 754 case USB_DEVICE_ID_LENOVO_TPKBD: 755 lenovo_remove_tpkbd(hdev); 756 break; 757 case USB_DEVICE_ID_LENOVO_CUSBKBD: 758 case USB_DEVICE_ID_LENOVO_CBTKBD: 759 lenovo_remove_cptkbd(hdev); 760 break; 761 } 762 763 hid_hw_stop(hdev); 764 } 765 766 static const struct hid_device_id lenovo_devices[] = { 767 { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) }, 768 { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CUSBKBD) }, 769 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CBTKBD) }, 770 { } 771 }; 772 773 MODULE_DEVICE_TABLE(hid, lenovo_devices); 774 775 static struct hid_driver lenovo_driver = { 776 .name = "lenovo", 777 .id_table = lenovo_devices, 778 .input_mapping = lenovo_input_mapping, 779 .probe = lenovo_probe, 780 .remove = lenovo_remove, 781 .raw_event = lenovo_raw_event, 782 }; 783 module_hid_driver(lenovo_driver); 784 785 MODULE_LICENSE("GPL"); 786 787 788 789 790 791 /* LDV_COMMENT_BEGIN_MAIN */ 792 #ifdef LDV_MAIN0_sequence_infinite_withcheck_stateful 793 794 /*###########################################################################*/ 795 796 /*############## Driver Environment Generator 0.2 output ####################*/ 797 798 /*###########################################################################*/ 799 800 801 802 /* LDV_COMMENT_FUNCTION_DECLARE_LDV Special function for LDV verifier. Test if all kernel resources are correctly released by driver before driver will be unloaded. */ 803 void ldv_check_final_state(void); 804 805 /* LDV_COMMENT_FUNCTION_DECLARE_LDV Special function for LDV verifier. Test correct return result. */ 806 void ldv_check_return_value(int res); 807 808 /* LDV_COMMENT_FUNCTION_DECLARE_LDV Special function for LDV verifier. Test correct return result of probe() function. */ 809 void ldv_check_return_value_probe(int res); 810 811 /* LDV_COMMENT_FUNCTION_DECLARE_LDV Special function for LDV verifier. Initializes the model. */ 812 void ldv_initialize(void); 813 814 /* LDV_COMMENT_FUNCTION_DECLARE_LDV Special function for LDV verifier. Reinitializes the model between distinct model function calls. */ 815 void ldv_handler_precall(void); 816 817 /* LDV_COMMENT_FUNCTION_DECLARE_LDV Special function for LDV verifier. Returns arbitrary interger value. */ 818 int nondet_int(void); 819 820 /* LDV_COMMENT_VAR_DECLARE_LDV Special variable for LDV verifier. */ 821 int LDV_IN_INTERRUPT; 822 823 /* LDV_COMMENT_FUNCTION_MAIN Main function for LDV verifier. */ 824 void ldv_main0_sequence_infinite_withcheck_stateful(void) { 825 826 827 828 /* LDV_COMMENT_BEGIN_VARIABLE_DECLARATION_PART */ 829 /*============================= VARIABLE DECLARATION PART =============================*/ 830 /** STRUCT: struct type: hid_driver, struct name: lenovo_driver **/ 831 /* content: static int lenovo_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max)*/ 832 /* LDV_COMMENT_BEGIN_PREP */ 833 #define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) 834 /* LDV_COMMENT_END_PREP */ 835 /* LDV_COMMENT_VAR_DECLARE Variable declaration for function "lenovo_input_mapping" */ 836 struct hid_device * var_group1; 837 /* LDV_COMMENT_VAR_DECLARE Variable declaration for function "lenovo_input_mapping" */ 838 struct hid_input * var_group2; 839 /* LDV_COMMENT_VAR_DECLARE Variable declaration for function "lenovo_input_mapping" */ 840 struct hid_field * var_lenovo_input_mapping_2_p2; 841 /* LDV_COMMENT_VAR_DECLARE Variable declaration for function "lenovo_input_mapping" */ 842 struct hid_usage * var_lenovo_input_mapping_2_p3; 843 /* LDV_COMMENT_VAR_DECLARE Variable declaration for function "lenovo_input_mapping" */ 844 unsigned long ** var_lenovo_input_mapping_2_p4; 845 /* LDV_COMMENT_VAR_DECLARE Variable declaration for function "lenovo_input_mapping" */ 846 int * var_lenovo_input_mapping_2_p5; 847 /* LDV_COMMENT_BEGIN_PREP */ 848 #undef map_key_clear 849 /* LDV_COMMENT_END_PREP */ 850 /* content: static int lenovo_probe(struct hid_device *hdev, const struct hid_device_id *id)*/ 851 /* LDV_COMMENT_BEGIN_PREP */ 852 #define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) 853 #undef map_key_clear 854 /* LDV_COMMENT_END_PREP */ 855 /* LDV_COMMENT_VAR_DECLARE Variable declaration for function "lenovo_probe" */ 856 const struct hid_device_id * var_lenovo_probe_27_p1; 857 /* LDV_COMMENT_VAR_DECLARE Variable declaration for test return result from function call "lenovo_probe" */ 858 static int res_lenovo_probe_27; 859 /* content: static void lenovo_remove(struct hid_device *hdev)*/ 860 /* LDV_COMMENT_BEGIN_PREP */ 861 #define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) 862 #undef map_key_clear 863 /* LDV_COMMENT_END_PREP */ 864 /* content: static int lenovo_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size)*/ 865 /* LDV_COMMENT_BEGIN_PREP */ 866 #define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) 867 #undef map_key_clear 868 /* LDV_COMMENT_END_PREP */ 869 /* LDV_COMMENT_VAR_DECLARE Variable declaration for function "lenovo_raw_event" */ 870 struct hid_report * var_group3; 871 /* LDV_COMMENT_VAR_DECLARE Variable declaration for function "lenovo_raw_event" */ 872 u8 * var_lenovo_raw_event_9_p2; 873 /* LDV_COMMENT_VAR_DECLARE Variable declaration for function "lenovo_raw_event" */ 874 int var_lenovo_raw_event_9_p3; 875 876 877 878 879 /* LDV_COMMENT_END_VARIABLE_DECLARATION_PART */ 880 /* LDV_COMMENT_BEGIN_VARIABLE_INITIALIZING_PART */ 881 /*============================= VARIABLE INITIALIZING PART =============================*/ 882 LDV_IN_INTERRUPT=1; 883 884 885 886 887 /* LDV_COMMENT_END_VARIABLE_INITIALIZING_PART */ 888 /* LDV_COMMENT_BEGIN_FUNCTION_CALL_SECTION */ 889 /*============================= FUNCTION CALL SECTION =============================*/ 890 /* LDV_COMMENT_FUNCTION_CALL Initialize LDV model. */ 891 ldv_initialize(); 892 int ldv_s_lenovo_driver_hid_driver = 0; 893 894 895 896 while( nondet_int() 897 || !(ldv_s_lenovo_driver_hid_driver == 0) 898 ) { 899 900 switch(nondet_int()) { 901 902 case 0: { 903 904 /** STRUCT: struct type: hid_driver, struct name: lenovo_driver **/ 905 if(ldv_s_lenovo_driver_hid_driver==0) { 906 907 /* content: static int lenovo_probe(struct hid_device *hdev, const struct hid_device_id *id)*/ 908 /* LDV_COMMENT_BEGIN_PREP */ 909 #define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) 910 #undef map_key_clear 911 /* LDV_COMMENT_END_PREP */ 912 /* LDV_COMMENT_FUNCTION_CALL Function from field "probe" from driver structure with callbacks "lenovo_driver". Standart function test for correct return result. */ 913 res_lenovo_probe_27 = lenovo_probe( var_group1, var_lenovo_probe_27_p1); 914 ldv_check_return_value(res_lenovo_probe_27); 915 ldv_check_return_value_probe(res_lenovo_probe_27); 916 if(res_lenovo_probe_27) 917 goto ldv_module_exit; 918 ldv_s_lenovo_driver_hid_driver++; 919 920 } 921 922 } 923 924 break; 925 case 1: { 926 927 /** STRUCT: struct type: hid_driver, struct name: lenovo_driver **/ 928 if(ldv_s_lenovo_driver_hid_driver==1) { 929 930 /* content: static void lenovo_remove(struct hid_device *hdev)*/ 931 /* LDV_COMMENT_BEGIN_PREP */ 932 #define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) 933 #undef map_key_clear 934 /* LDV_COMMENT_END_PREP */ 935 /* LDV_COMMENT_FUNCTION_CALL Function from field "remove" from driver structure with callbacks "lenovo_driver" */ 936 ldv_handler_precall(); 937 lenovo_remove( var_group1); 938 ldv_s_lenovo_driver_hid_driver=0; 939 940 } 941 942 } 943 944 break; 945 case 2: { 946 947 /** STRUCT: struct type: hid_driver, struct name: lenovo_driver **/ 948 949 950 /* content: static int lenovo_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max)*/ 951 /* LDV_COMMENT_BEGIN_PREP */ 952 #define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) 953 /* LDV_COMMENT_END_PREP */ 954 /* LDV_COMMENT_FUNCTION_CALL Function from field "input_mapping" from driver structure with callbacks "lenovo_driver" */ 955 ldv_handler_precall(); 956 lenovo_input_mapping( var_group1, var_group2, var_lenovo_input_mapping_2_p2, var_lenovo_input_mapping_2_p3, var_lenovo_input_mapping_2_p4, var_lenovo_input_mapping_2_p5); 957 /* LDV_COMMENT_BEGIN_PREP */ 958 #undef map_key_clear 959 /* LDV_COMMENT_END_PREP */ 960 961 962 963 964 } 965 966 break; 967 case 3: { 968 969 /** STRUCT: struct type: hid_driver, struct name: lenovo_driver **/ 970 971 972 /* content: static int lenovo_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size)*/ 973 /* LDV_COMMENT_BEGIN_PREP */ 974 #define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) 975 #undef map_key_clear 976 /* LDV_COMMENT_END_PREP */ 977 /* LDV_COMMENT_FUNCTION_CALL Function from field "raw_event" from driver structure with callbacks "lenovo_driver" */ 978 ldv_handler_precall(); 979 lenovo_raw_event( var_group1, var_group3, var_lenovo_raw_event_9_p2, var_lenovo_raw_event_9_p3); 980 981 982 983 984 } 985 986 break; 987 default: break; 988 989 } 990 991 } 992 993 ldv_module_exit: 994 995 /* LDV_COMMENT_FUNCTION_CALL Checks that all resources and locks are correctly released before the driver will be unloaded. */ 996 ldv_final: ldv_check_final_state(); 997 998 /* LDV_COMMENT_END_FUNCTION_CALL_SECTION */ 999 return; 1000 1001 } 1002 #endif 1003 1004 /* LDV_COMMENT_END_MAIN */

Here is an explanation of a rule violation arisen while checking your driver against a corresponding kernel.

Note that it may be false positive, i.e. there isn't a real error indeed. Please analyze a given error trace and related source code to understand whether there is an error in your driver.

Error trace column contains a path on which the given rule is violated. You can expand/collapse some entity classes by clicking on corresponding checkboxes in a main menu or in an advanced Others menu. Also you can expand/collapse each particular entity by clicking on +/-. In hovering on some entities you can see some tips. Also the error trace is bound with related source code. Line numbers may be shown as links on the left. You can click on them to open corresponding lines in source code.

Source code column contains a content of files related with the error trace. There is source code of your driver (note that there are some LDV modifications at the end), kernel headers and rule model. Tabs show a currently opened file and other available files. In hovering on them you can see full file names. On clicking a corresponding file content will be shown.

Ядро Модуль Правило Верификатор Вердикт Статус Время создания Описание проблемы
linux-4.0-rc1.tar.xz drivers/hid/hid-lenovo.ko 151_1a BLAST Bug Fixed 2015-05-13 13:33:18 L0196

Комментарий

Описание ошибки по старой трассе. В функции lenovo_probe_tpkbd в случае, если группа lenovo_attr_group_tpkbd (строка 594) создана, а затем вызов devm_kzalloc на строке 598 выполнился с ошибкой, группа не удаляется.

[В начало]