@@ -37,6 +37,11 @@ static bool userspace_control;
3737 */
3838static bool has_manual_suspend ;
3939
40+ /*
41+ * Lightbar version
42+ */
43+ static int lb_version ;
44+
4045static ssize_t interval_msec_show (struct device * dev ,
4146 struct device_attribute * attr , char * buf )
4247{
@@ -93,18 +98,20 @@ static int lb_throttle(void)
9398
9499static struct cros_ec_command * alloc_lightbar_cmd_msg (struct cros_ec_dev * ec )
95100{
101+ int len = max (ec -> ec_dev -> max_response , ec -> ec_dev -> max_request );
96102 struct cros_ec_command * msg ;
97- int len ;
98-
99- len = max (sizeof (struct ec_params_lightbar ),
100- sizeof (struct ec_response_lightbar ));
101103
102104 msg = kmalloc (sizeof (* msg ) + len , GFP_KERNEL );
103105 if (!msg )
104106 return NULL ;
105107
106108 msg -> version = 0 ;
107109 msg -> command = EC_CMD_LIGHTBAR_CMD + ec -> cmd_offset ;
110+ /*
111+ * Default sizes for regular commands.
112+ * Can be set smaller to optimize transfer,
113+ * larger when sending large light sequences.
114+ */
108115 msg -> outsize = sizeof (struct ec_params_lightbar );
109116 msg -> insize = sizeof (struct ec_response_lightbar );
110117
@@ -126,7 +133,7 @@ static int get_lightbar_version(struct cros_ec_dev *ec,
126133 param = (struct ec_params_lightbar * )msg -> data ;
127134 param -> cmd = LIGHTBAR_CMD_VERSION ;
128135 msg -> outsize = sizeof (param -> cmd );
129- msg -> result = sizeof (resp -> version );
136+ msg -> insize = sizeof (resp -> version );
130137 ret = cros_ec_cmd_xfer_status (ec -> ec_dev , msg );
131138 if (ret < 0 && ret != - EINVAL ) {
132139 ret = 0 ;
@@ -180,6 +187,47 @@ static ssize_t version_show(struct device *dev,
180187 return sysfs_emit (buf , "%d %d\n" , version , flags );
181188}
182189
190+ static ssize_t num_segments_show (struct device * dev ,
191+ struct device_attribute * attr , char * buf )
192+ {
193+ struct ec_params_lightbar * param ;
194+ struct ec_response_lightbar * resp ;
195+ struct cros_ec_command * msg ;
196+ struct cros_ec_dev * ec = to_cros_ec_dev (dev );
197+ uint32_t num = 0 ;
198+ int ret ;
199+
200+ ret = lb_throttle ();
201+ if (ret )
202+ return ret ;
203+
204+ msg = alloc_lightbar_cmd_msg (ec );
205+ if (!msg )
206+ return - ENOMEM ;
207+
208+ param = (struct ec_params_lightbar * )msg -> data ;
209+ param -> cmd = LIGHTBAR_CMD_GET_PARAMS_V3 ;
210+ msg -> outsize = sizeof (param -> cmd );
211+ msg -> insize = sizeof (resp -> get_params_v3 );
212+ ret = cros_ec_cmd_xfer_status (ec -> ec_dev , msg );
213+ if (ret < 0 && ret != - EINVAL )
214+ goto exit ;
215+
216+ if (msg -> result == EC_RES_SUCCESS ) {
217+ resp = (struct ec_response_lightbar * )msg -> data ;
218+ num = resp -> get_params_v3 .reported_led_num ;
219+ }
220+
221+ /*
222+ * Anything else (ie, EC_RES_INVALID_COMMAND) - no direct control over
223+ * LEDs, return that no leds are supported.
224+ */
225+ ret = sysfs_emit (buf , "%u\n" , num );
226+ exit :
227+ kfree (msg );
228+ return ret ;
229+ }
230+
183231static ssize_t brightness_store (struct device * dev ,
184232 struct device_attribute * attr ,
185233 const char * buf , size_t count )
@@ -430,25 +478,34 @@ static ssize_t sequence_store(struct device *dev, struct device_attribute *attr,
430478static ssize_t program_store (struct device * dev , struct device_attribute * attr ,
431479 const char * buf , size_t count )
432480{
433- int extra_bytes , max_size , ret ;
481+ size_t extra_bytes , max_size ;
434482 struct ec_params_lightbar * param ;
435483 struct cros_ec_command * msg ;
436484 struct cros_ec_dev * ec = to_cros_ec_dev (dev );
485+ int ret ;
437486
438487 /*
439488 * We might need to reject the program for size reasons. The EC
440489 * enforces a maximum program size, but we also don't want to try
441490 * and send a program that is too big for the protocol. In order
442491 * to ensure the latter, we also need to ensure we have extra bytes
443492 * to represent the rest of the packet.
493+ * With V3, larger program can be sent, limited only by the EC.
494+ * Only the protocol limit the payload size.
444495 */
445- extra_bytes = sizeof (* param ) - sizeof (param -> set_program .data );
446- max_size = min (EC_LB_PROG_LEN , ec -> ec_dev -> max_request - extra_bytes );
447- if (count > max_size ) {
448- dev_err (dev , "Program is %u bytes, too long to send (max: %u)" ,
449- (unsigned int )count , max_size );
450-
451- return - EINVAL ;
496+ if (lb_version < 3 ) {
497+ extra_bytes = sizeof (* param ) - sizeof (param -> set_program .data );
498+ max_size = min (EC_LB_PROG_LEN , ec -> ec_dev -> max_request - extra_bytes );
499+ if (count > max_size ) {
500+ dev_err (dev , "Program is %zu bytes, too long to send (max: %zu)" ,
501+ count , max_size );
502+
503+ return - EINVAL ;
504+ }
505+ } else {
506+ extra_bytes = offsetof(typeof (* param ), set_program_ex ) +
507+ sizeof (param -> set_program_ex );
508+ max_size = ec -> ec_dev -> max_request - extra_bytes ;
452509 }
453510
454511 msg = alloc_lightbar_cmd_msg (ec );
@@ -458,26 +515,44 @@ static ssize_t program_store(struct device *dev, struct device_attribute *attr,
458515 ret = lb_throttle ();
459516 if (ret )
460517 goto exit ;
518+ param = (struct ec_params_lightbar * )msg -> data ;
461519
462- dev_info (dev , "Copying %zu byte program to EC" , count );
520+ if (lb_version < 3 ) {
521+ dev_info (dev , "Copying %zu byte program to EC" , count );
463522
464- param = (struct ec_params_lightbar * )msg -> data ;
465- param -> cmd = LIGHTBAR_CMD_SET_PROGRAM ;
523+ param -> cmd = LIGHTBAR_CMD_SET_PROGRAM ;
466524
467- param -> set_program .size = count ;
468- memcpy (param -> set_program .data , buf , count );
525+ param -> set_program .size = count ;
526+ memcpy (param -> set_program .data , buf , count );
469527
470- /*
471- * We need to set the message size manually or else it will use
472- * EC_LB_PROG_LEN. This might be too long, and the program
473- * is unlikely to use all of the space.
474- */
475- msg -> outsize = count + extra_bytes ;
528+ /*
529+ * We need to set the message size manually or else it will use
530+ * EC_LB_PROG_LEN. This might be too long, and the program
531+ * is unlikely to use all of the space.
532+ */
533+ msg -> outsize = count + extra_bytes ;
476534
477- ret = cros_ec_cmd_xfer_status (ec -> ec_dev , msg );
478- if (ret < 0 )
479- goto exit ;
535+ ret = cros_ec_cmd_xfer_status (ec -> ec_dev , msg );
536+ if (ret < 0 )
537+ goto exit ;
538+ } else {
539+ size_t offset = 0 ;
540+ size_t payload = 0 ;
541+
542+ param -> cmd = LIGHTBAR_CMD_SET_PROGRAM_EX ;
543+ while (offset < count ) {
544+ payload = min (max_size , count - offset );
545+ param -> set_program_ex .offset = offset ;
546+ param -> set_program_ex .size = payload ;
547+ memcpy (param -> set_program_ex .data , & buf [offset ], payload );
548+ msg -> outsize = payload + extra_bytes ;
480549
550+ ret = cros_ec_cmd_xfer_status (ec -> ec_dev , msg );
551+ if (ret < 0 )
552+ goto exit ;
553+ offset += payload ;
554+ }
555+ }
481556 ret = count ;
482557exit :
483558 kfree (msg );
@@ -512,6 +587,7 @@ static ssize_t userspace_control_store(struct device *dev,
512587/* Module initialization */
513588
514589static DEVICE_ATTR_RW (interval_msec );
590+ static DEVICE_ATTR_RO (num_segments );
515591static DEVICE_ATTR_RO (version );
516592static DEVICE_ATTR_WO (brightness );
517593static DEVICE_ATTR_WO (led_rgb );
@@ -521,6 +597,7 @@ static DEVICE_ATTR_RW(userspace_control);
521597
522598static struct attribute * __lb_cmds_attrs [] = {
523599 & dev_attr_interval_msec .attr ,
600+ & dev_attr_num_segments .attr ,
524601 & dev_attr_version .attr ,
525602 & dev_attr_brightness .attr ,
526603 & dev_attr_led_rgb .attr ,
@@ -553,7 +630,7 @@ static int cros_ec_lightbar_probe(struct platform_device *pd)
553630 * Ask then for the lightbar version, if it's 0 then the 'cros_ec'
554631 * doesn't have a lightbar.
555632 */
556- if (!get_lightbar_version (ec_dev , NULL , NULL ))
633+ if (!get_lightbar_version (ec_dev , & lb_version , NULL ))
557634 return - ENODEV ;
558635
559636 /* Take control of the lightbar from the EC. */
0 commit comments