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, ®_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, ®_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, ®_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