summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/io/1394
diff options
context:
space:
mode:
authorap25164 <none@none>2005-06-16 12:21:18 -0700
committerap25164 <none@none>2005-06-16 12:21:18 -0700
commit8eea8e29cc4374d1ee24c25a07f45af132db3499 (patch)
tree4086aa247025ffc4f1f2aff56f12c9ae6ebb10db /usr/src/uts/common/io/1394
parent89a8ba833ef2615d086ab2ae9deffa0a858ed398 (diff)
downloadillumos-gate-8eea8e29cc4374d1ee24c25a07f45af132db3499.tar.gz
PSARC/2004/364 dcam1394 driver
4841261 dcamctl links are not removed 5087103 IIDC (1394-based digital cameras) should be supported by Solaris 6261805 dcam1394 will cause a panic after being called to release its isoch resources multiple times
Diffstat (limited to 'usr/src/uts/common/io/1394')
-rw-r--r--usr/src/uts/common/io/1394/targets/dcam1394/dcam.c1262
-rw-r--r--usr/src/uts/common/io/1394/targets/dcam1394/dcam_frame.c644
-rw-r--r--usr/src/uts/common/io/1394/targets/dcam1394/dcam_param.c1803
-rw-r--r--usr/src/uts/common/io/1394/targets/dcam1394/dcam_reg.c125
-rw-r--r--usr/src/uts/common/io/1394/targets/dcam1394/dcam_ring_buff.c350
5 files changed, 4184 insertions, 0 deletions
diff --git a/usr/src/uts/common/io/1394/targets/dcam1394/dcam.c b/usr/src/uts/common/io/1394/targets/dcam1394/dcam.c
new file mode 100644
index 0000000000..cb05730690
--- /dev/null
+++ b/usr/src/uts/common/io/1394/targets/dcam1394/dcam.c
@@ -0,0 +1,1262 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * dcam.c
+ *
+ * dcam1394 driver. Controls IIDC compliant devices attached through a
+ * IEEE-1394 bus.
+ */
+
+#include <sys/conf.h>
+#include <sys/ddi.h>
+#include <sys/modctl.h>
+#include <sys/sunndi.h>
+#include <sys/types.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/file.h>
+#include <sys/errno.h>
+#include <sys/open.h>
+#include <sys/cred.h>
+#include <sys/mkdev.h>
+#include <sys/kmem.h>
+#include <sys/stat.h>
+#include <sys/cmn_err.h>
+#include <sys/stream.h>
+#include <sys/buf.h>
+#include <sys/uio.h>
+#include <sys/devops.h>
+#include <sys/1394/t1394.h>
+#include <sys/tnf_probe.h>
+
+#include <sys/dcam/dcam1394_io.h>
+#include <sys/1394/targets/dcam1394/dcam.h>
+#include <sys/1394/targets/dcam1394/dcam_reg.h>
+#include <sys/1394/targets/dcam1394/dcam_param.h>
+#include <sys/1394/targets/dcam1394/dcam_frame.h>
+
+#ifndef NPROBE
+extern int tnf_mod_load(void);
+extern int tnf_mod_unload(struct modlinkage *mlp);
+#endif /* ! NPROBE */
+
+
+/* for power management (we have only one component) */
+static char *dcam_pmc[] = {
+ "NAME=dcam1394",
+ "0=Off",
+ "1=On"
+};
+
+int g_vid_mode_frame_num_bytes[] =
+{
+ 57600, /* vid mode 0 */
+ 153600, /* vid mode 1 */
+ 460800, /* vid mode 2 */
+ 614400, /* vid mode 3 */
+ 921600, /* vid mode 4 */
+ 307200 /* vid mode 5 */
+};
+
+static int byte_copy_to_user_buff(uchar_t *src_addr_p, struct uio *uio_p,
+ size_t num_bytes, int start_index, int *end_index);
+static int byte_copy_from_user_buff(uchar_t *dst_addr_p, struct uio *uio_p,
+ size_t num_bytes, int start_index, int *end_index);
+static int dcam_reset(dcam_state_t *softc_p);
+
+/* opaque state structure head */
+void *dcam_state_p;
+
+static struct cb_ops dcam_cb_ops = {
+ dcam_open, /* open */
+ dcam_close, /* close */
+ nodev, /* strategy */
+ nodev, /* print */
+ nodev, /* dump */
+ dcam_read, /* read */
+ nodev, /* write */
+ dcam_ioctl, /* ioctl */
+ nodev, /* devmap */
+ nodev, /* mmap */
+ nodev, /* segmap */
+ dcam_chpoll, /* chpoll */
+ ddi_prop_op, /* prop_op */
+ NULL, /* streams */
+ /* flags */
+ D_NEW | D_MP | D_64BIT | D_HOTPLUG,
+ CB_REV, /* rev */
+ nodev, /* aread */
+ nodev /* awrite */
+};
+
+static struct dev_ops dcam_dev_ops = {
+ DEVO_REV, /* DEVO_REV indicated by manual */
+ 0, /* device reference count */
+ dcam_getinfo, /* getinfo */
+ nulldev, /* identify */
+ nulldev, /* probe */
+ dcam_attach, /* attach */
+ dcam_detach, /* detach */
+ nodev, /* reset */
+ &dcam_cb_ops, /* ptr to cb_ops struct */
+ NULL, /* ptr to bus_ops struct; none */
+ dcam_power, /* power */
+};
+
+extern struct mod_ops mod_driverops;
+
+static struct modldrv modldrv = {
+ &mod_driverops,
+ "SUNW 1394-based Digital Camera driver 1.0",
+ &dcam_dev_ops,
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1,
+ (void *)&modldrv,
+ NULL,
+};
+
+
+int
+_init(void)
+{
+ int err;
+
+ err = ddi_soft_state_init(&dcam_state_p, sizeof (dcam_state_t), 2);
+
+ if (err) {
+ return (err);
+ }
+
+#ifndef NPROBE
+ (void) tnf_mod_load();
+#endif /* ! NPROBE */
+
+ if (err = mod_install(&modlinkage)) {
+
+#ifndef NPROBE
+ (void) tnf_mod_unload(&modlinkage);
+#endif /* ! NPROBE */
+
+ ddi_soft_state_fini(&dcam_state_p);
+
+ }
+
+ return (err);
+}
+
+
+int
+_info(struct modinfo *modinfop)
+{
+ int err;
+
+ err = mod_info(&modlinkage, modinfop);
+ return (err);
+}
+
+
+int
+_fini(void)
+{
+ int err;
+
+ if ((err = mod_remove(&modlinkage)) != 0) {
+ return (err);
+ }
+
+#ifndef NPROBE
+ (void) tnf_mod_unload(&modlinkage);
+#endif /* ! NPROBE */
+
+ ddi_soft_state_fini(&dcam_state_p);
+
+ return (err);
+}
+
+
+/*
+ * dcam_attach
+ */
+/* ARGSUSED */
+int
+dcam_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+ char tmp_str[MAX_STR_LEN];
+ dcam_state_t *softc_p;
+ ddi_eventcookie_t ev_cookie;
+ int instance;
+ int ret_val;
+
+ switch (cmd) {
+
+ case DDI_ATTACH:
+ instance = ddi_get_instance(dip);
+
+ if (ddi_soft_state_zalloc(dcam_state_p, instance) !=
+ DDI_SUCCESS) {
+ return (DDI_FAILURE);
+ }
+
+ if ((softc_p = ddi_get_soft_state(dcam_state_p, instance)) ==
+ NULL) {
+ ddi_soft_state_free(dcam_state_p, instance);
+ return (DDI_FAILURE);
+ }
+
+ /*
+ * Initialize soft state
+ */
+ softc_p->dip = dip;
+ softc_p->instance = instance;
+ softc_p->usr_model = -1;
+ softc_p->ixlp = NULL;
+
+ softc_p->seq_count = 0;
+ softc_p->param_status = 0;
+
+ /*
+ * set default vid_mode, frame_rate and ring_buff_capacity
+ */
+ softc_p->cur_vid_mode = 1;
+ softc_p->cur_frame_rate = 3;
+ softc_p->cur_ring_buff_capacity = 10;
+ softc_p->camera_online = 1;
+
+ (void) sprintf(tmp_str, "dcam%d", instance);
+
+ if (ddi_create_minor_node(dip, tmp_str, S_IFCHR, instance,
+ DDI_PSEUDO, 0) != DDI_SUCCESS) {
+ ddi_soft_state_free(dcam_state_p, instance);
+
+ return (DDI_FAILURE);
+ }
+
+ (void) sprintf(tmp_str, "dcamctl%d", instance);
+
+ if (ddi_create_minor_node(dip, tmp_str, S_IFCHR,
+ instance + DCAM1394_MINOR_CTRL, "ddi_dcam1394", 0) !=
+ DDI_SUCCESS) {
+ ddi_soft_state_free(dcam_state_p, instance);
+
+ return (DDI_FAILURE);
+ }
+
+ if (t1394_attach(dip, T1394_VERSION_V1, 0,
+ &(softc_p->attachinfo),
+ &(softc_p->sl_handle)) != DDI_SUCCESS) {
+ ddi_soft_state_free(dcam_state_p, instance);
+ ddi_remove_minor_node(dip, NULL);
+
+ return (DDI_FAILURE);
+ }
+
+ if (t1394_get_targetinfo(softc_p->sl_handle,
+ softc_p->attachinfo.localinfo.bus_generation, 0,
+ &(softc_p->targetinfo)) != DDI_SUCCESS) {
+ cmn_err(CE_WARN,
+ "dcam_attach: t1394_get_targetinfo failed\n");
+ }
+
+ if (ddi_get_eventcookie(dip, DDI_DEVI_BUS_RESET_EVENT,
+ &ev_cookie) != DDI_SUCCESS) {
+ (void) t1394_detach(&softc_p->sl_handle, 0);
+
+ ddi_soft_state_free(dcam_state_p, instance);
+ ddi_remove_minor_node(dip, NULL);
+
+ return (DDI_FAILURE);
+ }
+
+ if (ddi_add_event_handler(dip, ev_cookie, dcam_bus_reset_notify,
+ softc_p, &softc_p->event_id) != DDI_SUCCESS) {
+ (void) t1394_detach(&softc_p->sl_handle, 0);
+
+ ddi_soft_state_free(dcam_state_p, instance);
+ ddi_remove_minor_node(dip, NULL);
+
+ return (DDI_FAILURE);
+ }
+
+ mutex_init(&softc_p->softc_mutex, NULL, MUTEX_DRIVER,
+ softc_p->attachinfo.iblock_cookie);
+
+ mutex_init(&softc_p->dcam_frame_is_done_mutex, NULL,
+ MUTEX_DRIVER, softc_p->attachinfo.iblock_cookie);
+
+ /*
+ * init the soft state's parameter attribute structure
+ */
+ if (param_attr_init(softc_p, softc_p->param_attr) !=
+ DDI_SUCCESS) {
+ (void) ddi_remove_event_handler(softc_p->event_id);
+ (void) t1394_detach(&softc_p->sl_handle, 0);
+
+ ddi_soft_state_free(dcam_state_p, instance);
+ ddi_remove_minor_node(dip, NULL);
+
+ return (DDI_FAILURE);
+ }
+
+ /*
+ * power management stuff
+ */
+ if (ddi_prop_update_string_array(DDI_DEV_T_NONE,
+ dip, "pm-components", dcam_pmc,
+ sizeof (dcam_pmc)/sizeof (char *)) == DDI_PROP_SUCCESS) {
+
+ (void) pm_raise_power(dip, 0, 1);
+ if (ddi_prop_exists(DDI_DEV_T_ANY, dip, 0,
+ "power-managed?")) {
+ (void) pm_idle_component(dip, 0);
+ } else {
+ (void) pm_busy_component(dip, 0);
+ }
+ }
+
+ softc_p->flags |= DCAM1394_FLAG_ATTACH_COMPLETE;
+
+ ddi_report_dev(dip);
+ ret_val = DDI_SUCCESS;
+ break;
+
+ case DDI_RESUME:
+ instance = ddi_get_instance(dip);
+ if ((softc_p = ddi_get_soft_state(dcam_state_p, instance)) ==
+ NULL) {
+ ddi_soft_state_free(dcam_state_p, instance);
+ return (DDI_FAILURE);
+ }
+
+ mutex_enter(&softc_p->softc_mutex);
+
+ if (softc_p->flags & DCAM1394_FLAG_FRAME_RCV_INIT) {
+ (void) dcam1394_ioctl_frame_rcv_start(softc_p);
+ }
+
+ softc_p->suspended = 0;
+
+ mutex_exit(&softc_p->softc_mutex);
+
+ ret_val = DDI_SUCCESS;
+ break;
+
+ default:
+ ret_val = DDI_FAILURE;
+ break;
+ }
+
+ return (ret_val);
+}
+
+
+/*
+ * dcam_power: perform dcam power management
+ */
+/* ARGSUSED */
+int
+dcam_power(dev_info_t *dip, int component, int level)
+{
+ dcam_state_t *softc_p;
+ int instance;
+
+ instance = ddi_get_instance(dip);
+ softc_p = (dcam_state_t *)ddi_get_soft_state(dcam_state_p, instance);
+
+ if (softc_p == NULL)
+ return (DDI_FAILURE);
+
+ softc_p->pm_cable_power = level;
+
+ return (DDI_SUCCESS);
+
+}
+
+
+/*
+ * dcam_getinfo
+ */
+/* ARGSUSED */
+int
+dcam_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
+{
+ dev_t dev;
+ dcam_state_t *softc_p;
+ int status;
+ int instance;
+
+ switch (cmd) {
+
+ case DDI_INFO_DEVT2DEVINFO:
+ dev = (dev_t)arg;
+ instance = DEV_TO_INSTANCE(dev);
+ softc_p = (dcam_state_t *)
+ ddi_get_soft_state(dcam_state_p, instance);
+
+ if (softc_p == NULL) {
+ return (DDI_FAILURE);
+ }
+
+ *result = (void *)softc_p->dip;
+ status = DDI_SUCCESS;
+ break;
+
+ case DDI_INFO_DEVT2INSTANCE:
+ dev = (dev_t)arg;
+ instance = DEV_TO_INSTANCE(dev);
+ *result = (void *)(uintptr_t)instance;
+ status = DDI_SUCCESS;
+ break;
+
+ default:
+ status = DDI_FAILURE;
+ }
+
+ return (status);
+}
+
+
+/*
+ * dcam_detach
+ */
+/* ARGSUSED */
+int
+dcam_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+ int instance;
+ dcam_state_t *softc_p;
+
+ instance = ddi_get_instance(dip);
+
+ softc_p = (dcam_state_t *)ddi_get_soft_state(dcam_state_p, instance);
+ if (softc_p == NULL) {
+ return (DDI_FAILURE);
+ }
+
+
+ switch (cmd) {
+
+ case DDI_SUSPEND:
+ mutex_enter(&softc_p->softc_mutex);
+
+ softc_p->suspended = 1;
+
+ if (softc_p->flags & DCAM1394_FLAG_FRAME_RCV_INIT) {
+ (void) dcam_frame_rcv_stop(softc_p);
+ }
+
+ mutex_exit(&softc_p->softc_mutex);
+ return (DDI_SUCCESS);
+
+
+ case DDI_DETACH:
+ /*
+ * power management stuff
+ */
+ (void) pm_lower_power(dip, 0, 0);
+ (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "pm-components");
+
+ /*
+ * deregister with 1394 DDI framework
+ */
+ if (t1394_detach(&softc_p->sl_handle, 0) != DDI_SUCCESS) {
+ return (DDI_FAILURE);
+ }
+
+ (void) ddi_remove_event_handler(softc_p->event_id);
+
+ /*
+ * free state structures, mutexes, condvars;
+ * deregister interrupts
+ */
+ mutex_destroy(&softc_p->softc_mutex);
+ mutex_destroy(&softc_p->dcam_frame_is_done_mutex);
+
+ /*
+ * Remove all minor nodes, all dev_t's properties
+ */
+ ddi_remove_minor_node(dip, NULL);
+
+ ddi_soft_state_free(dcam_state_p, instance);
+ ddi_prop_remove_all(dip);
+
+ return (DDI_SUCCESS);
+
+ default:
+ return (DDI_FAILURE);
+
+ }
+}
+
+
+/*
+ * dcam_open
+ */
+/* ARGSUSED */
+int
+dcam_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
+{
+ dcam_state_t *softc_p;
+ int instance;
+ int is_ctrl_file;
+ uint_t new_flags;
+
+ instance = (int)DEV_TO_INSTANCE(*dev_p);
+
+ if ((softc_p = ddi_get_soft_state(dcam_state_p, instance)) == NULL) {
+ return (ENXIO);
+ }
+
+ /*
+ * if dcam_attach hasn't completed, return error
+ * XXX: Check this out
+ */
+ if (!(softc_p->flags & DCAM1394_FLAG_ATTACH_COMPLETE)) {
+ return (ENXIO);
+ }
+
+ /* disallow block, mount, and layered opens */
+ if (otyp != OTYP_CHR) {
+ return (EINVAL);
+ }
+
+ new_flags = 0;
+ is_ctrl_file = (getminor(*dev_p) & DCAM1394_MINOR_CTRL) ? 1 : 0;
+
+ mutex_enter(&softc_p->softc_mutex);
+
+ /*
+ * The open is either for the capture file or the control file.
+ * If it's the control file construct new flags.
+ *
+ * If it's the capture file return busy if it's already open,
+ * otherwise construct new flags.
+ */
+ if (is_ctrl_file) {
+ new_flags |= DCAM1394_FLAG_OPEN_CONTROL;
+ } else {
+ if (softc_p->flags & DCAM1394_FLAG_OPEN_CAPTURE) {
+ mutex_exit(&softc_p->softc_mutex);
+ return (EBUSY);
+ }
+
+ new_flags |= DCAM1394_FLAG_OPEN_CAPTURE;
+ }
+
+ new_flags |= DCAM1394_FLAG_OPEN;
+ softc_p->flags |= new_flags;
+
+ mutex_exit(&softc_p->softc_mutex);
+
+ /*
+ * power management stuff
+ */
+ if (softc_p->pm_open_count == 0) {
+ if (ddi_prop_exists(DDI_DEV_T_ANY, softc_p->dip, 0,
+ "power-managed?")) {
+ (void) pm_busy_component(softc_p->dip, 0);
+ if (softc_p->pm_cable_power == 0) {
+ int i;
+
+ (void) pm_raise_power(softc_p->dip, 0, 1);
+
+ /*
+ * Wait for the power to be up and stable
+ * before proceeding. 100 msecs should
+ * certainly be enough, and if we check
+ * every msec we'll probably loop just a
+ * few times.
+ */
+ for (i = 0; i < 100; i++) {
+ if (param_power_set(softc_p, 1) == 0) {
+ break;
+ }
+ delay((clock_t)drv_usectohz(1000));
+ }
+ }
+ }
+ }
+ softc_p->pm_open_count++;
+
+ return (0);
+}
+
+
+/*
+ * dcam_close
+ */
+/* ARGSUSED */
+int
+dcam_close(dev_t dev, int flags, int otyp, cred_t *cred_p)
+{
+ int instance;
+ dcam_state_t *softc;
+
+ instance = DEV_TO_INSTANCE(dev);
+ softc = (dcam_state_t *)ddi_get_soft_state(dcam_state_p, instance);
+
+ /*
+ * power management stuff
+ */
+ softc->pm_open_count = 0;
+ if (ddi_prop_exists(DDI_DEV_T_ANY, softc->dip, 0, "power-managed?")) {
+ (void) pm_idle_component(softc->dip, 0);
+ }
+
+ mutex_enter(&softc->softc_mutex);
+
+ if (getminor(dev) & DCAM1394_MINOR_CTRL) {
+ softc->flags &= ~DCAM1394_FLAG_OPEN_CONTROL;
+ } else {
+ /*
+ * If an application which has opened the camera capture
+ * device exits without calling DCAM1394_CMD_FRAME_RCV_STOP
+ * ioctl, then we need to release resources.
+ */
+ if (softc->flags & DCAM1394_FLAG_FRAME_RCV_INIT) {
+ (void) dcam_frame_rcv_stop(softc);
+ softc->flags &= ~DCAM1394_FLAG_FRAME_RCV_INIT;
+ }
+
+ (void) param_power_set(softc, 0);
+
+ softc->flags &= ~DCAM1394_FLAG_OPEN_CAPTURE;
+ }
+
+ /*
+ * If driver is completely closed, then stabilize the camera
+ * and turn off transient flags
+ */
+ if (!(softc->flags &
+ (DCAM1394_FLAG_OPEN_CONTROL | DCAM1394_FLAG_OPEN_CAPTURE))) {
+ softc->flags &= DCAM1394_FLAG_ATTACH_COMPLETE;
+ }
+
+ mutex_exit(&softc->softc_mutex);
+
+ return (DDI_SUCCESS);
+
+}
+
+
+/*
+ * dcam_read
+ *
+ * If read pointer is not pointing to the same position as write pointer
+ * copy frame data from ring buffer position pointed to by read pointer.
+ *
+ * If during the course of copying frame data, the device driver
+ * invalidated this read() request processing operation, restart
+ * this operation.
+ *
+ * Increment read pointer and return frame data to user process.
+ *
+ * Else return error
+ *
+ */
+/* ARGSUSED */
+int
+dcam_read(dev_t dev, struct uio *uio_p, cred_t *cred_p)
+{
+ buff_info_t *buff_info_p;
+ dcam_state_t *softc_p;
+ hrtime_t timestamp;
+ int index, instance;
+ int read_ptr_id;
+ size_t read_ptr_pos, write_ptr_pos;
+ int read_req_invalid;
+ ring_buff_t *ring_buff_p;
+ uchar_t *frame_data_p;
+ uint_t seq_num;
+ unsigned long user_frame_buff_addr;
+ uint_t vid_mode;
+ int gotten_addr_flag;
+
+ instance = DEV_TO_INSTANCE(dev);
+
+ softc_p = (dcam_state_t *)ddi_get_soft_state(dcam_state_p, instance);
+ if (softc_p == NULL) {
+ return (ENXIO);
+ }
+
+ if ((ring_buff_p = softc_p->ring_buff_p) == NULL) {
+ return (EAGAIN);
+ }
+
+ read_ptr_id = 0;
+
+ mutex_enter(&softc_p->dcam_frame_is_done_mutex);
+
+ softc_p->reader_flags[read_ptr_id] |= DCAM1394_FLAG_READ_REQ_PROC;
+
+ user_frame_buff_addr = 0;
+ gotten_addr_flag = 0;
+
+ do {
+ read_ptr_pos = ring_buff_read_ptr_pos_get(ring_buff_p,
+ read_ptr_id);
+
+ write_ptr_pos = ring_buff_write_ptr_pos_get(ring_buff_p);
+
+ if (read_ptr_pos != write_ptr_pos) {
+ /*
+ * Since the app wants realtime video, set the read
+ * pointer to the newest data.
+ */
+ if (write_ptr_pos == 0) {
+ read_ptr_pos = ring_buff_p->num_buffs - 1;
+ } else {
+ read_ptr_pos = write_ptr_pos - 1;
+ }
+
+ /*
+ * copy frame data from ring buffer position pointed
+ * to by read pointer
+ */
+ index = 0;
+ buff_info_p =
+ &(ring_buff_p->buff_info_array_p[read_ptr_pos]);
+
+ vid_mode = softc_p->cur_vid_mode;
+ seq_num = buff_info_p->seq_num;
+ timestamp = buff_info_p->timestamp;
+ frame_data_p = (uchar_t *)buff_info_p->kaddr_p;
+
+ mutex_exit(&softc_p->dcam_frame_is_done_mutex);
+
+ /*
+ * Fix for bug #4424042
+ * don't lock this section
+ */
+
+ if (byte_copy_to_user_buff((uchar_t *)&vid_mode,
+ uio_p, sizeof (uint_t), index, &index)) {
+
+ return (EFAULT);
+ }
+
+ if (byte_copy_to_user_buff((uchar_t *)&seq_num,
+ uio_p, sizeof (unsigned int), index, &index)) {
+
+ return (EFAULT);
+ }
+
+ if (byte_copy_to_user_buff((uchar_t *)&timestamp,
+ uio_p, sizeof (hrtime_t), index, &index)) {
+
+ return (EFAULT);
+ }
+
+ /*
+ * get buff pointer; do ddi_copyout()
+ * get user buffer address only once
+ */
+ if (!gotten_addr_flag) {
+ if (byte_copy_from_user_buff(
+ (uchar_t *)&user_frame_buff_addr, uio_p,
+ softc_p->usr_model, index, &index)) {
+
+ return (EFAULT);
+ }
+
+#ifdef _MULTI_DATAMODEL
+ if (softc_p->usr_model == ILP32_PTR_SIZE) {
+ user_frame_buff_addr =
+ ((user_frame_buff_addr >> 32) &
+ 0xffffffffULL) |
+ ((user_frame_buff_addr << 32) &
+ 0xffffffff00000000ULL);
+ }
+#endif /* _MULTI_DATAMODEL */
+
+ gotten_addr_flag = 1;
+ }
+
+ if (ddi_copyout(
+ (caddr_t)frame_data_p,
+ (caddr_t)user_frame_buff_addr,
+ g_vid_mode_frame_num_bytes[softc_p->cur_vid_mode],
+ 0)) {
+ return (EFAULT);
+ }
+
+ /*
+ * if during the course of copying frame data,
+ * the device driver invalidated this read()
+ * request processing operation; restart this
+ * operation
+ */
+
+ mutex_enter(&softc_p->dcam_frame_is_done_mutex);
+
+ read_req_invalid = softc_p->reader_flags[read_ptr_id] &
+ DCAM1394_FLAG_READ_REQ_INVALID;
+
+ softc_p->reader_flags[read_ptr_id] &=
+ ~(DCAM1394_FLAG_READ_REQ_INVALID);
+
+ mutex_exit(&softc_p->dcam_frame_is_done_mutex);
+
+ } else {
+ mutex_exit(&softc_p->dcam_frame_is_done_mutex);
+ return (EAGAIN);
+ }
+
+ mutex_enter(&softc_p->dcam_frame_is_done_mutex);
+ } while (read_req_invalid);
+
+ /*
+ * return number of bytes actually written to user space
+ */
+ uio_p->uio_resid -= g_vid_mode_frame_num_bytes[softc_p->cur_vid_mode];
+
+ softc_p->reader_flags[read_ptr_id] &= ~(DCAM1394_FLAG_READ_REQ_PROC);
+
+ /* increment read pointer */
+ ring_buff_read_ptr_incr(ring_buff_p, read_ptr_id);
+
+ mutex_exit(&softc_p->dcam_frame_is_done_mutex);
+
+ return (0);
+}
+
+
+/*
+ * dcam_ioctl
+ */
+/* ARGSUSED */
+int
+dcam_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p,
+ int *rvalp)
+{
+ dcam_state_t *softc_p;
+ dcam1394_param_list_t *param_list;
+ dcam1394_reg_io_t dcam_reg_io;
+ int instance, is_ctrl_file, rc, i;
+
+ rc = 0;
+ param_list = (dcam1394_param_list_t *)0;
+
+ instance = DEV_TO_INSTANCE(dev);
+
+ if ((softc_p = ddi_get_soft_state(dcam_state_p, instance)) == NULL) {
+ rc = ENXIO;
+ goto done;
+ }
+
+ /*
+ * determine user applications data model
+ */
+ if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32)
+ softc_p->usr_model = ILP32_PTR_SIZE;
+ else
+ softc_p->usr_model = LP64_PTR_SIZE;
+
+
+ switch (cmd) {
+
+ case DCAM1394_CMD_REG_READ:
+ if (ddi_copyin((caddr_t)arg, &dcam_reg_io,
+ sizeof (dcam1394_reg_io_t), mode)) {
+ rc = EFAULT;
+ goto done;
+ }
+
+ if (dcam_reg_read(softc_p, &dcam_reg_io)) {
+ rc = EFAULT;
+ goto done;
+ }
+
+ if (ddi_copyout(&dcam_reg_io, (caddr_t)arg,
+ sizeof (dcam1394_reg_io_t), mode)) {
+ rc = EFAULT;
+ goto done;
+ }
+ break;
+
+ case DCAM1394_CMD_REG_WRITE:
+ if (ddi_copyin((caddr_t)arg, &dcam_reg_io,
+ sizeof (dcam1394_reg_io_t), mode)) {
+ rc = EFAULT;
+ goto done;
+ }
+
+ if (dcam_reg_write(softc_p, &dcam_reg_io)) {
+ rc = EFAULT;
+ goto done;
+ }
+
+ if (ddi_copyout(&dcam_reg_io, (caddr_t)arg,
+ sizeof (dcam1394_reg_io_t), mode)) {
+ rc = EFAULT;
+ goto done;
+ }
+ break;
+
+ case DCAM1394_CMD_CAM_RESET:
+ if (dcam_reset(softc_p)) {
+ rc = EIO;
+ goto done;
+ }
+ break;
+
+ case DCAM1394_CMD_PARAM_GET:
+ param_list = (dcam1394_param_list_t *)
+ kmem_alloc(sizeof (dcam1394_param_list_t), KM_SLEEP);
+
+ if (ddi_copyin((caddr_t)arg, (caddr_t)param_list,
+ sizeof (dcam1394_param_list_t), mode)) {
+ rc = EFAULT;
+ goto done;
+ }
+
+ if (dcam1394_ioctl_param_get(softc_p, *param_list)) {
+ rc = EINVAL;
+ }
+
+ if (ddi_copyout((caddr_t)param_list, (caddr_t)arg,
+ sizeof (dcam1394_param_list_t), mode)) {
+ rc = EFAULT;
+ goto done;
+ }
+ break;
+
+ case DCAM1394_CMD_PARAM_SET:
+ param_list = (dcam1394_param_list_t *)
+ kmem_alloc((size_t)sizeof (dcam1394_param_list_t),
+ KM_SLEEP);
+
+ if (ddi_copyin((caddr_t)arg, (caddr_t)param_list,
+ sizeof (dcam1394_param_list_t), mode)) {
+ rc = EFAULT;
+ goto done;
+ }
+
+ is_ctrl_file = (getminor(dev) & DCAM1394_MINOR_CTRL) ? 1:0;
+
+ if (dcam1394_ioctl_param_set(softc_p, is_ctrl_file,
+ *param_list)) {
+ rc = EINVAL;
+ }
+
+ if (is_ctrl_file) {
+ mutex_enter(&softc_p->dcam_frame_is_done_mutex);
+ softc_p->param_status |= DCAM1394_STATUS_PARAM_CHANGE;
+ mutex_exit(&softc_p->dcam_frame_is_done_mutex);
+ }
+
+ if (ddi_copyout(param_list, (caddr_t)arg,
+ sizeof (dcam1394_param_list_t), mode)) {
+ rc = EFAULT;
+ goto done;
+ }
+ break;
+
+ case DCAM1394_CMD_FRAME_RCV_START:
+ if (dcam1394_ioctl_frame_rcv_start(softc_p)) {
+ rc = ENXIO;
+ }
+ break;
+
+ case DCAM1394_CMD_FRAME_RCV_STOP:
+ if (dcam_frame_rcv_stop(softc_p)) {
+ rc = ENXIO;
+ }
+ break;
+
+ case DCAM1394_CMD_RING_BUFF_FLUSH:
+ if (softc_p->ring_buff_p == NULL) {
+ rc = EAGAIN;
+ break;
+ }
+
+ /*
+ * the simplest way to flush ring_buff is to empty it
+ */
+ for (i = 0; i < softc_p->ring_buff_p->num_read_ptrs; i++) {
+ softc_p->ring_buff_p->read_ptr_pos[i] =
+ softc_p->ring_buff_p->write_ptr_pos;
+
+ /*
+ * if device driver is processing a user
+ * process's read() request
+ */
+ if (softc_p->reader_flags[i] &
+ DCAM1394_FLAG_READ_REQ_PROC) {
+
+ /*
+ * invalidate the read() request processing
+ * operation
+ */
+ softc_p->reader_flags[i] |=
+ DCAM1394_FLAG_READ_REQ_INVALID;
+ }
+ }
+ break;
+
+ case DCAM1394_CMD_FRAME_SEQ_NUM_COUNT_RESET:
+ mutex_enter(&softc_p->dcam_frame_is_done_mutex);
+ softc_p->seq_count = 0;
+ mutex_exit(&softc_p->dcam_frame_is_done_mutex);
+ break;
+
+ default:
+ rc = EIO;
+ break;
+
+ }
+
+done:
+ if (param_list)
+ kmem_free(param_list, sizeof (dcam1394_param_list_t));
+
+ return (rc);
+}
+
+
+/*
+ * dcam_chpoll
+ */
+/* ARGSUSED */
+int
+dcam_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
+ struct pollhead **phpp)
+{
+ dcam_state_t *softc_p;
+ int instance, ring_buff_has_data, read_ptr_id;
+ size_t read_ptr_pos, write_ptr_pos;
+ short revent;
+
+ instance = DEV_TO_INSTANCE(dev);
+
+ softc_p = (dcam_state_t *)ddi_get_soft_state(dcam_state_p, instance);
+ if (softc_p == NULL) {
+ return (ENXIO);
+ }
+
+ read_ptr_id = 0;
+ revent = 0;
+
+ if (softc_p->ring_buff_p == NULL) {
+ ring_buff_has_data = 0;
+ } else {
+ mutex_enter(&softc_p->dcam_frame_is_done_mutex);
+
+ read_ptr_pos =
+ ring_buff_read_ptr_pos_get(softc_p->ring_buff_p,
+ read_ptr_id);
+
+ write_ptr_pos =
+ ring_buff_write_ptr_pos_get(softc_p->ring_buff_p);
+
+ if (read_ptr_pos != write_ptr_pos) {
+ ring_buff_has_data = 1;
+ } else {
+ ring_buff_has_data = 0;
+ }
+
+ mutex_exit(&softc_p->dcam_frame_is_done_mutex);
+ }
+
+ /*
+ * now check for events
+ */
+ if ((events & POLLRDNORM) && ring_buff_has_data) {
+ revent |= POLLRDNORM;
+ }
+
+ if ((events & POLLPRI) && softc_p->param_status) {
+ revent |= POLLPRI;
+ }
+
+ /* if no events have occurred */
+ if (revent == 0) {
+ if (!anyyet) {
+ *phpp = &softc_p->dcam_pollhead;
+ }
+ }
+
+ *reventsp = revent;
+
+ return (0);
+}
+
+
+/*
+ * dcam_bus_reset_notify
+ */
+/* ARGSUSED */
+void
+dcam_bus_reset_notify(dev_info_t *dip, ddi_eventcookie_t ev_cookie, void *arg,
+ void *impl_data)
+{
+
+ dcam_state_t *softc_p;
+ t1394_localinfo_t *localinfo = impl_data;
+ t1394_targetinfo_t targetinfo;
+
+ softc_p = arg;
+
+ /*
+ * this is needed to handle LG camera "changing GUID" bug
+ * XXX: What's this about?
+ */
+ if ((dip == NULL) || (arg == NULL) || (impl_data == NULL) ||
+ (softc_p->sl_handle == NULL)) {
+ return;
+ }
+
+ localinfo = impl_data;
+
+ /*
+ * simply return if no target info
+ */
+ if (t1394_get_targetinfo(softc_p->sl_handle,
+ localinfo->bus_generation, 0, &targetinfo) != DDI_SUCCESS)
+ return;
+
+ if (localinfo->local_nodeID == softc_p->targetinfo.target_nodeID) {
+ softc_p->param_status |= DCAM1394_STATUS_CAM_UNPLUG;
+ } else {
+ softc_p->param_status &= ~DCAM1394_STATUS_CAM_UNPLUG;
+ }
+
+ /* struct copies */
+ softc_p->attachinfo.localinfo = *localinfo;
+
+ if (targetinfo.target_nodeID != T1394_INVALID_NODEID) {
+ softc_p->targetinfo.current_max_payload =
+ targetinfo.current_max_payload;
+
+ softc_p->targetinfo.current_max_speed =
+ targetinfo.current_max_speed;
+
+ softc_p->targetinfo.target_nodeID =
+ targetinfo.target_nodeID;
+ }
+}
+
+
+/*
+ * byte_copy_to_user_buff
+ */
+static int
+byte_copy_to_user_buff(uchar_t *src_addr_p, struct uio *uio_p, size_t num_bytes,
+ int start_index, int *end_index_p)
+{
+ int index;
+ size_t len;
+ uchar_t *u8_p;
+
+ index = start_index;
+ u8_p = (uchar_t *)src_addr_p;
+
+ while (num_bytes) {
+
+ len = num_bytes;
+
+ if (uiomove(u8_p, len, UIO_READ, uio_p)) {
+ return (-1);
+ }
+
+ index++;
+ u8_p += len;
+ num_bytes -= len;
+ }
+
+ *end_index_p = index;
+
+ return (0);
+}
+
+
+/*
+ * byte_copy_from_user_buff
+ */
+static int
+byte_copy_from_user_buff(uchar_t *dst_addr_p, struct uio *uio_p,
+ size_t num_bytes, int start_index, int *end_index_p)
+{
+ int index;
+ size_t len;
+ uchar_t *u8_p;
+
+ index = start_index;
+ u8_p = (uchar_t *)dst_addr_p;
+
+ while (num_bytes) {
+ len = num_bytes;
+
+ if (uiomove(u8_p, len, UIO_WRITE, uio_p)) {
+ return (-1);
+
+ }
+
+ index++;
+ u8_p += len;
+ num_bytes -= len;
+
+ }
+
+ *end_index_p = index;
+
+ return (0);
+}
+
+
+/*
+ * dcam_reset()
+ */
+static int
+dcam_reset(dcam_state_t *softc_p)
+{
+ dcam1394_reg_io_t dcam_reg_io;
+
+ dcam_reg_io.offs = DCAM1394_REG_OFFS_INITIALIZE;
+ dcam_reg_io.val = DCAM1394_REG_VAL_INITIALIZE_ASSERT;
+
+ if (dcam_reg_write(softc_p, &dcam_reg_io)) {
+ return (-1);
+ }
+
+ /*
+ * If the camera has a TI VSP, tweak the iris feature
+ * to "on" and value 4.
+ */
+ dcam_reg_io.offs = DCAM1394_REG_OFFS_FEATURE_CSR_BASE +
+ DCAM1394_REG_OFFS_IRIS_CSR;
+ dcam_reg_io.val = 0x82000004;
+
+ if (dcam_reg_write(softc_p, &dcam_reg_io)) {
+ return (-1);
+ }
+
+ return (0);
+}
diff --git a/usr/src/uts/common/io/1394/targets/dcam1394/dcam_frame.c b/usr/src/uts/common/io/1394/targets/dcam1394/dcam_frame.c
new file mode 100644
index 0000000000..d7bf12aa0f
--- /dev/null
+++ b/usr/src/uts/common/io/1394/targets/dcam1394/dcam_frame.c
@@ -0,0 +1,644 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * dcam_frame.c
+ *
+ * dcam1394 driver. Support for video frame access.
+ */
+
+#include <sys/int_limits.h>
+#include <sys/types.h>
+#include <sys/kmem.h>
+#include <sys/cmn_err.h>
+#include <sys/1394/targets/dcam1394/dcam.h>
+#include <sys/1394/targets/dcam1394/dcam_frame.h>
+#include <sys/tnf_probe.h>
+#include <sys/dcam/dcam1394_io.h>
+
+#include <sys/1394/targets/dcam1394/dcam_reg.h>
+
+static void dcam_free_resources(dcam_state_t *);
+
+typedef struct dcam_mode_info_s {
+ int bytes_per_pkt;
+ int pkts_per_frame;
+} dcam_mode_info_t;
+
+/*
+ * packets per frame
+ *
+ * 30fps
+ * mode_0 1/2h, 60q, 240b
+ * mode_1 1h, 160q, 640
+ * mode_2 2h, 480q, 1920
+ * mode_3 2h, 640q, 2560
+ * mode_4 2h, 960q, 3840
+ * mode_5 2h, 320q, 1280
+ *
+ * 15fps
+ * mode_0 1/4h, 30q, 120
+ * mode_1 1/2h, 80q, 320
+ * mode_2 1h, 240q, 960
+ * mode_3 1h, 320q, 1280
+ * mode_4 1h, 480q, 1920
+ * mode_5 1h, 160q, 640
+ *
+ * 7.5fps
+ * mode_0 1/8h, 15q, 60
+ * mode_1 1/4h, 40q, 160
+ * mode_2 1/2h, 120q, 480
+ * mode_3 1/2h, 160q, 640
+ * mode_4 1/2h, 240q, 960
+ * mode_5 1/2h, 80q, 320
+ *
+ * 3.75fps
+ * mode_0 x
+ * mode_1 1/8h, 20q, 80
+ * mode_2 1/4h, 60q, 240
+ * mode_3 1/4h, 80q, 320
+ * mode_4 1/4h, 120q, 480
+ * mode_5 1/4h, 40q, 160
+ *
+ * 60fps
+ * mode_5 4H, 640q, 2560
+ *
+ */
+
+/* indexed by vid mode, frame rate */
+static int g_bytes_per_packet[6][5] = {
+
+ /* fps: 3.75 7.5 15 30 60 */
+ /* vid mode 0 */ -1, 60, 120, 240, -1,
+ /* vid mode 1 */ 80, 160, 320, 640, -1,
+ /* vid mode 2 */ 240, 480, 960, 1920, -1,
+ /* vid mode 3 */ 320, 640, 1280, 2560, -1,
+ /* vid mode 4 */ 480, 960, 1920, 3840, -1,
+ /* vid mode 5 */ 160, 320, 640, 1280, 2560
+};
+
+/* indexed by vid mode */
+static int g_bytes_per_frame[6] = {
+ 57600,
+ 153600,
+ 460800,
+ 614400,
+ 921600,
+ 307200
+};
+
+
+static
+void dcam_rsrc_fail(t1394_isoch_single_handle_t t1394_single_hdl,
+ opaque_t single_evt_arg, t1394_isoch_rsrc_error_t fail_args);
+
+/*
+ * dcam1394_ioctl_frame_rcv_start
+ */
+int
+dcam1394_ioctl_frame_rcv_start(dcam_state_t *softc_p)
+{
+ if (!(softc_p->flags & DCAM1394_FLAG_FRAME_RCV_INIT)) {
+
+ if (dcam_frame_rcv_init(softc_p, softc_p->cur_vid_mode,
+ softc_p->cur_frame_rate, softc_p->cur_ring_buff_capacity)) {
+
+ dcam_free_resources(softc_p);
+ return (1);
+ }
+
+ softc_p->flags |= DCAM1394_FLAG_FRAME_RCV_INIT;
+ }
+
+ if (dcam_frame_rcv_start(softc_p)) {
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * dcam_frame_rcv_init
+ */
+int
+dcam_frame_rcv_init(dcam_state_t *softc_p, int vid_mode, int frame_rate,
+ int ring_buff_capacity)
+{
+ int16_t bytes_per_pkt; /* # pkt bytes + overhead */
+ int bytes_per_frame;
+ size_t frame;
+ int cookie;
+ int failure;
+ id1394_isoch_dmainfo_t isoch_args; /* for alloc isoch call */
+ ixl1394_command_t *last_ixlp; /* last ixl in chain, */
+ /* used for appending ixls */
+ ixl1394_command_t *new_ixl_cmdp; /* new ixl command */
+ ixl1394_set_syncwait_t *new_ixl_sswp; /* new ixl set syncwait */
+ ixl1394_xfer_pkt_t *new_ixl_xfpp; /* new ixl xfer packet */
+ ixl1394_xfer_buf_t *new_ixl_xfbp; /* new ixl xfer buffer */
+ ixl1394_callback_t *new_ixl_cbp; /* new ixl callback */
+ ixl1394_jump_t *new_ixl_jmpp; /* new ixl jump */
+ int32_t result; /* errno from alloc_isoch_dma */
+ buff_info_t *buff_info_p;
+ dcam1394_reg_io_t reg_io;
+ uint_t data;
+ size_t num_bytes, num_bytes_left;
+ size_t num_xfer_cmds, xfer_cmd;
+ size_t max_ixl_buff_size;
+ caddr_t ixl_buff_kaddr, ixl_buff_vaddr;
+
+ bytes_per_pkt = g_bytes_per_packet[vid_mode][frame_rate];
+ if (bytes_per_pkt == -1) {
+ return (1);
+ }
+
+ bytes_per_frame = g_bytes_per_frame[vid_mode];
+
+ if ((softc_p->ring_buff_p = ring_buff_create(softc_p,
+ (size_t)ring_buff_capacity, (size_t)bytes_per_frame)) == NULL) {
+ return (1);
+ }
+
+ softc_p->ring_buff_p->read_ptr_pos[0] = 0;
+
+ /* allocate isoch channel */
+ softc_p->sii.si_channel_mask = 0xFFFF000000000000;
+ softc_p->sii.si_bandwidth = bytes_per_pkt;
+ softc_p->sii.rsrc_fail_target = dcam_rsrc_fail;
+ softc_p->sii.single_evt_arg = softc_p;
+ softc_p->sii.si_speed = softc_p->targetinfo.current_max_speed;
+
+ if (t1394_alloc_isoch_single(softc_p->sl_handle,
+ &softc_p->sii, 0, &softc_p->sii_output_args, &softc_p->sii_hdl,
+ &failure) != DDI_SUCCESS) {
+ return (1);
+ }
+
+ /*
+ * At this point, all buffer memory has been allocated and
+ * mapped, and is tracked on a linear linked list. Now need to
+ * build the IXL. Done on a frame-by-frame basis. Could
+ * theoretically have been done at the same time as the mem alloc
+ * above, but hey, no need to be so fancy here.
+ *
+ * ixl buff size is bound by SHRT_MAX and needs to
+ * be a multiple of packet size
+ */
+ max_ixl_buff_size = (SHRT_MAX / bytes_per_pkt) * bytes_per_pkt;
+
+ /* for each frame build frame's ixl list */
+ for (frame = 0; frame < softc_p->ring_buff_p->num_buffs; frame++) {
+
+ buff_info_p = &(softc_p->ring_buff_p->buff_info_array_p[frame]);
+
+ /*
+ * if this is the 1st frame, put a IXL label at the top so a
+ * loop can be created later
+ */
+ if (frame == 0) {
+ new_ixl_cmdp = kmem_zalloc(
+ sizeof (ixl1394_label_t), KM_SLEEP);
+ softc_p->ixlp = new_ixl_cmdp;
+
+ new_ixl_cmdp->ixl_opcode = IXL1394_OP_LABEL;
+
+ last_ixlp = softc_p->ixlp;
+ }
+
+ /* add wait-for-sync IXL command */
+ new_ixl_sswp = kmem_zalloc(
+ sizeof (ixl1394_set_syncwait_t), KM_SLEEP);
+
+ new_ixl_sswp->ixl_opcode = IXL1394_OP_SET_SYNCWAIT;
+
+ last_ixlp->next_ixlp = (ixl1394_command_t *)new_ixl_sswp;
+ last_ixlp = (ixl1394_command_t *)new_ixl_sswp;
+
+ /* add in each dma cookie */
+ for (cookie = 0; cookie < buff_info_p->dma_cookie_count;
+ cookie++) {
+
+ num_xfer_cmds = min(bytes_per_frame,
+ buff_info_p->dma_cookie.dmac_size) /
+ max_ixl_buff_size;
+
+ if (min(bytes_per_frame,
+ buff_info_p->dma_cookie.dmac_size) %
+ max_ixl_buff_size) {
+ num_xfer_cmds++;
+ }
+
+ num_bytes_left = min(bytes_per_frame,
+ buff_info_p->dma_cookie.dmac_size);
+
+ ixl_buff_kaddr = (caddr_t)
+ buff_info_p->dma_cookie.dmac_laddress;
+
+ ixl_buff_vaddr = buff_info_p->kaddr_p;
+
+ for (xfer_cmd = 0; xfer_cmd < (num_xfer_cmds + 1);
+ xfer_cmd++) {
+ num_bytes = min(num_bytes_left,
+ max_ixl_buff_size);
+
+ if (xfer_cmd == 0) {
+ new_ixl_xfpp =
+ kmem_zalloc(
+ sizeof (ixl1394_xfer_pkt_t),
+ KM_SLEEP);
+
+ new_ixl_xfpp->ixl_opcode =
+ IXL1394_OP_RECV_PKT_ST;
+
+ new_ixl_xfpp->ixl_buf._dmac_ll =
+ (uint64_t)ixl_buff_kaddr;
+ new_ixl_xfpp->size =
+ (uint16_t)bytes_per_pkt;
+ new_ixl_xfpp->mem_bufp =
+ ixl_buff_vaddr;
+
+ last_ixlp->next_ixlp =
+ (ixl1394_command_t *)new_ixl_xfpp;
+ last_ixlp =
+ (ixl1394_command_t *)new_ixl_xfpp;
+
+ num_bytes_left -= bytes_per_pkt;
+ ixl_buff_kaddr += bytes_per_pkt;
+ ixl_buff_vaddr += bytes_per_pkt;
+
+ continue;
+ }
+
+ /* allocate & init an IXL transfer command. */
+ new_ixl_xfbp =
+ kmem_zalloc(sizeof (ixl1394_xfer_buf_t),
+ KM_SLEEP);
+
+ new_ixl_xfbp->ixl_opcode = IXL1394_OP_RECV_BUF;
+
+ new_ixl_xfbp->ixl_buf._dmac_ll =
+ (uint64_t)ixl_buff_kaddr;
+ new_ixl_xfbp->size = (uint16_t)num_bytes;
+ new_ixl_xfbp->pkt_size = bytes_per_pkt;
+ new_ixl_xfbp->mem_bufp = ixl_buff_vaddr;
+
+ last_ixlp->next_ixlp =
+ (ixl1394_command_t *)new_ixl_xfbp;
+ last_ixlp =
+ (ixl1394_command_t *)new_ixl_xfbp;
+
+ num_bytes_left -= num_bytes;
+ ixl_buff_kaddr += num_bytes;
+ ixl_buff_vaddr += num_bytes;
+ }
+
+ if (cookie > 0) {
+ ddi_dma_nextcookie(buff_info_p->dma_handle,
+ &(buff_info_p->dma_cookie));
+ }
+
+ }
+
+ /*
+ * at this point, have finished a frame. put in a callback
+ */
+ new_ixl_cbp = kmem_zalloc(
+ sizeof (ixl1394_callback_t), KM_SLEEP);
+
+ new_ixl_cbp->ixl_opcode = IXL1394_OP_CALLBACK;
+
+ new_ixl_cbp->callback = &dcam_frame_is_done;
+ new_ixl_cbp->callback_arg = NULL;
+
+ last_ixlp->next_ixlp = (ixl1394_command_t *)new_ixl_cbp;
+ last_ixlp = (ixl1394_command_t *)new_ixl_cbp;
+ }
+
+ /*
+ * for the final touch, put an IXL jump at the end to jump to the
+ * label at the top
+ */
+ new_ixl_jmpp = kmem_zalloc(sizeof (ixl1394_jump_t), KM_SLEEP);
+
+ new_ixl_jmpp->ixl_opcode = IXL1394_OP_JUMP;
+
+ new_ixl_jmpp->label = softc_p->ixlp;
+
+ last_ixlp->next_ixlp = (ixl1394_command_t *)new_ixl_jmpp;
+
+ /* don't need this, but it's neater */
+ last_ixlp = (ixl1394_command_t *)new_ixl_jmpp;
+
+ /* call fwim routine to alloc an isoch resource */
+ isoch_args.ixlp = softc_p->ixlp;
+ isoch_args.channel_num = softc_p->sii_output_args.channel_num;
+
+ /* other misc args. note speed doesn't matter for isoch receive */
+ isoch_args.idma_options = ID1394_LISTEN_PKT_MODE;
+ isoch_args.default_tag = 0;
+ isoch_args.default_sync = 1;
+ isoch_args.global_callback_arg = softc_p;
+
+ /* set the ISO channel number */
+ data = (softc_p->sii_output_args.channel_num & 0xF) << 28;
+
+ /* set the ISO speed */
+ data |= (softc_p->targetinfo.current_max_speed << 24);
+
+ reg_io.offs = DCAM1394_REG_OFFS_CUR_ISO_CHANNEL;
+ reg_io.val = data;
+
+ if (dcam_reg_write(softc_p, &reg_io)) {
+ return (1);
+ }
+
+ result = 1234;
+
+ if (t1394_alloc_isoch_dma(softc_p->sl_handle, &isoch_args, 0,
+ &softc_p->isoch_handle, &result) != DDI_SUCCESS) {
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * dcam_frame_rcv_fini
+ */
+int
+dcam_frame_rcv_fini(dcam_state_t *softc_p)
+{
+ t1394_free_isoch_dma(softc_p->sl_handle, 0, &softc_p->isoch_handle);
+
+ softc_p->isoch_handle = NULL;
+
+ t1394_free_isoch_single(softc_p->sl_handle, &softc_p->sii_hdl, 0);
+
+ return (0);
+}
+
+
+/*
+ * dcam_frame_rcv_start
+ */
+int
+dcam_frame_rcv_start(dcam_state_t *softc_p)
+{
+ id1394_isoch_dma_ctrlinfo_t idma_ctrlinfo; /* currently not used */
+ int32_t result;
+ dcam1394_reg_io_t reg_io;
+
+ if ((t1394_start_isoch_dma(softc_p->sl_handle, softc_p->isoch_handle,
+ &idma_ctrlinfo, 0, &result)) != DDI_SUCCESS) {
+ return (1);
+ }
+
+ reg_io.offs = DCAM1394_REG_OFFS_ISO_EN;
+ reg_io.val = 0x80000000;
+
+ if (dcam_reg_write(softc_p, &reg_io)) {
+ return (1);
+ }
+
+ softc_p->flags |= DCAM1394_FLAG_FRAME_RCVING;
+
+ return (0);
+}
+
+
+/*
+ * dcam_frame_rcv_stop
+ */
+int
+dcam_frame_rcv_stop(dcam_state_t *softc_p)
+{
+ dcam1394_reg_io_t reg_io;
+
+ /* if resources have already been cleared, nothing to do */
+ if (!(softc_p->flags & DCAM1394_FLAG_FRAME_RCV_INIT)) {
+ return (0);
+ }
+
+ reg_io.offs = DCAM1394_REG_OFFS_ISO_EN;
+ reg_io.val = 0;
+
+ (void) dcam_reg_write(softc_p, &reg_io);
+
+ t1394_stop_isoch_dma(softc_p->sl_handle, softc_p->isoch_handle, 0);
+ t1394_free_isoch_dma(softc_p->sl_handle, 0, &softc_p->isoch_handle);
+ t1394_free_isoch_single(softc_p->sl_handle, &softc_p->sii_hdl, 0);
+
+ dcam_free_resources(softc_p);
+
+ return (0);
+}
+
+
+void
+dcam_free_resources(dcam_state_t *softc_p)
+{
+ ixl1394_command_t *ptr;
+ ixl1394_command_t *tmp;
+
+ /*
+ * The following fixes a memory leak. See bug #4423667.
+ * The original code only released memory for the first frame.
+ */
+
+ /* free ixl opcode resources */
+ ptr = softc_p->ixlp;
+
+ while (ptr != NULL) {
+ tmp = ptr;
+ ptr = ptr->next_ixlp;
+
+ switch (tmp->ixl_opcode) {
+ case IXL1394_OP_LABEL:
+ kmem_free(tmp, sizeof (ixl1394_label_t));
+ break;
+
+ case IXL1394_OP_SET_SYNCWAIT:
+ kmem_free(tmp, sizeof (ixl1394_set_syncwait_t));
+ break;
+
+ case IXL1394_OP_RECV_PKT_ST:
+ kmem_free(tmp, sizeof (ixl1394_xfer_pkt_t));
+ break;
+
+ case IXL1394_OP_RECV_BUF:
+ kmem_free(tmp, sizeof (ixl1394_xfer_buf_t));
+ break;
+
+ case IXL1394_OP_CALLBACK:
+ kmem_free(tmp, sizeof (ixl1394_callback_t));
+ break;
+
+ case IXL1394_OP_JUMP:
+ kmem_free(tmp, sizeof (ixl1394_jump_t));
+ break;
+ }
+ }
+
+ /*
+ * free ring buff and indicate that the resources have been cleared
+ */
+ ring_buff_free(softc_p, softc_p->ring_buff_p);
+
+ softc_p->flags &= ~DCAM1394_FLAG_FRAME_RCV_INIT;
+ softc_p->ixlp = NULL;
+}
+
+
+/*
+ * dcam_frame_is_done
+ *
+ * This routine is called after DMA engine has stored a single received
+ * frame in ring buffer position pointed to by write pointer; this
+ * routine marks the frame's vid mode, timestamp, and sequence number
+ *
+ * Store received frame in ring buffer position pointed to by write pointer.
+ * Increment write pointer. If write pointer is pointing to the same
+ * position as read pointer, increment read pointer.
+ *
+ * If device driver is processing a user process's read() request
+ * invalidate the read() request processing operation.
+ *
+ */
+
+/* ARGSUSED */
+void
+dcam_frame_is_done(void *ssp, ixl1394_callback_t *ixlp)
+{
+ dcam_state_t *softc_p;
+ int num_read_ptrs;
+ int read_ptr_id;
+ int vid_mode;
+ size_t write_ptr_pos;
+ ring_buff_t *ring_buff_p;
+ unsigned int seq_num;
+
+ /*
+ * Store received frame in ring buffer position pointed to by
+ * write pointer (this routine is called after DMA engine has
+ * stored a single received frame in ring buffer position pointed
+ * to by write pointer; this routine marks the frame's vid mode,
+ * timestamp, and sequence number)
+ */
+
+ if ((softc_p = (dcam_state_t *)ssp) == NULL) {
+ return;
+ }
+
+ if ((ring_buff_p = softc_p->ring_buff_p) == NULL) {
+ return;
+ }
+
+ mutex_enter(&softc_p->dcam_frame_is_done_mutex);
+
+ write_ptr_pos = ring_buff_write_ptr_pos_get(ring_buff_p);
+
+ /* mark vid mode */
+ vid_mode =
+ softc_p->
+ param_attr[DCAM1394_PARAM_VID_MODE][DCAM1394_SUBPARAM_NONE];
+ ring_buff_p->buff_info_array_p[write_ptr_pos].vid_mode = vid_mode;
+
+
+ /* update sequence counter overflow in param_status */
+ if (softc_p->seq_count == 0xffffffff)
+ softc_p->param_status |=
+ DCAM1394_STATUS_FRAME_SEQ_NUM_COUNT_OVERFLOW;
+
+
+ /* mark frame's sequence number */
+ ring_buff_p->buff_info_array_p[write_ptr_pos].seq_num =
+ softc_p->seq_count++;
+
+ seq_num = ring_buff_p->buff_info_array_p[write_ptr_pos].seq_num;
+
+
+ /* mark frame's timestamp */
+ ring_buff_p->buff_info_array_p[write_ptr_pos].timestamp = gethrtime();
+
+
+ /* increment write pointer */
+ ring_buff_write_ptr_incr(ring_buff_p);
+
+ num_read_ptrs = 1;
+
+ for (read_ptr_id = 0; read_ptr_id < num_read_ptrs; read_ptr_id++) {
+
+ /*
+ * if write pointer is pointing to the same position as
+ * read pointer
+ */
+
+ if ((ring_buff_write_ptr_pos_get(ring_buff_p) ==
+ ring_buff_read_ptr_pos_get(ring_buff_p, read_ptr_id)) &&
+ (seq_num != 0)) {
+
+ /* increment read pointer */
+ ring_buff_read_ptr_incr(ring_buff_p, read_ptr_id);
+
+ /*
+ * if device driver is processing a user
+ * process's read() request
+ */
+ if (softc_p->reader_flags[read_ptr_id] &
+ DCAM1394_FLAG_READ_REQ_PROC) {
+
+ /*
+ * invalidate the read() request processing
+ * operation
+ */
+ softc_p->reader_flags[read_ptr_id] |=
+ DCAM1394_FLAG_READ_REQ_INVALID;
+ }
+
+ /* inform user app that we have lost one frame */
+ softc_p->param_status |=
+ DCAM1394_STATUS_RING_BUFF_LOST_FRAME;
+ }
+ }
+
+ /* inform user app that we have received one frame */
+ softc_p->param_status |= DCAM1394_STATUS_FRAME_RCV_DONE;
+
+ mutex_exit(&softc_p->dcam_frame_is_done_mutex);
+}
+
+
+/* ARGSUSED */
+static void
+dcam_rsrc_fail(t1394_isoch_single_handle_t t1394_single_hdl,
+ opaque_t single_evt_arg, t1394_isoch_rsrc_error_t fail_args)
+{
+ cmn_err(CE_NOTE, "dcam_rsrc_fail(): unable to re-alloc resources\n");
+}
diff --git a/usr/src/uts/common/io/1394/targets/dcam1394/dcam_param.c b/usr/src/uts/common/io/1394/targets/dcam1394/dcam_param.c
new file mode 100644
index 0000000000..445d3ae04d
--- /dev/null
+++ b/usr/src/uts/common/io/1394/targets/dcam1394/dcam_param.c
@@ -0,0 +1,1803 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * dcam_param.c
+ *
+ * dcam1394 driver. Device parameter access.
+ */
+
+#include <sys/1394/targets/dcam1394/dcam.h>
+#include <sys/1394/targets/dcam1394/dcam_param.h>
+#include <sys/1394/targets/dcam1394/dcam_reg.h>
+#include <sys/tnf_probe.h>
+
+/* index by vid_mode */
+int g_frame_num_bytes[] = {
+ 57600, /* vid mode 0 */
+ 153600, /* vid mode 1 */
+ 460800, /* vid mode 2 */
+ 614400, /* vid mode 3 */
+ 921600, /* vid mode 4 */
+ 307200 /* vid mode 5 */
+};
+
+
+static uint_t feature_csr_val_construct(uint_t subparam, uint_t param_val,
+ uint_t init_val);
+static uint_t feature_csr_val_subparam_extract(uint_t subparam,
+ uint_t feature_csr_val);
+static uint_t feature_elm_inq_reg_val_subparam_extract(uint_t subparam,
+ uint_t reg_val);
+
+
+/*
+ * param_attr_init
+ */
+int
+param_attr_init(dcam_state_t *softc_p, dcam1394_param_attr_t param_attr)
+{
+ int err, ret_err;
+ uint_t attr_bmap, cap_on_off, cap_power_ctrl, cap_read;
+ uint_t param, presence, subparam;
+
+ bzero(param_attr, sizeof (dcam1394_param_attr_t));
+
+ ret_err = DDI_SUCCESS;
+
+ /*
+ * power ctrl cap
+ */
+ param = DCAM1394_PARAM_CAP_POWER_CTRL;
+ subparam = DCAM1394_SUBPARAM_NONE;
+ attr_bmap = IS_VALID | IS_PRESENT | CAP_GET;
+ param_attr_set(param_attr, param, subparam, attr_bmap);
+
+ /*
+ * video mode cap
+ */
+ param = DCAM1394_PARAM_CAP_VID_MODE;
+ attr_bmap = IS_VALID | IS_PRESENT | CAP_GET;
+
+ for (subparam = DCAM1394_SUBPARAM_VID_MODE_0;
+ subparam <= DCAM1394_SUBPARAM_VID_MODE_5; subparam++) {
+ param_attr_set(param_attr, param, subparam, attr_bmap);
+ }
+
+ /*
+ * frame rate cap
+ */
+ attr_bmap = IS_VALID | IS_PRESENT | CAP_GET;
+
+ for (param = DCAM1394_PARAM_CAP_FRAME_RATE_VID_MODE_0;
+ param <= DCAM1394_PARAM_CAP_FRAME_RATE_VID_MODE_5; param++) {
+
+ for (subparam = DCAM1394_SUBPARAM_FRAME_RATE_0;
+ subparam <= DCAM1394_SUBPARAM_FRAME_RATE_4; subparam++) {
+ param_attr_set(param_attr, param, subparam, attr_bmap);
+ }
+ }
+
+ /*
+ * power
+ */
+ param = DCAM1394_PARAM_POWER;
+ subparam = DCAM1394_SUBPARAM_NONE;
+ err = dcam1394_param_get(softc_p, DCAM1394_PARAM_CAP_POWER_CTRL,
+ DCAM1394_SUBPARAM_NONE, &cap_power_ctrl);
+ attr_bmap = IS_VALID | IS_PRESENT | CAP_GET;
+
+ if (cap_power_ctrl) {
+ attr_bmap |= CAP_SET;
+ }
+ param_attr_set(param_attr, param, subparam, attr_bmap);
+
+ /*
+ * video mode
+ */
+ param = DCAM1394_PARAM_VID_MODE;
+ subparam = DCAM1394_SUBPARAM_NONE;
+ attr_bmap = IS_VALID | IS_PRESENT | CAP_GET | CAP_SET;
+ param_attr_set(param_attr, param, subparam, attr_bmap);
+
+ /*
+ * frame rate
+ */
+ param = DCAM1394_PARAM_FRAME_RATE;
+ subparam = DCAM1394_SUBPARAM_NONE;
+ attr_bmap = IS_VALID | IS_PRESENT | CAP_GET | CAP_SET;
+ param_attr_set(param_attr, param, subparam, attr_bmap);
+
+ /*
+ * ring buffer capacity
+ */
+ param = DCAM1394_PARAM_RING_BUFF_CAPACITY;
+ subparam = DCAM1394_SUBPARAM_NONE;
+ attr_bmap = IS_VALID | IS_PRESENT | CAP_GET | CAP_SET;
+ param_attr_set(param_attr, param, subparam, attr_bmap);
+
+ /*
+ * ring buffer: num frames ready
+ */
+ param = DCAM1394_PARAM_RING_BUFF_NUM_FRAMES_READY;
+ subparam = DCAM1394_SUBPARAM_NONE;
+ attr_bmap = IS_VALID | IS_PRESENT | CAP_GET;
+ param_attr_set(param_attr, param, subparam, attr_bmap);
+
+ /*
+ * ring buffer: read ptr increment stride
+ */
+ param = DCAM1394_PARAM_RING_BUFF_READ_PTR_INCR;
+ subparam = DCAM1394_SUBPARAM_NONE;
+ attr_bmap = IS_VALID | IS_PRESENT | CAP_GET | CAP_SET;
+ param_attr_set(param_attr, param, subparam, attr_bmap);
+
+ /*
+ * frame size
+ */
+ param = DCAM1394_PARAM_FRAME_NUM_BYTES;
+ subparam = DCAM1394_SUBPARAM_NONE;
+ attr_bmap = IS_VALID | IS_PRESENT | CAP_GET;
+ param_attr_set(param_attr, param, subparam, attr_bmap);
+
+ /*
+ * cam status
+ */
+ param = DCAM1394_PARAM_STATUS;
+ subparam = DCAM1394_SUBPARAM_NONE;
+ attr_bmap = IS_VALID | IS_PRESENT | CAP_GET;
+ param_attr_set(param_attr, param, subparam, attr_bmap);
+
+ /*
+ * features
+ */
+ for (param = DCAM1394_PARAM_BRIGHTNESS; param <= DCAM1394_PARAM_TILT;
+ param++) {
+
+ /*
+ * get feature presence
+ * If the operation to read the parameter fails, then act as
+ * though the feature is not implemented (because it isn't),
+ * don't report a DDI failure (as was previously done).
+ */
+ err = dcam1394_param_get(softc_p, param,
+ DCAM1394_SUBPARAM_PRESENCE, &presence);
+
+ if (!err) {
+ /* feature presence */
+ subparam = DCAM1394_SUBPARAM_PRESENCE;
+ attr_bmap = IS_VALID | IS_PRESENT | CAP_GET;
+ param_attr_set(param_attr, param, subparam, attr_bmap);
+
+ if (presence) {
+ /* feature cap read */
+ subparam = DCAM1394_SUBPARAM_CAP_READ;
+ attr_bmap = IS_VALID | IS_PRESENT | CAP_GET;
+ param_attr_set(param_attr, param,
+ subparam, attr_bmap);
+
+ /* feature cap on/off */
+ subparam = DCAM1394_SUBPARAM_CAP_ON_OFF;
+ attr_bmap = IS_VALID | IS_PRESENT | CAP_GET;
+ param_attr_set(param_attr, param,
+ subparam, attr_bmap);
+
+ /* feature cap ctrl auto */
+ subparam = DCAM1394_SUBPARAM_CAP_CTRL_AUTO;
+ attr_bmap = IS_VALID | IS_PRESENT | CAP_GET;
+ param_attr_set(param_attr, param,
+ subparam, attr_bmap);
+
+ /* feature cap ctrl manual */
+ subparam = DCAM1394_SUBPARAM_CAP_CTRL_MANUAL;
+ attr_bmap = IS_VALID | IS_PRESENT | CAP_GET;
+ param_attr_set(param_attr, param,
+ subparam, attr_bmap);
+
+ /* feature min val */
+ subparam = DCAM1394_SUBPARAM_MIN_VAL;
+ attr_bmap = IS_VALID | IS_PRESENT | CAP_GET;
+ param_attr_set(param_attr, param,
+ subparam, attr_bmap);
+
+ /* feature max val */
+ subparam = DCAM1394_SUBPARAM_MAX_VAL;
+ attr_bmap = IS_VALID | IS_PRESENT | CAP_GET;
+ param_attr_set(param_attr, param,
+ subparam, attr_bmap);
+
+ /* feature on/off */
+ subparam = DCAM1394_SUBPARAM_ON_OFF;
+
+ err = dcam1394_param_get(softc_p, param,
+ DCAM1394_SUBPARAM_CAP_ON_OFF, &cap_on_off);
+
+ attr_bmap = IS_VALID | IS_PRESENT | CAP_GET;
+
+ if (cap_on_off) {
+ attr_bmap |= (CAP_SET | CAP_CTRL_SET);
+ }
+
+ param_attr_set(param_attr, param,
+ subparam, attr_bmap);
+
+ /* feature control mode */
+ subparam = DCAM1394_SUBPARAM_CTRL_MODE;
+ attr_bmap = IS_VALID | IS_PRESENT | CAP_GET |
+ CAP_SET | CAP_CTRL_SET;
+
+ param_attr_set(param_attr, param,
+ subparam, attr_bmap);
+
+ /* get value read-out capability */
+ err = dcam1394_param_get(softc_p, param,
+ DCAM1394_SUBPARAM_CAP_READ,
+ &cap_read);
+
+ if (param == DCAM1394_PARAM_WHITE_BALANCE) {
+ /*
+ * white balance feature: u, v value
+ */
+ subparam = DCAM1394_SUBPARAM_U_VALUE;
+ attr_bmap = IS_VALID | IS_PRESENT |
+ CAP_SET | CAP_CTRL_SET;
+
+ if (cap_read) {
+ attr_bmap |= CAP_GET;
+ }
+
+ param_attr_set(param_attr, param,
+ subparam, attr_bmap);
+
+ subparam = DCAM1394_SUBPARAM_V_VALUE;
+ attr_bmap = IS_VALID | IS_PRESENT |
+ CAP_SET | CAP_CTRL_SET;
+
+ if (cap_read) {
+ attr_bmap |= CAP_GET;
+ }
+
+ param_attr_set(param_attr, param,
+ subparam, attr_bmap);
+
+ } else {
+ /* feature value */
+ subparam = DCAM1394_SUBPARAM_VALUE;
+ attr_bmap = IS_VALID | IS_PRESENT |
+ CAP_SET | CAP_CTRL_SET;
+
+ if (cap_read) {
+ attr_bmap |= CAP_GET;
+ }
+
+ param_attr_set(param_attr, param,
+ subparam, attr_bmap);
+ }
+
+ }
+
+ }
+ }
+
+ return (ret_err);
+}
+
+
+/*
+ * param_attr_set
+ */
+void
+param_attr_set(dcam1394_param_attr_t param_attr, uint_t param,
+ uint_t subparam, uint_t attr_bmap)
+{
+ param_attr[param][subparam] = attr_bmap;
+}
+
+
+/*
+ * dcam1394_ioctl_param_get
+ *
+ * softc's param_attr field must be initialized via param_attr_init()
+ * before using this function.
+ */
+int
+dcam1394_ioctl_param_get(dcam_state_t *softc_p,
+ dcam1394_param_list_t param_list)
+{
+ int err, ret_err;
+ int param, subparam;
+ uint_t cap_get, is_present, is_valid, val;
+
+ ret_err = 0;
+
+ for (param = 0; param < DCAM1394_NUM_PARAM; param++) {
+ for (subparam = 0;
+ subparam < DCAM1394_NUM_SUBPARAM;
+ subparam++) {
+
+ if (param_list[param][subparam].flag) {
+ is_valid =
+ softc_p->param_attr[param][subparam] &
+ IS_VALID;
+ is_present =
+ softc_p->param_attr[param][subparam] &
+ IS_PRESENT;
+ cap_get =
+ softc_p->param_attr[param][subparam] &
+ CAP_GET;
+
+ if (is_valid && is_present && cap_get) {
+ if (err = dcam1394_param_get(softc_p,
+ param, subparam, &val)) {
+
+ param_list[param][subparam].err = 1;
+ ret_err = 1;
+ }
+
+ if (!err) {
+ param_list[param][subparam].val =
+ val;
+ }
+ } else {
+ param_list[param][subparam].err = 1;
+ ret_err = 1;
+ }
+ }
+ }
+ }
+
+ return (ret_err);
+}
+
+
+/*
+ * dcam1394_ioctl_param_set
+ * softc's param_attr field must be initialized via param_attr_init()
+ * before using this function.
+ */
+int
+dcam1394_ioctl_param_set(dcam_state_t *softc_p, int is_ctrl_file,
+ dcam1394_param_list_t param_list)
+{
+ int param, subparam;
+ int ret_err;
+ uint_t cap_set, is_present, is_valid, val;
+
+ ret_err = 0;
+
+ for (param = 0; param < DCAM1394_NUM_PARAM; param++) {
+ for (subparam = 0;
+ subparam < DCAM1394_NUM_SUBPARAM;
+ subparam++) {
+ if (param_list[param][subparam].flag) {
+ is_valid =
+ softc_p->param_attr[param][subparam] &
+ IS_VALID;
+ is_present =
+ softc_p->param_attr[param][subparam] &
+ IS_PRESENT;
+
+ cap_set = is_ctrl_file ?
+ (softc_p->param_attr[param][subparam]
+ & CAP_CTRL_SET) :
+ (softc_p->param_attr[param][subparam]
+ & CAP_SET);
+
+ if (is_valid && is_present && cap_set) {
+ val = param_list[param][subparam].val;
+
+ if (dcam1394_param_set(softc_p,
+ param, subparam, val)) {
+
+ param_list[param][subparam].err = 1;
+ ret_err = 1;
+ }
+ } else {
+ param_list[param][subparam].err = 1;
+ ret_err = 1;
+ }
+ }
+ }
+ }
+
+ return (ret_err);
+}
+
+
+/*
+ * dcam1394_param_get
+ */
+int
+dcam1394_param_get(dcam_state_t *softc_p, uint_t param, uint_t subparam,
+ uint_t *val_p)
+{
+ int err;
+
+ switch (param) {
+
+ case DCAM1394_PARAM_CAP_POWER_CTRL:
+ err = param_cap_power_ctrl_get(softc_p, val_p);
+ break;
+
+ case DCAM1394_PARAM_CAP_VID_MODE:
+ err = param_cap_vid_mode_get(softc_p, subparam, val_p);
+ break;
+
+ case DCAM1394_PARAM_CAP_FRAME_RATE_VID_MODE_0:
+ case DCAM1394_PARAM_CAP_FRAME_RATE_VID_MODE_1:
+ case DCAM1394_PARAM_CAP_FRAME_RATE_VID_MODE_2:
+ case DCAM1394_PARAM_CAP_FRAME_RATE_VID_MODE_3:
+ case DCAM1394_PARAM_CAP_FRAME_RATE_VID_MODE_4:
+ case DCAM1394_PARAM_CAP_FRAME_RATE_VID_MODE_5:
+ err = param_cap_frame_rate_get(softc_p, param, subparam, val_p);
+ break;
+
+ case DCAM1394_PARAM_POWER:
+ err = param_power_get(softc_p, val_p);
+ break;
+
+ case DCAM1394_PARAM_VID_MODE:
+ err = param_vid_mode_get(softc_p, val_p);
+ break;
+
+ case DCAM1394_PARAM_FRAME_RATE:
+ err = param_frame_rate_get(softc_p, val_p);
+ break;
+
+ case DCAM1394_PARAM_RING_BUFF_CAPACITY:
+ err = param_ring_buff_capacity_get(softc_p, val_p);
+ break;
+
+ case DCAM1394_PARAM_RING_BUFF_NUM_FRAMES_READY:
+ err = param_ring_buff_num_frames_ready_get(softc_p, val_p);
+ break;
+
+ case DCAM1394_PARAM_RING_BUFF_READ_PTR_INCR:
+ err = param_ring_buff_read_ptr_incr_get(softc_p, val_p);
+ break;
+
+ case DCAM1394_PARAM_FRAME_NUM_BYTES:
+ err = param_frame_num_bytes_get(softc_p, val_p);
+ break;
+
+ case DCAM1394_PARAM_STATUS:
+ err = param_status_get(softc_p, val_p);
+ break;
+
+ case DCAM1394_PARAM_BRIGHTNESS:
+ err = param_brightness_get(softc_p, subparam, val_p);
+ break;
+
+ case DCAM1394_PARAM_EXPOSURE:
+ err = param_exposure_get(softc_p, subparam, val_p);
+ break;
+
+ case DCAM1394_PARAM_SHARPNESS:
+ err = param_sharpness_get(softc_p, subparam, val_p);
+ break;
+
+ case DCAM1394_PARAM_WHITE_BALANCE:
+ err = param_white_balance_get(softc_p, subparam, val_p);
+ break;
+
+ case DCAM1394_PARAM_HUE:
+ err = param_hue_get(softc_p, subparam, val_p);
+ break;
+
+ case DCAM1394_PARAM_SATURATION:
+ err = param_saturation_get(softc_p, subparam, val_p);
+ break;
+
+ case DCAM1394_PARAM_GAMMA:
+ err = param_gamma_get(softc_p, subparam, val_p);
+ break;
+
+ case DCAM1394_PARAM_SHUTTER:
+ err = param_shutter_get(softc_p, subparam, val_p);
+ break;
+
+ case DCAM1394_PARAM_GAIN:
+ err = param_gain_get(softc_p, subparam, val_p);
+ break;
+
+ case DCAM1394_PARAM_IRIS:
+ err = param_iris_get(softc_p, subparam, val_p);
+ break;
+
+ case DCAM1394_PARAM_FOCUS:
+ err = param_focus_get(softc_p, subparam, val_p);
+ break;
+
+ case DCAM1394_PARAM_ZOOM:
+ err = param_zoom_get(softc_p, subparam, val_p);
+ break;
+
+ case DCAM1394_PARAM_PAN:
+ err = param_pan_get(softc_p, subparam, val_p);
+ break;
+
+ case DCAM1394_PARAM_TILT:
+ err = param_tilt_get(softc_p, subparam, val_p);
+ break;
+
+ default:
+ err = 1;
+ break;
+ }
+
+ return (err);
+}
+
+
+/*
+ * dcam1394_param_set
+ */
+int
+dcam1394_param_set(dcam_state_t *softc_p, uint_t param, uint_t subparam,
+ uint_t val)
+{
+ int err;
+
+ switch (param) {
+
+ case DCAM1394_PARAM_POWER:
+ err = param_power_set(softc_p, val);
+ break;
+
+ case DCAM1394_PARAM_VID_MODE:
+ err = param_vid_mode_set(softc_p, val);
+ break;
+
+ case DCAM1394_PARAM_FRAME_RATE:
+ err = param_frame_rate_set(softc_p, val);
+ break;
+
+ case DCAM1394_PARAM_RING_BUFF_CAPACITY:
+ err = param_ring_buff_capacity_set(softc_p, val);
+ break;
+
+ case DCAM1394_PARAM_RING_BUFF_READ_PTR_INCR:
+ err = param_ring_buff_read_ptr_incr_set(softc_p, val);
+ break;
+
+ case DCAM1394_PARAM_BRIGHTNESS:
+ err = param_brightness_set(softc_p, subparam, val);
+ break;
+
+ case DCAM1394_PARAM_EXPOSURE:
+ err = param_exposure_set(softc_p, subparam, val);
+ break;
+
+ case DCAM1394_PARAM_SHARPNESS:
+ err = param_sharpness_set(softc_p, subparam, val);
+ break;
+
+ case DCAM1394_PARAM_WHITE_BALANCE:
+ err = param_white_balance_set(softc_p, subparam, val);
+ break;
+
+ case DCAM1394_PARAM_HUE:
+ err = param_hue_set(softc_p, subparam, val);
+ break;
+
+ case DCAM1394_PARAM_SATURATION:
+ err = param_saturation_set(softc_p, subparam, val);
+ break;
+
+ case DCAM1394_PARAM_GAMMA:
+ err = param_gamma_set(softc_p, subparam, val);
+ break;
+
+ case DCAM1394_PARAM_SHUTTER:
+ err = param_shutter_set(softc_p, subparam, val);
+ break;
+
+ case DCAM1394_PARAM_GAIN:
+ err = param_gain_set(softc_p, subparam, val);
+ break;
+
+ case DCAM1394_PARAM_IRIS:
+ err = param_iris_set(softc_p, subparam, val);
+ break;
+
+ case DCAM1394_PARAM_FOCUS:
+ err = param_focus_set(softc_p, subparam, val);
+ break;
+
+ case DCAM1394_PARAM_ZOOM:
+ err = param_zoom_set(softc_p, subparam, val);
+ break;
+
+ case DCAM1394_PARAM_PAN:
+ err = param_pan_set(softc_p, subparam, val);
+ break;
+
+ case DCAM1394_PARAM_TILT:
+ err = param_tilt_set(softc_p, subparam, val);
+ break;
+
+ default:
+ err = 1;
+ break;
+ }
+
+ return (err);
+}
+
+
+/*
+ * feature_get
+ */
+int
+feature_get(dcam_state_t *softc_p, uint_t feature_csr_offs,
+ uint_t feature_elm_inq_reg_offs, uint_t subparam, uint_t *val_p)
+{
+ dcam1394_reg_io_t reg_io;
+ uint_t val;
+
+ switch (subparam) {
+
+ case DCAM1394_SUBPARAM_PRESENCE:
+ case DCAM1394_SUBPARAM_ON_OFF:
+ case DCAM1394_SUBPARAM_CTRL_MODE:
+ case DCAM1394_SUBPARAM_VALUE:
+ case DCAM1394_SUBPARAM_U_VALUE:
+ case DCAM1394_SUBPARAM_V_VALUE:
+ reg_io.offs = feature_csr_offs +
+ DCAM1394_REG_OFFS_FEATURE_CSR_BASE;
+
+ if (dcam_reg_read(softc_p, &reg_io)) {
+ return (1);
+ }
+
+ val = feature_csr_val_subparam_extract(subparam, reg_io.val);
+ break;
+
+ case DCAM1394_SUBPARAM_CAP_READ:
+ case DCAM1394_SUBPARAM_CAP_ON_OFF:
+ case DCAM1394_SUBPARAM_CAP_CTRL_AUTO:
+ case DCAM1394_SUBPARAM_CAP_CTRL_MANUAL:
+ case DCAM1394_SUBPARAM_MIN_VAL:
+ case DCAM1394_SUBPARAM_MAX_VAL:
+ reg_io.offs = feature_elm_inq_reg_offs +
+ DCAM1394_REG_OFFS_FEATURE_ELM_INQ_BASE;
+
+ if (dcam_reg_read(softc_p, &reg_io)) {
+ return (1);
+ }
+
+ val = feature_elm_inq_reg_val_subparam_extract(subparam,
+ reg_io.val);
+
+ break;
+
+ default:
+ return (1);
+ }
+
+ *val_p = val;
+
+ return (0);
+}
+
+
+/*
+ * feature_set
+ */
+int
+feature_set(dcam_state_t *softc_p, uint_t feature_csr_offs,
+ uint_t subparam, uint_t val)
+{
+ dcam1394_reg_io_t reg_io;
+
+ reg_io.offs = feature_csr_offs + DCAM1394_REG_OFFS_FEATURE_CSR_BASE;
+
+ if (dcam_reg_read(softc_p, &reg_io)) {
+ return (1);
+ }
+
+ reg_io.val = feature_csr_val_construct(subparam, val, reg_io.val);
+
+ if (dcam_reg_write(softc_p, &reg_io)) {
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * param_cap_power_ctrl_get
+ */
+int
+param_cap_power_ctrl_get(dcam_state_t *softc_p, uint_t *val_p)
+{
+ dcam1394_reg_io_t reg_io;
+
+ reg_io.offs = DCAM1394_REG_OFFS_BASIC_FUNC_INQ;
+
+ if (dcam_reg_read(softc_p, &reg_io)) {
+ return (1);
+ }
+
+ *val_p = (reg_io.val & DCAM1394_MASK_CAM_POWER_CTRL) >>
+ DCAM1394_SHIFT_CAM_POWER_CTRL;
+
+ return (0);
+}
+
+
+/*
+ * param_cap_vid_mode_get
+ * dcam spec: sec 1.2.1.1
+ */
+int
+param_cap_vid_mode_get(dcam_state_t *softc_p, uint_t subparam, uint_t *val_p)
+{
+ dcam1394_reg_io_t reg_io;
+ uint_t mask, shift, vid_mode;
+
+ vid_mode = subparam - DCAM1394_SUBPARAM_VID_MODE_0;
+ reg_io.offs = DCAM1394_REG_OFFS_VID_MODE_INQ;
+
+ if (dcam_reg_read(softc_p, &reg_io)) {
+ return (1);
+ }
+
+ mask = 1 << (31 - vid_mode);
+ shift = 31 - vid_mode;
+
+ *val_p = (reg_io.val & mask) >> shift;
+
+ return (0);
+}
+
+
+/*
+ * param_cap_frame_rate_get()
+ * dcam spec: sec 1.2.2
+ */
+int
+param_cap_frame_rate_get(dcam_state_t *softc_p, uint_t param,
+ uint_t subparam, uint_t *val_p)
+{
+ dcam1394_reg_io_t reg_io;
+ uint_t frame_rate, mask, shift, vid_mode;
+
+ vid_mode = param - DCAM1394_PARAM_CAP_FRAME_RATE_VID_MODE_0;
+ frame_rate = subparam - DCAM1394_SUBPARAM_FRAME_RATE_0;
+
+ reg_io.offs = DCAM1394_REG_OFFS_FRAME_RATE_INQ_BASE + (4 * vid_mode);
+
+ if (dcam_reg_read(softc_p, &reg_io)) {
+ return (1);
+ }
+
+ mask = 1 << (31 - (frame_rate + 1));
+ shift = 31 - (frame_rate + 1);
+
+ *val_p = (reg_io.val & mask) >> shift;
+
+ return (0);
+}
+
+
+/*
+ * param_power_get
+ */
+int
+param_power_get(dcam_state_t *softc_p, uint_t *val_p)
+{
+ dcam1394_reg_io_t reg_io;
+
+ reg_io.offs = DCAM1394_REG_OFFS_CAMERA_POWER;
+
+ if (dcam_reg_read(softc_p, &reg_io)) {
+ return (1);
+ }
+
+ *val_p = reg_io.val >> DCAM1394_SHIFT_CAMERA_POWER;
+
+ return (0);
+}
+
+
+/*
+ * param_power_set()
+ */
+int
+param_power_set(dcam_state_t *softc_p, uint_t val)
+{
+ dcam1394_reg_io_t reg_io;
+
+ reg_io.offs = DCAM1394_REG_OFFS_CAMERA_POWER;
+ reg_io.val = val << DCAM1394_SHIFT_CAMERA_POWER;
+
+ if (dcam_reg_write(softc_p, &reg_io)) {
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * param_vid_mode_get
+ */
+int
+param_vid_mode_get(dcam_state_t *softc_p, uint_t *val_p)
+{
+ dcam1394_reg_io_t reg_io;
+
+ reg_io.offs = DCAM1394_REG_OFFS_CUR_V_MODE;
+
+ if (dcam_reg_read(softc_p, &reg_io)) {
+ return (1);
+ }
+
+ *val_p = reg_io.val >> DCAM1394_SHIFT_CUR_V_MODE;
+
+ return (0);
+}
+
+
+/*
+ * param_vid_mode_set
+ */
+int
+param_vid_mode_set(dcam_state_t *softc_p, uint_t val)
+{
+ dcam1394_reg_io_t reg_io;
+ uint_t vid_mode;
+
+ vid_mode = val - DCAM1394_VID_MODE_0;
+
+ reg_io.offs = DCAM1394_REG_OFFS_CUR_V_MODE;
+ reg_io.val = vid_mode << DCAM1394_SHIFT_CUR_V_MODE;
+
+ if (dcam_reg_write(softc_p, &reg_io)) {
+ return (1);
+ }
+
+ softc_p->cur_vid_mode = val;
+
+ /*
+ * if we are currently receiving frames, we need to do a restart
+ * so that the new vid mode value takes effect
+ */
+ if (softc_p->flags & DCAM1394_FLAG_FRAME_RCV_INIT) {
+ (void) dcam_frame_rcv_stop(softc_p);
+ (void) dcam1394_ioctl_frame_rcv_start(softc_p);
+ }
+
+ return (0);
+}
+
+
+/*
+ * param_frame_rate_get
+ */
+int
+param_frame_rate_get(dcam_state_t *softc_p, uint_t *val_p)
+{
+ dcam1394_reg_io_t reg_io;
+ uint_t frame_rate;
+
+ reg_io.offs = DCAM1394_REG_OFFS_CUR_V_FRM_RATE;
+
+ if (dcam_reg_read(softc_p, &reg_io)) {
+ return (1);
+ }
+
+ frame_rate = reg_io.val >> DCAM1394_SHIFT_CUR_V_FRM_RATE;
+
+ *val_p = frame_rate - 1 + DCAM1394_FRAME_RATE_0;
+
+ return (0);
+}
+
+
+/*
+ * param_frame_rate_set
+ */
+int
+param_frame_rate_set(dcam_state_t *softc_p, uint_t val)
+{
+ dcam1394_reg_io_t reg_io;
+ uint_t frame_rate;
+
+ /* if we are currently receiving frames, stop the camera */
+ if (softc_p->flags & DCAM1394_FLAG_FRAME_RCV_INIT) {
+ (void) dcam_frame_rcv_stop(softc_p);
+
+ frame_rate = val - DCAM1394_FRAME_RATE_0 + 1;
+
+ reg_io.offs = DCAM1394_REG_OFFS_CUR_V_FRM_RATE;
+ reg_io.val = frame_rate << DCAM1394_SHIFT_CUR_V_FRM_RATE;
+
+ if (dcam_reg_write(softc_p, &reg_io)) {
+ return (1);
+ }
+
+ /*
+ * Update the state info.
+ * note: the driver maintains frame rate in an array
+ * whereas the the camera uses predefined values whose
+ * lowest frame rate starts at 6
+ */
+ softc_p->cur_frame_rate = val - 6;
+
+ /* restart the camera */
+ (void) dcam1394_ioctl_frame_rcv_start(softc_p);
+ } else {
+ frame_rate = val - DCAM1394_FRAME_RATE_0 + 1;
+
+ reg_io.offs = DCAM1394_REG_OFFS_CUR_V_FRM_RATE;
+ reg_io.val = frame_rate << DCAM1394_SHIFT_CUR_V_FRM_RATE;
+
+ if (dcam_reg_write(softc_p, &reg_io)) {
+ return (1);
+ }
+
+ /* see note above re skewing of value by 6 */
+ softc_p->cur_frame_rate = val - 6;
+ }
+
+ return (0);
+}
+
+
+/*
+ * param_ring_buff_capacity_get()
+ */
+int
+param_ring_buff_capacity_get(dcam_state_t *softc_p, uint_t *val_p)
+{
+ *val_p = softc_p->cur_ring_buff_capacity;
+
+ return (0);
+}
+
+
+/*
+ * param_ring_buff_capacity_set
+ */
+int
+param_ring_buff_capacity_set(dcam_state_t *softc_p, uint_t val)
+{
+ /* bounds check */
+ if ((val < 2) || (val > 30)) {
+ return (1);
+ }
+
+ /* update our state info */
+ softc_p->cur_ring_buff_capacity = val;
+
+
+ /*
+ * if we are currently receiving frames, we need to do a restart
+ * so that the new buff_capacity value takes effect
+ */
+ if (softc_p->flags & DCAM1394_FLAG_FRAME_RCV_INIT) {
+ (void) dcam_frame_rcv_stop(softc_p);
+ (void) dcam1394_ioctl_frame_rcv_start(softc_p);
+ }
+ return (0);
+}
+
+
+/*
+ * param_ring_buff_num_frames_ready_get()
+ */
+int
+param_ring_buff_num_frames_ready_get(dcam_state_t *softc_p, uint_t *val_p)
+{
+ size_t read_pos, write_pos;
+
+ /*
+ * note: currently we support only one read_ptr_id, so the
+ * following logic will work. If multiple read_ptr_id's are
+ * supported, this function call will need to receive a
+ * read_ptr_id
+ */
+
+ if (softc_p->ring_buff_p == NULL) {
+ return (1);
+ }
+
+ mutex_enter(&softc_p->dcam_frame_is_done_mutex);
+
+ read_pos = ring_buff_read_ptr_pos_get(softc_p->ring_buff_p, 0);
+ write_pos = ring_buff_write_ptr_pos_get(softc_p->ring_buff_p);
+
+ if (read_pos < write_pos) {
+ *val_p = write_pos - read_pos;
+ } else {
+ *val_p = (softc_p->ring_buff_p->num_buffs + write_pos) -
+ read_pos;
+ }
+
+ mutex_exit(&softc_p->dcam_frame_is_done_mutex);
+
+ return (0);
+}
+
+
+/*
+ * param_ring_buff_read_ptr_incr_get()
+ */
+
+int
+param_ring_buff_read_ptr_incr_get(dcam_state_t *softc_p, uint_t *val_p)
+{
+ if (softc_p->ring_buff_p == NULL) {
+ return (1);
+ }
+
+ *val_p = softc_p->ring_buff_p->read_ptr_incr_val;
+
+ return (0);
+}
+
+
+/*
+ * param_ring_buff_read_ptr_incr_set
+ */
+int
+param_ring_buff_read_ptr_incr_set(dcam_state_t *softc_p, uint_t val)
+{
+ if (softc_p->ring_buff_p == NULL) {
+ return (1);
+ }
+
+ softc_p->ring_buff_p->read_ptr_incr_val = val;
+
+ return (0);
+}
+
+
+/*
+ * param_frame_num_bytes_get
+ */
+int
+param_frame_num_bytes_get(dcam_state_t *softc_p, uint_t *val_p)
+{
+ if (softc_p == NULL) {
+ return (1);
+ }
+
+ *val_p = g_frame_num_bytes[softc_p->cur_vid_mode];
+
+ return (0);
+}
+
+
+/*
+ * param_status_get()
+ */
+
+int
+param_status_get(dcam_state_t *softc_p, uint_t *val_p)
+{
+ mutex_enter(&softc_p->dcam_frame_is_done_mutex);
+
+ *val_p = softc_p->param_status;
+ softc_p->param_status = 0;
+
+ mutex_exit(&softc_p->dcam_frame_is_done_mutex);
+
+ return (0);
+}
+
+
+/*
+ * param_brightness_get
+ */
+int
+param_brightness_get(dcam_state_t *softc_p, uint_t subparam, uint_t *val_p)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+ uint_t feature_elm_inq_reg_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_BRIGHTNESS_CSR;
+ feature_elm_inq_reg_offs = DCAM1394_REG_OFFS_BRIGHTNESS_INQ;
+
+ ret_val = feature_get(softc_p, feature_csr_offs,
+ feature_elm_inq_reg_offs, subparam, val_p);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_brightness_set()
+ */
+int
+param_brightness_set(dcam_state_t *softc_p, uint_t subparam, uint_t val)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_BRIGHTNESS_CSR;
+
+ ret_val = feature_set(softc_p, feature_csr_offs, subparam, val);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_exposure_get
+ */
+int
+param_exposure_get(dcam_state_t *softc_p, uint_t subparam, uint_t *val_p)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+ uint_t feature_elm_inq_reg_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_EXPOSURE_CSR;
+ feature_elm_inq_reg_offs = DCAM1394_REG_OFFS_EXPOSURE_INQ;
+
+ ret_val = feature_get(softc_p, feature_csr_offs,
+ feature_elm_inq_reg_offs, subparam, val_p);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_exposure_set
+ */
+int
+param_exposure_set(dcam_state_t *softc_p, uint_t subparam, uint_t val)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_EXPOSURE_CSR;
+
+ ret_val = feature_set(softc_p, feature_csr_offs, subparam, val);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_sharpness_get
+ */
+int
+param_sharpness_get(dcam_state_t *softc_p, uint_t subparam, uint_t *val_p)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+ uint_t feature_elm_inq_reg_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_SHARPNESS_CSR;
+ feature_elm_inq_reg_offs = DCAM1394_REG_OFFS_SHARPNESS_INQ;
+
+ ret_val = feature_get(softc_p, feature_csr_offs,
+ feature_elm_inq_reg_offs, subparam, val_p);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_sharpness_set
+ */
+int
+param_sharpness_set(dcam_state_t *softc_p, uint_t subparam, uint_t val)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_SHARPNESS_CSR;
+
+ ret_val = feature_set(softc_p, feature_csr_offs, subparam, val);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_white_balance_get
+ */
+int
+param_white_balance_get(dcam_state_t *softc_p, uint_t subparam, uint_t *val_p)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+ uint_t feature_elm_inq_reg_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_WHITE_BALANCE_CSR;
+ feature_elm_inq_reg_offs = DCAM1394_REG_OFFS_WHITE_BALANCE_INQ;
+
+ ret_val = feature_get(softc_p, feature_csr_offs,
+ feature_elm_inq_reg_offs, subparam, val_p);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_white_balance_set
+ */
+int
+param_white_balance_set(dcam_state_t *softc_p, uint_t subparam, uint_t val)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_WHITE_BALANCE_CSR;
+
+ ret_val = feature_set(softc_p, feature_csr_offs, subparam, val);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_hue_get
+ */
+int
+param_hue_get(dcam_state_t *softc_p, uint_t subparam, uint_t *val_p)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+ uint_t feature_elm_inq_reg_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_HUE_CSR;
+ feature_elm_inq_reg_offs = DCAM1394_REG_OFFS_HUE_INQ;
+
+ ret_val = feature_get(softc_p, feature_csr_offs,
+ feature_elm_inq_reg_offs, subparam, val_p);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_hue_set
+ */
+int
+param_hue_set(dcam_state_t *softc_p, uint_t subparam, uint_t val)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_HUE_CSR;
+
+ ret_val = feature_set(softc_p, feature_csr_offs, subparam, val);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_saturation_get
+ */
+int
+param_saturation_get(dcam_state_t *softc_p, uint_t subparam, uint_t *val_p)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+ uint_t feature_elm_inq_reg_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_SATURATION_CSR;
+ feature_elm_inq_reg_offs = DCAM1394_REG_OFFS_SATURATION_INQ;
+
+ ret_val = feature_get(softc_p, feature_csr_offs,
+ feature_elm_inq_reg_offs, subparam, val_p);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_saturation_set
+ */
+int
+param_saturation_set(dcam_state_t *softc_p, uint_t subparam, uint_t val)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_SATURATION_CSR;
+
+ ret_val = feature_set(softc_p, feature_csr_offs, subparam, val);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_gamma_get
+ */
+int
+param_gamma_get(dcam_state_t *softc_p, uint_t subparam, uint_t *val_p)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+ uint_t feature_elm_inq_reg_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_GAMMA_CSR;
+ feature_elm_inq_reg_offs = DCAM1394_REG_OFFS_GAMMA_INQ;
+
+ ret_val = feature_get(softc_p, feature_csr_offs,
+ feature_elm_inq_reg_offs, subparam, val_p);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_gamma_set
+ */
+int
+param_gamma_set(dcam_state_t *softc_p, uint_t subparam, uint_t val)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_GAMMA_CSR;
+
+ ret_val = feature_set(softc_p, feature_csr_offs, subparam, val);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_shutter_get
+ */
+int
+param_shutter_get(dcam_state_t *softc_p, uint_t subparam, uint_t *val_p)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+ uint_t feature_elm_inq_reg_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_SHUTTER_CSR;
+ feature_elm_inq_reg_offs = DCAM1394_REG_OFFS_SHUTTER_INQ;
+
+ ret_val = feature_get(softc_p, feature_csr_offs,
+ feature_elm_inq_reg_offs, subparam, val_p);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_shutter_set
+ */
+int
+param_shutter_set(dcam_state_t *softc_p, uint_t subparam, uint_t val)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_SHUTTER_CSR;
+
+ ret_val = feature_set(softc_p, feature_csr_offs, subparam, val);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_gain_get
+ */
+int
+param_gain_get(dcam_state_t *softc_p, uint_t subparam, uint_t *val_p)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+ uint_t feature_elm_inq_reg_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_GAIN_CSR;
+ feature_elm_inq_reg_offs = DCAM1394_REG_OFFS_GAIN_INQ;
+
+ ret_val = feature_get(softc_p, feature_csr_offs,
+ feature_elm_inq_reg_offs, subparam, val_p);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_gain_set
+ */
+int
+param_gain_set(dcam_state_t *softc_p, uint_t subparam, uint_t val)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_GAIN_CSR;
+
+ ret_val = feature_set(softc_p, feature_csr_offs, subparam, val);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_iris_get
+ */
+int
+param_iris_get(dcam_state_t *softc_p, uint_t subparam, uint_t *val_p)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+ uint_t feature_elm_inq_reg_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_IRIS_CSR;
+ feature_elm_inq_reg_offs = DCAM1394_REG_OFFS_IRIS_INQ;
+
+ ret_val = feature_get(softc_p, feature_csr_offs,
+ feature_elm_inq_reg_offs, subparam, val_p);
+
+ switch (subparam) {
+ case DCAM1394_SUBPARAM_PRESENCE:
+ *val_p = 0;
+ break;
+ case DCAM1394_SUBPARAM_ON_OFF:
+ *val_p = 1;
+ break;
+ case DCAM1394_SUBPARAM_MIN_VAL:
+ case DCAM1394_SUBPARAM_MAX_VAL:
+ case DCAM1394_SUBPARAM_VALUE:
+ *val_p = 4;
+ break;
+ default:
+ break;
+ }
+
+ return (ret_val);
+}
+
+
+/*
+ * param_iris_set
+ */
+int
+param_iris_set(dcam_state_t *softc_p, uint_t subparam, uint_t val)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_IRIS_CSR;
+
+ if (subparam == DCAM1394_SUBPARAM_ON_OFF) {
+ val = 1;
+ } else if (subparam == DCAM1394_SUBPARAM_VALUE) {
+ val = 4;
+ }
+ ret_val = feature_set(softc_p, feature_csr_offs, subparam, val);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_focus_get
+ */
+int
+param_focus_get(dcam_state_t *softc_p, uint_t subparam, uint_t *val_p)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+ uint_t feature_elm_inq_reg_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_FOCUS_CSR;
+ feature_elm_inq_reg_offs = DCAM1394_REG_OFFS_FOCUS_INQ;
+
+ ret_val = feature_get(softc_p, feature_csr_offs,
+ feature_elm_inq_reg_offs, subparam, val_p);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_focus_set
+ */
+int
+param_focus_set(dcam_state_t *softc_p, uint_t subparam, uint_t val)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_FOCUS_CSR;
+
+ ret_val = feature_set(softc_p, feature_csr_offs, subparam, val);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_zoom_get
+ */
+int
+param_zoom_get(dcam_state_t *softc_p, uint_t subparam, uint_t *val_p)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+ uint_t feature_elm_inq_reg_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_ZOOM_CSR;
+ feature_elm_inq_reg_offs = DCAM1394_REG_OFFS_ZOOM_INQ;
+
+ ret_val = feature_get(softc_p, feature_csr_offs,
+ feature_elm_inq_reg_offs, subparam, val_p);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_zoom_set
+ */
+int
+param_zoom_set(dcam_state_t *softc_p, uint_t subparam, uint_t val)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_ZOOM_CSR;
+
+ ret_val = feature_set(softc_p, feature_csr_offs, subparam, val);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_pan_get
+ */
+int
+param_pan_get(dcam_state_t *softc_p, uint_t subparam, uint_t *val_p)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+ uint_t feature_elm_inq_reg_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_PAN_CSR;
+ feature_elm_inq_reg_offs = DCAM1394_REG_OFFS_PAN_INQ;
+
+ ret_val = feature_get(softc_p, feature_csr_offs,
+ feature_elm_inq_reg_offs, subparam, val_p);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_pan_set
+ */
+int
+param_pan_set(dcam_state_t *softc_p, uint_t subparam, uint_t val)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_PAN_CSR;
+
+ ret_val = feature_set(softc_p, feature_csr_offs, subparam, val);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_tilt_get
+ */
+int
+param_tilt_get(dcam_state_t *softc_p, uint_t subparam, uint_t *val_p)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+ uint_t feature_elm_inq_reg_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_TILT_CSR;
+ feature_elm_inq_reg_offs = DCAM1394_REG_OFFS_TILT_INQ;
+
+ ret_val = feature_get(softc_p, feature_csr_offs,
+ feature_elm_inq_reg_offs, subparam, val_p);
+
+ return (ret_val);
+}
+
+
+/*
+ * param_tilt_set
+ */
+int
+param_tilt_set(dcam_state_t *softc_p, uint_t subparam, uint_t val)
+{
+ int ret_val;
+ uint_t feature_csr_offs;
+
+ feature_csr_offs = DCAM1394_REG_OFFS_TILT_CSR;
+
+ ret_val = feature_set(softc_p, feature_csr_offs, subparam, val);
+
+ return (ret_val);
+}
+
+
+/*
+ * feature_csr_val_construct
+ */
+static uint_t
+feature_csr_val_construct(uint_t subparam, uint_t param_val, uint_t init_val)
+{
+ uint_t ret_val;
+
+ switch (subparam) {
+
+ case DCAM1394_SUBPARAM_ON_OFF:
+ ret_val = (init_val & ~(DCAM1394_MASK_ON_OFF)) |
+ (param_val << DCAM1394_SHIFT_ON_OFF);
+ break;
+
+ case DCAM1394_SUBPARAM_CTRL_MODE:
+ ret_val = (init_val & ~(DCAM1394_MASK_A_M_MODE)) |
+ (param_val << DCAM1394_SHIFT_A_M_MODE);
+ break;
+
+ case DCAM1394_SUBPARAM_VALUE:
+ ret_val = (init_val & ~(DCAM1394_MASK_VALUE)) |
+ (param_val << DCAM1394_SHIFT_VALUE);
+ break;
+
+ case DCAM1394_SUBPARAM_U_VALUE:
+ ret_val = (init_val & ~(DCAM1394_MASK_U_VALUE)) |
+ (param_val << DCAM1394_SHIFT_U_VALUE);
+ break;
+
+ case DCAM1394_SUBPARAM_V_VALUE:
+ ret_val = (init_val & ~(DCAM1394_MASK_V_VALUE)) |
+ (param_val << DCAM1394_SHIFT_V_VALUE);
+ break;
+
+ default:
+ break;
+
+ }
+
+ return (ret_val);
+}
+
+
+/*
+ * feature_csr_val_subparam_extract
+ */
+static uint_t
+feature_csr_val_subparam_extract(uint_t subparam, uint_t reg_val)
+{
+ uint_t ret_val;
+
+ switch (subparam) {
+
+ case DCAM1394_SUBPARAM_PRESENCE:
+ ret_val = (reg_val & DCAM1394_MASK_PRESENCE_INQ) >>
+ DCAM1394_SHIFT_PRESENCE_INQ;
+ break;
+
+ case DCAM1394_SUBPARAM_ON_OFF:
+ ret_val = (reg_val & DCAM1394_MASK_ON_OFF) >>
+ DCAM1394_SHIFT_ON_OFF;
+ break;
+
+ case DCAM1394_SUBPARAM_CTRL_MODE:
+ ret_val = (reg_val & DCAM1394_MASK_A_M_MODE) >>
+ DCAM1394_SHIFT_A_M_MODE;
+ break;
+
+ case DCAM1394_SUBPARAM_VALUE:
+ ret_val = (reg_val & DCAM1394_MASK_VALUE) >>
+ DCAM1394_SHIFT_VALUE;
+ break;
+
+ case DCAM1394_SUBPARAM_U_VALUE:
+ ret_val = (reg_val & DCAM1394_MASK_U_VALUE) >>
+ DCAM1394_SHIFT_U_VALUE;
+ break;
+
+ case DCAM1394_SUBPARAM_V_VALUE:
+
+ ret_val = (reg_val & DCAM1394_MASK_V_VALUE) >>
+ DCAM1394_SHIFT_V_VALUE;
+ break;
+
+ default:
+
+ ret_val = 0;
+
+ break;
+
+ }
+
+ return (ret_val);
+
+}
+
+
+/*
+ * feature_elm_inq_reg_val_subparam_extract
+ */
+static uint_t
+feature_elm_inq_reg_val_subparam_extract(uint_t subparam,
+ uint_t reg_val)
+{
+ uint_t ret_val;
+
+ switch (subparam) {
+
+ case DCAM1394_SUBPARAM_CAP_READ:
+ ret_val = (reg_val & DCAM1394_MASK_READOUT_INQ) >>
+ DCAM1394_SHIFT_READOUT_INQ;
+ break;
+
+ case DCAM1394_SUBPARAM_CAP_ON_OFF:
+ ret_val = (reg_val & DCAM1394_MASK_ON_OFF_INQ) >>
+ DCAM1394_SHIFT_ON_OFF_INQ;
+ break;
+
+ case DCAM1394_SUBPARAM_CAP_CTRL_AUTO:
+ ret_val = (reg_val & DCAM1394_MASK_AUTO_INQ) >>
+ DCAM1394_SHIFT_AUTO_INQ;
+ break;
+
+ case DCAM1394_SUBPARAM_CAP_CTRL_MANUAL:
+ ret_val = (reg_val & DCAM1394_MASK_MANUAL_INQ) >>
+ DCAM1394_SHIFT_MANUAL_INQ;
+ break;
+
+ case DCAM1394_SUBPARAM_MIN_VAL:
+ ret_val = (reg_val & DCAM1394_MASK_MIN_VAL) >>
+ DCAM1394_SHIFT_MIN_VAL;
+ break;
+
+ case DCAM1394_SUBPARAM_MAX_VAL:
+ ret_val = (reg_val & DCAM1394_MASK_MAX_VAL) >>
+ DCAM1394_SHIFT_MAX_VAL;
+ break;
+
+ default:
+ ret_val = 0;
+ break;
+
+ }
+
+ return (ret_val);
+}
diff --git a/usr/src/uts/common/io/1394/targets/dcam1394/dcam_reg.c b/usr/src/uts/common/io/1394/targets/dcam1394/dcam_reg.c
new file mode 100644
index 0000000000..096a632291
--- /dev/null
+++ b/usr/src/uts/common/io/1394/targets/dcam1394/dcam_reg.c
@@ -0,0 +1,125 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * dcam_reg.c
+ *
+ * dcam1394 driver. Control register access support.
+ */
+
+#include <sys/tnf_probe.h>
+#include <sys/1394/targets/dcam1394/dcam_reg.h>
+
+
+/*
+ * dcam_reg_read
+ */
+int
+dcam_reg_read(dcam_state_t *soft_state, dcam1394_reg_io_t *arg)
+{
+ cmd1394_cmd_t *cmdp;
+
+ if (t1394_alloc_cmd(soft_state->sl_handle, 1, &cmdp) != DDI_SUCCESS) {
+ return (-1);
+ }
+
+ cmdp->cmd_type = CMD1394_ASYNCH_RD_QUAD;
+ cmdp->cmd_addr = 0x0000FFFFF0F00000 |
+ (uint64_t)(arg->offs & 0x00000FFC);
+ cmdp->cmd_options = CMD1394_BLOCKING;
+
+#ifdef GRAPHICS_DELAY
+ /*
+ * This delay should not be necessary, but was added for some
+ * unknown reason. Should it ever be determined that it
+ * is necessary, this delay should be reenabled.
+ */
+ delay(drv_usectohz(500));
+#endif
+
+ if (t1394_read(soft_state->sl_handle, cmdp) != DDI_SUCCESS) {
+ (void) t1394_free_cmd(soft_state->sl_handle, 0, &cmdp);
+ return (-1);
+ }
+
+ if (cmdp->cmd_result != DDI_SUCCESS) {
+ (void) t1394_free_cmd(soft_state->sl_handle, 0, &cmdp);
+ return (-1);
+ }
+
+ /* perform endian adjustment */
+ cmdp->cmd_u.q.quadlet_data = T1394_DATA32(cmdp->cmd_u.q.quadlet_data);
+ arg->val = cmdp->cmd_u.q.quadlet_data;
+
+ (void) t1394_free_cmd(soft_state->sl_handle, 0, &cmdp);
+
+ return (0);
+}
+
+
+/*
+ * dcam_reg_write
+ */
+int
+dcam_reg_write(dcam_state_t *soft_state, dcam1394_reg_io_t *arg)
+{
+ cmd1394_cmd_t *cmdp;
+
+ if (t1394_alloc_cmd(soft_state->sl_handle, 0, &cmdp) != DDI_SUCCESS) {
+ return (-1);
+ }
+
+ cmdp->cmd_type = CMD1394_ASYNCH_WR_QUAD;
+ cmdp->cmd_addr = 0x0000FFFFF0F00000 |
+ (uint64_t)(arg->offs & 0x00000FFC);
+ cmdp->cmd_options = CMD1394_BLOCKING;
+
+ /* perform endian adjustment */
+ cmdp->cmd_u.q.quadlet_data = T1394_DATA32(arg->val);
+
+#ifdef GRAPHICS_DELAY
+ /*
+ * See the description in dcam_reg_read() above.
+ */
+ delay(drv_usectohz(500));
+#endif
+
+ if (t1394_write(soft_state->sl_handle, cmdp) != DDI_SUCCESS) {
+ (void) t1394_free_cmd(soft_state->sl_handle, 0, &cmdp);
+ return (-1);
+ }
+
+ if (cmdp->cmd_result != DDI_SUCCESS) {
+ (void) t1394_free_cmd(soft_state->sl_handle, 0, &cmdp);
+ return (-1);
+ }
+
+ (void) t1394_free_cmd(soft_state->sl_handle, 0, &cmdp);
+
+ return (0);
+}
diff --git a/usr/src/uts/common/io/1394/targets/dcam1394/dcam_ring_buff.c b/usr/src/uts/common/io/1394/targets/dcam1394/dcam_ring_buff.c
new file mode 100644
index 0000000000..0c0fe0aba9
--- /dev/null
+++ b/usr/src/uts/common/io/1394/targets/dcam1394/dcam_ring_buff.c
@@ -0,0 +1,350 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * dcam_ring_buff.c
+ *
+ * dcam1394 driver. Video frame ring buffer support.
+ */
+
+#include <sys/types.h>
+#include <sys/kmem.h>
+#include <sys/ddidmareq.h>
+#include <sys/types.h>
+#include <sys/inttypes.h>
+#include <sys/tnf_probe.h>
+#include <sys/cmn_err.h>
+
+#include <sys/1394/targets/dcam1394/dcam.h>
+
+/*
+ * ring_buff_create
+ *
+ * - alloc ring_buff_t structure
+ * - init ring_buff's num_buffs, buff_num_bytes, num_read_ptrs,
+ * read_ptr_pos
+ * - alloc (num buffs) entries in ring_buff's buff_info_array_p
+ *
+ * - for each buff
+ * - alloc DMA handle; store DMA handle in buff's buff_info_array_p
+ * - alloc mem for DMA transfer; store base addr, data access handle
+ * in buff's buff_info_array_p entry
+ * - bind alloc'ed mem to DMA handle; store assoc info in buff's
+ * buff_info_array_p entry
+ */
+ring_buff_t *
+ring_buff_create(dcam_state_t *softc_p, size_t num_buffs,
+ size_t buff_num_bytes)
+{
+ buff_info_t *buff_info_p;
+ size_t buff;
+ int i, rc;
+ ring_buff_t *ring_buff_p;
+ size_t num_bytes;
+
+ num_bytes = sizeof (ring_buff_t);
+
+ ring_buff_p = (ring_buff_t *)kmem_alloc(num_bytes, KM_SLEEP);
+
+ ring_buff_p->num_buffs = num_buffs;
+ ring_buff_p->buff_num_bytes = buff_num_bytes;
+ ring_buff_p->write_ptr_pos = 0;
+ ring_buff_p->num_read_ptrs = 0;
+ ring_buff_p->read_ptr_incr_val = 1;
+
+ for (i = 0; i < MAX_NUM_READ_PTRS; i++) {
+ ring_buff_p->read_ptr_pos[i] = (size_t)-1;
+ }
+
+ num_bytes = num_buffs * sizeof (buff_info_t);
+
+ ring_buff_p->buff_info_array_p =
+ (buff_info_t *)kmem_alloc(num_bytes, KM_SLEEP);
+
+ for (buff = 0; buff < num_buffs; buff++) {
+
+ buff_info_p = &(ring_buff_p->buff_info_array_p[buff]);
+
+ if ((ddi_dma_alloc_handle(
+ softc_p->dip,
+ &softc_p->attachinfo.dma_attr,
+ DDI_DMA_DONTWAIT,
+ NULL,
+ &(buff_info_p->dma_handle))) != DDI_SUCCESS) {
+ ring_buff_free(softc_p, ring_buff_p);
+ return (NULL);
+ }
+
+ if (ddi_dma_mem_alloc(
+ buff_info_p->dma_handle,
+ buff_num_bytes,
+ &softc_p->attachinfo.acc_attr,
+ DDI_DMA_STREAMING,
+ DDI_DMA_DONTWAIT,
+ (caddr_t)NULL,
+ &(buff_info_p->kaddr_p),
+ &(buff_info_p->real_len),
+ &(buff_info_p->data_acc_handle)) != DDI_SUCCESS) {
+ ring_buff_free(softc_p, ring_buff_p);
+
+ /*
+ * Print a warning, this triggered the bug
+ * report #4423667. This call can fail if
+ * the memory tests are being run in sunvts.
+ * The fact is, this code is doing the right
+ * thing. I added an error message, so that
+ * future occurrences can be dealt with directly.
+ * This is not a bug... The vmem test in sunvts
+ * can eat up all swap/virtual memory.
+ */
+ cmn_err(CE_WARN,
+ "ddi_dma_mem_alloc() failed in ring_buff_create(),"\
+ " insufficient memory resources.\n");
+ return (NULL);
+ }
+
+ rc = ddi_dma_addr_bind_handle(
+ buff_info_p->dma_handle,
+ (struct as *)NULL,
+ (caddr_t)buff_info_p->kaddr_p,
+ buff_info_p->real_len,
+ DDI_DMA_RDWR | DDI_DMA_STREAMING,
+ DDI_DMA_DONTWAIT,
+ NULL,
+ &buff_info_p->dma_cookie,
+ &buff_info_p->dma_cookie_count);
+
+ if (rc != DDI_DMA_MAPPED) {
+ ring_buff_free(softc_p, ring_buff_p);
+ return (NULL);
+ }
+ }
+
+ return (ring_buff_p);
+}
+
+
+/*
+ * ring_buff_free
+ */
+void
+ring_buff_free(dcam_state_t *softc_p, ring_buff_t *ring_buff_p)
+{
+ buff_info_t *buff_info_p;
+ int i;
+
+ if (ring_buff_p == NULL) {
+ softc_p->ring_buff_p = NULL;
+ return;
+ }
+
+ if (ring_buff_p->buff_info_array_p != NULL) {
+ for (i = 0; i < ring_buff_p->num_buffs; i++) {
+
+ buff_info_p = &(ring_buff_p->buff_info_array_p[i]);
+
+ (void) ddi_dma_unbind_handle(buff_info_p->dma_handle);
+ ddi_dma_mem_free(&buff_info_p->data_acc_handle);
+ ddi_dma_free_handle(&buff_info_p->dma_handle);
+ }
+
+ kmem_free(ring_buff_p->buff_info_array_p,
+ ring_buff_p->num_buffs * sizeof (buff_info_t));
+ }
+
+ kmem_free(ring_buff_p, sizeof (ring_buff_t));
+
+ softc_p->ring_buff_p = NULL;
+}
+
+
+/*
+ * ring_buff_read_ptr_add
+ */
+int
+ring_buff_read_ptr_add(ring_buff_t *ring_buff_p)
+{
+ int i;
+ int read_ptr_id;
+
+ read_ptr_id = -1;
+
+ for (i = 0; i < MAX_NUM_READ_PTRS; i++) {
+
+ if (ring_buff_p->read_ptr_pos[i] == -1) {
+ ring_buff_p->read_ptr_pos[i] = 0;
+ read_ptr_id = i;
+ break;
+ }
+ }
+
+ return (read_ptr_id);
+}
+
+
+/*
+ * ring_buff_read_ptr_remove
+ */
+int
+ring_buff_read_ptr_remove(ring_buff_t *ring_buff_p, int read_ptr_id)
+{
+ ring_buff_p->read_ptr_pos[read_ptr_id] = (size_t)-1;
+
+ return (0);
+}
+
+
+/*
+ * ring_buff_read_ptr_buff_get
+ *
+ * Return pointer to buffer that a read pointer associated with the
+ * ring buffer is pointing to.
+ */
+buff_info_t *
+ring_buff_read_ptr_buff_get(ring_buff_t *ring_buff_p, int read_ptr_id)
+{
+ size_t read_ptr_pos;
+ buff_info_t *buff_info_p;
+
+ read_ptr_pos = ring_buff_p->read_ptr_pos[read_ptr_id];
+ buff_info_p = &(ring_buff_p->buff_info_array_p[read_ptr_pos]);
+
+ return (buff_info_p);
+}
+
+
+/*
+ * ring_buff_read_ptr_pos_get
+ */
+size_t
+ring_buff_read_ptr_pos_get(ring_buff_t *ring_buff_p, int read_ptr_id)
+{
+ return (ring_buff_p->read_ptr_pos[read_ptr_id]);
+}
+
+
+/*
+ * ring_buff_read_ptr_incr
+ */
+void
+ring_buff_read_ptr_incr(ring_buff_t *ring_buff_p, int read_ptr_id)
+{
+ size_t read_ptr_pos;
+#if defined(_ADDL_RING_BUFF_CHECK)
+ size_t lrp, lwp; /* linear read, write positions */
+#endif /* _ADDL_RING_BUFFER_CHECK */
+
+ /*
+ * increment the read pointer based on read_ptr_incr_val
+ * which can vary from 1 to 10
+ */
+
+ /* get current read pointer pos */
+ read_ptr_pos = ring_buff_p->read_ptr_pos[read_ptr_id];
+
+ ring_buff_p->read_ptr_pos[read_ptr_id] =
+ (read_ptr_pos + 1) % ring_buff_p->num_buffs;
+
+#if defined(_ADDL_RING_BUFF_CHECK)
+ if ((read_ptr_pos == 0) && (ring_buff_p->write_ptr_pos == 0)) {
+ return;
+ }
+
+ if (read_ptr_pos < ring_buff_p->write_ptr_pos) {
+
+ /* calculate new read pointer position */
+ if ((read_ptr_pos + ring_buff_p->read_ptr_incr_val) <
+ ring_buff_p->write_ptr_pos) {
+
+ /* there is still some valid frame data */
+ ring_buff_p->read_ptr_pos[read_ptr_id] =
+ (read_ptr_pos +
+ ring_buff_p->read_ptr_incr_val) %
+ ring_buff_p->num_buffs;
+ } else {
+ /*
+ * we have skipped beyond available frame
+ * data, so the buffer is empty
+ */
+ ring_buff_p->read_ptr_pos[read_ptr_id] =
+ ring_buff_p->write_ptr_pos;
+ }
+ } else {
+ /*
+ * since read pointer is ahead of write pointer,
+ * it becomes easier to check for new read
+ * pointer position if we pretend that our data
+ * buffer is linear instead of circular
+ */
+
+ lrp = read_ptr_pos + ring_buff_p->read_ptr_incr_val;
+ lwp = ring_buff_p->num_buffs +
+ ring_buff_p->write_ptr_pos;
+
+ if (lrp < lwp) {
+ /* there is still some valid frame data */
+ ring_buff_p->read_ptr_pos[read_ptr_id] =
+ (read_ptr_pos +
+ ring_buff_p->read_ptr_incr_val) %
+ ring_buff_p->num_buffs;
+ } else {
+ /*
+ * we have skipped beyond available
+ * frame data, so the buffer is empty
+ */
+ ring_buff_p->read_ptr_pos[read_ptr_id] =
+ ring_buff_p->write_ptr_pos;
+ }
+ }
+#endif /* _ADDL_RING_BUFF_CHECK */
+}
+
+
+/*
+ * ring_buff_write_ptr_pos_get
+ */
+size_t
+ring_buff_write_ptr_pos_get(ring_buff_t *ring_buff_p)
+{
+ return (ring_buff_p->write_ptr_pos);
+}
+
+
+/*
+ * ring_buff_write_ptr_incr
+ */
+void
+ring_buff_write_ptr_incr(ring_buff_t *ring_buff_p)
+{
+ size_t write_ptr_pos;
+
+ write_ptr_pos = ring_buff_p->write_ptr_pos;
+
+ ring_buff_p->write_ptr_pos =
+ ((write_ptr_pos + 1) % ring_buff_p->num_buffs);
+}