OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [misc/] [msi-laptop.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*-*-linux-c-*-*/
2
 
3
/*
4
  Copyright (C) 2006 Lennart Poettering <mzxreary (at) 0pointer (dot) de>
5
 
6
  This program is free software; you can redistribute it and/or modify
7
  it under the terms of the GNU General Public License as published by
8
  the Free Software Foundation; either version 2 of the License, or
9
  (at your option) any later version.
10
 
11
  This program is distributed in the hope that it will be useful, but
12
  WITHOUT ANY WARRANTY; without even the implied warranty of
13
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
  General Public License for more details.
15
 
16
  You should have received a copy of the GNU General Public License
17
  along with this program; if not, write to the Free Software
18
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
  02110-1301, USA.
20
 */
21
 
22
/*
23
 * msi-laptop.c - MSI S270 laptop support. This laptop is sold under
24
 * various brands, including "Cytron/TCM/Medion/Tchibo MD96100".
25
 *
26
 * Driver also supports S271, S420 models.
27
 *
28
 * This driver exports a few files in /sys/devices/platform/msi-laptop-pf/:
29
 *
30
 *   lcd_level - Screen brightness: contains a single integer in the
31
 *   range 0..8. (rw)
32
 *
33
 *   auto_brightness - Enable automatic brightness control: contains
34
 *   either 0 or 1. If set to 1 the hardware adjusts the screen
35
 *   brightness automatically when the power cord is
36
 *   plugged/unplugged. (rw)
37
 *
38
 *   wlan - WLAN subsystem enabled: contains either 0 or 1. (ro)
39
 *
40
 *   bluetooth - Bluetooth subsystem enabled: contains either 0 or 1
41
 *   Please note that this file is constantly 0 if no Bluetooth
42
 *   hardware is available. (ro)
43
 *
44
 * In addition to these platform device attributes the driver
45
 * registers itself in the Linux backlight control subsystem and is
46
 * available to userspace under /sys/class/backlight/msi-laptop-bl/.
47
 *
48
 * This driver might work on other laptops produced by MSI. If you
49
 * want to try it you can pass force=1 as argument to the module which
50
 * will force it to load even when the DMI data doesn't identify the
51
 * laptop as MSI S270. YMMV.
52
 */
53
 
54
#include <linux/module.h>
55
#include <linux/kernel.h>
56
#include <linux/init.h>
57
#include <linux/acpi.h>
58
#include <linux/dmi.h>
59
#include <linux/backlight.h>
60
#include <linux/platform_device.h>
61
#include <linux/autoconf.h>
62
 
63
#define MSI_DRIVER_VERSION "0.5"
64
 
65
#define MSI_LCD_LEVEL_MAX 9
66
 
67
#define MSI_EC_COMMAND_WIRELESS 0x10
68
#define MSI_EC_COMMAND_LCD_LEVEL 0x11
69
 
70
static int force;
71
module_param(force, bool, 0);
72
MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
73
 
74
static int auto_brightness;
75
module_param(auto_brightness, int, 0);
76
MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)");
77
 
78
/* Hardware access */
79
 
80
static int set_lcd_level(int level)
81
{
82
        u8 buf[2];
83
 
84
        if (level < 0 || level >= MSI_LCD_LEVEL_MAX)
85
                return -EINVAL;
86
 
87
        buf[0] = 0x80;
88
        buf[1] = (u8) (level*31);
89
 
90
        return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, buf, sizeof(buf), NULL, 0, 1);
91
}
92
 
93
static int get_lcd_level(void)
94
{
95
        u8 wdata = 0, rdata;
96
        int result;
97
 
98
        result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1, 1);
99
        if (result < 0)
100
                return result;
101
 
102
        return (int) rdata / 31;
103
}
104
 
105
static int get_auto_brightness(void)
106
{
107
        u8 wdata = 4, rdata;
108
        int result;
109
 
110
        result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1, 1);
111
        if (result < 0)
112
                return result;
113
 
114
        return !!(rdata & 8);
115
}
116
 
117
static int set_auto_brightness(int enable)
118
{
119
        u8 wdata[2], rdata;
120
        int result;
121
 
122
        wdata[0] = 4;
123
 
124
        result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 1, &rdata, 1, 1);
125
        if (result < 0)
126
                return result;
127
 
128
        wdata[0] = 0x84;
129
        wdata[1] = (rdata & 0xF7) | (enable ? 8 : 0);
130
 
131
        return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2, NULL, 0, 1);
132
}
133
 
134
static int get_wireless_state(int *wlan, int *bluetooth)
135
{
136
        u8 wdata = 0, rdata;
137
        int result;
138
 
139
        result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1, 1);
140
        if (result < 0)
141
                return -1;
142
 
143
        if (wlan)
144
                *wlan = !!(rdata & 8);
