Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 141942
b: refs/heads/master
c: 6cc056b
h: refs/heads/master
v: v3
  • Loading branch information
Matthew Garrett authored and Len Brown committed Mar 27, 2009
1 parent 1d7fff1 commit caab66a
Show file tree
Hide file tree
Showing 2 changed files with 187 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 9b57896e62bfa752ee7435e6cfe57fb210c0db8c
refs/heads/master: 6cc056bc31ea9910afb01adc0848bb6ae68e0205
186 changes: 186 additions & 0 deletions trunk/drivers/platform/x86/sony-laptop.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
#include <asm/uaccess.h>
#include <linux/sonypi.h>
#include <linux/sony-laptop.h>
#include <linux/rfkill.h>
#ifdef CONFIG_SONYPI_COMPAT
#include <linux/poll.h>
#include <linux/miscdevice.h>
Expand Down Expand Up @@ -123,6 +124,18 @@ MODULE_PARM_DESC(minor,
"default is -1 (automatic)");
#endif

enum sony_nc_rfkill {
SONY_WIFI,
SONY_BLUETOOTH,
SONY_WWAN,
SONY_WIMAX,
SONY_RFKILL_MAX,
};

static struct rfkill *sony_rfkill_devices[SONY_RFKILL_MAX];
static int sony_rfkill_address[SONY_RFKILL_MAX] = {0x300, 0x500, 0x700, 0x900};
static void sony_nc_rfkill_update(void);

/*********** Input Devices ***********/

#define SONY_LAPTOP_BUF_SIZE 128
Expand All @@ -134,6 +147,7 @@ struct sony_laptop_input_s {
spinlock_t fifo_lock;
struct workqueue_struct *wq;
};

static struct sony_laptop_input_s sony_laptop_input = {
.users = ATOMIC_INIT(0),
};
Expand Down Expand Up @@ -891,6 +905,9 @@ static void sony_acpi_notify(acpi_handle handle, u32 event, void *data)
if (!sony_nc_events[i].data)
printk(KERN_INFO DRV_PFX
"Unknown event: %x %x\n", origev, ev);
} else if (sony_find_snc_handle(0x124) == ev) {
sony_nc_rfkill_update();
return;
}
}

Expand Down Expand Up @@ -973,6 +990,172 @@ static int sony_nc_resume(struct acpi_device *device)
return 0;
}

static void sony_nc_rfkill_cleanup(void)
{
int i;

for (i = 0; i < SONY_RFKILL_MAX; i++) {
if (sony_rfkill_devices[i])
rfkill_unregister(sony_rfkill_devices[i]);
}
}

static int sony_nc_rfkill_get(void *data, enum rfkill_state *state)
{
int result;
int argument = sony_rfkill_address[(long) data];

sony_call_snc_handle(0x124, 0x200, &result);
if (result & 0x1) {
sony_call_snc_handle(0x124, argument, &result);
if (result & 0xf)
*state = RFKILL_STATE_UNBLOCKED;
else
*state = RFKILL_STATE_SOFT_BLOCKED;
} else {
*state = RFKILL_STATE_HARD_BLOCKED;
}

return 0;
}

static int sony_nc_rfkill_set(void *data, enum rfkill_state state)
{
int result;
int argument = sony_rfkill_address[(long) data] + 0x100;

if (state == RFKILL_STATE_UNBLOCKED)
argument |= 0xff0000;

return sony_call_snc_handle(0x124, argument, &result);
}

static int sony_nc_setup_wifi_rfkill(struct acpi_device *device)
{
int err = 0;
struct rfkill *sony_wifi_rfkill;

sony_wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN);
if (!sony_wifi_rfkill)
return -1;
sony_wifi_rfkill->name = "sony-wifi";
sony_wifi_rfkill->toggle_radio = sony_nc_rfkill_set;
sony_wifi_rfkill->get_state = sony_nc_rfkill_get;
sony_wifi_rfkill->user_claim_unsupported = 1;
sony_wifi_rfkill->data = (void *)SONY_WIFI;
err = rfkill_register(sony_wifi_rfkill);
if (err)
rfkill_free(sony_wifi_rfkill);
else
sony_rfkill_devices[SONY_WIFI] = sony_wifi_rfkill;
return err;
}

