Commit 64fbf444 authored by Palash Bandyopadhyay's avatar Palash Bandyopadhyay Committed by Mauro Carvalho Chehab

[media] cx231xx: Added support for Carraera, Shelby, RDx_253S and VIDEO_GRABBER

Added support for new cx231xx boards - Carraera, Shelby, RDx_253S and
VIDEO_GRABBER.

[mchehab@redhat.com: Fix a merge conflict with BKL removal patches]
Signed-off-by: default avatarPalash Bandyopadhyay <palash.bandyopadhyay@conexant.com>
Signed-off-by: default avatarDevin Heitmueller <dheitmueller@hauppauge.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 47b75ec1
cx231xx-objs := cx231xx-video.o cx231xx-i2c.o cx231xx-cards.o cx231xx-core.o \ cx231xx-objs := cx231xx-video.o cx231xx-i2c.o cx231xx-cards.o cx231xx-core.o \
cx231xx-avcore.o cx231xx-pcb-cfg.o cx231xx-vbi.o cx231xx-avcore.o cx231xx-417.o cx231xx-pcb-cfg.o cx231xx-vbi.o
cx231xx-alsa-objs := cx231xx-audio.o cx231xx-alsa-objs := cx231xx-audio.o
......
This diff is collapsed.
...@@ -75,6 +75,30 @@ static int cx231xx_isoc_audio_deinit(struct cx231xx *dev) ...@@ -75,6 +75,30 @@ static int cx231xx_isoc_audio_deinit(struct cx231xx *dev)
return 0; return 0;
} }
static int cx231xx_bulk_audio_deinit(struct cx231xx *dev)
{
int i;
dprintk("Stopping bulk\n");
for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
if (dev->adev.urb[i]) {
if (!irqs_disabled())
usb_kill_urb(dev->adev.urb[i]);
else
usb_unlink_urb(dev->adev.urb[i]);
usb_free_urb(dev->adev.urb[i]);
dev->adev.urb[i] = NULL;
kfree(dev->adev.transfer_buffer[i]);
dev->adev.transfer_buffer[i] = NULL;
}
}
return 0;
}
static void cx231xx_audio_isocirq(struct urb *urb) static void cx231xx_audio_isocirq(struct urb *urb)
{ {
struct cx231xx *dev = urb->context; struct cx231xx *dev = urb->context;
...@@ -158,14 +182,92 @@ static void cx231xx_audio_isocirq(struct urb *urb) ...@@ -158,14 +182,92 @@ static void cx231xx_audio_isocirq(struct urb *urb)
return; return;
} }
static void cx231xx_audio_bulkirq(struct urb *urb)
{
struct cx231xx *dev = urb->context;
unsigned int oldptr;
int period_elapsed = 0;
int status;
unsigned char *cp;
unsigned int stride;
struct snd_pcm_substream *substream;
struct snd_pcm_runtime *runtime;
switch (urb->status) {
case 0: /* success */
case -ETIMEDOUT: /* NAK */
break;
case -ECONNRESET: /* kill */
case -ENOENT:
case -ESHUTDOWN:
return;
default: /* error */
dprintk("urb completition error %d.\n", urb->status);
break;
}
if (dev->adev.capture_pcm_substream) {
substream = dev->adev.capture_pcm_substream;
runtime = substream->runtime;
stride = runtime->frame_bits >> 3;
if (1) {
int length = urb->actual_length /
stride;
cp = (unsigned char *)urb->transfer_buffer;
oldptr = dev->adev.hwptr_done_capture;
if (oldptr + length >= runtime->buffer_size) {
unsigned int cnt;
cnt = runtime->buffer_size - oldptr;
memcpy(runtime->dma_area + oldptr * stride, cp,
cnt * stride);
memcpy(runtime->dma_area, cp + cnt * stride,
length * stride - cnt * stride);
} else {
memcpy(runtime->dma_area + oldptr * stride, cp,
length * stride);
}
snd_pcm_stream_lock(substream);
dev->adev.hwptr_done_capture += length;
if (dev->adev.hwptr_done_capture >=
runtime->buffer_size)
dev->adev.hwptr_done_capture -=
runtime->buffer_size;
dev->adev.capture_transfer_done += length;
if (dev->adev.capture_transfer_done >=
runtime->period_size) {
dev->adev.capture_transfer_done -=
runtime->period_size;
period_elapsed = 1;
}
snd_pcm_stream_unlock(substream);
}
if (period_elapsed)
snd_pcm_period_elapsed(substream);
}
urb->status = 0;
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status < 0) {
cx231xx_errdev("resubmit of audio urb failed (error=%i)\n",
status);
}
return;
}
static int cx231xx_init_audio_isoc(struct cx231xx *dev) static int cx231xx_init_audio_isoc(struct cx231xx *dev)
{ {
int i, errCode; int i, errCode;
int sb_size; int sb_size;
cx231xx_info("%s: Starting AUDIO transfers\n", __func__); cx231xx_info("%s: Starting ISO AUDIO transfers\n", __func__);
sb_size = CX231XX_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size; sb_size = CX231XX_ISO_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size;
for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
struct urb *urb; struct urb *urb;
...@@ -176,7 +278,7 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev) ...@@ -176,7 +278,7 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev)
return -ENOMEM; return -ENOMEM;
memset(dev->adev.transfer_buffer[i], 0x80, sb_size); memset(dev->adev.transfer_buffer[i], 0x80, sb_size);
urb = usb_alloc_urb(CX231XX_NUM_AUDIO_PACKETS, GFP_ATOMIC); urb = usb_alloc_urb(CX231XX_ISO_NUM_AUDIO_PACKETS, GFP_ATOMIC);
if (!urb) { if (!urb) {
cx231xx_errdev("usb_alloc_urb failed!\n"); cx231xx_errdev("usb_alloc_urb failed!\n");
for (j = 0; j < i; j++) { for (j = 0; j < i; j++) {
...@@ -194,10 +296,10 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev) ...@@ -194,10 +296,10 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev)
urb->transfer_buffer = dev->adev.transfer_buffer[i]; urb->transfer_buffer = dev->adev.transfer_buffer[i];
urb->interval = 1; urb->interval = 1;
urb->complete = cx231xx_audio_isocirq; urb->complete = cx231xx_audio_isocirq;
urb->number_of_packets = CX231XX_NUM_AUDIO_PACKETS; urb->number_of_packets = CX231XX_ISO_NUM_AUDIO_PACKETS;
urb->transfer_buffer_length = sb_size; urb->transfer_buffer_length = sb_size;
for (j = k = 0; j < CX231XX_NUM_AUDIO_PACKETS; for (j = k = 0; j < CX231XX_ISO_NUM_AUDIO_PACKETS;
j++, k += dev->adev.max_pkt_size) { j++, k += dev->adev.max_pkt_size) {
urb->iso_frame_desc[j].offset = k; urb->iso_frame_desc[j].offset = k;
urb->iso_frame_desc[j].length = dev->adev.max_pkt_size; urb->iso_frame_desc[j].length = dev->adev.max_pkt_size;
...@@ -216,6 +318,59 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev) ...@@ -216,6 +318,59 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev)
return errCode; return errCode;
} }
static int cx231xx_init_audio_bulk(struct cx231xx *dev)
{
int i, errCode;
int sb_size;
cx231xx_info("%s: Starting BULK AUDIO transfers\n", __func__);
sb_size = CX231XX_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size;
for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
struct urb *urb;
int j;
dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC);
if (!dev->adev.transfer_buffer[i])
return -ENOMEM;
memset(dev->adev.transfer_buffer[i], 0x80, sb_size);
urb = usb_alloc_urb(CX231XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
if (!urb) {
cx231xx_errdev("usb_alloc_urb failed!\n");
for (j = 0; j < i; j++) {
usb_free_urb(dev->adev.urb[j]);
kfree(dev->adev.transfer_buffer[j]);
}
return -ENOMEM;
}
urb->dev = dev->udev;
urb->context = dev;
urb->pipe = usb_rcvbulkpipe(dev->udev,
dev->adev.end_point_addr);
urb->transfer_flags = 0;
urb->transfer_buffer = dev->adev.transfer_buffer[i];
urb->complete = cx231xx_audio_bulkirq;
urb->transfer_buffer_length = sb_size;
dev->adev.urb[i] = urb;
}
for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
if (errCode < 0) {
cx231xx_bulk_audio_deinit(dev);
return errCode;
}
}
return errCode;
}
static int cx231xx_cmd(struct cx231xx *dev, int cmd, int arg) static int cx231xx_cmd(struct cx231xx *dev, int cmd, int arg)
{ {
dprintk("%s transfer\n", (dev->adev.capture_stream == STREAM_ON) ? dprintk("%s transfer\n", (dev->adev.capture_stream == STREAM_ON) ?
...@@ -225,7 +380,12 @@ static int cx231xx_cmd(struct cx231xx *dev, int cmd, int arg) ...@@ -225,7 +380,12 @@ static int cx231xx_cmd(struct cx231xx *dev, int cmd, int arg)
case CX231XX_CAPTURE_STREAM_EN: case CX231XX_CAPTURE_STREAM_EN:
if (dev->adev.capture_stream == STREAM_OFF && arg == 1) { if (dev->adev.capture_stream == STREAM_OFF && arg == 1) {
dev->adev.capture_stream = STREAM_ON; dev->adev.capture_stream = STREAM_ON;
cx231xx_init_audio_isoc(dev); if (is_fw_load(dev) == 0)
cx25840_call(dev, core, load_fw);
if (dev->USE_ISO)
cx231xx_init_audio_isoc(dev);
else
cx231xx_init_audio_bulk(dev);
} else if (dev->adev.capture_stream == STREAM_ON && arg == 0) { } else if (dev->adev.capture_stream == STREAM_ON && arg == 0) {
dev->adev.capture_stream = STREAM_OFF; dev->adev.capture_stream = STREAM_OFF;
cx231xx_isoc_audio_deinit(dev); cx231xx_isoc_audio_deinit(dev);
...@@ -300,7 +460,10 @@ static int snd_cx231xx_capture_open(struct snd_pcm_substream *substream) ...@@ -300,7 +460,10 @@ static int snd_cx231xx_capture_open(struct snd_pcm_substream *substream)
/* set alternate setting for audio interface */ /* set alternate setting for audio interface */
/* 1 - 48000 samples per sec */ /* 1 - 48000 samples per sec */
ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 1); if (dev->USE_ISO)
ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 1);
else
ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0);
if (ret < 0) { if (ret < 0) {
cx231xx_errdev("failed to set alternate setting !\n"); cx231xx_errdev("failed to set alternate setting !\n");
...@@ -330,6 +493,9 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream) ...@@ -330,6 +493,9 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream)
dprintk("closing device\n"); dprintk("closing device\n");
/* inform hardware to start streaming */
ret = cx231xx_capture_start(dev, 0, Audio);
/* set alternate setting for audio interface */ /* set alternate setting for audio interface */
/* 1 - 48000 samples per sec */ /* 1 - 48000 samples per sec */
ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0); ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0);
...@@ -339,9 +505,6 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream) ...@@ -339,9 +505,6 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream)
return ret; return ret;
} }
/* inform hardware to start streaming */
ret = cx231xx_capture_start(dev, 0, Audio);
dev->mute = 1; dev->mute = 1;
mutex_lock(&dev->lock); mutex_lock(&dev->lock);
dev->adev.users--; dev->adev.users--;
...@@ -391,6 +554,11 @@ static int snd_cx231xx_hw_capture_free(struct snd_pcm_substream *substream) ...@@ -391,6 +554,11 @@ static int snd_cx231xx_hw_capture_free(struct snd_pcm_substream *substream)
static int snd_cx231xx_prepare(struct snd_pcm_substream *substream) static int snd_cx231xx_prepare(struct snd_pcm_substream *substream)
{ {
struct cx231xx *dev = snd_pcm_substream_chip(substream);
dev->adev.hwptr_done_capture = 0;
dev->adev.capture_transfer_done = 0;
return 0; return 0;
} }
...@@ -495,6 +663,7 @@ static int cx231xx_audio_init(struct cx231xx *dev) ...@@ -495,6 +663,7 @@ static int cx231xx_audio_init(struct cx231xx *dev)
pcm->info_flags = 0; pcm->info_flags = 0;
pcm->private_data = dev; pcm->private_data = dev;
strcpy(pcm->name, "Conexant cx231xx Capture"); strcpy(pcm->name, "Conexant cx231xx Capture");
snd_card_set_dev(card, &dev->udev->dev);
strcpy(card->driver, "Cx231xx-Audio"); strcpy(card->driver, "Cx231xx-Audio");
strcpy(card->shortname, "Cx231xx Audio"); strcpy(card->shortname, "Cx231xx Audio");
strcpy(card->longname, "Conexant cx231xx Audio"); strcpy(card->longname, "Conexant cx231xx Audio");
......
This diff is collapsed.
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#define CIR_CAR_REG 0x38 #define CIR_CAR_REG 0x38
#define CIR_OT_CFG1 0x40 #define CIR_OT_CFG1 0x40
#define CIR_OT_CFG2 0x44 #define CIR_OT_CFG2 0x44
#define GBULK_BIT_EN 0x68
#define PWR_CTL_EN 0x74 #define PWR_CTL_EN 0x74
/* Polaris Endpoints capture mask for register EP_MODE_SET */ /* Polaris Endpoints capture mask for register EP_MODE_SET */
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -359,7 +359,7 @@ static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap, ...@@ -359,7 +359,7 @@ static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap,
if (num <= 0) if (num <= 0)
return 0; return 0;
mutex_lock(&dev->i2c_lock);
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
addr = msgs[i].addr >> 1; addr = msgs[i].addr >> 1;
...@@ -372,6 +372,7 @@ static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap, ...@@ -372,6 +372,7 @@ static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap,
rc = cx231xx_i2c_check_for_device(i2c_adap, &msgs[i]); rc = cx231xx_i2c_check_for_device(i2c_adap, &msgs[i]);
if (rc < 0) { if (rc < 0) {
dprintk2(2, " no device\n"); dprintk2(2, " no device\n");
mutex_lock(&dev->i2c_lock);
return rc; return rc;
} }
...@@ -384,7 +385,7 @@ static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap, ...@@ -384,7 +385,7 @@ static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap,
} }
} else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
msgs[i].addr == msgs[i + 1].addr msgs[i].addr == msgs[i + 1].addr
&& (msgs[i].len <= 2) && (bus->nr < 2)) { && (msgs[i].len <= 2) && (bus->nr < 3)) {
/* read bytes */ /* read bytes */
rc = cx231xx_i2c_recv_bytes_with_saddr(i2c_adap, rc = cx231xx_i2c_recv_bytes_with_saddr(i2c_adap,
&msgs[i], &msgs[i],
...@@ -407,10 +408,11 @@ static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap, ...@@ -407,10 +408,11 @@ static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap,
if (i2c_debug >= 2) if (i2c_debug >= 2)
printk("\n"); printk("\n");
} }
mutex_unlock(&dev->i2c_lock);
return num; return num;
err: err:
dprintk2(2, " ERROR: %i\n", rc); dprintk2(2, " ERROR: %i\n", rc);
mutex_unlock(&dev->i2c_lock);
return rc; return rc;
} }
......
...@@ -61,6 +61,7 @@ struct cx231xx_ir_poll_result { ...@@ -61,6 +61,7 @@ struct cx231xx_ir_poll_result {
struct cx231xx_IR { struct cx231xx_IR {
struct cx231xx *dev; struct cx231xx *dev;
struct input_dev *input; struct input_dev *input;
struct ir_input_state ir;
char name[32]; char name[32];
char phys[32]; char phys[32];
...@@ -68,7 +69,9 @@ struct cx231xx_IR { ...@@ -68,7 +69,9 @@ struct cx231xx_IR {
int polling; int polling;
struct work_struct work; struct work_struct work;
struct timer_list timer; struct timer_list timer;
unsigned int last_toggle:1;
unsigned int last_readcount; unsigned int last_readcount;
unsigned int repeat_interval;
int (*get_key) (struct cx231xx_IR *, struct cx231xx_ir_poll_result *); int (*get_key) (struct cx231xx_IR *, struct cx231xx_ir_poll_result *);
}; };
...@@ -80,6 +83,7 @@ struct cx231xx_IR { ...@@ -80,6 +83,7 @@ struct cx231xx_IR {
static void cx231xx_ir_handle_key(struct cx231xx_IR *ir) static void cx231xx_ir_handle_key(struct cx231xx_IR *ir)
{ {
int result; int result;
int do_sendkey = 0;
struct cx231xx_ir_poll_result poll_result; struct cx231xx_ir_poll_result poll_result;
/* read the registers containing the IR status */ /* read the registers containing the IR status */
...@@ -93,23 +97,44 @@ static void cx231xx_ir_handle_key(struct cx231xx_IR *ir) ...@@ -93,23 +97,44 @@ static void cx231xx_ir_handle_key(struct cx231xx_IR *ir)
poll_result.toggle_bit, poll_result.read_count, poll_result.toggle_bit, poll_result.read_count,
ir->last_readcount, poll_result.rc_data[0]); ir->last_readcount, poll_result.rc_data[0]);
if (poll_result.read_count > 0 && if (ir->dev->chip_id == CHIP_ID_EM2874) {
poll_result.read_count != ir->last_readcount)
ir_keydown(ir->input,
poll_result.rc_data[0],
poll_result.toggle_bit);
if (ir->dev->chip_id == CHIP_ID_EM2874)
/* The em2874 clears the readcount field every time the /* The em2874 clears the readcount field every time the
register is read. The em2860/2880 datasheet says that it register is read. The em2860/2880 datasheet says that it
is supposed to clear the readcount, but it doesn't. So with is supposed to clear the readcount, but it doesn't. So with
the em2874, we are looking for a non-zero read count as the em2874, we are looking for a non-zero read count as
opposed to a readcount that is incrementing */ opposed to a readcount that is incrementing */
ir->last_readcount = 0; ir->last_readcount = 0;
else }
ir->last_readcount = poll_result.read_count;
if (poll_result.read_count == 0) {
/* The button has not been pressed since the last read */
} else if (ir->last_toggle != poll_result.toggle_bit) {
/* A button has been pressed */
dprintk("button has been pressed\n");
ir->last_toggle = poll_result.toggle_bit;
ir->repeat_interval = 0;
do_sendkey = 1;
} else if (poll_result.toggle_bit == ir->last_toggle &&
poll_result.read_count > 0 &&
poll_result.read_count != ir->last_readcount) {
/* The button is still being held down */
dprintk("button being held down\n");
/* Debouncer for first keypress */
if (ir->repeat_interval++ > 9) {
/* Start repeating after 1 second */
do_sendkey = 1;
}
}
if (do_sendkey) {
dprintk("sending keypress\n");
ir_input_keydown(ir->input, &ir->ir, poll_result.rc_data[0]);
ir_input_nokey(ir->input, &ir->ir);
} }
ir->last_readcount = poll_result.read_count;
return;
} }
static void ir_timer(unsigned long data) static void ir_timer(unsigned long data)
...@@ -175,6 +200,10 @@ int cx231xx_ir_init(struct cx231xx *dev) ...@@ -175,6 +200,10 @@ int cx231xx_ir_init(struct cx231xx *dev)
usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
strlcat(ir->phys, "/input0", sizeof(ir->phys)); strlcat(ir->phys, "/input0", sizeof(ir->phys));
err = ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER);
if (err < 0)
goto err_out_free;
input_dev->name = ir->name; input_dev->name = ir->name;
input_dev->phys = ir->phys; input_dev->phys = ir->phys;
input_dev->id.bustype = BUS_USB; input_dev->id.bustype = BUS_USB;
...@@ -190,7 +219,7 @@ int cx231xx_ir_init(struct cx231xx *dev) ...@@ -190,7 +219,7 @@ int cx231xx_ir_init(struct cx231xx *dev)
cx231xx_ir_start(ir); cx231xx_ir_start(ir);
/* all done */ /* all done */
err = __ir_input_register(ir->input, dev->board.ir_codes, err = ir_input_register(ir->input, dev->board.ir_codes,
NULL, MODULE_NAME); NULL, MODULE_NAME);
if (err) if (err)
goto err_out_stop; goto err_out_stop;
......
This diff is collapsed.
...@@ -41,7 +41,7 @@ extern struct videobuf_queue_ops cx231xx_vbi_qops; ...@@ -41,7 +41,7 @@ extern struct videobuf_queue_ops cx231xx_vbi_qops;
/* stream functions */ /* stream functions */
int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets, int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
int num_bufs, int max_pkt_size, int num_bufs, int max_pkt_size,
int (*isoc_copy) (struct cx231xx *dev, int (*bulk_copy) (struct cx231xx *dev,
struct urb *urb)); struct urb *urb));
void cx231xx_uninit_vbi_isoc(struct cx231xx *dev); void cx231xx_uninit_vbi_isoc(struct cx231xx *dev);
......
This diff is collapsed.
This diff is collapsed.
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