Commit ada87d5c authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] dvb: update saa7146 driver

From: Michael Hunold <hunold@linuxtv.org>

- fix memory leak in page table handling

- minor coding style changes

- add simple resource management for video dmas (borrowed from saa7134)

- use resource management to lock video and vbi access which sometimes
  share the same video dmas

- honour return codes of extension functions in various places, when
  resources could not be locked

- remove remains of dead code which were commented out anyway

- add new flag FORMAT_IS_PLANAR to indicate planar capture formats,
  needed for resource allocation
parent 500638be
...@@ -137,7 +137,6 @@ static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages) ...@@ -137,7 +137,6 @@ static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages)
char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt) char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt)
{ {
struct scatterlist *slist = NULL;
int pages = (length+PAGE_SIZE-1)/PAGE_SIZE; int pages = (length+PAGE_SIZE-1)/PAGE_SIZE;
char *mem = vmalloc_32(length); char *mem = vmalloc_32(length);
int slen = 0; int slen = 0;
...@@ -146,35 +145,36 @@ char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa ...@@ -146,35 +145,36 @@ char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa
return NULL; return NULL;
} }
if (!(slist = vmalloc_to_sg(mem, pages))) { if (!(pt->slist = vmalloc_to_sg(mem, pages))) {
vfree(mem); vfree(mem);
return NULL; return NULL;
} }
if (saa7146_pgtable_alloc(pci, pt)) { if (saa7146_pgtable_alloc(pci, pt)) {
kfree(slist); kfree(pt->slist);
pt->slist = NULL;
vfree(mem); vfree(mem);
return NULL; return NULL;
} }
slen = pci_map_sg(pci,slist,pages,PCI_DMA_FROMDEVICE); slen = pci_map_sg(pci,pt->slist,pages,PCI_DMA_FROMDEVICE);
if (0 != saa7146_pgtable_build_single(pci, pt, slist, slen)) { if (0 != saa7146_pgtable_build_single(pci, pt, pt->slist, slen)) {
return NULL; return NULL;
} }
/* fixme: here's a memory leak: slist never gets freed by any other
function ...*/
return mem; return mem;
} }
void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt) void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt)
{ {
//fm DEB_EE(("pci:%p, pt:%p\n",pci,pt));
if (NULL == pt->cpu) if (NULL == pt->cpu)
return; return;
pci_free_consistent(pci, pt->size, pt->cpu, pt->dma); pci_free_consistent(pci, pt->size, pt->cpu, pt->dma);
pt->cpu = NULL; pt->cpu = NULL;
if (NULL != pt->slist) {
kfree(pt->slist);
pt->slist = NULL;
}
} }
int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt) int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
...@@ -182,11 +182,8 @@ int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt) ...@@ -182,11 +182,8 @@ int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
u32 *cpu; u32 *cpu;
dma_addr_t dma_addr; dma_addr_t dma_addr;
//fm DEB_EE(("pci:%p, pt:%p\n",pci,pt));
cpu = pci_alloc_consistent(pci, SAA7146_PGTABLE_SIZE, &dma_addr); cpu = pci_alloc_consistent(pci, SAA7146_PGTABLE_SIZE, &dma_addr);
if (NULL == cpu) { if (NULL == cpu) {
//fm ERR(("pci_alloc_consistent() failed."));
return -ENOMEM; return -ENOMEM;
} }
pt->size = SAA7146_PGTABLE_SIZE; pt->size = SAA7146_PGTABLE_SIZE;
......
...@@ -2,6 +2,65 @@ ...@@ -2,6 +2,65 @@
#define BOARD_CAN_DO_VBI(dev) (dev->revision != 0 && dev->vv_data->vbi_minor != -1) #define BOARD_CAN_DO_VBI(dev) (dev->revision != 0 && dev->vv_data->vbi_minor != -1)
/****************************************************************************/
/* resource management functions, shamelessly stolen from saa7134 driver */
int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit)
{
struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data;
if (fh->resources & bit)
/* have it already allocated */
return 1;
/* is it free? */
DEB_D(("getting lock...\n"));
down(&dev->lock);
DEB_D(("got lock\n"));
if (vv->resources & bit) {
DEB_D(("locked! vv->resources:0x%02x, we want:0x%02x\n",vv->resources,bit));
/* no, someone else uses it */
up(&dev->lock);
return 0;
}
/* it's free, grab it */
fh->resources |= bit;
vv->resources |= bit;
DEB_D(("res: get %d\n",bit));
up(&dev->lock);
return 1;
}
int saa7146_res_check(struct saa7146_fh *fh, unsigned int bit)
{
return (fh->resources & bit);
}
int saa7146_res_locked(struct saa7146_dev *dev, unsigned int bit)
{
struct saa7146_vv *vv = dev->vv_data;
return (vv->resources & bit);
}
void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits)
{
struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data;
if ((fh->resources & bits) != bits)
BUG();
DEB_D(("getting lock...\n"));
down(&dev->lock);
DEB_D(("got lock\n"));
fh->resources &= ~bits;
vv->resources &= ~bits;
DEB_D(("res: put %d\n",bits));
up(&dev->lock);
}
/********************************************************************************/ /********************************************************************************/
/* common dma functions */ /* common dma functions */
...@@ -216,29 +275,32 @@ static int fops_open(struct inode *inode, struct file *file) ...@@ -216,29 +275,32 @@ static int fops_open(struct inode *inode, struct file *file)
} }
memset(fh,0,sizeof(*fh)); memset(fh,0,sizeof(*fh));
// FIXME: do we need to increase *our* usage count?
if( 0 == try_module_get(dev->ext->module)) {
result = -EINVAL;
goto out;
}
file->private_data = fh; file->private_data = fh;
fh->dev = dev; fh->dev = dev;
fh->type = type; fh->type = type;
if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
DEB_S(("initializing vbi...\n")); DEB_S(("initializing vbi...\n"));
saa7146_vbi_uops.open(dev,file); result = saa7146_vbi_uops.open(dev,file);
} else { } else {
DEB_S(("initializing video...\n")); DEB_S(("initializing video...\n"));
saa7146_video_uops.open(dev,file); result = saa7146_video_uops.open(dev,file);
}
if (0 != result) {
goto out;
}
if( 0 == try_module_get(dev->ext->module)) {
result = -EINVAL;
goto out;
} }
result = 0; result = 0;
out: out:
if( fh != 0 && result != 0 ) { if( fh != 0 && result != 0 ) {
kfree(fh); kfree(fh);
file->private_data = NULL;
} }
up(&saa7146_devices_lock); up(&saa7146_devices_lock);
return result; return result;
......
...@@ -152,8 +152,7 @@ static int calculate_h_scale_registers(struct saa7146_dev *dev, ...@@ -152,8 +152,7 @@ static int calculate_h_scale_registers(struct saa7146_dev *dev,
if( 1 == xpsc ) { if( 1 == xpsc ) {
xacm = 1; xacm = 1;
dcgx = 0; dcgx = 0;
} } else {
else {
xacm = 0; xacm = 0;
/* get best match in the table of attenuations /* get best match in the table of attenuations
for horizontal scaling */ for horizontal scaling */
...@@ -268,8 +267,7 @@ static int calculate_v_scale_registers(struct saa7146_dev *dev, enum v4l2_field ...@@ -268,8 +267,7 @@ static int calculate_v_scale_registers(struct saa7146_dev *dev, enum v4l2_field
ype = ysci / 16; ype = ysci / 16;
ypo = ype + (ysci / 64); ypo = ype + (ysci / 64);
} } else {
else {
yacm = 1; yacm = 1;
/* calculate scaling increment */ /* calculate scaling increment */
...@@ -285,8 +283,7 @@ static int calculate_v_scale_registers(struct saa7146_dev *dev, enum v4l2_field ...@@ -285,8 +283,7 @@ static int calculate_v_scale_registers(struct saa7146_dev *dev, enum v4l2_field
... */ ... */
if ( ysci < 512) { if ( ysci < 512) {
yacl = 0; yacl = 0;
} } else {
else {
yacl = ( ysci / (1024 - ysci) ); yacl = ( ysci / (1024 - ysci) );
} }
...@@ -488,33 +485,31 @@ static void saa7146_disable_clipping(struct saa7146_dev *dev) ...@@ -488,33 +485,31 @@ static void saa7146_disable_clipping(struct saa7146_dev *dev)
saa7146_write(dev, MC2, (MASK_05 | MASK_21)); saa7146_write(dev, MC2, (MASK_05 | MASK_21));
/* disable video dma2 */ /* disable video dma2 */
saa7146_write(dev, MC1, (MASK_21)); saa7146_write(dev, MC1, MASK_21);
} }
static void saa7146_set_clipping_rect(struct saa7146_dev *dev, struct saa7146_fh *fh) static void saa7146_set_clipping_rect(struct saa7146_fh *fh)
{ {
struct saa7146_dev *dev = fh->dev;
enum v4l2_field field = fh->ov.win.field; enum v4l2_field field = fh->ov.win.field;
int clipcount = fh->ov.nclips;
struct saa7146_video_dma vdma2; struct saa7146_video_dma vdma2;
u32 clip_format;
u32 clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL); u32 arbtr_ctrl;
u32 arbtr_ctrl = saa7146_read(dev, PCI_BT_V1);
// fixme: is this used at all? SAA7146_CLIPPING_RECT_INVERTED;
u32 type = SAA7146_CLIPPING_RECT;
/* check clipcount, disable clipping if clipcount == 0*/ /* check clipcount, disable clipping if clipcount == 0*/
if( clipcount == 0 ) { if( fh->ov.nclips == 0 ) {
saa7146_disable_clipping(dev); saa7146_disable_clipping(dev);
return; return;
} }
clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL);
arbtr_ctrl = saa7146_read(dev, PCI_BT_V1);
calculate_clipping_registers_rect(dev, fh, &vdma2, &clip_format, &arbtr_ctrl, field); calculate_clipping_registers_rect(dev, fh, &vdma2, &clip_format, &arbtr_ctrl, field);
/* set clipping format */ /* set clipping format */
clip_format &= 0xffff0008; clip_format &= 0xffff0008;
clip_format |= (type << 4); clip_format |= (SAA7146_CLIPPING_RECT << 4);
/* prepare video dma2 */ /* prepare video dma2 */
saa7146_write(dev, BASE_EVEN2, vdma2.base_even); saa7146_write(dev, BASE_EVEN2, vdma2.base_even);
...@@ -660,25 +655,28 @@ void saa7146_set_hps_source_and_sync(struct saa7146_dev *dev, int source, int sy ...@@ -660,25 +655,28 @@ void saa7146_set_hps_source_and_sync(struct saa7146_dev *dev, int source, int sy
vv->current_hps_sync = sync; vv->current_hps_sync = sync;
} }
/* reprogram hps, enable(1) / disable(0) video */ int saa7146_enable_overlay(struct saa7146_fh *fh)
void saa7146_set_overlay(struct saa7146_dev *dev, struct saa7146_fh *fh, int v)
{ {
struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data; struct saa7146_vv *vv = dev->vv_data;
/* enable ? */
if( 0 == v) {
/* disable video dma1 */
saa7146_write(dev, MC1, MASK_22);
return;
}
saa7146_set_window(dev, fh->ov.win.w.width, fh->ov.win.w.height, fh->ov.win.field); saa7146_set_window(dev, fh->ov.win.w.width, fh->ov.win.w.height, fh->ov.win.field);
saa7146_set_position(dev, fh->ov.win.w.left, fh->ov.win.w.top, fh->ov.win.w.height, fh->ov.win.field); saa7146_set_position(dev, fh->ov.win.w.left, fh->ov.win.w.top, fh->ov.win.w.height, fh->ov.win.field);
saa7146_set_output_format(dev, vv->ov_fmt->trans); saa7146_set_output_format(dev, vv->ov_fmt->trans);
saa7146_set_clipping_rect(dev, fh); saa7146_set_clipping_rect(fh);
/* enable video dma1 */ /* enable video dma1 */
saa7146_write(dev, MC1, (MASK_06 | MASK_22)); saa7146_write(dev, MC1, (MASK_06 | MASK_22));
return 0;
}
void saa7146_disable_overlay(struct saa7146_fh *fh)
{
struct saa7146_dev *dev = fh->dev;
/* disable clipping + video dma1 */
saa7146_disable_clipping(dev);
saa7146_write(dev, MC1, MASK_22);
} }
void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_video_dma* vdma) void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_video_dma* vdma)
...@@ -692,15 +690,8 @@ void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_vi ...@@ -692,15 +690,8 @@ void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_vi
/* calculate starting address */ /* calculate starting address */
where = (which-1)*0x18; where = (which-1)*0x18;
/*
if( 0 != (dev->ext_vv_data->flags & SAA7146_EXT_SWAP_ODD_EVEN)) {
saa7146_write(dev, where, vdma->base_even);
saa7146_write(dev, where+0x04, vdma->base_odd);
} else {
*/
saa7146_write(dev, where, vdma->base_odd); saa7146_write(dev, where, vdma->base_odd);
saa7146_write(dev, where+0x04, vdma->base_even); saa7146_write(dev, where+0x04, vdma->base_even);
// }
saa7146_write(dev, where+0x08, vdma->prot_addr); saa7146_write(dev, where+0x08, vdma->prot_addr);
saa7146_write(dev, where+0x0c, vdma->pitch); saa7146_write(dev, where+0x0c, vdma->pitch);
saa7146_write(dev, where+0x10, vdma->base_page); saa7146_write(dev, where+0x10, vdma->base_page);
...@@ -937,7 +928,7 @@ static int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa71 ...@@ -937,7 +928,7 @@ static int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa71
} }
saa7146_write_out_dma(dev, 1, &vdma1); saa7146_write_out_dma(dev, 1, &vdma1);
if( sfmt->swap != 0 ) { if( (sfmt->flags & FORMAT_BYTE_SWAP) != 0 ) {
saa7146_write_out_dma(dev, 3, &vdma2); saa7146_write_out_dma(dev, 3, &vdma2);
saa7146_write_out_dma(dev, 2, &vdma3); saa7146_write_out_dma(dev, 2, &vdma3);
} else { } else {
...@@ -955,13 +946,6 @@ static void program_capture_engine(struct saa7146_dev *dev, int planar) ...@@ -955,13 +946,6 @@ static void program_capture_engine(struct saa7146_dev *dev, int planar)
unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B; unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B;
unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B; unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B;
/*
if( 0 != (dev->ext_vv_data->flags & SAA7146_EXT_SWAP_ODD_EVEN)) {
unsigned long tmp = e_wait;
e_wait = o_wait;
o_wait = tmp;
}
*/
/* wait for o_fid_a/b / e_fid_a/b toggle only if rps register 0 is not set*/ /* wait for o_fid_a/b / e_fid_a/b toggle only if rps register 0 is not set*/
WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | o_wait); WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | o_wait);
WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | e_wait); WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | e_wait);
...@@ -1038,7 +1022,6 @@ void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struc ...@@ -1038,7 +1022,6 @@ void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struc
saa7146_set_window(dev, buf->fmt->width, buf->fmt->height, buf->fmt->field); saa7146_set_window(dev, buf->fmt->width, buf->fmt->height, buf->fmt->field);
saa7146_set_output_format(dev, sfmt->trans); saa7146_set_output_format(dev, sfmt->trans);
saa7146_disable_clipping(dev);
if ( vv->last_field == V4L2_FIELD_INTERLACED ) { if ( vv->last_field == V4L2_FIELD_INTERLACED ) {
} else if ( vv->last_field == V4L2_FIELD_TOP ) { } else if ( vv->last_field == V4L2_FIELD_TOP ) {
......
...@@ -366,7 +366,7 @@ static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv) ...@@ -366,7 +366,7 @@ static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
init_waitqueue_head(&vv->vbi_wq); init_waitqueue_head(&vv->vbi_wq);
} }
static void vbi_open(struct saa7146_dev *dev, struct file *file) static int vbi_open(struct saa7146_dev *dev, struct file *file)
{ {
struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data; struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
...@@ -375,6 +375,12 @@ static void vbi_open(struct saa7146_dev *dev, struct file *file) ...@@ -375,6 +375,12 @@ static void vbi_open(struct saa7146_dev *dev, struct file *file)
DEB_VBI(("dev:%p, fh:%p\n",dev,fh)); DEB_VBI(("dev:%p, fh:%p\n",dev,fh));
ret = saa7146_res_get(fh, RESOURCE_DMA3_BRS);
if (0 == ret) {
DEB_S(("cannot get vbi RESOURCE_DMA3_BRS resource\n"));
return -EBUSY;
}
/* adjust arbitrition control for video dma 3 */ /* adjust arbitrition control for video dma 3 */
arbtr_ctrl &= ~0x1f0000; arbtr_ctrl &= ~0x1f0000;
arbtr_ctrl |= 0x1d0000; arbtr_ctrl |= 0x1d0000;
...@@ -419,6 +425,7 @@ static void vbi_open(struct saa7146_dev *dev, struct file *file) ...@@ -419,6 +425,7 @@ static void vbi_open(struct saa7146_dev *dev, struct file *file)
/* upload brs register */ /* upload brs register */
saa7146_write(dev, MC2, (MASK_08|MASK_24)); saa7146_write(dev, MC2, (MASK_08|MASK_24));
return 0;
} }
static void vbi_close(struct saa7146_dev *dev, struct file *file) static void vbi_close(struct saa7146_dev *dev, struct file *file)
...@@ -430,6 +437,7 @@ static void vbi_close(struct saa7146_dev *dev, struct file *file) ...@@ -430,6 +437,7 @@ static void vbi_close(struct saa7146_dev *dev, struct file *file)
if( fh == vv->vbi_streaming ) { if( fh == vv->vbi_streaming ) {
vbi_stop(fh, file); vbi_stop(fh, file);
} }
saa7146_res_free(fh, RESOURCE_DMA3_BRS);
} }
static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status) static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status)
......
...@@ -12,48 +12,55 @@ static struct saa7146_format formats[] = { ...@@ -12,48 +12,55 @@ static struct saa7146_format formats[] = {
.pixelformat = V4L2_PIX_FMT_RGB332, .pixelformat = V4L2_PIX_FMT_RGB332,
.trans = RGB08_COMPOSED, .trans = RGB08_COMPOSED,
.depth = 8, .depth = 8,
.flags = 0,
}, { }, {
.name = "RGB-16 (5/B-6/G-5/R)", /* really? */ .name = "RGB-16 (5/B-6/G-5/R)",
.pixelformat = V4L2_PIX_FMT_RGB565, .pixelformat = V4L2_PIX_FMT_RGB565,
.trans = RGB16_COMPOSED, .trans = RGB16_COMPOSED,
.depth = 16, .depth = 16,
.flags = 0,
}, { }, {
.name = "RGB-24 (B-G-R)", .name = "RGB-24 (B-G-R)",
.pixelformat = V4L2_PIX_FMT_BGR24, .pixelformat = V4L2_PIX_FMT_BGR24,
.trans = RGB24_COMPOSED, .trans = RGB24_COMPOSED,
.depth = 24, .depth = 24,
.flags = 0,
}, { }, {
.name = "RGB-32 (B-G-R)", .name = "RGB-32 (B-G-R)",
.pixelformat = V4L2_PIX_FMT_BGR32, .pixelformat = V4L2_PIX_FMT_BGR32,
.trans = RGB32_COMPOSED, .trans = RGB32_COMPOSED,
.depth = 32, .depth = 32,
.flags = 0,
}, { }, {
.name = "Greyscale-8", .name = "Greyscale-8",
.pixelformat = V4L2_PIX_FMT_GREY, .pixelformat = V4L2_PIX_FMT_GREY,
.trans = Y8, .trans = Y8,
.depth = 8, .depth = 8,
.flags = 0,
}, { }, {
.name = "YUV 4:2:2 planar (Y-Cb-Cr)", .name = "YUV 4:2:2 planar (Y-Cb-Cr)",
.pixelformat = V4L2_PIX_FMT_YUV422P, .pixelformat = V4L2_PIX_FMT_YUV422P,
.trans = YUV422_DECOMPOSED, .trans = YUV422_DECOMPOSED,
.depth = 16, .depth = 16,
.swap = 1, .flags = FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR,
}, { }, {
.name = "YVU 4:2:0 planar (Y-Cb-Cr)", .name = "YVU 4:2:0 planar (Y-Cb-Cr)",
.pixelformat = V4L2_PIX_FMT_YVU420, .pixelformat = V4L2_PIX_FMT_YVU420,
.trans = YUV420_DECOMPOSED, .trans = YUV420_DECOMPOSED,
.depth = 12, .depth = 12,
.swap = 1, .flags = FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR,
}, { }, {
.name = "YUV 4:2:0 planar (Y-Cb-Cr)", .name = "YUV 4:2:0 planar (Y-Cb-Cr)",
.pixelformat = V4L2_PIX_FMT_YUV420, .pixelformat = V4L2_PIX_FMT_YUV420,
.trans = YUV420_DECOMPOSED, .trans = YUV420_DECOMPOSED,
.depth = 12, .depth = 12,
.flags = FORMAT_IS_PLANAR,
}, { }, {
.name = "YUV 4:2:2 (U-Y-V-Y)", .name = "YUV 4:2:2 (U-Y-V-Y)",
.pixelformat = V4L2_PIX_FMT_UYVY, .pixelformat = V4L2_PIX_FMT_UYVY,
.trans = YUV422_COMPOSED, .trans = YUV422_COMPOSED,
.depth = 16, .depth = 16,
.flags = 0,
} }
}; };
...@@ -243,13 +250,13 @@ int saa7146_start_preview(struct saa7146_fh *fh) ...@@ -243,13 +250,13 @@ int saa7146_start_preview(struct saa7146_fh *fh)
{ {
struct saa7146_dev *dev = fh->dev; struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data; struct saa7146_vv *vv = dev->vv_data;
int err = 0; int ret = 0, err = 0;
DEB_EE(("dev:%p, fh:%p\n",dev,fh)); DEB_EE(("dev:%p, fh:%p\n",dev,fh));
/* check if we have overlay informations */ /* check if we have overlay informations */
if( NULL == fh->ov.fh ) { if( NULL == fh->ov.fh ) {
DEB_D(("not overlay data available. try S_FMT first.\n")); DEB_D(("no overlay data available. try S_FMT first.\n"));
return -EAGAIN; return -EAGAIN;
} }
...@@ -280,7 +287,11 @@ int saa7146_start_preview(struct saa7146_fh *fh) ...@@ -280,7 +287,11 @@ int saa7146_start_preview(struct saa7146_fh *fh)
fh->ov.win.w.left,fh->ov.win.w.top, fh->ov.win.w.left,fh->ov.win.w.top,
vv->ov_fmt->name,v4l2_field_names[fh->ov.win.field])); vv->ov_fmt->name,v4l2_field_names[fh->ov.win.field]));
saa7146_set_overlay(dev, fh, 1); if (0 != (ret = saa7146_enable_overlay(fh))) {
vv->ov_data = NULL;
DEB_D(("enabling overlay failed: %d\n",ret));
return ret;
}
return 0; return 0;
} }
...@@ -290,7 +301,7 @@ int saa7146_stop_preview(struct saa7146_fh *fh) ...@@ -290,7 +301,7 @@ int saa7146_stop_preview(struct saa7146_fh *fh)
struct saa7146_dev *dev = fh->dev; struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data; struct saa7146_vv *vv = dev->vv_data;
DEB_EE(("saa7146.o: saa7146_stop_preview()\n")); DEB_EE(("dev:%p, fh:%p\n",dev,fh));
/* check if overlay is running */ /* check if overlay is running */
if( 0 == vv->ov_data ) { if( 0 == vv->ov_data ) {
...@@ -300,11 +311,11 @@ int saa7146_stop_preview(struct saa7146_fh *fh) ...@@ -300,11 +311,11 @@ int saa7146_stop_preview(struct saa7146_fh *fh)
if( fh != vv->ov_data->fh ) { if( fh != vv->ov_data->fh ) {
DEB_D(("overlay is active, but for another open.\n")); DEB_D(("overlay is active, but for another open.\n"));
return -EBUSY; return 0;
} }
saa7146_set_overlay(dev, fh, 0);
vv->ov_data = NULL; vv->ov_data = NULL;
saa7146_disable_overlay(fh);
return 0; return 0;
} }
...@@ -675,21 +686,37 @@ static int video_begin(struct saa7146_fh *fh) ...@@ -675,21 +686,37 @@ static int video_begin(struct saa7146_fh *fh)
{ {
struct saa7146_dev *dev = fh->dev; struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data; struct saa7146_vv *vv = dev->vv_data;
struct saa7146_format *fmt = NULL;
unsigned long flags; unsigned long flags;
unsigned int resource;
int ret = 0;
DEB_EE(("dev:%p, fh:%p\n",dev,fh)); DEB_EE(("dev:%p, fh:%p\n",dev,fh));
if( fh == vv->streaming ) { if( fh == vv->streaming ) {
DEB_S(("already capturing.\n")); DEB_S(("already capturing.\n"));
return 0; return -EBUSY;
} }
if( vv->streaming != 0 ) { if( vv->streaming != 0 ) {
DEB_S(("already capturing, but in another open.\n")); DEB_S(("already capturing, but in another open.\n"));
return -EBUSY; return -EBUSY;
} }
/* fixme: check for planar formats here, if we will interfere with fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat);
vbi capture for example */ /* we need to have a valid format set here */
BUG_ON(NULL == fmt);
if (0 != (fmt->flags & FORMAT_IS_PLANAR)) {
resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS;
} else {
resource = RESOURCE_DMA1_HPS;
}
ret = saa7146_res_get(fh, resource);
if (0 == ret) {
DEB_S(("cannot get capture resource %d\n",resource));
return -EBUSY;
}
spin_lock_irqsave(&dev->slock,flags); spin_lock_irqsave(&dev->slock,flags);
...@@ -708,8 +735,10 @@ static int video_end(struct saa7146_fh *fh, struct file *file) ...@@ -708,8 +735,10 @@ static int video_end(struct saa7146_fh *fh, struct file *file)
{ {
struct saa7146_dev *dev = fh->dev; struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data; struct saa7146_vv *vv = dev->vv_data;
struct saa7146_format *fmt = NULL;
unsigned long flags; unsigned long flags;
unsigned int resource;
u32 dmas = 0;
DEB_EE(("dev:%p, fh:%p\n",dev,fh)); DEB_EE(("dev:%p, fh:%p\n",dev,fh));
if( vv->streaming != fh ) { if( vv->streaming != fh ) {
...@@ -717,6 +746,19 @@ static int video_end(struct saa7146_fh *fh, struct file *file) ...@@ -717,6 +746,19 @@ static int video_end(struct saa7146_fh *fh, struct file *file)
return -EINVAL; return -EINVAL;
} }
fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat);
/* we need to have a valid format set here */
BUG_ON(NULL == fmt);
if (0 != (fmt->flags & FORMAT_IS_PLANAR)) {
resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS;
dmas = MASK_22 | MASK_21 | MASK_20;
} else {
resource = RESOURCE_DMA1_HPS;
dmas = MASK_20;
}
saa7146_res_free(fh, resource);
spin_lock_irqsave(&dev->slock,flags); spin_lock_irqsave(&dev->slock,flags);
/* disable rps0 */ /* disable rps0 */
...@@ -725,14 +767,8 @@ static int video_end(struct saa7146_fh *fh, struct file *file) ...@@ -725,14 +767,8 @@ static int video_end(struct saa7146_fh *fh, struct file *file)
/* disable rps0 irqs */ /* disable rps0 irqs */
IER_DISABLE(dev, MASK_27); IER_DISABLE(dev, MASK_27);
// fixme: only used formats here!
/* fixme: look at planar formats here, especially at the
shutdown of planar formats! */
/* shut down all used video dma transfers */ /* shut down all used video dma transfers */
/* fixme: what about the budget-dvb cards? they use saa7146_write(dev, MC1, dmas);
video-dma3, but video_end should not get called anyway ...*/
saa7146_write(dev, MC1, 0x00700000);
vv->streaming = NULL; vv->streaming = NULL;
...@@ -849,8 +885,12 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int ...@@ -849,8 +885,12 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
return -EINVAL; return -EINVAL;
} }
down(&dev->lock); /* planar formats are not allowed for overlay video, clipping and video dma would clash */
if (0 != (fmt->flags & FORMAT_IS_PLANAR)) {
DEB_S(("planar pixelformat '%4.4s' not allowed for overlay\n",(char *)&fmt->pixelformat));
}
down(&dev->lock);
if( vv->ov_data != NULL ) { if( vv->ov_data != NULL ) {
ov_fh = vv->ov_data->fh; ov_fh = vv->ov_data->fh;
saa7146_stop_preview(ov_fh); saa7146_stop_preview(ov_fh);
...@@ -1002,7 +1042,9 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int ...@@ -1002,7 +1042,9 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
return -EBUSY; return -EBUSY;
} }
DEB_D(("before getting lock...\n"));
down(&dev->lock); down(&dev->lock);
DEB_D(("got lock\n"));
if( vv->ov_data != NULL ) { if( vv->ov_data != NULL ) {
ov_fh = vv->ov_data->fh; ov_fh = vv->ov_data->fh;
...@@ -1047,22 +1089,33 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int ...@@ -1047,22 +1089,33 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
if( 0 != on ) { if( 0 != on ) {
if( vv->ov_data != NULL ) { if( vv->ov_data != NULL ) {
if( fh != vv->ov_data->fh) { if( fh != vv->ov_data->fh) {
DEB_D(("overlay already active in another open\n"));
return -EAGAIN; return -EAGAIN;
} }
} }
if (0 == saa7146_res_get(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) {
DEB_D(("cannot get overlay resources\n"));
return -EBUSY;
}
spin_lock_irqsave(&dev->slock,flags); spin_lock_irqsave(&dev->slock,flags);
err = saa7146_start_preview(fh); err = saa7146_start_preview(fh);
spin_unlock_irqrestore(&dev->slock,flags); spin_unlock_irqrestore(&dev->slock,flags);
} else { return err;
}
if( vv->ov_data != NULL ) { if( vv->ov_data != NULL ) {
if( fh != vv->ov_data->fh) { if( fh != vv->ov_data->fh) {
DEB_D(("overlay is active, but in another open\n"));
return -EAGAIN; return -EAGAIN;
} }
} }
spin_lock_irqsave(&dev->slock,flags); spin_lock_irqsave(&dev->slock,flags);
err = saa7146_stop_preview(fh); err = saa7146_stop_preview(fh);
spin_unlock_irqrestore(&dev->slock,flags); spin_unlock_irqrestore(&dev->slock,flags);
} /* free resources */
saa7146_res_free(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
return err; return err;
} }
case VIDIOC_REQBUFS: { case VIDIOC_REQBUFS: {
...@@ -1093,7 +1146,13 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int ...@@ -1093,7 +1146,13 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
int *type = arg; int *type = arg;
DEB_D(("VIDIOC_STREAMON, type:%d\n",*type)); DEB_D(("VIDIOC_STREAMON, type:%d\n",*type));
if( 0 != (err = video_begin(fh))) { if( fh == vv->streaming ) {
DEB_D(("already capturing.\n"));
return 0;
}
err = video_begin(fh);
if( 0 != err) {
return err; return err;
} }
err = videobuf_streamon(file,q); err = videobuf_streamon(file,q);
...@@ -1103,6 +1162,12 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int ...@@ -1103,6 +1162,12 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
int *type = arg; int *type = arg;
DEB_D(("VIDIOC_STREAMOFF, type:%d\n",*type)); DEB_D(("VIDIOC_STREAMOFF, type:%d\n",*type));
if( fh != vv->streaming ) {
DEB_D(("this open is not capturing.\n"));
return -EINVAL;
}
err = videobuf_streamoff(file,q); err = videobuf_streamoff(file,q);
video_end(fh, file); video_end(fh, file);
return err; return err;
...@@ -1309,7 +1374,7 @@ static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv) ...@@ -1309,7 +1374,7 @@ static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
} }
static void video_open(struct saa7146_dev *dev, struct file *file) static int video_open(struct saa7146_dev *dev, struct file *file)
{ {
struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data; struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
struct saa7146_format *sfmt; struct saa7146_format *sfmt;
...@@ -1329,6 +1394,8 @@ static void video_open(struct saa7146_dev *dev, struct file *file) ...@@ -1329,6 +1394,8 @@ static void video_open(struct saa7146_dev *dev, struct file *file)
sizeof(struct saa7146_buf)); sizeof(struct saa7146_buf));
init_MUTEX(&fh->video_q.lock); init_MUTEX(&fh->video_q.lock);
return 0;
} }
...@@ -1381,20 +1448,35 @@ static ssize_t video_read(struct file *file, char *data, size_t count, loff_t *p ...@@ -1381,20 +1448,35 @@ static ssize_t video_read(struct file *file, char *data, size_t count, loff_t *p
DEB_EE(("called.\n")); DEB_EE(("called.\n"));
/* fixme: should we allow read() captures while streaming capture? */
if( 0 != vv->streaming ) {
DEB_S(("already capturing.\n"));
return -EBUSY;
}
/* stop any active overlay */
if( vv->ov_data != NULL ) { if( vv->ov_data != NULL ) {
ov_fh = vv->ov_data->fh; ov_fh = vv->ov_data->fh;
saa7146_stop_preview(ov_fh); saa7146_stop_preview(ov_fh);
saa7146_res_free(ov_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
restart_overlay = 1; restart_overlay = 1;
} }
if( 0 != video_begin(fh)) { ret = video_begin(fh);
return -EAGAIN; if( 0 != ret) {
goto out;
} }
ret = videobuf_read_one(file,&fh->video_q , data, count, ppos); ret = videobuf_read_one(file,&fh->video_q , data, count, ppos);
video_end(fh, file); video_end(fh, file);
out:
/* restart overlay if it was active before */ /* restart overlay if it was active before */
if( 0 != restart_overlay ) { if( 0 != restart_overlay ) {
if (0 == saa7146_res_get(ov_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) {
DEB_D(("cannot get overlay resources again!\n"));
BUG();
}
saa7146_start_preview(ov_fh); saa7146_start_preview(ov_fh);
} }
......
...@@ -67,6 +67,8 @@ struct saa7146_pgtable { ...@@ -67,6 +67,8 @@ struct saa7146_pgtable {
dma_addr_t dma; dma_addr_t dma;
/* used for offsets for u,v planes for planar capture modes */ /* used for offsets for u,v planes for planar capture modes */
unsigned long offset; unsigned long offset;
/* used for custom pagetables (used for example by budget dvb cards) */
struct scatterlist *slist;
}; };
struct saa7146_pci_extension_data { struct saa7146_pci_extension_data {
......
...@@ -26,12 +26,15 @@ struct saa7146_video_dma { ...@@ -26,12 +26,15 @@ struct saa7146_video_dma {
u32 num_line_byte; u32 num_line_byte;
}; };
#define FORMAT_BYTE_SWAP 0x1
#define FORMAT_IS_PLANAR 0x2
struct saa7146_format { struct saa7146_format {
char *name; char *name;
int pixelformat; u32 pixelformat;
u32 trans; u32 trans;
u8 depth; u8 depth;
int swap; u8 flags;
}; };
struct saa7146_standard struct saa7146_standard
...@@ -97,6 +100,8 @@ struct saa7146_fh { ...@@ -97,6 +100,8 @@ struct saa7146_fh {
struct videobuf_queue vbi_q; struct videobuf_queue vbi_q;
struct v4l2_vbi_format vbi_fmt; struct v4l2_vbi_format vbi_fmt;
struct timer_list vbi_read_timeout; struct timer_list vbi_read_timeout;
unsigned int resources; /* resource management for device open */
}; };
struct saa7146_vv struct saa7146_vv
...@@ -136,6 +141,8 @@ struct saa7146_vv ...@@ -136,6 +141,8 @@ struct saa7146_vv
int current_hps_sync; int current_hps_sync;
struct saa7146_dma d_clipping; /* pointer to clipping memory */ struct saa7146_dma d_clipping; /* pointer to clipping memory */
unsigned int resources; /* resource management for device */
}; };
#define SAA7146_EXCLUSIVE 0x1 #define SAA7146_EXCLUSIVE 0x1
...@@ -149,7 +156,6 @@ struct saa7146_extension_ioctls ...@@ -149,7 +156,6 @@ struct saa7146_extension_ioctls
}; };
/* flags */ /* flags */
// #define SAA7146_EXT_SWAP_ODD_EVEN 0x1 /* needs odd/even fields swapped */
#define SAA7146_USE_PORT_B_FOR_VBI 0x2 /* use input port b for vbi hardware bug workaround */ #define SAA7146_USE_PORT_B_FOR_VBI 0x2 /* use input port b for vbi hardware bug workaround */
struct saa7146_ext_vv struct saa7146_ext_vv
...@@ -171,7 +177,7 @@ struct saa7146_ext_vv ...@@ -171,7 +177,7 @@ struct saa7146_ext_vv
struct saa7146_use_ops { struct saa7146_use_ops {
void (*init)(struct saa7146_dev *, struct saa7146_vv *); void (*init)(struct saa7146_dev *, struct saa7146_vv *);
void(*open)(struct saa7146_dev *, struct file *); int(*open)(struct saa7146_dev *, struct file *);
void (*release)(struct saa7146_dev *, struct file *); void (*release)(struct saa7146_dev *, struct file *);
void (*irq_done)(struct saa7146_dev *, unsigned long status); void (*irq_done)(struct saa7146_dev *, unsigned long status);
ssize_t (*read)(struct file *, char *, size_t, loff_t *); ssize_t (*read)(struct file *, char *, size_t, loff_t *);
...@@ -189,9 +195,10 @@ void saa7146_dma_free(struct saa7146_dev *dev,struct saa7146_buf *buf); ...@@ -189,9 +195,10 @@ void saa7146_dma_free(struct saa7146_dev *dev,struct saa7146_buf *buf);
int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv); int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv);
int saa7146_vv_release(struct saa7146_dev* dev); int saa7146_vv_release(struct saa7146_dev* dev);
/* from saa7146_hlp.c */ /* from saa7146_hlp.c */
void saa7146_set_overlay(struct saa7146_dev *dev, struct saa7146_fh *fh, int v); int saa7146_enable_overlay(struct saa7146_fh *fh);
void saa7146_disable_overlay(struct saa7146_fh *fh);
void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next); void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next);
void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_video_dma* vdma) ; void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_video_dma* vdma) ;
void saa7146_set_hps_source_and_sync(struct saa7146_dev *saa, int source, int sync); void saa7146_set_hps_source_and_sync(struct saa7146_dev *saa, int source, int sync);
...@@ -205,6 +212,16 @@ int saa7146_stop_preview(struct saa7146_fh *fh); ...@@ -205,6 +212,16 @@ int saa7146_stop_preview(struct saa7146_fh *fh);
/* from saa7146_vbi.c */ /* from saa7146_vbi.c */
extern struct saa7146_use_ops saa7146_vbi_uops; extern struct saa7146_use_ops saa7146_vbi_uops;
/* resource management functions */
int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit);
int saa7146_res_check(struct saa7146_fh *fh, unsigned int bit);
int saa7146_res_locked(struct saa7146_dev *dev, unsigned int bit);
void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits);
#define RESOURCE_DMA1_HPS 0x1
#define RESOURCE_DMA2_CLP 0x2
#define RESOURCE_DMA3_BRS 0x4
/* saa7146 source inputs */ /* saa7146 source inputs */
#define SAA7146_HPS_SOURCE_PORT_A 0x00 #define SAA7146_HPS_SOURCE_PORT_A 0x00
#define SAA7146_HPS_SOURCE_PORT_B 0x01 #define SAA7146_HPS_SOURCE_PORT_B 0x01
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment