2008-06-09 16:22:22 -07:00
/*-*-linux-c-*-*/
/*
Copyright ( C ) 2008 Cezary Jackiewicz < cezary . jackiewicz ( at ) gmail . com >
based on MSI driver
Copyright ( C ) 2006 Lennart Poettering < mzxreary ( at ) 0 pointer ( dot ) de >
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful , but
WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA
02110 - 1301 , USA .
*/
/*
* comapl - laptop . c - Compal laptop support .
*
2009-08-25 10:30:13 -05:00
* The driver registers itself with the rfkill subsystem and
* the Linux backlight control subsystem .
2008-06-09 16:22:22 -07:00
*
* This driver might work on other laptops produced by Compal . If you
* want to try it you can pass force = 1 as argument to the module which
* will force it to load even when the DMI data doesn ' t identify the
2008-06-12 22:08:59 +02:00
* laptop as FL9x .
2008-06-09 16:22:22 -07:00
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/acpi.h>
# include <linux/dmi.h>
# include <linux/backlight.h>
# include <linux/platform_device.h>
2009-08-25 10:30:13 -05:00
# include <linux/rfkill.h>
2008-06-09 16:22:22 -07:00
2008-06-12 22:08:59 +02:00
# define COMPAL_DRIVER_VERSION "0.2.6"
2008-06-09 16:22:22 -07:00
# define COMPAL_LCD_LEVEL_MAX 8
# define COMPAL_EC_COMMAND_WIRELESS 0xBB
# define COMPAL_EC_COMMAND_LCD_LEVEL 0xB9
# define KILLSWITCH_MASK 0x10
# define WLAN_MASK 0x01
# define BT_MASK 0x02
2009-08-25 10:30:13 -05:00
static struct rfkill * wifi_rfkill ;
static struct rfkill * bt_rfkill ;
static struct platform_device * compal_device ;
2008-06-09 16:22:22 -07:00
static int force ;
module_param ( force , bool , 0 ) ;
MODULE_PARM_DESC ( force , " Force driver load, ignore DMI data " ) ;
/* Hardware access */
static int set_lcd_level ( int level )
{
if ( level < 0 | | level > = COMPAL_LCD_LEVEL_MAX )
return - EINVAL ;
ec_write ( COMPAL_EC_COMMAND_LCD_LEVEL , level ) ;
return 0 ;
}
static int get_lcd_level ( void )
{
u8 result ;
ec_read ( COMPAL_EC_COMMAND_LCD_LEVEL , & result ) ;
return ( int ) result ;
}
2009-08-25 10:30:13 -05:00
static int compal_rfkill_set ( void * data , bool blocked )
2008-06-09 16:22:22 -07:00
{
2009-08-25 10:30:13 -05:00
unsigned long radio = ( unsigned long ) data ;
2008-06-09 16:22:22 -07:00
u8 result , value ;
ec_read ( COMPAL_EC_COMMAND_WIRELESS , & result ) ;
2009-08-25 10:30:13 -05:00
if ( ! blocked )
value = ( u8 ) ( result | radio ) ;
else
value = ( u8 ) ( result & ~ radio ) ;
ec_write ( COMPAL_EC_COMMAND_WIRELESS , value ) ;
2008-06-09 16:22:22 -07:00
return 0 ;
}
2009-08-25 10:30:13 -05:00
static void compal_rfkill_poll ( struct rfkill * rfkill , void * data )
2008-06-09 16:22:22 -07:00
{
2009-08-25 10:30:13 -05:00
u8 result ;
bool hw_blocked ;
2008-06-09 16:22:22 -07:00
ec_read ( COMPAL_EC_COMMAND_WIRELESS , & result ) ;
2009-08-25 10:30:13 -05:00
hw_blocked = ! ( result & KILLSWITCH_MASK ) ;
rfkill_set_hw_state ( rfkill , hw_blocked ) ;
2008-06-09 16:22:22 -07:00
}
2009-08-25 10:30:13 -05:00
static const struct rfkill_ops compal_rfkill_ops = {
. poll = compal_rfkill_poll ,
. set_block = compal_rfkill_set ,
} ;
static int setup_rfkill ( void )
2008-06-09 16:22:22 -07:00
{
2009-08-25 10:30:13 -05:00
int ret ;
2008-06-09 16:22:22 -07:00
2009-08-25 10:30:13 -05:00
wifi_rfkill = rfkill_alloc ( " compal-wifi " , & compal_device - > dev ,
RFKILL_TYPE_WLAN , & compal_rfkill_ops ,
( void * ) WLAN_MASK ) ;
if ( ! wifi_rfkill )
return - ENOMEM ;
2008-06-09 16:22:22 -07:00
2009-08-25 10:30:13 -05:00
ret = rfkill_register ( wifi_rfkill ) ;
if ( ret )
goto err_wifi ;
2008-06-09 16:22:22 -07:00
2009-08-25 10:30:13 -05:00
bt_rfkill = rfkill_alloc ( " compal-bluetooth " , & compal_device - > dev ,
RFKILL_TYPE_BLUETOOTH , & compal_rfkill_ops ,
( void * ) BT_MASK ) ;
if ( ! bt_rfkill ) {
ret = - ENOMEM ;
goto err_allocate_bt ;
2008-06-09 16:22:22 -07:00
}
2009-08-25 10:30:13 -05:00
ret = rfkill_register ( bt_rfkill ) ;
if ( ret )
goto err_register_bt ;
2008-06-09 16:22:22 -07:00
return 0 ;
2009-08-25 10:30:13 -05:00
err_register_bt :
rfkill_destroy ( bt_rfkill ) ;
err_allocate_bt :
rfkill_unregister ( wifi_rfkill ) ;
err_wifi :
rfkill_destroy ( wifi_rfkill ) ;
return ret ;
2008-06-09 16:22:22 -07:00
}
/* Backlight device stuff */
static int bl_get_brightness ( struct backlight_device * b )
{
return get_lcd_level ( ) ;
}
static int bl_update_status ( struct backlight_device * b )
{
return set_lcd_level ( b - > props . brightness ) ;
}
static struct backlight_ops compalbl_ops = {
. get_brightness = bl_get_brightness ,
. update_status = bl_update_status ,
} ;
static struct backlight_device * compalbl_device ;
static struct platform_driver compal_driver = {
. driver = {
. name = " compal-laptop " ,
. owner = THIS_MODULE ,
}
} ;
/* Initialization */
static int dmi_check_cb ( const struct dmi_system_id * id )
{
printk ( KERN_INFO " compal-laptop: Identified laptop model '%s'. \n " ,
id - > ident ) ;
return 0 ;
}
static struct dmi_system_id __initdata compal_dmi_table [ ] = {
{
. ident = " FL90/IFL90 " ,
. matches = {
DMI_MATCH ( DMI_BOARD_NAME , " IFL90 " ) ,
DMI_MATCH ( DMI_BOARD_VERSION , " IFT00 " ) ,
} ,
. callback = dmi_check_cb
} ,
{
. ident = " FL90/IFL90 " ,
. matches = {
DMI_MATCH ( DMI_BOARD_NAME , " IFL90 " ) ,
DMI_MATCH ( DMI_BOARD_VERSION , " REFERENCE " ) ,
} ,
. callback = dmi_check_cb
} ,
{
. ident = " FL91/IFL91 " ,
. matches = {
DMI_MATCH ( DMI_BOARD_NAME , " IFL91 " ) ,
DMI_MATCH ( DMI_BOARD_VERSION , " IFT00 " ) ,
} ,
. callback = dmi_check_cb
} ,
{
. ident = " FL92/JFL92 " ,
. matches = {
DMI_MATCH ( DMI_BOARD_NAME , " JFL92 " ) ,
DMI_MATCH ( DMI_BOARD_VERSION , " IFT00 " ) ,
} ,
. callback = dmi_check_cb
} ,
{
. ident = " FT00/IFT00 " ,
. matches = {
DMI_MATCH ( DMI_BOARD_NAME , " IFT00 " ) ,
DMI_MATCH ( DMI_BOARD_VERSION , " IFT00 " ) ,
} ,
. callback = dmi_check_cb
} ,
2009-08-24 16:00:47 -05:00
{
. ident = " Dell Mini 9 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Dell Inc. " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " Inspiron 910 " ) ,
} ,
. callback = dmi_check_cb
} ,
{
. ident = " Dell Mini 10 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Dell Inc. " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " Inspiron 1010 " ) ,
} ,
. callback = dmi_check_cb
} ,
{
. ident = " Dell Mini 10v " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Dell Inc. " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " Inspiron 1011 " ) ,
} ,
. callback = dmi_check_cb
} ,
{
. ident = " Dell Inspiron 11z " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Dell Inc. " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " Inspiron 1110 " ) ,
} ,
. callback = dmi_check_cb
} ,
{
. ident = " Dell Mini 12 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Dell Inc. " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " Inspiron 1210 " ) ,
} ,
. callback = dmi_check_cb
} ,
2008-06-09 16:22:22 -07:00
{ }
} ;
static int __init compal_init ( void )
{
int ret ;
if ( acpi_disabled )
return - ENODEV ;
if ( ! force & & ! dmi_check_system ( compal_dmi_table ) )
return - ENODEV ;
/* Register backlight stuff */
2008-08-01 17:37:58 +02:00
if ( ! acpi_video_backlight_support ( ) ) {
2010-02-17 16:39:44 -05:00
struct backlight_properties props ;
memset ( & props , 0 , sizeof ( struct backlight_properties ) ) ;
props . max_brightness = COMPAL_LCD_LEVEL_MAX - 1 ;
compalbl_device = backlight_device_register ( " compal-laptop " ,
NULL , NULL ,
& compalbl_ops ,
& props ) ;
2008-08-01 17:37:58 +02:00
if ( IS_ERR ( compalbl_device ) )
return PTR_ERR ( compalbl_device ) ;
}
2008-06-09 16:22:22 -07:00
ret = platform_driver_register ( & compal_driver ) ;
if ( ret )
goto fail_backlight ;
/* Register platform stuff */
compal_device = platform_device_alloc ( " compal-laptop " , - 1 ) ;
if ( ! compal_device ) {
ret = - ENOMEM ;
goto fail_platform_driver ;
}
ret = platform_device_add ( compal_device ) ;
if ( ret )
2009-08-25 10:30:13 -05:00
goto fail_platform_device ;
2008-06-09 16:22:22 -07:00
2009-08-25 10:30:13 -05:00
ret = setup_rfkill ( ) ;
2008-06-09 16:22:22 -07:00
if ( ret )
2009-08-25 10:30:13 -05:00
goto fail_rfkill ;
2008-06-09 16:22:22 -07:00
printk ( KERN_INFO " compal-laptop: driver " COMPAL_DRIVER_VERSION
" successfully loaded. \n " ) ;
return 0 ;
2009-08-25 10:30:13 -05:00
fail_rfkill :
2008-06-09 16:22:22 -07:00
platform_device_del ( compal_device ) ;
2009-08-25 10:30:13 -05:00
fail_platform_device :
2008-06-09 16:22:22 -07:00
platform_device_put ( compal_device ) ;
fail_platform_driver :
platform_driver_unregister ( & compal_driver ) ;
fail_backlight :
backlight_device_unregister ( compalbl_device ) ;
return ret ;
}
static void __exit compal_cleanup ( void )
{
platform_device_unregister ( compal_device ) ;
platform_driver_unregister ( & compal_driver ) ;
backlight_device_unregister ( compalbl_device ) ;
2009-08-25 10:30:13 -05:00
rfkill_unregister ( wifi_rfkill ) ;
rfkill_destroy ( wifi_rfkill ) ;
rfkill_unregister ( bt_rfkill ) ;
rfkill_destroy ( bt_rfkill ) ;
2008-06-09 16:22:22 -07:00
printk ( KERN_INFO " compal-laptop: driver unloaded. \n " ) ;
}
module_init ( compal_init ) ;
module_exit ( compal_cleanup ) ;
MODULE_AUTHOR ( " Cezary Jackiewicz " ) ;
MODULE_DESCRIPTION ( " Compal Laptop Support " ) ;
MODULE_VERSION ( COMPAL_DRIVER_VERSION ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " dmi:*:rnIFL90:rvrIFT00:* " ) ;
MODULE_ALIAS ( " dmi:*:rnIFL90:rvrREFERENCE:* " ) ;
MODULE_ALIAS ( " dmi:*:rnIFL91:rvrIFT00:* " ) ;
MODULE_ALIAS ( " dmi:*:rnJFL92:rvrIFT00:* " ) ;
MODULE_ALIAS ( " dmi:*:rnIFT00:rvrIFT00:* " ) ;
2009-08-24 16:00:47 -05:00
MODULE_ALIAS ( " dmi:*:svnDellInc.:pnInspiron910:* " ) ;
MODULE_ALIAS ( " dmi:*:svnDellInc.:pnInspiron1010:* " ) ;
MODULE_ALIAS ( " dmi:*:svnDellInc.:pnInspiron1011:* " ) ;
MODULE_ALIAS ( " dmi:*:svnDellInc.:pnInspiron1110:* " ) ;
MODULE_ALIAS ( " dmi:*:svnDellInc.:pnInspiron1210:* " ) ;