145
 
146
        if (bluetooth)
147
                *bluetooth = !!(rdata & 128);
148
 
149
        return 0;
150
}
151
 
152
/* Backlight device stuff */
153
 
154
static int bl_get_brightness(struct backlight_device *b)
155
{
156
        return get_lcd_level();
157
}
158
 
159
 
160
static int bl_update_status(struct backlight_device *b)
161
{
162
        return set_lcd_level(b->props.brightness);
163
}
164
 
165
static struct backlight_ops msibl_ops = {
166
        .get_brightness = bl_get_brightness,
167
        .update_status  = bl_update_status,
168
};
169
 
170
static struct backlight_device *msibl_device;
171
 
172
/* Platform device */
173
 
174
static ssize_t show_wlan(struct device *dev,
175
        struct device_attribute *attr, char *buf)
176
{
177
 
178
        int ret, enabled;
179
 
180
        ret = get_wireless_state(&enabled, NULL);
181
        if (ret < 0)
182
                return ret;
183
 
184
        return sprintf(buf, "%i\n", enabled);
185
}
186
 
187
static ssize_t show_bluetooth(struct device *dev,
188
        struct device_attribute *attr, char *buf)
189
{
190
 
191
        int ret, enabled;
192
 
193
        ret = get_wireless_state(NULL, &enabled);
194
        if (ret < 0)
195
                return ret;
196
 
197
        return sprintf(buf, "%i\n", enabled);
198
}
199
 
200
static ssize_t show_lcd_level(struct device *dev,
201
        struct device_attribute *attr, char *buf)
202
{
203
 
204
        int ret;
205
 
206
        ret = get_lcd_level();
207
        if (ret < 0)
208
                return ret;
209
 
210
        return sprintf(buf, "%i\n", ret);
211
}
212
 
213
static ssize_t store_lcd_level(struct device *dev,
214
        struct device_attribute *attr, const char *buf, size_t count)
215
{
216
 
217
        int level, ret;
218
 
219
        if (sscanf(buf, "%i", &level) != 1 || (level < 0 || level >= MSI_LCD_LEVEL_MAX))
220
                return -EINVAL;
221
 
222
        ret = set_lcd_level(level);
223
        if (ret < 0)
224
                return ret;
225
 
226
        return count;
227
}
228
 
229
static ssize_t show_auto_brightness(struct device *dev,
230
        struct device_attribute *attr, char *buf)
231
{
232
 
233
        int ret;
234
 
235
        ret = get_auto_brightness();
236
        if (ret < 0)
237
                return ret;
238
 
239
        return sprintf(buf, "%i\n", ret);
240
}
241
 
242
static ssize_t store_auto_brightness(struct device *dev,
243
        struct device_attribute *attr, const char *buf, size_t count)
244
{
245
 
246
        int enable, ret;
247
 
248
        if (sscanf(buf, "%i", &enable) != 1 || (enable != (enable & 1)))
249
                return -EINVAL;
250
 
251
        ret = set_auto_brightness(enable);
252
        if (ret < 0)
253
                return ret;
254
 
255
        return count;
256
}
257
 
258
static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level);
259
static DEVICE_ATTR(auto_brightness, 0644, show_auto_brightness, store_auto_brightness);
260
static DEVICE_ATTR(bluetooth, 0444, show_bluetooth, NULL);
261
static DEVICE_ATTR(wlan, 0444, show_wlan, NULL);
262
 
263
static struct attribute *msipf_attributes[] = {
264
        &dev_attr_lcd_level.attr,
265
        &dev_attr_auto_brightness.attr,
266
        &dev_attr_bluetooth.attr,
267
        &dev_attr_wlan.attr,
268
        NULL
269
};
270
 
271
static struct attribute_group msipf_attribute_group = {
272
        .attrs = msipf_attributes
273
};
274
 
275
static struct platform_driver msipf_driver = {
276
        .driver = {
277
                .name = "msi-laptop-pf",
278
                .owner = THIS_MODULE,
279
        }
280
};
281
 
282
static struct platform_device *msipf_device;
283
 
284
/* Initialization */
285
 
286
static int dmi_check_cb(const struct dmi_system_id *id)
287
{
288
        printk("msi-laptop: Identified laptop model '%s'.\n", id->ident);
289
        return 0;
290
}
291
 
