@@ -28,6 +28,7 @@ enum lg_g15_model {
2828 LG_G15_V2 ,
2929 LG_G510 ,
3030 LG_G510_USB_AUDIO ,
31+ LG_Z10 ,
3132};
3233
3334enum lg_g15_led_type {
@@ -457,14 +458,34 @@ static int lg_g15_get_initial_led_brightness(struct lg_g15_data *g15)
457458 return ret ;
458459
459460 return lg_g510_update_mkey_led_brightness (g15 );
461+ case LG_Z10 :
462+ /*
463+ * Getting the LCD backlight brightness is not supported.
464+ * Reading Feature(2) fails with -EPIPE and this crashes
465+ * the LCD and touch keys part of the speakers.
466+ */
467+ return 0 ;
460468 }
461469 return - EINVAL ; /* Never reached */
462470}
463471
464472/******** Input functions ********/
465473
466474/* On the G15 Mark I Logitech has been quite creative with which bit is what */
467- static int lg_g15_event (struct lg_g15_data * g15 , u8 * data , int size )
475+ static void lg_g15_handle_lcd_menu_keys (struct lg_g15_data * g15 , u8 * data )
476+ {
477+ int i , val ;
478+
479+ /* Most left (round/display) button below the LCD */
480+ input_report_key (g15 -> input , KEY_KBD_LCD_MENU1 , data [8 ] & 0x80 );
481+ /* 4 other buttons below the LCD */
482+ for (i = 0 ; i < 4 ; i ++ ) {
483+ val = data [i + 2 ] & 0x80 ;
484+ input_report_key (g15 -> input , KEY_KBD_LCD_MENU2 + i , val );
485+ }
486+ }
487+
488+ static int lg_g15_event (struct lg_g15_data * g15 , u8 * data )
468489{
469490 int i , val ;
470491
@@ -494,13 +515,7 @@ static int lg_g15_event(struct lg_g15_data *g15, u8 *data, int size)
494515 /* MR */
495516 input_report_key (g15 -> input , KEY_MACRO_RECORD_START , data [7 ] & 0x40 );
496517
497- /* Most left (round) button below the LCD */
498- input_report_key (g15 -> input , KEY_KBD_LCD_MENU1 , data [8 ] & 0x80 );
499- /* 4 other buttons below the LCD */
500- for (i = 0 ; i < 4 ; i ++ ) {
501- val = data [i + 2 ] & 0x80 ;
502- input_report_key (g15 -> input , KEY_KBD_LCD_MENU2 + i , val );
503- }
518+ lg_g15_handle_lcd_menu_keys (g15 , data );
504519
505520 /* Backlight cycle button pressed? */
506521 if (data [1 ] & 0x80 )
@@ -510,7 +525,7 @@ static int lg_g15_event(struct lg_g15_data *g15, u8 *data, int size)
510525 return 0 ;
511526}
512527
513- static int lg_g15_v2_event (struct lg_g15_data * g15 , u8 * data , int size )
528+ static int lg_g15_v2_event (struct lg_g15_data * g15 , u8 * data )
514529{
515530 int i , val ;
516531
@@ -542,7 +557,7 @@ static int lg_g15_v2_event(struct lg_g15_data *g15, u8 *data, int size)
542557 return 0 ;
543558}
544559
545- static int lg_g510_event (struct lg_g15_data * g15 , u8 * data , int size )
560+ static int lg_g510_event (struct lg_g15_data * g15 , u8 * data )
546561{
547562 bool game_mode_enabled ;
548563 int i , val ;
@@ -586,7 +601,7 @@ static int lg_g510_event(struct lg_g15_data *g15, u8 *data, int size)
586601 return 0 ;
587602}
588603
589- static int lg_g510_leds_event (struct lg_g15_data * g15 , u8 * data , int size )
604+ static int lg_g510_leds_event (struct lg_g15_data * g15 , u8 * data )
590605{
591606 bool backlight_disabled ;
592607
@@ -613,18 +628,24 @@ static int lg_g15_raw_event(struct hid_device *hdev, struct hid_report *report,
613628 switch (g15 -> model ) {
614629 case LG_G15 :
615630 if (data [0 ] == 0x02 && size == 9 )
616- return lg_g15_event (g15 , data , size );
631+ return lg_g15_event (g15 , data );
617632 break ;
618633 case LG_G15_V2 :
619634 if (data [0 ] == 0x02 && size == 5 )
620- return lg_g15_v2_event (g15 , data , size );
635+ return lg_g15_v2_event (g15 , data );
636+ break ;
637+ case LG_Z10 :
638+ if (data [0 ] == 0x02 && size == 9 ) {
639+ lg_g15_handle_lcd_menu_keys (g15 , data );
640+ input_sync (g15 -> input );
641+ }
621642 break ;
622643 case LG_G510 :
623644 case LG_G510_USB_AUDIO :
624645 if (data [0 ] == 0x03 && size == 5 )
625- return lg_g510_event (g15 , data , size );
646+ return lg_g510_event (g15 , data );
626647 if (data [0 ] == 0x04 && size == 2 )
627- return lg_g510_leds_event (g15 , data , size );
648+ return lg_g510_leds_event (g15 , data );
628649 break ;
629650 }
630651
@@ -645,25 +666,18 @@ static void lg_g15_input_close(struct input_dev *dev)
645666 hid_hw_close (hdev );
646667}
647668
648- static int lg_g15_register_led (struct lg_g15_data * g15 , int i )
669+ static int lg_g15_register_led (struct lg_g15_data * g15 , int i , const char * name )
649670{
650- static const char * const led_names [] = {
651- "g15::kbd_backlight" ,
652- "g15::lcd_backlight" ,
653- "g15::macro_preset1" ,
654- "g15::macro_preset2" ,
655- "g15::macro_preset3" ,
656- "g15::macro_record" ,
657- };
658-
659671 g15 -> leds [i ].led = i ;
660- g15 -> leds [i ].cdev .name = led_names [ i ] ;
672+ g15 -> leds [i ].cdev .name = name ;
661673
662674 switch (g15 -> model ) {
663675 case LG_G15 :
664676 case LG_G15_V2 :
665- g15 -> leds [i ].cdev .brightness_set_blocking = lg_g15_led_set ;
666677 g15 -> leds [i ].cdev .brightness_get = lg_g15_led_get ;
678+ fallthrough ;
679+ case LG_Z10 :
680+ g15 -> leds [i ].cdev .brightness_set_blocking = lg_g15_led_set ;
667681 if (i < LG_G15_BRIGHTNESS_MAX ) {
668682 g15 -> leds [i ].cdev .flags = LED_BRIGHT_HW_CHANGED ;
669683 g15 -> leds [i ].cdev .max_brightness = 2 ;
@@ -702,8 +716,38 @@ static int lg_g15_register_led(struct lg_g15_data *g15, int i)
702716 return devm_led_classdev_register (& g15 -> hdev -> dev , & g15 -> leds [i ].cdev );
703717}
704718
719+ /* Common input device init code shared between keyboards and Z-10 speaker handling */
720+ static void lg_g15_init_input_dev (struct hid_device * hdev , struct input_dev * input ,
721+ const char * name )
722+ {
723+ int i ;
724+
725+ input -> name = name ;
726+ input -> phys = hdev -> phys ;
727+ input -> uniq = hdev -> uniq ;
728+ input -> id .bustype = hdev -> bus ;
729+ input -> id .vendor = hdev -> vendor ;
730+ input -> id .product = hdev -> product ;
731+ input -> id .version = hdev -> version ;
732+ input -> dev .parent = & hdev -> dev ;
733+ input -> open = lg_g15_input_open ;
734+ input -> close = lg_g15_input_close ;
735+
736+ /* Keys below the LCD, intended for controlling a menu on the LCD */
737+ for (i = 0 ; i < 5 ; i ++ )
738+ input_set_capability (input , EV_KEY , KEY_KBD_LCD_MENU1 + i );
739+ }
740+
705741static int lg_g15_probe (struct hid_device * hdev , const struct hid_device_id * id )
706742{
743+ static const char * const led_names [] = {
744+ "g15::kbd_backlight" ,
745+ "g15::lcd_backlight" ,
746+ "g15::macro_preset1" ,
747+ "g15::macro_preset2" ,
748+ "g15::macro_preset3" ,
749+ "g15::macro_record" ,
750+ };
707751 u8 gkeys_settings_output_report = 0 ;
708752 u8 gkeys_settings_feature_report = 0 ;
709753 struct hid_report_enum * rep_enum ;
@@ -744,6 +788,8 @@ static int lg_g15_probe(struct hid_device *hdev, const struct hid_device_id *id)
744788
745789 g15 -> hdev = hdev ;
746790 g15 -> model = id -> driver_data ;
791+ g15 -> input = input ;
792+ input_set_drvdata (input , hdev );
747793 hid_set_drvdata (hdev , (void * )g15 );
748794
749795 switch (g15 -> model ) {
@@ -772,6 +818,9 @@ static int lg_g15_probe(struct hid_device *hdev, const struct hid_device_id *id)
772818 gkeys_settings_feature_report = 0x01 ;
773819 gkeys = 18 ;
774820 break ;
821+ case LG_Z10 :
822+ connect_mask = HID_CONNECT_HIDRAW ;
823+ break ;
775824 }
776825
777826 ret = hid_hw_start (hdev , connect_mask );
@@ -814,17 +863,21 @@ static int lg_g15_probe(struct hid_device *hdev, const struct hid_device_id *id)
814863 if (ret )
815864 goto error_hw_stop ;
816865
866+ if (g15 -> model == LG_Z10 ) {
867+ lg_g15_init_input_dev (hdev , g15 -> input , "Logitech Z-10 LCD Menu Keys" );
868+ ret = input_register_device (g15 -> input );
869+ if (ret )
870+ goto error_hw_stop ;
871+
872+ ret = lg_g15_register_led (g15 , 1 , "z-10::lcd_backlight" );
873+ if (ret )
874+ goto error_hw_stop ;
875+
876+ return 0 ; /* All done */
877+ }
878+
817879 /* Setup and register input device */
818- input -> name = "Logitech Gaming Keyboard Gaming Keys" ;
819- input -> phys = hdev -> phys ;
820- input -> uniq = hdev -> uniq ;
821- input -> id .bustype = hdev -> bus ;
822- input -> id .vendor = hdev -> vendor ;
823- input -> id .product = hdev -> product ;
824- input -> id .version = hdev -> version ;
825- input -> dev .parent = & hdev -> dev ;
826- input -> open = lg_g15_input_open ;
827- input -> close = lg_g15_input_close ;
880+ lg_g15_init_input_dev (hdev , input , "Logitech Gaming Keyboard Gaming Keys" );
828881
829882 /* G-keys */
830883 for (i = 0 ; i < gkeys ; i ++ )
@@ -835,10 +888,6 @@ static int lg_g15_probe(struct hid_device *hdev, const struct hid_device_id *id)
835888 input_set_capability (input , EV_KEY , KEY_MACRO_PRESET1 + i );
836889 input_set_capability (input , EV_KEY , KEY_MACRO_RECORD_START );
837890
838- /* Keys below the LCD, intended for controlling a menu on the LCD */
839- for (i = 0 ; i < 5 ; i ++ )
840- input_set_capability (input , EV_KEY , KEY_KBD_LCD_MENU1 + i );
841-
842891 /*
843892 * On the G510 only report headphone and mic mute keys when *not* using
844893 * the builtin USB audio device. When the builtin audio is used these
@@ -850,16 +899,13 @@ static int lg_g15_probe(struct hid_device *hdev, const struct hid_device_id *id)
850899 input_set_capability (input , EV_KEY , KEY_F20 );
851900 }
852901
853- g15 -> input = input ;
854- input_set_drvdata (input , hdev );
855-
856902 ret = input_register_device (input );
857903 if (ret )
858904 goto error_hw_stop ;
859905
860906 /* Register LED devices */
861907 for (i = 0 ; i < LG_G15_LED_MAX ; i ++ ) {
862- ret = lg_g15_register_led (g15 , i );
908+ ret = lg_g15_register_led (g15 , i , led_names [ i ] );
863909 if (ret )
864910 goto error_hw_stop ;
865911 }
@@ -890,6 +936,10 @@ static const struct hid_device_id lg_g15_devices[] = {
890936 { HID_USB_DEVICE (USB_VENDOR_ID_LOGITECH ,
891937 USB_DEVICE_ID_LOGITECH_G510_USB_AUDIO ),
892938 .driver_data = LG_G510_USB_AUDIO },
939+ /* Z-10 speakers */
940+ { HID_USB_DEVICE (USB_VENDOR_ID_LOGITECH ,
941+ USB_DEVICE_ID_LOGITECH_Z_10_SPK ),
942+ .driver_data = LG_Z10 },
893943 { }
894944};
895945MODULE_DEVICE_TABLE (hid , lg_g15_devices );
@@ -902,4 +952,5 @@ static struct hid_driver lg_g15_driver = {
902952};
903953module_hid_driver (lg_g15_driver );
904954
955+ MODULE_AUTHOR ("Hans de Goede <hdegoede@redhat.com>" );
905956MODULE_LICENSE ("GPL" );
0 commit comments