static int sony_nc_setup_bluetooth_rfkill(struct acpi_device *device)
{
int err = 0;
struct rfkill *sony_bluetooth_rfkill;

sony_bluetooth_rfkill = rfkill_allocate(&device->dev,
RFKILL_TYPE_BLUETOOTH);
if (!sony_bluetooth_rfkill)
return -1;
sony_bluetooth_rfkill->name = "sony-bluetooth";
sony_bluetooth_rfkill->toggle_radio = sony_nc_rfkill_set;
sony_bluetooth_rfkill->get_state = sony_nc_rfkill_get;
sony_bluetooth_rfkill->user_claim_unsupported = 1;
sony_bluetooth_rfkill->data = (void *)SONY_BLUETOOTH;
err = rfkill_register(sony_bluetooth_rfkill);
if (err)
rfkill_free(sony_bluetooth_rfkill);
else
sony_rfkill_devices[SONY_BLUETOOTH] = sony_bluetooth_rfkill;
return err;
}

static int sony_nc_setup_wwan_rfkill(struct acpi_device *device)
{
int err = 0;
struct rfkill *sony_wwan_rfkill;

sony_wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN);
if (!sony_wwan_rfkill)
return -1;
sony_wwan_rfkill->name = "sony-wwan";
sony_wwan_rfkill->toggle_radio = sony_nc_rfkill_set;
sony_wwan_rfkill->get_state = sony_nc_rfkill_get;
sony_wwan_rfkill->user_claim_unsupported = 1;
sony_wwan_rfkill->data = (void *)SONY_WWAN;
err = rfkill_register(sony_wwan_rfkill);
if (err)
rfkill_free(sony_wwan_rfkill);
else
sony_rfkill_devices[SONY_WWAN] = sony_wwan_rfkill;
return err;
}

static int sony_nc_setup_wimax_rfkill(struct acpi_device *device)
{
int err = 0;
struct rfkill *sony_wimax_rfkill;

sony_wimax_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WIMAX);
if (!sony_wimax_rfkill)
return -1;
sony_wimax_rfkill->name = "sony-wimax";
sony_wimax_rfkill->toggle_radio = sony_nc_rfkill_set;
sony_wimax_rfkill->get_state = sony_nc_rfkill_get;
sony_wimax_rfkill->user_claim_unsupported = 1;
sony_wimax_rfkill->data = (void *)SONY_WIMAX;
err = rfkill_register(sony_wimax_rfkill);
if (err)
rfkill_free(sony_wimax_rfkill);
else
sony_rfkill_devices[SONY_WIMAX] = sony_wimax_rfkill;
return err;
}

static void sony_nc_rfkill_update()
{
int i;
enum rfkill_state state;

for (i = 0; i < SONY_RFKILL_MAX; i++) {
if (sony_rfkill_devices[i]) {
sony_rfkill_devices[i]->
get_state(sony_rfkill_devices[i]->data,
&state);
rfkill_force_state(sony_rfkill_devices[i], state);
}
}
}

static int sony_nc_rfkill_setup(struct acpi_device *device)
{
int result, ret;

if (sony_find_snc_handle(0x124) == -1)
return -1;

ret = sony_call_snc_handle(0x124, 0xb00, &result);
if (ret) {
printk(KERN_INFO DRV_PFX
"Unable to enumerate rfkill devices: %x\n", ret);
return ret;
}

if (result & 0x1)
sony_nc_setup_wifi_rfkill(device);
if (result & 0x2)
sony_nc_setup_bluetooth_rfkill(device);
if (result & 0x1c)
sony_nc_setup_wwan_rfkill(device);
if (result & 0x20)
sony_nc_setup_wimax_rfkill(device);

return 0;
}

static int sony_nc_add(struct acpi_device *device)
{
acpi_status status;
Expand Down Expand Up @@ -1026,6 +1209,7 @@ static int sony_nc_add(struct acpi_device *device)
&handle))) {
dprintk("Doing SNC setup\n");
sony_nc_function_setup(device);
sony_nc_rfkill_setup(device);
}

/* setup input devices and helper fifo */
Expand Down Expand Up @@ -1132,6 +1316,7 @@ static int sony_nc_add(struct acpi_device *device)
sony_laptop_remove_input();

outwalk:
sony_nc_rfkill_cleanup();
return result;
}

Expand All @@ -1157,6 +1342,7 @@ static int sony_nc_remove(struct acpi_device *device, int type)

sony_pf_remove();
sony_laptop_remove_input();
sony_nc_rfkill_cleanup();
dprintk(SONY_NC_DRIVER_NAME " removed.\n");

return 0;
Expand Down

0 comments on commit caab66a

Please sign in to comment.