2
* init.c -- module initialization code
4
* This program is free software; you can redistribute it and/or modify it
5
* under the terms of the GNU General Public License as published by the
6
* Free Software Foundation; either version 2, or (at your option) any
9
* This program is distributed in the hope that it will be useful, but
10
* WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* General Public License for more details.
14
* Written by Soós Péter <sp@osb.hu>, 2002-2004
15
* Modified by Mathieu Bérard <mathieu.berard@crans.org>, 2006
20
#include <linux/proc_fs.h>
21
#include <linux/dmi.h>
22
#include <linux/version.h>
23
#include <asm/uaccess.h>
28
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15))
29
#include <linux/platform_device.h>
31
#include <linux/device.h>
35
* For compatibility with kernel older than 2.6.11
38
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11))
39
typedef u32 pm_message_t;
42
static int __init omnibook_probe(struct platform_device *dev);
43
static int __exit omnibook_remove(struct platform_device *dev);
44
static int omnibook_suspend(struct platform_device *dev, pm_message_t state);
45
static int omnibook_resume(struct platform_device *dev);
48
* For compatibility with kernel older than 2.6.15
51
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15))
53
#define to_platform_device(x) container_of((x), struct platform_device, dev)
55
static int __init compat_omnibook_probe(struct device *dev)
57
struct platform_device *pdev = to_platform_device(dev);
58
return omnibook_probe(pdev);
61
static int __exit compat_omnibook_remove(struct device *dev)
63
struct platform_device *pdev = to_platform_device(dev);
64
return omnibook_remove(pdev);
67
static int compat_omnibook_suspend(struct device *dev, pm_message_t state, u32 level)
69
struct platform_device *pdev = to_platform_device(dev);
70
return omnibook_suspend(pdev, state);
73
static int compat_omnibook_resume(struct device *dev, u32 level)
75
struct platform_device *pdev = to_platform_device(dev);
76
return omnibook_resume(pdev);
81
static struct proc_dir_entry *omnibook_proc_root = NULL;
83
enum omnibook_ectype_t omnibook_ectype = NONE;
85
static const char *laptop_model __initdata;
87
static int omnibook_userset = 0;
90
* The platform_driver interface was added in linux 2.6.15
92
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15))
94
static struct platform_device *omnibook_device;
96
static struct platform_driver omnibook_driver = {
97
.probe = omnibook_probe,
98
.remove = omnibook_remove,
100
.suspend = omnibook_suspend,
101
.resume = omnibook_resume,
104
.name = OMNIBOOK_MODULE_NAME,
105
.owner = THIS_MODULE,
111
static struct device_driver omnibook_driver = {
112
.name = OMNIBOOK_MODULE_NAME,
113
.bus = &platform_bus_type,
114
.probe = compat_omnibook_probe,
115
.remove = compat_omnibook_remove,
117
.suspend = compat_omnibook_suspend,
118
.resume = compat_omnibook_resume,
122
static struct platform_device omnibook_device = {
123
.name = OMNIBOOK_MODULE_NAME,
128
/* Linked list of all enabled features */
129
static struct omnibook_feature *omnibook_available_feature;
131
/* Delimiters of the .features section wich holds all the omnibook_feature structs */
132
extern struct omnibook_feature _start_features_driver[];
133
extern struct omnibook_feature _end_features_driver[];
135
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
136
static int __init dmi_matched(struct dmi_system_id *dmi)
138
static int __init dmi_matched(const struct dmi_system_id *dmi)
141
omnibook_ectype = (enum omnibook_ectype_t)dmi->driver_data;
143
laptop_model = (char *)dmi->ident;
145
laptop_model = dmi_get_system_info(DMI_PRODUCT_VERSION);
146
return 1; /* return non zero means we stop the parsing selecting this entry */
150
* Callback function for procfs file reading: the name of the file read was stored in *data
152
static int procfile_read_dispatch(char *page, char **start, off_t off, int count, int *eof,
155
struct omnibook_feature *feature = (struct omnibook_feature *)data;
158
if (!feature || !feature->read)
164
len = feature->read(page, feature->io_op);
174
* Callback function for procfs file writing: the name of the file written was stored in *data
176
static int procfile_write_dispatch(struct file *file, const char __user * userbuf,
177
unsigned long count, void *data)
179
struct omnibook_feature *feature = (struct omnibook_feature *)data;
183
if (!feature || !feature->write)
186
kernbuf = kmalloc(count + 1, GFP_KERNEL);
190
if (copy_from_user(kernbuf, userbuf, count)) {
195
/* Make sure the string is \0 terminated */
196
kernbuf[count] = '\0';
198
retval = feature->write(kernbuf, feature->io_op);
208
* Match an ectype and return pointer to corresponding omnibook_operation.
209
* Also make corresponding backend initialisation if necessary, and skip
210
* to the next entry if it fails.
212
static struct omnibook_operation *omnibook_backend_match(struct omnibook_tbl *tbl)
215
struct omnibook_operation *matched = NULL;
217
for (i = 0; tbl[i].ectypes; i++) {
218
if (omnibook_ectype & tbl[i].ectypes) {
219
if (tbl[i].io_op.backend->init && tbl[i].io_op.backend->init(&tbl[i].io_op)) {
220
dprintk("Backend %s init failed, skipping entry.\n",
221
tbl[i].io_op.backend->name);
224
matched = &tbl[i].io_op;
225
dprintk("Returning table entry nr %i.\n", i);
233
* Initialise a feature and add it to the linked list of active features
235
static int __init omnibook_init(struct omnibook_feature *feature)
239
struct proc_dir_entry *proc_entry;
240
struct omnibook_operation *op;
246
* Select appropriate backend for feature operations
247
* We copy the io_op field so the tbl can be initdata
250
dprintk("Begin table match of %s feature.\n", feature->name);
251
op = omnibook_backend_match(feature->tbl);
253
dprintk("Match failed: disabling %s.\n", feature->name);
256
feature->io_op = kmalloc(sizeof(struct omnibook_operation), GFP_KERNEL);
259
memcpy(feature->io_op, op, sizeof(struct omnibook_operation));
261
dprintk("%s feature has no backend table, io_op not initialized.\n", feature->name);
264
* Specific feature init code
266
if (feature->init && (retval = feature->init(feature->io_op))) {
267
printk(O_ERR "Init function of %s failed with error %i.\n", feature->name, retval);
273
if (feature->name && feature->read) {
274
pmode = S_IFREG | S_IRUGO;
275
if (feature->write) {
277
if (omnibook_userset)
281
proc_entry = create_proc_entry(feature->name, pmode, omnibook_proc_root);
284
printk(O_ERR "Unable to create proc entry %s\n", feature->name);
286
feature->exit(feature->io_op);
290
proc_entry->data = feature;
291
proc_entry->read_proc = &procfile_read_dispatch;
293
proc_entry->write_proc = &procfile_write_dispatch;
294
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
295
proc_entry->owner = THIS_MODULE;
298
list_add_tail(&feature->list, &omnibook_available_feature->list);
301
if (feature->io_op && feature->io_op->backend->exit)
302
feature->io_op->backend->exit(feature->io_op);
303
kfree(feature->io_op);
308
* Callback function for driver registering :
309
* Initialize the linked list of enabled features and call omnibook_init to populate it
311
static int __init omnibook_probe(struct platform_device *dev)
314
struct omnibook_feature *feature;
317
mutex_init(&kbc_backend.mutex);
318
mutex_init(&pio_backend.mutex);
319
mutex_init(&ec_backend.mutex);
321
omnibook_available_feature = kzalloc(sizeof(struct omnibook_feature), GFP_KERNEL);
322
if (!omnibook_available_feature)
324
INIT_LIST_HEAD(&omnibook_available_feature->list);
326
for (i = 0; i < _end_features_driver - _start_features_driver; i++) {
328
feature = &_start_features_driver[i];
330
if (!feature->enabled)
333
if ((omnibook_ectype & feature->ectypes) || (!feature->ectypes))
334
omnibook_init(feature);
337
printk(O_INFO "Enabled features:");
338
list_for_each_entry(feature, &omnibook_available_feature->list, list) {
340
printk(" %s", feature->name);
348
* Callback function for driver removal
350
static int __exit omnibook_remove(struct platform_device *dev)
352
struct omnibook_feature *feature, *temp;
354
list_for_each_entry_safe(feature, temp, &omnibook_available_feature->list, list) {
355
list_del(&feature->list);
356
/* Feature specific cleanup */
358
feature->exit(feature->io_op);
359
/* Generic backend cleanup */
360
if (feature->io_op && feature->io_op->backend->exit)
361
feature->io_op->backend->exit(feature->io_op);
363
remove_proc_entry(feature->name, omnibook_proc_root);
364
kfree(feature->io_op);
366
kfree(omnibook_available_feature);
372
* Callback function for system suspend
374
static int omnibook_suspend(struct platform_device *dev, pm_message_t state)
377
struct omnibook_feature *feature;
379
list_for_each_entry(feature, &omnibook_available_feature->list, list) {
380
if (feature->suspend) {
381
retval = feature->suspend(feature->io_op);
383
printk(O_ERR "Unable to suspend the %s feature (error %i).\n", feature->name, retval);
390
* Callback function for system resume
392
static int omnibook_resume(struct platform_device *dev)
395
struct omnibook_feature *feature;
397
list_for_each_entry(feature, &omnibook_available_feature->list, list) {
398
if (feature->resume) {
399
retval = feature->resume(feature->io_op);
401
printk(O_ERR "Unable to resume the %s feature (error %i).\n", feature->name, retval);
408
* Find a given available feature by its name
410
struct omnibook_feature *omnibook_find_feature(char *name)
412
struct omnibook_feature *feature;
414
list_for_each_entry(feature, &omnibook_available_feature->list, list) {
415
if (!strcmp(feature->name, name))
422
* Maintain compatibility with the old ectype numbers:
423
* ex: The user set/get ectype=12 for TSM70=2^(12-1)
425
static int __init set_ectype_param(const char *val, struct kernel_param *kp)
433
value = simple_strtol(val, &endp, 10);
434
if (endp == val) /* No match */
436
omnibook_ectype = 1 << (value - 1);
440
static int get_ectype_param(char *buffer, struct kernel_param *kp)
442
return sprintf(buffer, "%i", ffs(omnibook_ectype));
445
static int __init omnibook_module_init(void)
449
printk(O_INFO "Driver version %s.\n", OMNIBOOK_MODULE_VERSION);
451
if (omnibook_ectype != NONE)
452
printk(O_WARN "Forced load with EC type %i.\n", ffs(omnibook_ectype));
453
else if (dmi_check_system(omnibook_ids))
454
printk(O_INFO "%s detected.\n", laptop_model);
456
printk(O_INFO "Unknown model.\n");
458
omnibook_proc_root = proc_mkdir(OMNIBOOK_MODULE_NAME, NULL);
459
if (!omnibook_proc_root) {
460
printk(O_ERR "Unable to create /proc/%s.\n", OMNIBOOK_MODULE_NAME);
465
* The platform_driver interface was added in linux 2.6.15
468
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15))
470
retval = platform_driver_register(&omnibook_driver);
474
omnibook_device = platform_device_alloc(OMNIBOOK_MODULE_NAME, -1);
475
if (!omnibook_device) {
476
platform_driver_unregister(&omnibook_driver);
480
retval = platform_device_add(omnibook_device);
482
platform_device_put(omnibook_device);
483
platform_driver_unregister(&omnibook_driver);
488
retval = driver_register(&omnibook_driver);
492
retval = platform_device_register(&omnibook_device);
495
driver_unregister(&omnibook_driver);
502
static void __exit omnibook_module_cleanup(void)
506
* The platform_driver interface was added in linux 2.6.15
509
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15))
510
platform_device_unregister(omnibook_device);
511
platform_driver_unregister(&omnibook_driver);
513
platform_device_unregister(&omnibook_device);
514
driver_unregister(&omnibook_driver);
517
if (omnibook_proc_root)
518
remove_proc_entry("omnibook", NULL);
519
printk(O_INFO "Module is unloaded.\n");
522
module_init(omnibook_module_init);
523
module_exit(omnibook_module_cleanup);
525
MODULE_AUTHOR("Soós Péter, Mathieu Bérard");
526
MODULE_VERSION(OMNIBOOK_MODULE_VERSION);
528
("Kernel interface for HP OmniBook, HP Pavilion, Toshiba Satellite and Compal ACL00 laptops");
529
MODULE_LICENSE("GPL");
530
module_param_call(ectype, set_ectype_param, get_ectype_param, NULL, S_IRUGO);
531
module_param_named(userset, omnibook_userset, int, S_IRUGO);
532
MODULE_PARM_DESC(ectype, "Type of embedded controller firmware");
533
MODULE_PARM_DESC(userset, "Use 0 to disable, 1 to enable users to set parameters");