You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branches 'from-henrik', 'hidraw', 'logitech', 'picolcd', 'ps3', 'uclogic', 'wacom' and 'wiimote' into for-linus
This commit is contained in:
+20
-1
@@ -527,6 +527,14 @@ config HID_PICOLCD_LEDS
|
||||
---help---
|
||||
Provide access to PicoLCD's GPO pins via leds class.
|
||||
|
||||
config HID_PICOLCD_CIR
|
||||
bool "CIR via RC class" if EXPERT
|
||||
default !EXPERT
|
||||
depends on HID_PICOLCD
|
||||
depends on HID_PICOLCD=RC_CORE || RC_CORE=y
|
||||
---help---
|
||||
Provide access to PicoLCD's CIR interface via remote control (LIRC).
|
||||
|
||||
config HID_PRIMAX
|
||||
tristate "Primax non-fully HID-compliant devices"
|
||||
depends on USB_HID
|
||||
@@ -534,6 +542,15 @@ config HID_PRIMAX
|
||||
Support for Primax devices that are not fully compliant with the
|
||||
HID standard.
|
||||
|
||||
config HID_PS3REMOTE
|
||||
tristate "Sony PS3 BD Remote Control"
|
||||
depends on BT_HIDP
|
||||
---help---
|
||||
Support for the Sony PS3 Blue-ray Disk Remote Control and Logitech
|
||||
Harmony Adapter for PS3, which connect over Bluetooth.
|
||||
|
||||
Support for the 6-axis controllers is provided by HID_SONY.
|
||||
|
||||
config HID_ROCCAT
|
||||
tristate "Roccat device support"
|
||||
depends on USB_HID
|
||||
@@ -561,7 +578,9 @@ config HID_SONY
|
||||
tristate "Sony PS3 controller"
|
||||
depends on USB_HID
|
||||
---help---
|
||||
Support for Sony PS3 controller.
|
||||
Support for Sony PS3 6-axis controllers.
|
||||
|
||||
Support for the Sony PS3 BD Remote is provided by HID_PS3REMOTE.
|
||||
|
||||
config HID_SPEEDLINK
|
||||
tristate "Speedlink VAD Cezanne mouse support"
|
||||
|
||||
@@ -69,7 +69,28 @@ obj-$(CONFIG_HID_PRODIKEYS) += hid-prodikeys.o
|
||||
obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o
|
||||
obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o
|
||||
obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o
|
||||
hid-picolcd-y += hid-picolcd_core.o
|
||||
ifdef CONFIG_HID_PICOLCD_FB
|
||||
hid-picolcd-y += hid-picolcd_fb.o
|
||||
endif
|
||||
ifdef CONFIG_HID_PICOLCD_BACKLIGHT
|
||||
hid-picolcd-y += hid-picolcd_backlight.o
|
||||
endif
|
||||
ifdef CONFIG_HID_PICOLCD_LCD
|
||||
hid-picolcd-y += hid-picolcd_lcd.o
|
||||
endif
|
||||
ifdef CONFIG_HID_PICOLCD_LEDS
|
||||
hid-picolcd-y += hid-picolcd_leds.o
|
||||
endif
|
||||
ifdef CONFIG_HID_PICOLCD_CIR
|
||||
hid-picolcd-y += hid-picolcd_cir.o
|
||||
endif
|
||||
ifdef CONFIG_DEBUG_FS
|
||||
hid-picolcd-y += hid-picolcd_debugfs.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_HID_PRIMAX) += hid-primax.o
|
||||
obj-$(CONFIG_HID_PS3REMOTE) += hid-ps3remote.o
|
||||
obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \
|
||||
hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \
|
||||
hid-roccat-koneplus.o hid-roccat-kovaplus.o hid-roccat-pyra.o \
|
||||
|
||||
@@ -1566,6 +1566,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER) },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_PS3) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI) },
|
||||
@@ -1639,6 +1640,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
|
||||
@@ -1663,6 +1665,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SUPER_JOY_BOX_3) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD) },
|
||||
|
||||
@@ -499,6 +499,7 @@
|
||||
#define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101
|
||||
#define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110
|
||||
#define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f
|
||||
#define USB_DEVICE_ID_LOGITECH_HARMONY_PS3 0x0306
|
||||
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD 0xc20a
|
||||
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD 0xc211
|
||||
#define USB_DEVICE_ID_LOGITECH_EXTREME_3D 0xc215
|
||||
@@ -686,6 +687,7 @@
|
||||
|
||||
#define USB_VENDOR_ID_SONY 0x054c
|
||||
#define USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE 0x024b
|
||||
#define USB_DEVICE_ID_SONY_PS3_BDREMOTE 0x0306
|
||||
#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268
|
||||
#define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f
|
||||
|
||||
@@ -761,6 +763,7 @@
|
||||
#define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U 0x0005
|
||||
#define USB_DEVICE_ID_UCLOGIC_TABLET_WP1062 0x0064
|
||||
#define USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850 0x0522
|
||||
#define USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60 0x0781
|
||||
|
||||
#define USB_VENDOR_ID_UNITEC 0x227d
|
||||
#define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709 0x0709
|
||||
|
||||
@@ -519,6 +519,8 @@ static void tpkbd_remove_tp(struct hid_device *hdev)
|
||||
led_classdev_unregister(&data_pointer->led_mute);
|
||||
|
||||
hid_set_drvdata(hdev, NULL);
|
||||
kfree(data_pointer->led_micmute.name);
|
||||
kfree(data_pointer->led_mute.name);
|
||||
kfree(data_pointer);
|
||||
}
|
||||
|
||||
|
||||
@@ -342,6 +342,9 @@ static int lg_event(struct hid_device *hdev, struct hid_field *field,
|
||||
-value);
|
||||
return 1;
|
||||
}
|
||||
if (drv_data->quirks & LG_FF4) {
|
||||
return lg4ff_adjust_input_event(hdev, field, usage, value, drv_data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -358,7 +361,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
return -ENOMEM;
|
||||
}
|
||||
drv_data->quirks = id->driver_data;
|
||||
|
||||
|
||||
hid_set_drvdata(hdev, (void *)drv_data);
|
||||
|
||||
if (drv_data->quirks & LG_NOGET)
|
||||
@@ -380,7 +383,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
}
|
||||
|
||||
/* Setup wireless link with Logitech Wii wheel */
|
||||
if(hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
|
||||
if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
|
||||
unsigned char buf[] = { 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
|
||||
@@ -476,7 +479,7 @@ static const struct hid_device_id lg_devices[] = {
|
||||
.driver_data = LG_NOGET | LG_FF4 },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
|
||||
.driver_data = LG_FF4 },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ),
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG),
|
||||
.driver_data = LG_FF },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
|
||||
.driver_data = LG_FF2 },
|
||||
|
||||
@@ -25,9 +25,13 @@ static inline int lg3ff_init(struct hid_device *hdev) { return -1; }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_LOGIWHEELS_FF
|
||||
int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field,
|
||||
struct hid_usage *usage, __s32 value, struct lg_drv_data *drv_data);
|
||||
int lg4ff_init(struct hid_device *hdev);
|
||||
int lg4ff_deinit(struct hid_device *hdev);
|
||||
#else
|
||||
static inline int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field,
|
||||
struct hid_usage *usage, __s32 value, struct lg_drv_data *drv_data) { return 0; }
|
||||
static inline int lg4ff_init(struct hid_device *hdev) { return -1; }
|
||||
static inline int lg4ff_deinit(struct hid_device *hdev) { return -1; }
|
||||
#endif
|
||||
|
||||
+135
-57
@@ -43,6 +43,11 @@
|
||||
#define G27_REV_MAJ 0x12
|
||||
#define G27_REV_MIN 0x38
|
||||
|
||||
#define DFP_X_MIN 0
|
||||
#define DFP_X_MAX 16383
|
||||
#define DFP_PEDAL_MIN 0
|
||||
#define DFP_PEDAL_MAX 255
|
||||
|
||||
#define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
|
||||
|
||||
static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range);
|
||||
@@ -53,6 +58,7 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at
|
||||
static DEVICE_ATTR(range, S_IRWXU | S_IRWXG | S_IRWXO, lg4ff_range_show, lg4ff_range_store);
|
||||
|
||||
struct lg4ff_device_entry {
|
||||
__u32 product_id;
|
||||
__u16 range;
|
||||
__u16 min_range;
|
||||
__u16 max_range;
|
||||
@@ -129,26 +135,77 @@ static const struct lg4ff_usb_revision lg4ff_revs[] = {
|
||||
{G27_REV_MAJ, G27_REV_MIN, &native_g27}, /* G27 */
|
||||
};
|
||||
|
||||
/* Recalculates X axis value accordingly to currently selected range */
|
||||
static __s32 lg4ff_adjust_dfp_x_axis(__s32 value, __u16 range)
|
||||
{
|
||||
__u16 max_range;
|
||||
__s32 new_value;
|
||||
|
||||
if (range == 900)
|
||||
return value;
|
||||
else if (range == 200)
|
||||
return value;
|
||||
else if (range < 200)
|
||||
max_range = 200;
|
||||
else
|
||||
max_range = 900;
|
||||
|
||||
new_value = 8192 + mult_frac(value - 8192, max_range, range);
|
||||
if (new_value < 0)
|
||||
return 0;
|
||||
else if (new_value > 16383)
|
||||
return 16383;
|
||||
else
|
||||
return new_value;
|
||||
}
|
||||
|
||||
int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field,
|
||||
struct hid_usage *usage, __s32 value, struct lg_drv_data *drv_data)
|
||||
{
|
||||
struct lg4ff_device_entry *entry = drv_data->device_props;
|
||||
__s32 new_value = 0;
|
||||
|
||||
if (!entry) {
|
||||
hid_err(hid, "Device properties not found");
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (entry->product_id) {
|
||||
case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
|
||||
switch (usage->code) {
|
||||
case ABS_X:
|
||||
new_value = lg4ff_adjust_dfp_x_axis(value, entry->range);
|
||||
input_event(field->hidinput->input, usage->type, usage->code, new_value);
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
|
||||
{
|
||||
struct hid_device *hid = input_get_drvdata(dev);
|
||||
struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
|
||||
struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
|
||||
__s32 *value = report->field[0]->value;
|
||||
int x;
|
||||
|
||||
#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff
|
||||
#define CLAMP(x) do { if (x < 0) x = 0; else if (x > 0xff) x = 0xff; } while (0)
|
||||
|
||||
switch (effect->type) {
|
||||
case FF_CONSTANT:
|
||||
x = effect->u.ramp.start_level + 0x80; /* 0x80 is no force */
|
||||
CLAMP(x);
|
||||
report->field[0]->value[0] = 0x11; /* Slot 1 */
|
||||
report->field[0]->value[1] = 0x08;
|
||||
report->field[0]->value[2] = x;
|
||||
report->field[0]->value[3] = 0x80;
|
||||
report->field[0]->value[4] = 0x00;
|
||||
report->field[0]->value[5] = 0x00;
|
||||
report->field[0]->value[6] = 0x00;
|
||||
value[0] = 0x11; /* Slot 1 */
|
||||
value[1] = 0x08;
|
||||
value[2] = x;
|
||||
value[3] = 0x80;
|
||||
value[4] = 0x00;
|
||||
value[5] = 0x00;
|
||||
value[6] = 0x00;
|
||||
|
||||
usbhid_submit_report(hid, report, USB_DIR_OUT);
|
||||
break;
|
||||
@@ -163,14 +220,15 @@ static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitud
|
||||
struct hid_device *hid = input_get_drvdata(dev);
|
||||
struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
|
||||
struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
|
||||
__s32 *value = report->field[0]->value;
|
||||
|
||||
report->field[0]->value[0] = 0xfe;
|
||||
report->field[0]->value[1] = 0x0d;
|
||||
report->field[0]->value[2] = magnitude >> 13;
|
||||
report->field[0]->value[3] = magnitude >> 13;
|
||||
report->field[0]->value[4] = magnitude >> 8;
|
||||
report->field[0]->value[5] = 0x00;
|
||||
report->field[0]->value[6] = 0x00;
|
||||
value[0] = 0xfe;
|
||||
value[1] = 0x0d;
|
||||
value[2] = magnitude >> 13;
|
||||
value[3] = magnitude >> 13;
|
||||
value[4] = magnitude >> 8;
|
||||
value[5] = 0x00;
|
||||
value[6] = 0x00;
|
||||
|
||||
usbhid_submit_report(hid, report, USB_DIR_OUT);
|
||||
}
|
||||
@@ -181,16 +239,16 @@ static void hid_lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude)
|
||||
struct hid_device *hid = input_get_drvdata(dev);
|
||||
struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
|
||||
struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
|
||||
__s32 *value = report->field[0]->value;
|
||||
magnitude = magnitude * 90 / 65535;
|
||||
|
||||
|
||||
report->field[0]->value[0] = 0xfe;
|
||||
report->field[0]->value[1] = 0x03;
|
||||
report->field[0]->value[2] = magnitude >> 14;
|
||||
report->field[0]->value[3] = magnitude >> 14;
|
||||
report->field[0]->value[4] = magnitude;
|
||||
report->field[0]->value[5] = 0x00;
|
||||
report->field[0]->value[6] = 0x00;
|
||||
value[0] = 0xfe;
|
||||
value[1] = 0x03;
|
||||
value[2] = magnitude >> 14;
|
||||
value[3] = magnitude >> 14;
|
||||
value[4] = magnitude;
|
||||
value[5] = 0x00;
|
||||
value[6] = 0x00;
|
||||
|
||||
usbhid_submit_report(hid, report, USB_DIR_OUT);
|
||||
}
|
||||
@@ -200,15 +258,17 @@ static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range)
|
||||
{
|
||||
struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
|
||||
struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
|
||||
__s32 *value = report->field[0]->value;
|
||||
|
||||
dbg_hid("G25/G27/DFGT: setting range to %u\n", range);
|
||||
|
||||
report->field[0]->value[0] = 0xf8;
|
||||
report->field[0]->value[1] = 0x81;
|
||||
report->field[0]->value[2] = range & 0x00ff;
|
||||
report->field[0]->value[3] = (range & 0xff00) >> 8;
|
||||
report->field[0]->value[4] = 0x00;
|
||||
report->field[0]->value[5] = 0x00;
|
||||
report->field[0]->value[6] = 0x00;
|
||||
value[0] = 0xf8;
|
||||
value[1] = 0x81;
|
||||
value[2] = range & 0x00ff;
|
||||
value[3] = (range & 0xff00) >> 8;
|
||||
value[4] = 0x00;
|
||||
value[5] = 0x00;
|
||||
value[6] = 0x00;
|
||||
|
||||
usbhid_submit_report(hid, report, USB_DIR_OUT);
|
||||
}
|
||||
@@ -219,16 +279,18 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range)
|
||||
struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
|
||||
struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
|
||||
int start_left, start_right, full_range;
|
||||
__s32 *value = report->field[0]->value;
|
||||
|
||||
dbg_hid("Driving Force Pro: setting range to %u\n", range);
|
||||
|
||||
/* Prepare "coarse" limit command */
|
||||
report->field[0]->value[0] = 0xf8;
|
||||
report->field[0]->value[1] = 0x00; /* Set later */
|
||||
report->field[0]->value[2] = 0x00;
|
||||
report->field[0]->value[3] = 0x00;
|
||||
report->field[0]->value[4] = 0x00;
|
||||
report->field[0]->value[5] = 0x00;
|
||||
report->field[0]->value[6] = 0x00;
|
||||
value[0] = 0xf8;
|
||||
value[1] = 0x00; /* Set later */
|
||||
value[2] = 0x00;
|
||||
value[3] = 0x00;
|
||||
value[4] = 0x00;
|
||||
value[5] = 0x00;
|
||||
value[6] = 0x00;
|
||||
|
||||
if (range > 200) {
|
||||
report->field[0]->value[1] = 0x03;
|
||||
@@ -240,13 +302,13 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range)
|
||||
usbhid_submit_report(hid, report, USB_DIR_OUT);
|
||||
|
||||
/* Prepare "fine" limit command */
|
||||
report->field[0]->value[0] = 0x81;
|
||||
report->field[0]->value[1] = 0x0b;
|
||||
report->field[0]->value[2] = 0x00;
|
||||
report->field[0]->value[3] = 0x00;
|
||||
report->field[0]->value[4] = 0x00;
|
||||
report->field[0]->value[5] = 0x00;
|
||||
report->field[0]->value[6] = 0x00;
|
||||
value[0] = 0x81;
|
||||
value[1] = 0x0b;
|
||||
value[2] = 0x00;
|
||||
value[3] = 0x00;
|
||||
value[4] = 0x00;
|
||||
value[5] = 0x00;
|
||||
value[6] = 0x00;
|
||||
|
||||
if (range == 200 || range == 900) { /* Do not apply any fine limit */
|
||||
usbhid_submit_report(hid, report, USB_DIR_OUT);
|
||||
@@ -257,11 +319,11 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range)
|
||||
start_left = (((full_range - range + 1) * 2047) / full_range);
|
||||
start_right = 0xfff - start_left;
|
||||
|
||||
report->field[0]->value[2] = start_left >> 4;
|
||||
report->field[0]->value[3] = start_right >> 4;
|
||||
report->field[0]->value[4] = 0xff;
|
||||
report->field[0]->value[5] = (start_right & 0xe) << 4 | (start_left & 0xe);
|
||||
report->field[0]->value[6] = 0xff;
|
||||
value[2] = start_left >> 4;
|
||||
value[3] = start_right >> 4;
|
||||
value[4] = 0xff;
|
||||
value[5] = (start_right & 0xe) << 4 | (start_left & 0xe);
|
||||
value[6] = 0xff;
|
||||
|
||||
usbhid_submit_report(hid, report, USB_DIR_OUT);
|
||||
}
|
||||
@@ -344,14 +406,15 @@ static void lg4ff_set_leds(struct hid_device *hid, __u8 leds)
|
||||
{
|
||||
struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
|
||||
struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
|
||||
__s32 *value = report->field[0]->value;
|
||||
|
||||
report->field[0]->value[0] = 0xf8;
|
||||
report->field[0]->value[1] = 0x12;
|
||||
report->field[0]->value[2] = leds;
|
||||
report->field[0]->value[3] = 0x00;
|
||||
report->field[0]->value[4] = 0x00;
|
||||
report->field[0]->value[5] = 0x00;
|
||||
report->field[0]->value[6] = 0x00;
|
||||
value[0] = 0xf8;
|
||||
value[1] = 0x12;
|
||||
value[2] = leds;
|
||||
value[3] = 0x00;
|
||||
value[4] = 0x00;
|
||||
value[5] = 0x00;
|
||||
value[6] = 0x00;
|
||||
usbhid_submit_report(hid, report, USB_DIR_OUT);
|
||||
}
|
||||
|
||||
@@ -501,7 +564,7 @@ int lg4ff_init(struct hid_device *hid)
|
||||
/* Check if autocentering is available and
|
||||
* set the centering force to zero by default */
|
||||
if (test_bit(FF_AUTOCENTER, dev->ffbit)) {
|
||||
if(rev_maj == FFEX_REV_MAJ && rev_min == FFEX_REV_MIN) /* Formula Force EX expects different autocentering command */
|
||||
if (rev_maj == FFEX_REV_MAJ && rev_min == FFEX_REV_MIN) /* Formula Force EX expects different autocentering command */
|
||||
dev->ff->set_autocenter = hid_lg4ff_set_autocenter_ffex;
|
||||
else
|
||||
dev->ff->set_autocenter = hid_lg4ff_set_autocenter_default;
|
||||
@@ -524,6 +587,7 @@ int lg4ff_init(struct hid_device *hid)
|
||||
}
|
||||
drv_data->device_props = entry;
|
||||
|
||||
entry->product_id = lg4ff_devices[i].product_id;
|
||||
entry->min_range = lg4ff_devices[i].min_range;
|
||||
entry->max_range = lg4ff_devices[i].max_range;
|
||||
entry->set_range = lg4ff_devices[i].set_range;
|
||||
@@ -534,6 +598,18 @@ int lg4ff_init(struct hid_device *hid)
|
||||
return error;
|
||||
dbg_hid("sysfs interface created\n");
|
||||
|
||||
/* Set default axes parameters */
|
||||
switch (lg4ff_devices[i].product_id) {
|
||||
case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
|
||||
dbg_hid("Setting axes parameters for Driving Force Pro\n");
|
||||
input_set_abs_params(dev, ABS_X, DFP_X_MIN, DFP_X_MAX, 0, 0);
|
||||
input_set_abs_params(dev, ABS_Y, DFP_PEDAL_MIN, DFP_PEDAL_MAX, 0, 0);
|
||||
input_set_abs_params(dev, ABS_RZ, DFP_PEDAL_MIN, DFP_PEDAL_MAX, 0, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set the maximum range to start with */
|
||||
entry->range = entry->max_range;
|
||||
if (entry->set_range != NULL)
|
||||
@@ -594,6 +670,8 @@ out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int lg4ff_deinit(struct hid_device *hid)
|
||||
{
|
||||
struct lg4ff_device_entry *entry;
|
||||
|
||||
@@ -193,6 +193,7 @@ static struct hid_ll_driver logi_dj_ll_driver;
|
||||
static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
|
||||
size_t count,
|
||||
unsigned char report_type);
|
||||
static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev);
|
||||
|
||||
static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev,
|
||||
struct dj_report *dj_report)
|
||||
@@ -233,6 +234,7 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
|
||||
if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] &
|
||||
SPFUNCTION_DEVICE_LIST_EMPTY) {
|
||||
dbg_hid("%s: device list is empty\n", __func__);
|
||||
djrcv_dev->querying_devices = false;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -243,6 +245,12 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
|
||||
return;
|
||||
}
|
||||
|
||||
if (djrcv_dev->paired_dj_devices[dj_report->device_index]) {
|
||||
/* The device is already known. No need to reallocate it. */
|
||||
dbg_hid("%s: device is already known\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
dj_hiddev = hid_allocate_device();
|
||||
if (IS_ERR(dj_hiddev)) {
|
||||
dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n",
|
||||
@@ -306,6 +314,7 @@ static void delayedwork_callback(struct work_struct *work)
|
||||
struct dj_report dj_report;
|
||||
unsigned long flags;
|
||||
int count;
|
||||
int retval;
|
||||
|
||||
dbg_hid("%s\n", __func__);
|
||||
|
||||
@@ -338,6 +347,25 @@ static void delayedwork_callback(struct work_struct *work)
|
||||
logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report);
|
||||
break;
|
||||
default:
|
||||
/* A normal report (i. e. not belonging to a pair/unpair notification)
|
||||
* arriving here, means that the report arrived but we did not have a
|
||||
* paired dj_device associated to the report's device_index, this
|
||||
* means that the original "device paired" notification corresponding
|
||||
* to this dj_device never arrived to this driver. The reason is that
|
||||
* hid-core discards all packets coming from a device while probe() is
|
||||
* executing. */
|
||||
if (!djrcv_dev->paired_dj_devices[dj_report.device_index]) {
|
||||
/* ok, we don't know the device, just re-ask the
|
||||
* receiver for the list of connected devices. */
|
||||
retval = logi_dj_recv_query_paired_devices(djrcv_dev);
|
||||
if (!retval) {
|
||||
/* everything went fine, so just leave */
|
||||
break;
|
||||
}
|
||||
dev_err(&djrcv_dev->hdev->dev,
|
||||
"%s:logi_dj_recv_query_paired_devices "
|
||||
"error:%d\n", __func__, retval);
|
||||
}
|
||||
dbg_hid("%s: unexpected report type\n", __func__);
|
||||
}
|
||||
}
|
||||
@@ -368,6 +396,12 @@ static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev,
|
||||
if (!djdev) {
|
||||
dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
|
||||
" is NULL, index %d\n", dj_report->device_index);
|
||||
kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
|
||||
|
||||
if (schedule_work(&djrcv_dev->work) == 0) {
|
||||
dbg_hid("%s: did not schedule the work item, was already "
|
||||
"queued\n", __func__);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -398,6 +432,12 @@ static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev,
|
||||
if (dj_device == NULL) {
|
||||
dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
|
||||
" is NULL, index %d\n", dj_report->device_index);
|
||||
kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
|
||||
|
||||
if (schedule_work(&djrcv_dev->work) == 0) {
|
||||
dbg_hid("%s: did not schedule the work item, was already "
|
||||
"queued\n", __func__);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -439,6 +479,10 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
|
||||
struct dj_report *dj_report;
|
||||
int retval;
|
||||
|
||||
/* no need to protect djrcv_dev->querying_devices */
|
||||
if (djrcv_dev->querying_devices)
|
||||
return 0;
|
||||
|
||||
dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL);
|
||||
if (!dj_report)
|
||||
return -ENOMEM;
|
||||
@@ -450,6 +494,7 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev,
|
||||
unsigned timeout)
|
||||
{
|
||||
|
||||
@@ -101,6 +101,7 @@ struct dj_receiver_dev {
|
||||
struct work_struct work;
|
||||
struct kfifo notif_fifo;
|
||||
spinlock_t lock;
|
||||
bool querying_devices;
|
||||
};
|
||||
|
||||
struct dj_device {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,309 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org> *
|
||||
* *
|
||||
* Based on Logitech G13 driver (v0.4) *
|
||||
* Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, version 2 of the License. *
|
||||
* *
|
||||
* This driver is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this software. If not see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#define PICOLCD_NAME "PicoLCD (graphic)"
|
||||
|
||||
/* Report numbers */
|
||||
#define REPORT_ERROR_CODE 0x10 /* LCD: IN[16] */
|
||||
#define ERR_SUCCESS 0x00
|
||||
#define ERR_PARAMETER_MISSING 0x01
|
||||
#define ERR_DATA_MISSING 0x02
|
||||
#define ERR_BLOCK_READ_ONLY 0x03
|
||||
#define ERR_BLOCK_NOT_ERASABLE 0x04
|
||||
#define ERR_BLOCK_TOO_BIG 0x05
|
||||
#define ERR_SECTION_OVERFLOW 0x06
|
||||
#define ERR_INVALID_CMD_LEN 0x07
|
||||
#define ERR_INVALID_DATA_LEN 0x08
|
||||
#define REPORT_KEY_STATE 0x11 /* LCD: IN[2] */
|
||||
#define REPORT_IR_DATA 0x21 /* LCD: IN[63] */
|
||||
#define REPORT_EE_DATA 0x32 /* LCD: IN[63] */
|
||||
#define REPORT_MEMORY 0x41 /* LCD: IN[63] */
|
||||
#define REPORT_LED_STATE 0x81 /* LCD: OUT[1] */
|
||||
#define REPORT_BRIGHTNESS 0x91 /* LCD: OUT[1] */
|
||||
#define REPORT_CONTRAST 0x92 /* LCD: OUT[1] */
|
||||
#define REPORT_RESET 0x93 /* LCD: OUT[2] */
|
||||
#define REPORT_LCD_CMD 0x94 /* LCD: OUT[63] */
|
||||
#define REPORT_LCD_DATA 0x95 /* LCD: OUT[63] */
|
||||
#define REPORT_LCD_CMD_DATA 0x96 /* LCD: OUT[63] */
|
||||
#define REPORT_EE_READ 0xa3 /* LCD: OUT[63] */
|
||||
#define REPORT_EE_WRITE 0xa4 /* LCD: OUT[63] */
|
||||
#define REPORT_ERASE_MEMORY 0xb2 /* LCD: OUT[2] */
|
||||
#define REPORT_READ_MEMORY 0xb3 /* LCD: OUT[3] */
|
||||
#define REPORT_WRITE_MEMORY 0xb4 /* LCD: OUT[63] */
|
||||
#define REPORT_SPLASH_RESTART 0xc1 /* LCD: OUT[1] */
|
||||
#define REPORT_EXIT_KEYBOARD 0xef /* LCD: OUT[2] */
|
||||
#define REPORT_VERSION 0xf1 /* LCD: IN[2],OUT[1] Bootloader: IN[2],OUT[1] */
|
||||
#define REPORT_BL_ERASE_MEMORY 0xf2 /* Bootloader: IN[36],OUT[4] */
|
||||
#define REPORT_BL_READ_MEMORY 0xf3 /* Bootloader: IN[36],OUT[4] */
|
||||
#define REPORT_BL_WRITE_MEMORY 0xf4 /* Bootloader: IN[36],OUT[36] */
|
||||
#define REPORT_DEVID 0xf5 /* LCD: IN[5], OUT[1] Bootloader: IN[5],OUT[1] */
|
||||
#define REPORT_SPLASH_SIZE 0xf6 /* LCD: IN[4], OUT[1] */
|
||||
#define REPORT_HOOK_VERSION 0xf7 /* LCD: IN[2], OUT[1] */
|
||||
#define REPORT_EXIT_FLASHER 0xff /* Bootloader: OUT[2] */
|
||||
|
||||
/* Description of in-progress IO operation, used for operations
|
||||
* that trigger response from device */
|
||||
struct picolcd_pending {
|
||||
struct hid_report *out_report;
|
||||
struct hid_report *in_report;
|
||||
struct completion ready;
|
||||
int raw_size;
|
||||
u8 raw_data[64];
|
||||
};
|
||||
|
||||
|
||||
#define PICOLCD_KEYS 17
|
||||
|
||||
/* Per device data structure */
|
||||
struct picolcd_data {
|
||||
struct hid_device *hdev;
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debug_reset;
|
||||
struct dentry *debug_eeprom;
|
||||
struct dentry *debug_flash;
|
||||
struct mutex mutex_flash;
|
||||
int addr_sz;
|
||||
#endif
|
||||
u8 version[2];
|
||||
unsigned short opmode_delay;
|
||||
/* input stuff */
|
||||
u8 pressed_keys[2];
|
||||
struct input_dev *input_keys;
|
||||
#ifdef CONFIG_HID_PICOLCD_CIR
|
||||
struct rc_dev *rc_dev;
|
||||
#endif
|
||||
unsigned short keycode[PICOLCD_KEYS];
|
||||
|
||||
#ifdef CONFIG_HID_PICOLCD_FB
|
||||
/* Framebuffer stuff */
|
||||
struct fb_info *fb_info;
|
||||
#endif /* CONFIG_HID_PICOLCD_FB */
|
||||
#ifdef CONFIG_HID_PICOLCD_LCD
|
||||
struct lcd_device *lcd;
|
||||
u8 lcd_contrast;
|
||||
#endif /* CONFIG_HID_PICOLCD_LCD */
|
||||
#ifdef CONFIG_HID_PICOLCD_BACKLIGHT
|
||||
struct backlight_device *backlight;
|
||||
u8 lcd_brightness;
|
||||
u8 lcd_power;
|
||||
#endif /* CONFIG_HID_PICOLCD_BACKLIGHT */
|
||||
#ifdef CONFIG_HID_PICOLCD_LEDS
|
||||
/* LED stuff */
|
||||
u8 led_state;
|
||||
struct led_classdev *led[8];
|
||||
#endif /* CONFIG_HID_PICOLCD_LEDS */
|
||||
|
||||
/* Housekeeping stuff */
|
||||
spinlock_t lock;
|
||||
struct mutex mutex;
|
||||
struct picolcd_pending *pending;
|
||||
int status;
|
||||
#define PICOLCD_BOOTLOADER 1
|
||||
#define PICOLCD_FAILED 2
|
||||
#define PICOLCD_CIR_SHUN 4
|
||||
};
|
||||
|
||||
#ifdef CONFIG_HID_PICOLCD_FB
|
||||
struct picolcd_fb_data {
|
||||
/* Framebuffer stuff */
|
||||
spinlock_t lock;
|
||||
struct picolcd_data *picolcd;
|
||||
u8 update_rate;
|
||||
u8 bpp;
|
||||
u8 force;
|
||||
u8 ready;
|
||||
u8 *vbitmap; /* local copy of what was sent to PicoLCD */
|
||||
u8 *bitmap; /* framebuffer */
|
||||
};
|
||||
#endif /* CONFIG_HID_PICOLCD_FB */
|
||||
|
||||
/* Find a given report */
|
||||
#define picolcd_in_report(id, dev) picolcd_report(id, dev, HID_INPUT_REPORT)
|
||||
#define picolcd_out_report(id, dev) picolcd_report(id, dev, HID_OUTPUT_REPORT)
|
||||
|
||||
struct hid_report *picolcd_report(int id, struct hid_device *hdev, int dir);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
void picolcd_debug_out_report(struct picolcd_data *data,
|
||||
struct hid_device *hdev, struct hid_report *report);
|
||||
#define usbhid_submit_report(a, b, c) \
|
||||
do { \
|
||||
picolcd_debug_out_report(hid_get_drvdata(a), a, b); \
|
||||
usbhid_submit_report(a, b, c); \
|
||||
} while (0)
|
||||
|
||||
void picolcd_debug_raw_event(struct picolcd_data *data,
|
||||
struct hid_device *hdev, struct hid_report *report,
|
||||
u8 *raw_data, int size);
|
||||
|
||||
void picolcd_init_devfs(struct picolcd_data *data,
|
||||
struct hid_report *eeprom_r, struct hid_report *eeprom_w,
|
||||
struct hid_report *flash_r, struct hid_report *flash_w,
|
||||
struct hid_report *reset);
|
||||
|
||||
void picolcd_exit_devfs(struct picolcd_data *data);
|
||||
#else
|
||||
static inline void picolcd_debug_out_report(struct picolcd_data *data,
|
||||
struct hid_device *hdev, struct hid_report *report)
|
||||
{
|
||||
}
|
||||
static inline void picolcd_debug_raw_event(struct picolcd_data *data,
|
||||
struct hid_device *hdev, struct hid_report *report,
|
||||
u8 *raw_data, int size)
|
||||
{
|
||||
}
|
||||
static inline void picolcd_init_devfs(struct picolcd_data *data,
|
||||
struct hid_report *eeprom_r, struct hid_report *eeprom_w,
|
||||
struct hid_report *flash_r, struct hid_report *flash_w,
|
||||
struct hid_report *reset)
|
||||
{
|
||||
}
|
||||
static inline void picolcd_exit_devfs(struct picolcd_data *data)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
|
||||
|
||||
#ifdef CONFIG_HID_PICOLCD_FB
|
||||
int picolcd_fb_reset(struct picolcd_data *data, int clear);
|
||||
|
||||
int picolcd_init_framebuffer(struct picolcd_data *data);
|
||||
|
||||
void picolcd_exit_framebuffer(struct picolcd_data *data);
|
||||
|
||||
void picolcd_fb_refresh(struct picolcd_data *data);
|
||||
#define picolcd_fbinfo(d) ((d)->fb_info)
|
||||
#else
|
||||
static inline int picolcd_fb_reset(struct picolcd_data *data, int clear)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int picolcd_init_framebuffer(struct picolcd_data *data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void picolcd_exit_framebuffer(struct picolcd_data *data)
|
||||
{
|
||||
}
|
||||
static inline void picolcd_fb_refresh(struct picolcd_data *data)
|
||||
{
|
||||
}
|
||||
#define picolcd_fbinfo(d) NULL
|
||||
#endif /* CONFIG_HID_PICOLCD_FB */
|
||||
|
||||
|
||||
#ifdef CONFIG_HID_PICOLCD_BACKLIGHT
|
||||
int picolcd_init_backlight(struct picolcd_data *data,
|
||||
struct hid_report *report);
|
||||
|
||||
void picolcd_exit_backlight(struct picolcd_data *data);
|
||||
|
||||
int picolcd_resume_backlight(struct picolcd_data *data);
|
||||
|
||||
void picolcd_suspend_backlight(struct picolcd_data *data);
|
||||
#else
|
||||
static inline int picolcd_init_backlight(struct picolcd_data *data,
|
||||
struct hid_report *report)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void picolcd_exit_backlight(struct picolcd_data *data)
|
||||
{
|
||||
}
|
||||
static inline int picolcd_resume_backlight(struct picolcd_data *data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void picolcd_suspend_backlight(struct picolcd_data *data)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_HID_PICOLCD_BACKLIGHT */
|
||||
|
||||
|
||||
#ifdef CONFIG_HID_PICOLCD_LCD
|
||||
int picolcd_init_lcd(struct picolcd_data *data,
|
||||
struct hid_report *report);
|
||||
|
||||
void picolcd_exit_lcd(struct picolcd_data *data);
|
||||
|
||||
int picolcd_resume_lcd(struct picolcd_data *data);
|
||||
#else
|
||||
static inline int picolcd_init_lcd(struct picolcd_data *data,
|
||||
struct hid_report *report)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void picolcd_exit_lcd(struct picolcd_data *data)
|
||||
{
|
||||
}
|
||||
static inline int picolcd_resume_lcd(struct picolcd_data *data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_HID_PICOLCD_LCD */
|
||||
|
||||
|
||||
#ifdef CONFIG_HID_PICOLCD_LEDS
|
||||
int picolcd_init_leds(struct picolcd_data *data,
|
||||
struct hid_report *report);
|
||||
|
||||
void picolcd_exit_leds(struct picolcd_data *data);
|
||||
|
||||
void picolcd_leds_set(struct picolcd_data *data);
|
||||
#else
|
||||
static inline int picolcd_init_leds(struct picolcd_data *data,
|
||||
struct hid_report *report)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void picolcd_exit_leds(struct picolcd_data *data)
|
||||
{
|
||||
}
|
||||
static inline void picolcd_leds_set(struct picolcd_data *data)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_HID_PICOLCD_LEDS */
|
||||
|
||||
|
||||
#ifdef CONFIG_HID_PICOLCD_CIR
|
||||
int picolcd_raw_cir(struct picolcd_data *data,
|
||||
struct hid_report *report, u8 *raw_data, int size);
|
||||
|
||||
int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report);
|
||||
|
||||
void picolcd_exit_cir(struct picolcd_data *data);
|
||||
#else
|
||||
static inline int picolcd_raw_cir(struct picolcd_data *data,
|
||||
struct hid_report *report, u8 *raw_data, int size)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
static inline int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void picolcd_exit_cir(struct picolcd_data *data)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_HID_PICOLCD_LIRC */
|
||||
|
||||
int picolcd_reset(struct hid_device *hdev);
|
||||
struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev,
|
||||
int report_id, const u8 *raw_data, int size);
|
||||
@@ -0,0 +1,122 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org> *
|
||||
* *
|
||||
* Based on Logitech G13 driver (v0.4) *
|
||||
* Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, version 2 of the License. *
|
||||
* *
|
||||
* This driver is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this software. If not see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#include <linux/hid.h>
|
||||
#include "usbhid/usbhid.h"
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/backlight.h>
|
||||
|
||||
#include "hid-picolcd.h"
|
||||
|
||||
static int picolcd_get_brightness(struct backlight_device *bdev)
|
||||
{
|
||||
struct picolcd_data *data = bl_get_data(bdev);
|
||||
return data->lcd_brightness;
|
||||
}
|
||||
|
||||
static int picolcd_set_brightness(struct backlight_device *bdev)
|
||||
{
|
||||
struct picolcd_data *data = bl_get_data(bdev);
|
||||
struct hid_report *report = picolcd_out_report(REPORT_BRIGHTNESS, data->hdev);
|
||||
unsigned long flags;
|
||||
|
||||
if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
|
||||
return -ENODEV;
|
||||
|
||||
data->lcd_brightness = bdev->props.brightness & 0x0ff;
|
||||
data->lcd_power = bdev->props.power;
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
hid_set_field(report->field[0], 0, data->lcd_power == FB_BLANK_UNBLANK ? data->lcd_brightness : 0);
|
||||
if (!(data->status & PICOLCD_FAILED))
|
||||
usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int picolcd_check_bl_fb(struct backlight_device *bdev, struct fb_info *fb)
|
||||
{
|
||||
return fb && fb == picolcd_fbinfo((struct picolcd_data *)bl_get_data(bdev));
|
||||
}
|
||||
|
||||
static const struct backlight_ops picolcd_blops = {
|
||||
.update_status = picolcd_set_brightness,
|
||||
.get_brightness = picolcd_get_brightness,
|
||||
.check_fb = picolcd_check_bl_fb,
|
||||
};
|
||||
|
||||
int picolcd_init_backlight(struct picolcd_data *data, struct hid_report *report)
|
||||
{
|
||||
struct device *dev = &data->hdev->dev;
|
||||
struct backlight_device *bdev;
|
||||
struct backlight_properties props;
|
||||
if (!report)
|
||||
return -ENODEV;
|
||||
if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
|
||||
report->field[0]->report_size != 8) {
|
||||
dev_err(dev, "unsupported BRIGHTNESS report");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(&props, 0, sizeof(props));
|
||||
props.type = BACKLIGHT_RAW;
|
||||
props.max_brightness = 0xff;
|
||||
bdev = backlight_device_register(dev_name(dev), dev, data,
|
||||
&picolcd_blops, &props);
|
||||
if (IS_ERR(bdev)) {
|
||||
dev_err(dev, "failed to register backlight\n");
|
||||
return PTR_ERR(bdev);
|
||||
}
|
||||
bdev->props.brightness = 0xff;
|
||||
data->lcd_brightness = 0xff;
|
||||
data->backlight = bdev;
|
||||
picolcd_set_brightness(bdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void picolcd_exit_backlight(struct picolcd_data *data)
|
||||
{
|
||||
struct backlight_device *bdev = data->backlight;
|
||||
|
||||
data->backlight = NULL;
|
||||
if (bdev)
|
||||
backlight_device_unregister(bdev);
|
||||
}
|
||||
|
||||
int picolcd_resume_backlight(struct picolcd_data *data)
|
||||
{
|
||||
if (!data->backlight)
|
||||
return 0;
|
||||
return picolcd_set_brightness(data->backlight);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
void picolcd_suspend_backlight(struct picolcd_data *data)
|
||||
{
|
||||
int bl_power = data->lcd_power;
|
||||
if (!data->backlight)
|
||||
return;
|
||||
|
||||
data->backlight->props.power = FB_BLANK_POWERDOWN;
|
||||
picolcd_set_brightness(data->backlight);
|
||||
data->lcd_power = data->backlight->props.power = bl_power;
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org> *
|
||||
* *
|
||||
* Based on Logitech G13 driver (v0.4) *
|
||||
* Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, version 2 of the License. *
|
||||
* *
|
||||
* This driver is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this software. If not see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#include <linux/hid.h>
|
||||
#include <linux/hid-debug.h>
|
||||
#include <linux/input.h>
|
||||
#include "hid-ids.h"
|
||||
#include "usbhid/usbhid.h"
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/lcd.h>
|
||||
|
||||
#include <linux/leds.h>
|
||||
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/module.h>
|
||||
#include <media/rc-core.h>
|
||||
|
||||
#include "hid-picolcd.h"
|
||||
|
||||
|
||||
int picolcd_raw_cir(struct picolcd_data *data,
|
||||
struct hid_report *report, u8 *raw_data, int size)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i, w, sz;
|
||||
DEFINE_IR_RAW_EVENT(rawir);
|
||||
|
||||
/* ignore if rc_dev is NULL or status is shunned */
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
if (!data->rc_dev || (data->status & PICOLCD_CIR_SHUN)) {
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
return 1;
|
||||
}
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
|
||||
/* PicoLCD USB packets contain 16-bit intervals in network order,
|
||||
* with value negated for pulse. Intervals are in microseconds.
|
||||
*
|
||||
* Note: some userspace LIRC code for PicoLCD says negated values
|
||||
* for space - is it a matter of IR chip? (pulse for my TSOP2236)
|
||||
*
|
||||
* In addition, the first interval seems to be around 15000 + base
|
||||
* interval for non-first report of IR data - thus the quirk below
|
||||
* to get RC_CODE to understand Sony and JVC remotes I have at hand
|
||||
*/
|
||||
sz = size > 0 ? min((int)raw_data[0], size-1) : 0;
|
||||
for (i = 0; i+1 < sz; i += 2) {
|
||||
init_ir_raw_event(&rawir);
|
||||
w = (raw_data[i] << 8) | (raw_data[i+1]);
|
||||
rawir.pulse = !!(w & 0x8000);
|
||||
rawir.duration = US_TO_NS(rawir.pulse ? (65536 - w) : w);
|
||||
/* Quirk!! - see above */
|
||||
if (i == 0 && rawir.duration > 15000000)
|
||||
rawir.duration -= 15000000;
|
||||
ir_raw_event_store(data->rc_dev, &rawir);
|
||||
}
|
||||
ir_raw_event_handle(data->rc_dev);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int picolcd_cir_open(struct rc_dev *dev)
|
||||
{
|
||||
struct picolcd_data *data = dev->priv;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
data->status &= ~PICOLCD_CIR_SHUN;
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void picolcd_cir_close(struct rc_dev *dev)
|
||||
{
|
||||
struct picolcd_data *data = dev->priv;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
data->status |= PICOLCD_CIR_SHUN;
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
}
|
||||
|
||||
/* initialize CIR input device */
|
||||
int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report)
|
||||
{
|
||||
struct rc_dev *rdev;
|
||||
int ret = 0;
|
||||
|
||||
rdev = rc_allocate_device();
|
||||
if (!rdev)
|
||||
return -ENOMEM;
|
||||
|
||||
rdev->priv = data;
|
||||
rdev->driver_type = RC_DRIVER_IR_RAW;
|
||||
rdev->allowed_protos = RC_TYPE_ALL;
|
||||
rdev->open = picolcd_cir_open;
|
||||
rdev->close = picolcd_cir_close;
|
||||
rdev->input_name = data->hdev->name;
|
||||
rdev->input_phys = data->hdev->phys;
|
||||
rdev->input_id.bustype = data->hdev->bus;
|
||||
rdev->input_id.vendor = data->hdev->vendor;
|
||||
rdev->input_id.product = data->hdev->product;
|
||||
rdev->input_id.version = data->hdev->version;
|
||||
rdev->dev.parent = &data->hdev->dev;
|
||||
rdev->driver_name = PICOLCD_NAME;
|
||||
rdev->map_name = RC_MAP_RC6_MCE;
|
||||
rdev->timeout = MS_TO_NS(100);
|
||||
rdev->rx_resolution = US_TO_NS(1);
|
||||
|
||||
ret = rc_register_device(rdev);
|
||||
if (ret)
|
||||
goto err;
|
||||
data->rc_dev = rdev;
|
||||
return 0;
|
||||
|
||||
err:
|
||||
rc_free_device(rdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void picolcd_exit_cir(struct picolcd_data *data)
|
||||
{
|
||||
struct rc_dev *rdev = data->rc_dev;
|
||||
|
||||
data->rc_dev = NULL;
|
||||
rc_unregister_device(rdev);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,107 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org> *
|
||||
* *
|
||||
* Based on Logitech G13 driver (v0.4) *
|
||||
* Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, version 2 of the License. *
|
||||
* *
|
||||
* This driver is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this software. If not see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#include <linux/hid.h>
|
||||
#include "usbhid/usbhid.h"
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/lcd.h>
|
||||
|
||||
#include "hid-picolcd.h"
|
||||
|
||||
/*
|
||||
* lcd class device
|
||||
*/
|
||||
static int picolcd_get_contrast(struct lcd_device *ldev)
|
||||
{
|
||||
struct picolcd_data *data = lcd_get_data(ldev);
|
||||
return data->lcd_contrast;
|
||||
}
|
||||
|
||||
static int picolcd_set_contrast(struct lcd_device *ldev, int contrast)
|
||||
{
|
||||
struct picolcd_data *data = lcd_get_data(ldev);
|
||||
struct hid_report *report = picolcd_out_report(REPORT_CONTRAST, data->hdev);
|
||||
unsigned long flags;
|
||||
|
||||
if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
|
||||
return -ENODEV;
|
||||
|
||||
data->lcd_contrast = contrast & 0x0ff;
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
hid_set_field(report->field[0], 0, data->lcd_contrast);
|
||||
if (!(data->status & PICOLCD_FAILED))
|
||||
usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int picolcd_check_lcd_fb(struct lcd_device *ldev, struct fb_info *fb)
|
||||
{
|
||||
return fb && fb == picolcd_fbinfo((struct picolcd_data *)lcd_get_data(ldev));
|
||||
}
|
||||
|
||||
static struct lcd_ops picolcd_lcdops = {
|
||||
.get_contrast = picolcd_get_contrast,
|
||||
.set_contrast = picolcd_set_contrast,
|
||||
.check_fb = picolcd_check_lcd_fb,
|
||||
};
|
||||
|
||||
int picolcd_init_lcd(struct picolcd_data *data, struct hid_report *report)
|
||||
{
|
||||
struct device *dev = &data->hdev->dev;
|
||||
struct lcd_device *ldev;
|
||||
|
||||
if (!report)
|
||||
return -ENODEV;
|
||||
if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
|
||||
report->field[0]->report_size != 8) {
|
||||
dev_err(dev, "unsupported CONTRAST report");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ldev = lcd_device_register(dev_name(dev), dev, data, &picolcd_lcdops);
|
||||
if (IS_ERR(ldev)) {
|
||||
dev_err(dev, "failed to register LCD\n");
|
||||
return PTR_ERR(ldev);
|
||||
}
|
||||
ldev->props.max_contrast = 0x0ff;
|
||||
data->lcd_contrast = 0xe5;
|
||||
data->lcd = ldev;
|
||||
picolcd_set_contrast(ldev, 0xe5);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void picolcd_exit_lcd(struct picolcd_data *data)
|
||||
{
|
||||
struct lcd_device *ldev = data->lcd;
|
||||
|
||||
data->lcd = NULL;
|
||||
if (ldev)
|
||||
lcd_device_unregister(ldev);
|
||||
}
|
||||
|
||||
int picolcd_resume_lcd(struct picolcd_data *data)
|
||||
{
|
||||
if (!data->lcd)
|
||||
return 0;
|
||||
return picolcd_set_contrast(data->lcd, data->lcd_contrast);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org> *
|
||||
* *
|
||||
* Based on Logitech G13 driver (v0.4) *
|
||||
* Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, version 2 of the License. *
|
||||
* *
|
||||
* This driver is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this software. If not see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#include <linux/hid.h>
|
||||
#include <linux/hid-debug.h>
|
||||
#include <linux/input.h>
|
||||
#include "hid-ids.h"
|
||||
#include "usbhid/usbhid.h"
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/lcd.h>
|
||||
|
||||
#include <linux/leds.h>
|
||||
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "hid-picolcd.h"
|
||||
|
||||
|
||||
void picolcd_leds_set(struct picolcd_data *data)
|
||||
{
|
||||
struct hid_report *report;
|
||||
unsigned long flags;
|
||||
|
||||
if (!data->led[0])
|
||||
return;
|
||||
report = picolcd_out_report(REPORT_LED_STATE, data->hdev);
|
||||
if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
hid_set_field(report->field[0], 0, data->led_state);
|
||||
if (!(data->status & PICOLCD_FAILED))
|
||||
usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
}
|
||||
|
||||
static void picolcd_led_set_brightness(struct led_classdev *led_cdev,
|
||||
enum led_brightness value)
|
||||
{
|
||||
struct device *dev;
|
||||
struct hid_device *hdev;
|
||||
struct picolcd_data *data;
|
||||
int i, state = 0;
|
||||
|
||||
dev = led_cdev->dev->parent;
|
||||
hdev = container_of(dev, struct hid_device, dev);
|
||||
data = hid_get_drvdata(hdev);
|
||||
if (!data)
|
||||
return;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (led_cdev != data->led[i])
|
||||
continue;
|
||||
state = (data->led_state >> i) & 1;
|
||||
if (value == LED_OFF && state) {
|
||||
data->led_state &= ~(1 << i);
|
||||
picolcd_leds_set(data);
|
||||
} else if (value != LED_OFF && !state) {
|
||||
data->led_state |= 1 << i;
|
||||
picolcd_leds_set(data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static enum led_brightness picolcd_led_get_brightness(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct device *dev;
|
||||
struct hid_device *hdev;
|
||||
struct picolcd_data *data;
|
||||
int i, value = 0;
|
||||
|
||||
dev = led_cdev->dev->parent;
|
||||
hdev = container_of(dev, struct hid_device, dev);
|
||||
data = hid_get_drvdata(hdev);
|
||||
for (i = 0; i < 8; i++)
|
||||
if (led_cdev == data->led[i]) {
|
||||
value = (data->led_state >> i) & 1;
|
||||
break;
|
||||
}
|
||||
return value ? LED_FULL : LED_OFF;
|
||||
}
|
||||
|
||||
int picolcd_init_leds(struct picolcd_data *data, struct hid_report *report)
|
||||
{
|
||||
struct device *dev = &data->hdev->dev;
|
||||
struct led_classdev *led;
|
||||
size_t name_sz = strlen(dev_name(dev)) + 8;
|
||||
char *name;
|
||||
int i, ret = 0;
|
||||
|
||||
if (!report)
|
||||
return -ENODEV;
|
||||
if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
|
||||
report->field[0]->report_size != 8) {
|
||||
dev_err(dev, "unsupported LED_STATE report");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
|
||||
if (!led) {
|
||||
dev_err(dev, "can't allocate memory for LED %d\n", i);
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
name = (void *)(&led[1]);
|
||||
snprintf(name, name_sz, "%s::GPO%d", dev_name(dev), i);
|
||||
led->name = name;
|
||||
led->brightness = 0;
|
||||
led->max_brightness = 1;
|
||||
led->brightness_get = picolcd_led_get_brightness;
|
||||
led->brightness_set = picolcd_led_set_brightness;
|
||||
|
||||
data->led[i] = led;
|
||||
ret = led_classdev_register(dev, data->led[i]);
|
||||
if (ret) {
|
||||
data->led[i] = NULL;
|
||||
kfree(led);
|
||||
dev_err(dev, "can't register LED %d\n", i);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
err:
|
||||
for (i = 0; i < 8; i++)
|
||||
if (data->led[i]) {
|
||||
led = data->led[i];
|
||||
data->led[i] = NULL;
|
||||
led_classdev_unregister(led);
|
||||
kfree(led);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void picolcd_exit_leds(struct picolcd_data *data)
|
||||
{
|
||||
struct led_classdev *led;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
led = data->led[i];
|
||||
data->led[i] = NULL;
|
||||
if (!led)
|
||||
continue;
|
||||
led_classdev_unregister(led);
|
||||
kfree(led);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* HID driver for Sony PS3 BD Remote Control
|
||||
*
|
||||
* Copyright (c) 2012 David Dillow <dave@thedillows.org>
|
||||
* Based on a blend of the bluez fakehid user-space code by Marcel Holtmann
|
||||
* and other kernel HID drivers.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*/
|
||||
|
||||
/* NOTE: in order for the Sony PS3 BD Remote Control to be found by
|
||||
* a Bluetooth host, the key combination Start+Enter has to be kept pressed
|
||||
* for about 7 seconds with the Bluetooth Host Controller in discovering mode.
|
||||
*
|
||||
* There will be no PIN request from the device.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "hid-ids.h"
|
||||
|
||||
static __u8 ps3remote_rdesc[] = {
|
||||
0x05, 0x01, /* GUsagePage Generic Desktop */
|
||||
0x09, 0x05, /* LUsage 0x05 [Game Pad] */
|
||||
0xA1, 0x01, /* MCollection Application (mouse, keyboard) */
|
||||
|
||||
/* Use collection 1 for joypad buttons */
|
||||
0xA1, 0x02, /* MCollection Logical (interrelated data) */
|
||||
|
||||
/* Ignore the 1st byte, maybe it is used for a controller
|
||||
* number but it's not needed for correct operation */
|
||||
0x75, 0x08, /* GReportSize 0x08 [8] */
|
||||
0x95, 0x01, /* GReportCount 0x01 [1] */
|
||||
0x81, 0x01, /* MInput 0x01 (Const[0] Arr[1] Abs[2]) */
|
||||
|
||||
/* Bytes from 2nd to 4th are a bitmap for joypad buttons, for these
|
||||
* buttons multiple keypresses are allowed */
|
||||
0x05, 0x09, /* GUsagePage Button */
|
||||
0x19, 0x01, /* LUsageMinimum 0x01 [Button 1 (primary/trigger)] */
|
||||
0x29, 0x18, /* LUsageMaximum 0x18 [Button 24] */
|
||||
0x14, /* GLogicalMinimum [0] */
|
||||
0x25, 0x01, /* GLogicalMaximum 0x01 [1] */
|
||||
0x75, 0x01, /* GReportSize 0x01 [1] */
|
||||
0x95, 0x18, /* GReportCount 0x18 [24] */
|
||||
0x81, 0x02, /* MInput 0x02 (Data[0] Var[1] Abs[2]) */
|
||||
|
||||
0xC0, /* MEndCollection */
|
||||
|
||||
/* Use collection 2 for remote control buttons */
|
||||
0xA1, 0x02, /* MCollection Logical (interrelated data) */
|
||||
|
||||
/* 5th byte is used for remote control buttons */
|
||||
0x05, 0x09, /* GUsagePage Button */
|
||||
0x18, /* LUsageMinimum [No button pressed] */
|
||||
0x29, 0xFE, /* LUsageMaximum 0xFE [Button 254] */
|
||||
0x14, /* GLogicalMinimum [0] */
|
||||
0x26, 0xFE, 0x00, /* GLogicalMaximum 0x00FE [254] */
|
||||
0x75, 0x08, /* GReportSize 0x08 [8] */
|
||||
0x95, 0x01, /* GReportCount 0x01 [1] */
|
||||
0x80, /* MInput */
|
||||
|
||||
/* Ignore bytes from 6th to 11th, 6th to 10th are always constant at
|
||||
* 0xff and 11th is for press indication */
|
||||
0x75, 0x08, /* GReportSize 0x08 [8] */
|
||||
0x95, 0x06, /* GReportCount 0x06 [6] */
|
||||
0x81, 0x01, /* MInput 0x01 (Const[0] Arr[1] Abs[2]) */
|
||||
|
||||
/* 12th byte is for battery strength */
|
||||
0x05, 0x06, /* GUsagePage Generic Device Controls */
|
||||
0x09, 0x20, /* LUsage 0x20 [Battery Strength] */
|
||||
0x14, /* GLogicalMinimum [0] */
|
||||
0x25, 0x05, /* GLogicalMaximum 0x05 [5] */
|
||||
0x75, 0x08, /* GReportSize 0x08 [8] */
|
||||
0x95, 0x01, /* GReportCount 0x01 [1] */
|
||||
0x81, 0x02, /* MInput 0x02 (Data[0] Var[1] Abs[2]) */
|
||||
|
||||
0xC0, /* MEndCollection */
|
||||
|
||||
0xC0 /* MEndCollection [Game Pad] */
|
||||
};
|
||||
|
||||
static const unsigned int ps3remote_keymap_joypad_buttons[] = {
|
||||
[0x01] = KEY_SELECT,
|
||||
[0x02] = BTN_THUMBL, /* L3 */
|
||||
[0x03] = BTN_THUMBR, /* R3 */
|
||||
[0x04] = BTN_START,
|
||||
[0x05] = KEY_UP,
|
||||
[0x06] = KEY_RIGHT,
|
||||
[0x07] = KEY_DOWN,
|
||||
[0x08] = KEY_LEFT,
|
||||
[0x09] = BTN_TL2, /* L2 */
|
||||
[0x0a] = BTN_TR2, /* R2 */
|
||||
[0x0b] = BTN_TL, /* L1 */
|
||||
[0x0c] = BTN_TR, /* R1 */
|
||||
[0x0d] = KEY_OPTION, /* options/triangle */
|
||||
[0x0e] = KEY_BACK, /* back/circle */
|
||||
[0x0f] = BTN_0, /* cross */
|
||||
[0x10] = KEY_SCREEN, /* view/square */
|
||||
[0x11] = KEY_HOMEPAGE, /* PS button */
|
||||
[0x14] = KEY_ENTER,
|
||||
};
|
||||
static const unsigned int ps3remote_keymap_remote_buttons[] = {
|
||||
[0x00] = KEY_1,
|
||||
[0x01] = KEY_2,
|
||||
[0x02] = KEY_3,
|
||||
[0x03] = KEY_4,
|
||||
[0x04] = KEY_5,
|
||||
[0x05] = KEY_6,
|
||||
[0x06] = KEY_7,
|
||||
[0x07] = KEY_8,
|
||||
[0x08] = KEY_9,
|
||||
[0x09] = KEY_0,
|
||||
[0x0e] = KEY_ESC, /* return */
|
||||
[0x0f] = KEY_CLEAR,
|
||||
[0x16] = KEY_EJECTCD,
|
||||
[0x1a] = KEY_MENU, /* top menu */
|
||||
[0x28] = KEY_TIME,
|
||||
[0x30] = KEY_PREVIOUS,
|
||||
[0x31] = KEY_NEXT,
|
||||
[0x32] = KEY_PLAY,
|
||||
[0x33] = KEY_REWIND, /* scan back */
|
||||
[0x34] = KEY_FORWARD, /* scan forward */
|
||||
[0x38] = KEY_STOP,
|
||||
[0x39] = KEY_PAUSE,
|
||||
[0x40] = KEY_CONTEXT_MENU, /* pop up/menu */
|
||||
[0x60] = KEY_FRAMEBACK, /* slow/step back */
|
||||
[0x61] = KEY_FRAMEFORWARD, /* slow/step forward */
|
||||
[0x63] = KEY_SUBTITLE,
|
||||
[0x64] = KEY_AUDIO,
|
||||
[0x65] = KEY_ANGLE,
|
||||
[0x70] = KEY_INFO, /* display */
|
||||
[0x80] = KEY_BLUE,
|
||||
[0x81] = KEY_RED,
|
||||
[0x82] = KEY_GREEN,
|
||||
[0x83] = KEY_YELLOW,
|
||||
};
|
||||
|
||||
static __u8 *ps3remote_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
unsigned int *rsize)
|
||||
{
|
||||
*rsize = sizeof(ps3remote_rdesc);
|
||||
return ps3remote_rdesc;
|
||||
}
|
||||
|
||||
static int ps3remote_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||
struct hid_field *field, struct hid_usage *usage,
|
||||
unsigned long **bit, int *max)
|
||||
{
|
||||
unsigned int key = usage->hid & HID_USAGE;
|
||||
|
||||
if ((usage->hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
|
||||
return -1;
|
||||
|
||||
switch (usage->collection_index) {
|
||||
case 1:
|
||||
if (key >= ARRAY_SIZE(ps3remote_keymap_joypad_buttons))
|
||||
return -1;
|
||||
|
||||
key = ps3remote_keymap_joypad_buttons[key];
|
||||
if (!key)
|
||||
return -1;
|
||||
break;
|
||||
case 2:
|
||||
if (key >= ARRAY_SIZE(ps3remote_keymap_remote_buttons))
|
||||
return -1;
|
||||
|
||||
key = ps3remote_keymap_remote_buttons[key];
|
||||
if (!key)
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
hid_map_usage_clear(hi, usage, bit, max, EV_KEY, key);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct hid_device_id ps3remote_devices[] = {
|
||||
/* PS3 BD Remote Control */
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE) },
|
||||
/* Logitech Harmony Adapter for PS3 */
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_PS3) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, ps3remote_devices);
|
||||
|
||||
static struct hid_driver ps3remote_driver = {
|
||||
.name = "ps3_remote",
|
||||
.id_table = ps3remote_devices,
|
||||
.report_fixup = ps3remote_fixup,
|
||||
.input_mapping = ps3remote_mapping,
|
||||
};
|
||||
|
||||
static int __init ps3remote_init(void)
|
||||
{
|
||||
return hid_register_driver(&ps3remote_driver);
|
||||
}
|
||||
|
||||
static void __exit ps3remote_exit(void)
|
||||
{
|
||||
hid_unregister_driver(&ps3remote_driver);
|
||||
}
|
||||
|
||||
module_init(ps3remote_init);
|
||||
module_exit(ps3remote_exit);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("David Dillow <dave@thedillows.org>, Antonio Ospite <ospite@studenti.unina.it>");
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user