#include <sys/types.h>
#include <sys/kmem.h>
#include <sys/ddidmareq.h>
#include <sys/types.h>
#include <sys/inttypes.h>
#include <sys/cmn_err.h>
#include <sys/1394/targets/dcam1394/dcam.h>
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);
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);
}
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;
}
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);
}
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);
}
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);
}
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]);
}
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;
#endif
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) {
if ((read_ptr_pos + ring_buff_p->read_ptr_incr_val) <
ring_buff_p->write_ptr_pos) {
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 {
ring_buff_p->read_ptr_pos[read_ptr_id] =
ring_buff_p->write_ptr_pos;
}
} else {
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) {
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 {
ring_buff_p->read_ptr_pos[read_ptr_id] =
ring_buff_p->write_ptr_pos;
}
}
#endif
}
size_t
ring_buff_write_ptr_pos_get(ring_buff_t *ring_buff_p)
{
return (ring_buff_p->write_ptr_pos);
}
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);
}