ACPI: add ACPI thermal_zone sysfs interface
Subsystems (2)
Zhang Rui
reviewerPATCH 8/8 ACPI: add ACPI thermal_zone sysfs interface
From: Zhang Rui <[email protected]>
Add ACPI thermal_zone sysfs interface.
Required attributes:
Attribute Mode Description
state RO state of the current thermal zone
(ok/passive/active[x]/hot/critical)cooling_mode RW the cooling policy of the current thermal zone.
0x00 = active, 0x01 = passive, 0xff = critical.
polling_freq RW
temperature RO temperature of the current thermal zone.(celsius)critical_temp RW critical trip point where OSPM must perform a
critical shutdown
Optional attributes:
Attribute Mode Descriptionhot_temp RW critical trip point where OSPM may choose to
transition the system into S4passive_temp RW the passive cooling policy threshold valuepassive_tc1 RO thermal constant for passive coolingpassive_tc2 RO thermal constant for passive coolingpassive_tsp RO thermal sampling period for passive coolingactive0_temp RW active cooling policy threshold value
...active9_temp RW active cooling policy threshold value
Syslinks to cooling devices(dynamic, optional):passive_cooling_device0
...passive_cooling_device9
active0_cooling_device0
...active0_cooling_device9
...
...active9_cooling_device0
...active9_cooling_device9
--- drivers/acpi/thermal.c | 713 ++++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 622 insertions(+), 91 deletions(-)
drivers/acpi/thermal.c +622 -91
@@ -83,19 +83,6 @@ MODULE_PARM_DESC(tzp, "Thermal zone pollstatic int acpi_thermal_add (struct acpi_device *device);static int acpi_thermal_remove (struct acpi_device *device,int type);static int acpi_thermal_resume (struct acpi_device *device); -static int acpi_thermal_state_open_fs (struct inode *inode,struct file *file); -static int acpi_thermal_temp_open_fs (struct inode *inode,struct file *file); -static int acpi_thermal_trip_open_fs (struct inode *inode,struct file *file); -static ssize_t acpi_thermal_write_trip_points (struct file *, -const char __user *,size_t , -loff_t *); -static int acpi_thermal_cooling_open_fs (struct inode *inode,struct file *file); -static ssize_t acpi_thermal_write_cooling_mode (struct file *, -const char __user *,size_t , -loff_t *); -static int acpi_thermal_polling_open_fs (struct inode *inode,struct file *file); -static ssize_t acpi_thermal_write_polling (struct file *,const char __user *, -size_t ,loff_t *);static struct acpi_driver acpi_thermal_driver = { .name ="thermal" ,
@@ -176,44 +163,6 @@ struct acpi_thermal {struct timer_list timer; }; -static const struct file_operations acpi_thermal_state_fops = { - .open = acpi_thermal_state_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations acpi_thermal_temp_fops = { - .open = acpi_thermal_temp_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations acpi_thermal_trip_fops = { - .open = acpi_thermal_trip_open_fs, - .read = seq_read, - .write = acpi_thermal_write_trip_points, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations acpi_thermal_cooling_fops = { - .open = acpi_thermal_cooling_open_fs, - .read = seq_read, - .write = acpi_thermal_write_cooling_mode, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations acpi_thermal_polling_fops = { - .open = acpi_thermal_polling_open_fs, - .read = seq_read, - .write = acpi_thermal_write_polling, - .llseek = seq_lseek, - .release = single_release, -}; -/* -------------------------------------------------------------------------- Thermal Zone Management -------------------------------------------------------------------------- */
@@ -305,15 +254,25 @@ static int acpi_thermal_set_cooling_modereturn 0 ; } +static int acpi_thermal_cooling_device_update (struct acpi_thermal *thermal,int state, +struct acpi_handle_list *new_devices); +static int acpi_thermal_sysfs_update (struct acpi_thermal *thermal,struct acpi_thermal_state *old_state);static int acpi_thermal_get_trip_points (struct acpi_thermal *tz) {acpi_status status =AE_OK ;int i =0 ; +struct acpi_handle_list devices; +struct acpi_thermal_state state;if (!tz)return -EINVAL ; + state.hot = tz->trips.hot.flags.valid; + state.passive= tz->trips.passive.flags.valid; +for (state.active_index =0 ; state.active_index <ACPI_THERMAL_MAX_ACTIVE && + tz->trips.active[state.active_index].flags.valid; state.active_index ++); +/* Critical Shutdown (required) */ status = acpi_evaluate_integer(tz->device->handle, "_CRT", NULL,
@@ -374,7 +333,7 @@ static int acpi_thermal_get_trip_points( status =acpi_evaluate_reference (tz->device->handle,"_PSL" ,NULL , - &tz->trips.passive.devices); + &devices);if (ACPI_FAILURE (status)) tz->trips.passive.flags.valid =0 ;
@@ -386,6 +345,13 @@ static int acpi_thermal_get_trip_points( tz->trips.passive.temperature)); } +if (!tz->trips.passive.flags.valid) + devices.count =0 ; + status =acpi_thermal_cooling_device_update (tz,-1 , &devices); +if (status) +ACPI_DEBUG_PRINT ((ACPI_DB_WARN , +"Passive cooling device update failed!\n" )); +/* Active: Fans, etc. (optional) */ for (i =0 ; i <ACPI_THERMAL_MAX_ACTIVE ; i++) {
@@ -396,22 +362,35 @@ static int acpi_thermal_get_trip_points(acpi_evaluate_integer (tz->device->handle, name,NULL , &tz->trips.active[i].temperature);if (ACPI_FAILURE (status)) -break ; - - name[2 ] ='L' ; - status = -acpi_evaluate_reference (tz->device->handle, name,NULL , - &tz->trips.active[i].devices); -if (ACPI_SUCCESS (status)) { - tz->trips.active[i].flags.valid =1 ; -ACPI_DEBUG_PRINT ((ACPI_DB_INFO , -"Found active threshold [%d]:[%lu]\n" , - i, tz->trips.active[i].temperature)); - }else -ACPI_EXCEPTION ((AE_INFO , status, -"Invalid active threshold [%d]" , i)); + tz->trips.active[i].flags.valid =0 ; +else { + name[2 ] ='L' ; + status = +acpi_evaluate_reference (tz->device->handle, name,NULL , + &devices); +if (ACPI_SUCCESS (status)) { + tz->trips.active[i].flags.valid =1 ; +ACPI_DEBUG_PRINT ((ACPI_DB_INFO , +"Found active threshold [%d]:[%lu]\n" , + i, tz->trips.active[i].temperature)); + }else { + tz->trips.active[i].flags.valid =0 ; +ACPI_EXCEPTION ((AE_INFO , status, +"Invalid active threshold [%d]" , i)); + } + } +if (!tz->trips.active[i].flags.valid) + devices.count =0 ; + status =acpi_thermal_cooling_device_update (tz, i, &devices); +if (status) +ACPI_DEBUG_PRINT ((ACPI_DB_WARN , +"Active[%d] cooling device update failed!\n" , i)); } +if (acpi_thermal_sysfs_update (tz, &state)) +ACPI_DEBUG_PRINT ((ACPI_DB_WARN , +"Trip point sysfs update failed!\n" )); +return 0 ; }
@@ -771,9 +750,495 @@ static void acpi_thermal_check(void *dat }/* -------------------------------------------------------------------------- -FS Interface (/proc) +FS Interface (/sys) -------------------------------------------------------------------------- */ +static ssize_t +acpi_thermal_state_show (struct acpi_device *dev,char *buf) +{ +struct acpi_thermal *thermal =acpi_driver_data (dev); +int result =0 ; + +if (!thermal->state.critical && !thermal->state.hot && !thermal->state.passive + && !thermal->state.active) + result =sprintf (buf,"ok\n" ); +else { +if (thermal->state.critical) + result +=sprintf (buf,"critical " ); +if (thermal->state.hot) + result +=sprintf (buf,"hot " ); +if (thermal->state.passive) + result +=sprintf (buf,"passive " ); +if (thermal->state.active) + result +=sprintf (buf,"active[%d]" , thermal->state.active_index); +sprintf (buf,"\n" ); + } +return result; +} +static ACPI_DEVICE_ATTR(state, 0444, acpi_thermal_state_show, NULL); + +static ssize_t +acpi_thermal_temperature_show (struct acpi_device *dev,char *buf) +{ +struct acpi_thermal *thermal =acpi_driver_data (dev); +int result =0 ; + + result =acpi_thermal_get_temperature (thermal); +if (!result) +return sprintf (buf,"%ld\n" ,KELVIN_TO_CELSIUS (thermal->temperature)); +else +return result; +} +static ACPI_DEVICE_ATTR(temperature, 0444, acpi_thermal_temperature_show, NULL); + +static ssize_t +acpi_thermal_cooling_mode_show (struct acpi_device *dev,char *buf) +{ +struct acpi_thermal *thermal =acpi_driver_data (dev); + +if (!thermal) +return -EINVAL ; + +if (thermal->flags.cooling_mode) +return sprintf (buf,"0x%02x\n" , thermal->cooling_mode); + +return 0 ; +} + +static ssize_t +acpi_thermal_cooling_mode_store (struct acpi_device *dev,const char *buf,size_t count) +{ +struct acpi_thermal *thermal =acpi_driver_data (dev); +u32 mode; +char *end; +int ret =0 ; + + mode =simple_strtoul (buf, &end,0 ); +if (*end =='\0' ) +return -EINVAL ; + +if (thermal->flags.cooling_mode){ + ret =acpi_thermal_set_cooling_mode (thermal, mode); +if (ret) +return ret; +acpi_thermal_check (thermal); +return count; + } +else +return -ENODEV ; +} +static ACPI_DEVICE_ATTR(cooling_mode, 0644, acpi_thermal_cooling_mode_show, acpi_thermal_cooling_mode_store); + +static ssize_t +acpi_thermal_polling_freq_show (struct acpi_device *dev,char *buf) +{ +struct acpi_thermal *thermal =acpi_driver_data (dev); + +if (thermal->polling_frequency) +return sprintf (buf,"%lu\n" , (thermal->polling_frequency /10 )); + +return 0 ; +} + +static ssize_t +acpi_thermal_polling_freq_store (struct acpi_device *dev,const char *buf,size_t count) +{ +struct acpi_thermal *thermal =acpi_driver_data (dev); +unsigned long freq; +char * end; +int ret =0 ; + + freq =simple_strtoul (buf, &end,0 ); +if (*end =='\0' ) +return -EINVAL ; + + ret =acpi_thermal_set_polling (thermal, freq); +if (ret) +return ret; + +acpi_thermal_check (thermal); +return count; +} +static ACPI_DEVICE_ATTR(polling_freq, 0644, acpi_thermal_polling_freq_show, acpi_thermal_polling_freq_store); + +static ssize_t +acpi_thermal_passive_tc1_show (struct acpi_device *dev,char *buf) +{ +struct acpi_thermal *thermal =acpi_driver_data (dev); + +if (!thermal) +return -EINVAL ; + +if (thermal->trips.passive.flags.valid) +return sprintf (buf,"%ld\n" , thermal->trips.passive.tc1); +else +return -ENODEV ; +} +static ACPI_DEVICE_ATTR(passive_tc1, 0444, acpi_thermal_passive_tc1_show, NULL); + +static ssize_t +acpi_thermal_passive_tc2_show (struct acpi_device *dev,char *buf) +{ +struct acpi_thermal *thermal =acpi_driver_data (dev); + +if (!thermal) +return -EINVAL ; + +if (thermal->trips.passive.flags.valid) +return sprintf (buf,"%ld\n" , thermal->trips.passive.tc2); +else +return -ENODEV ; +} +static ACPI_DEVICE_ATTR(passive_tc2, 0444, acpi_thermal_passive_tc2_show, NULL); + +static ssize_t +acpi_thermal_passive_tsp_show (struct acpi_device *dev,char *buf) +{ +struct acpi_thermal *thermal =acpi_driver_data (dev); + +if (!thermal) +return -EINVAL ; + +if (thermal->trips.passive.flags.valid) +return sprintf (buf,"%ld\n" , thermal->trips.passive.tsp); +else +return -ENODEV ; +} +static ACPI_DEVICE_ATTR(passive_tsp, 0444, acpi_thermal_passive_tsp_show, NULL); + +typedef ssize_t (*trip_point_show )(struct acpi_thermal *thermal, +int type,int state,char *buf); +typedef ssize_t (*trip_point_store )(struct acpi_thermal *thermal,int type, +int state,const char *buf,size_t count); + +struct acpi_thermal_trip_point_attr { +struct device_attribute attr; +int type; +int state; +trip_point_show show; +trip_point_store store; +}; + +#define ACPI_THERMAL_TRIP_POINT_CRITICAL 0 +#define ACPI_THERMAL_TRIP_POINT_HOT 1 +#define ACPI_THERMAL_TRIP_POINT_PASSIVE 2 +#define ACPI_THERMAL_TRIP_POINT_ACTIVE 3 + +static ssize_t +acpi_thermal_trip_point_show (struct acpi_thermal *thermal, +int type,int state,char *buf) +{ +ssize_t result = -ENODEV ; + +switch (type) { +case ACPI_THERMAL_TRIP_POINT_CRITICAL : +if (thermal->trips.critical.flags.valid) + result =sprintf (buf,"%ld\n" ,KELVIN_TO_CELSIUS (thermal->trips.critical.temperature)); +break ; +case ACPI_THERMAL_TRIP_POINT_HOT : +if (thermal->trips.hot.flags.valid) + result =sprintf (buf,"%ld\n" ,KELVIN_TO_CELSIUS (thermal->trips.hot.temperature)); +break ; +case ACPI_THERMAL_TRIP_POINT_PASSIVE : +if (thermal->trips.passive.flags.valid) + result =sprintf (buf,"%ld\n" ,KELVIN_TO_CELSIUS (thermal->trips.passive.temperature)); +break ; +case ACPI_THERMAL_TRIP_POINT_ACTIVE : +if (thermal->trips.active[state].flags.valid) { +if (state >=0 && state <ACPI_THERMAL_MAX_ACTIVE ) + result =sprintf (buf,"%ld\n" ,KELVIN_TO_CELSIUS (thermal->trips.active[state].temperature)); +else + result = -EINVAL ; + } +break ; +default : + result = -EINVAL ; + } + +return result; +} + +static ssize_t +acpi_thermal_trip_point_store (struct acpi_thermal *thermal,int type, +int state,const char *buf,size_t count) +{ +char *end; +u32 val; +ssize_t result = -ENODEV ; + + val =simple_strtol (buf, &end,0 ); +if (*end =='\0' ) +return -EINVAL ; + +switch (type) { +case ACPI_THERMAL_TRIP_POINT_CRITICAL : +if (thermal->trips.critical.flags.valid){ + thermal->trips.critical.temperature =CELSIUS_TO_KELVIN (val); + result = count; + } +break ; +case ACPI_THERMAL_TRIP_POINT_HOT : +if (thermal->trips.hot.flags.valid){ + thermal->trips.hot.temperature =CELSIUS_TO_KELVIN (val); + result = count; + } +break ; +case ACPI_THERMAL_TRIP_POINT_PASSIVE : +if (thermal->trips.passive.flags.valid){ + thermal->trips.passive.temperature =CELSIUS_TO_KELVIN (val); + result = count; + } +break ; +case ACPI_THERMAL_TRIP_POINT_ACTIVE : +if (thermal->trips.active[state].flags.valid){ +if (state >=0 && state <ACPI_THERMAL_MAX_ACTIVE ) { + thermal->trips.active[state].temperature =CELSIUS_TO_KELVIN (val); + result = count; + } +else + result = -EINVAL ; + } +break ; +default : + result = -EINVAL ; + } +return result; +} + +static ssize_t _trip_point_show (struct device *dev,struct device_attribute *attr, +char *buf) +{ + struct acpi_thermal_trip_point_attr *thermal_attr = container_of(attr, struct acpi_thermal_trip_point_attr, attr); +struct acpi_device *acpi_dev =to_acpi_device (dev); +struct acpi_thermal *thermal =acpi_driver_data (acpi_dev); + +if (!thermal_attr->store) +return -EINVAL ; + +return thermal_attr->show (thermal, thermal_attr->type, thermal_attr->state, buf); +} +static ssize_t _trip_point_store (struct device *dev,struct device_attribute *attr, +const char *buf,size_t count) +{ + struct acpi_thermal_trip_point_attr *thermal_attr = container_of(attr, struct acpi_thermal_trip_point_attr, attr); +struct acpi_device *acpi_dev =to_acpi_device (dev); +struct acpi_thermal *thermal =acpi_driver_data (acpi_dev); + +if (!thermal_attr->store) +return -EINVAL ; + +return thermal_attr->store (thermal, thermal_attr->type, thermal_attr->state, buf, count); +} + +#define ACPI_THERMAL_TRIP_POINT (_name, _type, _state) \ +struct acpi_thermal_trip_point_attr _name##_attr = \ +{ \ + .attr = __ATTR(_name, 0644, _trip_point_show, _trip_point_store), \ + .type = _type, \ + .state = _state, \ + .show = acpi_thermal_trip_point_show, \ + .store = acpi_thermal_trip_point_store, \ +} + + +static ACPI_THERMAL_TRIP_POINT(critical_temp, ACPI_THERMAL_TRIP_POINT_CRITICAL, 0); +static ACPI_THERMAL_TRIP_POINT(hot_temp, ACPI_THERMAL_TRIP_POINT_HOT, 0); +static ACPI_THERMAL_TRIP_POINT(passive_temp, ACPI_THERMAL_TRIP_POINT_PASSIVE, 0); +static ACPI_THERMAL_TRIP_POINT(active0_temp, ACPI_THERMAL_TRIP_POINT_ACTIVE, 0); +static ACPI_THERMAL_TRIP_POINT(active1_temp, ACPI_THERMAL_TRIP_POINT_ACTIVE, 1); +static ACPI_THERMAL_TRIP_POINT(active2_temp, ACPI_THERMAL_TRIP_POINT_ACTIVE, 2); +static ACPI_THERMAL_TRIP_POINT(active3_temp, ACPI_THERMAL_TRIP_POINT_ACTIVE, 3); +static ACPI_THERMAL_TRIP_POINT(active4_temp, ACPI_THERMAL_TRIP_POINT_ACTIVE, 4); +static ACPI_THERMAL_TRIP_POINT(active5_temp, ACPI_THERMAL_TRIP_POINT_ACTIVE, 5); +static ACPI_THERMAL_TRIP_POINT(active6_temp, ACPI_THERMAL_TRIP_POINT_ACTIVE, 6); +static ACPI_THERMAL_TRIP_POINT(active7_temp, ACPI_THERMAL_TRIP_POINT_ACTIVE, 7); +static ACPI_THERMAL_TRIP_POINT(active8_temp, ACPI_THERMAL_TRIP_POINT_ACTIVE, 8); +static ACPI_THERMAL_TRIP_POINT(active9_temp, ACPI_THERMAL_TRIP_POINT_ACTIVE, 9); + +static struct device_attribute *thermal_default_attr[] = +{ +GET_DEV_ATTR (state), +GET_DEV_ATTR (temperature), +GET_DEV_ATTR (cooling_mode), +GET_DEV_ATTR (polling_freq), +GET_DEV_ATTR (critical_temp), +NULL , +}; + +static struct device_attribute *thermal_optional_attr[] = +{ +GET_DEV_ATTR (hot_temp), +GET_DEV_ATTR (passive_temp), +GET_DEV_ATTR (passive_tc1), +GET_DEV_ATTR (passive_tc2), +GET_DEV_ATTR (passive_tsp), +GET_DEV_ATTR (active0_temp), +GET_DEV_ATTR (active1_temp), +GET_DEV_ATTR (active2_temp), +GET_DEV_ATTR (active3_temp), +GET_DEV_ATTR (active4_temp), +GET_DEV_ATTR (active5_temp), +GET_DEV_ATTR (active6_temp), +GET_DEV_ATTR (active7_temp), +GET_DEV_ATTR (active8_temp), +GET_DEV_ATTR (active9_temp), +}; + +static int acpi_thermal_add_sysfs (struct acpi_device * device) +{ +int result =0 ; + + result =acpi_device_add_sysfs (device, thermal_default_attr); + +/* +* optional trip point attributes (hot/passive/active) +* and syslinks to cooling devices both are dynamic +*/ + +return result; +} + +static void acpi_thermal_remove_sysfs (struct acpi_device * device) +{ +struct acpi_thermal *thermal =acpi_driver_data (device); +struct acpi_handle_list new_devices; +int i =0 ; + +acpi_device_remove_sysfs (device, thermal_default_attr); + +/* +* remove syslinks to cooling devices +*/ + new_devices.count =0 ; + +if (thermal->trips.passive.flags.valid) +acpi_thermal_cooling_device_update (thermal,-1 , &new_devices); + + +for (i =0 ; i <ACPI_THERMAL_MAX_ACTIVE ; i++) +if (thermal->trips.active[i].flags.valid) +acpi_thermal_cooling_device_update (thermal, i, &new_devices); + +/* +* remove optional trip point attributes +*/ +if (thermal->trips.hot.flags.valid ) +device_remove_file (&device->dev, thermal_optional_attr[0 ]); + +if (thermal->trips.passive.flags.valid) +for (i =0 ; i <4 ; i++) +device_remove_file (&device->dev, thermal_optional_attr[1 +i]); + + +for (i =0 ; i <ACPI_THERMAL_MAX_ACTIVE ; i++) +if ((thermal->trips.active[i].flags.valid)) +device_remove_file (&device->dev, thermal_optional_attr[5 +i]); + +return ; +} + +static int acpi_thermal_cooling_device_update (struct acpi_thermal * thermal,int state, +struct acpi_handle_list *new_devices) +{ +struct acpi_device *device = thermal->device; +struct acpi_handle_list *old_devices; +struct acpi_device *cooling_device; +char buf[24 ]; +int i =0 ; +int result =0 ; + +if (!device || !new_devices) +return -EINVAL ; + +if (state ==-1 ) { +sprintf (buf,"passive_cooling_device0" ); + old_devices = &thermal->trips.passive.devices; + } +else +if (state >=0 && state <ACPI_THERMAL_MAX_ACTIVE ) { +sprintf (buf,"active%d_cooling_device0" , state); + old_devices = &thermal->trips.active[state].devices; + } +else +return -EINVAL ; + +for (i =0 ; i < old_devices->count || i < new_devices->count; i++) { +if (i >= old_devices->count) + old_devices->handles[i] =NULL ; +if (i >= new_devices->count) + new_devices->handles[i] =NULL ; +if (new_devices->handles[i] != old_devices->handles[i]) { + buf[22 ] ='0' +i; + +if (i < old_devices->count && old_devices->handles[i]) +sysfs_remove_link (&device->dev.kobj, buf); + +if (i < new_devices->count && new_devices->handles[i]) { +acpi_bus_get_device (new_devices->handles[i], &cooling_device); + result =sysfs_create_link (&device->dev.kobj, &cooling_device->dev.kobj, buf); +if (result) +return result; + } + old_devices->handles[i] = new_devices->handles[i]; + } + } + old_devices->count = new_devices->count; + +return result; +} + +static int acpi_thermal_trip_point_update (struct device *dev,struct device_attribute *attr,int type) +{ +int result =0 ; + +if (type) + result =device_create_file (dev, attr); +else +device_remove_file (dev, attr); + +return result; +} + +static int acpi_thermal_sysfs_update (struct acpi_thermal *thermal,struct acpi_thermal_state *old_state) +{ +struct acpi_device *device = thermal->device; +int result =0 ; +int i =0 ; + +if (thermal->trips.hot.flags.valid != old_state->hot) { + result =acpi_thermal_trip_point_update (&device->dev, thermal_optional_attr[0 ], + thermal->trips.hot.flags.valid); +if (result) + goto done; + } + +if (thermal->trips.passive.flags.valid != old_state->passive) +for (i =0 ; i <4 ; i++) { + result =acpi_thermal_trip_point_update (&device->dev, thermal_optional_attr[1 +i], + thermal->trips.passive.flags.valid); +if (result) + goto done; + } + +for (i =0 ; i <ACPI_THERMAL_MAX_ACTIVE ; i++) + { +if ((thermal->trips.active[i].flags.valid && i >= old_state->active_index) || + (!thermal->trips.active[i].flags.valid && i < old_state->active_index)) { + result =acpi_thermal_trip_point_update (&device->dev, thermal_optional_attr[5 +i], + thermal->trips.active[i].flags.valid); +if (result) + goto done; + } + } + + done: +return result; +} + +/* -------------------------------------------------------------------------- +FS Interface (/proc) +-------------------------------------------------------------------------- */ +#ifdef CONFIG_ACPI_PROCFS static struct proc_dir_entry *acpi_thermal_dir;static int acpi_thermal_state_seq_show (struct seq_file *seq,void *offset)
@@ -838,6 +1303,7 @@ static int acpi_thermal_temp_open_fs(strstatic int acpi_thermal_trip_seq_show (struct seq_file *seq,void *offset) {struct acpi_thermal *tz = seq->private; +struct acpi_device *device;int i =0 ;int j =0 ;
@@ -860,9 +1326,8 @@ static int acpi_thermal_trip_seq_show(st tz->trips.passive.tc1, tz->trips.passive.tc2, tz->trips.passive.tsp);for (j =0 ; j < tz->trips.passive.devices.count; j++) { - -seq_printf (seq,"0x%p " , - tz->trips.passive.devices.handles[j]); +acpi_bus_get_device (tz->trips.passive.devices.handles[j], &device); +seq_printf (seq,"%4.4s " ,acpi_device_bid (device)); }seq_puts (seq,"\n" ); }
@@ -873,9 +1338,10 @@ static int acpi_thermal_trip_seq_show(stseq_printf (seq,"active[%d]: %ld C: devices=" , i,KELVIN_TO_CELSIUS (tz->trips.active[i].temperature)); -for (j =0 ; j < tz->trips.active[i].devices.count; j++) -seq_printf (seq,"0x%p " , - tz->trips.active[i].devices.handles[j]); +for (j =0 ; j < tz->trips.active[i].devices.count; j++) { +acpi_bus_get_device (tz->trips.active[i].devices.handles[j], &device); +seq_printf (seq,"%4.4s " ,acpi_device_bid (device)); + }seq_puts (seq,"\n" ); }
@@ -1067,7 +1533,45 @@ acpi_thermal_write_polling(struct file *return count; } -static int acpi_thermal_add_fs (struct acpi_device *device) +static const struct file_operations acpi_thermal_state_fops = { + .open = acpi_thermal_state_open_fs, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations acpi_thermal_temp_fops = { + .open = acpi_thermal_temp_open_fs, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations acpi_thermal_trip_fops = { + .open = acpi_thermal_trip_open_fs, + .read = seq_read, + .write = acpi_thermal_write_trip_points, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations acpi_thermal_cooling_fops = { + .open = acpi_thermal_cooling_open_fs, + .read = seq_read, + .write = acpi_thermal_write_cooling_mode, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations acpi_thermal_polling_fops = { + .open = acpi_thermal_polling_open_fs, + .read = seq_read, + .write = acpi_thermal_write_polling, + .llseek = seq_lseek, + .release = single_release, +}; + +static int acpi_thermal_add_procfs (struct acpi_device *device) {struct proc_dir_entry *entry =NULL ;
@@ -1141,7 +1645,7 @@ static int acpi_thermal_add_fs(struct acreturn 0 ; } -static int acpi_thermal_remove_fs (struct acpi_device *device) +static int acpi_thermal_remove_procfs (struct acpi_device *device) {if (acpi_device_dir (device)) {
@@ -1162,6 +1666,26 @@ static int acpi_thermal_remove_fs(struct return 0; } +static int acpi_thermal_procfs_init (void ) +{ + acpi_thermal_dir =proc_mkdir (ACPI_THERMAL_CLASS , acpi_root_dir); +if (!acpi_thermal_dir) +return -ENODEV ; + acpi_thermal_dir->owner =THIS_MODULE ; + +return 0 ; +} + +static int acpi_thermal_procfs_exit (void ) +{ +remove_proc_entry (ACPI_THERMAL_CLASS , acpi_root_dir); + +return 0 ; +} +#else +declare_acpi_device_procfs (thermal); +#endif +/* -------------------------------------------------------------------------- Driver Interface -------------------------------------------------------------------------- */
@@ -1283,10 +1807,14 @@ static int acpi_thermal_add(struct acpi_if (result) goto end; - result =acpi_thermal_add_fs (device); + result =acpi_thermal_add_sysfs (device);if (result) goto end; + result =acpi_thermal_add_procfs (device); +if (result) + goto procfs_error; +init_timer (&tz->timer);acpi_thermal_check (tz);
@@ -1296,19 +1824,22 @@ static int acpi_thermal_add(struct acpi_ acpi_thermal_notify, tz);if (ACPI_FAILURE (status)) { result = -ENODEV ; - goto end; + goto notify_error; } printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n",acpi_device_name (device),acpi_device_bid (device), KELVIN_TO_CELSIUS(tz->temperature)); - end: -if (result) { -acpi_thermal_remove_fs (device); -kfree (tz); - } + goto end; + notify_error: +acpi_thermal_remove_procfs (device); + procfs_error: +acpi_thermal_remove_sysfs (device); + end: +if (result) +kfree (tz);return result; }
@@ -1347,7 +1878,9 @@ static int acpi_thermal_remove(struct acacpi_thermal_active (tz); } -acpi_thermal_remove_fs (device); +acpi_thermal_remove_procfs (device); + +acpi_thermal_remove_sysfs (device);kfree (tz);return 0 ;
@@ -1390,15 +1923,14 @@ static int __init acpi_thermal_init(void {int result =0 ; + result =acpi_thermal_procfs_init (); +if (result) +return result; - acpi_thermal_dir =proc_mkdir (ACPI_THERMAL_CLASS , acpi_root_dir); -if (!acpi_thermal_dir) -return -ENODEV ; - acpi_thermal_dir->owner =THIS_MODULE ; - + acpi_thermal_driver.owner =THIS_MODULE ; result =acpi_bus_register_driver (&acpi_thermal_driver);if (result <0 ) { -remove_proc_entry (ACPI_THERMAL_CLASS , acpi_root_dir); +acpi_thermal_procfs_exit ();return -ENODEV ; }
@@ -1407,10 +1939,9 @@ static int __init acpi_thermal_init(void static void __exit acpi_thermal_exit(void) { -acpi_bus_unregister_driver (&acpi_thermal_driver); -remove_proc_entry (ACPI_THERMAL_CLASS , acpi_root_dir); +acpi_thermal_procfs_exit ();return ; }
Len Brown
reviewerQuoted 32 lines · Zhang Rui
From: Zhang Rui <[email protected]>
Add ACPI
thermal_zonesysfs interface.Required attributes:
Attribute Mode Description
state RO state of the current thermal zone
(ok/passive/active[x]/hot/critical)cooling_modeRW the cooling policy of the current thermal zone.0x00 = active, 0x01 = passive, 0xff = critical.
polling_freqRW
temperature RO temperature of the current thermal zone.(celsius)critical_tempRW critical trip point where OSPM must perform a
critical shutdownOptional attributes:
Attribute Mode Descriptionhot_tempRW critical trip point where OSPM may choose to
transition the system into S4passive_tempRW the passive cooling policy threshold valuepassive_tc1RO thermal constant for passive coolingpassive_tc2RO thermal constant for passive coolingpassive_tspRO thermal sampling period for passive coolingactive0_tempRW active cooling policy threshold value
...active9_tempRW active cooling policy threshold valueSyslinks to cooling
devices(dynamic, optional):passive_cooling_device0
...passive_cooling_device9
Quoted 9 lines
active0_cooling_device0
...active0_cooling_device9
...
...active9_cooling_device0
...active9_cooling_device9
I think this is an improvement over the procfs thermal_zone/*/trip_points file, which confuses a lot of people with its format.
-Len
Quoted 877 lines
Signed-off-by Zhang Rui <[email protected]>--- drivers/acpi/thermal.c | 713 ++++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 622 insertions(+), 91 deletions(-)Index:
linux-2.6.21-rc4-mm1/drivers/acpi/thermal.c
===================================================================drivers/acpi/thermal.c +622
-91@@ -83,19 +83,6 @@ MODULE_PARM_DESC(tzp, "Thermal zone pollstatic int acpi_thermal_add (struct acpi_device *device);static int acpi_thermal_remove (struct acpi_device *device,int type);static int acpi_thermal_resume (struct acpi_device *device); -static int acpi_thermal_state_open_fs (struct inode *inode,struct file *file); -static int acpi_thermal_temp_open_fs (struct inode *inode,struct file *file); -static int acpi_thermal_trip_open_fs (struct inode *inode,struct file *file); -static ssize_t acpi_thermal_write_trip_points (struct file *, -const char __user *,size_t , -loff_t *); -static int acpi_thermal_cooling_open_fs (struct inode *inode,struct file *file); -static ssize_t acpi_thermal_write_cooling_mode (struct file *, -const char __user *,size_t , -loff_t *); -static int acpi_thermal_polling_open_fs (struct inode *inode,struct file *file); -static ssize_t acpi_thermal_write_polling (struct file *,const char __user *, -size_t ,loff_t *);static struct acpi_driver acpi_thermal_driver = { .name ="thermal" ,@@ -176,44 +163,6 @@ struct acpi_thermal {struct timer_list timer; }; -static const struct file_operations acpi_thermal_state_fops = { - .open = acpi_thermal_state_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations acpi_thermal_temp_fops = { - .open = acpi_thermal_temp_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations acpi_thermal_trip_fops = { - .open = acpi_thermal_trip_open_fs, - .read = seq_read, - .write = acpi_thermal_write_trip_points, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations acpi_thermal_cooling_fops = { - .open = acpi_thermal_cooling_open_fs, - .read = seq_read, - .write = acpi_thermal_write_cooling_mode, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations acpi_thermal_polling_fops = { - .open = acpi_thermal_polling_open_fs, - .read = seq_read, - .write = acpi_thermal_write_polling, - .llseek = seq_lseek, - .release = single_release, -}; -/* -------------------------------------------------------------------------- Thermal Zone Management -------------------------------------------------------------------------- */ @@ -305,15 +254,25 @@ static int acpi_thermal_set_cooling_modereturn 0 ; } +static int acpi_thermal_cooling_device_update (struct acpi_thermal *thermal,int state, +struct acpi_handle_list *new_devices); +static int acpi_thermal_sysfs_update (struct acpi_thermal *thermal,struct acpi_thermal_state *old_state);static int acpi_thermal_get_trip_points (struct acpi_thermal *tz) {acpi_status status =AE_OK ;int i =0 ; +struct acpi_handle_list devices; +struct acpi_thermal_state state;if (!tz)return -EINVAL ; + state.hot = tz->trips.hot.flags.valid; + state.passive= tz->trips.passive.flags.valid; +for (state.active_index =0 ; state.active_index <ACPI_THERMAL_MAX_ACTIVE && + tz->trips.active[state.active_index].flags.valid; state.active_index ++); +/* Critical Shutdown (required) */ status = acpi_evaluate_integer(tz->device->handle, "_CRT", NULL,@@ -374,7 +333,7 @@ static int acpi_thermal_get_trip_points( status =acpi_evaluate_reference (tz->device->handle,"_PSL" ,NULL , - &tz->trips.passive.devices); + &devices);if (ACPI_FAILURE (status)) tz->trips.passive.flags.valid =0 ;@@ -386,6 +345,13 @@ static int acpi_thermal_get_trip_points( tz->trips.passive.temperature)); } +if (!tz->trips.passive.flags.valid) + devices.count =0 ; + status =acpi_thermal_cooling_device_update (tz,-1 , &devices); +if (status) +ACPI_DEBUG_PRINT ((ACPI_DB_WARN , +"Passive cooling device update failed!\n" )); +/* Active: Fans, etc. (optional) */ for (i =0 ; i <ACPI_THERMAL_MAX_ACTIVE ; i++) {@@ -396,22 +362,35 @@ static int acpi_thermal_get_trip_points(acpi_evaluate_integer (tz->device->handle, name,NULL , &tz->trips.active[i].temperature);if (ACPI_FAILURE (status)) -break ; - - name[2 ] ='L' ; - status = -acpi_evaluate_reference (tz->device->handle, name,NULL , - &tz->trips.active[i].devices); -if (ACPI_SUCCESS (status)) { - tz->trips.active[i].flags.valid =1 ; -ACPI_DEBUG_PRINT ((ACPI_DB_INFO , -"Found active threshold [%d]:[%lu]\n" , - i, tz->trips.active[i].temperature)); - }else -ACPI_EXCEPTION ((AE_INFO , status, -"Invalid active threshold [%d]" , i)); + tz->trips.active[i].flags.valid =0 ; +else { + name[2 ] ='L' ; + status = +acpi_evaluate_reference (tz->device->handle, name,NULL , + &devices); +if (ACPI_SUCCESS (status)) { + tz->trips.active[i].flags.valid =1 ; +ACPI_DEBUG_PRINT ((ACPI_DB_INFO , +"Found active threshold [%d]:[%lu]\n" , + i, tz->trips.active[i].temperature)); + }else { + tz->trips.active[i].flags.valid =0 ; +ACPI_EXCEPTION ((AE_INFO , status, +"Invalid active threshold [%d]" , i)); + } + } +if (!tz->trips.active[i].flags.valid) + devices.count =0 ; + status =acpi_thermal_cooling_device_update (tz, i, &devices); +if (status) +ACPI_DEBUG_PRINT ((ACPI_DB_WARN , +"Active[%d] cooling device update failed!\n" , i)); } +if (acpi_thermal_sysfs_update (tz, &state)) +ACPI_DEBUG_PRINT ((ACPI_DB_WARN , +"Trip point sysfs update failed!\n" )); +return 0 ; }@@ -771,9 +750,495 @@ static void acpi_thermal_check(void *dat }/* -------------------------------------------------------------------------- -FS Interface (/proc) +FS Interface (/sys) -------------------------------------------------------------------------- */ +static ssize_t +acpi_thermal_state_show (struct acpi_device *dev,char *buf) +{ +struct acpi_thermal *thermal =acpi_driver_data (dev); +int result =0 ; + +if (!thermal->state.critical && !thermal->state.hot && !thermal->state.passive + && !thermal->state.active) + result =sprintf (buf,"ok\n" ); +else { +if (thermal->state.critical) + result +=sprintf (buf,"critical " ); +if (thermal->state.hot) + result +=sprintf (buf,"hot " ); +if (thermal->state.passive) + result +=sprintf (buf,"passive " ); +if (thermal->state.active) + result +=sprintf (buf,"active[%d]" , thermal->state.active_index); +sprintf (buf,"\n" ); + } +return result; +} +static ACPI_DEVICE_ATTR(state, 0444, acpi_thermal_state_show, NULL); + +static ssize_t +acpi_thermal_temperature_show (struct acpi_device *dev,char *buf) +{ +struct acpi_thermal *thermal =acpi_driver_data (dev); +int result =0 ; + + result =acpi_thermal_get_temperature (thermal); +if (!result) +return sprintf (buf,"%ld\n" ,KELVIN_TO_CELSIUS (thermal->temperature)); +else +return result; +} +static ACPI_DEVICE_ATTR(temperature, 0444, acpi_thermal_temperature_show, NULL); + +static ssize_t +acpi_thermal_cooling_mode_show (struct acpi_device *dev,char *buf) +{ +struct acpi_thermal *thermal =acpi_driver_data (dev); + +if (!thermal) +return -EINVAL ; + +if (thermal->flags.cooling_mode) +return sprintf (buf,"0x%02x\n" , thermal->cooling_mode); + +return 0 ; +} + +static ssize_t +acpi_thermal_cooling_mode_store (struct acpi_device *dev,const char *buf,size_t count) +{ +struct acpi_thermal *thermal =acpi_driver_data (dev); +u32 mode; +char *end; +int ret =0 ; + + mode =simple_strtoul (buf, &end,0 ); +if (*end =='\0' ) +return -EINVAL ; + +if (thermal->flags.cooling_mode){ + ret =acpi_thermal_set_cooling_mode (thermal, mode); +if (ret) +return ret; +acpi_thermal_check (thermal); +return count; + } +else +return -ENODEV ; +} +static ACPI_DEVICE_ATTR(cooling_mode, 0644, acpi_thermal_cooling_mode_show, acpi_thermal_cooling_mode_store); + +static ssize_t +acpi_thermal_polling_freq_show (struct acpi_device *dev,char *buf) +{ +struct acpi_thermal *thermal =acpi_driver_data (dev); + +if (thermal->polling_frequency) +return sprintf (buf,"%lu\n" , (thermal->polling_frequency /10 )); + +return 0 ; +} + +static ssize_t +acpi_thermal_polling_freq_store (struct acpi_device *dev,const char *buf,size_t count) +{ +struct acpi_thermal *thermal =acpi_driver_data (dev); +unsigned long freq; +char * end; +int ret =0 ; + + freq =simple_strtoul (buf, &end,0 ); +if (*end =='\0' ) +return -EINVAL ; + + ret =acpi_thermal_set_polling (thermal, freq); +if (ret) +return ret; + +acpi_thermal_check (thermal); +return count; +} +static ACPI_DEVICE_ATTR(polling_freq, 0644, acpi_thermal_polling_freq_show, acpi_thermal_polling_freq_store); + +static ssize_t +acpi_thermal_passive_tc1_show (struct acpi_device *dev,char *buf) +{ +struct acpi_thermal *thermal =acpi_driver_data (dev); + +if (!thermal) +return -EINVAL ; + +if (thermal->trips.passive.flags.valid) +return sprintf (buf,"%ld\n" , thermal->trips.passive.tc1); +else +return -ENODEV ; +} +static ACPI_DEVICE_ATTR(passive_tc1, 0444, acpi_thermal_passive_tc1_show, NULL); + +static ssize_t +acpi_thermal_passive_tc2_show (struct acpi_device *dev,char *buf) +{ +struct acpi_thermal *thermal =acpi_driver_data (dev); + +if (!thermal) +return -EINVAL ; + +if (thermal->trips.passive.flags.valid) +return sprintf (buf,"%ld\n" , thermal->trips.passive.tc2); +else +return -ENODEV ; +} +static ACPI_DEVICE_ATTR(passive_tc2, 0444, acpi_thermal_passive_tc2_show, NULL); + +static ssize_t +acpi_thermal_passive_tsp_show (struct acpi_device *dev,char *buf) +{ +struct acpi_thermal *thermal =acpi_driver_data (dev); + +if (!thermal) +return -EINVAL ; + +if (thermal->trips.passive.flags.valid) +return sprintf (buf,"%ld\n" , thermal->trips.passive.tsp); +else +return -ENODEV ; +} +static ACPI_DEVICE_ATTR(passive_tsp, 0444, acpi_thermal_passive_tsp_show, NULL); + +typedef ssize_t (*trip_point_show )(struct acpi_thermal *thermal, +int type,int state,char *buf); +typedef ssize_t (*trip_point_store )(struct acpi_thermal *thermal,int type, +int state,const char *buf,size_t count); + +struct acpi_thermal_trip_point_attr { +struct device_attribute attr; +int type; +int state; +trip_point_show show; +trip_point_store store; +}; + +#define ACPI_THERMAL_TRIP_POINT_CRITICAL 0 +#define ACPI_THERMAL_TRIP_POINT_HOT 1 +#define ACPI_THERMAL_TRIP_POINT_PASSIVE 2 +#define ACPI_THERMAL_TRIP_POINT_ACTIVE 3 + +static ssize_t +acpi_thermal_trip_point_show (struct acpi_thermal *thermal, +int type,int state,char *buf) +{ +ssize_t result = -ENODEV ; + +switch (type) { +case ACPI_THERMAL_TRIP_POINT_CRITICAL : +if (thermal->trips.critical.flags.valid) + result =sprintf (buf,"%ld\n" ,KELVIN_TO_CELSIUS (thermal->trips.critical.temperature)); +break ; +case ACPI_THERMAL_TRIP_POINT_HOT : +if (thermal->trips.hot.flags.valid) + result =sprintf (buf,"%ld\n" ,KELVIN_TO_CELSIUS (thermal->trips.hot.temperature)); +break ; +case ACPI_THERMAL_TRIP_POINT_PASSIVE : +if (thermal->trips.passive.flags.valid) + result =sprintf (buf,"%ld\n" ,KELVIN_TO_CELSIUS (thermal->trips.passive.temperature)); +break ; +case ACPI_THERMAL_TRIP_POINT_ACTIVE : +if (thermal->trips.active[state].flags.valid) { +if (state >=0 && state <ACPI_THERMAL_MAX_ACTIVE ) + result =sprintf (buf,"%ld\n" ,KELVIN_TO_CELSIUS (thermal->trips.active[state].temperature)); +else + result = -EINVAL ; + } +break ; +default : + result = -EINVAL ; + } + +return result; +} + +static ssize_t +acpi_thermal_trip_point_store (struct acpi_thermal *thermal,int type, +int state,const char *buf,size_t count) +{ +char *end; +u32 val; +ssize_t result = -ENODEV ; + + val =simple_strtol (buf, &end,0 ); +if (*end =='\0' ) +return -EINVAL ; + +switch (type) { +case ACPI_THERMAL_TRIP_POINT_CRITICAL : +if (thermal->trips.critical.flags.valid){ + thermal->trips.critical.temperature =CELSIUS_TO_KELVIN (val); + result = count; + } +break ; +case ACPI_THERMAL_TRIP_POINT_HOT : +if (thermal->trips.hot.flags.valid){ + thermal->trips.hot.temperature =CELSIUS_TO_KELVIN (val); + result = count; + } +break ; +case ACPI_THERMAL_TRIP_POINT_PASSIVE : +if (thermal->trips.passive.flags.valid){ + thermal->trips.passive.temperature =CELSIUS_TO_KELVIN (val); + result = count; + } +break ; +case ACPI_THERMAL_TRIP_POINT_ACTIVE : +if (thermal->trips.active[state].flags.valid){ +if (state >=0 && state <ACPI_THERMAL_MAX_ACTIVE ) { + thermal->trips.active[state].temperature =CELSIUS_TO_KELVIN (val); + result = count; + } +else + result = -EINVAL ; + } +break ; +default : + result = -EINVAL ; + } +return result; +} + +static ssize_t _trip_point_show (struct device *dev,struct device_attribute *attr, +char *buf) +{ + struct acpi_thermal_trip_point_attr *thermal_attr = container_of(attr, struct acpi_thermal_trip_point_attr, attr); +struct acpi_device *acpi_dev =to_acpi_device (dev); +struct acpi_thermal *thermal =acpi_driver_data (acpi_dev); + +if (!thermal_attr->store) +return -EINVAL ; + +return thermal_attr->show (thermal, thermal_attr->type, thermal_attr->state, buf); +} +static ssize_t _trip_point_store (struct device *dev,struct device_attribute *attr, +const char *buf,size_t count) +{ + struct acpi_thermal_trip_point_attr *thermal_attr = container_of(attr, struct acpi_thermal_trip_point_attr, attr); +struct acpi_device *acpi_dev =to_acpi_device (dev); +struct acpi_thermal *thermal =acpi_driver_data (acpi_dev); + +if (!thermal_attr->store) +return -EINVAL ; + +return thermal_attr->store (thermal, thermal_attr->type, thermal_attr->state, buf, count); +} + +#define ACPI_THERMAL_TRIP_POINT (_name, _type, _state) \ +struct acpi_thermal_trip_point_attr _name##_attr = \ +{ \ + .attr = __ATTR(_name, 0644, _trip_point_show, _trip_point_store), \ + .type = _type, \ + .state = _state, \ + .show = acpi_thermal_trip_point_show, \ + .store = acpi_thermal_trip_point_store, \ +} + + +static ACPI_THERMAL_TRIP_POINT(critical_temp, ACPI_THERMAL_TRIP_POINT_CRITICAL, 0); +static ACPI_THERMAL_TRIP_POINT(hot_temp, ACPI_THERMAL_TRIP_POINT_HOT, 0); +static ACPI_THERMAL_TRIP_POINT(passive_temp, ACPI_THERMAL_TRIP_POINT_PASSIVE, 0); +static ACPI_THERMAL_TRIP_POINT(active0_temp, ACPI_THERMAL_TRIP_POINT_ACTIVE, 0); +static ACPI_THERMAL_TRIP_POINT(active1_temp, ACPI_THERMAL_TRIP_POINT_ACTIVE, 1); +static ACPI_THERMAL_TRIP_POINT(active2_temp, ACPI_THERMAL_TRIP_POINT_ACTIVE, 2); +static ACPI_THERMAL_TRIP_POINT(active3_temp, ACPI_THERMAL_TRIP_POINT_ACTIVE, 3); +static ACPI_THERMAL_TRIP_POINT(active4_temp, ACPI_THERMAL_TRIP_POINT_ACTIVE, 4); +static ACPI_THERMAL_TRIP_POINT(active5_temp, ACPI_THERMAL_TRIP_POINT_ACTIVE, 5); +static ACPI_THERMAL_TRIP_POINT(active6_temp, ACPI_THERMAL_TRIP_POINT_ACTIVE, 6); +static ACPI_THERMAL_TRIP_POINT(active7_temp, ACPI_THERMAL_TRIP_POINT_ACTIVE, 7); +static ACPI_THERMAL_TRIP_POINT(active8_temp, ACPI_THERMAL_TRIP_POINT_ACTIVE, 8); +static ACPI_THERMAL_TRIP_POINT(active9_temp, ACPI_THERMAL_TRIP_POINT_ACTIVE, 9); + +static struct device_attribute *thermal_default_attr[] = +{ +GET_DEV_ATTR (state), +GET_DEV_ATTR (temperature), +GET_DEV_ATTR (cooling_mode), +GET_DEV_ATTR (polling_freq), +GET_DEV_ATTR (critical_temp), +NULL , +}; + +static struct device_attribute *thermal_optional_attr[] = +{ +GET_DEV_ATTR (hot_temp), +GET_DEV_ATTR (passive_temp), +GET_DEV_ATTR (passive_tc1), +GET_DEV_ATTR (passive_tc2), +GET_DEV_ATTR (passive_tsp), +GET_DEV_ATTR (active0_temp), +GET_DEV_ATTR (active1_temp), +GET_DEV_ATTR (active2_temp), +GET_DEV_ATTR (active3_temp), +GET_DEV_ATTR (active4_temp), +GET_DEV_ATTR (active5_temp), +GET_DEV_ATTR (active6_temp), +GET_DEV_ATTR (active7_temp), +GET_DEV_ATTR (active8_temp), +GET_DEV_ATTR (active9_temp), +}; + +static int acpi_thermal_add_sysfs (struct acpi_device * device) +{ +int result =0 ; + + result =acpi_device_add_sysfs (device, thermal_default_attr); + +/* +* optional trip point attributes (hot/passive/active) +* and syslinks to cooling devices both are dynamic +*/ + +return result; +} + +static void acpi_thermal_remove_sysfs (struct acpi_device * device) +{ +struct acpi_thermal *thermal =acpi_driver_data (device); +struct acpi_handle_list new_devices; +int i =0 ; + +acpi_device_remove_sysfs (device, thermal_default_attr); + +/* +* remove syslinks to cooling devices +*/ + new_devices.count =0 ; + +if (thermal->trips.passive.flags.valid) +acpi_thermal_cooling_device_update (thermal,-1 , &new_devices); + + +for (i =0 ; i <ACPI_THERMAL_MAX_ACTIVE ; i++) +if (thermal->trips.active[i].flags.valid) +acpi_thermal_cooling_device_update (thermal, i, &new_devices); + +/* +* remove optional trip point attributes +*/ +if (thermal->trips.hot.flags.valid ) +device_remove_file (&device->dev, thermal_optional_attr[0 ]); + +if (thermal->trips.passive.flags.valid) +for (i =0 ; i <4 ; i++) +device_remove_file (&device->dev, thermal_optional_attr[1 +i]); + + +for (i =0 ; i <ACPI_THERMAL_MAX_ACTIVE ; i++) +if ((thermal->trips.active[i].flags.valid)) +device_remove_file (&device->dev, thermal_optional_attr[5 +i]); + +return ; +} + +static int acpi_thermal_cooling_device_update (struct acpi_thermal * thermal,int state, +struct acpi_handle_list *new_devices) +{ +struct acpi_device *device = thermal->device; +struct acpi_handle_list *old_devices; +struct acpi_device *cooling_device; +char buf[24 ]; +int i =0 ; +int result =0 ; + +if (!device || !new_devices) +return -EINVAL ; + +if (state ==-1 ) { +sprintf (buf,"passive_cooling_device0" ); + old_devices = &thermal->trips.passive.devices; + } +else +if (state >=0 && state <ACPI_THERMAL_MAX_ACTIVE ) { +sprintf (buf,"active%d_cooling_device0" , state); + old_devices = &thermal->trips.active[state].devices; + } +else +return -EINVAL ; + +for (i =0 ; i < old_devices->count || i < new_devices->count; i++) { +if (i >= old_devices->count) + old_devices->handles[i] =NULL ; +if (i >= new_devices->count) + new_devices->handles[i] =NULL ; +if (new_devices->handles[i] != old_devices->handles[i]) { + buf[22 ] ='0' +i; + +if (i < old_devices->count && old_devices->handles[i]) +sysfs_remove_link (&device->dev.kobj, buf); + +if (i < new_devices->count && new_devices->handles[i]) { +acpi_bus_get_device (new_devices->handles[i], &cooling_device); + result =sysfs_create_link (&device->dev.kobj, &cooling_device->dev.kobj, buf); +if (result) +return result; + } + old_devices->handles[i] = new_devices->handles[i]; + } + } + old_devices->count = new_devices->count; + +return result; +} + +static int acpi_thermal_trip_point_update (struct device *dev,struct device_attribute *attr,int type) +{ +int result =0 ; + +if (type) + result =device_create_file (dev, attr); +else +device_remove_file (dev, attr); + +return result; +} + +static int acpi_thermal_sysfs_update (struct acpi_thermal *thermal,struct acpi_thermal_state *old_state) +{ +struct acpi_device *device = thermal->device; +int result =0 ; +int i =0 ; + +if (thermal->trips.hot.flags.valid != old_state->hot) { + result =acpi_thermal_trip_point_update (&device->dev, thermal_optional_attr[0 ], + thermal->trips.hot.flags.valid); +if (result) + goto done; + } + +if (thermal->trips.passive.flags.valid != old_state->passive) +for (i =0 ; i <4 ; i++) { + result =acpi_thermal_trip_point_update (&device->dev, thermal_optional_attr[1 +i], + thermal->trips.passive.flags.valid); +if (result) + goto done; + } + +for (i =0 ; i <ACPI_THERMAL_MAX_ACTIVE ; i++) + { +if ((thermal->trips.active[i].flags.valid && i >= old_state->active_index) || + (!thermal->trips.active[i].flags.valid && i < old_state->active_index)) { + result =acpi_thermal_trip_point_update (&device->dev, thermal_optional_attr[5 +i], + thermal->trips.active[i].flags.valid); +if (result) + goto done; + } + } + + done: +return result; +} + +/* -------------------------------------------------------------------------- +FS Interface (/proc) +-------------------------------------------------------------------------- */ +#ifdef CONFIG_ACPI_PROCFS static struct proc_dir_entry *acpi_thermal_dir;static int acpi_thermal_state_seq_show (struct seq_file *seq,void *offset)@@ -838,6 +1303,7 @@ static int acpi_thermal_temp_open_fs(strstatic int acpi_thermal_trip_seq_show (struct seq_file *seq,void *offset) {struct acpi_thermal *tz = seq->private; +struct acpi_device *device;int i =0 ;int j =0 ;@@ -860,9 +1326,8 @@ static int acpi_thermal_trip_seq_show(st tz->trips.passive.tc1, tz->trips.passive.tc2, tz->trips.passive.tsp);for (j =0 ; j < tz->trips.passive.devices.count; j++) { - -seq_printf (seq,"0x%p " , - tz->trips.passive.devices.handles[j]); +acpi_bus_get_device (tz->trips.passive.devices.handles[j], &device); +seq_printf (seq,"%4.4s " ,acpi_device_bid (device)); }seq_puts (seq,"\n" ); }@@ -873,9 +1338,10 @@ static int acpi_thermal_trip_seq_show(stseq_printf (seq,"active[%d]: %ld C: devices=" , i,KELVIN_TO_CELSIUS (tz->trips.active[i].temperature)); -for (j =0 ; j < tz->trips.active[i].devices.count; j++) -seq_printf (seq,"0x%p " , - tz->trips.active[i].devices.handles[j]); +for (j =0 ; j < tz->trips.active[i].devices.count; j++) { +acpi_bus_get_device (tz->trips.active[i].devices.handles[j], &device); +seq_printf (seq,"%4.4s " ,acpi_device_bid (device)); + }seq_puts (seq,"\n" ); }@@ -1067,7 +1533,45 @@ acpi_thermal_write_polling(struct file *return count; } -static int acpi_thermal_add_fs (struct acpi_device *device) +static const struct file_operations acpi_thermal_state_fops = { + .open = acpi_thermal_state_open_fs, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations acpi_thermal_temp_fops = { + .open = acpi_thermal_temp_open_fs, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations acpi_thermal_trip_fops = { + .open = acpi_thermal_trip_open_fs, + .read = seq_read, + .write = acpi_thermal_write_trip_points, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations acpi_thermal_cooling_fops = { + .open = acpi_thermal_cooling_open_fs, + .read = seq_read, + .write = acpi_thermal_write_cooling_mode, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations acpi_thermal_polling_fops = { + .open = acpi_thermal_polling_open_fs, + .read = seq_read, + .write = acpi_thermal_write_polling, + .llseek = seq_lseek, + .release = single_release, +}; + +static int acpi_thermal_add_procfs (struct acpi_device *device) {struct proc_dir_entry *entry =NULL ;@@ -1141,7 +1645,7 @@ static int acpi_thermal_add_fs(struct acreturn 0 ; } -static int acpi_thermal_remove_fs (struct acpi_device *device) +static int acpi_thermal_remove_procfs (struct acpi_device *device) {if (acpi_device_dir (device)) {@@ -1162,6 +1666,26 @@ static int acpi_thermal_remove_fs(struct return 0; } +static int acpi_thermal_procfs_init (void ) +{ + acpi_thermal_dir =proc_mkdir (ACPI_THERMAL_CLASS , acpi_root_dir); +if (!acpi_thermal_dir) +return -ENODEV ; + acpi_thermal_dir->owner =THIS_MODULE ; + +return 0 ; +} + +static int acpi_thermal_procfs_exit (void ) +{ +remove_proc_entry (ACPI_THERMAL_CLASS , acpi_root_dir); + +return 0 ; +} +#else +declare_acpi_device_procfs (thermal); +#endif +/* -------------------------------------------------------------------------- Driver Interface -------------------------------------------------------------------------- */ @@ -1283,10 +1807,14 @@ static int acpi_thermal_add(struct acpi_if (result) goto end; - result =acpi_thermal_add_fs (device); + result =acpi_thermal_add_sysfs (device);if (result) goto end; + result =acpi_thermal_add_procfs (device); +if (result) + goto procfs_error; +init_timer (&tz->timer);acpi_thermal_check (tz);@@ -1296,19 +1824,22 @@ static int acpi_thermal_add(struct acpi_ acpi_thermal_notify, tz);if (ACPI_FAILURE (status)) { result = -ENODEV ; - goto end; + goto notify_error; } printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n",acpi_device_name (device),acpi_device_bid (device), KELVIN_TO_CELSIUS(tz->temperature)); - end: -if (result) { -acpi_thermal_remove_fs (device); -kfree (tz); - } + goto end; + notify_error: +acpi_thermal_remove_procfs (device); + procfs_error: +acpi_thermal_remove_sysfs (device); + end: +if (result) +kfree (tz);return result; }@@ -1347,7 +1878,9 @@ static int acpi_thermal_remove(struct acacpi_thermal_active (tz); } -acpi_thermal_remove_fs (device); +acpi_thermal_remove_procfs (device); + +acpi_thermal_remove_sysfs (device);kfree (tz);return 0 ;@@ -1390,15 +1923,14 @@ static int __init acpi_thermal_init(void {int result =0 ; + result =acpi_thermal_procfs_init (); +if (result) +return result; - acpi_thermal_dir =proc_mkdir (ACPI_THERMAL_CLASS , acpi_root_dir); -if (!acpi_thermal_dir) -return -ENODEV ; - acpi_thermal_dir->owner =THIS_MODULE ; - + acpi_thermal_driver.owner =THIS_MODULE ; result =acpi_bus_register_driver (&acpi_thermal_driver);if (result <0 ) { -remove_proc_entry (ACPI_THERMAL_CLASS , acpi_root_dir); +acpi_thermal_procfs_exit ();return -ENODEV ; }@@ -1407,10 +1939,9 @@ static int __init acpi_thermal_init(void static void __exit acpi_thermal_exit(void) { -acpi_bus_unregister_driver (&acpi_thermal_driver); -remove_proc_entry (ACPI_THERMAL_CLASS , acpi_root_dir); +acpi_thermal_procfs_exit ();return ; }