@@ -410,6 +410,18 @@ static const char * const joycon_player_led_names[] = {
410410 LED_FUNCTION_PLAYER4 ,
411411};
412412#define JC_NUM_LEDS ARRAY_SIZE(joycon_player_led_names)
413+ #define JC_NUM_LED_PATTERNS 8
414+ /* Taken from https://www.nintendo.com/my/support/qa/detail/33822 */
415+ static const enum led_brightness joycon_player_led_patterns [JC_NUM_LED_PATTERNS ][JC_NUM_LEDS ] = {
416+ { 1 , 0 , 0 , 0 },
417+ { 1 , 1 , 0 , 0 },
418+ { 1 , 1 , 1 , 0 },
419+ { 1 , 1 , 1 , 1 },
420+ { 1 , 0 , 0 , 1 },
421+ { 1 , 0 , 1 , 0 },
422+ { 1 , 0 , 1 , 1 },
423+ { 0 , 1 , 1 , 0 },
424+ };
413425
414426/* Each physical controller is associated with a joycon_ctlr struct */
415427struct joycon_ctlr {
@@ -699,6 +711,25 @@ static int joycon_set_player_leds(struct joycon_ctlr *ctlr, u8 flash, u8 on)
699711 return joycon_send_subcmd (ctlr , req , 1 , HZ /4 );
700712}
701713
714+ static int joycon_set_home_led (struct joycon_ctlr * ctlr , enum led_brightness brightness )
715+ {
716+ struct joycon_subcmd_request * req ;
717+ u8 buffer [sizeof (* req ) + 5 ] = { 0 };
718+ u8 * data ;
719+
720+ req = (struct joycon_subcmd_request * )buffer ;
721+ req -> subcmd_id = JC_SUBCMD_SET_HOME_LIGHT ;
722+ data = req -> data ;
723+ data [0 ] = 0x01 ;
724+ data [1 ] = brightness << 4 ;
725+ data [2 ] = brightness | (brightness << 4 );
726+ data [3 ] = 0x11 ;
727+ data [4 ] = 0x11 ;
728+
729+ hid_dbg (ctlr -> hdev , "setting home led brightness\n" );
730+ return joycon_send_subcmd (ctlr , req , 5 , HZ /4 );
731+ }
732+
702733static int joycon_request_spi_flash_read (struct joycon_ctlr * ctlr ,
703734 u32 start_addr , u8 size , u8 * * reply )
704735{
@@ -1840,6 +1871,7 @@ static int joycon_input_create(struct joycon_ctlr *ctlr)
18401871 return 0 ;
18411872}
18421873
1874+ /* Because the subcommand sets all the leds at once, the brightness argument is ignored */
18431875static int joycon_player_led_brightness_set (struct led_classdev * led ,
18441876 enum led_brightness brightness )
18451877{
@@ -1849,29 +1881,17 @@ static int joycon_player_led_brightness_set(struct led_classdev *led,
18491881 int val = 0 ;
18501882 int i ;
18511883 int ret ;
1852- int num ;
18531884
18541885 ctlr = hid_get_drvdata (hdev );
18551886 if (!ctlr ) {
18561887 hid_err (hdev , "No controller data\n" );
18571888 return - ENODEV ;
18581889 }
18591890
1860- /* determine which player led this is */
1861- for (num = 0 ; num < JC_NUM_LEDS ; num ++ ) {
1862- if (& ctlr -> leds [num ] == led )
1863- break ;
1864- }
1865- if (num >= JC_NUM_LEDS )
1866- return - EINVAL ;
1891+ for (i = 0 ; i < JC_NUM_LEDS ; i ++ )
1892+ val |= ctlr -> leds [i ].brightness << i ;
18671893
18681894 mutex_lock (& ctlr -> output_mutex );
1869- for (i = 0 ; i < JC_NUM_LEDS ; i ++ ) {
1870- if (i == num )
1871- val |= brightness << i ;
1872- else
1873- val |= ctlr -> leds [i ].brightness << i ;
1874- }
18751895 ret = joycon_set_player_leds (ctlr , 0 , val );
18761896 mutex_unlock (& ctlr -> output_mutex );
18771897
@@ -1884,85 +1904,80 @@ static int joycon_home_led_brightness_set(struct led_classdev *led,
18841904 struct device * dev = led -> dev -> parent ;
18851905 struct hid_device * hdev = to_hid_device (dev );
18861906 struct joycon_ctlr * ctlr ;
1887- struct joycon_subcmd_request * req ;
1888- u8 buffer [sizeof (* req ) + 5 ] = { 0 };
1889- u8 * data ;
18901907 int ret ;
18911908
18921909 ctlr = hid_get_drvdata (hdev );
18931910 if (!ctlr ) {
18941911 hid_err (hdev , "No controller data\n" );
18951912 return - ENODEV ;
18961913 }
1897-
1898- req = (struct joycon_subcmd_request * )buffer ;
1899- req -> subcmd_id = JC_SUBCMD_SET_HOME_LIGHT ;
1900- data = req -> data ;
1901- data [0 ] = 0x01 ;
1902- data [1 ] = brightness << 4 ;
1903- data [2 ] = brightness | (brightness << 4 );
1904- data [3 ] = 0x11 ;
1905- data [4 ] = 0x11 ;
1906-
1907- hid_dbg (hdev , "setting home led brightness\n" );
19081914 mutex_lock (& ctlr -> output_mutex );
1909- ret = joycon_send_subcmd (ctlr , req , 5 , HZ / 4 );
1915+ ret = joycon_set_home_led (ctlr , brightness );
19101916 mutex_unlock (& ctlr -> output_mutex );
1911-
19121917 return ret ;
19131918}
19141919
1915- static DEFINE_MUTEX ( joycon_input_num_mutex );
1920+ static DEFINE_SPINLOCK ( joycon_input_num_spinlock );
19161921static int joycon_leds_create (struct joycon_ctlr * ctlr )
19171922{
19181923 struct hid_device * hdev = ctlr -> hdev ;
19191924 struct device * dev = & hdev -> dev ;
19201925 const char * d_name = dev_name (dev );
19211926 struct led_classdev * led ;
1927+ int led_val = 0 ;
19221928 char * name ;
1923- int ret = 0 ;
1929+ int ret ;
19241930 int i ;
1925- static int input_num = 1 ;
1931+ unsigned long flags ;
1932+ int player_led_pattern ;
1933+ static int input_num ;
19261934
1927- /* Set the default controller player leds based on controller number */
1928- mutex_lock (& joycon_input_num_mutex );
1929- mutex_lock (& ctlr -> output_mutex );
1930- ret = joycon_set_player_leds (ctlr , 0 , 0xF >> (4 - input_num ));
1931- if (ret )
1932- hid_warn (ctlr -> hdev , "Failed to set leds; ret=%d\n" , ret );
1933- mutex_unlock (& ctlr -> output_mutex );
1935+ /*
1936+ * Set the player leds based on controller number
1937+ * Because there is no standard concept of "player number", the pattern
1938+ * number will simply increase by 1 every time a controller is connected.
1939+ */
1940+ spin_lock_irqsave (& joycon_input_num_spinlock , flags );
1941+ player_led_pattern = input_num ++ % JC_NUM_LED_PATTERNS ;
1942+ spin_unlock_irqrestore (& joycon_input_num_spinlock , flags );
19341943
19351944 /* configure the player LEDs */
19361945 for (i = 0 ; i < JC_NUM_LEDS ; i ++ ) {
19371946 name = devm_kasprintf (dev , GFP_KERNEL , "%s:%s:%s" ,
19381947 d_name ,
19391948 "green" ,
19401949 joycon_player_led_names [i ]);
1941- if (!name ) {
1942- mutex_unlock (& joycon_input_num_mutex );
1950+ if (!name )
19431951 return - ENOMEM ;
1944- }
19451952
19461953 led = & ctlr -> leds [i ];
19471954 led -> name = name ;
1948- led -> brightness = (( i + 1 ) <= input_num ) ? 1 : 0 ;
1955+ led -> brightness = joycon_player_led_patterns [ player_led_pattern ][ i ] ;
19491956 led -> max_brightness = 1 ;
19501957 led -> brightness_set_blocking =
19511958 joycon_player_led_brightness_set ;
19521959 led -> flags = LED_CORE_SUSPENDRESUME | LED_HW_PLUGGABLE ;
19531960
1961+ led_val |= joycon_player_led_patterns [player_led_pattern ][i ] << i ;
1962+ }
1963+ mutex_lock (& ctlr -> output_mutex );
1964+ ret = joycon_set_player_leds (ctlr , 0 , led_val );
1965+ mutex_unlock (& ctlr -> output_mutex );
1966+ if (ret ) {
1967+ hid_warn (hdev , "Failed to set players LEDs, skipping registration; ret=%d\n" , ret );
1968+ goto home_led ;
1969+ }
1970+
1971+ for (i = 0 ; i < JC_NUM_LEDS ; i ++ ) {
1972+ led = & ctlr -> leds [i ];
19541973 ret = devm_led_classdev_register (& hdev -> dev , led );
19551974 if (ret ) {
1956- hid_err (hdev , "Failed registering %s LED\n" , led -> name );
1957- mutex_unlock (& joycon_input_num_mutex );
1975+ hid_err (hdev , "Failed to register player %d LED; ret=%d\n" , i + 1 , ret );
19581976 return ret ;
19591977 }
19601978 }
19611979
1962- if (++ input_num > 4 )
1963- input_num = 1 ;
1964- mutex_unlock (& joycon_input_num_mutex );
1965-
1980+ home_led :
19661981 /* configure the home LED */
19671982 if (jc_type_has_right (ctlr )) {
19681983 name = devm_kasprintf (dev , GFP_KERNEL , "%s:%s:%s" ,
@@ -1978,16 +1993,20 @@ static int joycon_leds_create(struct joycon_ctlr *ctlr)
19781993 led -> max_brightness = 0xF ;
19791994 led -> brightness_set_blocking = joycon_home_led_brightness_set ;
19801995 led -> flags = LED_CORE_SUSPENDRESUME | LED_HW_PLUGGABLE ;
1981- ret = devm_led_classdev_register (& hdev -> dev , led );
1996+
1997+ /* Set the home LED to 0 as default state */
1998+ mutex_lock (& ctlr -> output_mutex );
1999+ ret = joycon_set_home_led (ctlr , 0 );
2000+ mutex_unlock (& ctlr -> output_mutex );
19822001 if (ret ) {
1983- hid_err (hdev , "Failed registering home led \n" );
1984- return ret ;
2002+ hid_warn (hdev , "Failed to set home LED, skipping registration; ret=%d \n" , ret );
2003+ return 0 ;
19852004 }
1986- /* Set the home LED to 0 as default state */
1987- ret = joycon_home_led_brightness_set ( led , 0 );
2005+
2006+ ret = devm_led_classdev_register ( & hdev -> dev , led );
19882007 if (ret ) {
1989- hid_warn (hdev , "Failed to set home LED default, unregistering home LED" );
1990- devm_led_classdev_unregister ( & hdev -> dev , led ) ;
2008+ hid_err (hdev , "Failed to register home LED; ret=%d\n" , ret );
2009+ return ret ;
19912010 }
19922011 }
19932012
0 commit comments