Blob Blame History Raw
/*
 * 1394-Based Digital Camera Control Library
 *
 * Camera control code for Windows
 *
 * Written by
 *   Satofumi Kamimura <satofumi@users.sourceforge.jp>
 *
 * We use CMU 1394 Digital Camera Driver project's source code for this project.
 *   http://www.cs.cmu.edu/~iwan/1394/
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <windows.h>
#include <stdlib.h>
#include "dc1394/internal.h"
#include "platform_windows.h"
#include "types.h"


// \todo remove this function
extern dc1394error_t
dc1394_windows_iso_allocate_channel (platform_camera_t * cam,
                                     uint64_t channels_allowed, int * channel);

extern dc1394error_t
dc1394_windows_iso_release_channel (platform_camera_t * cam, int channel);

extern dc1394error_t
dc1394_windows_capture_setup(platform_camera_t * craw, uint32_t num_dma_buffers,
                             uint32_t flags);

extern dc1394error_t
dc1394_windows_capture_stop(platform_camera_t *craw);

extern dc1394error_t
dc1394_windows_capture_dequeue (platform_camera_t * craw,
                                dc1394capture_policy_t policy,
                                dc1394video_frame_t **frame);

extern dc1394error_t
dc1394_windows_capture_enqueue (platform_camera_t * craw,
                                dc1394video_frame_t * frame);


static platform_t *
dc1394_windows_new (void)
{
    HDEVINFO * dev_info = t1394CmdrGetDeviceList();
    if (dev_info == INVALID_HANDLE_VALUE) {
        return NULL;
    }

    platform_t * p = calloc (1, sizeof (platform_t));
    if (!p) {
        return NULL;
    }

    p->dev_info = dev_info;
    return p;
}

static void
dc1394_windows_free (platform_t * p)
{
    if (p == NULL) {
        return;
    }

    SetupDiDestroyDeviceInfoList(p->dev_info);
    free (p);
}

static int
read_retry (const char * device_path, ULONG offset, PULONG data)
{
    int retry = DC1394_MAX_RETRIES;
    while (retry > 0) {
        DWORD ret = ReadRegisterUL ((char *)device_path, offset, data);
        if (ret == ERROR_SUCCESS) {
            return 0;
        }

        if (ret != ERROR_SEM_TIMEOUT && ret != ERROR_BUSY) {
            break;
        }
        usleep (DC1394_SLOW_DOWN);
        retry--;
    }
    return -1;
}

static int
write_retry (const char * device_path, ULONG offset, ULONG data)
{
    int retry = DC1394_MAX_RETRIES;
    while (retry > 0) {
        DWORD ret = WriteRegisterUL ((char *)device_path, offset, data);
        if (ret == ERROR_SUCCESS) {
            return 0;
        }

        if (ret != ERROR_SEM_TIMEOUT && ret != ERROR_BUSY) {
            break;
        }
        usleep (DC1394_SLOW_DOWN);
        retry--;
    }
    return -1;
}

static int number_of_devices(platform_t * p)
{
    int n;

    for (n = 0; n < MAX_DEVICE_SIZE; ++n) {
        char device_path[DEVICE_PATH_SIZE];
        ULONG device_path_size = DEVICE_PATH_SIZE;

        if (t1394CmdrGetDevicePath (p->dev_info, n,
                                    device_path, &device_path_size) <= 0) {
            return n;
        }
    }
    return 0;
}

static platform_device_list_t *
dc1394_windows_get_device_list (platform_t * p)
{
    platform_device_list_t * list;
    int device_size;
    int i;

    list = calloc (1, sizeof (platform_device_list_t));
    if (!list) {
        return NULL;
    }

    device_size = number_of_devices(p);
    list->devices = malloc (device_size * sizeof(platform_device_t *));
    if (!list->devices) {
        free (list);
        return NULL;
    }
    list->num_devices = 0;

    // find device path
    for (i = 0; i < device_size; ++i) {
        char device_path[DEVICE_PATH_SIZE];
        ULONG device_path_size = DEVICE_PATH_SIZE;
        ULONG quad;
        platform_device_t * device;
        int j;

        if (t1394CmdrGetDevicePath (p->dev_info, i,
                                    device_path, &device_path_size) <= 0) {
            break;
        }

        if (read_retry (device_path, 0xf0000400, &quad) < 0) {
            break;
        }

        device = malloc (sizeof (platform_device_t));
        if (!device) {
            break;
        }

        strncpy(device->device_path, device_path, device_path_size);
        device->node = i;
        device->config_rom[0] = quad;
        for (j = 1; j < CONFIG_ROM_SIZE; ++j) {
            if (read_retry (device_path, 0xf0000400 + 4*j, &quad) < 0) {
                break;
            }
            device->config_rom[j] = quad;
        }
        device->config_rom_size = j;

        list->devices[list->num_devices] = device;
        ++list->num_devices;
    }
    return list;
}

static void
dc1394_windows_free_device_list (platform_device_list_t * d)
{
    int i;

    if (!d) {
        return;
    }

    for (i = 0; i < d->num_devices; ++i) {
        free (d->devices[i]);
    }
    free (d);
}

static int
dc1394_windows_device_get_config_rom (platform_device_t * device,
                                      uint32_t * quads, int * num_quads)
{
    if (*num_quads > device->config_rom_size) {
        *num_quads = device->config_rom_size;
    }

    memcpy (quads, device->config_rom, *num_quads * sizeof (uint32_t));
    return 0;
}

static platform_camera_t *
dc1394_windows_camera_new (platform_t * p, platform_device_t * device,
                           uint32_t unit_directory_offset)
{
    platform_camera_t * camera = malloc (sizeof (platform_camera_t));
    if (!camera) {
        return NULL;
    }

    camera->device = device;
    camera->camera = NULL;
    camera->capture_is_set = 0;
    camera->allocated_channel = 0;
    camera->allocated_bandwidth = 0;
    camera->iso_channel = 0;
    camera->iso_auto_started = 0;

    camera->capture.flags = 0;
    camera->capture.frames = NULL;

    return camera;
}

static void
dc1394_windows_camera_free (platform_camera_t * cam)
{
    free (cam);
}

static void
dc1394_windows_camera_set_parent (platform_camera_t * cam,
                                  dc1394camera_t * parent)
{
    cam->camera = parent;
}

static dc1394error_t
dc1394_windows_camera_print_info (platform_camera_t * cam, FILE *fd)
{
    fprintf(fd,"------ Camera platform-specific information ------\n");
    fprintf(fd,"Device                            :     %p\n", cam->device);
    fprintf(fd,"Camera                            :     %p\n", cam->camera);

    return DC1394_SUCCESS;
}

static dc1394error_t
dc1394_windows_camera_read (platform_camera_t * cam, uint64_t offset,
                            uint32_t * quads, int num_quads)
{
    int i;

    for (i = 0; i < num_quads; ++i) {
        if (read_retry (cam->device->device_path,
                        0xf0000000 + offset + 4*i, (PULONG)&quads[i]) < 0) {
            return DC1394_FAILURE;
        }
    }

    return DC1394_SUCCESS;
}

static dc1394error_t
dc1394_windows_camera_write (platform_camera_t * cam, uint64_t offset,
                             const uint32_t * quads, int num_quads)
{
    int i;

    for (i = 0; i < num_quads; ++i) {
        if (write_retry (cam->device->device_path,
                         0xf0000000 + offset + 4*i, quads[i]) < 0) {
            return DC1394_FAILURE;
        }
    }

    return DC1394_SUCCESS;
}

static dc1394error_t
dc1394_windows_reset_bus (platform_camera_t * cam)
{
    // \todo implement
    return DC1394_FAILURE;
}

static dc1394error_t
dc1394_windows_read_cycle_timer (platform_camera_t * cam,
                                 uint32_t * cycle_timer, uint64_t * local_time)
{
    // \todo implement
    return DC1394_FAILURE;
}

static dc1394error_t
dc1394_windows_set_broadcast (platform_camera_t * craw, dc1394bool_t pwr)
{
    // \todo implement
    return DC1394_FAILURE;
}

static dc1394error_t
dc1394_windows_get_broadcast (platform_camera_t * craw, dc1394bool_t *pwr)
{
    // \todo implement
    return DC1394_FAILURE;
}

static dc1394error_t
dc1394_windows_iso_set_persist (platform_camera_t * cam)
{
    // \todo implement
    return DC1394_FAILURE;
}

static dc1394error_t
dc1394_windows_iso_allocate_bandwidth (platform_camera_t * cam,
                                       int bandwidth_units)
{
    // \todo implement
    return DC1394_SUCCESS;
}

static dc1394error_t
dc1394_windows_iso_release_bandwidth (platform_camera_t * cam,
                                      int bandwidth_units)
{
    // \todo implement
    //return DC1394_FAILURE;
    return DC1394_SUCCESS;
}

static dc1394error_t
dc1394_windows_camera_get_node(platform_camera_t * cam, uint32_t *node,
                               uint32_t * generation)
{
    *node = cam->device->node;

    // \todo implement
    return DC1394_FAILURE;
}

dc1394error_t
dc1394_camera_get_windows_port(dc1394camera_t *camera, uint32_t *port)
{
    // \todo implement
    return DC1394_FAILURE;
}


static int
dc1394_windows_capture_get_fileno (platform_camera_t * craw)
{
    // \todo implement
    return -1;
}

static platform_dispatch_t
windows_dispatch = {
    .platform_new = dc1394_windows_new,
    .platform_free = dc1394_windows_free,

    .get_device_list = dc1394_windows_get_device_list,
    .free_device_list = dc1394_windows_free_device_list,
    .device_get_config_rom = dc1394_windows_device_get_config_rom,

    .camera_new = dc1394_windows_camera_new,
    .camera_free = dc1394_windows_camera_free,
    .camera_set_parent = dc1394_windows_camera_set_parent,

    .camera_read = dc1394_windows_camera_read,
    .camera_write = dc1394_windows_camera_write,

    .reset_bus = dc1394_windows_reset_bus,
    .camera_print_info = dc1394_windows_camera_print_info,
    .camera_get_node = dc1394_windows_camera_get_node,
    .set_broadcast = dc1394_windows_set_broadcast,
    .get_broadcast = dc1394_windows_get_broadcast,
    .read_cycle_timer = dc1394_windows_read_cycle_timer,

    .capture_setup = dc1394_windows_capture_setup,
    .capture_stop = dc1394_windows_capture_stop,
    .capture_dequeue = dc1394_windows_capture_dequeue,
    .capture_enqueue = dc1394_windows_capture_enqueue,
    .capture_get_fileno = dc1394_windows_capture_get_fileno,

    .iso_set_persist = dc1394_windows_iso_set_persist,
    .iso_allocate_channel = dc1394_windows_iso_allocate_channel,
    .iso_release_channel = dc1394_windows_iso_release_channel,
    .iso_allocate_bandwidth = dc1394_windows_iso_allocate_bandwidth,
    .iso_release_bandwidth = dc1394_windows_iso_release_bandwidth,
    .capture_set_callback = NULL,
    .capture_schedule_with_runloop = NULL,
};

void
windows_init(dc1394_t * d)
{
    register_platform (d, &windows_dispatch, "windows");
}