/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* av1394 isochronous transmit module
*/
static int av1394_it_start_common(av1394_ic_t *);
/* configuration routines */
static void av1394_it_cleanup(av1394_ic_t *, int);
static int av1394_it_bld_ixl(av1394_ic_t *);
static void av1394_it_destroy_ixl(av1394_ic_t *);
static int av1394_it_ixl_bld_data(av1394_ic_t *);
static void av1394_it_ixl_destroy_data(av1394_ic_t *);
off_t, int, int);
static void av1394_it_ixl_complete_buf(av1394_it_ixl_buf_t *,
static void av1394_it_ixl_complete_buf2(av1394_it_ixl_buf_t *,
int);
static void av1394_it_ixl_complete_empty_cip(av1394_it_ixl_empty_cip_t *,
static void av1394_it_ixl_bld_begin(av1394_ic_t *);
static void av1394_it_ixl_begin_update_pkts(av1394_ic_t *,
static int av1394_it_alloc_isoch_dma(av1394_ic_t *);
static void av1394_it_free_isoch_dma(av1394_ic_t *);
static void av1394_it_dma_sync_frames(av1394_ic_t *, int, int);
/* callbacks */
static int av1394_it_underrun_resume(av1394_ic_t *);
static void av1394_it_dma_stopped_cb(t1394_isoch_dma_handle_t,
/* data transfer routines */
static int av1394_it_add_frames(av1394_ic_t *, int, int);
static int av1394_it_wait_frames(av1394_ic_t *, int *, int *, int *);
static void av1394_it_reset_frame_syt(av1394_ic_t *, int);
/* tunables */
int av1394_it_dump_ixl = 0;
int
{
int nframes;
if (nframes == 0) {
return (EINVAL);
}
return (EINVAL);
}
return (EINVAL);
}
return (EINVAL);
}
return (0);
}
void
{
}
int
{
int ret = 0;
/* should be enough full frames to be able to start */
}
return (ret);
}
static int
{
int result;
int err;
int ret = 0;
&idma_ctrlinfo, 0, &result);
if (err == DDI_SUCCESS) {
} else {
}
return (ret);
}
int
{
itp->it_first_empty = 0;
}
return (0);
}
int
{
int ret = 0;
/* check arguments */
return (EINVAL);
}
/* add full frames to the pool */
if (cnt > 0) {
return (ret);
}
}
return (ret);
}
}
/* wait for new empty frames */
return (ret);
}
int
{
int dv;
int ret = 0;
int full_cnt;
int miss_cnt;
/* must have at least one empty frame */
if (itp->it_write_cnt == 0) {
if (ret != 0) {
break;
}
}
/* copyin as much data as we can */
if (axp->ax_copy_ciph) {
}
break;
}
/* add full frames to the pool */
if (full_cnt > 0) {
if (ret != 0) {
break;
}
}
/* start xfer if not already */
return (ret);
}
}
}
return (ret);
}
/*
*
* --- configuration routines
*
*/
static void
{
switch (level) {
default:
/* FALLTHRU */
case 3:
/* FALLTHRU */
case 2:
/* FALLTHRU */
case 1:
/* FALLTHRU */
}
}
/*
* av1394_it_bld_ixl()
* Build an IXL chain out of several blocks.
*/
static int
{
int ret;
/* data block */
return (ret);
}
/* begin block */
} else {
}
if (av1394_it_dump_ixl) {
}
return (ret);
}
static void
{
}
/*
* build data transmit part of the IXL chain
*/
static int
{
int a, n, d; /* N/D algorithm variables */
int tb_flags;
sizeof (av1394_it_frame_info_t), KM_SLEEP);
/*
* following assert guarantees no more than one empty CIP in a row,
* i.e. empty CIPs account for <=50% of all packets.
* this should be ensured by ioctl argument validation.
*/
ASSERT((n == 0) || (d / n > 1));
/*
* build the chain. it is hard to precalculate amount of memory
* needed for the entire chain, so we simply allocate as we go.
*/
a = n;
/* insert empty CIPs using N/D algorithm */
a += n;
if (a > d) {
a -= d;
} else {
nfull++;
}
/*
* merge series of full packets into single SEND_BUF commands.
* a series can be terminated by:
* - an empty CIP;
* - series buffer size reached maximum;
* - end of isoch segment;
* - end of frame (which is always at the end of segment);
*/
/* build buffer block */
tb_flags = 0;
if (type == AV1394_CIP_EMPTY) {
}
framenum++;
}
}
}
/* complete previous empty CIP or a buffer */
if (ep) {
} else if (prevbp) {
}
/* if current segment is used up, pick next one */
}
segoff = 0;
}
nfull = 0;
}
/* insert an empty packet if needed */
if (type == AV1394_CIP_EMPTY) {
}
}
/* last packet must be an empty CIP, except when n == 0 */
if (n != 0) {
if (ptype != AV1394_CIP_EMPTY) {
}
} else {
}
return (DDI_SUCCESS);
}
static void
{
}
}
static av1394_it_ixl_buf_t *
{
/* tc_next later */
if (flags & AV1394_IT_IXL_BUF_EOF) {
} else {
}
/*
* jump label and next_ixlp later.
* unset fields will be set in av1394_it_ixl_complete_buf()
*
* save additional frame info
*/
if (flags & AV1394_IT_IXL_BUF_SOF) {
} else if (flags & AV1394_IT_IXL_BUF_EOF) {
}
return (bp);
}
static void
{
}
static void
{
}
static av1394_it_ixl_empty_cip_t *
{
/* tc_next later */
/* ixl_buf and mem_bufp later */
/*
* label and next_ixlp later.
* unset fields will be set in av1394_it_ixl_complete_empty_cip()
*/
return (ep);
}
/*
* empty CIP packet contains CIP header of the next packet,
* so we just point to the same address as the next packet's header
*/
static void
{
}
static void
{
int i;
for (i = 0; i < AV1394_IT_IXL_BEGIN_NPOST; i++) {
}
}
static void
{
int i;
for (i = 0; i < AV1394_IT_IXL_BEGIN_NPOST; i++) {
}
}
static int
{
int result;
int ret;
/*
* XXX this should really be IXL1394_SKIP_TO_NEXT,
* but it can't be used yet due to the Framework bug
*/
di.default_sync = 0;
}
return (ret);
}
static void
{
}
static void
{
}
/*
*
* --- callbacks
*
*/
static void
{
int first;
/* save initial timestamp value */
/*
* update frame timestamps if needed
*/
return;
}
}
/*ARGSUSED*/
static void
{
}
}
static void
{
}
}
}
void
{
int idx;
int err;
int result;
/*
* update the last full frame's jump to NULL
*/
if (err == DDI_SUCCESS) {
} else {
}
}
/*
* resume from the underrun condition
*/
static int
{
int idx;
int err;
int result;
/*
* resuming the transfer it a lot like starting the transfer:
* first the IXL begin block needs to be executed, then the rest
* of the IXL chain. The following dynamic updates are needed:
*
* 1. update the begin block to jump to the first empty frame;
* 2. restore the original jump label which we previously
* changed to jump to the underrun block;
*
* update #1
* start by updating the begin block with a new buffer address
*/
if (err != DDI_SUCCESS) {
return (EIO);
}
/*
* update #2
*/
if (err != DDI_SUCCESS) {
return (EIO);
}
return (0);
}
/*ARGSUSED*/
static void
{
}
/*
*
* --- data transfer routines
*
* av1394_it_add_frames()
* Add full frames to the pool.
*/
static int
{
int ret = 0;
/* can only add to tail */
return (EINVAL);
}
/* turn empty frames into full ones */
/*
* update frame timestamps if needed
*/
}
/* if suspended due to overrun, check if we can resume */
}
return (ret);
}
/*
* wait for empty frames
*/
static int
{
int ret = 0;
break;
}
}
*nlost = 0;
ret = 0;
}
return (ret);
}
/*
* update frame timestamps for a range of frames
*/
static void
{
int i;
int j = first; /* frame number */
for (i = cnt; i > 0; i--) {
}
}
/*
* convert cycle timestamp into SYT timestamp:
*
* Cycle timer: cycleSeconds cycleCount cycleOffset
* 31_30_29_28_27_26_25 24___15_14_13_12 11________0
* Cycle timestamp: |------------------------|
* SYT timestamp: |----------------------|
*/
static uint16_t
{
}
/*
* increment SYT by a number of cycles
*/
static uint16_t
{
}
/*
* copyin from the kernel buffer
*/
static void
{
}
/*
* copyin from the user buffer
*/
static int
{
int ret = 0;
*full_cnt = 0;
if (ret != 0) {
break;
}
/*
* for DV formats, make sure we got a frame start.
* this is to ensure correct timestamping
*/
while (!av1394_it_is_dv_frame_start(kaddr)) {
break;
}
}
if (start_resid != framesz) {
}
}
/* for DV formats, reset frame's SYT fields */
if (dv) {
}
itp->it_write_off = 0;
itp->it_write_cnt--;
(*full_cnt)++;
}
}
return (ret);
}
/*
* check if a packet starts a new DV frame
*/
static boolean_t
{
/*
* in the DIF block ID data, which immediately follows CIP header,
* SCT, Dseq and DBN fields should be zero (Ref: IEC 61834-2, Fig. 66)
*/
return (((p[0] & 0xE0) == 0) && ((p[1] & 0xF0) == 0) && (p[2] == 0));
}
/*
* reset all frame's SYT fields
*/
static void
{
kaddr += 6;
}
}