All of lore.kernel.org
 help / color / mirror / Atom feed
From: Frank Praznik <frank.praznik@gmail.com>
To: Antonio Ospite <ao2@ao2.it>, Frank Praznik <frank.praznik@oh.rr.com>
Cc: linux-input@vger.kernel.org, jkosina@suse.cz, dh.herrmann@gmail.com
Subject: Re: [PATCH 4/6] HID: sony: Add blink support to the LEDs
Date: Sun, 02 Mar 2014 18:43:17 -0500	[thread overview]
Message-ID: <5313C215.6070000@gmail.com> (raw)
In-Reply-To: <20140301152031.1bbf4e527d374f1121401d32@ao2.it>

On 3/1/2014 09:20, Antonio Ospite wrote:
> Hi Frank,
>
> On Fri, 28 Feb 2014 22:58:59 -0500
> Frank Praznik <frank.praznik@oh.rr.com> wrote:
>
>> Add support for setting the blink rate of the LEDs.  The Sixaxis allows control
>> over each individual LED, but the Dualshock 4 only has one global control for
>> the light bar so changing any individual color changes them all.
>>
>> Setting the brightness cancels the blinking as per the LED class
>> specifications.
>>
>> The Sixaxis and Dualshock 4 controllers accept delays in decisecond increments
>> from 0 to 255 (2550 milliseconds).
>>
>> Signed-off-by: Frank Praznik <frank.praznik@oh.rr.com>
>> ---
>>   drivers/hid/hid-sony.c | 105 +++++++++++++++++++++++++++++++++++++++++++------
>>   1 file changed, 93 insertions(+), 12 deletions(-)
>>
>> diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
>> index dc6e6fa..914a6cc 100644
>> --- a/drivers/hid/hid-sony.c
>> +++ b/drivers/hid/hid-sony.c
>> @@ -741,6 +741,8 @@ struct sony_sc {
>>   	__u8 battery_charging;
>>   	__u8 battery_capacity;
>>   	__u8 led_state[MAX_LEDS];
>> +	__u8 led_blink_on[MAX_LEDS];
>> +	__u8 led_blink_off[MAX_LEDS];
> Are those values meant to be for the duty cycle in deciseconds?
> What about using a more explicative name? leds_blink_on makes me think
> to something boolean (it could be just me), maybe leds_delay_on and
> leds_delay_off?
>
> Also grouping spare arrays into a single array of structs may be worth
> considering:
>
> struct sony_sc {
> 	...
> 	struct {
> 		struct led_classdev *ldev;
> 		__u8 state;
> 		__u8 delay_on;
> 		__u8 delay_off;
> 	} leds[MAX_LEDS];
> 	...
> };
>
> Defining the struct for leds separately if you prefer so.
It would be a little more organized, but it would also add extra padding 
to the struct.  I'll think about this one.
>
>>   	__u8 led_count;
>>   };
>>   
>> @@ -1127,8 +1129,7 @@ static void sony_led_set_brightness(struct led_classdev *led,
>>   	struct device *dev = led->dev->parent;
>>   	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
>>   	struct sony_sc *drv_data;
>> -
>> -	int n;
>> +	int n, blink_index = 0;
>>   
>>   	drv_data = hid_get_drvdata(hdev);
>>   	if (!drv_data) {
>> @@ -1136,14 +1137,30 @@ static void sony_led_set_brightness(struct led_classdev *led,
>>   		return;
>>   	}
>>   
>> +	/* Get the index of the LED */
>>   	for (n = 0; n < drv_data->led_count; n++) {
>> -		if (led == drv_data->leds[n]) {
>> -			if (value != drv_data->led_state[n]) {
>> -				drv_data->led_state[n] = value;
>> -				sony_set_leds(drv_data, drv_data->led_state, drv_data->led_count);
>> -			}
>> +		if (led == drv_data->leds[n])
>>   			break;
>> -		}
>> +	}
>> +
>> +	/* This LED is not registered on this device */
>> +	if (n >= drv_data->led_count)
>> +		return;
>> +
>> +	/* The DualShock 4 has a global LED and always uses index 0 */
>> +	if (!(drv_data->quirks & DUALSHOCK4_CONTROLLER))
>> +		blink_index = n;
>> +
> If you feel the need for a comment here, what about not initializing
> blink_index to 0 before and add an else block here, this way the code
> itself is more explicit, and more symmetric too.
Good idea, I'll fix it in v2.
>
>> +	if ((value != drv_data->led_state[n])   ||
>> +		drv_data->led_blink_on[blink_index] ||
>> +		drv_data->led_blink_off[blink_index]) {
>> +		drv_data->led_state[n] = value;
>> +
>> +		/* Setting the brightness stops the blinking */
>> +		drv_data->led_blink_on[blink_index] = 0;
>> +		drv_data->led_blink_off[blink_index] = 0;
>> +
>> +		sony_set_leds(drv_data, drv_data->led_state, drv_data->led_count);
>>   	}
>>   }
>>   
>> @@ -1169,6 +1186,56 @@ static enum led_brightness sony_led_get_brightness(struct led_classdev *led)
>>   	return LED_OFF;
>>   }
>>   
>> +static int sony_blink_set(struct led_classdev *led, unsigned long *delay_on,
>> +				unsigned long *delay_off)
>> +{
>> +	struct device *dev = led->dev->parent;
>> +	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
>> +	struct sony_sc *drv_data = hid_get_drvdata(hdev);
>> +	int n = 0;
>> +	__u8 new_on, new_off;
>> +
>> +	if (!drv_data) {
>> +		hid_err(hdev, "No device data\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	/* Max delay is 255 deciseconds or 2550 milliseconds */
>> +	if (*delay_on > 2550)
>> +		*delay_on = 2550;
>> +	if (*delay_off > 2550)
>> +		*delay_off = 2550;
>> +
>> +	/* Blink at 1 Hz if both values are zero */
>> +	if (!*delay_on && !*delay_off)
>> +		*delay_on = *delay_off = 1000;
>> +
>> +	new_on = *delay_on / 10;
>> +	new_off = *delay_off / 10;
>> +
>> +	/* The blink controls are global on the DualShock 4 */
>> +	if (!(drv_data->quirks & DUALSHOCK4_CONTROLLER)) {
>> +		for (n = 0; n < drv_data->led_count; n++) {
>> +			if (led == drv_data->leds[n])
>> +				break;
>> +		}
>> +	}
>> +
>> +	/* This LED is not registered on this device */
>> +	if (n >= drv_data->led_count)
>> +		return -EINVAL;
>> +
>> +	/* Don't schedule work if the values didn't change */
>> +	if (new_on != drv_data->led_blink_on[n] ||
>> +		new_off != drv_data->led_blink_off[n]) {
>> +		drv_data->led_blink_on[n] = new_on;
>> +		drv_data->led_blink_off[n] = new_off;
>> +		schedule_work(&drv_data->state_worker);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>>   static void sony_leds_remove(struct sony_sc *sc)
>>   {
>>   	struct led_classdev *led;
>> @@ -1259,6 +1326,9 @@ static int sony_leds_init(struct sony_sc *sc)
>>   		led->brightness_get = sony_led_get_brightness;
>>   		led->brightness_set = sony_led_set_brightness;
>>   
>> +		if (!(sc->quirks & BUZZ_CONTROLLER))
>> +			led->blink_set = sony_blink_set;
>> +
>>   		ret = led_classdev_register(&hdev->dev, led);
>>   		if (ret) {
>>   			hid_err(hdev, "Failed to register LED %d\n", n);
>> @@ -1280,14 +1350,15 @@ error_leds:
>>   static void sixaxis_state_worker(struct work_struct *work)
>>   {
>>   	struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
>> +	int n;
>>   	unsigned char buf[] = {
>>   		0x01,
>>   		0x00, 0xff, 0x00, 0xff, 0x00,
>>   		0x00, 0x00, 0x00, 0x00, 0x00,
>> -		0xff, 0x27, 0x10, 0x00, 0x32,
>> -		0xff, 0x27, 0x10, 0x00, 0x32,
>> -		0xff, 0x27, 0x10, 0x00, 0x32,
>> -		0xff, 0x27, 0x10, 0x00, 0x32,
>> +		0xff, 0x27, 0x10, 0x00, 0x32, /* LED 4 */
>> +		0xff, 0x27, 0x10, 0x00, 0x32, /* LED 3 */
>> +		0xff, 0x27, 0x10, 0x00, 0x32, /* LED 2 */
>> +		0xff, 0x27, 0x10, 0x00, 0x32, /* LED 1 */
>>   		0x00, 0x00, 0x00, 0x00, 0x00
>>   	};
>>   
>> @@ -1301,6 +1372,13 @@ static void sixaxis_state_worker(struct work_struct *work)
>>   	buf[10] |= sc->led_state[2] << 3;
>>   	buf[10] |= sc->led_state[3] << 4;
>>   
>> +	for (n = 0; n < 4; n++) {
>> +		if (sc->led_blink_on[n] || sc->led_blink_off[n]) {
>> +			buf[29-(n*5)] = sc->led_blink_off[n];
>> +			buf[30-(n*5)] = sc->led_blink_on[n];
>                              ^^^^^^^^
> Kernel coding style prefers spaces around operators.
> I see that scripts/checkpatch.pl does not warn about this, but it's in
> Documentation/CodingStyle.
>
> However the calculations here made me wonder if it's the case to go
> semantic and represent the output report with a struct instead of an
> array (maybe even using a union), so you can access the individual
> fields in a more meaningful, and less bug prone, way.
>
> For example (untested):
>
> struct sixaxis_led {
> 	uint8_t time_enabled; /* the total time the led is active (0xff means forever) */
> 	uint8_t duty_length;   /* how long a cycle is in deciseconds (0 means "really fast") */
> 	uint8_t enabled;
> 	uint8_t duty_off; /* % of duty_length the led is off (0xff means 100%) */
> 	uint8_t duty_on; /* % of duty_length the led is on (0xff mean 100%) */
>
> } __attribute__ ((packed));
>
> struct sixaxis_output_report {
> 	uint8_t report_id;
> 	uint8_t rumble[5]; /* TODO: add the rumble bits here... */
> 	uint8_t padding[4];
> 	uint8_t leds_bitmap; /* bitmap of enabled LEDs: LED_1 = 0x02, LED_2 = 0x04, ... */
> 	struct sixaxis_led led[4]; /* LEDx at (4 - x), add a macro? */
> 	struct sixaxis_led _reserved; /* LED5, not actually soldered */
> }; __attribute__ ((packed));
>
> union output_report_01 {
> 	struct sixaxis_output_report data;
> 	uint8_t buf[36];
> };
>
> I had the snippet above buried somewhere and I don't remember where
> all the info came from.
Nice, this will be much clearer.  I'll tidy it up and add this as a 
separate refactor patch in v2.  Thanks for the snippet.
>> +		}
>> +	}
>> +
>>   	if (sc->quirks & SIXAXIS_CONTROLLER_USB)
>>   		hid_output_raw_report(sc->hdev, buf, sizeof(buf), HID_OUTPUT_REPORT);
>>   	else
>> @@ -1338,6 +1416,9 @@ static void dualshock4_state_worker(struct work_struct *work)
>>   	buf[offset++] = sc->led_state[1];
>>   	buf[offset++] = sc->led_state[2];
>>   
>> +	buf[offset++] = sc->led_blink_on[0];
>> +	buf[offset++] = sc->led_blink_off[0];
>> +
>>   	if (sc->quirks & DUALSHOCK4_CONTROLLER_USB)
>>   		hid_hw_output_report(hdev, buf, 32);
>>   	else
>> -- 
>> 1.8.5.3
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-input" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>


  reply	other threads:[~2014-03-02 23:43 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-03-01  3:58 [PATCH 0/6] HID: sony: More Sony controller fixes and improvements Frank Praznik
2014-03-01  3:58 ` [PATCH 1/6] HID: sony: Fix Sixaxis cable state detection Frank Praznik
2014-03-01  3:58 ` [PATCH 2/6] HID: sony: Convert startup and shutdown functions to use a uniform parameter type Frank Praznik
2014-03-01  3:58 ` [PATCH 3/6] HID: sony: Use inliners for work queue initialization and cancellation Frank Praznik
2014-03-01  3:58 ` [PATCH 4/6] HID: sony: Add blink support to the LEDs Frank Praznik
2014-03-01 14:20   ` Antonio Ospite
2014-03-02 23:43     ` Frank Praznik [this message]
2014-03-01  3:59 ` [PATCH 5/6] HID: sony: Add an led trigger to report controller battery status Frank Praznik
2014-03-01 14:36   ` Antonio Ospite
2014-03-02 23:48   ` Frank Praznik
2014-03-01  3:59 ` [PATCH 6/6] HID: sony: Turn on the LEDs by default Frank Praznik
2014-03-01 14:38   ` Antonio Ospite
2014-03-01 13:53 ` [PATCH 0/6] HID: sony: More Sony controller fixes and improvements Antonio Ospite
2014-03-02 16:26   ` Frank Praznik
2014-03-02 17:21     ` David Herrmann
2014-03-04 12:34     ` Antonio Ospite
2014-03-04 14:54       ` Frank Praznik

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5313C215.6070000@gmail.com \
    --to=frank.praznik@gmail.com \
    --cc=ao2@ao2.it \
    --cc=dh.herrmann@gmail.com \
    --cc=frank.praznik@oh.rr.com \
    --cc=jkosina@suse.cz \
    --cc=linux-input@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.