From patchwork Mon Apr 26 21:50:28 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marcin Tolysz X-Patchwork-Id: 95212 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o3QLoZ5e007155 for ; Mon, 26 Apr 2010 21:50:35 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755398Ab0DZVue (ORCPT ); Mon, 26 Apr 2010 17:50:34 -0400 Received: from mail-ww0-f46.google.com ([74.125.82.46]:58072 "EHLO mail-ww0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755361Ab0DZVud (ORCPT ); Mon, 26 Apr 2010 17:50:33 -0400 Received: by wwb22 with SMTP id 22so818242wwb.19 for ; Mon, 26 Apr 2010 14:50:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:subject:from:to:cc :content-type:date:message-id:mime-version:x-mailer; bh=mwvduGiahWXEIF/D2+eLoorT1652rU76LjGlDBXzvkk=; b=OfTDT6MDx0ZdDBR1VU0X4ZiJwUCeReqe56AmkucXtKChd5rXBs4Bh62uh2YWR/tn2j 04p4thJaDNTe95ksuNtuncaXfjrli1y78BjXu/UoQrw3/TOYhTZymAfWRlENql22REb/ nIqErCrJ9tK9gLWCwEAtQz2llK/UfFzfOOH3w= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=subject:from:to:cc:content-type:date:message-id:mime-version :x-mailer; b=bcFXaDi4QHYekNJrHfL4mY/G7w5pmwMo4FR53bKzqZ22AUj29weuYXudeoTuC9wm4+ EBWYsbYjA5PZXEC8Pcq1X2f/2Pjc2oMTX7TN16JuxDIyjZ4PfIK66HkGJv9rrOjDPMzz NLn/koU9fFL6bhYZMF+NrEwGQjVc0LM/Q81oQ= Received: by 10.216.86.196 with SMTP id w46mr2199810wee.201.1272318631453; Mon, 26 Apr 2010 14:50:31 -0700 (PDT) Received: from [192.168.1.65] (188-222-174-147.zone13.bethere.co.uk [188.222.174.147]) by mx.google.com with ESMTPS id t27sm1295548wbc.23.2010.04.26.14.50.29 (version=SSLv3 cipher=RC4-MD5); Mon, 26 Apr 2010 14:50:30 -0700 (PDT) Subject: [PATCH] Actual code fixing Sixaxis From: Marcin Tolysz To: linux-input@vger.kernel.org, linux-bluetooth@vger.kernel.org Cc: ospite@studenti.unina.it, hadess@hadess.net Date: Mon, 26 Apr 2010 22:50:28 +0100 Message-ID: <1272318628.3269.44.camel@zony.bied.prout.be> Mime-Version: 1.0 X-Mailer: Evolution 2.28.3 Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Mon, 26 Apr 2010 21:50:35 +0000 (UTC) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 2e2aa75..bb40a19 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -333,10 +334,8 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item) return 0; case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM: - if (parser->global.physical_minimum < 0) - parser->global.physical_maximum = item_sdata(item); - else - parser->global.physical_maximum = item_udata(item); + /* always signed value, if it is less then minimum we need to invert axis */ + parser->global.physical_maximum = item_sdata(item); return 0; case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT: @@ -642,6 +641,10 @@ int hid_parse_report(struct hid_device *device, __u8 *start, struct hid_item item; __u8 *end; int ret; + const struct firmware *fw; + int fw_fail; + const char *file; + static int (*dispatch_type[])(struct hid_parser *parser, struct hid_item *item) = { hid_parser_main, @@ -652,10 +655,39 @@ int hid_parse_report(struct hid_device *device, __u8 *start, if (device->driver->report_fixup) device->driver->report_fixup(device, start, size); + /* Now try to load a hid descriptor from a file firmware + if succesful ignoring this fixup thing */ + /* + Mini howto: fixing the descriptor: + 1) dump it from /debug/hid/!!device!!/rdesc + 2) copy 1st line &edit it + 3) convert to bin eg. cat descriptor.txt | hex2bin.sh > descriptor.bin + +----hex2bin.sh +#!/bin/bash +echo -n -e $(tr -d '[:space:]' | sed 's/../\\x&/g') +4) place in /lib/firmware/hid/... where the location is provided by kern.log +*/ + file = kasprintf(GFP_KERNEL, "hid/%04X:%04X:%04X:%04X.bin", + device->bus, device->vendor, device->product, device->version); + + fw_fail = request_firmware(&fw, file, &device->dev); + + if (fw_fail) + pr_info("To relace HID descriptor place it in /lib/firmaware/%s\n", file); + else{ + start = fw->data; + size = fw->size; + pr_info("HID descriptor relaced with /lib/firmaware/%s\n", file); + } + kfree(file); device->rdesc = kmalloc(size, GFP_KERNEL); - if (device->rdesc == NULL) + if (device->rdesc == NULL) { + if (!fw_fail) + release_firmware(fw); return -ENOMEM; + } memcpy(device->rdesc, start, size); device->rsize = size; @@ -692,6 +724,8 @@ int hid_parse_report(struct hid_device *device, __u8 *start, dbg_hid("unbalanced delimiter at end of report description\n"); goto err; } + if (!fw_fail) + release_firmware(fw); vfree(parser); return 0; } @@ -699,6 +733,8 @@ int hid_parse_report(struct hid_device *device, __u8 *start, dbg_hid("item fetching failed at offset %d\n", (int)(end - start)); err: + if (!fw_fail) + release_firmware(fw); vfree(parser); return ret; } @@ -878,6 +914,25 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field, } /* + * Translate values from logical to physical, exponent is still missing. + */ +static __s32 convert_to_physical(__s32 x, struct hid_field *field) +{ + __s32 min = field->logical_minimum; + __s32 max = field->logical_maximum; + __s32 pmin = field->physical_minimum; + __s32 pmax = field->physical_maximum; +/* __s32 uexp = field->unit_exponent; need to find a way how to use it */ + + if ((pmin == pmax) /* would give pmin and covers the case ==0 */ + || (pmin == min && pmax == max) /* would do nothing */ + || (min == max)) /* would be div by 0 */ + return x; + else + return (pmax - pmin)*(x - min) / (max - min) + pmin; +} + +/* * Analyse a received field, and fetch the data from it. The field * content is stored for next report processing (we do differential * reporting to the layer). @@ -911,7 +966,7 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field, for (n = 0; n < count; n++) { if (HID_MAIN_ITEM_VARIABLE & field->flags) { - hid_process_event(hid, field, &field->usage[n], value[n], interrupt); + hid_process_event(hid, field, &field->usage[n], convert_to_physical(value[n], field), interrupt); continue; } diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 7502a4b..3e094e4 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -45,6 +45,24 @@ static void sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, } /* + * There is a few bits that has to be shifted around to make this report more compatibile with + * HID standard descriptions, and we want it to be parsable by standard driver + */ +static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, __u8 *rd, int size) +{ + /* for sixaxis connected via usb. */ + if (rd[0] == 0x01 && size == 49) { + swap(rd[41], rd[42]); + swap(rd[43], rd[44]); + swap(rd[45], rd[46]); + swap(rd[47], rd[48]); + } + +return 0; +} + + +/* * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller * to "operational". Without this, the ps3 controller will not report any * events. @@ -151,6 +169,7 @@ static struct hid_driver sony_driver = { .probe = sony_probe, .remove = sony_remove, .report_fixup = sony_report_fixup, + .raw_event = sony_raw_event, }; static int __init sony_init(void)