1313#include "acpi_thermal_rel.h"
1414
1515#define INT3400_THERMAL_TABLE_CHANGED 0x83
16+ #define INT3400_ODVP_CHANGED 0x88
1617
1718enum int3400_thermal_uuid {
1819 INT3400_THERMAL_PASSIVE_1 ,
@@ -41,8 +42,11 @@ static char *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {
4142 "BE84BABF-C4D4-403D-B495-3128FD44dAC1" ,
4243};
4344
45+ struct odvp_attr ;
46+
4447struct int3400_thermal_priv {
4548 struct acpi_device * adev ;
49+ struct platform_device * pdev ;
4650 struct thermal_zone_device * thermal ;
4751 int mode ;
4852 int art_count ;
@@ -53,6 +57,17 @@ struct int3400_thermal_priv {
5357 int rel_misc_dev_res ;
5458 int current_uuid_index ;
5559 char * data_vault ;
60+ int odvp_count ;
61+ int * odvp ;
62+ struct odvp_attr * odvp_attrs ;
63+ };
64+
65+ static int evaluate_odvp (struct int3400_thermal_priv * priv );
66+
67+ struct odvp_attr {
68+ int odvp ;
69+ struct int3400_thermal_priv * priv ;
70+ struct kobj_attribute attr ;
5671};
5772
5873static ssize_t data_vault_read (struct file * file , struct kobject * kobj ,
@@ -210,9 +225,110 @@ static int int3400_thermal_run_osc(acpi_handle handle,
210225 result = - EPERM ;
211226
212227 kfree (context .ret .pointer );
228+
213229 return result ;
214230}
215231
232+ static ssize_t odvp_show (struct kobject * kobj , struct kobj_attribute * attr ,
233+ char * buf )
234+ {
235+ struct odvp_attr * odvp_attr ;
236+
237+ odvp_attr = container_of (attr , struct odvp_attr , attr );
238+
239+ return sprintf (buf , "%d\n" , odvp_attr -> priv -> odvp [odvp_attr -> odvp ]);
240+ }
241+
242+ static void cleanup_odvp (struct int3400_thermal_priv * priv )
243+ {
244+ int i ;
245+
246+ if (priv -> odvp_attrs ) {
247+ for (i = 0 ; i < priv -> odvp_count ; i ++ ) {
248+ sysfs_remove_file (& priv -> pdev -> dev .kobj ,
249+ & priv -> odvp_attrs [i ].attr .attr );
250+ kfree (priv -> odvp_attrs [i ].attr .attr .name );
251+ }
252+ kfree (priv -> odvp_attrs );
253+ }
254+ kfree (priv -> odvp );
255+ priv -> odvp_count = 0 ;
256+ }
257+
258+ static int evaluate_odvp (struct int3400_thermal_priv * priv )
259+ {
260+ struct acpi_buffer odvp = { ACPI_ALLOCATE_BUFFER , NULL };
261+ union acpi_object * obj = NULL ;
262+ acpi_status status ;
263+ int i , ret ;
264+
265+ status = acpi_evaluate_object (priv -> adev -> handle , "ODVP" , NULL , & odvp );
266+ if (ACPI_FAILURE (status )) {
267+ ret = - EINVAL ;
268+ goto out_err ;
269+ }
270+
271+ obj = odvp .pointer ;
272+ if (obj -> type != ACPI_TYPE_PACKAGE ) {
273+ ret = - EINVAL ;
274+ goto out_err ;
275+ }
276+
277+ if (priv -> odvp == NULL ) {
278+ priv -> odvp_count = obj -> package .count ;
279+ priv -> odvp = kmalloc_array (priv -> odvp_count , sizeof (int ),
280+ GFP_KERNEL );
281+ if (!priv -> odvp ) {
282+ ret = - ENOMEM ;
283+ goto out_err ;
284+ }
285+ }
286+
287+ if (priv -> odvp_attrs == NULL ) {
288+ priv -> odvp_attrs = kcalloc (priv -> odvp_count ,
289+ sizeof (struct odvp_attr ),
290+ GFP_KERNEL );
291+ if (!priv -> odvp_attrs ) {
292+ ret = - ENOMEM ;
293+ goto out_err ;
294+ }
295+ for (i = 0 ; i < priv -> odvp_count ; i ++ ) {
296+ struct odvp_attr * odvp = & priv -> odvp_attrs [i ];
297+
298+ sysfs_attr_init (& odvp -> attr .attr );
299+ odvp -> priv = priv ;
300+ odvp -> odvp = i ;
301+ odvp -> attr .attr .name = kasprintf (GFP_KERNEL ,
302+ "odvp%d" , i );
303+
304+ if (!odvp -> attr .attr .name ) {
305+ ret = - ENOMEM ;
306+ goto out_err ;
307+ }
308+ odvp -> attr .attr .mode = 0444 ;
309+ odvp -> attr .show = odvp_show ;
310+ odvp -> attr .store = NULL ;
311+ ret = sysfs_create_file (& priv -> pdev -> dev .kobj ,
312+ & odvp -> attr .attr );
313+ if (ret )
314+ goto out_err ;
315+ }
316+ }
317+
318+ for (i = 0 ; i < obj -> package .count ; i ++ ) {
319+ if (obj -> package .elements [i ].type == ACPI_TYPE_INTEGER )
320+ priv -> odvp [i ] = obj -> package .elements [i ].integer .value ;
321+ }
322+
323+ kfree (obj );
324+ return 0 ;
325+
326+ out_err :
327+ cleanup_odvp (priv );
328+ kfree (obj );
329+ return ret ;
330+ }
331+
216332static void int3400_notify (acpi_handle handle ,
217333 u32 event ,
218334 void * data )
@@ -236,6 +352,9 @@ static void int3400_notify(acpi_handle handle,
236352 kobject_uevent_env (& priv -> thermal -> device .kobj , KOBJ_CHANGE ,
237353 thermal_prop );
238354 break ;
355+ case INT3400_ODVP_CHANGED :
356+ evaluate_odvp (priv );
357+ break ;
239358 default :
240359 /* Ignore unknown notification codes sent to INT3400 device */
241360 break ;
@@ -285,6 +404,9 @@ static int int3400_thermal_set_mode(struct thermal_zone_device *thermal,
285404 priv -> current_uuid_index ,
286405 enable );
287406 }
407+
408+ evaluate_odvp (priv );
409+
288410 return result ;
289411}
290412
@@ -338,6 +460,7 @@ static int int3400_thermal_probe(struct platform_device *pdev)
338460 if (!priv )
339461 return - ENOMEM ;
340462
463+ priv -> pdev = pdev ;
341464 priv -> adev = adev ;
342465
343466 result = int3400_thermal_get_uuids (priv );
@@ -358,6 +481,8 @@ static int int3400_thermal_probe(struct platform_device *pdev)
358481
359482 int3400_setup_gddv (priv );
360483
484+ evaluate_odvp (priv );
485+
361486 priv -> thermal = thermal_zone_device_register ("INT3400 Thermal" , 0 , 0 ,
362487 priv , & int3400_thermal_ops ,
363488 & int3400_thermal_params , 0 , 0 );
@@ -389,8 +514,11 @@ static int int3400_thermal_probe(struct platform_device *pdev)
389514 return 0 ;
390515
391516free_sysfs :
392- if (priv -> data_vault )
517+ cleanup_odvp (priv );
518+ if (priv -> data_vault ) {
393519 sysfs_remove_group (& pdev -> dev .kobj , & data_attribute_group );
520+ kfree (priv -> data_vault );
521+ }
394522free_uuid :
395523 sysfs_remove_group (& pdev -> dev .kobj , & uuid_attribute_group );
396524free_rel_misc :
@@ -413,6 +541,8 @@ static int int3400_thermal_remove(struct platform_device *pdev)
413541 priv -> adev -> handle , ACPI_DEVICE_NOTIFY ,
414542 int3400_notify );
415543
544+ cleanup_odvp (priv );
545+
416546 if (!priv -> rel_misc_dev_res )
417547 acpi_thermal_rel_misc_device_remove (priv -> adev -> handle );
418548
0 commit comments