cx23885: Return -ENXIO on slave nack
A message that is not in the archive (sent off-list or not yet received): [email protected]
PATCH 1/17 cx23885: Return -ENXIO on slave nack
From: Jean Delvare <[email protected]>
Documentation/i2c/fault-codes says that i2c adapter drivers should return -ENXIO when no slave acks an address byte.
--- drivers/media/video/cx23885/cx23885-i2c.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/media/video/cx23885/cx23885-i2c.c +2 -2
@@ -99,7 +99,7 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,if (!i2c_wait_done (i2c_adap))return -EIO ;if (!i2c_slave_did_ack (i2c_adap)) -return -EIO ; +return -ENXIO ;dprintk (1 ,"%s() returns 0\n" , __func__);return 0 ;
@@ -185,7 +185,7 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,if (!i2c_wait_done (i2c_adap))return -EIO ;if (!i2c_slave_did_ack (i2c_adap)) -return -EIO ; +return -ENXIO ;dprintk (1 ,"%s() returns 0\n" , __func__);
Signature · 1 line
1.7.1.1
PATCH 2/17 cx23885: Check for slave nack on all transactions
In reply to a message not in the archiveFrom: Jean Delvare <[email protected]>
Don't just check for nacks on zero-length transactions. Check on other transactions too.
--- drivers/media/video/cx23885/cx23885-i2c.c | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-)
drivers/media/video/cx23885/cx23885-i2c.c +8 -0
@@ -125,6 +125,10 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, goto err;if (retval ==0 ) goto eio; +if (!i2c_slave_did_ack (i2c_adap)) { + retval = -ENXIO ; + goto err; + }if (i2c_debug) {printk (" <W %02x %02x" , msg->addr <<1 , msg->buf[0 ]);if (!(ctrl &I2C_NOSTOP ))
@@ -214,6 +218,10 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap, goto err;if (retval ==0 ) goto eio; +if (cnt ==0 && !i2c_slave_did_ack (i2c_adap)) { + retval = -ENXIO ; + goto err; + } msg->buf[cnt] =cx_read (bus->reg_rdata) &0xff ;if (i2c_debug) {dprintk (1 ," %02x" , msg->buf[cnt]);
Signature · 1 line
1.7.1.1
PATCH 3/17 cx23885: i2c_wait_done returns 0 or 1, don't check for < 0 return value
In reply to a message not in the archiveFrom: Jean Delvare <[email protected]>
Function i2c_wait_done() never returns negative values, so there is no point in checking for them.
--- drivers/media/video/cx23885/cx23885-i2c.c | 15 +++------------ 1 files changed, 3 insertions(+), 12 deletions(-)
drivers/media/video/cx23885/cx23885-i2c.c +3 -12
@@ -120,10 +120,7 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,cx_write (bus->reg_wdata, wdata);cx_write (bus->reg_ctrl, ctrl); - retval =i2c_wait_done (i2c_adap); -if (retval <0 ) - goto err; -if (retval ==0 ) +if (!i2c_wait_done (i2c_adap)) goto eio;if (!i2c_slave_did_ack (i2c_adap)) { retval = -ENXIO ;
@@ -149,10 +146,7 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,cx_write (bus->reg_wdata, wdata);cx_write (bus->reg_ctrl, ctrl); - retval =i2c_wait_done (i2c_adap); -if (retval <0 ) - goto err; -if (retval ==0 ) +if (!i2c_wait_done (i2c_adap)) goto eio;if (i2c_debug) {dprintk (1 ," %02x" , msg->buf[cnt]);
@@ -213,10 +207,7 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,cx_write (bus->reg_addr, msg->addr <<25 );cx_write (bus->reg_ctrl, ctrl); - retval =i2c_wait_done (i2c_adap); -if (retval <0 ) - goto err; -if (retval ==0 ) +if (!i2c_wait_done (i2c_adap)) goto eio;if (cnt ==0 && !i2c_slave_did_ack (i2c_adap)) { retval = -ENXIO ;
Signature · 1 line
1.7.1.1
PATCH 4/17 cx25840: Make cx25840 i2c register read transactions atomic
In reply to a message not in the archiveThere was a small window between writing the cx25840 register address over the i2c bus and reading the register contents back from the cx25840 device that the i2c adapter lock was released. This change ensures the adapter lock is not released until the register read is done.
--- drivers/media/video/cx25840/cx25840-core.c | 58 +++++++++++++++++++--------- 1 files changed, 39 insertions(+), 19 deletions(-)
drivers/media/video/cx25840/cx25840-core.c +39 -19
@@ -80,33 +80,53 @@ int cx25840_write4(struct i2c_client *client, u16 addr, u32 value)u8 cx25840_read (struct i2c_client * client,u16 addr) { -u8 buffer[2 ]; - buffer[0 ] = addr >>8 ; - buffer[1 ] = addr &0xff ; - -if (i2c_master_send (client, buffer,2 ) <2 ) -return 0 ; - -if (i2c_master_recv (client, buffer,1 ) <1 ) +struct i2c_msg msgs[2 ]; +u8 tx_buf[2 ], rx_buf[1 ]; + +/* Write register address */ + tx_buf[0 ] = addr >>8 ; + tx_buf[1 ] = addr &0xff ; + msgs[0 ].addr = client->addr; + msgs[0 ].flags =0 ; + msgs[0 ].len =2 ; + msgs[0 ].buf = (char *) tx_buf; + +/* Read data from register */ + msgs[1 ].addr = client->addr; + msgs[1 ].flags =I2C_M_RD ; + msgs[1 ].len =1 ; + msgs[1 ].buf = (char *) rx_buf; + +if (i2c_transfer (client->adapter, msgs,2 ) <2 )return 0 ; -return buffer[0 ]; +return rx_buf[0 ]; }u32 cx25840_read4 (struct i2c_client * client,u16 addr) { -u8 buffer[4 ]; - buffer[0 ] = addr >>8 ; - buffer[1 ] = addr &0xff ; - -if (i2c_master_send (client, buffer,2 ) <2 ) -return 0 ; - -if (i2c_master_recv (client, buffer,4 ) <4 ) +struct i2c_msg msgs[2 ]; +u8 tx_buf[2 ], rx_buf[4 ]; + +/* Write register address */ + tx_buf[0 ] = addr >>8 ; + tx_buf[1 ] = addr &0xff ; + msgs[0 ].addr = client->addr; + msgs[0 ].flags =0 ; + msgs[0 ].len =2 ; + msgs[0 ].buf = (char *) tx_buf; + +/* Read data from registers */ + msgs[1 ].addr = client->addr; + msgs[1 ].flags =I2C_M_RD ; + msgs[1 ].len =4 ; + msgs[1 ].buf = (char *) rx_buf; + +if (i2c_transfer (client->adapter, msgs,2 ) <2 )return 0 ; -return (buffer[3 ] <<24 ) | (buffer[2 ] <<16 ) | - (buffer[1 ] <<8 ) | buffer[0 ]; +return (rx_buf[3 ] <<24 ) | (rx_buf[2 ] <<16 ) | (rx_buf[1 ] <<8 ) | + rx_buf[0 ]; } int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask,
Signature · 1 line
1.7.1.1
Re: [PATCH 04/17] cx25840: Make cx25840 i2c register read transactions atomic
Hi Andy,
Quoted 6 lines · Andy Walls
There was a small window between writing the cx25840 register address over the i2c bus and reading the register contents back from the cx25840 device that the i2c adapter lock was released. This change ensures the adapter lock is not released until the register read is done.
Signed-off-by Andy Walls <[email protected]>
Good catch.
Note that cx25840_and_or() still has a (smaller and less dangerous) race window. If several calls to cx25840_and_or() happen in parallel on the same register, some of the changes may be lost. I don't know if this can be a problem in practice though. If it is, then additional locking around cx25840_and_or() would be needed.
Quoted 81 lines
--- drivers/media/video/cx25840/cx25840-core.c | 58 +++++++++++++++++++--------- 1 files changed, 39 insertions(+), 19 deletions(-)drivers/media/video/cx25840/cx25840-core.c +39
-19@@ -80,33 +80,53 @@ int cx25840_write4(struct i2c_client *client, u16 addr, u32 value)u8 cx25840_read (struct i2c_client * client,u16 addr) { -u8 buffer[2 ]; - buffer[0 ] = addr >>8 ; - buffer[1 ] = addr &0xff ; - -if (i2c_master_send (client, buffer,2 ) <2 ) -return 0 ; - -if (i2c_master_recv (client, buffer,1 ) <1 ) +struct i2c_msg msgs[2 ]; +u8 tx_buf[2 ], rx_buf[1 ]; + +/* Write register address */ + tx_buf[0 ] = addr >>8 ; + tx_buf[1 ] = addr &0xff ; + msgs[0 ].addr = client->addr; + msgs[0 ].flags =0 ; + msgs[0 ].len =2 ; + msgs[0 ].buf = (char *) tx_buf; + +/* Read data from register */ + msgs[1 ].addr = client->addr; + msgs[1 ].flags =I2C_M_RD ; + msgs[1 ].len =1 ; + msgs[1 ].buf = (char *) rx_buf; + +if (i2c_transfer (client->adapter, msgs,2 ) <2 )return 0 ; -return buffer[0 ]; +return rx_buf[0 ]; }u32 cx25840_read4 (struct i2c_client * client,u16 addr) { -u8 buffer[4 ]; - buffer[0 ] = addr >>8 ; - buffer[1 ] = addr &0xff ; - -if (i2c_master_send (client, buffer,2 ) <2 ) -return 0 ; - -if (i2c_master_recv (client, buffer,4 ) <4 ) +struct i2c_msg msgs[2 ]; +u8 tx_buf[2 ], rx_buf[4 ]; + +/* Write register address */ + tx_buf[0 ] = addr >>8 ; + tx_buf[1 ] = addr &0xff ; + msgs[0 ].addr = client->addr; + msgs[0 ].flags =0 ; + msgs[0 ].len =2 ; + msgs[0 ].buf = (char *) tx_buf; + +/* Read data from registers */ + msgs[1 ].addr = client->addr; + msgs[1 ].flags =I2C_M_RD ; + msgs[1 ].len =4 ; + msgs[1 ].buf = (char *) rx_buf; + +if (i2c_transfer (client->adapter, msgs,2 ) <2 )return 0 ; -return (buffer[3 ] <<24 ) | (buffer[2 ] <<16 ) | - (buffer[1 ] <<8 ) | buffer[0 ]; +return (rx_buf[3 ] <<24 ) | (rx_buf[2 ] <<16 ) | (rx_buf[1 ] <<8 ) | + rx_buf[0 ]; } int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask,
Signature · 1 line
Jean Delvare
Re: [PATCH 04/17] cx25840: Make cx25840 i2c register read transactions atomic
Quoted 11 lines · Jean Delvare
Hi Andy,
Quoted 6 lines · Andy Walls
There was a small window between writing the cx25840 register address over the i2c bus and reading the register contents back from the cx25840 device that the i2c adapter lock was released. This change ensures the adapter lock is not released until the register read is done.
Signed-off-by Andy Walls <[email protected]>Good catch.
Thanks.
Quoted 7 lines
Acked-by Jean Delvare <[email protected]>Note that
cx25840_and_or()still has a (smaller and less dangerous) race window. If several calls tocx25840_and_or()happen in parallel on the same register, some of the changes may be lost. I don't know if this can be a problem in practice though. If it is, then additional locking aroundcx25840_and_or()would be needed.
Ah, thank you for pointing that out.
So, please bear with me while I think out loud:
1. There are many explicit cases of read-modify-write on a register in the cx25840 module, this is not the only one.
2. The bridge driver historically has always serialized access to the cx25840 module so races have never previously been an issue.
3. I have added a work handler in the cx23885 module that calls the cx25840 module's interrupt handler. Calls by the work handler are serialized with respect to themselves, but not with respect to serialized calls in #2.
4. IIRC, registers written to by the cx25840 interrupt handler are never written to by the other cx25840 module functions; and vice-versa. I will have to audit the cx25840 module code to be sure.
5. There is always a race on r-m-w on *some* registers in the 0x800-0x9ff range with the audio microcontroller that is built into the chip. The only way to provide locking for those is to halt the microcontroller. I've just looked at Patch 12/17 again. The interrupt handler only reads the CX23885_AUD_MC_INT_MASK_REG, which is used by the audio micrcontroller. The interrupt handler does do a r-m-w on the CX25840_AUD_INT_STAT_REG, but that register is not used by the microcontroller.
So, I think I'm OK with just not dropping the i2c adapter lock in a cx25840 register read transaction until it is complete.
Thanks for making me think that one through. :)
Regards,
Andy
Re: [PATCH 04/17] cx25840: Make cx25840 i2c register read transactions atomic
Quoted 52 lines · Andy Walls
Quoted 11 lines · Jean Delvare
Hi Andy,
Quoted 6 lines · Andy Walls
There was a small window between writing the cx25840 register address over the i2c bus and reading the register contents back from the cx25840 device that the i2c adapter lock was released. This change ensures the adapter lock is not released until the register read is done.
Signed-off-by Andy Walls <[email protected]>Good catch.
Thanks.
Quoted 7 lines
Acked-by Jean Delvare <[email protected]>Note that
cx25840_and_or()still has a (smaller and less dangerous) race window. If several calls tocx25840_and_or()happen in parallel on the same register, some of the changes may be lost. I don't know if this can be a problem in practice though. If it is, then additional locking aroundcx25840_and_or()would be needed.Ah, thank you for pointing that out.
So, please bear with me while I think out loud:
1. There are many explicit cases of read-modify-write on a register in the cx25840 module, this is not the only one.
2. The bridge driver historically has always serialized access to the cx25840 module so races have never previously been an issue.
3. I have added a work handler in the cx23885 module that calls the cx25840 module's interrupt handler. Calls by the work handler are serialized with respect to themselves, but not with respect to serialized calls in #2.
4. IIRC, registers written to by the cx25840 interrupt handler are never written to by the other cx25840 module functions; and vice-versa. I will have to audit the cx25840 module code to be sure.
5. There is always a race on r-m-w on *some* registers in the 0x800-0x9ff range with the audio microcontroller that is built into the chip. The only way to provide locking for those is to halt the microcontroller. I've just looked at Patch 12/17 again. The interrupt handler only reads the
CX23885_AUD_MC_INT_MASK_REG, which is used by the audio micrcontroller. The interrupt handler does do a r-m-w on theCX25840_AUD_INT_STAT_REG, but that register is not used by the microcontroller.
Quoted 4 lines
So, I think I'm OK with just not dropping the i2c adapter lock in a cx25840 register read transaction until it is complete.
Thanks for making me think that one through. :)
Looks like you're OK then, but you may want to document this somewhere for future contributors to these drivers.
Signature · 1 line
Jean Delvare
PATCH 5/17 cx23885: Add correct detection of the HVR-1250 model 79501
In reply to a message not in the archiveThe offset in the eeprom data for the 79501 version of the HVR-1250 is at 0xc0 vs. the standard 0x80.
--- drivers/media/video/cx23885/cx23885-cards.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-)
drivers/media/video/cx23885/cx23885-cards.c +10 -0
@@ -586,6 +586,9 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)case 79101 :/* WinTV-HVR1250 (PCIe, Retail, IR, half height, ATSC and Basic analog */ +case 79501 : +/* WinTV-HVR1250 (PCIe, No IR, half height, +ATSC [at least] and Basic analog) */ case 79561 :/* WinTV-HVR1250 (PCIe, OEM, No IR, half height, ATSC and Basic analog */
@@ -988,6 +991,13 @@ void cx23885_card_setup(struct cx23885_dev *dev)switch (dev->board) {case CX23885_BOARD_HAUPPAUGE_HVR1250 : +if (dev->i2c_bus[0 ].i2c_rc ==0 ) { +if (eeprom[0x80 ] !=0x84 ) +hauppauge_eeprom (dev, eeprom+0xc0 ); +else +hauppauge_eeprom (dev, eeprom+0x80 ); + } +break ;case CX23885_BOARD_HAUPPAUGE_HVR1500 :case CX23885_BOARD_HAUPPAUGE_HVR1500Q :case CX23885_BOARD_HAUPPAUGE_HVR1400 :
Signature · 1 line
1.7.1.1
PATCH 6/17 cx23885: Add a VIDIOC_LOG_STATUS ioctl function for analog video devices
In reply to a message not in the archiveAdd a simple log_status function for raw analog video capture device nodes, to provide insight into the state of the CX2388[578] A/V decoder core.
--- drivers/media/video/cx23885/cx23885-video.c | 16 ++++++++++++++++ 1 files changed, 16 insertions(+), 0 deletions(-)
drivers/media/video/cx23885/cx23885-video.c +16 -0
@@ -1205,6 +1205,21 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)return 0 ; } +static int vidioc_log_status (struct file *file,void *priv) +{ +struct cx23885_fh *fh = priv; +struct cx23885_dev *dev = fh->dev; + +printk (KERN_INFO +"%s/0: ============ START LOG STATUS ============\n" , + dev->name); +call_all (dev, core, log_status); +printk (KERN_INFO +"%s/0: ============= END LOG STATUS =============\n" , + dev->name); +return 0 ; +} +static int vidioc_queryctrl (struct file *file,void *priv,struct v4l2_queryctrl *qctrl) {
@@ -1410,6 +1425,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, + .vidioc_log_status = vidioc_log_status, .vidioc_queryctrl = vidioc_queryctrl, .vidioc_g_ctrl = vidioc_g_ctrl, .vidioc_s_ctrl = vidioc_s_ctrl,
Signature · 1 line
1.7.1.1
PATCH 7/17 v4l2_subdev: Add s_io_pin_config to v4l2_subdev_core_ops
In reply to a message not in the archiveAdd a method to v4l2_sudev_core_ops to allow bridge drivers to manage what signal pads/functions are routed out to multiplexed IO pins on a pin by pin basis. The interface also allows specifying initial output settings for pins and disabling an IO pin altogether.
--- include/media/v4l2-subdev.h | 23 +++++++++++++++++++++++ 1 files changed, 23 insertions(+), 0 deletions(-)
include/media/v4l2-subdev.h +23 -0
@@ -90,10 +90,31 @@ struct v4l2_decode_vbi_line {not yet implemented) since ops provide proper type-checking. */ +/* Subdevice external IO pin configuration */ +#define V4L2_SUBDEV_IO_PIN_DISABLE (1 << 0)/* ENABLE assumed */ +#define V4L2_SUBDEV_IO_PIN_OUTPUT (1 << 1) +#define V4L2_SUBDEV_IO_PIN_INPUT (1 << 2) +#define V4L2_SUBDEV_IO_PIN_SET_VALUE (1 << 3)/* Set output value */ +#define V4L2_SUBDEV_IO_PIN_ACTIVE_LOW (1 << 4)/* ACTIVE HIGH assumed */ + +struct v4l2_subdev_io_pin_config { +u32 flags;/* V4L2_SUBDEV_IO_PIN_* flags for this pin's config */ +u8 pin;/* Chip external IO pin to configure */ +u8 function;/* Internal signal pad/function to route to IO pin */ +u8 value;/* Initial value for pin - e.g. GPIO output value */ +u8 strength;/* Pin drive strength */ +}; +/* s_config: if set, then it is always called by the v4l2_i2c_new_subdev* functions after the v4l2_subdev was registered. It is used to pass platform data to the subdev which can be used during initialization. +s_io_pin_config: configure one or more chip I/O pins for chips that +multiplex different internal signal pads out to IO pins. This function +takes a pointer to an array of 'n' pin configuration entries, one for +each pin being configured. This function could be called at times +other than just subdevice initialization. +init: initialize the sensor registors to some sort of reasonable default values. Do not use for new drivers and should be removed in existing drivers.
@@ -115,6 +136,8 @@ struct v4l2_subdev_core_ops {int (*g_chip_ident)(struct v4l2_subdev *sd,struct v4l2_dbg_chip_ident *chip);int (*log_status)(struct v4l2_subdev *sd);int (*s_config)(struct v4l2_subdev *sd,int irq,void *platform_data); +int (*s_io_pin_config)(struct v4l2_subdev *sd,size_t n, +struct v4l2_subdev_io_pin_config *pincfg);int (*init)(struct v4l2_subdev *sd,u32 val);int (*load_fw)(struct v4l2_subdev *sd);int (*reset)(struct v4l2_subdev *sd,u32 val);
Signature · 1 line
1.7.1.1
PATCH 8/17 cx25840: Add s_io_pin_config core subdev ops for the CX2388[578]
In reply to a message not in the archiveAdd s_io_pin_config core subdev op for the CX2388[578] AV cores. This is complete for IR_RX, IR_TX, GPIOs 16,19-23, and IRQ_N. It likely needs work for the I2S signal direction.
--- drivers/media/video/cx25840/cx25840-core.c | 153 ++++++++++++++++++++++++++++ include/media/cx25840.h | 75 ++++++++++++++ 2 files changed, 228 insertions(+), 0 deletions(-)
drivers/media/video/cx25840/cx25840-core.c +153 -0
@@ -144,6 +144,158 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp/* ----------------------------------------------------------------------- */ +static int cx23885_s_io_pin_config (struct v4l2_subdev *sd,size_t n, +struct v4l2_subdev_io_pin_config *p) +{ +struct i2c_client *client =v4l2_get_subdevdata (sd); +int i; +u32 pin_ctrl; +u8 gpio_oe, gpio_data, strength; + + pin_ctrl =cx25840_read4 (client,0x120 ); + gpio_oe =cx25840_read (client,0x160 ); + gpio_data =cx25840_read (client,0x164 ); + +for (i =0 ; i < n; i++) { + strength = p[i].strength; +if (strength >CX25840_PIN_DRIVE_FAST ) + strength =CX25840_PIN_DRIVE_FAST ; + +switch (p[i].pin) { +case CX23885_PIN_IRQ_N_GPIO16 : +if (p[i].function !=CX23885_PAD_IRQ_N ) { +/* GPIO16 */ + pin_ctrl &= ~(0x1 <<25 ); + }else { +/* IRQ_N */ +if (p[i].flags & + (V4L2_SUBDEV_IO_PIN_DISABLE | +V4L2_SUBDEV_IO_PIN_INPUT )) { + pin_ctrl &= ~(0x1 <<25 ); + }else { + pin_ctrl |= (0x1 <<25 ); + } +if (p[i].flags & +V4L2_SUBDEV_IO_PIN_ACTIVE_LOW ) { + pin_ctrl &= ~(0x1 <<24 ); + }else { + pin_ctrl |= (0x1 <<24 ); + } + } +break ; +case CX23885_PIN_IR_RX_GPIO19 : +if (p[i].function !=CX23885_PAD_GPIO19 ) { +/* IR_RX */ + gpio_oe |= (0x1 <<0 ); + pin_ctrl &= ~(0x3 <<18 ); + pin_ctrl |= (strength <<18 ); + }else { +/* GPIO19 */ + gpio_oe &= ~(0x1 <<0 ); +if (p[i].flags &V4L2_SUBDEV_IO_PIN_SET_VALUE ) { + gpio_data &= ~(0x1 <<0 ); + gpio_data |= ((p[i].value &0x1 ) <<0 ); + } + pin_ctrl &= ~(0x3 <<12 ); + pin_ctrl |= (strength <<12 ); + } +break ; +case CX23885_PIN_IR_TX_GPIO20 : +if (p[i].function !=CX23885_PAD_GPIO20 ) { +/* IR_TX */ + gpio_oe |= (0x1 <<1 ); +if (p[i].flags &V4L2_SUBDEV_IO_PIN_DISABLE ) + pin_ctrl &= ~(0x1 <<10 ); +else + pin_ctrl |= (0x1 <<10 ); + pin_ctrl &= ~(0x3 <<18 ); + pin_ctrl |= (strength <<18 ); + }else { +/* GPIO20 */ + gpio_oe &= ~(0x1 <<1 ); +if (p[i].flags &V4L2_SUBDEV_IO_PIN_SET_VALUE ) { + gpio_data &= ~(0x1 <<1 ); + gpio_data |= ((p[i].value &0x1 ) <<1 ); + } + pin_ctrl &= ~(0x3 <<12 ); + pin_ctrl |= (strength <<12 ); + } +break ; +case CX23885_PIN_I2S_SDAT_GPIO21 : +if (p[i].function !=CX23885_PAD_GPIO21 ) { +/* I2S_SDAT */ +/* TODO: Input or Output config */ + gpio_oe |= (0x1 <<2 ); + pin_ctrl &= ~(0x3 <<22 ); + pin_ctrl |= (strength <<22 ); + }else { +/* GPIO21 */ + gpio_oe &= ~(0x1 <<2 ); +if (p[i].flags &V4L2_SUBDEV_IO_PIN_SET_VALUE ) { + gpio_data &= ~(0x1 <<2 ); + gpio_data |= ((p[i].value &0x1 ) <<2 ); + } + pin_ctrl &= ~(0x3 <<12 ); + pin_ctrl |= (strength <<12 ); + } +break ; +case CX23885_PIN_I2S_WCLK_GPIO22 : +if (p[i].function !=CX23885_PAD_GPIO22 ) { +/* I2S_WCLK */ +/* TODO: Input or Output config */ + gpio_oe |= (0x1 <<3 ); + pin_ctrl &= ~(0x3 <<22 ); + pin_ctrl |= (strength <<22 ); + }else { +/* GPIO22 */ + gpio_oe &= ~(0x1 <<3 ); +if (p[i].flags &V4L2_SUBDEV_IO_PIN_SET_VALUE ) { + gpio_data &= ~(0x1 <<3 ); + gpio_data |= ((p[i].value &0x1 ) <<3 ); + } + pin_ctrl &= ~(0x3 <<12 ); + pin_ctrl |= (strength <<12 ); + } +break ; +case CX23885_PIN_I2S_BCLK_GPIO23 : +if (p[i].function !=CX23885_PAD_GPIO23 ) { +/* I2S_BCLK */ +/* TODO: Input or Output config */ + gpio_oe |= (0x1 <<4 ); + pin_ctrl &= ~(0x3 <<22 ); + pin_ctrl |= (strength <<22 ); + }else { +/* GPIO23 */ + gpio_oe &= ~(0x1 <<4 ); +if (p[i].flags &V4L2_SUBDEV_IO_PIN_SET_VALUE ) { + gpio_data &= ~(0x1 <<4 ); + gpio_data |= ((p[i].value &0x1 ) <<4 ); + } + pin_ctrl &= ~(0x3 <<12 ); + pin_ctrl |= (strength <<12 ); + } +break ; + } + } + +cx25840_write (client,0x164 , gpio_data); +cx25840_write (client,0x160 , gpio_oe); +cx25840_write4 (client,0x120 , pin_ctrl); +return 0 ; +} + +static int common_s_io_pin_config (struct v4l2_subdev *sd,size_t n, +struct v4l2_subdev_io_pin_config *pincfg) +{ +struct cx25840_state *state =to_state (sd); + +if (is_cx2388x (state)) +return cx23885_s_io_pin_config (sd, n, pincfg); +return 0 ; +} + +/* ----------------------------------------------------------------------- */ +static void init_dll1 (struct i2c_client *client) {/* This is the Hauppauge sequence used to
@@ -1610,6 +1762,7 @@ static const struct v4l2_subdev_core_ops cx25840_core_ops = { .s_std = cx25840_s_std, .reset = cx25840_reset, .load_fw = cx25840_load_fw, + .s_io_pin_config = common_s_io_pin_config, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = cx25840_g_register, .s_register = cx25840_s_register,
include/media/cx25840.h +75 -0
79 lines not on this page · raw message
Signature · 1 line
1.7.1.1
PATCH 9/17 v4l2_subdev, cx23885: Differentiate IR carrier sense and I/O pin inversion
In reply to a message not in the archiveThere is a distinction on IR Tx for the CX2388[578] chips of carrier sense inversion (space is a carrier burst and mark is no burst) and I/O pin level inversion (0 is high output level, 1 is low output level). Allow the caller to set these parameters distinctly as v4l2_subdevice IR parameters. This permits the IR device to be configured and enabled without the IR Tx LED being on during idle/space time due to an external hardware level inversion
--- drivers/media/video/cx23885/cx23885-input.c | 2 +- drivers/media/video/cx23885/cx23888-ir.c | 32 ++++++++++++++++++++------ include/media/v4l2-subdev.h | 5 +++- 3 files changed, 29 insertions(+), 10 deletions(-)
drivers/media/video/cx23885/cx23885-input.c +1 -1
@@ -170,7 +170,7 @@ static int cx23885_input_ir_start(struct cx23885_dev *dev)* mark is received as low logic level; * falling edges are detected as rising edges; etc. */ - params.invert = true; + params.invert_level = true;break ; }v4l2_subdev_call (dev->sd_ir, ir, rx_s_parameters, ¶ms);
drivers/media/video/cx23885/cx23888-ir.c +24 -8
@@ -60,6 +60,8 @@ MODULE_PARM_DESC(ir_888_debug, "enable debug messages [CX23888 IR controller]");#define CNTRL_CPL 0x00001000#define CNTRL_LBM 0x00002000#define CNTRL_R 0x00004000 +/* CX23888 specific control flag */ +#define CNTRL_IVO 0x00008000#define CX23888_IR_TXCLK_REG 0x170004#define TXCLK_TCD 0x0000FFFF
@@ -423,6 +425,13 @@ static inline void control_tx_polarity_invert(struct cx23885_dev *dev, invert ? CNTRL_CPL : 0); } +static inline void control_tx_level_invert (struct cx23885_dev *dev, +bool invert) +{ +cx23888_ir_and_or4 (dev,CX23888_IR_CNTRL_REG , ~CNTRL_IVO , + invert ?CNTRL_IVO :0 ); +} +/* * IR Rx & Tx Clock Register helpers */
@@ -782,8 +791,8 @@ static int cx23888_ir_rx_s_parameters(struct v4l2_subdev *sd,control_rx_s_edge_detection (dev,CNTRL_EDG_BOTH ); - o->invert = p->invert; -atomic_set (&state->rx_invert, p->invert); + o->invert_level = p->invert_level; +atomic_set (&state->rx_invert, p->invert_level); o->interrupt_enable = p->interrupt_enable; o->enable = p->enable;
@@ -894,8 +903,11 @@ static int cx23888_ir_tx_s_parameters(struct v4l2_subdev *sd,/* FIXME - make this dependent on resolution for better performance */ control_tx_irq_watermark (dev,TX_FIFO_HALF_EMPTY ); -control_tx_polarity_invert (dev, p->invert); - o->invert = p->invert; +control_tx_polarity_invert (dev, p->invert_carrier_sense); + o->invert_carrier_sense = p->invert_carrier_sense; + +control_tx_level_invert (dev, p->invert_level); + o->invert_level = p->invert_level; o->interrupt_enable = p->interrupt_enable; o->enable = p->enable;
@@ -1025,8 +1037,11 @@ static int cx23888_ir_log_status(struct v4l2_subdev *sd) cntrl & CNTRL_TFE ? "enabled" : "disabled");v4l2_info (sd,"\tFIFO interrupt watermark: %s\n" , cntrl &CNTRL_TIC ?"not empty" :"half full or less" ); -v4l2_info (sd,"\tSignal polarity: %s\n" , - cntrl &CNTRL_CPL ?"0:mark 1:space" :"0:space 1:mark" ); +v4l2_info (sd,"\tOutput pin level inversion %s\n" , + cntrl &CNTRL_IVO ?"yes" :"no" ); +v4l2_info (sd,"\tCarrier polarity: %s\n" , + cntrl &CNTRL_CPL ?"space:burst mark:noburst" + :"space:noburst mark:burst" );if (cntrl &CNTRL_MOD ) {v4l2_info (sd,"\tCarrier (16 clocks): %u Hz\n" ,clock_divider_to_carrier_freq (txclk));
@@ -1146,7 +1161,7 @@ static const struct v4l2_subdev_ir_parameters default_rx_params = { .noise_filter_min_width = 333333, /* ns */ .carrier_range_lower = 35000, .carrier_range_upper = 37000, - .invert = false, + .invert_level = false, };static const struct v4l2_subdev_ir_parameters default_tx_params = {
@@ -1160,7 +1175,8 @@ static const struct v4l2_subdev_ir_parameters default_tx_params = { .modulation = true, .carrier_freq = 36000, /* 36 kHz - RC-5 carrier */ .duty_cycle = 25, /* 25 % - RC-5 carrier */ - .invert = false, + .invert_level = false, + .invert_carrier_sense = false, };int cx23888_ir_probe (struct cx23885_dev *dev)
include/media/v4l2-subdev.h +4 -1
@@ -379,7 +379,10 @@ struct v4l2_subdev_ir_parameters {u32 max_pulse_width;/* ns, valid only for baseband signal */ unsigned int carrier_freq;/* Hz, valid only for modulated signal*/ unsigned int duty_cycle;/* percent, valid only for modulated signal*/ -bool invert;/* logically invert sense of mark/space */ +bool invert_level;/* invert signal level */ + +/* Tx only */ +bool invert_carrier_sense;/* Send 0/space as a carrier burst */ /* Rx only */ u32 noise_filter_min_width;/* ns, min time of a valid pulse */
Signature · 1 line
1.7.1.1
PATCH 10/17 cx23885: For CX23888 IR, configure the IO pin mux IR pins explcitly
In reply to a message not in the archiveExplicitly configure the IR Tx and IR Rx pins to be driven by the IR Rx and Tx pads from the AV core for CX23888 IR.
For the HVR-1850 and HVR-1290 configure the IR Tx level inversion, so the Tx LED is off when idle.
--- drivers/media/video/cx23885/cx23885-cards.c | 31 +++++++++++++++++++++++++++ 1 files changed, 31 insertions(+), 0 deletions(-)
drivers/media/video/cx23885/cx23885-cards.c +31 -0
@@ -922,6 +922,24 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)int cx23885_ir_init (struct cx23885_dev *dev) { +static struct v4l2_subdev_io_pin_config ir_pin_cfg[] = { + { + .flags =V4L2_SUBDEV_IO_PIN_INPUT , + .pin =CX23885_PIN_IR_RX_GPIO19 , + .function =CX23885_PAD_IR_RX , + .value =0 , + .strength =CX25840_PIN_DRIVE_MEDIUM , + }, { + .flags =V4L2_SUBDEV_IO_PIN_OUTPUT , + .pin =CX23885_PIN_IR_TX_GPIO20 , + .function =CX23885_PAD_IR_TX , + .value =0 , + .strength =CX25840_PIN_DRIVE_MEDIUM , + } + }; +const size_t ir_pin_cfg_count =ARRAY_SIZE (ir_pin_cfg); + +struct v4l2_subdev_ir_parameters params;int ret =0 ;switch (dev->board) {case CX23885_BOARD_HAUPPAUGE_HVR1250 :
@@ -942,7 +960,20 @@ int cx23885_ir_init(struct cx23885_dev *dev)if (ret)break ; dev->sd_ir =cx23885_find_hw (dev,CX23885_HW_888_IR ); +v4l2_subdev_call (dev->sd_cx25840, core, s_io_pin_config, + ir_pin_cfg_count, ir_pin_cfg); dev->pci_irqmask |=PCI_MSK_IR ; +/* +* For these boards we need to invert the Tx output via the +* IR controller to have the LED off while idle +*/ +v4l2_subdev_call (dev->sd_ir, ir, tx_g_parameters, ¶ms); + params.enable = false; + params.shutdown = false; + params.invert_level = true; +v4l2_subdev_call (dev->sd_ir, ir, tx_s_parameters, ¶ms); + params.shutdown = true; +v4l2_subdev_call (dev->sd_ir, ir, tx_s_parameters, ¶ms);break ;case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP :request_module ("ir-kbd-i2c" );
Signature · 1 line
1.7.1.1
PATCH 11/17 v4l2_subdev: Move interrupt_service_routine ptr to v4l2_subdev_core_ops
In reply to a message not in the archiveThe CX2584x and related cores are multifunction subdevices with a number of internal blocks that act as interrupt sources. Move the v4L2_subdev interrupt_service_routine callback from v4l_subdev_ir_ops to v4l2_subdev_core_ops, as the video and audio blocks of a CX2584x and related cores can generate interrupts along with the IR block. This change also makes sense for other subdev's that generate interrupts and do not have an IR block.
--- drivers/media/video/cx23885/cx23885-core.c | 2 +- drivers/media/video/cx23885/cx23888-ir.c | 3 +-- include/media/v4l2-subdev.h | 16 +++++++--------- 3 files changed, 9 insertions(+), 12 deletions(-)
drivers/media/video/cx23885/cx23885-core.c +1 -1
@@ -1765,7 +1765,7 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) handled +=cx23885_video_irq (dev, vida_status);if (pci_status &PCI_MSK_IR ) { -v4l2_subdev_call (dev->sd_ir, ir, interrupt_service_routine, +v4l2_subdev_call (dev->sd_ir, core, interrupt_service_routine, pci_status, &ir_handled);if (ir_handled) handled++;
drivers/media/video/cx23885/cx23888-ir.c +1 -2
@@ -1126,11 +1126,10 @@ static const struct v4l2_subdev_core_ops cx23888_ir_core_ops = { .g_register = cx23888_ir_g_register, .s_register = cx23888_ir_s_register, #endif + .interrupt_service_routine = cx23888_ir_irq_handler, }; static const struct v4l2_subdev_ir_ops cx23888_ir_ir_ops = { - .interrupt_service_routine = cx23888_ir_irq_handler, - .rx_read = cx23888_ir_rx_read, .rx_g_parameters = cx23888_ir_rx_g_parameters, .rx_s_parameters = cx23888_ir_rx_s_parameters,
include/media/v4l2-subdev.h +7 -9
@@ -131,6 +131,11 @@ struct v4l2_subdev_io_pin_config {s_power: puts subdevice in power saving mode (on == 0) or normal operation mode (on == 1). + +interrupt_service_routine: Called by the bridge chip's interrupt service +handler, when an interrupt status has be raised due to this subdev, +so that this subdev can handle the details. It may schedule work to be +performed later. It must not sleep. *Called from an IRQ context*. */ struct v4l2_subdev_core_ops {int (*g_chip_ident)(struct v4l2_subdev *sd,struct v4l2_dbg_chip_ident *chip);
@@ -156,6 +161,8 @@ struct v4l2_subdev_core_ops {int (*s_register)(struct v4l2_subdev *sd,struct v4l2_dbg_register *reg);#endif int (*s_power)(struct v4l2_subdev *sd,int on); +int (*interrupt_service_routine)(struct v4l2_subdev *sd, +u32 status,bool *handled); };/* s_mode: switch the tuner to a specific tuner mode. Replacement of s_radio.
@@ -330,11 +337,6 @@ struct v4l2_subdev_sensor_ops { };/* -interrupt_service_routine: Called by the bridge chip's interrupt service -handler, when an IR interrupt status has be raised due to this subdev, -so that this subdev can handle the details. It may schedule work to be -performed later. It must not sleep. *Called from an IRQ context*. -[rt]x_g_parameters: Get the current operating parameters and state of the the IR receiver or transmitter.
@@ -392,10 +394,6 @@ struct v4l2_subdev_ir_parameters { };struct v4l2_subdev_ir_ops { -/* Common to receiver and transmitter */ -int (*interrupt_service_routine)(struct v4l2_subdev *sd, -u32 status,bool *handled); -/* Receiver */ int (*rx_read)(struct v4l2_subdev *sd,u8 *buf,size_t count,ssize_t *num);
Signature · 1 line
1.7.1.1
PATCH 12/17 cx25840: Add support for CX2388[57] A/V core integrated IR controllers
In reply to a message not in the archiveThis patch is primarily a port of the integrated IR controller code in cx23885/cx23888-ir.c. Right now, only the CX2388[57] AV core will really try to set up IR. This IR support, by design, still requires the bridge driver to do final IO pin mux configuration and setup of the IR controller parameters.
For the CX2388[578] chips, enabling the AV Core for IR also starts sending Audio and Video interrupts to the bridge driver. For CX2388[578] chips audio and video interrupts are ignored and acknowledged when they happen.
IR interrupt handling and status logging is exluded for the CX23888 which does not have an IR controller on the AV core.
Note that experimentation reveals that the IR irq enables on the CX23885 have an inverted logic sense. The CX23887 likely suffers from the same quirk. For these chips, those irq enable bits are handled as interrupt disables.
--- drivers/media/video/cx25840/Makefile | 2 +- drivers/media/video/cx25840/cx25840-core.c | 128 +++ drivers/media/video/cx25840/cx25840-core.h | 28 + drivers/media/video/cx25840/cx25840-ir.c | 1262 ++++++++++++++++++++++++++++ 4 files changed, 1419 insertions(+), 1 deletions(-) create mode 100644 drivers/media/video/cx25840/cx25840-ir.c
drivers/media/video/cx25840/Makefile +1 -1
@@ -1,5 +1,5 @@ cx25840-objs := cx25840-core.o cx25840-audio.o cx25840-firmware.o \ - cx25840-vbi.o + cx25840-vbi.o cx25840-ir.o obj-$(CONFIG_VIDEO_CX25840) += cx25840.o
drivers/media/video/cx25840/cx25840-core.c +128 -0
185 lines not on this page · raw message
drivers/media/video/cx25840/cx25840-core.h +28 -0
@@ -34,6 +34,8 @@providing this information. */ #define CX25840_CID_ENABLE_PVR150_WORKAROUND (V4L2_CID_PRIVATE_BASE+0) +struct cx25840_ir_state ; +struct cx25840_state {struct i2c_client *c;struct v4l2_subdev sd;
@@ -52,6 +54,7 @@ struct cx25840_state {int is_initialized;wait_queue_head_t fw_wait;/* wake up when the fw load is finished */ struct work_struct fw_work;/* work entry for fw load */ +struct cx25840_ir_state *ir_state; };static inline struct cx25840_state *to_state (struct v4l2_subdev *sd)
@@ -77,6 +80,21 @@ static inline bool is_cx2388x(struct cx25840_state *state) state->id ==V4L2_IDENT_CX23888_AV ; } +static inline bool is_cx23885 (struct cx25840_state *state) +{ +return state->id ==V4L2_IDENT_CX23885_AV ; +} + +static inline bool is_cx23887 (struct cx25840_state *state) +{ +return state->id ==V4L2_IDENT_CX23887_AV ; +} + +static inline bool is_cx23888 (struct cx25840_state *state) +{ +return state->id ==V4L2_IDENT_CX23888_AV ; +} +/* ----------------------------------------------------------------------- */ /* cx25850-core.c */ int cx25840_write (struct i2c_client *client,u16 addr,u8 value);
@@ -84,6 +102,8 @@ int cx25840_write4(struct i2c_client *client, u16 addr, u32 value);u8 cx25840_read (struct i2c_client *client,u16 addr);u32 cx25840_read4 (struct i2c_client *client,u16 addr);int cx25840_and_or (struct i2c_client *client,u16 addr,unsigned mask,u8 value); +int cx25840_and_or4 (struct i2c_client *client,u16 addr,u32 and_mask, +u32 or_value);void cx25840_std_setup (struct i2c_client *client);/* ----------------------------------------------------------------------- */
@@ -104,4 +124,12 @@ int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *int cx25840_g_sliced_fmt (struct v4l2_subdev *sd,struct v4l2_sliced_vbi_format *fmt);int cx25840_decode_vbi_line (struct v4l2_subdev *sd,struct v4l2_decode_vbi_line *vbi); +/* ----------------------------------------------------------------------- */ +/* cx25850-ir.c */ +extern const struct v4l2_subdev_ir_ops cx25840_ir_ops; +int cx25840_ir_log_status (struct v4l2_subdev *sd); +int cx25840_ir_irq_handler (struct v4l2_subdev *sd,u32 status,bool *handled); +int cx25840_ir_probe (struct v4l2_subdev *sd); +int cx25840_ir_remove (struct v4l2_subdev *sd); +#endif
drivers/media/video/cx25840/cx25840-ir.c new file +1262 -0
1,262 lines not on this page · raw message
Signature · 1 line
1.7.1.1
PATCH 13/17 cx23885: Add a v4l2_subdev group id for the CX2388[578] integrated AV core
In reply to a message not in the archive--- drivers/media/video/cx23885/cx23885-cards.c | 5 ++++- drivers/media/video/cx23885/cx23885.h | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-)
drivers/media/video/cx23885/cx23885-cards.c +4 -1
@@ -1152,7 +1152,10 @@ void cx23885_card_setup(struct cx23885_dev *dev) dev->sd_cx25840 =v4l2_i2c_new_subdev (&dev->v4l2_dev, &dev->i2c_bus[2 ].i2c_adap,"cx25840" ,"cx25840" ,0x88 >>1 ,NULL ); -v4l2_subdev_call (dev->sd_cx25840, core, load_fw); +if (dev->sd_cx25840) { + dev->sd_cx25840->grp_id =CX23885_HW_AV_CORE ; +v4l2_subdev_call (dev->sd_cx25840, core, load_fw); + }break ; }
drivers/media/video/cx23885/cx23885.h +2 -1
@@ -403,7 +403,8 @@ static inline struct cx23885_dev *to_cx23885(struct v4l2_device *v4l2_dev) #define call_all(dev, o, f, args...) \ v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args) -#define CX23885_HW_888_IR (1 << 0) +#define CX23885_HW_888_IR (1 << 0) +#define CX23885_HW_AV_CORE (1 << 1) #define call_hw(dev, grpid, o, f, args...) \ v4l2_device_call_all(&dev->v4l2_dev, grpid, o, f, ##args)
Signature · 1 line
1.7.1.1
PATCH 14/17 cx23885: Add preliminary IR Rx support for the HVR-1250 and TeVii S470
In reply to a message not in the archiveAdd initial IR Rx support using the intergrated IR controller in the A/V core of the CX23885 bridge chip.
This initial support is flawed in that I2C transactions should not be performed in a hard irq context. That will be fixed in a follow on patch.
The TeVii S470 support is reported to generate perptual interrupts that renders a user' system nearly unusable. The TeVii S470 IR will be disabled by default in a follow on patch.
--- drivers/media/video/cx23885/cx23885-cards.c | 52 ++++++++++++++++++++++++-- drivers/media/video/cx23885/cx23885-core.c | 22 +++++++++-- drivers/media/video/cx23885/cx23885-input.c | 46 ++++++++++++++++++++++- drivers/media/video/cx23885/cx23885-reg.h | 1 + 4 files changed, 111 insertions(+), 10 deletions(-)
drivers/media/video/cx23885/cx23885-cards.c +48 -4
@@ -922,7 +922,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)int cx23885_ir_init (struct cx23885_dev *dev) { -static struct v4l2_subdev_io_pin_config ir_pin_cfg[] = { +static struct v4l2_subdev_io_pin_config ir_rxtx_pin_cfg[] = { { .flags =V4L2_SUBDEV_IO_PIN_INPUT , .pin =CX23885_PIN_IR_RX_GPIO19 ,
@@ -937,12 +937,22 @@ int cx23885_ir_init(struct cx23885_dev *dev) .strength = CX25840_PIN_DRIVE_MEDIUM, } }; -const size_t ir_pin_cfg_count =ARRAY_SIZE (ir_pin_cfg); +const size_t ir_rxtx_pin_cfg_count =ARRAY_SIZE (ir_rxtx_pin_cfg); + +static struct v4l2_subdev_io_pin_config ir_rx_pin_cfg[] = { + { + .flags =V4L2_SUBDEV_IO_PIN_INPUT , + .pin =CX23885_PIN_IR_RX_GPIO19 , + .function =CX23885_PAD_IR_RX , + .value =0 , + .strength =CX25840_PIN_DRIVE_MEDIUM , + } + }; +const size_t ir_rx_pin_cfg_count =ARRAY_SIZE (ir_rx_pin_cfg);struct v4l2_subdev_ir_parameters params;int ret =0 ;switch (dev->board) { -case CX23885_BOARD_HAUPPAUGE_HVR1250 :case CX23885_BOARD_HAUPPAUGE_HVR1500 :case CX23885_BOARD_HAUPPAUGE_HVR1500Q :case CX23885_BOARD_HAUPPAUGE_HVR1800 :
@@ -961,7 +971,7 @@ int cx23885_ir_init(struct cx23885_dev *dev)break ; dev->sd_ir =cx23885_find_hw (dev,CX23885_HW_888_IR );v4l2_subdev_call (dev->sd_cx25840, core, s_io_pin_config, - ir_pin_cfg_count, ir_pin_cfg); + ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg); dev->pci_irqmask |=PCI_MSK_IR ;/* * For these boards we need to invert the Tx output via the
@@ -975,6 +985,26 @@ int cx23885_ir_init(struct cx23885_dev *dev) params.shutdown = true;v4l2_subdev_call (dev->sd_ir, ir, tx_s_parameters, ¶ms);break ; +case CX23885_BOARD_TEVII_S470 : + dev->sd_ir =cx23885_find_hw (dev,CX23885_HW_AV_CORE ); +if (dev->sd_ir ==NULL ) { + ret = -ENODEV ; +break ; + } +v4l2_subdev_call (dev->sd_cx25840, core, s_io_pin_config, + ir_rx_pin_cfg_count, ir_rx_pin_cfg); + dev->pci_irqmask |=PCI_MSK_AV_CORE ; +break ; +case CX23885_BOARD_HAUPPAUGE_HVR1250 : + dev->sd_ir =cx23885_find_hw (dev,CX23885_HW_AV_CORE ); +if (dev->sd_ir ==NULL ) { + ret = -ENODEV ; +break ; + } +v4l2_subdev_call (dev->sd_cx25840, core, s_io_pin_config, + ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg); + dev->pci_irqmask |=PCI_MSK_AV_CORE ; +break ;case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP :request_module ("ir-kbd-i2c" );break ;
@@ -993,6 +1023,13 @@ void cx23885_ir_fini(struct cx23885_dev *dev)cx23888_ir_remove (dev); dev->sd_ir =NULL ;break ; +case CX23885_BOARD_TEVII_S470 : +case CX23885_BOARD_HAUPPAUGE_HVR1250 : + dev->pci_irqmask &= ~PCI_MSK_AV_CORE ; +cx_clear (PCI_INT_MSK ,PCI_MSK_AV_CORE ); +/* sd_ir is a duplicate pointer to the AV Core, just clear it */ + dev->sd_ir =NULL ; +break ; } }
@@ -1004,6 +1041,11 @@ void cx23885_ir_pci_int_enable(struct cx23885_dev *dev)if (dev->sd_ir && (dev->pci_irqmask &PCI_MSK_IR ))cx_set (PCI_INT_MSK ,PCI_MSK_IR );break ; +case CX23885_BOARD_TEVII_S470 : +case CX23885_BOARD_HAUPPAUGE_HVR1250 : +if (dev->sd_ir && (dev->pci_irqmask &PCI_MSK_AV_CORE )) +cx_set (PCI_INT_MSK ,PCI_MSK_AV_CORE ); +break ; } }
@@ -1149,6 +1191,8 @@ void cx23885_card_setup(struct cx23885_dev *dev)case CX23885_BOARD_MAGICPRO_PROHDTVE2 :case CX23885_BOARD_HAUPPAUGE_HVR1290 :case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200 : +case CX23885_BOARD_TEVII_S470 : +case CX23885_BOARD_HAUPPAUGE_HVR1250 : dev->sd_cx25840 =v4l2_i2c_new_subdev (&dev->v4l2_dev, &dev->i2c_bus[2 ].i2c_adap,"cx25840" ,"cx25840" ,0x88 >>1 ,NULL );
drivers/media/video/cx23885/cx23885-core.c +18 -4
@@ -1650,7 +1650,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; +bool subdev_handled; pci_status =cx_read (PCI_INT_STAT ); pci_mask =cx_read (PCI_INT_MSK );
@@ -1681,7 +1681,7 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) 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)) { + PCI_MSK_AV_CORE | PCI_MSK_IR)) {if (pci_status &PCI_MSK_RISC_RD ) dprintk(7, " (PCI_MSK_RISC_RD 0x%08x)\n",
@@ -1731,6 +1731,10 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)dprintk (7 ," (PCI_MSK_GPIO1 0x%08x)\n" ,PCI_MSK_GPIO1 ); +if (pci_status &PCI_MSK_AV_CORE ) +dprintk (7 ," (PCI_MSK_AV_CORE 0x%08x)\n" , +PCI_MSK_AV_CORE ); +if (pci_status &PCI_MSK_IR )dprintk (7 ," (PCI_MSK_IR 0x%08x)\n" ,PCI_MSK_IR );
@@ -1765,9 +1769,19 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) handled +=cx23885_video_irq (dev, vida_status);if (pci_status &PCI_MSK_IR ) { + subdev_handled = false;v4l2_subdev_call (dev->sd_ir, core, interrupt_service_routine, - pci_status, &ir_handled); -if (ir_handled) + pci_status, &subdev_handled); +if (subdev_handled) + handled++; + } + +if (pci_status &PCI_MSK_AV_CORE ) { + subdev_handled = false; +v4l2_subdev_call (dev->sd_cx25840, + core, interrupt_service_routine, + pci_status, &subdev_handled); +if (subdev_handled) handled++; }
drivers/media/video/cx23885/cx23885-input.c +44 -2
76 lines not on this page · raw message
drivers/media/video/cx23885/cx23885-reg.h +1 -0
@@ -213,6 +213,7 @@ Channel manager Data Structure entry = 20 DWORD#define DEV_CNTRL2 0x00040000#define PCI_MSK_IR (1 << 28) +#define PCI_MSK_AV_CORE (1 << 27)#define PCI_MSK_GPIO1 (1 << 24)#define PCI_MSK_GPIO0 (1 << 23)#define PCI_MSK_APB_DMA (1 << 12)
Signature · 1 line
1.7.1.1
PATCH 15/17 cx23885: Protect PCI interrupt mask manipulations with a spinlock
In reply to a message not in the archiveThis patch encapsulates access to the PCI_INT_MSK register and dev->pci_irqmask variable and protects them with a spinlock. This is needed because both the hard IRQ handler and a workhandler will need to manipulate the mask to disable the AV_CORE interrupt.
--- drivers/media/video/cx23885/cx23885-cards.c | 17 ++--- drivers/media/video/cx23885/cx23885-core.c | 94 +++++++++++++++++++++++++-- drivers/media/video/cx23885/cx23885-vbi.c | 2 +- drivers/media/video/cx23885/cx23885-video.c | 7 +- drivers/media/video/cx23885/cx23885.h | 5 ++ 5 files changed, 103 insertions(+), 22 deletions(-)
drivers/media/video/cx23885/cx23885-cards.c +6 -11
@@ -972,7 +972,6 @@ int cx23885_ir_init(struct cx23885_dev *dev) dev->sd_ir =cx23885_find_hw (dev,CX23885_HW_888_IR );v4l2_subdev_call (dev->sd_cx25840, core, s_io_pin_config, ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg); - dev->pci_irqmask |=PCI_MSK_IR ;/* * For these boards we need to invert the Tx output via the * IR controller to have the LED off while idle
@@ -993,7 +992,6 @@ int cx23885_ir_init(struct cx23885_dev *dev) }v4l2_subdev_call (dev->sd_cx25840, core, s_io_pin_config, ir_rx_pin_cfg_count, ir_rx_pin_cfg); - dev->pci_irqmask |=PCI_MSK_AV_CORE ;break ;case CX23885_BOARD_HAUPPAUGE_HVR1250 : dev->sd_ir =cx23885_find_hw (dev,CX23885_HW_AV_CORE );
@@ -1003,7 +1001,6 @@ int cx23885_ir_init(struct cx23885_dev *dev) }v4l2_subdev_call (dev->sd_cx25840, core, s_io_pin_config, ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg); - dev->pci_irqmask |=PCI_MSK_AV_CORE ;break ;case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP :request_module ("ir-kbd-i2c" );
@@ -1018,15 +1015,13 @@ void cx23885_ir_fini(struct cx23885_dev *dev)switch (dev->board) {case CX23885_BOARD_HAUPPAUGE_HVR1850 :case CX23885_BOARD_HAUPPAUGE_HVR1290 : - dev->pci_irqmask &= ~PCI_MSK_IR ; -cx_clear (PCI_INT_MSK ,PCI_MSK_IR ); +cx23885_irq_remove (dev,PCI_MSK_IR );cx23888_ir_remove (dev); dev->sd_ir =NULL ;break ;case CX23885_BOARD_TEVII_S470 :case CX23885_BOARD_HAUPPAUGE_HVR1250 : - dev->pci_irqmask &= ~PCI_MSK_AV_CORE ; -cx_clear (PCI_INT_MSK ,PCI_MSK_AV_CORE ); +cx23885_irq_remove (dev,PCI_MSK_AV_CORE );/* sd_ir is a duplicate pointer to the AV Core, just clear it */ dev->sd_ir =NULL ;break ;
@@ -1038,13 +1033,13 @@ void cx23885_ir_pci_int_enable(struct cx23885_dev *dev)switch (dev->board) {case CX23885_BOARD_HAUPPAUGE_HVR1850 :case CX23885_BOARD_HAUPPAUGE_HVR1290 : -if (dev->sd_ir && (dev->pci_irqmask &PCI_MSK_IR )) -cx_set (PCI_INT_MSK ,PCI_MSK_IR ); +if (dev->sd_ir) +cx23885_irq_add_enable (dev,PCI_MSK_IR );break ;case CX23885_BOARD_TEVII_S470 :case CX23885_BOARD_HAUPPAUGE_HVR1250 : -if (dev->sd_ir && (dev->pci_irqmask &PCI_MSK_AV_CORE )) -cx_set (PCI_INT_MSK ,PCI_MSK_AV_CORE ); +if (dev->sd_ir) +cx23885_irq_add_enable (dev,PCI_MSK_AV_CORE );break ; } }
drivers/media/video/cx23885/cx23885-core.c +87 -7
143 lines not on this page · raw message
drivers/media/video/cx23885/cx23885-vbi.c +1 -1
@@ -74,7 +74,7 @@ static int cx23885_start_vbi_dma(struct cx23885_dev *dev, q->count =1 ;/* enable irqs */ -cx_set (PCI_INT_MSK ,cx_read (PCI_INT_MSK ) |0x01 ); +cx23885_irq_add_enable (dev,0x01 );cx_set (VID_A_INT_MSK ,0x000022 );/* start dma */
drivers/media/video/cx23885/cx23885-video.c +4 -3
@@ -441,7 +441,7 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev, q->count =1 ;/* enable irq */ -cx_set (PCI_INT_MSK ,cx_read (PCI_INT_MSK ) |0x01 ); +cx23885_irq_add_enable (dev,0x01 );cx_set (VID_A_INT_MSK ,0x000011 );/* start dma */
@@ -1465,7 +1465,7 @@ static const struct v4l2_file_operations radio_fops = {void cx23885_video_unregister (struct cx23885_dev *dev) {dprintk (1 ,"%s()\n" , __func__); -cx_clear (PCI_INT_MSK ,1 ); +cx23885_irq_remove (dev,0x01 );if (dev->video_dev) {if (video_is_registered (dev->video_dev))
@@ -1502,7 +1502,8 @@ int cx23885_video_register(struct cx23885_dev *dev) VID_A_DMA_CTL, 0x11, 0x00);/* Don't enable VBI yet */ -cx_set (PCI_INT_MSK ,1 ); + +cx23885_irq_add_enable (dev,0x01 );if (TUNER_ABSENT != dev->tuner_type) {struct v4l2_subdev *sd =NULL ;
drivers/media/video/cx23885/cx23885.h +5 -0
@@ -325,6 +325,7 @@ struct cx23885_dev {u32 __iomem *lmmio;u8 __iomem *bmmio;int pci_irqmask; +spinlock_t pci_irqmask_lock;/* protects mask reg too */ int hwrevision;/* This valud is board specific and is used to configure the
@@ -485,6 +486,10 @@ extern u32 cx23885_gpio_get(struct cx23885_dev *dev, u32 mask);extern void cx23885_gpio_enable (struct cx23885_dev *dev,u32 mask,int asoutput); +extern void cx23885_irq_add_enable (struct cx23885_dev *dev,u32 mask); +extern void cx23885_irq_enable (struct cx23885_dev *dev,u32 mask); +extern void cx23885_irq_disable (struct cx23885_dev *dev,u32 mask); +extern void cx23885_irq_remove (struct cx23885_dev *dev,u32 mask);/* ----------------------------------------------------------- */ /* cx23885-cards.c */
Signature · 1 line
1.7.1.1
PATCH 16/17 cx23885: Move AV Core irq handling to a work handler
In reply to a message not in the archiveInterrupts from the AV Core are best handled by a workqueue handler since many I2C transactions are required to service the AV Core interrupt. The AV_CORE PCI interrupt is disabled by the IRQ handler and reenabled when the work handler is finished.
--- drivers/media/video/cx23885/Makefile | 5 ++- drivers/media/video/cx23885/cx23885-av.c | 35 ++++++++++++++++++++++++++++ drivers/media/video/cx23885/cx23885-av.h | 27 +++++++++++++++++++++ drivers/media/video/cx23885/cx23885-core.c | 20 ++++++++------- drivers/media/video/cx23885/cx23885-ir.c | 24 ++++++++++++++++--- drivers/media/video/cx23885/cx23885.h | 1 + 6 files changed, 97 insertions(+), 15 deletions(-) create mode 100644 drivers/media/video/cx23885/cx23885-av.c create mode 100644 drivers/media/video/cx23885/cx23885-av.h
drivers/media/video/cx23885/Makefile +3 -2
@@ -1,7 +1,8 @@ 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 cx23885-ir.o cx23885-input.o cx23888-ir.o \ - netup-init.o cimax2.o netup-eeprom.o cx23885-f300.o + cx23885-ioctl.o cx23885-ir.o cx23885-av.o cx23885-input.o \ + cx23888-ir.o netup-init.o cimax2.o netup-eeprom.o \ + cx23885-f300.o obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
drivers/media/video/cx23885/cx23885-av.c new file +35 -0
@@ -0,0 +1,35 @@ +/* +* Driver for the Conexant CX23885/7/8 PCIe bridge +* +* AV device support routines - non-input, non-vl42_subdev routines +* +* Copyright (C) 2010 Andy Walls <[email protected]> +* +* 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 "cx23885.h" + +void cx23885_av_work_handler (struct work_struct *work) +{ +struct cx23885_dev *dev = + container_of(work, struct cx23885_dev, cx25840_work); +bool handled; + +v4l2_subdev_call (dev->sd_cx25840, core, interrupt_service_routine, +PCI_MSK_AV_CORE , &handled); +cx23885_irq_enable (dev,PCI_MSK_AV_CORE ); +}
drivers/media/video/cx23885/cx23885-av.h new file +27 -0
@@ -0,0 +1,27 @@ +/* +* Driver for the Conexant CX23885/7/8 PCIe bridge +* +* AV device support routines - non-input, non-vl42_subdev routines +* +* Copyright (C) 2010 Andy Walls <[email protected]> +* +* 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_AV_H_ +#define _CX23885_AV_H_ +void cx23885_av_work_handler (struct work_struct *work); +#endif
drivers/media/video/cx23885/cx23885-core.c +11 -9
@@ -34,6 +34,7 @@#include "cimax2.h" #include "cx23888-ir.h" #include "cx23885-ir.h" +#include "cx23885-av.h" #include "cx23885-input.h" MODULE_DESCRIPTION ("Driver for cx23885 based TV cards" );
@@ -1856,13 +1857,13 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) handled++; } -if (pci_status &PCI_MSK_AV_CORE ) { - subdev_handled = false; -v4l2_subdev_call (dev->sd_cx25840, - core, interrupt_service_routine, - pci_status, &subdev_handled); -if (subdev_handled) - handled++; +if ((pci_status & pci_mask) &PCI_MSK_AV_CORE ) { +cx23885_irq_disable (dev,PCI_MSK_AV_CORE ); +if (!schedule_work (&dev->cx25840_work)) +printk (KERN_ERR "%s: failed to set up deferred work for" +" AV Core/IR interrupt. Interrupt is disabled" +" and won't be re-enabled\n" , dev->name); + handled++; }if (handled)
@@ -1882,11 +1883,11 @@ static void cx23885_v4l2_dev_notify(struct v4l2_subdev *sd, dev =to_cx23885 (sd->v4l2_dev);switch (notification) { -case V4L2_SUBDEV_IR_RX_NOTIFY :/* Called in an IRQ context */ +case V4L2_SUBDEV_IR_RX_NOTIFY :/* Possibly 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 */ +case V4L2_SUBDEV_IR_TX_NOTIFY :/* Possibly called in an IRQ context */ if (sd == dev->sd_ir)cx23885_ir_tx_v4l2_dev_notify (sd, *(u32 *)arg);break ;
@@ -1895,6 +1896,7 @@ static void cx23885_v4l2_dev_notify(struct v4l2_subdev *sd,static void cx23885_v4l2_dev_notify_init (struct cx23885_dev *dev) { +INIT_WORK (&dev->cx25840_work, cx23885_av_work_handler);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;
drivers/media/video/cx23885/cx23885-ir.c +20 -4
@@ -72,7 +72,7 @@ void cx23885_ir_tx_work_handler(struct work_struct *work) } -/* Called in an IRQ context */ +/* Possibly 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);
@@ -86,10 +86,18 @@ void cx23885_ir_rx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events)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); + +/* +* For the integrated AV core, we are already in a workqueue context. +* For the CX23888 integrated IR, we are in an interrupt context. +*/ +if (sd == dev->sd_cx25840) +cx23885_ir_rx_work_handler (&dev->ir_rx_work); +else +schedule_work (&dev->ir_rx_work); } -/* Called in an IRQ context */ +/* Possibly 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);
@@ -97,5 +105,13 @@ void cx23885_ir_tx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events)if (events &V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ )set_bit (CX23885_IR_TX_FIFO_SERVICE_REQ , notifications); -schedule_work (&dev->ir_tx_work); + +/* +* For the integrated AV core, we are already in a workqueue context. +* For the CX23888 integrated IR, we are in an interrupt context. +*/ +if (sd == dev->sd_cx25840) +cx23885_ir_tx_work_handler (&dev->ir_tx_work); +else +schedule_work (&dev->ir_tx_work); }
drivers/media/video/cx23885/cx23885.h +1 -0
@@ -366,6 +366,7 @@ struct cx23885_dev {unsigned char radio_addr;unsigned int has_radio;struct v4l2_subdev *sd_cx25840; +struct work_struct cx25840_work;/* Infrared */ struct v4l2_subdev *sd_ir;
Signature · 1 line
1.7.1.1
PATCH 17/17 cx23885: Require user to explicitly enable CX2388[57] IR via module param
In reply to a message not in the archiveThe CX23885 IR controller was reported to cause an interrupt storm on a TeVii S470 card, but was reported fine on an HVR-1250. Keep integrated IR disabled by default on CX2388[57] based cards to avoid a bad user experience in the general case.
--- drivers/media/video/cx23885/cx23885-cards.c | 21 +++++++++++++++++++-- 1 files changed, 19 insertions(+), 2 deletions(-)
drivers/media/video/cx23885/cx23885-cards.c +19 -2
@@ -30,6 +30,16 @@#include "netup-init.h" #include "cx23888-ir.h" +static unsigned int enable_885_ir; +module_param (enable_885_ir, int,0644 ); +MODULE_PARM_DESC (enable_885_ir, +"Enable integrated IR controller for supported\n" +"\t\t CX2388[57] boards that are wired for it:\n" +"\t\t\tHVR-1250 (reported safe)\n" +"\t\t\tTeVii S470 (reported unsafe)\n" +"\t\t This can cause an interrupt storm with some cards.\n" +"\t\t Default: 0 [Disabled]" ); +/* ------------------------------------------------------------------ */ /* board config info */
@@ -985,6 +995,8 @@ int cx23885_ir_init(struct cx23885_dev *dev)v4l2_subdev_call (dev->sd_ir, ir, tx_s_parameters, ¶ms);break ;case CX23885_BOARD_TEVII_S470 : +if (!enable_885_ir) +break ; dev->sd_ir =cx23885_find_hw (dev,CX23885_HW_AV_CORE );if (dev->sd_ir ==NULL ) { ret = -ENODEV ;
@@ -994,6 +1006,8 @@ int cx23885_ir_init(struct cx23885_dev *dev) ir_rx_pin_cfg_count, ir_rx_pin_cfg);break ;case CX23885_BOARD_HAUPPAUGE_HVR1250 : +if (!enable_885_ir) +break ; dev->sd_ir =cx23885_find_hw (dev,CX23885_HW_AV_CORE );if (dev->sd_ir ==NULL ) { ret = -ENODEV ;
@@ -1174,6 +1188,11 @@ void cx23885_card_setup(struct cx23885_dev *dev)* loaded, ensure this happens. */ switch (dev->board) { +case CX23885_BOARD_TEVII_S470 : +case CX23885_BOARD_HAUPPAUGE_HVR1250 : +/* Currently only enabled for the integrated IR controller */ +if (!enable_885_ir) +break ;case CX23885_BOARD_HAUPPAUGE_HVR1800 :case CX23885_BOARD_HAUPPAUGE_HVR1800lp:case CX23885_BOARD_HAUPPAUGE_HVR1700 :
@@ -1186,8 +1205,6 @@ void cx23885_card_setup(struct cx23885_dev *dev)case CX23885_BOARD_MAGICPRO_PROHDTVE2 :case CX23885_BOARD_HAUPPAUGE_HVR1290 :case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200 : -case CX23885_BOARD_TEVII_S470 : -case CX23885_BOARD_HAUPPAUGE_HVR1250 : dev->sd_cx25840 =v4l2_i2c_new_subdev (&dev->v4l2_dev, &dev->i2c_bus[2 ].i2c_adap,"cx25840" ,"cx25840" ,0x88 >>1 ,NULL );
Signature · 1 line
1.7.1.1