Skip to content

Commit

Permalink
V4L/DVB (13098): cx23885: Add integrated IR subdevice interrupt and n…
Browse files Browse the repository at this point in the history
…otification handling

Add integrated IR subdevice interrupt and notification handling.  This is in
preparation of input keypress handling changes for the cx23885 module.

Signed-off-by: Andy Walls <awalls@radix.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
  • Loading branch information
Andy Walls authored and Mauro Carvalho Chehab committed Dec 5, 2009
1 parent 1a0b9d8 commit f59ad61
Show file tree
Hide file tree
Showing 7 changed files with 224 additions and 18 deletions.
2 changes: 1 addition & 1 deletion drivers/media/video/cx23885/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o \
cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o \
cx23885-ioctl.o cx23888-ir.o \
cx23885-ioctl.o cx23885-ir.o cx23888-ir.o \
netup-init.o cimax2.o netup-eeprom.o

obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
Expand Down
23 changes: 23 additions & 0 deletions drivers/media/video/cx23885/cx23885-cards.c
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,7 @@ int cx23885_ir_init(struct cx23885_dev *dev)
if (ret)
break;
dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR);
dev->pci_irqmask |= PCI_MSK_IR;
break;
case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
request_module("ir-kbd-i2c");
Expand All @@ -830,6 +831,28 @@ int cx23885_ir_init(struct cx23885_dev *dev)
return ret;
}

void cx23885_ir_fini(struct cx23885_dev *dev)
{
switch (dev->board) {
case CX23885_BOARD_HAUPPAUGE_HVR1850:
dev->pci_irqmask &= ~PCI_MSK_IR;
cx_clear(PCI_INT_MSK, PCI_MSK_IR);
cx23888_ir_remove(dev);
dev->sd_ir = NULL;
break;
}
}

void cx23885_ir_pci_int_enable(struct cx23885_dev *dev)
{
switch (dev->board) {
case CX23885_BOARD_HAUPPAUGE_HVR1850:
if (dev->sd_ir && (dev->pci_irqmask & PCI_MSK_IR))
cx_set(PCI_INT_MSK, PCI_MSK_IR);
break;
}
}

void cx23885_card_setup(struct cx23885_dev *dev)
{
struct cx23885_tsport *ts1 = &dev->ts1;
Expand Down
74 changes: 60 additions & 14 deletions drivers/media/video/cx23885/cx23885-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "cx23885.h"
#include "cimax2.h"
#include "cx23888-ir.h"
#include "cx23885-ir.h"

MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
Expand Down Expand Up @@ -1655,6 +1656,7 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
u32 ts1_status, ts1_mask;
u32 ts2_status, ts2_mask;
int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0;
bool ir_handled = false;

pci_status = cx_read(PCI_INT_STAT);
pci_mask = cx_read(PCI_INT_MSK);
Expand All @@ -1680,18 +1682,12 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n",
ts2_status, ts2_mask, ts2_count);

