#include <acpi/acpi_bus.h>
#include <asm/uaccess.h>
#include <linux/sonypi.h>
-#ifdef CONFIG_SONY_LAPTOP_OLD
+#include <linux/sony-laptop.h>
+#ifdef CONFIG_SONYPI_COMPAT
#include <linux/poll.h>
#include <linux/miscdevice.h>
#endif
"set this to 1 to enable Motion Eye camera controls "
"(only use it if you have a C1VE or C1VN model)");
-#ifdef CONFIG_SONY_LAPTOP_OLD
+#ifdef CONFIG_SONYPI_COMPAT
static int minor = -1;
module_param(minor, int, 0);
MODULE_PARM_DESC(minor,
int model;
u8 camera_power;
u8 bluetooth_power;
+ u8 wwan_power;
struct acpi_device *acpi_dev;
struct sony_pic_irq *cur_irq;
struct sony_pic_ioport *cur_ioport;
struct list_head interrupts;
struct list_head ioports;
+ struct mutex lock;
};
static struct sony_pic_dev spic_dev = {
/* camera tests and poweron/poweroff */
#define SONYPI_CAMERA_PICTURE 5
-#define SONYPI_CAMERA_MUTE_MASK 0x40
#define SONYPI_CAMERA_CONTROL 0x10
-#define SONYPI_CAMERA_STATUS 7
-#define SONYPI_CAMERA_STATUS_READY 0x2
-#define SONYPI_CAMERA_STATUS_POSITION 0x4
-static int sony_pic_camera_ready(void)
+#define SONYPI_CAMERA_BRIGHTNESS 0
+#define SONYPI_CAMERA_CONTRAST 1
+#define SONYPI_CAMERA_HUE 2
+#define SONYPI_CAMERA_COLOR 3
+#define SONYPI_CAMERA_SHARPNESS 4
+
+#define SONYPI_CAMERA_EXPOSURE_MASK 0xC
+#define SONYPI_CAMERA_WHITE_BALANCE_MASK 0x3
+#define SONYPI_CAMERA_PICTURE_MODE_MASK 0x30
+#define SONYPI_CAMERA_MUTE_MASK 0x40
+
+/* the rest don't need a loop until not 0xff */
+#define SONYPI_CAMERA_AGC 6
+#define SONYPI_CAMERA_AGC_MASK 0x30
+#define SONYPI_CAMERA_SHUTTER_MASK 0x7
+
+#define SONYPI_CAMERA_SHUTDOWN_REQUEST 7
+#define SONYPI_CAMERA_CONTROL 0x10
+
+#define SONYPI_CAMERA_STATUS 7
+#define SONYPI_CAMERA_STATUS_READY 0x2
+#define SONYPI_CAMERA_STATUS_POSITION 0x4
+
+#define SONYPI_DIRECTION_BACKWARDS 0x4
+
+#define SONYPI_CAMERA_REVISION 8
+#define SONYPI_CAMERA_ROMVERSION 9
+
+static int __sony_pic_camera_ready(void)
{
u8 v;
return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY));
}
-static int sony_pic_camera_off(void)
+static int __sony_pic_camera_off(void)
{
if (!camera) {
printk(KERN_WARNING DRV_PFX "camera control not enabled\n");
return 0;
}
-static int sony_pic_camera_on(void)
+static int __sony_pic_camera_on(void)
{
int i, j, x;
sony_pic_call1(0x93);
for (i = 400; i > 0; i--) {
- if (sony_pic_camera_ready())
+ if (__sony_pic_camera_ready())
break;
msleep(10);
}
return 0;
}
-static ssize_t sony_pic_camerapower_store(struct device *dev,
+/* External camera command (exported to the motion eye v4l driver) */
+int sony_pic_camera_command(int command, u8 value)
+{
+ if (!camera)
+ return -EIO;
+
+ mutex_lock(&spic_dev.lock);
+
+ switch (command) {
+ case SONY_PIC_COMMAND_SETCAMERA:
+ if (value)
+ __sony_pic_camera_on();
+ else
+ __sony_pic_camera_off();
+ break;
+ case SONY_PIC_COMMAND_SETCAMERABRIGHTNESS:
+ wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_BRIGHTNESS, value),
+ ITERATIONS_SHORT);
+ break;
+ case SONY_PIC_COMMAND_SETCAMERACONTRAST:
+ wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTRAST, value),
+ ITERATIONS_SHORT);
+ break;
+ case SONY_PIC_COMMAND_SETCAMERAHUE:
+ wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_HUE, value),
+ ITERATIONS_SHORT);
+ break;
+ case SONY_PIC_COMMAND_SETCAMERACOLOR:
+ wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_COLOR, value),
+ ITERATIONS_SHORT);
+ break;
+ case SONY_PIC_COMMAND_SETCAMERASHARPNESS:
+ wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_SHARPNESS, value),
+ ITERATIONS_SHORT);
+ break;
+ case SONY_PIC_COMMAND_SETCAMERAPICTURE:
+ wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE, value),
+ ITERATIONS_SHORT);
+ break;
+ case SONY_PIC_COMMAND_SETCAMERAAGC:
+ wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_AGC, value),
+ ITERATIONS_SHORT);
+ break;
+ default:
+ printk(KERN_ERR DRV_PFX "sony_pic_camera_command invalid: %d\n",
+ command);
+ break;
+ }
+ mutex_unlock(&spic_dev.lock);
+ return 0;
+}
+EXPORT_SYMBOL(sony_pic_camera_command);
+
+/* gprs/edge modem (SZ460N and SZ210P), thanks to Joshua Wise */
+static void sony_pic_set_wwanpower(u8 state)
+{
+ state = !!state;
+ mutex_lock(&spic_dev.lock);
+ if (spic_dev.wwan_power == state) {
+ mutex_unlock(&spic_dev.lock);
+ return;
+ }
+ sony_pic_call2(0xB0, state);
+ spic_dev.wwan_power = state;
+ mutex_unlock(&spic_dev.lock);
+}
+
+static ssize_t sony_pic_wwanpower_store(struct device *dev,
struct device_attribute *attr,
const char *buffer, size_t count)
{
unsigned long value;
- int result;
if (count > 31)
return -EINVAL;
value = simple_strtoul(buffer, NULL, 10);
- if (value)
- result = sony_pic_camera_on();
- else
- result = sony_pic_camera_off();
-
- if (result)
- return result;
+ sony_pic_set_wwanpower(value);
return count;
}
-static ssize_t sony_pic_camerapower_show(struct device *dev,
+static ssize_t sony_pic_wwanpower_show(struct device *dev,
struct device_attribute *attr, char *buffer)
{
- return snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.camera_power);
+ ssize_t count;
+ mutex_lock(&spic_dev.lock);
+ count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.wwan_power);
+ mutex_unlock(&spic_dev.lock);
+ return count;
}
/* bluetooth subsystem power state */
-static void sony_pic_set_bluetoothpower(u8 state)
+static void __sony_pic_set_bluetoothpower(u8 state)
{
state = !!state;
if (spic_dev.bluetooth_power == state)
return -EINVAL;
value = simple_strtoul(buffer, NULL, 10);
- sony_pic_set_bluetoothpower(value);
+ mutex_lock(&spic_dev.lock);
+ __sony_pic_set_bluetoothpower(value);
+ mutex_unlock(&spic_dev.lock);
return count;
}
static ssize_t sony_pic_bluetoothpower_show(struct device *dev,
struct device_attribute *attr, char *buffer)
{
- return snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.bluetooth_power);
+ ssize_t count = 0;
+ mutex_lock(&spic_dev.lock);
+ count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.bluetooth_power);
+ mutex_unlock(&spic_dev.lock);
+ return count;
}
/* fan speed */
_mode, sony_pic_## _name ##_show, \
sony_pic_## _name ##_store)
-static SPIC_ATTR(camerapower, 0644);
static SPIC_ATTR(bluetoothpower, 0644);
+static SPIC_ATTR(wwanpower, 0644);
static SPIC_ATTR(fanspeed, 0644);
static struct attribute *spic_attributes[] = {
- &spic_attr_camerapower.attr,
&spic_attr_bluetoothpower.attr,
+ &spic_attr_wwanpower.attr,
&spic_attr_fanspeed.attr,
NULL
};
};
/******** SONYPI compatibility **********/
-#ifdef CONFIG_SONY_LAPTOP_OLD
+#ifdef CONFIG_SONYPI_COMPAT
/* battery / brightness / temperature addresses */
#define SONYPI_BAT_FLAGS 0x81
u16 val16;
int value;
- /*down(&sonypi_device.lock);*/
+ mutex_lock(&spic_dev.lock);
switch (cmd) {
case SONYPI_IOCGBRT:
if (sony_backlight_device == NULL) {
ret = -EFAULT;
break;
}
- sony_pic_set_bluetoothpower(val8);
+ __sony_pic_set_bluetoothpower(val8);
break;
/* FAN Controls */
case SONYPI_IOCGFAN:
default:
ret = -EINVAL;
}
- /*up(&sonypi_device.lock);*/
+ mutex_unlock(&spic_dev.lock);
return ret;
}
}
init_waitqueue_head(&sonypi_compat.fifo_proc_list);
- /*init_MUTEX(&sonypi_device.lock);*/
if (minor != -1)
sonypi_misc_device.minor = minor;
static int sonypi_compat_init(void) { return 0; }
static void sonypi_compat_exit(void) { }
static void sonypi_compat_report_event(u8 event) { }
-#endif /* CONFIG_SONY_LAPTOP_OLD */
+#endif /* CONFIG_SONYPI_COMPAT */
/*
* ACPI callbacks
if (!interrupt)
return AE_ERROR;
- list_add(&interrupt->list, &dev->interrupts);
+ list_add_tail(&interrupt->list, &dev->interrupts);
interrupt->irq.triggering = p->triggering;
interrupt->irq.polarity = p->polarity;
interrupt->irq.sharable = p->sharable;
if (!ioport)
return AE_ERROR;
- list_add(&ioport->list, &dev->ioports);
+ list_add_tail(&ioport->list, &dev->ioports);
memcpy(&ioport->io, io, sizeof(*io));
return AE_OK;
}
spic_dev.acpi_dev = device;
strcpy(acpi_device_class(device), "sony/hotkey");
spic_dev.model = sony_pic_detect_device_type();
+ mutex_init(&spic_dev.lock);
/* read _PRS resources */
result = sony_pic_possible_resources(device);