18eea8e29Sap /*
28eea8e29Sap  * CDDL HEADER START
38eea8e29Sap  *
48eea8e29Sap  * The contents of this file are subject to the terms of the
58eea8e29Sap  * Common Development and Distribution License, Version 1.0 only
68eea8e29Sap  * (the "License").  You may not use this file except in compliance
78eea8e29Sap  * with the License.
88eea8e29Sap  *
98eea8e29Sap  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
108eea8e29Sap  * or http://www.opensolaris.org/os/licensing.
118eea8e29Sap  * See the License for the specific language governing permissions
128eea8e29Sap  * and limitations under the License.
138eea8e29Sap  *
148eea8e29Sap  * When distributing Covered Code, include this CDDL HEADER in each
158eea8e29Sap  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
168eea8e29Sap  * If applicable, add the following below this CDDL HEADER, with the
178eea8e29Sap  * fields enclosed by brackets "[]" replaced with your own identifying
188eea8e29Sap  * information: Portions Copyright [yyyy] [name of copyright owner]
198eea8e29Sap  *
208eea8e29Sap  * CDDL HEADER END
218eea8e29Sap  */
228eea8e29Sap /*
238eea8e29Sap  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
248eea8e29Sap  * Use is subject to license terms.
258eea8e29Sap  */
268eea8e29Sap 
278eea8e29Sap /*
288eea8e29Sap  * dcam_frame.c
298eea8e29Sap  *
308eea8e29Sap  * dcam1394 driver.  Support for video frame access.
318eea8e29Sap  */
328eea8e29Sap 
338eea8e29Sap #include <sys/int_limits.h>
348eea8e29Sap #include <sys/types.h>
358eea8e29Sap #include <sys/kmem.h>
368eea8e29Sap #include <sys/cmn_err.h>
378eea8e29Sap #include <sys/1394/targets/dcam1394/dcam.h>
388eea8e29Sap #include <sys/1394/targets/dcam1394/dcam_frame.h>
398eea8e29Sap #include <sys/dcam/dcam1394_io.h>
408eea8e29Sap 
418eea8e29Sap #include <sys/1394/targets/dcam1394/dcam_reg.h>
428eea8e29Sap 
438eea8e29Sap static void dcam_free_resources(dcam_state_t *);
448eea8e29Sap 
458eea8e29Sap typedef struct dcam_mode_info_s {
468eea8e29Sap 	int bytes_per_pkt;
478eea8e29Sap 	int pkts_per_frame;
488eea8e29Sap } dcam_mode_info_t;
498eea8e29Sap 
508eea8e29Sap /*
518eea8e29Sap  * packets per frame
528eea8e29Sap  *
538eea8e29Sap  * 30fps
548eea8e29Sap  *  mode_0 1/2h, 60q,  240b
558eea8e29Sap  *  mode_1 1h,  160q,  640
568eea8e29Sap  *  mode_2 2h,  480q, 1920
578eea8e29Sap  *  mode_3 2h,  640q, 2560
588eea8e29Sap  *  mode_4 2h,  960q, 3840
598eea8e29Sap  *  mode_5 2h,  320q, 1280
608eea8e29Sap  *
618eea8e29Sap  * 15fps
628eea8e29Sap  *  mode_0 1/4h, 30q,  120
638eea8e29Sap  *  mode_1 1/2h, 80q,  320
648eea8e29Sap  *  mode_2 1h,  240q,  960
658eea8e29Sap  *  mode_3 1h,  320q, 1280
668eea8e29Sap  *  mode_4 1h,  480q, 1920
678eea8e29Sap  *  mode_5 1h,  160q,  640
688eea8e29Sap  *
698eea8e29Sap  * 7.5fps
708eea8e29Sap  *  mode_0 1/8h,  15q,  60
718eea8e29Sap  *  mode_1 1/4h,  40q, 160
728eea8e29Sap  *  mode_2 1/2h, 120q, 480
738eea8e29Sap  *  mode_3 1/2h, 160q, 640
748eea8e29Sap  *  mode_4 1/2h, 240q, 960
758eea8e29Sap  *  mode_5 1/2h,  80q, 320
768eea8e29Sap  *
778eea8e29Sap  * 3.75fps
788eea8e29Sap  *  mode_0 x
798eea8e29Sap  *  mode_1 1/8h,  20q,  80
808eea8e29Sap  *  mode_2 1/4h,  60q, 240
818eea8e29Sap  *  mode_3 1/4h,  80q, 320
828eea8e29Sap  *  mode_4 1/4h, 120q, 480
838eea8e29Sap  *  mode_5 1/4h,  40q, 160
848eea8e29Sap  *
858eea8e29Sap  * 60fps
868eea8e29Sap  *  mode_5 4H, 640q, 2560
878eea8e29Sap  *
888eea8e29Sap  */
898eea8e29Sap 
908eea8e29Sap /* indexed by vid mode, frame rate */
918eea8e29Sap static int g_bytes_per_packet[6][5] = {
928eea8e29Sap 
938eea8e29Sap 	/* fps:			3.75	7.5	15	30	60 */
948eea8e29Sap 	/* vid mode 0 */	-1,	60,	120,	240,	-1,
958eea8e29Sap 	/* vid mode 1 */	80,	160,	320,	640,	-1,
968eea8e29Sap 	/* vid mode 2 */	240,	480,	960,	1920,	-1,
978eea8e29Sap 	/* vid mode 3 */	320,	640,	1280,	2560,	-1,
988eea8e29Sap 	/* vid mode 4 */	480,	960,	1920,	3840,	-1,
998eea8e29Sap 	/* vid mode 5 */	160,	320,	640,	1280,	2560
1008eea8e29Sap };
1018eea8e29Sap 
1028eea8e29Sap /* indexed by vid mode */
1038eea8e29Sap static int g_bytes_per_frame[6] = {
1048eea8e29Sap     57600,
1058eea8e29Sap     153600,
1068eea8e29Sap     460800,
1078eea8e29Sap     614400,
1088eea8e29Sap     921600,
1098eea8e29Sap     307200
1108eea8e29Sap };
1118eea8e29Sap 
1128eea8e29Sap 
1138eea8e29Sap static
1148eea8e29Sap void dcam_rsrc_fail(t1394_isoch_single_handle_t	t1394_single_hdl,
1158eea8e29Sap     opaque_t single_evt_arg, t1394_isoch_rsrc_error_t fail_args);
1168eea8e29Sap 
1178eea8e29Sap /*
1188eea8e29Sap  * dcam1394_ioctl_frame_rcv_start
1198eea8e29Sap  */
1208eea8e29Sap int
dcam1394_ioctl_frame_rcv_start(dcam_state_t * softc_p)1218eea8e29Sap dcam1394_ioctl_frame_rcv_start(dcam_state_t *softc_p)
1228eea8e29Sap {
1238eea8e29Sap 	if (!(softc_p->flags & DCAM1394_FLAG_FRAME_RCV_INIT)) {
1248eea8e29Sap 
1258eea8e29Sap 		if (dcam_frame_rcv_init(softc_p, softc_p->cur_vid_mode,
1268eea8e29Sap 		    softc_p->cur_frame_rate, softc_p->cur_ring_buff_capacity)) {
1278eea8e29Sap 
1288eea8e29Sap 			dcam_free_resources(softc_p);
1298eea8e29Sap 			return (1);
1308eea8e29Sap 		}
1318eea8e29Sap 
1328eea8e29Sap 		softc_p->flags |= DCAM1394_FLAG_FRAME_RCV_INIT;
1338eea8e29Sap 	}
1348eea8e29Sap 
1358eea8e29Sap 	if (dcam_frame_rcv_start(softc_p)) {
1368eea8e29Sap 		return (1);
1378eea8e29Sap 	}
1388eea8e29Sap 
1398eea8e29Sap 	return (0);
1408eea8e29Sap }
1418eea8e29Sap 
1428eea8e29Sap 
1438eea8e29Sap /*
1448eea8e29Sap  * dcam_frame_rcv_init
1458eea8e29Sap  */
1468eea8e29Sap int
dcam_frame_rcv_init(dcam_state_t * softc_p,int vid_mode,int frame_rate,int ring_buff_capacity)1478eea8e29Sap dcam_frame_rcv_init(dcam_state_t *softc_p, int vid_mode, int frame_rate,
1488eea8e29Sap     int ring_buff_capacity)
1498eea8e29Sap {
1508eea8e29Sap 	int16_t			bytes_per_pkt;	/* # pkt bytes + overhead */
1518eea8e29Sap 	int			bytes_per_frame;
1528eea8e29Sap 	size_t			frame;
1538eea8e29Sap 	int			cookie;
1548eea8e29Sap 	int			failure;
1558eea8e29Sap 	id1394_isoch_dmainfo_t	isoch_args;	/* for alloc isoch call */
1568eea8e29Sap 	ixl1394_command_t	*last_ixlp;	/* last ixl in chain, */
1578eea8e29Sap 						/* used for appending ixls */
1588eea8e29Sap 	ixl1394_command_t	*new_ixl_cmdp;	/* new ixl command */
1598eea8e29Sap 	ixl1394_set_syncwait_t	*new_ixl_sswp;	/* new ixl set syncwait */
1608eea8e29Sap 	ixl1394_xfer_pkt_t	*new_ixl_xfpp;	/* new ixl xfer packet */
1618eea8e29Sap 	ixl1394_xfer_buf_t	*new_ixl_xfbp;	/* new ixl xfer buffer */
1628eea8e29Sap 	ixl1394_callback_t	*new_ixl_cbp;	/* new ixl callback */
1638eea8e29Sap 	ixl1394_jump_t		*new_ixl_jmpp;	/* new ixl jump */
1648eea8e29Sap 	int32_t			result;		/* errno from alloc_isoch_dma */
1658eea8e29Sap 	buff_info_t		*buff_info_p;
1668eea8e29Sap 	dcam1394_reg_io_t	reg_io;
1678eea8e29Sap 	uint_t			data;
1688eea8e29Sap 	size_t			num_bytes, num_bytes_left;
1698eea8e29Sap 	size_t			num_xfer_cmds, xfer_cmd;
1708eea8e29Sap 	size_t			max_ixl_buff_size;
171*c7ff2aaeSap 	uint64_t		ixl_buff_kaddr;
172*c7ff2aaeSap 	caddr_t			ixl_buff_vaddr;
1738eea8e29Sap 
1748eea8e29Sap 	bytes_per_pkt = g_bytes_per_packet[vid_mode][frame_rate];
1758eea8e29Sap 	if (bytes_per_pkt == -1) {
1768eea8e29Sap 		return (1);
1778eea8e29Sap 	}
1788eea8e29Sap 
1798eea8e29Sap 	bytes_per_frame = g_bytes_per_frame[vid_mode];
1808eea8e29Sap 
1818eea8e29Sap 	if ((softc_p->ring_buff_p = ring_buff_create(softc_p,
1828eea8e29Sap 	    (size_t)ring_buff_capacity, (size_t)bytes_per_frame)) == NULL) {
1838eea8e29Sap 		return (1);
1848eea8e29Sap 	}
1858eea8e29Sap 
1868eea8e29Sap 	softc_p->ring_buff_p->read_ptr_pos[0] = 0;
1878eea8e29Sap 
1888eea8e29Sap 	/* allocate isoch channel */
1898eea8e29Sap 	softc_p->sii.si_channel_mask	= 0xFFFF000000000000;
1908eea8e29Sap 	softc_p->sii.si_bandwidth	= bytes_per_pkt;
1918eea8e29Sap 	softc_p->sii.rsrc_fail_target	= dcam_rsrc_fail;
1928eea8e29Sap 	softc_p->sii.single_evt_arg	= softc_p;
1938eea8e29Sap 	softc_p->sii.si_speed		= softc_p->targetinfo.current_max_speed;
1948eea8e29Sap 
1958eea8e29Sap 	if (t1394_alloc_isoch_single(softc_p->sl_handle,
1968eea8e29Sap 	    &softc_p->sii, 0, &softc_p->sii_output_args, &softc_p->sii_hdl,
1978eea8e29Sap 	    &failure) != DDI_SUCCESS) {
1988eea8e29Sap 		return (1);
1998eea8e29Sap 	}
2008eea8e29Sap 
2018eea8e29Sap 	/*
2028eea8e29Sap 	 * At this point, all buffer memory has been allocated and
2038eea8e29Sap 	 * mapped, and is tracked on a linear linked list.  Now need to
2048eea8e29Sap 	 * build the IXL.  Done on a frame-by-frame basis.  Could
2058eea8e29Sap 	 * theoretically have been done at the same time as the mem alloc
2068eea8e29Sap 	 * above, but hey, no need to be so fancy here.
2078eea8e29Sap 	 *
2088eea8e29Sap 	 * ixl buff size is bound by SHRT_MAX and needs to
2098eea8e29Sap 	 * be a multiple of packet size
2108eea8e29Sap 	 */
2118eea8e29Sap 	max_ixl_buff_size = (SHRT_MAX / bytes_per_pkt) * bytes_per_pkt;
2128eea8e29Sap 
2138eea8e29Sap 	/* for each frame build frame's ixl list */
2148eea8e29Sap 	for (frame = 0; frame < softc_p->ring_buff_p->num_buffs; frame++) {
2158eea8e29Sap 
2168eea8e29Sap 		buff_info_p = &(softc_p->ring_buff_p->buff_info_array_p[frame]);
2178eea8e29Sap 
2188eea8e29Sap 		/*
2198eea8e29Sap 		 * if this is the 1st frame, put a IXL label at the top so a
2208eea8e29Sap 		 * loop can be created later
2218eea8e29Sap 		 */
2228eea8e29Sap 		if (frame == 0) {
2238eea8e29Sap 			new_ixl_cmdp = kmem_zalloc(
2248eea8e29Sap 					sizeof (ixl1394_label_t), KM_SLEEP);
2258eea8e29Sap 			softc_p->ixlp = new_ixl_cmdp;
2268eea8e29Sap 
2278eea8e29Sap 			new_ixl_cmdp->ixl_opcode = IXL1394_OP_LABEL;
2288eea8e29Sap 
2298eea8e29Sap 			last_ixlp = softc_p->ixlp;
2308eea8e29Sap 		}
2318eea8e29Sap 
2328eea8e29Sap 		/* add wait-for-sync IXL command */
2338eea8e29Sap 		new_ixl_sswp = kmem_zalloc(
2348eea8e29Sap 				sizeof (ixl1394_set_syncwait_t), KM_SLEEP);
2358eea8e29Sap 
2368eea8e29Sap 		new_ixl_sswp->ixl_opcode = IXL1394_OP_SET_SYNCWAIT;
2378eea8e29Sap 
2388eea8e29Sap 		last_ixlp->next_ixlp = (ixl1394_command_t *)new_ixl_sswp;
2398eea8e29Sap 		last_ixlp = (ixl1394_command_t *)new_ixl_sswp;
2408eea8e29Sap 
2418eea8e29Sap 		/* add in each dma cookie */
2428eea8e29Sap 		for (cookie = 0; cookie < buff_info_p->dma_cookie_count;
2438eea8e29Sap 		    cookie++) {
2448eea8e29Sap 
2458eea8e29Sap 			num_xfer_cmds = min(bytes_per_frame,
2468eea8e29Sap 			    buff_info_p->dma_cookie.dmac_size) /
2478eea8e29Sap 			    max_ixl_buff_size;
2488eea8e29Sap 
2498eea8e29Sap 			if (min(bytes_per_frame,
2508eea8e29Sap 			    buff_info_p->dma_cookie.dmac_size) %
2518eea8e29Sap 			    max_ixl_buff_size) {
2528eea8e29Sap 				num_xfer_cmds++;
2538eea8e29Sap 			}
2548eea8e29Sap 
2558eea8e29Sap 			num_bytes_left = min(bytes_per_frame,
2568eea8e29Sap 			    buff_info_p->dma_cookie.dmac_size);
2578eea8e29Sap 
258*c7ff2aaeSap 			ixl_buff_kaddr =
2598eea8e29Sap 			    buff_info_p->dma_cookie.dmac_laddress;
2608eea8e29Sap 
2618eea8e29Sap 			ixl_buff_vaddr = buff_info_p->kaddr_p;
2628eea8e29Sap 
2638eea8e29Sap 			for (xfer_cmd = 0; xfer_cmd < (num_xfer_cmds + 1);
2648eea8e29Sap 			    xfer_cmd++) {
2658eea8e29Sap 				num_bytes = min(num_bytes_left,
2668eea8e29Sap 				    max_ixl_buff_size);
2678eea8e29Sap 
2688eea8e29Sap 				if (xfer_cmd == 0) {
2698eea8e29Sap 					new_ixl_xfpp =
2708eea8e29Sap 					    kmem_zalloc(
2718eea8e29Sap 						sizeof (ixl1394_xfer_pkt_t),
2728eea8e29Sap 						KM_SLEEP);
2738eea8e29Sap 
2748eea8e29Sap 					new_ixl_xfpp->ixl_opcode =
2758eea8e29Sap 					    IXL1394_OP_RECV_PKT_ST;
2768eea8e29Sap 
2778eea8e29Sap 					new_ixl_xfpp->ixl_buf._dmac_ll =
278*c7ff2aaeSap 					    ixl_buff_kaddr;
2798eea8e29Sap 					new_ixl_xfpp->size =
2808eea8e29Sap 					    (uint16_t)bytes_per_pkt;
2818eea8e29Sap 					new_ixl_xfpp->mem_bufp =
2828eea8e29Sap 					    ixl_buff_vaddr;
2838eea8e29Sap 
2848eea8e29Sap 					last_ixlp->next_ixlp =
2858eea8e29Sap 					    (ixl1394_command_t *)new_ixl_xfpp;
2868eea8e29Sap 					last_ixlp =
2878eea8e29Sap 					    (ixl1394_command_t *)new_ixl_xfpp;
2888eea8e29Sap 
2898eea8e29Sap 					num_bytes_left -= bytes_per_pkt;
2908eea8e29Sap 					ixl_buff_kaddr += bytes_per_pkt;
2918eea8e29Sap 					ixl_buff_vaddr += bytes_per_pkt;
2928eea8e29Sap 
2938eea8e29Sap 					continue;
2948eea8e29Sap 				}
2958eea8e29Sap 
2968eea8e29Sap 				/* allocate & init an IXL transfer command. */
2978eea8e29Sap 				new_ixl_xfbp =
2988eea8e29Sap 				    kmem_zalloc(sizeof (ixl1394_xfer_buf_t),
2998eea8e29Sap 					    KM_SLEEP);
3008eea8e29Sap 
3018eea8e29Sap 				new_ixl_xfbp->ixl_opcode = IXL1394_OP_RECV_BUF;
3028eea8e29Sap 
3038eea8e29Sap 				new_ixl_xfbp->ixl_buf._dmac_ll =
304*c7ff2aaeSap 				    ixl_buff_kaddr;
3058eea8e29Sap 				new_ixl_xfbp->size = (uint16_t)num_bytes;
3068eea8e29Sap 				new_ixl_xfbp->pkt_size = bytes_per_pkt;
3078eea8e29Sap 				new_ixl_xfbp->mem_bufp = ixl_buff_vaddr;
3088eea8e29Sap 
3098eea8e29Sap 				last_ixlp->next_ixlp =
3108eea8e29Sap 				    (ixl1394_command_t *)new_ixl_xfbp;
3118eea8e29Sap 				last_ixlp =
3128eea8e29Sap 				    (ixl1394_command_t *)new_ixl_xfbp;
3138eea8e29Sap 
3148eea8e29Sap 				num_bytes_left -= num_bytes;
3158eea8e29Sap 				ixl_buff_kaddr += num_bytes;
3168eea8e29Sap 				ixl_buff_vaddr += num_bytes;
3178eea8e29Sap 			}
3188eea8e29Sap 
3198eea8e29Sap 			if (cookie > 0) {
3208eea8e29Sap 				ddi_dma_nextcookie(buff_info_p->dma_handle,
3218eea8e29Sap 				    &(buff_info_p->dma_cookie));
3228eea8e29Sap 			}
3238eea8e29Sap 
3248eea8e29Sap 		}
3258eea8e29Sap 
3268eea8e29Sap 		/*
3278eea8e29Sap 		 * at this point, have finished a frame.  put in a callback
3288eea8e29Sap 		 */
3298eea8e29Sap 		new_ixl_cbp = kmem_zalloc(
3308eea8e29Sap 				sizeof (ixl1394_callback_t), KM_SLEEP);
3318eea8e29Sap 
3328eea8e29Sap 		new_ixl_cbp->ixl_opcode	= IXL1394_OP_CALLBACK;
3338eea8e29Sap 
3348eea8e29Sap 		new_ixl_cbp->callback = &dcam_frame_is_done;
3358eea8e29Sap 		new_ixl_cbp->callback_arg = NULL;
3368eea8e29Sap 
3378eea8e29Sap 		last_ixlp->next_ixlp = (ixl1394_command_t *)new_ixl_cbp;
3388eea8e29Sap 		last_ixlp = (ixl1394_command_t *)new_ixl_cbp;
3398eea8e29Sap 	}
3408eea8e29Sap 
3418eea8e29Sap 	/*
3428eea8e29Sap 	 * for the final touch, put an IXL jump at the end to jump to the
3438eea8e29Sap 	 * label at the top
3448eea8e29Sap 	 */
3458eea8e29Sap 	new_ixl_jmpp = kmem_zalloc(sizeof (ixl1394_jump_t), KM_SLEEP);
3468eea8e29Sap 
3478eea8e29Sap 	new_ixl_jmpp->ixl_opcode = IXL1394_OP_JUMP;
3488eea8e29Sap 
3498eea8e29Sap 	new_ixl_jmpp->label = softc_p->ixlp;
3508eea8e29Sap 
3518eea8e29Sap 	last_ixlp->next_ixlp = (ixl1394_command_t *)new_ixl_jmpp;
3528eea8e29Sap 
3538eea8e29Sap 	/* don't need this, but it's neater */
3548eea8e29Sap 	last_ixlp = (ixl1394_command_t *)new_ixl_jmpp;
3558eea8e29Sap 
3568eea8e29Sap 	/* call fwim routine to alloc an isoch resource */
3578eea8e29Sap 	isoch_args.ixlp		= softc_p->ixlp;
3588eea8e29Sap 	isoch_args.channel_num	= softc_p->sii_output_args.channel_num;
3598eea8e29Sap 
3608eea8e29Sap 	/* other misc args.  note speed doesn't matter for isoch receive */
3618eea8e29Sap 	isoch_args.idma_options		= ID1394_LISTEN_PKT_MODE;
3628eea8e29Sap 	isoch_args.default_tag		= 0;
3638eea8e29Sap 	isoch_args.default_sync		= 1;
3648eea8e29Sap 	isoch_args.global_callback_arg	= softc_p;
3658eea8e29Sap 
3668eea8e29Sap 	/* set the ISO channel number */
3678eea8e29Sap 	data = (softc_p->sii_output_args.channel_num & 0xF) << 28;
3688eea8e29Sap 
3698eea8e29Sap 	/* set the ISO speed */
3708eea8e29Sap 	data |= (softc_p->targetinfo.current_max_speed << 24);
3718eea8e29Sap 
3728eea8e29Sap 	reg_io.offs = DCAM1394_REG_OFFS_CUR_ISO_CHANNEL;
3738eea8e29Sap 	reg_io.val  = data;
3748eea8e29Sap 
3758eea8e29Sap 	if (dcam_reg_write(softc_p, &reg_io)) {
3768eea8e29Sap 		return (1);
3778eea8e29Sap 	}
3788eea8e29Sap 
3798eea8e29Sap 	result = 1234;
3808eea8e29Sap 
3818eea8e29Sap 	if (t1394_alloc_isoch_dma(softc_p->sl_handle, &isoch_args, 0,
3828eea8e29Sap 	    &softc_p->isoch_handle, &result) != DDI_SUCCESS) {
3838eea8e29Sap 		return (1);
3848eea8e29Sap 	}
3858eea8e29Sap 
3868eea8e29Sap 	return (0);
3878eea8e29Sap }
3888eea8e29Sap 
3898eea8e29Sap 
3908eea8e29Sap /*
3918eea8e29Sap  * dcam_frame_rcv_fini
3928eea8e29Sap  */
3938eea8e29Sap int
dcam_frame_rcv_fini(dcam_state_t * softc_p)3948eea8e29Sap dcam_frame_rcv_fini(dcam_state_t *softc_p)
3958eea8e29Sap {
3968eea8e29Sap 	t1394_free_isoch_dma(softc_p->sl_handle, 0, &softc_p->isoch_handle);
3978eea8e29Sap 
3988eea8e29Sap 	softc_p->isoch_handle = NULL;
3998eea8e29Sap 
4008eea8e29Sap 	t1394_free_isoch_single(softc_p->sl_handle, &softc_p->sii_hdl, 0);
4018eea8e29Sap 
4028eea8e29Sap 	return (0);
4038eea8e29Sap }
4048eea8e29Sap 
4058eea8e29Sap 
4068eea8e29Sap /*
4078eea8e29Sap  * dcam_frame_rcv_start
4088eea8e29Sap  */
4098eea8e29Sap int
dcam_frame_rcv_start(dcam_state_t * softc_p)4108eea8e29Sap dcam_frame_rcv_start(dcam_state_t *softc_p)
4118eea8e29Sap {
4128eea8e29Sap 	id1394_isoch_dma_ctrlinfo_t	idma_ctrlinfo; /* currently not used */
4138eea8e29Sap 	int32_t				result;
4148eea8e29Sap 	dcam1394_reg_io_t		reg_io;
4158eea8e29Sap 
4168eea8e29Sap 	if ((t1394_start_isoch_dma(softc_p->sl_handle, softc_p->isoch_handle,
4178eea8e29Sap 	    &idma_ctrlinfo, 0, &result)) != DDI_SUCCESS) {
4188eea8e29Sap 		return (1);
4198eea8e29Sap 	}
4208eea8e29Sap 
4218eea8e29Sap 	reg_io.offs = DCAM1394_REG_OFFS_ISO_EN;
4228eea8e29Sap 	reg_io.val  = 0x80000000;
4238eea8e29Sap 
4248eea8e29Sap 	if (dcam_reg_write(softc_p, &reg_io)) {
4258eea8e29Sap 		return (1);
4268eea8e29Sap 	}
4278eea8e29Sap 
4288eea8e29Sap 	softc_p->flags |= DCAM1394_FLAG_FRAME_RCVING;
4298eea8e29Sap 
4308eea8e29Sap 	return (0);
4318eea8e29Sap }
4328eea8e29Sap 
4338eea8e29Sap 
4348eea8e29Sap /*
4358eea8e29Sap  * dcam_frame_rcv_stop
4368eea8e29Sap  */
4378eea8e29Sap int
dcam_frame_rcv_stop(dcam_state_t * softc_p)4388eea8e29Sap dcam_frame_rcv_stop(dcam_state_t *softc_p)
4398eea8e29Sap {
4408eea8e29Sap 	dcam1394_reg_io_t reg_io;
4418eea8e29Sap 
4428eea8e29Sap 	/* if resources have already been cleared, nothing to do */
4438eea8e29Sap 	if (!(softc_p->flags & DCAM1394_FLAG_FRAME_RCV_INIT)) {
4448eea8e29Sap 		return (0);
4458eea8e29Sap 	}
4468eea8e29Sap 
4478eea8e29Sap 	reg_io.offs = DCAM1394_REG_OFFS_ISO_EN;
4488eea8e29Sap 	reg_io.val  = 0;
4498eea8e29Sap 
4508eea8e29Sap 	(void) dcam_reg_write(softc_p, &reg_io);
4518eea8e29Sap 
4528eea8e29Sap 	t1394_stop_isoch_dma(softc_p->sl_handle, softc_p->isoch_handle, 0);
4538eea8e29Sap 	t1394_free_isoch_dma(softc_p->sl_handle, 0, &softc_p->isoch_handle);
4548eea8e29Sap 	t1394_free_isoch_single(softc_p->sl_handle, &softc_p->sii_hdl, 0);
4558eea8e29Sap 
4568eea8e29Sap 	dcam_free_resources(softc_p);
4578eea8e29Sap 
4588eea8e29Sap 	return (0);
4598eea8e29Sap }
4608eea8e29Sap 
4618eea8e29Sap 
4628eea8e29Sap void
dcam_free_resources(dcam_state_t * softc_p)4638eea8e29Sap dcam_free_resources(dcam_state_t *softc_p)
4648eea8e29Sap {
4658eea8e29Sap 	ixl1394_command_t *ptr;
4668eea8e29Sap 	ixl1394_command_t *tmp;
4678eea8e29Sap 
4688eea8e29Sap 	/*
4698eea8e29Sap 	 *  The following fixes a memory leak.  See bug #4423667.
4708eea8e29Sap 	 *  The original code  only released memory for the first  frame.
4718eea8e29Sap 	 */
4728eea8e29Sap 
4738eea8e29Sap 	/* free ixl opcode resources */
4748eea8e29Sap 	ptr = softc_p->ixlp;
4758eea8e29Sap 
4768eea8e29Sap 	while (ptr != NULL) {
4778eea8e29Sap 		tmp = ptr;
4788eea8e29Sap 		ptr = ptr->next_ixlp;
4798eea8e29Sap 
4808eea8e29Sap 		switch (tmp->ixl_opcode) {
4818eea8e29Sap 			case IXL1394_OP_LABEL:
4828eea8e29Sap 				kmem_free(tmp, sizeof (ixl1394_label_t));
4838eea8e29Sap 			break;
4848eea8e29Sap 
4858eea8e29Sap 			case IXL1394_OP_SET_SYNCWAIT:
4868eea8e29Sap 				kmem_free(tmp, sizeof (ixl1394_set_syncwait_t));
4878eea8e29Sap 			break;
4888eea8e29Sap 
4898eea8e29Sap 			case IXL1394_OP_RECV_PKT_ST:
4908eea8e29Sap 				kmem_free(tmp, sizeof (ixl1394_xfer_pkt_t));
4918eea8e29Sap 			break;
4928eea8e29Sap 
4938eea8e29Sap 			case IXL1394_OP_RECV_BUF:
4948eea8e29Sap 				kmem_free(tmp, sizeof (ixl1394_xfer_buf_t));
4958eea8e29Sap 			break;
4968eea8e29Sap 
4978eea8e29Sap 			case IXL1394_OP_CALLBACK:
4988eea8e29Sap 				kmem_free(tmp, sizeof (ixl1394_callback_t));
4998eea8e29Sap 			break;
5008eea8e29Sap 
5018eea8e29Sap 			case IXL1394_OP_JUMP:
5028eea8e29Sap 				kmem_free(tmp, sizeof (ixl1394_jump_t));
5038eea8e29Sap 			break;
5048eea8e29Sap 		}
5058eea8e29Sap 	}
5068eea8e29Sap 
5078eea8e29Sap 	/*
5088eea8e29Sap 	 * free ring buff and indicate that the resources have been cleared
5098eea8e29Sap 	 */
5108eea8e29Sap 	ring_buff_free(softc_p, softc_p->ring_buff_p);
5118eea8e29Sap 
5128eea8e29Sap 	softc_p->flags &= ~DCAM1394_FLAG_FRAME_RCV_INIT;
5138eea8e29Sap 	softc_p->ixlp = NULL;
5148eea8e29Sap }
5158eea8e29Sap 
5168eea8e29Sap 
5178eea8e29Sap /*
5188eea8e29Sap  * dcam_frame_is_done
5198eea8e29Sap  *
5208eea8e29Sap  * This routine is called after DMA engine has stored a single received
5218eea8e29Sap  * frame in ring buffer position pointed to by write pointer; this
5228eea8e29Sap  * routine marks the frame's vid mode, timestamp, and sequence number
5238eea8e29Sap  *
5248eea8e29Sap  * Store received frame in ring buffer position pointed to by write pointer.
5258eea8e29Sap  * Increment write pointer.  If write pointer is pointing to the same
5268eea8e29Sap  * position as read pointer, increment read pointer.
5278eea8e29Sap  *
5288eea8e29Sap  * If device driver is processing a user process's read() request
5298eea8e29Sap  * invalidate the read() request processing operation.
5308eea8e29Sap  *
5318eea8e29Sap  */
5328eea8e29Sap 
5338eea8e29Sap /* ARGSUSED */
5348eea8e29Sap void
dcam_frame_is_done(void * ssp,ixl1394_callback_t * ixlp)5358eea8e29Sap dcam_frame_is_done(void *ssp, ixl1394_callback_t *ixlp)
5368eea8e29Sap {
5378eea8e29Sap 	dcam_state_t	*softc_p;
5388eea8e29Sap 	int		 num_read_ptrs;
5398eea8e29Sap 	int		 read_ptr_id;
5408eea8e29Sap 	int		 vid_mode;
5418eea8e29Sap 	size_t		 write_ptr_pos;
5428eea8e29Sap 	ring_buff_t	*ring_buff_p;
5438eea8e29Sap 	unsigned int	 seq_num;
5448eea8e29Sap 
5458eea8e29Sap 	/*
5468eea8e29Sap 	 * Store received frame in ring buffer position pointed to by
5478eea8e29Sap 	 * write pointer (this routine is called after DMA engine has
5488eea8e29Sap 	 * stored a single received frame in ring buffer position pointed
5498eea8e29Sap 	 * to by write pointer; this routine marks the frame's vid mode,
5508eea8e29Sap 	 * timestamp, and sequence number)
5518eea8e29Sap 	 */
5528eea8e29Sap 
5538eea8e29Sap 	if ((softc_p = (dcam_state_t *)ssp) == NULL) {
5548eea8e29Sap 		return;
5558eea8e29Sap 	}
5568eea8e29Sap 
5578eea8e29Sap 	if ((ring_buff_p = softc_p->ring_buff_p) == NULL) {
5588eea8e29Sap 		return;
5598eea8e29Sap 	}
5608eea8e29Sap 
5618eea8e29Sap 	mutex_enter(&softc_p->dcam_frame_is_done_mutex);
5628eea8e29Sap 
5638eea8e29Sap 	write_ptr_pos = ring_buff_write_ptr_pos_get(ring_buff_p);
5648eea8e29Sap 
5658eea8e29Sap 	/* mark vid mode */
5668eea8e29Sap 	vid_mode =
5678eea8e29Sap 	    softc_p->
5688eea8e29Sap 		param_attr[DCAM1394_PARAM_VID_MODE][DCAM1394_SUBPARAM_NONE];
5698eea8e29Sap 	ring_buff_p->buff_info_array_p[write_ptr_pos].vid_mode = vid_mode;
5708eea8e29Sap 
5718eea8e29Sap 
5728eea8e29Sap 	/* update sequence counter overflow in param_status */
5738eea8e29Sap 	if (softc_p->seq_count == 0xffffffff)
5748eea8e29Sap 		softc_p->param_status |=
5758eea8e29Sap 		    DCAM1394_STATUS_FRAME_SEQ_NUM_COUNT_OVERFLOW;
5768eea8e29Sap 
5778eea8e29Sap 
5788eea8e29Sap 	/* mark frame's sequence number */
5798eea8e29Sap 	ring_buff_p->buff_info_array_p[write_ptr_pos].seq_num =
5808eea8e29Sap 	    softc_p->seq_count++;
5818eea8e29Sap 
5828eea8e29Sap 	seq_num = ring_buff_p->buff_info_array_p[write_ptr_pos].seq_num;
5838eea8e29Sap 
5848eea8e29Sap 
5858eea8e29Sap 	/* mark frame's timestamp */
5868eea8e29Sap 	ring_buff_p->buff_info_array_p[write_ptr_pos].timestamp = gethrtime();
5878eea8e29Sap 
5888eea8e29Sap 
5898eea8e29Sap 	/* increment write pointer */
5908eea8e29Sap 	ring_buff_write_ptr_incr(ring_buff_p);
5918eea8e29Sap 
5928eea8e29Sap 	num_read_ptrs = 1;
5938eea8e29Sap 
5948eea8e29Sap 	for (read_ptr_id = 0; read_ptr_id < num_read_ptrs; read_ptr_id++) {
5958eea8e29Sap 
5968eea8e29Sap 		/*
5978eea8e29Sap 		 * if write pointer is pointing to the same position as
5988eea8e29Sap 		 * read pointer
5998eea8e29Sap 		 */
6008eea8e29Sap 
6018eea8e29Sap 		if ((ring_buff_write_ptr_pos_get(ring_buff_p) ==
6028eea8e29Sap 		    ring_buff_read_ptr_pos_get(ring_buff_p, read_ptr_id)) &&
6038eea8e29Sap 		    (seq_num != 0)) {
6048eea8e29Sap 
6058eea8e29Sap 			/* increment read pointer */
6068eea8e29Sap 			ring_buff_read_ptr_incr(ring_buff_p, read_ptr_id);
6078eea8e29Sap 
6088eea8e29Sap 			/*
6098eea8e29Sap 			 * if device driver is processing a user
6108eea8e29Sap 			 * process's read() request
6118eea8e29Sap 			 */
6128eea8e29Sap 			if (softc_p->reader_flags[read_ptr_id] &
6138eea8e29Sap 			    DCAM1394_FLAG_READ_REQ_PROC) {
6148eea8e29Sap 
6158eea8e29Sap 				/*
6168eea8e29Sap 				 * invalidate the read() request processing
6178eea8e29Sap 				 * operation
6188eea8e29Sap 				 */
6198eea8e29Sap 				softc_p->reader_flags[read_ptr_id] |=
6208eea8e29Sap 				    DCAM1394_FLAG_READ_REQ_INVALID;
6218eea8e29Sap 			}
6228eea8e29Sap 
6238eea8e29Sap 			/* inform user app that we have lost one frame */
6248eea8e29Sap 			softc_p->param_status |=
6258eea8e29Sap 			    DCAM1394_STATUS_RING_BUFF_LOST_FRAME;
6268eea8e29Sap 		}
6278eea8e29Sap 	}
6288eea8e29Sap 
6298eea8e29Sap 	/* inform user app that we have received one frame */
6308eea8e29Sap 	softc_p->param_status |= DCAM1394_STATUS_FRAME_RCV_DONE;
6318eea8e29Sap 
6328eea8e29Sap 	mutex_exit(&softc_p->dcam_frame_is_done_mutex);
6338eea8e29Sap }
6348eea8e29Sap 
6358eea8e29Sap 
6368eea8e29Sap /* ARGSUSED */
6378eea8e29Sap 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)6388eea8e29Sap dcam_rsrc_fail(t1394_isoch_single_handle_t t1394_single_hdl,
6398eea8e29Sap     opaque_t single_evt_arg, t1394_isoch_rsrc_error_t fail_args)
6408eea8e29Sap {
6418eea8e29Sap 	cmn_err(CE_NOTE, "dcam_rsrc_fail(): unable to re-alloc resources\n");
6428eea8e29Sap }
643