if ((pci_status & PCI_MSK_RISC_RD) ||
(pci_status & PCI_MSK_RISC_WR) ||
(pci_status & PCI_MSK_AL_RD) ||
(pci_status & PCI_MSK_AL_WR) ||
(pci_status & PCI_MSK_APB_DMA) ||
(pci_status & PCI_MSK_VID_C) ||
(pci_status & PCI_MSK_VID_B) ||
(pci_status & PCI_MSK_VID_A) ||
(pci_status & PCI_MSK_AUD_INT) ||
(pci_status & PCI_MSK_AUD_EXT) ||
(pci_status & PCI_MSK_GPIO0) ||
(pci_status & PCI_MSK_GPIO1)) {
if (pci_status & (PCI_MSK_RISC_RD | PCI_MSK_RISC_WR |
PCI_MSK_AL_RD | PCI_MSK_AL_WR | PCI_MSK_APB_DMA |
PCI_MSK_VID_C | PCI_MSK_VID_B | PCI_MSK_VID_A |
PCI_MSK_AUD_INT | PCI_MSK_AUD_EXT |
PCI_MSK_GPIO0 | PCI_MSK_GPIO1 |
PCI_MSK_IR)) {

if (pci_status & PCI_MSK_RISC_RD)
dprintk(7, " (PCI_MSK_RISC_RD 0x%08x)\n",
Expand Down Expand Up @@ -1740,6 +1736,10 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
if (pci_status & PCI_MSK_GPIO1)
dprintk(7, " (PCI_MSK_GPIO1 0x%08x)\n",
PCI_MSK_GPIO1);

if (pci_status & PCI_MSK_IR)
dprintk(7, " (PCI_MSK_IR 0x%08x)\n",
PCI_MSK_IR);
}

if (cx23885_boards[dev->board].cimax > 0 &&
Expand Down Expand Up @@ -1770,12 +1770,48 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
if (vida_status)
handled += cx23885_video_irq(dev, vida_status);

if (pci_status & PCI_MSK_IR) {
v4l2_subdev_call(dev->sd_ir, ir, interrupt_service_routine,
pci_status, &ir_handled);
if (ir_handled)
handled++;
}

if (handled)
cx_write(PCI_INT_STAT, pci_status);
out:
return IRQ_RETVAL(handled);
}

static void cx23885_v4l2_dev_notify(struct v4l2_subdev *sd,
unsigned int notification, void *arg)
{
struct cx23885_dev *dev;

if (sd == NULL)
return;

dev = to_cx23885(sd->v4l2_dev);

switch (notification) {
case V4L2_SUBDEV_IR_RX_NOTIFY: /* Called in an IRQ context */
if (sd == dev->sd_ir)
cx23885_ir_rx_v4l2_dev_notify(sd, *(u32 *)arg);
break;
case V4L2_SUBDEV_IR_TX_NOTIFY: /* Called in an IRQ context */
if (sd == dev->sd_ir)
cx23885_ir_tx_v4l2_dev_notify(sd, *(u32 *)arg);
break;
}
}

static void cx23885_v4l2_dev_notify_init(struct cx23885_dev *dev)
{
INIT_WORK(&dev->ir_rx_work, cx23885_ir_rx_work_handler);
INIT_WORK(&dev->ir_tx_work, cx23885_ir_tx_work_handler);
dev->v4l2_dev.notify = cx23885_v4l2_dev_notify;
}

static inline int encoder_on_portb(struct cx23885_dev *dev)
{
return cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER;
Expand Down Expand Up @@ -1872,6 +1908,9 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
if (err < 0)
goto fail_free;

/* Prepare to handle notifications from subdevices */
cx23885_v4l2_dev_notify_init(dev);

/* pci init */
dev->pci = pci_dev;
if (pci_enable_device(pci_dev)) {
Expand Down Expand Up @@ -1914,6 +1953,13 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
break;
}

/*
* The CX2388[58] IR controller can start firing interrupts when
* enabled, so these have to take place after the cx23885_irq() handler
* is hooked up by the call to request_irq() above.
*/
cx23885_ir_pci_int_enable(dev);

return 0;

fail_irq:
Expand All @@ -1930,9 +1976,9 @@ static void __devexit cx23885_finidev(struct pci_dev *pci_dev)
struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
struct cx23885_dev *dev = to_cx23885(v4l2_dev);

cx23885_shutdown(dev);
cx23885_ir_fini(dev);

cx23888_ir_remove(dev);
cx23885_shutdown(dev);

pci_disable_device(pci_dev);

Expand Down
97 changes: 97 additions & 0 deletions drivers/media/video/cx23885/cx23885-ir.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Driver for the Conexant CX23885/7/8 PCIe bridge
*
* Infrared device support routines - non-input, non-vl42_subdev routines
*
* Copyright (C) 2009 Andy Walls <awalls@radix.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/

#include <media/v4l2-device.h>

#include "cx23885.h"

#define CX23885_IR_RX_FIFO_SERVICE_REQ 0
#define CX23885_IR_RX_END_OF_RX_DETECTED 1
#define CX23885_IR_RX_HW_FIFO_OVERRUN 2
#define CX23885_IR_RX_SW_FIFO_OVERRUN 3

#define CX23885_IR_TX_FIFO_SERVICE_REQ 0


void cx23885_ir_rx_work_handler(struct work_struct *work)
{
struct cx23885_dev *dev =
container_of(work, struct cx23885_dev, ir_rx_work);
u32 events = 0;
unsigned long *notifications = &dev->ir_rx_notifications;

if (test_and_clear_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications))
events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN;
if (test_and_clear_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications))
events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN;
if (test_and_clear_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications))
events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED;
if (test_and_clear_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications))
events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ;