292
static struct dmi_system_id __initdata msi_dmi_table[] = {
293
        {
294
                .ident = "MSI S270",
295
                .matches = {
296
                        DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD"),
297
                        DMI_MATCH(DMI_PRODUCT_NAME, "MS-1013"),
298
                        DMI_MATCH(DMI_PRODUCT_VERSION, "0131"),
299
                        DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR INT'L CO.,LTD")
300
                },
301
                .callback = dmi_check_cb
302
        },
303
        {
304
                .ident = "MSI S271",
305
                .matches = {
306
                        DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
307
                        DMI_MATCH(DMI_PRODUCT_NAME, "MS-1058"),
308
                        DMI_MATCH(DMI_PRODUCT_VERSION, "0581"),
309
                        DMI_MATCH(DMI_BOARD_NAME, "MS-1058")
310
                },
311
                .callback = dmi_check_cb
312
        },
313
        {
314
                .ident = "MSI S420",
315
                .matches = {
316
                        DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
317
                        DMI_MATCH(DMI_PRODUCT_NAME, "MS-1412"),
318
                        DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
319
                        DMI_MATCH(DMI_BOARD_NAME, "MS-1412")
320
                },
321
                .callback = dmi_check_cb
322
        },
323
        {
324
                .ident = "Medion MD96100",
325
                .matches = {
326
                        DMI_MATCH(DMI_SYS_VENDOR, "NOTEBOOK"),
327
                        DMI_MATCH(DMI_PRODUCT_NAME, "SAM2000"),
328
                        DMI_MATCH(DMI_PRODUCT_VERSION, "0131"),
329
                        DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR INT'L CO.,LTD")
330
                },
331
                .callback = dmi_check_cb
332
        },
333
        { }
334
};
335
 
336
static int __init msi_init(void)
337
{
338
        int ret;
339
 
340
        if (acpi_disabled)
341
                return -ENODEV;
342
 
343
        if (!force && !dmi_check_system(msi_dmi_table))
344
                return -ENODEV;
345
 
346
        if (auto_brightness < 0 || auto_brightness > 2)
347
                return -EINVAL;
348
 
349
        /* Register backlight stuff */
350
 
351
        msibl_device = backlight_device_register("msi-laptop-bl", NULL, NULL,
352
                                                &msibl_ops);
353
        if (IS_ERR(msibl_device))
354
                return PTR_ERR(msibl_device);
355
 
356
        msibl_device->props.max_brightness = MSI_LCD_LEVEL_MAX-1;
357
 
358
        ret = platform_driver_register(&msipf_driver);
359
        if (ret)
360
                goto fail_backlight;
361
 
362
        /* Register platform stuff */
363
 
364
        msipf_device = platform_device_alloc("msi-laptop-pf", -1);
365
        if (!msipf_device) {
366
                ret = -ENOMEM;
367
                goto fail_platform_driver;
368
        }
369
 
370
        ret = platform_device_add(msipf_device);
371
        if (ret)
372
                goto fail_platform_device1;
373
 
374
        ret = sysfs_create_group(&msipf_device->dev.kobj, &msipf_attribute_group);
375
        if (ret)
376
                goto fail_platform_device2;
377
 
378
        /* Disable automatic brightness control by default because
379
         * this module was probably loaded to do brightness control in
380
         * software. */
381
 
382
        if (auto_brightness != 2)
383
                set_auto_brightness(auto_brightness);
384
 
385
        printk(KERN_INFO "msi-laptop: driver "MSI_DRIVER_VERSION" successfully loaded.\n");
386
 
387
        return 0;
388
 
389
fail_platform_device2:
390
 
391
        platform_device_del(msipf_device);
392
 
393
fail_platform_device1:
394
 
395
        platform_device_put(msipf_device);
396
 
397
fail_platform_driver:
398
 
399
        platform_driver_unregister(&msipf_driver);
400
 
401
fail_backlight:
402
 
403
        backlight_device_unregister(msibl_device);
404
 
405
        return ret;
406
}
407
 
408
static void __exit msi_cleanup(void)
409
{
410
 
411
        sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group);
412
        platform_device_unregister(msipf_device);
413
        platform_driver_unregister(&msipf_driver);
414
        backlight_device_unregister(msibl_device);
415
 
416
        /* Enable automatic brightness control again */
417
        if (auto_brightness != 2)
418
                set_auto_brightness(1);
419
 
420
        printk(KERN_INFO "msi-laptop: driver unloaded.\n");
421
}
422
 
423
module_init(msi_init);
424
module_exit(msi_cleanup);
425
 
426
MODULE_AUTHOR("Lennart Poettering");
427
MODULE_DESCRIPTION("MSI Laptop Support");
428
MODULE_VERSION(MSI_DRIVER_VERSION);
429
MODULE_LICENSE("GPL");
430
 
431
MODULE_ALIAS("dmi:*:svnMICRO-STARINT'LCO.,LTD:pnMS-1013:pvr0131*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");
432
MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1058:pvr0581:rvnMSI:rnMS-1058:*:ct10:*");
433
MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1412:*:rvnMSI:rnMS-1412:*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");
434
MODULE_ALIAS("dmi:*:svnNOTEBOOK:pnSAM2000:pvr0131*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.