/* am7xxx - communication with AM7xxx based USB Pico Projectors and DPFs
*
- * Copyright (C) 2012 Antonio Ospite <ospite@studenti.unina.it>
+ * Copyright (C) 2012-2014 Antonio Ospite <ao2@ao2.it>
*
* 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
#include "am7xxx.h"
#include "serialize.h"
+#include "tools.h"
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
};
static int default_set_power_mode(am7xxx_device *dev, am7xxx_power_mode power);
+static int picopix_set_power_mode(am7xxx_device *dev, am7xxx_power_mode power);
static int default_set_zoom_mode(am7xxx_device *dev, am7xxx_zoom_mode zoom);
+static int picopix_set_zoom_mode(am7xxx_device *dev, am7xxx_zoom_mode zoom);
#define DEFAULT_OPS { \
.set_power_mode = default_set_power_mode, \
.product_id = 0x0016,
.configuration = 2,
.interface_number = 0,
+ .ops = {
+ .set_power_mode = picopix_set_power_mode,
+ .set_zoom_mode = picopix_set_zoom_mode,
+ },
},
{
.name = "Philips/Sagemcom PicoPix 2330",
AM7XXX_PACKET_TYPE_IMAGE = 0x02,
AM7XXX_PACKET_TYPE_POWER = 0x04,
AM7XXX_PACKET_TYPE_ZOOM = 0x05,
+ AM7XXX_PACKET_TYPE_PICOPIX_POWER_LOW = 0x15,
+ AM7XXX_PACKET_TYPE_PICOPIX_POWER_MEDIUM = 0x16,
+ AM7XXX_PACKET_TYPE_PICOPIX_POWER_HIGH = 0x17,
+ AM7XXX_PACKET_TYPE_PICOPIX_ENABLE_TI = 0x18,
+ AM7XXX_PACKET_TYPE_PICOPIX_DISABLE_TI = 0x19,
} am7xxx_packet_type;
struct am7xxx_generic_header {
#ifdef DEBUG
+static void debug_dump_generic_header(am7xxx_context *ctx, struct am7xxx_generic_header *g)
+{
+ if (ctx == NULL || g == NULL)
+ return;
+
+ debug(ctx, "Generic header:\n");
+ debug(ctx, "\tfield0: 0x%08x (%u)\n", g->field0, g->field0);
+ debug(ctx, "\tfield1: 0x%08x (%u)\n", g->field1, g->field1);
+ debug(ctx, "\tfield2: 0x%08x (%u)\n", g->field2, g->field2);
+ debug(ctx, "\tfield3: 0x%08x (%u)\n", g->field3, g->field3);
+}
+
static void debug_dump_devinfo_header(am7xxx_context *ctx, struct am7xxx_devinfo_header *d)
{
if (ctx == NULL || d == NULL)
break;
default:
- debug(ctx, "Packet type not supported!\n");
+ debug(ctx, "Parsing data not supported for this packet type!\n");
+ debug_dump_generic_header(ctx, &(h->header_data.data));
break;
}
debug(ctx, "END\n\n");
return ret;
}
+static int send_command(am7xxx_device *dev, am7xxx_packet_type type)
+{
+ struct am7xxx_header h = {
+ .packet_type = type,
+ .direction = AM7XXX_DIRECTION_OUT,
+ .header_data_len = 0x00,
+ .unknown2 = 0x3e,
+ .unknown3 = 0x10,
+ .header_data = {
+ .data = {
+ .field0 = 0,
+ .field1 = 0,
+ .field2 = 0,
+ .field3 = 0,
+ },
+ },
+ };
+
+ return send_header(dev, &h);
+}
+
+
/* When level == AM7XXX_LOG_FATAL do not check the log_level from the context
* and print the message unconditionally, this makes it possible to print
* fatal messages even early on initialization, before the context has been
return 0;
}
+static int picopix_set_power_mode(am7xxx_device *dev, am7xxx_power_mode power)
+{
+ switch(power) {
+ case AM7XXX_POWER_LOW:
+ return send_command(dev, AM7XXX_PACKET_TYPE_PICOPIX_POWER_LOW);
+
+ case AM7XXX_POWER_MIDDLE:
+ return send_command(dev, AM7XXX_PACKET_TYPE_PICOPIX_POWER_MEDIUM);
+
+ case AM7XXX_POWER_HIGH:
+ return send_command(dev, AM7XXX_PACKET_TYPE_PICOPIX_POWER_HIGH);
+
+ case AM7XXX_POWER_OFF:
+ case AM7XXX_POWER_TURBO:
+ default:
+ error(dev->ctx, "Unsupported power mode.\n");
+ return -EINVAL;
+ };
+}
+
static int default_set_zoom_mode(am7xxx_device *dev, am7xxx_zoom_mode zoom)
{
int ret;
h.header_data.zoom.bit0 = 1;
break;
+ case AM7XXX_ZOOM_TELE:
default:
error(dev->ctx, "Unsupported zoom mode.\n");
return -EINVAL;
return 0;
}
+static int picopix_set_zoom_mode(am7xxx_device *dev, am7xxx_zoom_mode zoom)
+{
+ int ret;
+ am7xxx_packet_type packet_type;
+
+ switch(zoom) {
+ case AM7XXX_ZOOM_ORIGINAL:
+ packet_type = AM7XXX_PACKET_TYPE_PICOPIX_DISABLE_TI;
+ break;
+
+ case AM7XXX_ZOOM_TELE:
+ packet_type = AM7XXX_PACKET_TYPE_PICOPIX_ENABLE_TI;
+ break;
+
+ case AM7XXX_ZOOM_H:
+ case AM7XXX_ZOOM_H_V:
+ case AM7XXX_ZOOM_TEST:
+ default:
+ error(dev->ctx, "Unsupported zoom mode.\n");
+ return -EINVAL;
+ };
+
+ ret = send_command(dev, packet_type);
+ if (ret < 0)
+ return ret;
+
+ /* The Windows drivers wait for 100ms and send the same command again,
+ * probably to overcome a firmware deficiency */
+ ret = msleep(100);
+ if (ret < 0)
+ return ret;
+
+ return send_command(dev, packet_type);
+}
+
/* Public API */
AM7XXX_PUBLIC int am7xxx_init(am7xxx_context **ctx)
am7xxx_device_info *device_info)
{
int ret;
- struct am7xxx_header h = {
- .packet_type = AM7XXX_PACKET_TYPE_DEVINFO,
- .direction = AM7XXX_DIRECTION_OUT,
- .header_data_len = 0x00,
- .unknown2 = 0x3e,
- .unknown3 = 0x10,
- .header_data = {
- .devinfo = {
- .native_width = 0,
- .native_height = 0,
- .unknown0 = 0,
- .unknown1 = 0,
- },
- },
- };
+ struct am7xxx_header h;
if (dev->device_info) {
memcpy(device_info, dev->device_info, sizeof(*device_info));
return 0;
}
- ret = send_header(dev, &h);
+ ret = send_command(dev, AM7XXX_PACKET_TYPE_DEVINFO);
if (ret < 0)
return ret;
+ memset(&h, 0, sizeof(h));
ret = read_header(dev, &h);
if (ret < 0)
return ret;