if (events == 0)
return;
}

void cx23885_ir_tx_work_handler(struct work_struct *work)
{
struct cx23885_dev *dev =
container_of(work, struct cx23885_dev, ir_tx_work);
u32 events = 0;
unsigned long *notifications = &dev->ir_tx_notifications;

if (test_and_clear_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications))
events |= V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ;

if (events == 0)
return;

}

/* Called in an IRQ context */
void cx23885_ir_rx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events)
{
struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev);
unsigned long *notifications = &dev->ir_rx_notifications;

if (events & V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ)
set_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications);
if (events & V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED)
set_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications);
if (events & V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN)
set_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications);
if (events & V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN)
set_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications);
schedule_work(&dev->ir_rx_work);
}

/* Called in an IRQ context */
void cx23885_ir_tx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events)
{
struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev);
unsigned long *notifications = &dev->ir_tx_notifications;

if (events & V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ)
set_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications);
schedule_work(&dev->ir_tx_work);
}
31 changes: 31 additions & 0 deletions drivers/media/video/cx23885/cx23885-ir.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Driver for the Conexant CX23885/7/8 PCIe bridge
*
* Infrared device support routines - non-input, non-vl42_subdev routines
*
* Copyright (C) 2009 Andy Walls <awalls@radix.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/

#ifndef _CX23885_IR_H_
#define _CX23885_IR_H_
void cx23885_ir_rx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events);
void cx23885_ir_tx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events);

void cx23885_ir_rx_work_handler(struct work_struct *work);
void cx23885_ir_tx_work_handler(struct work_struct *work);
#endif
5 changes: 3 additions & 2 deletions drivers/media/video/cx23885/cx23885-reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,9 @@ Channel manager Data Structure entry = 20 DWORD

#define DEV_CNTRL2 0x00040000

#define PCI_MSK_GPIO1 (1 << 24)
#define PCI_MSK_GPIO0 (1 << 23)
#define PCI_MSK_IR (1 << 28)
#define PCI_MSK_GPIO1 (1 << 24)
#define PCI_MSK_GPIO0 (1 << 23)
#define PCI_MSK_APB_DMA (1 << 12)
#define PCI_MSK_AL_WR (1 << 11)
#define PCI_MSK_AL_RD (1 << 10)
Expand Down
10 changes: 9 additions & 1 deletion drivers/media/video/cx23885/cx23885.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,13 @@ struct cx23885_dev {
unsigned char radio_addr;
unsigned int has_radio;
struct v4l2_subdev *sd_cx25840;
struct v4l2_subdev *sd_ir;

/* Infrared */
struct v4l2_subdev *sd_ir;
struct work_struct ir_rx_work;
unsigned long ir_rx_notifications;
struct work_struct ir_tx_work;
unsigned long ir_tx_notifications;

/* V4l */
u32 freq;
Expand Down Expand Up @@ -479,6 +485,8 @@ extern int cx23885_tuner_callback(void *priv, int component,
int command, int arg);
extern void cx23885_card_list(struct cx23885_dev *dev);
extern int cx23885_ir_init(struct cx23885_dev *dev);
extern void cx23885_ir_pci_int_enable(struct cx23885_dev *dev);
extern void cx23885_ir_fini(struct cx23885_dev *dev);
extern void cx23885_gpio_setup(struct cx23885_dev *dev);
extern void cx23885_card_setup(struct cx23885_dev *dev);
extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev);
Expand Down

0 comments on commit f59ad61

Please sign in to comment.