2 * kernel/power/tuxonice_sysfs.c
4 * Copyright (C) 2002-2010 Nigel Cunningham (nigel at tuxonice net)
6 * This file is released under the GPLv2.
8 * This file contains support for sysfs entries for tuning TuxOnIce.
10 * We have a generic handler that deals with the most common cases, and
11 * hooks for special handlers to use.
14 #include <linux/suspend.h>
16 #include "tuxonice_sysfs.h"
18 #include "tuxonice_storage.h"
19 #include "tuxonice_alloc.h"
21 static int toi_sysfs_initialised
;
23 static void toi_initialise_sysfs(void);
25 static struct toi_sysfs_data sysfs_params
[];
27 #define to_sysfs_data(_attr) container_of(_attr, struct toi_sysfs_data, attr)
29 static void toi_main_wrapper(void)
34 static ssize_t
toi_attr_show(struct kobject
*kobj
, struct attribute
*attr
, char *page
)
36 struct toi_sysfs_data
*sysfs_data
= to_sysfs_data(attr
);
38 int full_prep
= sysfs_data
->flags
& SYSFS_NEEDS_SM_FOR_READ
;
40 if (full_prep
&& toi_start_anything(0))
43 if (sysfs_data
->flags
& SYSFS_NEEDS_SM_FOR_READ
)
46 switch (sysfs_data
->type
) {
47 case TOI_SYSFS_DATA_CUSTOM
:
48 len
= (sysfs_data
->data
.special
.read_sysfs
) ?
49 (sysfs_data
->data
.special
.read_sysfs
) (page
, PAGE_SIZE
)
52 case TOI_SYSFS_DATA_BIT
:
53 len
= sprintf(page
, "%d\n",
54 -test_bit(sysfs_data
->data
.bit
.bit
, sysfs_data
->data
.bit
.bit_vector
));
56 case TOI_SYSFS_DATA_INTEGER
:
57 len
= sprintf(page
, "%d\n", *(sysfs_data
->data
.integer
.variable
));
59 case TOI_SYSFS_DATA_LONG
:
60 len
= sprintf(page
, "%ld\n", *(sysfs_data
->data
.a_long
.variable
));
62 case TOI_SYSFS_DATA_UL
:
63 len
= sprintf(page
, "%lu\n", *(sysfs_data
->data
.ul
.variable
));
65 case TOI_SYSFS_DATA_STRING
:
66 len
= sprintf(page
, "%s\n", sysfs_data
->data
.string
.variable
);
70 if (sysfs_data
->flags
& SYSFS_NEEDS_SM_FOR_READ
)
74 toi_finish_anything(0);
79 #define BOUND(_variable, _type) do { \
80 if (*_variable < sysfs_data->data._type.minimum) \
81 *_variable = sysfs_data->data._type.minimum; \
82 else if (*_variable > sysfs_data->data._type.maximum) \
83 *_variable = sysfs_data->data._type.maximum; \
86 static ssize_t
toi_attr_store(struct kobject
*kobj
, struct attribute
*attr
,
87 const char *my_buf
, size_t count
)
89 int assigned_temp_buffer
= 0, result
= count
;
90 struct toi_sysfs_data
*sysfs_data
= to_sysfs_data(attr
);
92 if (toi_start_anything((sysfs_data
->flags
& SYSFS_HIBERNATE_OR_RESUME
)))
95 ((char *)my_buf
)[count
] = 0;
97 if (sysfs_data
->flags
& SYSFS_NEEDS_SM_FOR_WRITE
)
100 switch (sysfs_data
->type
) {
101 case TOI_SYSFS_DATA_CUSTOM
:
102 if (sysfs_data
->data
.special
.write_sysfs
)
103 result
= (sysfs_data
->data
.special
.write_sysfs
) (my_buf
, count
);
105 case TOI_SYSFS_DATA_BIT
:
108 result
= strict_strtoul(my_buf
, 0, &value
);
112 set_bit(sysfs_data
->data
.bit
.bit
,
113 (sysfs_data
->data
.bit
.bit_vector
));
115 clear_bit(sysfs_data
->data
.bit
.bit
,
116 (sysfs_data
->data
.bit
.bit_vector
));
119 case TOI_SYSFS_DATA_INTEGER
:
122 result
= strict_strtol(my_buf
, 0, &temp
);
125 *(sysfs_data
->data
.integer
.variable
) = (int)temp
;
126 BOUND(sysfs_data
->data
.integer
.variable
, integer
);
129 case TOI_SYSFS_DATA_LONG
:
131 long *variable
= sysfs_data
->data
.a_long
.variable
;
132 result
= strict_strtol(my_buf
, 0, variable
);
135 BOUND(variable
, a_long
);
138 case TOI_SYSFS_DATA_UL
:
140 unsigned long *variable
= sysfs_data
->data
.ul
.variable
;
141 result
= strict_strtoul(my_buf
, 0, variable
);
148 case TOI_SYSFS_DATA_STRING
:
150 int copy_len
= count
;
151 char *variable
= sysfs_data
->data
.string
.variable
;
153 if (sysfs_data
->data
.string
.max_length
&&
154 (copy_len
> sysfs_data
->data
.string
.max_length
))
155 copy_len
= sysfs_data
->data
.string
.max_length
;
158 variable
= (char *)toi_get_zeroed_page(31, TOI_ATOMIC_GFP
);
159 sysfs_data
->data
.string
.variable
= variable
;
160 assigned_temp_buffer
= 1;
162 strncpy(variable
, my_buf
, copy_len
);
163 if (copy_len
&& my_buf
[copy_len
- 1] == '\n')
164 variable
[count
- 1] = 0;
173 /* Side effect routine? */
174 if (result
== count
&& sysfs_data
->write_side_effect
)
175 sysfs_data
->write_side_effect();
177 /* Free temporary buffers */
178 if (assigned_temp_buffer
) {
179 toi_free_page(31, (unsigned long)sysfs_data
->data
.string
.variable
);
180 sysfs_data
->data
.string
.variable
= NULL
;
183 if (sysfs_data
->flags
& SYSFS_NEEDS_SM_FOR_WRITE
)
186 toi_finish_anything(sysfs_data
->flags
& SYSFS_HIBERNATE_OR_RESUME
);
191 static struct sysfs_ops toi_sysfs_ops
= {
192 .show
= &toi_attr_show
,
193 .store
= &toi_attr_store
,
196 static struct kobj_type toi_ktype
= {
197 .sysfs_ops
= &toi_sysfs_ops
,
200 struct kobject
*tuxonice_kobj
;
202 /* Non-module sysfs entries.
204 * This array contains entries that are automatically registered at
205 * boot. Modules and the console code register their own entries separately.
208 static struct toi_sysfs_data sysfs_params
[] = {
209 SYSFS_CUSTOM("do_hibernate", SYSFS_WRITEONLY
, NULL
, NULL
,
210 SYSFS_HIBERNATING
, toi_main_wrapper
),
211 SYSFS_CUSTOM("do_resume", SYSFS_WRITEONLY
, NULL
, NULL
,
212 SYSFS_RESUMING
, toi_try_resume
)
215 void remove_toi_sysdir(struct kobject
*kobj
)
223 struct kobject
*make_toi_sysdir(char *name
)
225 struct kobject
*kobj
= kobject_create_and_add(name
, tuxonice_kobj
);
228 printk(KERN_INFO
"TuxOnIce: Can't allocate kobject for sysfs " "dir!\n");
232 kobj
->ktype
= &toi_ktype
;
237 /* toi_register_sysfs_file
239 * Helper for registering a new /sysfs/tuxonice entry.
242 int toi_register_sysfs_file(struct kobject
*kobj
, struct toi_sysfs_data
*toi_sysfs_data
)
246 if (!toi_sysfs_initialised
)
247 toi_initialise_sysfs();
249 result
= sysfs_create_file(kobj
, &toi_sysfs_data
->attr
);
251 printk(KERN_INFO
"TuxOnIce: sysfs_create_file for %s "
252 "returned %d.\n", toi_sysfs_data
->attr
.name
, result
);
253 kobj
->ktype
= &toi_ktype
;
257 EXPORT_SYMBOL_GPL(toi_register_sysfs_file
);
259 /* toi_unregister_sysfs_file
261 * Helper for removing unwanted /sys/power/tuxonice entries.
264 void toi_unregister_sysfs_file(struct kobject
*kobj
, struct toi_sysfs_data
*toi_sysfs_data
)
266 sysfs_remove_file(kobj
, &toi_sysfs_data
->attr
);
268 EXPORT_SYMBOL_GPL(toi_unregister_sysfs_file
);
270 void toi_cleanup_sysfs(void)
272 int i
, numfiles
= sizeof(sysfs_params
) / sizeof(struct toi_sysfs_data
);
274 if (!toi_sysfs_initialised
)
277 for (i
= 0; i
< numfiles
; i
++)
278 toi_unregister_sysfs_file(tuxonice_kobj
, &sysfs_params
[i
]);
280 kobject_put(tuxonice_kobj
);
281 toi_sysfs_initialised
= 0;
284 /* toi_initialise_sysfs
286 * Initialise the /sysfs/tuxonice directory.
289 static void toi_initialise_sysfs(void)
292 int numfiles
= sizeof(sysfs_params
) / sizeof(struct toi_sysfs_data
);
294 if (toi_sysfs_initialised
)
297 /* Make our TuxOnIce directory a child of /sys/power */
298 tuxonice_kobj
= kobject_create_and_add("tuxonice", power_kobj
);
302 toi_sysfs_initialised
= 1;
304 for (i
= 0; i
< numfiles
; i
++)
305 toi_register_sysfs_file(tuxonice_kobj
, &sysfs_params
[i
]);
308 int toi_sysfs_init(void)
310 toi_initialise_sysfs();
314 void toi_sysfs_exit(void)