dcam.c revision 8eea8e29cc4374d1ee24c25a07f45af132db3499
/*
* 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
* 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/tnf_probe.h>
#ifndef NPROBE
extern int tnf_mod_load(void);
#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 */
};
/* 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 */
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;
"SUNW 1394-based Digital Camera driver 1.0",
};
static struct modlinkage modlinkage = {
(void *)&modldrv,
NULL,
};
int
_init(void)
{
int err;
if (err) {
return (err);
}
#ifndef NPROBE
(void) tnf_mod_load();
#endif /* ! NPROBE */
#ifndef NPROBE
(void) tnf_mod_unload(&modlinkage);
#endif /* ! NPROBE */
}
return (err);
}
int
{
int err;
return (err);
}
int
_fini(void)
{
int err;
return (err);
}
#ifndef NPROBE
(void) tnf_mod_unload(&modlinkage);
#endif /* ! NPROBE */
return (err);
}
/*
* dcam_attach
*/
/* ARGSUSED */
int
{
char tmp_str[MAX_STR_LEN];
int instance;
int ret_val;
switch (cmd) {
case DDI_ATTACH:
DDI_SUCCESS) {
return (DDI_FAILURE);
}
NULL) {
return (DDI_FAILURE);
}
/*
* Initialize soft state
*/
softc_p->param_status = 0;
/*
* set default vid_mode, frame_rate and ring_buff_capacity
*/
DDI_PSEUDO, 0) != DDI_SUCCESS) {
return (DDI_FAILURE);
}
DDI_SUCCESS) {
return (DDI_FAILURE);
}
&(softc_p->attachinfo),
return (DDI_FAILURE);
}
"dcam_attach: t1394_get_targetinfo failed\n");
}
&ev_cookie) != DDI_SUCCESS) {
return (DDI_FAILURE);
}
return (DDI_FAILURE);
}
/*
* init the soft state's parameter attribute structure
*/
DDI_SUCCESS) {
return (DDI_FAILURE);
}
/*
* power management stuff
*/
sizeof (dcam_pmc)/sizeof (char *)) == DDI_PROP_SUCCESS) {
"power-managed?")) {
(void) pm_idle_component(dip, 0);
} else {
(void) pm_busy_component(dip, 0);
}
}
break;
case DDI_RESUME:
NULL) {
return (DDI_FAILURE);
}
(void) dcam1394_ioctl_frame_rcv_start(softc_p);
}
break;
default:
break;
}
return (ret_val);
}
/*
* dcam_power: perform dcam power management
*/
/* ARGSUSED */
int
{
int instance;
return (DDI_FAILURE);
return (DDI_SUCCESS);
}
/*
* dcam_getinfo
*/
/* ARGSUSED */
int
{
int status;
int instance;
switch (cmd) {
case DDI_INFO_DEVT2DEVINFO:
softc_p = (dcam_state_t *)
return (DDI_FAILURE);
}
break;
case DDI_INFO_DEVT2INSTANCE:
break;
default:
}
return (status);
}
/*
* dcam_detach
*/
/* ARGSUSED */
int
{
int instance;
return (DDI_FAILURE);
}
switch (cmd) {
case DDI_SUSPEND:
(void) dcam_frame_rcv_stop(softc_p);
}
return (DDI_SUCCESS);
case DDI_DETACH:
/*
* power management stuff
*/
(void) pm_lower_power(dip, 0, 0);
/*
* deregister with 1394 DDI framework
*/
return (DDI_FAILURE);
}
/*
* free state structures, mutexes, condvars;
* deregister interrupts
*/
/*
* Remove all minor nodes, all dev_t's properties
*/
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
}
/*
* dcam_open
*/
/* ARGSUSED */
int
{
int instance;
int is_ctrl_file;
return (ENXIO);
}
/*
* if dcam_attach hasn't completed, return error
* XXX: Check this out
*/
return (ENXIO);
}
/* disallow block, mount, and layered opens */
return (EINVAL);
}
new_flags = 0;
/*
* 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) {
} else {
return (EBUSY);
}
}
/*
* power management stuff
*/
if (softc_p->pm_open_count == 0) {
"power-managed?")) {
if (softc_p->pm_cable_power == 0) {
int i;
/*
* 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++) {
break;
}
}
}
}
}
softc_p->pm_open_count++;
return (0);
}
/*
* dcam_close
*/
/* ARGSUSED */
int
{
int instance;
/*
* power management stuff
*/
softc->pm_open_count = 0;
}
} 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.
*/
(void) dcam_frame_rcv_stop(softc);
}
(void) param_power_set(softc, 0);
}
/*
* If driver is completely closed, then stabilize the camera
* and turn off transient flags
*/
}
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
{
int read_ptr_id;
int read_req_invalid;
unsigned long user_frame_buff_addr;
int gotten_addr_flag;
return (ENXIO);
}
return (EAGAIN);
}
read_ptr_id = 0;
user_frame_buff_addr = 0;
gotten_addr_flag = 0;
do {
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) {
} else {
}
/*
* copy frame data from ring buffer position pointed
* to by read pointer
*/
index = 0;
/*
* Fix for bug #4424042
* don't lock this section
*/
return (EFAULT);
}
return (EFAULT);
}
return (EFAULT);
}
/*
* get buff pointer; do ddi_copyout()
* get user buffer address only once
*/
if (!gotten_addr_flag) {
return (EFAULT);
}
#ifdef _MULTI_DATAMODEL
((user_frame_buff_addr >> 32) &
0xffffffffULL) |
((user_frame_buff_addr << 32) &
0xffffffff00000000ULL);
}
#endif /* _MULTI_DATAMODEL */
gotten_addr_flag = 1;
}
if (ddi_copyout(
0)) {
return (EFAULT);
}
/*
* if during the course of copying frame data,
* the device driver invalidated this read()
* request processing operation; restart this
* operation
*/
} else {
return (EAGAIN);
}
} while (read_req_invalid);
/*
* return number of bytes actually written to user space
*/
/* increment read pointer */
return (0);
}
/*
* dcam_ioctl
*/
/* ARGSUSED */
int
int *rvalp)
{
rc = 0;
param_list = (dcam1394_param_list_t *)0;
goto done;
}
/*
* determine user applications data model
*/
else
switch (cmd) {
case DCAM1394_CMD_REG_READ:
sizeof (dcam1394_reg_io_t), mode)) {
goto done;
}
goto done;
}
sizeof (dcam1394_reg_io_t), mode)) {
goto done;
}
break;
case DCAM1394_CMD_REG_WRITE:
sizeof (dcam1394_reg_io_t), mode)) {
goto done;
}
goto done;
}
sizeof (dcam1394_reg_io_t), mode)) {
goto done;
}
break;
case DCAM1394_CMD_CAM_RESET:
if (dcam_reset(softc_p)) {
goto done;
}
break;
case DCAM1394_CMD_PARAM_GET:
sizeof (dcam1394_param_list_t), mode)) {
goto done;
}
}
sizeof (dcam1394_param_list_t), mode)) {
goto done;
}
break;
case DCAM1394_CMD_PARAM_SET:
KM_SLEEP);
sizeof (dcam1394_param_list_t), mode)) {
goto done;
}
*param_list)) {
}
if (is_ctrl_file) {
}
sizeof (dcam1394_param_list_t), mode)) {
goto done;
}
break;
}
break;
if (dcam_frame_rcv_stop(softc_p)) {
}
break;
break;
}
/*
* the simplest way to flush ring_buff is to empty it
*/
/*
* if device driver is processing a user
* process's read() request
*/
if (softc_p->reader_flags[i] &
/*
* invalidate the read() request processing
* operation
*/
softc_p->reader_flags[i] |=
}
}
break;
break;
default:
break;
}
done:
if (param_list)
return (rc);
}
/*
* dcam_chpoll
*/
/* ARGSUSED */
int
{
short revent;
return (ENXIO);
}
read_ptr_id = 0;
revent = 0;
ring_buff_has_data = 0;
} else {
if (read_ptr_pos != write_ptr_pos) {
ring_buff_has_data = 1;
} else {
ring_buff_has_data = 0;
}
}
/*
* now check for events
*/
revent |= POLLRDNORM;
}
}
/* if no events have occurred */
if (revent == 0) {
if (!anyyet) {
}
}
return (0);
}
/*
* dcam_bus_reset_notify
*/
/* ARGSUSED */
void
void *impl_data)
{
/*
* this is needed to handle LG camera "changing GUID" bug
* XXX: What's this about?
*/
return;
}
/*
* simply return if no target info
*/
return;
} else {
}
/* struct copies */
}
}
/*
* byte_copy_to_user_buff
*/
static int
int start_index, int *end_index_p)
{
int index;
index = start_index;
while (num_bytes) {
return (-1);
}
index++;
}
*end_index_p = index;
return (0);
}
/*
* byte_copy_from_user_buff
*/
static int
{
int index;
index = start_index;
while (num_bytes) {
return (-1);
}
index++;
}
*end_index_p = index;
return (0);
}
/*
* dcam_reset()
*/
static int
{
return (-1);
}
/*
* If the camera has a TI VSP, tweak the iris feature
* to "on" and value 4.
*/
return (-1);
}
return (0);
}