aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/cpu.c2
-rw-r--r--drivers/base/firmware_class.c6
-rw-r--r--drivers/base/map.c21
-rw-r--r--drivers/base/platform.c4
-rw-r--r--drivers/char/Makefile2
-rw-r--r--drivers/char/drm/Kconfig4
-rw-r--r--drivers/char/ip2/Makefile8
-rw-r--r--drivers/char/ip2/ip2base.c (renamed from drivers/char/ip2.c)6
-rw-r--r--drivers/char/ip2/ip2main.c (renamed from drivers/char/ip2main.c)20
-rw-r--r--drivers/char/s3c2410-rtc.c4
-rw-r--r--drivers/char/watchdog/mpcore_wdt.c4
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.c9
-rw-r--r--drivers/i2c/busses/i2c-mpc.c5
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c4
-rw-r--r--drivers/ide/mips/au1xxx-ide.c5
-rw-r--r--drivers/infiniband/core/agent.c19
-rw-r--r--drivers/infiniband/core/cm.c42
-rw-r--r--drivers/infiniband/core/fmr_pool.c6
-rw-r--r--drivers/infiniband/core/mad.c195
-rw-r--r--drivers/infiniband/core/mad_priv.h16
-rw-r--r--drivers/infiniband/core/mad_rmpp.c148
-rw-r--r--drivers/infiniband/core/smi.h9
-rw-r--r--drivers/infiniband/core/sysfs.c36
-rw-r--r--drivers/infiniband/core/user_mad.c225
-rw-r--r--drivers/infiniband/core/uverbs.h5
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c202
-rw-r--r--drivers/infiniband/core/uverbs_main.c6
-rw-r--r--drivers/infiniband/core/verbs.c259
-rw-r--r--drivers/infiniband/hw/mthca/mthca_av.c33
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cmd.c323
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cmd.h14
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cq.c161
-rw-r--r--drivers/infiniband/hw/mthca/mthca_dev.h33
-rw-r--r--drivers/infiniband/hw/mthca/mthca_eq.c6
-rw-r--r--drivers/infiniband/hw/mthca/mthca_mad.c17
-rw-r--r--drivers/infiniband/hw/mthca/mthca_main.c23
-rw-r--r--drivers/infiniband/hw/mthca/mthca_mcg.c2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_memfree.c29
-rw-r--r--drivers/infiniband/hw/mthca/mthca_memfree.h10
-rw-r--r--drivers/infiniband/hw/mthca/mthca_mr.c42
-rw-r--r--drivers/infiniband/hw/mthca/mthca_pd.c3
-rw-r--r--drivers/infiniband/hw/mthca/mthca_profile.c10
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.c170
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.h53
-rw-r--r--drivers/infiniband/hw/mthca/mthca_qp.c448
-rw-r--r--drivers/infiniband/hw/mthca/mthca_srq.c43
-rw-r--r--drivers/infiniband/hw/mthca/mthca_user.h7
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h12
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c10
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c15
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c25
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_verbs.c2
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c85
-rw-r--r--drivers/media/common/Makefile1
-rw-r--r--drivers/media/common/ir-common.c519
-rw-r--r--drivers/media/common/ir-functions.c272
-rw-r--r--drivers/media/common/ir-keymaps.c1415
-rw-r--r--drivers/media/common/saa7146_core.c9
-rw-r--r--drivers/media/common/saa7146_fops.c24
-rw-r--r--drivers/media/common/saa7146_i2c.c4
-rw-r--r--drivers/media/common/saa7146_vbi.c2
-rw-r--r--drivers/media/common/saa7146_video.c30
-rw-r--r--drivers/media/dvb/b2c2/flexcop-common.h4
-rw-r--r--drivers/media/dvb/b2c2/flexcop-i2c.c6
-rw-r--r--drivers/media/dvb/bt8xx/Makefile2
-rw-r--r--drivers/media/dvb/bt8xx/bt878.c4
-rw-r--r--drivers/media/dvb/bt8xx/bt878.h4
-rw-r--r--drivers/media/dvb/bt8xx/dst.c14
-rw-r--r--drivers/media/dvb/bt8xx/dst_ca.c6
-rw-r--r--drivers/media/dvb/bt8xx/dst_common.h3
-rw-r--r--drivers/media/dvb/bt8xx/dvb-bt8xx.c45
-rw-r--r--drivers/media/dvb/bt8xx/dvb-bt8xx.h3
-rw-r--r--drivers/media/dvb/cinergyT2/cinergyT2.c51
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.c795
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.h36
-rw-r--r--drivers/media/dvb/dvb-core/dvb_demux.c104
-rw-r--r--drivers/media/dvb/dvb-core/dvb_demux.h4
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c21
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.h1
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c14
-rw-r--r--drivers/media/dvb/dvb-core/dvb_ringbuffer.c2
-rw-r--r--drivers/media/dvb/dvb-core/dvb_ringbuffer.h1
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c4
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-common.c4
-rw-r--r--drivers/media/dvb/dvb-usb/digitv.c4
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-init.c4
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-urb.c4
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb.h9
-rw-r--r--drivers/media/dvb/dvb-usb/vp702x.c4
-rw-r--r--drivers/media/dvb/dvb-usb/vp7045.c4
-rw-r--r--drivers/media/dvb/frontends/Kconfig12
-rw-r--r--drivers/media/dvb/frontends/Makefile1
-rw-r--r--drivers/media/dvb/frontends/bcm3510.c9
-rw-r--r--drivers/media/dvb/frontends/bsbe1.h123
-rw-r--r--drivers/media/dvb/frontends/bsru6.h140
-rw-r--r--drivers/media/dvb/frontends/cx24110.c13
-rw-r--r--drivers/media/dvb/frontends/cx24110.h1
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.c61
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.h7
-rw-r--r--drivers/media/dvb/frontends/lnbp21.h139
-rw-r--r--drivers/media/dvb/frontends/tda1004x.c25
-rw-r--r--drivers/media/dvb/frontends/tda1004x.h3
-rw-r--r--drivers/media/dvb/frontends/zl10353.c311
-rw-r--r--drivers/media/dvb/frontends/zl10353.h43
-rw-r--r--drivers/media/dvb/frontends/zl10353_priv.h42
-rw-r--r--drivers/media/dvb/ttpci/av7110.c260
-rw-r--r--drivers/media/dvb/ttpci/av7110.h7
-rw-r--r--drivers/media/dvb/ttpci/av7110_hw.c40
-rw-r--r--drivers/media/dvb/ttpci/av7110_v4l.c11
-rw-r--r--drivers/media/dvb/ttpci/budget-av.c4
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c136
-rw-r--r--drivers/media/dvb/ttpci/budget-patch.c99
-rw-r--r--drivers/media/dvb/ttpci/budget.c250
-rw-r--r--drivers/media/dvb/ttpci/budget.h4
-rw-r--r--drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c35
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusb_dec.c31
-rw-r--r--drivers/media/radio/miropcm20-rds-core.c11
-rw-r--r--drivers/media/radio/radio-aimslab.c20
-rw-r--r--drivers/media/radio/radio-aztech.c12
-rw-r--r--drivers/media/radio/radio-maestro.c11
-rw-r--r--drivers/media/radio/radio-maxiradio.c11
-rw-r--r--drivers/media/radio/radio-sf16fmi.c22
-rw-r--r--drivers/media/radio/radio-sf16fmr2.c22
-rw-r--r--drivers/media/radio/radio-typhoon.c12
-rw-r--r--drivers/media/radio/radio-zoltrix.c26
-rw-r--r--drivers/media/video/Kconfig54
-rw-r--r--drivers/media/video/Makefile15
-rw-r--r--drivers/media/video/arv.c16
-rw-r--r--drivers/media/video/bttv-cards.c16
-rw-r--r--drivers/media/video/bttv-driver.c48
-rw-r--r--drivers/media/video/bttv-input.c248
-rw-r--r--drivers/media/video/bttv-risc.c17
-rw-r--r--drivers/media/video/bw-qcam.c16
-rw-r--r--drivers/media/video/bw-qcam.h2
-rw-r--r--drivers/media/video/c-qcam.c19
-rw-r--r--drivers/media/video/cpia.c102
-rw-r--r--drivers/media/video/cpia.h5
-rw-r--r--drivers/media/video/cpia2/Kconfig9
-rw-r--r--drivers/media/video/cpia2/Makefile3
-rw-r--r--drivers/media/video/cpia2/cpia2.h497
-rw-r--r--drivers/media/video/cpia2/cpia2_core.c2525
-rw-r--r--drivers/media/video/cpia2/cpia2_registers.h476
-rw-r--r--drivers/media/video/cpia2/cpia2_usb.c907
-rw-r--r--drivers/media/video/cpia2/cpia2_v4l.c2079
-rw-r--r--drivers/media/video/cpia2/cpia2dev.h50
-rw-r--r--drivers/media/video/cpia2/cpia2patch.h233
-rw-r--r--drivers/media/video/cx25840/Kconfig9
-rw-r--r--drivers/media/video/cx25840/Makefile2
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c46
-rw-r--r--drivers/media/video/cx25840/cx25840-vbi.c6
-rw-r--r--drivers/media/video/cx25840/cx25840.h1
-rw-r--r--drivers/media/video/cx88/Kconfig11
-rw-r--r--drivers/media/video/cx88/Makefile1
-rw-r--r--drivers/media/video/cx88/cx88-alsa.c10
-rw-r--r--drivers/media/video/cx88/cx88-cards.c111
-rw-r--r--drivers/media/video/cx88/cx88-core.c9
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c108
-rw-r--r--drivers/media/video/cx88/cx88-input.c339
-rw-r--r--drivers/media/video/cx88/cx88-video.c57
-rw-r--r--drivers/media/video/cx88/cx88.h8
-rw-r--r--drivers/media/video/dpc7146.c58
-rw-r--r--drivers/media/video/em28xx/Kconfig1
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c72
-rw-r--r--drivers/media/video/em28xx/em28xx-i2c.c1
-rw-r--r--drivers/media/video/em28xx/em28xx-input.c85
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c1613
-rw-r--r--drivers/media/video/em28xx/em28xx.h9
-rw-r--r--drivers/media/video/hexium_gemini.c10
-rw-r--r--drivers/media/video/hexium_orion.c18
-rw-r--r--drivers/media/video/ir-kbd-i2c.c50
-rw-r--r--drivers/media/video/meye.c112
-rw-r--r--drivers/media/video/meye.h4
-rw-r--r--drivers/media/video/msp3400-driver.c76
-rw-r--r--drivers/media/video/msp3400-kthreads.c333
-rw-r--r--drivers/media/video/msp3400.h10
-rw-r--r--drivers/media/video/mxb.c150
-rw-r--r--drivers/media/video/mxb.h2
-rw-r--r--drivers/media/video/planb.c8
-rw-r--r--drivers/media/video/planb.h2
-rw-r--r--drivers/media/video/pms.c28
-rw-r--r--drivers/media/video/saa5246a.c10
-rw-r--r--drivers/media/video/saa5249.c10
-rw-r--r--drivers/media/video/saa7115.c107
-rw-r--r--drivers/media/video/saa7134/saa7134-alsa.c9
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c294
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c31
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c182
-rw-r--r--drivers/media/video/saa7134/saa7134-empress.c8
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c507
-rw-r--r--drivers/media/video/saa7134/saa7134-oss.c46
-rw-r--r--drivers/media/video/saa7134/saa7134-tvaudio.c14
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c70
-rw-r--r--drivers/media/video/saa7134/saa7134.h16
-rw-r--r--drivers/media/video/tda8290.c8
-rw-r--r--drivers/media/video/tda9840.c3
-rw-r--r--drivers/media/video/tea6415c.c5
-rw-r--r--drivers/media/video/tea6420.c5
-rw-r--r--drivers/media/video/tuner-core.c69
-rw-r--r--drivers/media/video/tuner-simple.c166
-rw-r--r--drivers/media/video/tuner-types.c599
-rw-r--r--drivers/media/video/tvaudio.c26
-rw-r--r--drivers/media/video/tvp5150.c681
-rw-r--r--drivers/media/video/tvp5150_reg.h125
-rw-r--r--drivers/media/video/v4l2-common.c558
-rw-r--r--drivers/media/video/video-buf-dvb.c10
-rw-r--r--drivers/media/video/video-buf.c59
-rw-r--r--drivers/media/video/videodev.c22
-rw-r--r--drivers/media/video/vino.c33
-rw-r--r--drivers/mmc/pxamci.c2
-rw-r--r--drivers/net/arm/am79c961a.c4
-rw-r--r--drivers/net/fs_enet/mac-fcc.c2
-rw-r--r--drivers/net/fs_enet/mac-fec.c2
-rw-r--r--drivers/net/fs_enet/mac-scc.c2
-rw-r--r--drivers/net/gianfar.c4
-rw-r--r--drivers/net/smc91x.c4
-rw-r--r--drivers/pcmcia/omap_cf.c2
-rw-r--r--drivers/scsi/Kconfig8
-rw-r--r--drivers/scsi/Makefile2
-rw-r--r--drivers/scsi/ahci.c197
-rw-r--r--drivers/scsi/ata_piix.c392
-rw-r--r--drivers/scsi/libata-bmdma.c703
-rw-r--r--drivers/scsi/libata-core.c2794
-rw-r--r--drivers/scsi/libata-scsi.c240
-rw-r--r--drivers/scsi/libata.h3
-rw-r--r--drivers/scsi/pdc_adma.c6
-rw-r--r--drivers/scsi/sata_mv.c281
-rw-r--r--drivers/scsi/sata_nv.c2
-rw-r--r--drivers/scsi/sata_promise.c129
-rw-r--r--drivers/scsi/sata_qstor.c10
-rw-r--r--drivers/scsi/sata_sil.c126
-rw-r--r--drivers/scsi/sata_sil24.c102
-rw-r--r--drivers/scsi/sata_sis.c2
-rw-r--r--drivers/scsi/sata_svw.c2
-rw-r--r--drivers/scsi/sata_sx4.c25
-rw-r--r--drivers/scsi/sata_uli.c2
-rw-r--r--drivers/scsi/sata_via.c2
-rw-r--r--drivers/scsi/sata_vsc.c2
-rw-r--r--drivers/scsi/scsi_error.c7
-rw-r--r--drivers/serial/s3c2410.c2
-rw-r--r--drivers/usb/core/driver.c6
-rw-r--r--drivers/usb/host/ohci-omap.c9
-rw-r--r--drivers/video/Kconfig2
-rw-r--r--drivers/video/epson1355fb.c1
-rw-r--r--drivers/video/sa1100fb.c2
-rw-r--r--drivers/video/vfb.c1
245 files changed, 19183 insertions, 8504 deletions
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 07a7f97e1de..29f3d7504da 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -141,7 +141,7 @@ int __devinit register_cpu(struct cpu *cpu, int num, struct node *root)
return error;
}
-struct sys_device *get_cpu_sysdev(int cpu)
+struct sys_device *get_cpu_sysdev(unsigned cpu)
{
if (cpu < NR_CPUS)
return cpu_sys_devices[cpu];
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index e97e911ebf7..47231820523 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -211,18 +211,20 @@ static int
fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
{
u8 *new_data;
+ int new_size = fw_priv->alloc_size;
if (min_size <= fw_priv->alloc_size)
return 0;
- new_data = vmalloc(fw_priv->alloc_size + PAGE_SIZE);
+ new_size = ALIGN(min_size, PAGE_SIZE);
+ new_data = vmalloc(new_size);
if (!new_data) {
printk(KERN_ERR "%s: unable to alloc buffer\n", __FUNCTION__);
/* Make sure that we don't keep incomplete data */
fw_load_abort(fw_priv);
return -ENOMEM;
}
- fw_priv->alloc_size += PAGE_SIZE;
+ fw_priv->alloc_size = new_size;
if (fw_priv->fw->data) {
memcpy(new_data, fw_priv->fw->data, fw_priv->fw->size);
vfree(fw_priv->fw->data);
diff --git a/drivers/base/map.c b/drivers/base/map.c
index b449dae6f0d..e87017f3685 100644
--- a/drivers/base/map.c
+++ b/drivers/base/map.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/mutex.h>
#include <linux/kdev_t.h>
#include <linux/kobject.h>
#include <linux/kobj_map.h>
@@ -25,7 +26,7 @@ struct kobj_map {
int (*lock)(dev_t, void *);
void *data;
} *probes[255];
- struct semaphore *sem;
+ struct mutex *lock;
};
int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,
@@ -53,7 +54,7 @@ int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,
p->range = range;
p->data = data;
}
- down(domain->sem);
+ mutex_lock(domain->lock);
for (i = 0, p -= n; i < n; i++, p++, index++) {
struct probe **s = &domain->probes[index % 255];
while (*s && (*s)->range < range)
@@ -61,7 +62,7 @@ int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,
p->next = *s;
*s = p;
}
- up(domain->sem);
+ mutex_unlock(domain->lock);
return 0;
}
@@ -75,7 +76,7 @@ void kobj_unmap(struct kobj_map *domain, dev_t dev, unsigned long range)
if (n > 255)
n = 255;
- down(domain->sem);
+ mutex_lock(domain->lock);
for (i = 0; i < n; i++, index++) {
struct probe **s;
for (s = &domain->probes[index % 255]; *s; s = &(*s)->next) {
@@ -88,7 +89,7 @@ void kobj_unmap(struct kobj_map *domain, dev_t dev, unsigned long range)
}
}
}
- up(domain->sem);
+ mutex_unlock(domain->lock);
kfree(found);
}
@@ -99,7 +100,7 @@ struct kobject *kobj_lookup(struct kobj_map *domain, dev_t dev, int *index)
unsigned long best = ~0UL;
retry:
- down(domain->sem);
+ mutex_lock(domain->lock);
for (p = domain->probes[MAJOR(dev) % 255]; p; p = p->next) {
struct kobject *(*probe)(dev_t, int *, void *);
struct module *owner;
@@ -120,7 +121,7 @@ retry:
module_put(owner);
continue;
}
- up(domain->sem);
+ mutex_unlock(domain->lock);
kobj = probe(dev, index, data);
/* Currently ->owner protects _only_ ->probe() itself. */
module_put(owner);
@@ -128,11 +129,11 @@ retry:
return kobj;
goto retry;
}
- up(domain->sem);
+ mutex_unlock(domain->lock);
return NULL;
}
-struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct semaphore *sem)
+struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct mutex *lock)
{
struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL);
struct probe *base = kzalloc(sizeof(*base), GFP_KERNEL);
@@ -149,6 +150,6 @@ struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct semaphore *sem)
base->get = base_probe;
for (i = 0; i < 255; i++)
p->probes[i] = base;
- p->sem = sem;
+ p->lock = lock;
return p;
}
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 461554a0251..89b26832132 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -61,7 +61,7 @@ int platform_get_irq(struct platform_device *dev, unsigned int num)
{
struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num);
- return r ? r->start : 0;
+ return r ? r->start : -ENXIO;
}
EXPORT_SYMBOL_GPL(platform_get_irq);
@@ -98,7 +98,7 @@ int platform_get_irq_byname(struct platform_device *dev, char *name)
{
struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name);
- return r ? r->start : 0;
+ return r ? r->start : -ENXIO;
}
EXPORT_SYMBOL_GPL(platform_get_irq_byname);
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 503dd901d40..090d154098b 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -31,7 +31,7 @@ obj-$(CONFIG_MOXA_INTELLIO) += moxa.o
obj-$(CONFIG_A2232) += ser_a2232.o generic_serial.o
obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o
obj-$(CONFIG_MOXA_SMARTIO) += mxser.o
-obj-$(CONFIG_COMPUTONE) += ip2.o ip2main.o
+obj-$(CONFIG_COMPUTONE) += ip2/
obj-$(CONFIG_RISCOM8) += riscom8.o
obj-$(CONFIG_ISI) += isicom.o
obj-$(CONFIG_SYNCLINK) += synclink.o
diff --git a/drivers/char/drm/Kconfig b/drivers/char/drm/Kconfig
index 56ace9d5e2a..5278c388d3e 100644
--- a/drivers/char/drm/Kconfig
+++ b/drivers/char/drm/Kconfig
@@ -37,8 +37,8 @@ config DRM_RADEON
help
Choose this option if you have an ATI Radeon graphics card. There
are both PCI and AGP versions. You don't need to choose this to
- run the Radeon in plain VGA mode. There is a product page at
- <http://www.ati.com/na/pages/products/pc/radeon32/index.html>.
+ run the Radeon in plain VGA mode.
+
If M is selected, the module will be called radeon.
config DRM_I810
diff --git a/drivers/char/ip2/Makefile b/drivers/char/ip2/Makefile
new file mode 100644
index 00000000000..6bfe2543ddc
--- /dev/null
+++ b/drivers/char/ip2/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the Computone IntelliPort Plus Driver
+#
+
+obj-$(CONFIG_COMPUTONE) += ip2.o ip2main.o
+
+ip2-objs := ip2base.o
+
diff --git a/drivers/char/ip2.c b/drivers/char/ip2/ip2base.c
index 7cadfc6ef35..435ccfc7495 100644
--- a/drivers/char/ip2.c
+++ b/drivers/char/ip2/ip2base.c
@@ -20,14 +20,14 @@
#define __initdata
#endif
-#include "./ip2/ip2types.h"
-#include "./ip2/fip_firm.h" // the meat
+#include "ip2types.h"
+#include "fip_firm.h" // the meat
int
ip2_loadmain(int *, int *, unsigned char *, int ); // ref into ip2main.c
/* Note: Add compiled in defaults to these arrays, not to the structure
- in ip2/ip2.h any longer. That structure WILL get overridden
+ in ip2.h any longer. That structure WILL get overridden
by these values, or command line values, or insmod values!!! =mhw=
*/
static int io[IP2_MAX_BOARDS]= { 0, 0, 0, 0 };
diff --git a/drivers/char/ip2main.c b/drivers/char/ip2/ip2main.c
index 48fcfba37bf..03db1cb3fa9 100644
--- a/drivers/char/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -35,7 +35,7 @@
// Clean up potential NULL pointer dereferences
// Clean up devfs registration
// Add kernel command line parsing for io and irq
-// Compile defaults for io and irq are now set in ip2.c not ip2/ip2.h!
+// Compile defaults for io and irq are now set in ip2.c not ip2.h!
// Reworked poll_only hack for explicit parameter setting
// You must now EXPLICITLY set poll_only = 1 or set all irqs to 0
// Merged ip2_loadmain and old_ip2_init
@@ -123,12 +123,12 @@
#include <asm/uaccess.h>
-#include "./ip2/ip2types.h"
-#include "./ip2/ip2trace.h"
-#include "./ip2/ip2ioctl.h"
-#include "./ip2/ip2.h"
-#include "./ip2/i2ellis.h"
-#include "./ip2/i2lib.h"
+#include "ip2types.h"
+#include "ip2trace.h"
+#include "ip2ioctl.h"
+#include "ip2.h"
+#include "i2ellis.h"
+#include "i2lib.h"
/*****************
* /proc/ip2mem *
@@ -282,9 +282,9 @@ static int tracewrap;
/* Code */
/********/
-#include "./ip2/i2ellis.c" /* Extremely low-level interface services */
-#include "./ip2/i2cmd.c" /* Standard loadware command definitions */
-#include "./ip2/i2lib.c" /* High level interface services */
+#include "i2ellis.c" /* Extremely low-level interface services */
+#include "i2cmd.c" /* Standard loadware command definitions */
+#include "i2lib.c" /* High level interface services */
/* Configuration area for modprobe */
diff --git a/drivers/char/s3c2410-rtc.c b/drivers/char/s3c2410-rtc.c
index 2e308657f6f..b0038b19b50 100644
--- a/drivers/char/s3c2410-rtc.c
+++ b/drivers/char/s3c2410-rtc.c
@@ -448,13 +448,13 @@ static int s3c2410_rtc_probe(struct platform_device *pdev)
/* find the IRQs */
s3c2410_rtc_tickno = platform_get_irq(pdev, 1);
- if (s3c2410_rtc_tickno <= 0) {
+ if (s3c2410_rtc_tickno < 0) {
dev_err(&pdev->dev, "no irq for rtc tick\n");
return -ENOENT;
}
s3c2410_rtc_alarmno = platform_get_irq(pdev, 0);
- if (s3c2410_rtc_alarmno <= 0) {
+ if (s3c2410_rtc_alarmno < 0) {
dev_err(&pdev->dev, "no irq for alarm\n");
return -ENOENT;
}
diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c
index b4d84348988..2c2c5177320 100644
--- a/drivers/char/watchdog/mpcore_wdt.c
+++ b/drivers/char/watchdog/mpcore_wdt.c
@@ -338,6 +338,10 @@ static int __devinit mpcore_wdt_probe(struct platform_device *dev)
wdt->dev = &dev->dev;
wdt->irq = platform_get_irq(dev, 0);
+ if (wdt->irq < 0) {
+ ret = -ENXIO;
+ goto err_free;
+ }
wdt->base = ioremap(res->start, res->end - res->start + 1);
if (!wdt->base) {
ret = -ENOMEM;
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index 1414851a17b..d00a02fc23e 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -434,7 +434,7 @@ static int
iop3xx_i2c_probe(struct platform_device *pdev)
{
struct resource *res;
- int ret;
+ int ret, irq;
struct i2c_adapter *new_adapter;
struct i2c_algo_iop3xx_data *adapter_data;
@@ -470,7 +470,12 @@ iop3xx_i2c_probe(struct platform_device *pdev)
goto release_region;
}
- ret = request_irq(platform_get_irq(pdev, 0), iop3xx_i2c_irq_handler, 0,
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ ret = -ENXIO;
+ goto unmap;
+ }
+ ret = request_irq(irq, iop3xx_i2c_irq_handler, 0,
pdev->name, adapter_data);
if (ret) {
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 5ccd338a9dc..2721e4c8184 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -302,6 +302,10 @@ static int fsl_i2c_probe(struct platform_device *pdev)
}
i2c->irq = platform_get_irq(pdev, 0);
+ if (i2c->irq < 0) {
+ result = -ENXIO;
+ goto fail_get_irq;
+ }
i2c->flags = pdata->device_flags;
init_waitqueue_head(&i2c->queue);
@@ -340,6 +344,7 @@ static int fsl_i2c_probe(struct platform_device *pdev)
fail_irq:
iounmap(i2c->base);
fail_map:
+ fail_get_irq:
kfree(i2c);
return result;
};
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index 22781d84f79..ac5cde1bbd2 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -516,6 +516,10 @@ mv64xxx_i2c_probe(struct platform_device *pd)
drv_data->freq_m = pdata->freq_m;
drv_data->freq_n = pdata->freq_n;
drv_data->irq = platform_get_irq(pd, 0);
+ if (drv_data->irq < 0) {
+ rc = -ENXIO;
+ goto exit_unmap_regs;
+ }
drv_data->adapter.id = I2C_HW_MV64XXX;
drv_data->adapter.algo = &mv64xxx_i2c_algo;
drv_data->adapter.owner = THIS_MODULE;
diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c
index 32431dcf5d8..71f27e955d8 100644
--- a/drivers/ide/mips/au1xxx-ide.c
+++ b/drivers/ide/mips/au1xxx-ide.c
@@ -674,6 +674,11 @@ static int au_ide_probe(struct device *dev)
ret = -ENODEV;
goto out;
}
+ if (ahwif->irq < 0) {
+ pr_debug("%s %d: no IRQ\n", DRV_NAME, pdev->id);
+ ret = -ENODEV;
+ goto out;
+ }
if (!request_mem_region (res->start, res->end-res->start, pdev->name)) {
pr_debug("%s: request_mem_region failed\n", DRV_NAME);
diff --git a/drivers/infiniband/core/agent.c b/drivers/infiniband/core/agent.c
index 34b724afd28..ecd1a3057c6 100644
--- a/drivers/infiniband/core/agent.c
+++ b/drivers/infiniband/core/agent.c
@@ -78,25 +78,6 @@ ib_get_agent_port(struct ib_device *device, int port_num)
return entry;
}
-int smi_check_local_dr_smp(struct ib_smp *smp,
- struct ib_device *device,
- int port_num)
-{
- struct ib_agent_port_private *port_priv;
-
- if (smp->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
- return 1;
-
- port_priv = ib_get_agent_port(device, port_num);
- if (!port_priv) {
- printk(KERN_DEBUG SPFX "smi_check_local_dr_smp %s port %d "
- "not open\n", device->name, port_num);
- return 1;
- }
-
- return smi_check_local_smp(port_priv->agent[0], smp);
-}
-
int agent_send_response(struct ib_mad *mad, struct ib_grh *grh,
struct ib_wc *wc, struct ib_device *device,
int port_num, int qpn)
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 2514de3480d..7cfedb8d9bc 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -121,7 +121,7 @@ struct cm_id_private {
struct rb_node service_node;
struct rb_node sidr_id_node;
- spinlock_t lock;
+ spinlock_t lock; /* Do not acquire inside cm.lock */
wait_queue_head_t wait;
atomic_t refcount;
@@ -1547,40 +1547,46 @@ static int cm_rep_handler(struct cm_work *work)
return -EINVAL;
}
+ cm_format_rep_event(work);
+
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+ switch (cm_id_priv->id.state) {
+ case IB_CM_REQ_SENT:
+ case IB_CM_MRA_REQ_RCVD:
+ break;
+ default:
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ ret = -EINVAL;
+ goto error;
+ }
+
cm_id_priv->timewait_info->work.remote_id = rep_msg->local_comm_id;
cm_id_priv->timewait_info->remote_ca_guid = rep_msg->local_ca_guid;
cm_id_priv->timewait_info->remote_qpn = cm_rep_get_local_qpn(rep_msg);
- spin_lock_irqsave(&cm.lock, flags);
+ spin_lock(&cm.lock);
/* Check for duplicate REP. */
if (cm_insert_remote_id(cm_id_priv->timewait_info)) {
- spin_unlock_irqrestore(&cm.lock, flags);
+ spin_unlock(&cm.lock);
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
ret = -EINVAL;
goto error;
}
/* Check for a stale connection. */
if (cm_insert_remote_qpn(cm_id_priv->timewait_info)) {
- spin_unlock_irqrestore(&cm.lock, flags);
+ rb_erase(&cm_id_priv->timewait_info->remote_id_node,
+ &cm.remote_id_table);
+ cm_id_priv->timewait_info->inserted_remote_id = 0;
+ spin_unlock(&cm.lock);
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
cm_issue_rej(work->port, work->mad_recv_wc,
IB_CM_REJ_STALE_CONN, CM_MSG_RESPONSE_REP,
NULL, 0);
ret = -EINVAL;
goto error;
}
- spin_unlock_irqrestore(&cm.lock, flags);
-
- cm_format_rep_event(work);
+ spin_unlock(&cm.lock);
- spin_lock_irqsave(&cm_id_priv->lock, flags);
- switch (cm_id_priv->id.state) {
- case IB_CM_REQ_SENT:
- case IB_CM_MRA_REQ_RCVD:
- break;
- default:
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
- ret = -EINVAL;
- goto error;
- }
cm_id_priv->id.state = IB_CM_REP_RCVD;
cm_id_priv->id.remote_id = rep_msg->local_comm_id;
cm_id_priv->remote_qpn = cm_rep_get_local_qpn(rep_msg);
@@ -1603,7 +1609,7 @@ static int cm_rep_handler(struct cm_work *work)
cm_deref_id(cm_id_priv);
return 0;
-error: cm_cleanup_timewait(cm_id_priv->timewait_info);
+error:
cm_deref_id(cm_id_priv);
return ret;
}
diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c
index d34a6f1c4f4..838bf54458d 100644
--- a/drivers/infiniband/core/fmr_pool.c
+++ b/drivers/infiniband/core/fmr_pool.c
@@ -278,9 +278,9 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
{
struct ib_pool_fmr *fmr;
struct ib_fmr_attr attr = {
- .max_pages = params->max_pages_per_fmr,
- .max_maps = IB_FMR_MAX_REMAPS,
- .page_size = PAGE_SHIFT
+ .max_pages = params->max_pages_per_fmr,
+ .max_maps = IB_FMR_MAX_REMAPS,
+ .page_shift = params->page_shift
};
for (i = 0; i < params->pool_size; ++i) {
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index c82f47a66e4..f7854b65fd5 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -31,7 +31,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
- * $Id: mad.c 2817 2005-07-07 11:29:26Z halr $
+ * $Id: mad.c 5596 2006-03-03 01:00:07Z sean.hefty $
*/
#include <linux/dma-mapping.h>
@@ -679,8 +679,8 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
goto out;
}
/* Check to post send on QP or process locally */
- ret = smi_check_local_dr_smp(smp, device, port_num);
- if (!ret || !device->process_mad)
+ ret = smi_check_local_smp(smp, device);
+ if (!ret)
goto out;
local = kmalloc(sizeof *local, GFP_ATOMIC);
@@ -765,18 +765,67 @@ out:
return ret;
}
-static int get_buf_length(int hdr_len, int data_len)
+static int get_pad_size(int hdr_len, int data_len)
{
int seg_size, pad;
seg_size = sizeof(struct ib_mad) - hdr_len;
if (data_len && seg_size) {
pad = seg_size - data_len % seg_size;
- if (pad == seg_size)
- pad = 0;
+ return pad == seg_size ? 0 : pad;
} else
- pad = seg_size;
- return hdr_len + data_len + pad;
+ return seg_size;
+}
+
+static void free_send_rmpp_list(struct ib_mad_send_wr_private *mad_send_wr)
+{
+ struct ib_rmpp_segment *s, *t;
+
+ list_for_each_entry_safe(s, t, &mad_send_wr->rmpp_list, list) {
+ list_del(&s->list);
+ kfree(s);
+ }
+}
+
+static int alloc_send_rmpp_list(struct ib_mad_send_wr_private *send_wr,
+ gfp_t gfp_mask)
+{
+ struct ib_mad_send_buf *send_buf = &send_wr->send_buf;
+ struct ib_rmpp_mad *rmpp_mad = send_buf->mad;
+ struct ib_rmpp_segment *seg = NULL;
+ int left, seg_size, pad;
+
+ send_buf->seg_size = sizeof (struct ib_mad) - send_buf->hdr_len;
+ seg_size = send_buf->seg_size;
+ pad = send_wr->pad;
+
+ /* Allocate data segments. */
+ for (left = send_buf->data_len + pad; left > 0; left -= seg_size) {
+ seg = kmalloc(sizeof (*seg) + seg_size, gfp_mask);
+ if (!seg) {
+ printk(KERN_ERR "alloc_send_rmpp_segs: RMPP mem "
+ "alloc failed for len %zd, gfp %#x\n",
+ sizeof (*seg) + seg_size, gfp_mask);
+ free_send_rmpp_list(send_wr);
+ return -ENOMEM;
+ }
+ seg->num = ++send_buf->seg_count;
+ list_add_tail(&seg->list, &send_wr->rmpp_list);
+ }
+
+ /* Zero any padding */
+ if (pad)
+ memset(seg->data + seg_size - pad, 0, pad);
+
+ rmpp_mad->rmpp_hdr.rmpp_version = send_wr->mad_agent_priv->
+ agent.rmpp_version;
+ rmpp_mad->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_DATA;
+ ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE);
+
+ send_wr->cur_seg = container_of(send_wr->rmpp_list.next,
+ struct ib_rmpp_segment, list);
+ send_wr->last_ack_seg = send_wr->cur_seg;
+ return 0;
}
struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent,
@@ -787,32 +836,40 @@ struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent,
{
struct ib_mad_agent_private *mad_agent_priv;
struct ib_mad_send_wr_private *mad_send_wr;
- int buf_size;
+ int pad, message_size, ret, size;
void *buf;
mad_agent_priv = container_of(mad_agent, struct ib_mad_agent_private,
agent);
- buf_size = get_buf_length(hdr_len, data_len);
+ pad = get_pad_size(hdr_len, data_len);
+ message_size = hdr_len + data_len + pad;
if ((!mad_agent->rmpp_version &&
- (rmpp_active || buf_size > sizeof(struct ib_mad))) ||
- (!rmpp_active && buf_size > sizeof(struct ib_mad)))
+ (rmpp_active || message_size > sizeof(struct ib_mad))) ||
+ (!rmpp_active && message_size > sizeof(struct ib_mad)))
return ERR_PTR(-EINVAL);
- buf = kzalloc(sizeof *mad_send_wr + buf_size, gfp_mask);
+ size = rmpp_active ? hdr_len : sizeof(struct ib_mad);
+ buf = kzalloc(sizeof *mad_send_wr + size, gfp_mask);
if (!buf)
return ERR_PTR(-ENOMEM);
- mad_send_wr = buf + buf_size;
+ mad_send_wr = buf + size;
+ INIT_LIST_HEAD(&mad_send_wr->rmpp_list);
mad_send_wr->send_buf.mad = buf;
+ mad_send_wr->send_buf.hdr_len = hdr_len;
+ mad_send_wr->send_buf.data_len = data_len;
+ mad_send_wr->pad = pad;
mad_send_wr->mad_agent_priv = mad_agent_priv;
- mad_send_wr->sg_list[0].length = buf_size;
+ mad_send_wr->sg_list[0].length = hdr_len;
mad_send_wr->sg_list[0].lkey = mad_agent->mr->lkey;
+ mad_send_wr->sg_list[1].length = sizeof(struct ib_mad) - hdr_len;
+ mad_send_wr->sg_list[1].lkey = mad_agent->mr->lkey;
mad_send_wr->send_wr.wr_id = (unsigned long) mad_send_wr;
mad_send_wr->send_wr.sg_list = mad_send_wr->sg_list;
- mad_send_wr->send_wr.num_sge = 1;
+ mad_send_wr->send_wr.num_sge = 2;
mad_send_wr->send_wr.opcode = IB_WR_SEND;
mad_send_wr->send_wr.send_flags = IB_SEND_SIGNALED;
mad_send_wr->send_wr.wr.ud.remote_qpn = remote_qpn;
@@ -820,13 +877,11 @@ struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent,
mad_send_wr->send_wr.wr.ud.pkey_index = pkey_index;
if (rmpp_active) {
- struct ib_rmpp_mad *rmpp_mad = mad_send_wr->send_buf.mad;
- rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(hdr_len -
- IB_MGMT_RMPP_HDR + data_len);
- rmpp_mad->rmpp_hdr.rmpp_version = mad_agent->rmpp_version;
- rmpp_mad->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_DATA;
- ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr,
- IB_MGMT_RMPP_FLAG_ACTIVE);
+ ret = alloc_send_rmpp_list(mad_send_wr, gfp_mask);
+ if (ret) {
+ kfree(buf);
+ return ERR_PTR(ret);
+ }
}
mad_send_wr->send_buf.mad_agent = mad_agent;
@@ -835,14 +890,50 @@ struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent,
}
EXPORT_SYMBOL(ib_create_send_mad);
+void *ib_get_rmpp_segment(struct ib_mad_send_buf *send_buf, int seg_num)
+{
+ struct ib_mad_send_wr_private *mad_send_wr;
+ struct list_head *list;
+
+ mad_send_wr = container_of(send_buf, struct ib_mad_send_wr_private,
+ send_buf);
+ list = &mad_send_wr->cur_seg->list;
+
+ if (mad_send_wr->cur_seg->num < seg_num) {
+ list_for_each_entry(mad_send_wr->cur_seg, list, list)
+ if (mad_send_wr->cur_seg->num == seg_num)
+ break;
+ } else if (mad_send_wr->cur_seg->num > seg_num) {
+ list_for_each_entry_reverse(mad_send_wr->cur_seg, list, list)
+ if (mad_send_wr->cur_seg->num == seg_num)
+ break;
+ }
+ return mad_send_wr->cur_seg->data;
+}
+EXPORT_SYMBOL(ib_get_rmpp_segment);
+
+static inline void *ib_get_payload(struct ib_mad_send_wr_private *mad_send_wr)
+{
+ if (mad_send_wr->send_buf.seg_count)
+ return ib_get_rmpp_segment(&mad_send_wr->send_buf,
+ mad_send_wr->seg_num);
+ else
+ return mad_send_wr->send_buf.mad +
+ mad_send_wr->send_buf.hdr_len;
+}
+
void ib_free_send_mad(struct ib_mad_send_buf *send_buf)
{
struct ib_mad_agent_private *mad_agent_priv;
+ struct ib_mad_send_wr_private *mad_send_wr;
mad_agent_priv = container_of(send_buf->mad_agent,
struct ib_mad_agent_private, agent);
- kfree(send_buf->mad);
+ mad_send_wr = container_of(send_buf, struct ib_mad_send_wr_private,
+ send_buf);
+ free_send_rmpp_list(mad_send_wr);
+ kfree(send_buf->mad);
if (atomic_dec_and_test(&mad_agent_priv->refcount))
wake_up(&mad_agent_priv->wait);
}
@@ -865,10 +956,17 @@ int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr)
mad_agent = mad_send_wr->send_buf.mad_agent;
sge = mad_send_wr->sg_list;
- sge->addr = dma_map_single(mad_agent->device->dma_device,
- mad_send_wr->send_buf.mad, sge->length,
- DMA_TO_DEVICE);
- pci_unmap_addr_set(mad_send_wr, mapping, sge->addr);
+ sge[0].addr = dma_map_single(mad_agent->device->dma_device,
+ mad_send_wr->send_buf.mad,
+ sge[0].length,
+ DMA_TO_DEVICE);
+ pci_unmap_addr_set(mad_send_wr, header_mapping, sge[0].addr);
+
+ sge[1].addr = dma_map_single(mad_agent->device->dma_device,
+ ib_get_payload(mad_send_wr),
+ sge[1].length,
+ DMA_TO_DEVICE);
+ pci_unmap_addr_set(mad_send_wr, payload_mapping, sge[1].addr);
spin_lock_irqsave(&qp_info->send_queue.lock, flags);
if (qp_info->send_queue.count < qp_info->send_queue.max_active) {
@@ -885,11 +983,14 @@ int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr)
list_add_tail(&mad_send_wr->mad_list.list, list);
}
spin_unlock_irqrestore(&qp_info->send_queue.lock, flags);
- if (ret)
+ if (ret) {
dma_unmap_single(mad_agent->device->dma_device,
- pci_unmap_addr(mad_send_wr, mapping),
- sge->length, DMA_TO_DEVICE);
-
+ pci_unmap_addr(mad_send_wr, header_mapping),
+ sge[0].length, DMA_TO_DEVICE);
+ dma_unmap_single(mad_agent->device->dma_device,
+ pci_unmap_addr(mad_send_wr, payload_mapping),
+ sge[1].length, DMA_TO_DEVICE);
+ }
return ret;
}
@@ -1661,9 +1762,7 @@ static void ib_mad_recv_done_handler(struct ib_mad_port_private *port_priv,
port_priv->device->node_type,
port_priv->port_num))
goto out;
- if (!smi_check_local_dr_smp(&recv->mad.smp,
- port_priv->device,
- port_priv->port_num))
+ if (!smi_check_local_smp(&recv->mad.smp, port_priv->device))
goto out;
}
@@ -1862,8 +1961,11 @@ static void ib_mad_send_done_handler(struct ib_mad_port_private *port_priv,
retry:
dma_unmap_single(mad_send_wr->send_buf.mad_agent->device->dma_device,
- pci_unmap_addr(mad_send_wr, mapping),
+ pci_unmap_addr(mad_send_wr, header_mapping),
mad_send_wr->sg_list[0].length, DMA_TO_DEVICE);
+ dma_unmap_single(mad_send_wr->send_buf.mad_agent->device->dma_device,
+ pci_unmap_addr(mad_send_wr, payload_mapping),
+ mad_send_wr->sg_list[1].length, DMA_TO_DEVICE);
queued_send_wr = NULL;
spin_lock_irqsave(&send_queue->lock, flags);
list_del(&mad_list->list);
@@ -2262,8 +2364,12 @@ static void timeout_sends(void *data)
static void ib_mad_thread_completion_handler(struct ib_cq *cq, void *arg)
{
struct ib_mad_port_private *port_priv = cq->cq_context;
+ unsigned long flags;
- queue_work(port_priv->wq, &port_priv->work);
+ spin_lock_irqsave(&ib_mad_port_list_lock, flags);
+ if (!list_empty(&port_priv->port_list))
+ queue_work(port_priv->wq, &port_priv->work);
+ spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
}
/*
@@ -2575,18 +2681,23 @@ static int ib_mad_port_open(struct ib_device *device,
}
INIT_WORK(&port_priv->work, ib_mad_completion_handler, port_priv);
+ spin_lock_irqsave(&ib_mad_port_list_lock, flags);
+ list_add_tail(&port_priv->port_list, &ib_mad_port_list);
+ spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
+
ret = ib_mad_port_start(port_priv);
if (ret) {
printk(KERN_ERR PFX "Couldn't start port\n");
goto error9;
}
- spin_lock_irqsave(&ib_mad_port_list_lock, flags);
- list_add_tail(&port_priv->port_list, &ib_mad_port_list);
- spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
return 0;
error9:
+ spin_lock_irqsave(&ib_mad_port_list_lock, flags);
+ list_del_init(&port_priv->port_list);
+ spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
+
destroy_workqueue(port_priv->wq);
error8:
destroy_mad_qp(&port_priv->qp_info[1]);
@@ -2623,11 +2734,9 @@ static int ib_mad_port_close(struct ib_device *device, int port_num)
printk(KERN_ERR PFX "Port %d not found\n", port_num);
return -ENODEV;
}
- list_del(&port_priv->port_list);
+ list_del_init(&port_priv->port_list);
spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
- /* Stop processing completions. */
- flush_workqueue(port_priv->wq);
destroy_workqueue(port_priv->wq);
destroy_mad_qp(&port_priv->qp_info[1]);
destroy_mad_qp(&port_priv->qp_info[0]);
diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h
index 570f78682af..a7125d4b5cc 100644
--- a/drivers/infiniband/core/mad_priv.h
+++ b/drivers/infiniband/core/mad_priv.h
@@ -31,7 +31,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
- * $Id: mad_priv.h 2730 2005-06-28 16:43:03Z sean.hefty $
+ * $Id: mad_priv.h 5596 2006-03-03 01:00:07Z sean.hefty $
*/
#ifndef __IB_MAD_PRIV_H__
@@ -85,6 +85,12 @@ struct ib_mad_private {
} mad;
} __attribute__ ((packed));
+struct ib_rmpp_segment {
+ struct list_head list;
+ u32 num;
+ u8 data[0];
+};
+
struct ib_mad_agent_private {
struct list_head agent_list;
struct ib_mad_agent agent;
@@ -119,7 +125,8 @@ struct ib_mad_send_wr_private {
struct list_head agent_list;
struct ib_mad_agent_private *mad_agent_priv;
struct ib_mad_send_buf send_buf;
- DECLARE_PCI_UNMAP_ADDR(mapping)
+ DECLARE_PCI_UNMAP_ADDR(header_mapping)
+ DECLARE_PCI_UNMAP_ADDR(payload_mapping)
struct ib_send_wr send_wr;
struct ib_sge sg_list[IB_MAD_SEND_REQ_MAX_SG];
__be64 tid;
@@ -130,11 +137,12 @@ struct ib_mad_send_wr_private {
enum ib_wc_status status;
/* RMPP control */
+ struct list_head rmpp_list;
+ struct ib_rmpp_segment *last_ack_seg;
+ struct ib_rmpp_segment *cur_seg;
int last_ack;
int seg_num;
int newwin;
- int total_seg;
- int data_offset;
int pad;
};
diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c
index 3249e1d8c07..bacfdd5bdda 100644
--- a/drivers/infiniband/core/mad_rmpp.c
+++ b/drivers/infiniband/core/mad_rmpp.c
@@ -111,14 +111,14 @@ static int data_offset(u8 mgmt_class)
return IB_MGMT_RMPP_HDR;
}
-static void format_ack(struct ib_rmpp_mad *ack,
+static void format_ack(struct ib_mad_send_buf *msg,
struct ib_rmpp_mad *data,
struct mad_rmpp_recv *rmpp_recv)
{
+ struct ib_rmpp_mad *ack = msg->mad;
unsigned long flags;
- memcpy(&ack->mad_hdr, &data->mad_hdr,
- data_offset(data->mad_hdr.mgmt_class));
+ memcpy(ack, &data->mad_hdr, msg->hdr_len);
ack->mad_hdr.method ^= IB_MGMT_METHOD_RESP;
ack->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_ACK;
@@ -135,16 +135,16 @@ static void ack_recv(struct mad_rmpp_recv *rmpp_recv,
struct ib_mad_recv_wc *recv_wc)
{
struct ib_mad_send_buf *msg;
- int ret;
+ int ret, hdr_len;
+ hdr_len = data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class);
msg = ib_create_send_mad(&rmpp_recv->agent->agent, recv_wc->wc->src_qp,
- recv_wc->wc->pkey_index, 1, IB_MGMT_RMPP_HDR,
- IB_MGMT_RMPP_DATA, GFP_KERNEL);
+ recv_wc->wc->pkey_index, 1, hdr_len,
+ 0, GFP_KERNEL);
if (!msg)
return;
- format_ack(msg->mad, (struct ib_rmpp_mad *) recv_wc->recv_buf.mad,
- rmpp_recv);
+ format_ack(msg, (struct ib_rmpp_mad *) recv_wc->recv_buf.mad, rmpp_recv);
msg->ah = rmpp_recv->ah;
ret = ib_post_send_mad(msg, NULL);
if (ret)
@@ -156,16 +156,17 @@ static struct ib_mad_send_buf *alloc_response_msg(struct ib_mad_agent *agent,
{
struct ib_mad_send_buf *msg;
struct ib_ah *ah;
+ int hdr_len;
ah = ib_create_ah_from_wc(agent->qp->pd, recv_wc->wc,
recv_wc->recv_buf.grh, agent->port_num);
if (IS_ERR(ah))
return (void *) ah;
+ hdr_len = data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class);
msg = ib_create_send_mad(agent, recv_wc->wc->src_qp,
recv_wc->wc->pkey_index, 1,
- IB_MGMT_RMPP_HDR, IB_MGMT_RMPP_DATA,
- GFP_KERNEL);
+ hdr_len, 0, GFP_KERNEL);
if (IS_ERR(msg))
ib_destroy_ah(ah);
else
@@ -195,8 +196,7 @@ static void nack_recv(struct ib_mad_agent_private *agent,
return;
rmpp_mad = msg->mad;
- memcpy(rmpp_mad, recv_wc->recv_buf.mad,
- data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class));
+ memcpy(rmpp_mad, recv_wc->recv_buf.mad, msg->hdr_len);
rmpp_mad->mad_hdr.method ^= IB_MGMT_METHOD_RESP;
rmpp_mad->rmpp_hdr.rmpp_version = IB_MGMT_RMPP_VERSION;
@@ -433,44 +433,6 @@ static struct ib_mad_recv_wc * complete_rmpp(struct mad_rmpp_recv *rmpp_recv)
return rmpp_wc;
}
-void ib_coalesce_recv_mad(struct ib_mad_recv_wc *mad_recv_wc, void *buf)
-{
- struct ib_mad_recv_buf *seg_buf;
- struct ib_rmpp_mad *rmpp_mad;
- void *data;
- int size, len, offset;
- u8 flags;
-
- len = mad_recv_wc->mad_len;
- if (len <= sizeof(struct ib_mad)) {
- memcpy(buf, mad_recv_wc->recv_buf.mad, len);
- return;
- }
-
- offset = data_offset(mad_recv_wc->recv_buf.mad->mad_hdr.mgmt_class);
-
- list_for_each_entry(seg_buf, &mad_recv_wc->rmpp_list, list) {
- rmpp_mad = (struct ib_rmpp_mad *)seg_buf->mad;
- flags = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr);
-
- if (flags & IB_MGMT_RMPP_FLAG_FIRST) {
- data = rmpp_mad;
- size = sizeof(*rmpp_mad);
- } else {
- data = (void *) rmpp_mad + offset;
- if (flags & IB_MGMT_RMPP_FLAG_LAST)
- size = len;
- else
- size = sizeof(*rmpp_mad) - offset;
- }
-
- memcpy(buf, data, size);
- len -= size;
- buf += size;
- }
-}
-EXPORT_SYMBOL(ib_coalesce_recv_mad);
-
static struct ib_mad_recv_wc *
continue_rmpp(struct ib_mad_agent_private *agent,
struct ib_mad_recv_wc *mad_recv_wc)
@@ -570,50 +532,33 @@ start_rmpp(struct ib_mad_agent_private *agent,
return mad_recv_wc;
}
-static inline u64 get_seg_addr(struct ib_mad_send_wr_private *mad_send_wr)
-{
- return mad_send_wr->sg_list[0].addr + mad_send_wr->data_offset +
- (sizeof(struct ib_rmpp_mad) - mad_send_wr->data_offset) *
- (mad_send_wr->seg_num - 1);
-}
-
static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr)
{
struct ib_rmpp_mad *rmpp_mad;
int timeout;
- u32 paylen;
+ u32 paylen = 0;
rmpp_mad = mad_send_wr->send_buf.mad;
ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE);
- rmpp_mad->rmpp_hdr.seg_num = cpu_to_be32(mad_send_wr->seg_num);
+ rmpp_mad->rmpp_hdr.seg_num = cpu_to_be32(++mad_send_wr->seg_num);
if (mad_send_wr->seg_num == 1) {
rmpp_mad->rmpp_hdr.rmpp_rtime_flags |= IB_MGMT_RMPP_FLAG_FIRST;
- paylen = mad_send_wr->total_seg * IB_MGMT_RMPP_DATA -
+ paylen = mad_send_wr->send_buf.seg_count * IB_MGMT_RMPP_DATA -
mad_send_wr->pad;
- rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(paylen);
- mad_send_wr->sg_list[0].length = sizeof(struct ib_rmpp_mad);
- } else {
- mad_send_wr->send_wr.num_sge = 2;
- mad_send_wr->sg_list[0].length = mad_send_wr->data_offset;
- mad_send_wr->sg_list[1].addr = get_seg_addr(mad_send_wr);
- mad_send_wr->sg_list[1].length = sizeof(struct ib_rmpp_mad) -
- mad_send_wr->data_offset;
- mad_send_wr->sg_list[1].lkey = mad_send_wr->sg_list[0].lkey;
- rmpp_mad->rmpp_hdr.paylen_newwin = 0;
}
- if (mad_send_wr->seg_num == mad_send_wr->total_seg) {
+ if (mad_send_wr->seg_num == mad_send_wr->send_buf.seg_count) {
rmpp_mad->rmpp_hdr.rmpp_rtime_flags |= IB_MGMT_RMPP_FLAG_LAST;
paylen = IB_MGMT_RMPP_DATA - mad_send_wr->pad;
- rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(paylen);
}
+ rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(paylen);
/* 2 seconds for an ACK until we can find the packet lifetime */
timeout = mad_send_wr->send_buf.timeout_ms;
if (!timeout || timeout > 2000)
mad_send_wr->timeout = msecs_to_jiffies(2000);
- mad_send_wr->seg_num++;
+
return ib_send_mad(mad_send_wr);
}
@@ -629,7 +574,7 @@ static void abort_send(struct ib_mad_agent_private *agent, __be64 tid,
if (!mad_send_wr)
goto out; /* Unmatched send */
- if ((mad_send_wr->last_ack == mad_send_wr->total_seg) ||
+ if ((mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) ||
(!mad_send_wr->timeout) || (mad_send_wr->status != IB_WC_SUCCESS))
goto out; /* Send is already done */
@@ -645,6 +590,18 @@ out:
spin_unlock_irqrestore(&agent->lock, flags);
}
+static inline void adjust_last_ack(struct ib_mad_send_wr_private *wr,
+ int seg_num)
+{
+ struct list_head *list;
+
+ wr->last_ack = seg_num;
+ list = &wr->last_ack_seg->list;
+ list_for_each_entry(wr->last_ack_seg, list, list)
+ if (wr->last_ack_seg->num == seg_num)
+ break;
+}
+
static void process_rmpp_ack(struct ib_mad_agent_private *agent,
struct ib_mad_recv_wc *mad_recv_wc)
{
@@ -675,11 +632,12 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent,
if (!mad_send_wr)
goto out; /* Unmatched ACK */
- if ((mad_send_wr->last_ack == mad_send_wr->total_seg) ||
+ if ((mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) ||
(!mad_send_wr->timeout) || (mad_send_wr->status != IB_WC_SUCCESS))
goto out; /* Send is already done */
- if (seg_num > mad_send_wr->total_seg || seg_num > mad_send_wr->newwin) {
+ if (seg_num > mad_send_wr->send_buf.seg_count ||
+ seg_num > mad_send_wr->newwin) {
spin_unlock_irqrestore(&agent->lock, flags);
abort_send(agent, rmpp_mad->mad_hdr.tid,
IB_MGMT_RMPP_STATUS_S2B);
@@ -691,11 +649,11 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent,
goto out; /* Old ACK */
if (seg_num > mad_send_wr->last_ack) {
- mad_send_wr->last_ack = seg_num;
+ adjust_last_ack(mad_send_wr, seg_num);
mad_send_wr->retries = mad_send_wr->send_buf.retries;
}
mad_send_wr->newwin = newwin;
- if (mad_send_wr->last_ack == mad_send_wr->total_seg) {
+ if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) {
/* If no response is expected, the ACK completes the send */
if (!mad_send_wr->send_buf.timeout_ms) {
struct ib_mad_send_wc wc;
@@ -714,7 +672,7 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent,
mad_send_wr->send_buf.timeout_ms);
} else if (mad_send_wr->refcount == 1 &&
mad_send_wr->seg_num < mad_send_wr->newwin &&
- mad_send_wr->seg_num <= mad_send_wr->total_seg) {
+ mad_send_wr->seg_num < mad_send_wr->send_buf.seg_count) {
/* Send failure will just result in a timeout/retry */
ret = send_next_seg(mad_send_wr);
if (ret)
@@ -838,31 +796,19 @@ out:
int ib_send_rmpp_mad(struct ib_mad_send_wr_private *mad_send_wr)
{
struct ib_rmpp_mad *rmpp_mad;
- int i, total_len, ret;
+ int ret;
rmpp_mad = mad_send_wr->send_buf.mad;
if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
IB_MGMT_RMPP_FLAG_ACTIVE))
return IB_RMPP_RESULT_UNHANDLED;
- if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA)
+ if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA) {
+ mad_send_wr->seg_num = 1;
return IB_RMPP_RESULT_INTERNAL;
+ }
- if (mad_send_wr->send_wr.num_sge > 1)
- return -EINVAL; /* TODO: support num_sge > 1 */
-
- mad_send_wr->seg_num = 1;
mad_send_wr->newwin = 1;
- mad_send_wr->data_offset = data_offset(rmpp_mad->mad_hdr.mgmt_class);
-
- total_len = 0;
- for (i = 0; i < mad_send_wr->send_wr.num_sge; i++)
- total_len += mad_send_wr->send_wr.sg_list[i].length;
-
- mad_send_wr->total_seg = (total_len - mad_send_wr->data_offset) /
- (sizeof(struct ib_rmpp_mad) - mad_send_wr->data_offset);
- mad_send_wr->pad = total_len - IB_MGMT_RMPP_HDR -
- be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin);
/* We need to wait for the final ACK even if there isn't a response */
mad_send_wr->refcount += (mad_send_wr->timeout == 0);
@@ -893,14 +839,14 @@ int ib_process_rmpp_send_wc(struct ib_mad_send_wr_private *mad_send_wr,
if (!mad_send_wr->timeout)
return IB_RMPP_RESULT_PROCESSED; /* Response received */
- if (mad_send_wr->last_ack == mad_send_wr->total_seg) {
+ if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) {
mad_send_wr->timeout =
msecs_to_jiffies(mad_send_wr->send_buf.timeout_ms);
return IB_RMPP_RESULT_PROCESSED; /* Send done */
}
- if (mad_send_wr->seg_num > mad_send_wr->newwin ||
- mad_send_wr->seg_num > mad_send_wr->total_seg)
+ if (mad_send_wr->seg_num == mad_send_wr->newwin ||
+ mad_send_wr->seg_num == mad_send_wr->send_buf.seg_count)
return IB_RMPP_RESULT_PROCESSED; /* Wait for ACK */
ret = send_next_seg(mad_send_wr);
@@ -921,10 +867,12 @@ int ib_retry_rmpp(struct ib_mad_send_wr_private *mad_send_wr)
IB_MGMT_RMPP_FLAG_ACTIVE))
return IB_RMPP_RESULT_UNHANDLED; /* RMPP not active */
- if (mad_send_wr->last_ack == mad_send_wr->total_seg)
+ if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count)
return IB_RMPP_RESULT_PROCESSED;
- mad_send_wr->seg_num = mad_send_wr->last_ack + 1;
+ mad_send_wr->seg_num = mad_send_wr->last_ack;
+ mad_send_wr->cur_seg = mad_send_wr->last_ack_seg;
+
ret = send_next_seg(mad_send_wr);
if (ret)
return IB_RMPP_RESULT_PROCESSED;
diff --git a/drivers/infiniband/core/smi.h b/drivers/infiniband/core/smi.h
index 2b3c40198f8..3011bfd86dc 100644
--- a/drivers/infiniband/core/smi.h
+++ b/drivers/infiniband/core/smi.h
@@ -49,19 +49,16 @@ extern int smi_check_forward_dr_smp(struct ib_smp *smp);
extern int smi_handle_dr_smp_send(struct ib_smp *smp,
u8 node_type,
int port_num);
-extern int smi_check_local_dr_smp(struct ib_smp *smp,
- struct ib_device *device,
- int port_num);
/*
* Return 1 if the SMP should be handled by the local SMA/SM via process_mad
*/
-static inline int smi_check_local_smp(struct ib_mad_agent *mad_agent,
- struct ib_smp *smp)
+static inline int smi_check_local_smp(struct ib_smp *smp,
+ struct ib_device *device)
{
/* C14-9:3 -- We're at the end of the DR segment of path */
/* C14-9:4 -- Hop Pointer = Hop Count + 1 -> give to SMA/SM */
- return ((mad_agent->device->process_mad &&
+ return ((device->process_mad &&
!ib_get_smp_direction(smp) &&
(smp->hop_ptr == smp->hop_cnt + 1)));
}
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index 5982d687a00..15121cb5a1f 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -112,7 +112,7 @@ static ssize_t state_show(struct ib_port *p, struct port_attribute *unused,
return ret;
return sprintf(buf, "%d: %s\n", attr.state,
- attr.state >= 0 && attr.state <= ARRAY_SIZE(state_name) ?
+ attr.state >= 0 && attr.state < ARRAY_SIZE(state_name) ?
state_name[attr.state] : "UNKNOWN");
}
@@ -472,8 +472,10 @@ alloc_group_attrs(ssize_t (*show)(struct ib_port *,
goto err;
if (snprintf(element->name, sizeof(element->name),
- "%d", i) >= sizeof(element->name))
+ "%d", i) >= sizeof(element->name)) {
+ kfree(element);
goto err;
+ }
element->attr.attr.name = element->name;
element->attr.attr.mode = S_IRUGO;
@@ -628,14 +630,42 @@ static ssize_t show_node_guid(struct class_device *cdev, char *buf)
be16_to_cpu(((__be16 *) &dev->node_guid)[3]));
}
+static ssize_t show_node_desc(struct class_device *cdev, char *buf)
+{
+ struct ib_device *dev = container_of(cdev, struct ib_device, class_dev);
+
+ return sprintf(buf, "%.64s\n", dev->node_desc);
+}
+
+static ssize_t set_node_desc(struct class_device *cdev, const char *buf,
+ size_t count)
+{
+ struct ib_device *dev = container_of(cdev, struct ib_device, class_dev);
+ struct ib_device_modify desc = {};
+ int ret;
+
+ if (!dev->modify_device)
+ return -EIO;
+
+ memcpy(desc.node_desc, buf, min_t(int, count, 64));
+ ret = ib_modify_device(dev, IB_DEVICE_MODIFY_NODE_DESC, &desc);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
static CLASS_DEVICE_ATTR(node_type, S_IRUGO, show_node_type, NULL);
static CLASS_DEVICE_ATTR(sys_image_guid, S_IRUGO, show_sys_image_guid, NULL);
static CLASS_DEVICE_ATTR(node_guid, S_IRUGO, show_node_guid, NULL);
+static CLASS_DEVICE_ATTR(node_desc, S_IRUGO | S_IWUSR, show_node_desc,
+ set_node_desc);
static struct class_device_attribute *ib_class_attributes[] = {
&class_device_attr_node_type,
&class_device_attr_sys_image_guid,
- &class_device_attr_node_guid
+ &class_device_attr_node_guid,
+ &class_device_attr_node_desc
};
static struct class ib_class = {
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index c908de8db5a..fb6cd42601f 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -31,7 +31,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
- * $Id: user_mad.c 4010 2005-11-09 23:11:56Z roland $
+ * $Id: user_mad.c 5596 2006-03-03 01:00:07Z sean.hefty $
*/
#include <linux/module.h>
@@ -121,6 +121,7 @@ struct ib_umad_file {
struct ib_umad_packet {
struct ib_mad_send_buf *msg;
+ struct ib_mad_recv_wc *recv_wc;
struct list_head list;
int length;
struct ib_user_mad mad;
@@ -176,31 +177,32 @@ static int queue_packet(struct ib_umad_file *file,
return ret;
}
+static int data_offset(u8 mgmt_class)
+{
+ if (mgmt_class == IB_MGMT_CLASS_SUBN_ADM)
+ return IB_MGMT_SA_HDR;
+ else if ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) &&
+ (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END))
+ return IB_MGMT_VENDOR_HDR;
+ else
+ return IB_MGMT_RMPP_HDR;
+}
+
static void send_handler(struct ib_mad_agent *agent,
struct ib_mad_send_wc *send_wc)
{
struct ib_umad_file *file = agent->context;
- struct ib_umad_packet *timeout;
struct ib_umad_packet *packet = send_wc->send_buf->context[0];
ib_destroy_ah(packet->msg->ah);
ib_free_send_mad(packet->msg);
if (send_wc->status == IB_WC_RESP_TIMEOUT_ERR) {
- timeout = kzalloc(sizeof *timeout + IB_MGMT_MAD_HDR, GFP_KERNEL);
- if (!timeout)
- goto out;
-
- timeout->length = IB_MGMT_MAD_HDR;
- timeout->mad.hdr.id = packet->mad.hdr.id;
- timeout->mad.hdr.status = ETIMEDOUT;
- memcpy(timeout->mad.data, packet->mad.data,
- sizeof (struct ib_mad_hdr));
-
- if (queue_packet(file, agent, timeout))
- kfree(timeout);
+ packet->length = IB_MGMT_MAD_HDR;
+ packet->mad.hdr.status = ETIMEDOUT;
+ if (!queue_packet(file, agent, packet))
+ return;
}
-out:
kfree(packet);
}
@@ -209,22 +211,20 @@ static void recv_handler(struct ib_mad_agent *agent,
{
struct ib_umad_file *file = agent->context;
struct ib_umad_packet *packet;
- int length;
if (mad_recv_wc->wc->status != IB_WC_SUCCESS)
- goto out;
+ goto err1;
- length = mad_recv_wc->mad_len;
- packet = kzalloc(sizeof *packet + length, GFP_KERNEL);
+ packet = kzalloc(sizeof *packet, GFP_KERNEL);
if (!packet)
- goto out;
+ goto err1;
- packet->length = length;
-
- ib_coalesce_recv_mad(mad_recv_wc, packet->mad.data);
+ packet->length = mad_recv_wc->mad_len;
+ packet->recv_wc = mad_recv_wc;
packet->mad.hdr.status = 0;
- packet->mad.hdr.length = length + sizeof (struct ib_user_mad);
+ packet->mad.hdr.length = sizeof (struct ib_user_mad) +
+ mad_recv_wc->mad_len;
packet->mad.hdr.qpn = cpu_to_be32(mad_recv_wc->wc->src_qp);
packet->mad.hdr.lid = cpu_to_be16(mad_recv_wc->wc->slid);
packet->mad.hdr.sl = mad_recv_wc->wc->sl;
@@ -240,12 +240,79 @@ static void recv_handler(struct ib_mad_agent *agent,
}
if (queue_packet(file, agent, packet))
- kfree(packet);
+ goto err2;
+ return;
-out:
+err2:
+ kfree(packet);
+err1:
ib_free_recv_mad(mad_recv_wc);
}
+static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet,
+ size_t count)
+{
+ struct ib_mad_recv_buf *recv_buf;
+ int left, seg_payload, offset, max_seg_payload;
+
+ /* We need enough room to copy the first (or only) MAD segment. */
+ recv_buf = &packet->recv_wc->recv_buf;
+ if ((packet->length <= sizeof (*recv_buf->mad) &&
+ count < sizeof (packet->mad) + packet->length) ||
+ (packet->length > sizeof (*recv_buf->mad) &&
+ count < sizeof (packet->mad) + sizeof (*recv_buf->mad)))
+ return -EINVAL;
+
+ if (copy_to_user(buf, &packet->mad, sizeof (packet->mad)))
+ return -EFAULT;
+
+ buf += sizeof (packet->mad);
+ seg_payload = min_t(int, packet->length, sizeof (*recv_buf->mad));
+ if (copy_to_user(buf, recv_buf->mad, seg_payload))
+ return -EFAULT;
+
+ if (seg_payload < packet->length) {
+ /*
+ * Multipacket RMPP MAD message. Copy remainder of message.
+ * Note that last segment may have a shorter payload.
+ */
+ if (count < sizeof (packet->mad) + packet->length) {
+ /*
+ * The buffer is too small, return the first RMPP segment,
+ * which includes the RMPP message length.
+ */
+ return -ENOSPC;
+ }
+ offset = data_offset(recv_buf->mad->mad_hdr.mgmt_class);
+ max_seg_payload = sizeof (struct ib_mad) - offset;
+
+ for (left = packet->length - seg_payload, buf += seg_payload;
+ left; left -= seg_payload, buf += seg_payload) {
+ recv_buf = container_of(recv_buf->list.next,
+ struct ib_mad_recv_buf, list);
+ seg_payload = min(left, max_seg_payload);
+ if (copy_to_user(buf, ((void *) recv_buf->mad) + offset,
+ seg_payload))
+ return -EFAULT;
+ }
+ }
+ return sizeof (packet->mad) + packet->length;
+}
+
+static ssize_t copy_send_mad(char __user *buf, struct ib_umad_packet *packet,
+ size_t count)
+{
+ ssize_t size = sizeof (packet->mad) + packet->length;
+
+ if (count < size)
+ return -EINVAL;
+
+ if (copy_to_user(buf, &packet->mad, size))
+ return -EFAULT;
+
+ return size;
+}
+
static ssize_t ib_umad_read(struct file *filp, char __user *buf,
size_t count, loff_t *pos)
{
@@ -253,7 +320,7 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
struct ib_umad_packet *packet;
ssize_t ret;
- if (count < sizeof (struct ib_user_mad) + sizeof (struct ib_mad))
+ if (count < sizeof (struct ib_user_mad))
return -EINVAL;
spin_lock_irq(&file->recv_lock);
@@ -276,28 +343,44 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
spin_unlock_irq(&file->recv_lock);
- if (count < packet->length + sizeof (struct ib_user_mad)) {
- /* Return length needed (and first RMPP segment) if too small */
- if (copy_to_user(buf, &packet->mad,
- sizeof (struct ib_user_mad) + sizeof (struct ib_mad)))
- ret = -EFAULT;
- else
- ret = -ENOSPC;
- } else if (copy_to_user(buf, &packet->mad,
- packet->length + sizeof (struct ib_user_mad)))
- ret = -EFAULT;
+ if (packet->recv_wc)
+ ret = copy_recv_mad(buf, packet, count);
else
- ret = packet->length + sizeof (struct ib_user_mad);
+ ret = copy_send_mad(buf, packet, count);
+
if (ret < 0) {
/* Requeue packet */
spin_lock_irq(&file->recv_lock);
list_add(&packet->list, &file->recv_list);
spin_unlock_irq(&file->recv_lock);
- } else
+ } else {
+ if (packet->recv_wc)
+ ib_free_recv_mad(packet->recv_wc);
kfree(packet);
+ }
return ret;
}
+static int copy_rmpp_mad(struct ib_mad_send_buf *msg, const char __user *buf)
+{
+ int left, seg;
+
+ /* Copy class specific header */
+ if ((msg->hdr_len > IB_MGMT_RMPP_HDR) &&
+ copy_from_user(msg->mad + IB_MGMT_RMPP_HDR, buf + IB_MGMT_RMPP_HDR,
+ msg->hdr_len - IB_MGMT_RMPP_HDR))
+ return -EFAULT;
+
+ /* All headers are in place. Copy data segments. */
+ for (seg = 1, left = msg->data_len, buf += msg->hdr_len; left > 0;
+ seg++, left -= msg->seg_size, buf += msg->seg_size) {
+ if (copy_from_user(ib_get_rmpp_segment(msg, seg), buf,
+ min(left, msg->seg_size)))
+ return -EFAULT;
+ }
+ return 0;
+}
+
static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
size_t count, loff_t *pos)
{
@@ -309,14 +392,12 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
struct ib_rmpp_mad *rmpp_mad;
u8 method;
__be64 *tid;
- int ret, length, hdr_len, copy_offset;
- int rmpp_active, has_rmpp_header;
+ int ret, data_len, hdr_len, copy_offset, rmpp_active;
if (count < sizeof (struct ib_user_mad) + IB_MGMT_RMPP_HDR)
return -EINVAL;
- length = count - sizeof (struct ib_user_mad);
- packet = kmalloc(sizeof *packet + IB_MGMT_RMPP_HDR, GFP_KERNEL);
+ packet = kzalloc(sizeof *packet + IB_MGMT_RMPP_HDR, GFP_KERNEL);
if (!packet)
return -ENOMEM;
@@ -363,35 +444,25 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
if (rmpp_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_ADM) {
hdr_len = IB_MGMT_SA_HDR;
copy_offset = IB_MGMT_RMPP_HDR;
- has_rmpp_header = 1;
+ rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
+ IB_MGMT_RMPP_FLAG_ACTIVE;
} else if (rmpp_mad->mad_hdr.mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START &&
rmpp_mad->mad_hdr.mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END) {
- hdr_len = IB_MGMT_VENDOR_HDR;
- copy_offset = IB_MGMT_RMPP_HDR;
- has_rmpp_header = 1;
+ hdr_len = IB_MGMT_VENDOR_HDR;
+ copy_offset = IB_MGMT_RMPP_HDR;
+ rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
+ IB_MGMT_RMPP_FLAG_ACTIVE;
} else {
hdr_len = IB_MGMT_MAD_HDR;
copy_offset = IB_MGMT_MAD_HDR;
- has_rmpp_header = 0;
- }
-
- if (has_rmpp_header)
- rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
- IB_MGMT_RMPP_FLAG_ACTIVE;
- else
rmpp_active = 0;
-
- /* Validate that the management class can support RMPP */
- if (rmpp_active && !agent->rmpp_version) {
- ret = -EINVAL;
- goto err_ah;
}
+ data_len = count - sizeof (struct ib_user_mad) - hdr_len;
packet->msg = ib_create_send_mad(agent,
be32_to_cpu(packet->mad.hdr.qpn),
- 0, rmpp_active,
- hdr_len, length - hdr_len,
- GFP_KERNEL);
+ 0, rmpp_active, hdr_len,
+ data_len, GFP_KERNEL);
if (IS_ERR(packet->msg)) {
ret = PTR_ERR(packet->msg);
goto err_ah;
@@ -402,14 +473,21 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
packet->msg->retries = packet->mad.hdr.retries;
packet->msg->context[0] = packet;
- /* Copy MAD headers (RMPP header in place) */
+ /* Copy MAD header. Any RMPP header is already in place. */
memcpy(packet->msg->mad, packet->mad.data, IB_MGMT_MAD_HDR);
- /* Now, copy rest of message from user into send buffer */
- if (copy_from_user(packet->msg->mad + copy_offset,
- buf + sizeof (struct ib_user_mad) + copy_offset,
- length - copy_offset)) {
- ret = -EFAULT;
- goto err_msg;
+ buf += sizeof (struct ib_user_mad);
+
+ if (!rmpp_active) {
+ if (copy_from_user(packet->msg->mad + copy_offset,
+ buf + copy_offset,
+ hdr_len + data_len - copy_offset)) {
+ ret = -EFAULT;
+ goto err_msg;
+ }
+ } else {
+ ret = copy_rmpp_mad(packet->msg, buf);
+ if (ret)
+ goto err_msg;
}
/*
@@ -433,18 +511,14 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
goto err_msg;
up_read(&file->port->mutex);
-
return count;
err_msg:
ib_free_send_mad(packet->msg);
-
err_ah:
ib_destroy_ah(ah);
-
err_up:
up_read(&file->port->mutex);
-
err:
kfree(packet);
return ret;
@@ -627,8 +701,11 @@ static int ib_umad_close(struct inode *inode, struct file *filp)
already_dead = file->agents_dead;
file->agents_dead = 1;
- list_for_each_entry_safe(packet, tmp, &file->recv_list, list)
+ list_for_each_entry_safe(packet, tmp, &file->recv_list, list) {
+ if (packet->recv_wc)
+ ib_free_recv_mad(packet->recv_wc);
kfree(packet);
+ }
list_del(&file->port_list);
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index f7eecbc6af6..3372d67ff13 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2005 Topspin Communications. All rights reserved.
- * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved.
* Copyright (c) 2005 Mellanox Technologies. All rights reserved.
* Copyright (c) 2005 Voltaire, Inc. All rights reserved.
* Copyright (c) 2005 PathScale, Inc. All rights reserved.
@@ -178,10 +178,12 @@ IB_UVERBS_DECLARE_CMD(reg_mr);
IB_UVERBS_DECLARE_CMD(dereg_mr);
IB_UVERBS_DECLARE_CMD(create_comp_channel);
IB_UVERBS_DECLARE_CMD(create_cq);
+IB_UVERBS_DECLARE_CMD(resize_cq);
IB_UVERBS_DECLARE_CMD(poll_cq);
IB_UVERBS_DECLARE_CMD(req_notify_cq);
IB_UVERBS_DECLARE_CMD(destroy_cq);
IB_UVERBS_DECLARE_CMD(create_qp);
+IB_UVERBS_DECLARE_CMD(query_qp);
IB_UVERBS_DECLARE_CMD(modify_qp);
IB_UVERBS_DECLARE_CMD(destroy_qp);
IB_UVERBS_DECLARE_CMD(post_send);
@@ -193,6 +195,7 @@ IB_UVERBS_DECLARE_CMD(attach_mcast);
IB_UVERBS_DECLARE_CMD(detach_mcast);
IB_UVERBS_DECLARE_CMD(create_srq);
IB_UVERBS_DECLARE_CMD(modify_srq);
+IB_UVERBS_DECLARE_CMD(query_srq);
IB_UVERBS_DECLARE_CMD(destroy_srq);
#endif /* UVERBS_H */
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 407b6284d7d..9f69bd48eb1 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -1,7 +1,8 @@
/*
* Copyright (c) 2005 Topspin Communications. All rights reserved.
- * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved.
* Copyright (c) 2005 PathScale, Inc. All rights reserved.
+ * Copyright (c) 2006 Mellanox Technologies. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -675,6 +676,46 @@ err:
return ret;
}
+ssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len)
+{
+ struct ib_uverbs_resize_cq cmd;
+ struct ib_uverbs_resize_cq_resp resp;
+ struct ib_udata udata;
+ struct ib_cq *cq;
+ int ret = -EINVAL;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ INIT_UDATA(&udata, buf + sizeof cmd,
+ (unsigned long) cmd.response + sizeof resp,
+ in_len - sizeof cmd, out_len - sizeof resp);
+
+ mutex_lock(&ib_uverbs_idr_mutex);
+
+ cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle);
+ if (!cq || cq->uobject->context != file->ucontext || !cq->device->resize_cq)
+ goto out;
+
+ ret = cq->device->resize_cq(cq, cmd.cqe, &udata);
+ if (ret)
+ goto out;
+
+ memset(&resp, 0, sizeof resp);
+ resp.cqe = cq->cqe;
+
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+ &resp, sizeof resp))
+ ret = -EFAULT;
+
+out:
+ mutex_unlock(&ib_uverbs_idr_mutex);
+
+ return ret ? ret : in_len;
+}
+
ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
const char __user *buf, int in_len,
int out_len)
@@ -956,6 +997,106 @@ err_up:
return ret;
}
+ssize_t ib_uverbs_query_qp(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len)
+{
+ struct ib_uverbs_query_qp cmd;
+ struct ib_uverbs_query_qp_resp resp;
+ struct ib_qp *qp;
+ struct ib_qp_attr *attr;
+ struct ib_qp_init_attr *init_attr;
+ int ret;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ attr = kmalloc(sizeof *attr, GFP_KERNEL);
+ init_attr = kmalloc(sizeof *init_attr, GFP_KERNEL);
+ if (!attr || !init_attr) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ mutex_lock(&ib_uverbs_idr_mutex);
+
+ qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
+ if (qp && qp->uobject->context == file->ucontext)
+ ret = ib_query_qp(qp, attr, cmd.attr_mask, init_attr);
+ else
+ ret = -EINVAL;
+
+ mutex_unlock(&ib_uverbs_idr_mutex);
+
+ if (ret)
+ goto out;
+
+ memset(&resp, 0, sizeof resp);
+
+ resp.qp_state = attr->qp_state;
+ resp.cur_qp_state = attr->cur_qp_state;
+ resp.path_mtu = attr->path_mtu;
+ resp.path_mig_state = attr->path_mig_state;
+ resp.qkey = attr->qkey;
+ resp.rq_psn = attr->rq_psn;
+ resp.sq_psn = attr->sq_psn;
+ resp.dest_qp_num = attr->dest_qp_num;
+ resp.qp_access_flags = attr->qp_access_flags;
+ resp.pkey_index = attr->pkey_index;
+ resp.alt_pkey_index = attr->alt_pkey_index;
+ resp.en_sqd_async_notify = attr->en_sqd_async_notify;
+ resp.max_rd_atomic = attr->max_rd_atomic;
+ resp.max_dest_rd_atomic = attr->max_dest_rd_atomic;
+ resp.min_rnr_timer = attr->min_rnr_timer;
+ resp.port_num = attr->port_num;
+ resp.timeout = attr->timeout;
+ resp.retry_cnt = attr->retry_cnt;
+ resp.rnr_retry = attr->rnr_retry;
+ resp.alt_port_num = attr->alt_port_num;
+ resp.alt_timeout = attr->alt_timeout;
+
+ memcpy(resp.dest.dgid, attr->ah_attr.grh.dgid.raw, 16);
+ resp.dest.flow_label = attr->ah_attr.grh.flow_label;
+ resp.dest.sgid_index = attr->ah_attr.grh.sgid_index;
+ resp.dest.hop_limit = attr->ah_attr.grh.hop_limit;
+ resp.dest.traffic_class = attr->ah_attr.grh.traffic_class;
+ resp.dest.dlid = attr->ah_attr.dlid;
+ resp.dest.sl = attr->ah_attr.sl;
+ resp.dest.src_path_bits = attr->ah_attr.src_path_bits;
+ resp.dest.static_rate = attr->ah_attr.static_rate;
+ resp.dest.is_global = !!(attr->ah_attr.ah_flags & IB_AH_GRH);
+ resp.dest.port_num = attr->ah_attr.port_num;
+
+ memcpy(resp.alt_dest.dgid, attr->alt_ah_attr.grh.dgid.raw, 16);
+ resp.alt_dest.flow_label = attr->alt_ah_attr.grh.flow_label;
+ resp.alt_dest.sgid_index = attr->alt_ah_attr.grh.sgid_index;
+ resp.alt_dest.hop_limit = attr->alt_ah_attr.grh.hop_limit;
+ resp.alt_dest.traffic_class = attr->alt_ah_attr.grh.traffic_class;
+ resp.alt_dest.dlid = attr->alt_ah_attr.dlid;
+ resp.alt_dest.sl = attr->alt_ah_attr.sl;
+ resp.alt_dest.src_path_bits = attr->alt_ah_attr.src_path_bits;
+ resp.alt_dest.static_rate = attr->alt_ah_attr.static_rate;
+ resp.alt_dest.is_global = !!(attr->alt_ah_attr.ah_flags & IB_AH_GRH);
+ resp.alt_dest.port_num = attr->alt_ah_attr.port_num;
+
+ resp.max_send_wr = init_attr->cap.max_send_wr;
+ resp.max_recv_wr = init_attr->cap.max_recv_wr;
+ resp.max_send_sge = init_attr->cap.max_send_sge;
+ resp.max_recv_sge = init_attr->cap.max_recv_sge;
+ resp.max_inline_data = init_attr->cap.max_inline_data;
+ resp.sq_sig_all = init_attr->sq_sig_type == IB_SIGNAL_ALL_WR;
+
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+ &resp, sizeof resp))
+ ret = -EFAULT;
+
+out:
+ kfree(attr);
+ kfree(init_attr);
+
+ return ret ? ret : in_len;
+}
+
ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
const char __user *buf, int in_len,
int out_len)
@@ -990,7 +1131,7 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
attr->dest_qp_num = cmd.dest_qp_num;
attr->qp_access_flags = cmd.qp_access_flags;
attr->pkey_index = cmd.pkey_index;
- attr->alt_pkey_index = cmd.pkey_index;
+ attr->alt_pkey_index = cmd.alt_pkey_index;
attr->en_sqd_async_notify = cmd.en_sqd_async_notify;
attr->max_rd_atomic = cmd.max_rd_atomic;
attr->max_dest_rd_atomic = cmd.max_dest_rd_atomic;
@@ -1094,8 +1235,8 @@ out:
}
ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
- const char __user *buf, int in_len,
- int out_len)
+ const char __user *buf, int in_len,
+ int out_len)
{
struct ib_uverbs_post_send cmd;
struct ib_uverbs_post_send_resp resp;
@@ -1323,8 +1464,8 @@ err:
}
ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file,
- const char __user *buf, int in_len,
- int out_len)
+ const char __user *buf, int in_len,
+ int out_len)
{
struct ib_uverbs_post_recv cmd;
struct ib_uverbs_post_recv_resp resp;
@@ -1374,8 +1515,8 @@ out:
}
ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file,
- const char __user *buf, int in_len,
- int out_len)
+ const char __user *buf, int in_len,
+ int out_len)
{
struct ib_uverbs_post_srq_recv cmd;
struct ib_uverbs_post_srq_recv_resp resp;
@@ -1723,6 +1864,8 @@ retry:
goto err_destroy;
resp.srq_handle = uobj->uobject.id;
+ resp.max_wr = attr.attr.max_wr;
+ resp.max_sge = attr.attr.max_sge;
if (copy_to_user((void __user *) (unsigned long) cmd.response,
&resp, sizeof resp)) {
@@ -1783,6 +1926,49 @@ out:
return ret ? ret : in_len;
}
+ssize_t ib_uverbs_query_srq(struct ib_uverbs_file *file,
+ const char __user *buf,
+ int in_len, int out_len)
+{
+ struct ib_uverbs_query_srq cmd;
+ struct ib_uverbs_query_srq_resp resp;
+ struct ib_srq_attr attr;
+ struct ib_srq *srq;
+ int ret;
+
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ mutex_lock(&ib_uverbs_idr_mutex);
+
+ srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle);
+ if (srq && srq->uobject->context == file->ucontext)
+ ret = ib_query_srq(srq, &attr);
+ else
+ ret = -EINVAL;
+
+ mutex_unlock(&ib_uverbs_idr_mutex);
+
+ if (ret)
+ goto out;
+
+ memset(&resp, 0, sizeof resp);
+
+ resp.max_wr = attr.max_wr;
+ resp.max_sge = attr.max_sge;
+ resp.srq_limit = attr.srq_limit;
+
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+ &resp, sizeof resp))
+ ret = -EFAULT;
+
+out:
+ return ret ? ret : in_len;
+}
+
ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
const char __user *buf, int in_len,
int out_len)
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index 903f85a4bc0..ff092a0a94d 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2005 Topspin Communications. All rights reserved.
- * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved.
* Copyright (c) 2005 Mellanox Technologies. All rights reserved.
* Copyright (c) 2005 Voltaire, Inc. All rights reserved.
* Copyright (c) 2005 PathScale, Inc. All rights reserved.
@@ -91,10 +91,12 @@ static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file,
[IB_USER_VERBS_CMD_DEREG_MR] = ib_uverbs_dereg_mr,
[IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL] = ib_uverbs_create_comp_channel,
[IB_USER_VERBS_CMD_CREATE_CQ] = ib_uverbs_create_cq,
+ [IB_USER_VERBS_CMD_RESIZE_CQ] = ib_uverbs_resize_cq,
[IB_USER_VERBS_CMD_POLL_CQ] = ib_uverbs_poll_cq,
[IB_USER_VERBS_CMD_REQ_NOTIFY_CQ] = ib_uverbs_req_notify_cq,
[IB_USER_VERBS_CMD_DESTROY_CQ] = ib_uverbs_destroy_cq,
[IB_USER_VERBS_CMD_CREATE_QP] = ib_uverbs_create_qp,
+ [IB_USER_VERBS_CMD_QUERY_QP] = ib_uverbs_query_qp,
[IB_USER_VERBS_CMD_MODIFY_QP] = ib_uverbs_modify_qp,
[IB_USER_VERBS_CMD_DESTROY_QP] = ib_uverbs_destroy_qp,
[IB_USER_VERBS_CMD_POST_SEND] = ib_uverbs_post_send,
@@ -106,6 +108,7 @@ static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file,
[IB_USER_VERBS_CMD_DETACH_MCAST] = ib_uverbs_detach_mcast,
[IB_USER_VERBS_CMD_CREATE_SRQ] = ib_uverbs_create_srq,
[IB_USER_VERBS_CMD_MODIFY_SRQ] = ib_uverbs_modify_srq,
+ [IB_USER_VERBS_CMD_QUERY_SRQ] = ib_uverbs_query_srq,
[IB_USER_VERBS_CMD_DESTROY_SRQ] = ib_uverbs_destroy_srq,
};
@@ -461,7 +464,6 @@ void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr)
ib_uverbs_async_handler(uobj->uverbs_file, uobj->uobject.user_handle,
event->event, &uobj->async_list,
&uobj->async_events_reported);
-
}
void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr)
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index c857361be44..cae0845f472 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -5,7 +5,7 @@
* Copyright (c) 2004 Topspin Corporation. All rights reserved.
* Copyright (c) 2004 Voltaire Corporation. All rights reserved.
* Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
- * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -245,6 +245,258 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd,
}
EXPORT_SYMBOL(ib_create_qp);
+static const struct {
+ int valid;
+ enum ib_qp_attr_mask req_param[IB_QPT_RAW_ETY + 1];
+ enum ib_qp_attr_mask opt_param[IB_QPT_RAW_ETY + 1];
+} qp_state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
+ [IB_QPS_RESET] = {
+ [IB_QPS_RESET] = { .valid = 1 },
+ [IB_QPS_ERR] = { .valid = 1 },
+ [IB_QPS_INIT] = {
+ .valid = 1,
+ .req_param = {
+ [IB_QPT_UD] = (IB_QP_PKEY_INDEX |
+ IB_QP_PORT |
+ IB_QP_QKEY),
+ [IB_QPT_UC] = (IB_QP_PKEY_INDEX |
+ IB_QP_PORT |
+ IB_QP_ACCESS_FLAGS),
+ [IB_QPT_RC] = (IB_QP_PKEY_INDEX |
+ IB_QP_PORT |
+ IB_QP_ACCESS_FLAGS),
+ [IB_QPT_SMI] = (IB_QP_PKEY_INDEX |
+ IB_QP_QKEY),
+ [IB_QPT_GSI] = (IB_QP_PKEY_INDEX |
+ IB_QP_QKEY),
+ }
+ },
+ },
+ [IB_QPS_INIT] = {
+ [IB_QPS_RESET] = { .valid = 1 },
+ [IB_QPS_ERR] = { .valid = 1 },
+ [IB_QPS_INIT] = {
+ .valid = 1,
+ .opt_param = {
+ [IB_QPT_UD] = (IB_QP_PKEY_INDEX |
+ IB_QP_PORT |
+ IB_QP_QKEY),
+ [IB_QPT_UC] = (IB_QP_PKEY_INDEX |
+ IB_QP_PORT |
+ IB_QP_ACCESS_FLAGS),
+ [IB_QPT_RC] = (IB_QP_PKEY_INDEX |
+ IB_QP_PORT |
+ IB_QP_ACCESS_FLAGS),
+ [IB_QPT_SMI] = (IB_QP_PKEY_INDEX |
+ IB_QP_QKEY),
+ [IB_QPT_GSI] = (IB_QP_PKEY_INDEX |
+ IB_QP_QKEY),
+ }
+ },
+ [IB_QPS_RTR] = {
+ .valid = 1,
+ .req_param = {
+ [IB_QPT_UC] = (IB_QP_AV |
+ IB_QP_PATH_MTU |
+ IB_QP_DEST_QPN |
+ IB_QP_RQ_PSN),
+ [IB_QPT_RC] = (IB_QP_AV |
+ IB_QP_PATH_MTU |
+ IB_QP_DEST_QPN |
+ IB_QP_RQ_PSN |
+ IB_QP_MAX_DEST_RD_ATOMIC |
+ IB_QP_MIN_RNR_TIMER),
+ },
+ .opt_param = {
+ [IB_QPT_UD] = (IB_QP_PKEY_INDEX |
+ IB_QP_QKEY),
+ [IB_QPT_UC] = (IB_QP_ALT_PATH |
+ IB_QP_ACCESS_FLAGS |
+ IB_QP_PKEY_INDEX),
+ [IB_QPT_RC] = (IB_QP_ALT_PATH |
+ IB_QP_ACCESS_FLAGS |
+ IB_QP_PKEY_INDEX),
+ [IB_QPT_SMI] = (IB_QP_PKEY_INDEX |
+ IB_QP_QKEY),
+ [IB_QPT_GSI] = (IB_QP_PKEY_INDEX |
+ IB_QP_QKEY),
+ }
+ }
+ },
+ [IB_QPS_RTR] = {
+ [IB_QPS_RESET] = { .valid = 1 },
+ [IB_QPS_ERR] = { .valid = 1 },
+ [IB_QPS_RTS] = {
+ .valid = 1,
+ .req_param = {
+ [IB_QPT_UD] = IB_QP_SQ_PSN,
+ [IB_QPT_UC] = IB_QP_SQ_PSN,
+ [IB_QPT_RC] = (IB_QP_TIMEOUT |
+ IB_QP_RETRY_CNT |
+ IB_QP_RNR_RETRY |
+ IB_QP_SQ_PSN |
+ IB_QP_MAX_QP_RD_ATOMIC),
+ [IB_QPT_SMI] = IB_QP_SQ_PSN,
+ [IB_QPT_GSI] = IB_QP_SQ_PSN,
+ },
+ .opt_param = {
+ [IB_QPT_UD] = (IB_QP_CUR_STATE |
+ IB_QP_QKEY),
+ [IB_QPT_UC] = (IB_QP_CUR_STATE |
+ IB_QP_ALT_PATH |
+ IB_QP_ACCESS_FLAGS |
+ IB_QP_PATH_MIG_STATE),
+ [IB_QPT_RC] = (IB_QP_CUR_STATE |
+ IB_QP_ALT_PATH |
+ IB_QP_ACCESS_FLAGS |
+ IB_QP_MIN_RNR_TIMER |
+ IB_QP_PATH_MIG_STATE),
+ [IB_QPT_SMI] = (IB_QP_CUR_STATE |
+ IB_QP_QKEY),
+ [IB_QPT_GSI] = (IB_QP_CUR_STATE |
+ IB_QP_QKEY),
+ }
+ }
+ },
+ [IB_QPS_RTS] = {
+ [IB_QPS_RESET] = { .valid = 1 },
+ [IB_QPS_ERR] = { .valid = 1 },
+ [IB_QPS_RTS] = {
+ .valid = 1,
+ .opt_param = {
+ [IB_QPT_UD] = (IB_QP_CUR_STATE |
+ IB_QP_QKEY),
+ [IB_QPT_UC] = (IB_QP_CUR_STATE |
+ IB_QP_ACCESS_FLAGS |
+ IB_QP_ALT_PATH |
+ IB_QP_PATH_MIG_STATE),
+ [IB_QPT_RC] = (IB_QP_CUR_STATE |
+ IB_QP_ACCESS_FLAGS |
+ IB_QP_ALT_PATH |
+ IB_QP_PATH_MIG_STATE |
+ IB_QP_MIN_RNR_TIMER),
+ [IB_QPT_SMI] = (IB_QP_CUR_STATE |
+ IB_QP_QKEY),
+ [IB_QPT_GSI] = (IB_QP_CUR_STATE |
+ IB_QP_QKEY),
+ }
+ },
+ [IB_QPS_SQD] = {
+ .valid = 1,
+ .opt_param = {
+ [IB_QPT_UD] = IB_QP_EN_SQD_ASYNC_NOTIFY,
+ [IB_QPT_UC] = IB_QP_EN_SQD_ASYNC_NOTIFY,
+ [IB_QPT_RC] = IB_QP_EN_SQD_ASYNC_NOTIFY,
+ [IB_QPT_SMI] = IB_QP_EN_SQD_ASYNC_NOTIFY,
+ [IB_QPT_GSI] = IB_QP_EN_SQD_ASYNC_NOTIFY
+ }
+ },
+ },
+ [IB_QPS_SQD] = {
+ [IB_QPS_RESET] = { .valid = 1 },
+ [IB_QPS_ERR] = { .valid = 1 },
+ [IB_QPS_RTS] = {
+ .valid = 1,
+ .opt_param = {
+ [IB_QPT_UD] = (IB_QP_CUR_STATE |
+ IB_QP_QKEY),
+ [IB_QPT_UC] = (IB_QP_CUR_STATE |
+ IB_QP_ALT_PATH |
+ IB_QP_ACCESS_FLAGS |
+ IB_QP_PATH_MIG_STATE),
+ [IB_QPT_RC] = (IB_QP_CUR_STATE |
+ IB_QP_ALT_PATH |
+ IB_QP_ACCESS_FLAGS |
+ IB_QP_MIN_RNR_TIMER |
+ IB_QP_PATH_MIG_STATE),
+ [IB_QPT_SMI] = (IB_QP_CUR_STATE |
+ IB_QP_QKEY),
+ [IB_QPT_GSI] = (IB_QP_CUR_STATE |
+ IB_QP_QKEY),
+ }
+ },
+ [IB_QPS_SQD] = {
+ .valid = 1,
+ .opt_param = {
+ [IB_QPT_UD] = (IB_QP_PKEY_INDEX |
+ IB_QP_QKEY),
+ [IB_QPT_UC] = (IB_QP_AV |
+ IB_QP_ALT_PATH |
+ IB_QP_ACCESS_FLAGS |
+ IB_QP_PKEY_INDEX |
+ IB_QP_PATH_MIG_STATE),
+ [IB_QPT_RC] = (IB_QP_PORT |
+ IB_QP_AV |
+ IB_QP_TIMEOUT |
+ IB_QP_RETRY_CNT |
+ IB_QP_RNR_RETRY |
+ IB_QP_MAX_QP_RD_ATOMIC |
+ IB_QP_MAX_DEST_RD_ATOMIC |
+ IB_QP_ALT_PATH |
+ IB_QP_ACCESS_FLAGS |
+ IB_QP_PKEY_INDEX |
+ IB_QP_MIN_RNR_TIMER |
+ IB_QP_PATH_MIG_STATE),
+ [IB_QPT_SMI] = (IB_QP_PKEY_INDEX |
+ IB_QP_QKEY),
+ [IB_QPT_GSI] = (IB_QP_PKEY_INDEX |
+ IB_QP_QKEY),
+ }
+ }
+ },
+ [IB_QPS_SQE] = {
+ [IB_QPS_RESET] = { .valid = 1 },
+ [IB_QPS_ERR] = { .valid = 1 },
+ [IB_QPS_RTS] = {
+ .valid = 1,
+ .opt_param = {
+ [IB_QPT_UD] = (IB_QP_CUR_STATE |
+ IB_QP_QKEY),
+ [IB_QPT_UC] = (IB_QP_CUR_STATE |
+ IB_QP_ACCESS_FLAGS),
+ [IB_QPT_SMI] = (IB_QP_CUR_STATE |
+ IB_QP_QKEY),
+ [IB_QPT_GSI] = (IB_QP_CUR_STATE |
+ IB_QP_QKEY),
+ }
+ }
+ },
+ [IB_QPS_ERR] = {
+ [IB_QPS_RESET] = { .valid = 1 },
+ [IB_QPS_ERR] = { .valid = 1 }
+ }
+};
+
+int ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state,
+ enum ib_qp_type type, enum ib_qp_attr_mask mask)
+{
+ enum ib_qp_attr_mask req_param, opt_param;
+
+ if (cur_state < 0 || cur_state > IB_QPS_ERR ||
+ next_state < 0 || next_state > IB_QPS_ERR)
+ return 0;
+
+ if (mask & IB_QP_CUR_STATE &&
+ cur_state != IB_QPS_RTR && cur_state != IB_QPS_RTS &&
+ cur_state != IB_QPS_SQD && cur_state != IB_QPS_SQE)
+ return 0;
+
+ if (!qp_state_table[cur_state][next_state].valid)
+ return 0;
+
+ req_param = qp_state_table[cur_state][next_state].req_param[type];
+ opt_param = qp_state_table[cur_state][next_state].opt_param[type];
+
+ if ((mask & req_param) != req_param)
+ return 0;
+
+ if (mask & ~(req_param | opt_param | IB_QP_STATE))
+ return 0;
+
+ return 1;
+}
+EXPORT_SYMBOL(ib_modify_qp_is_ok);
+
int ib_modify_qp(struct ib_qp *qp,
struct ib_qp_attr *qp_attr,
int qp_attr_mask)
@@ -322,11 +574,10 @@ int ib_destroy_cq(struct ib_cq *cq)
}
EXPORT_SYMBOL(ib_destroy_cq);
-int ib_resize_cq(struct ib_cq *cq,
- int cqe)
+int ib_resize_cq(struct ib_cq *cq, int cqe)
{
return cq->device->resize_cq ?
- cq->device->resize_cq(cq, cqe) : -ENOSYS;
+ cq->device->resize_cq(cq, cqe, NULL) : -ENOSYS;
}
EXPORT_SYMBOL(ib_resize_cq);
diff --git a/drivers/infiniband/hw/mthca/mthca_av.c b/drivers/infiniband/hw/mthca/mthca_av.c
index a19e0ed03d7..f023d393651 100644
--- a/drivers/infiniband/hw/mthca/mthca_av.c
+++ b/drivers/infiniband/hw/mthca/mthca_av.c
@@ -147,7 +147,7 @@ int mthca_destroy_ah(struct mthca_dev *dev, struct mthca_ah *ah)
switch (ah->type) {
case MTHCA_AH_ON_HCA:
mthca_free(&dev->av_table.alloc,
- (ah->avdma - dev->av_table.ddr_av_base) /
+ (ah->avdma - dev->av_table.ddr_av_base) /
MTHCA_AV_SIZE);
break;
@@ -193,6 +193,37 @@ int mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah,
return 0;
}
+int mthca_ah_query(struct ib_ah *ibah, struct ib_ah_attr *attr)
+{
+ struct mthca_ah *ah = to_mah(ibah);
+ struct mthca_dev *dev = to_mdev(ibah->device);
+
+ /* Only implement for MAD and memfree ah for now. */
+ if (ah->type == MTHCA_AH_ON_HCA)
+ return -ENOSYS;
+
+ memset(attr, 0, sizeof *attr);
+ attr->dlid = be16_to_cpu(ah->av->dlid);
+ attr->sl = be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 28;
+ attr->static_rate = ah->av->msg_sr & 0x7;
+ attr->src_path_bits = ah->av->g_slid & 0x7F;
+ attr->port_num = be32_to_cpu(ah->av->port_pd) >> 24;
+ attr->ah_flags = mthca_ah_grh_present(ah) ? IB_AH_GRH : 0;
+
+ if (attr->ah_flags) {
+ attr->grh.traffic_class =
+ be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 20;
+ attr->grh.flow_label =
+ be32_to_cpu(ah->av->sl_tclass_flowlabel) & 0xfffff;
+ attr->grh.hop_limit = ah->av->hop_limit;
+ attr->grh.sgid_index = ah->av->gid_index &
+ (dev->limits.gid_table_len - 1);
+ memcpy(attr->grh.dgid.raw, ah->av->dgid, 16);
+ }
+
+ return 0;
+}
+
int __devinit mthca_init_av_table(struct mthca_dev *dev)
{
int err;
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
index 2825615ce81..343eca50787 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
* Copyright (c) 2005 Mellanox Technologies. All rights reserved.
- * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -182,25 +182,58 @@ struct mthca_cmd_context {
u8 status;
};
+static int fw_cmd_doorbell = 1;
+module_param(fw_cmd_doorbell, int, 0644);
+MODULE_PARM_DESC(fw_cmd_doorbell, "post FW commands through doorbell page if nonzero "
+ "(and supported by FW)");
+
static inline int go_bit(struct mthca_dev *dev)
{
return readl(dev->hcr + HCR_STATUS_OFFSET) &
swab32(1 << HCR_GO_BIT);
}
-static int mthca_cmd_post(struct mthca_dev *dev,
- u64 in_param,
- u64 out_param,
- u32 in_modifier,
- u8 op_modifier,
- u16 op,
- u16 token,
- int event)
+static void mthca_cmd_post_dbell(struct mthca_dev *dev,
+ u64 in_param,
+ u64 out_param,
+ u32 in_modifier,
+ u8 op_modifier,
+ u16 op,
+ u16 token)
{
- int err = 0;
+ void __iomem *ptr = dev->cmd.dbell_map;
+ u16 *offs = dev->cmd.dbell_offsets;
- mutex_lock(&dev->cmd.hcr_mutex);
+ __raw_writel((__force u32) cpu_to_be32(in_param >> 32), ptr + offs[0]);
+ wmb();
+ __raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful), ptr + offs[1]);
+ wmb();
+ __raw_writel((__force u32) cpu_to_be32(in_modifier), ptr + offs[2]);
+ wmb();
+ __raw_writel((__force u32) cpu_to_be32(out_param >> 32), ptr + offs[3]);
+ wmb();
+ __raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), ptr + offs[4]);
+ wmb();
+ __raw_writel((__force u32) cpu_to_be32(token << 16), ptr + offs[5]);
+ wmb();
+ __raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT) |
+ (1 << HCA_E_BIT) |
+ (op_modifier << HCR_OPMOD_SHIFT) |
+ op), ptr + offs[6]);
+ wmb();
+ __raw_writel((__force u32) 0, ptr + offs[7]);
+ wmb();
+}
+static int mthca_cmd_post_hcr(struct mthca_dev *dev,
+ u64 in_param,
+ u64 out_param,
+ u32 in_modifier,
+ u8 op_modifier,
+ u16 op,
+ u16 token,
+ int event)
+{
if (event) {
unsigned long end = jiffies + GO_BIT_TIMEOUT;
@@ -210,10 +243,8 @@ static int mthca_cmd_post(struct mthca_dev *dev,
}
}
- if (go_bit(dev)) {
- err = -EAGAIN;
- goto out;
- }
+ if (go_bit(dev))
+ return -EAGAIN;
/*
* We use writel (instead of something like memcpy_toio)
@@ -236,7 +267,29 @@ static int mthca_cmd_post(struct mthca_dev *dev,
(op_modifier << HCR_OPMOD_SHIFT) |
op), dev->hcr + 6 * 4);
-out:
+ return 0;
+}
+
+static int mthca_cmd_post(struct mthca_dev *dev,
+ u64 in_param,
+ u64 out_param,
+ u32 in_modifier,
+ u8 op_modifier,
+ u16 op,
+ u16 token,
+ int event)
+{
+ int err = 0;
+
+ mutex_lock(&dev->cmd.hcr_mutex);
+
+ if (event && dev->cmd.flags & MTHCA_CMD_POST_DOORBELLS && fw_cmd_doorbell)
+ mthca_cmd_post_dbell(dev, in_param, out_param, in_modifier,
+ op_modifier, op, token);
+ else
+ err = mthca_cmd_post_hcr(dev, in_param, out_param, in_modifier,
+ op_modifier, op, token, event);
+
mutex_unlock(&dev->cmd.hcr_mutex);
return err;
}
@@ -275,7 +328,7 @@ static int mthca_cmd_poll(struct mthca_dev *dev,
}
if (out_is_imm)
- *out_param =
+ *out_param =
(u64) be32_to_cpu((__force __be32)
__raw_readl(dev->hcr + HCR_OUT_PARAM_OFFSET)) << 32 |
(u64) be32_to_cpu((__force __be32)
@@ -386,7 +439,7 @@ static int mthca_cmd_box(struct mthca_dev *dev,
unsigned long timeout,
u8 *status)
{
- if (dev->cmd.use_events)
+ if (dev->cmd.flags & MTHCA_CMD_USE_EVENTS)
return mthca_cmd_wait(dev, in_param, &out_param, 0,
in_modifier, op_modifier, op,
timeout, status);
@@ -423,7 +476,7 @@ static int mthca_cmd_imm(struct mthca_dev *dev,
unsigned long timeout,
u8 *status)
{
- if (dev->cmd.use_events)
+ if (dev->cmd.flags & MTHCA_CMD_USE_EVENTS)
return mthca_cmd_wait(dev, in_param, out_param, 1,
in_modifier, op_modifier, op,
timeout, status);
@@ -437,7 +490,7 @@ int mthca_cmd_init(struct mthca_dev *dev)
{
mutex_init(&dev->cmd.hcr_mutex);
sema_init(&dev->cmd.poll_sem, 1);
- dev->cmd.use_events = 0;
+ dev->cmd.flags = 0;
dev->hcr = ioremap(pci_resource_start(dev->pdev, 0) + MTHCA_HCR_BASE,
MTHCA_HCR_SIZE);
@@ -461,6 +514,8 @@ void mthca_cmd_cleanup(struct mthca_dev *dev)
{
pci_pool_destroy(dev->cmd.pool);
iounmap(dev->hcr);
+ if (dev->cmd.flags & MTHCA_CMD_POST_DOORBELLS)
+ iounmap(dev->cmd.dbell_map);
}
/*
@@ -498,7 +553,8 @@ int mthca_cmd_use_events(struct mthca_dev *dev)
; /* nothing */
--dev->cmd.token_mask;
- dev->cmd.use_events = 1;
+ dev->cmd.flags |= MTHCA_CMD_USE_EVENTS;
+
down(&dev->cmd.poll_sem);
return 0;
@@ -511,7 +567,7 @@ void mthca_cmd_use_polling(struct mthca_dev *dev)
{
int i;
- dev->cmd.use_events = 0;
+ dev->cmd.flags &= ~MTHCA_CMD_USE_EVENTS;
for (i = 0; i < dev->cmd.max_cmds; ++i)
down(&dev->cmd.event_sem);
@@ -596,8 +652,9 @@ static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
* address or size and use that as our log2 size.
*/
lg = ffs(mthca_icm_addr(&iter) | mthca_icm_size(&iter)) - 1;
- if (lg < 12) {
- mthca_warn(dev, "Got FW area not aligned to 4K (%llx/%lx).\n",
+ if (lg < MTHCA_ICM_PAGE_SHIFT) {
+ mthca_warn(dev, "Got FW area not aligned to %d (%llx/%lx).\n",
+ MTHCA_ICM_PAGE_SIZE,
(unsigned long long) mthca_icm_addr(&iter),
mthca_icm_size(&iter));
err = -EINVAL;
@@ -609,8 +666,9 @@ static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
virt += 1 << lg;
}
- pages[nent * 2 + 1] = cpu_to_be64((mthca_icm_addr(&iter) +
- (i << lg)) | (lg - 12));
+ pages[nent * 2 + 1] =
+ cpu_to_be64((mthca_icm_addr(&iter) + (i << lg)) |
+ (lg - MTHCA_ICM_PAGE_SHIFT));
ts += 1 << (lg - 10);
++tc;
@@ -661,12 +719,41 @@ int mthca_RUN_FW(struct mthca_dev *dev, u8 *status)
return mthca_cmd(dev, 0, 0, 0, CMD_RUN_FW, CMD_TIME_CLASS_A, status);
}
+static void mthca_setup_cmd_doorbells(struct mthca_dev *dev, u64 base)
+{
+ unsigned long addr;
+ u16 max_off = 0;
+ int i;
+
+ for (i = 0; i < 8; ++i)
+ max_off = max(max_off, dev->cmd.dbell_offsets[i]);
+
+ if ((base & PAGE_MASK) != ((base + max_off) & PAGE_MASK)) {
+ mthca_warn(dev, "Firmware doorbell region at 0x%016llx, "
+ "length 0x%x crosses a page boundary\n",
+ (unsigned long long) base, max_off);
+ return;
+ }
+
+ addr = pci_resource_start(dev->pdev, 2) +
+ ((pci_resource_len(dev->pdev, 2) - 1) & base);
+ dev->cmd.dbell_map = ioremap(addr, max_off + sizeof(u32));
+ if (!dev->cmd.dbell_map)
+ return;
+
+ dev->cmd.flags |= MTHCA_CMD_POST_DOORBELLS;
+ mthca_dbg(dev, "Mapped doorbell page for posting FW commands\n");
+}
+
int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
{
struct mthca_mailbox *mailbox;
u32 *outbox;
+ u64 base;
+ u32 tmp;
int err = 0;
u8 lg;
+ int i;
#define QUERY_FW_OUT_SIZE 0x100
#define QUERY_FW_VER_OFFSET 0x00
@@ -674,6 +761,10 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
#define QUERY_FW_ERR_START_OFFSET 0x30
#define QUERY_FW_ERR_SIZE_OFFSET 0x38
+#define QUERY_FW_CMD_DB_EN_OFFSET 0x10
+#define QUERY_FW_CMD_DB_OFFSET 0x50
+#define QUERY_FW_CMD_DB_BASE 0x60
+
#define QUERY_FW_START_OFFSET 0x20
#define QUERY_FW_END_OFFSET 0x28
@@ -702,16 +793,29 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
((dev->fw_ver & 0xffff0000ull) >> 16) |
((dev->fw_ver & 0x0000ffffull) << 16);
+ mthca_dbg(dev, "FW version %012llx, max commands %d\n",
+ (unsigned long long) dev->fw_ver, dev->cmd.max_cmds);
+
MTHCA_GET(lg, outbox, QUERY_FW_MAX_CMD_OFFSET);
dev->cmd.max_cmds = 1 << lg;
MTHCA_GET(dev->catas_err.addr, outbox, QUERY_FW_ERR_START_OFFSET);
MTHCA_GET(dev->catas_err.size, outbox, QUERY_FW_ERR_SIZE_OFFSET);
- mthca_dbg(dev, "FW version %012llx, max commands %d\n",
- (unsigned long long) dev->fw_ver, dev->cmd.max_cmds);
mthca_dbg(dev, "Catastrophic error buffer at 0x%llx, size 0x%x\n",
(unsigned long long) dev->catas_err.addr, dev->catas_err.size);
+ MTHCA_GET(tmp, outbox, QUERY_FW_CMD_DB_EN_OFFSET);
+ if (tmp & 0x1) {
+ mthca_dbg(dev, "FW supports commands through doorbells\n");
+
+ MTHCA_GET(base, outbox, QUERY_FW_CMD_DB_BASE);
+ for (i = 0; i < MTHCA_CMD_NUM_DBELL_DWORDS; ++i)
+ MTHCA_GET(dev->cmd.dbell_offsets[i], outbox,
+ QUERY_FW_CMD_DB_OFFSET + (i << 1));
+
+ mthca_setup_cmd_doorbells(dev, base);
+ }
+
if (mthca_is_memfree(dev)) {
MTHCA_GET(dev->fw.arbel.fw_pages, outbox, QUERY_FW_SIZE_OFFSET);
MTHCA_GET(dev->fw.arbel.clr_int_base, outbox, QUERY_FW_CLR_INT_BASE_OFFSET);
@@ -720,12 +824,12 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
mthca_dbg(dev, "FW size %d KB\n", dev->fw.arbel.fw_pages << 2);
/*
- * Arbel page size is always 4 KB; round up number of
- * system pages needed.
+ * Round up number of system pages needed in case
+ * MTHCA_ICM_PAGE_SIZE < PAGE_SIZE.
*/
dev->fw.arbel.fw_pages =
- ALIGN(dev->fw.arbel.fw_pages, PAGE_SIZE >> 12) >>
- (PAGE_SHIFT - 12);
+ ALIGN(dev->fw.arbel.fw_pages, PAGE_SIZE / MTHCA_ICM_PAGE_SIZE) >>
+ (PAGE_SHIFT - MTHCA_ICM_PAGE_SHIFT);
mthca_dbg(dev, "Clear int @ %llx, EQ arm @ %llx, EQ set CI @ %llx\n",
(unsigned long long) dev->fw.arbel.clr_int_base,
@@ -1173,7 +1277,8 @@ int mthca_INIT_HCA(struct mthca_dev *dev,
int err;
#define INIT_HCA_IN_SIZE 0x200
-#define INIT_HCA_FLAGS_OFFSET 0x014
+#define INIT_HCA_FLAGS1_OFFSET 0x00c
+#define INIT_HCA_FLAGS2_OFFSET 0x014
#define INIT_HCA_QPC_OFFSET 0x020
#define INIT_HCA_QPC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x10)
#define INIT_HCA_LOG_QP_OFFSET (INIT_HCA_QPC_OFFSET + 0x17)
@@ -1216,15 +1321,18 @@ int mthca_INIT_HCA(struct mthca_dev *dev,
memset(inbox, 0, INIT_HCA_IN_SIZE);
+ if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT)
+ MTHCA_PUT(inbox, 0x1, INIT_HCA_FLAGS1_OFFSET);
+
#if defined(__LITTLE_ENDIAN)
- *(inbox + INIT_HCA_FLAGS_OFFSET / 4) &= ~cpu_to_be32(1 << 1);
+ *(inbox + INIT_HCA_FLAGS2_OFFSET / 4) &= ~cpu_to_be32(1 << 1);
#elif defined(__BIG_ENDIAN)
- *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 1);
+ *(inbox + INIT_HCA_FLAGS2_OFFSET / 4) |= cpu_to_be32(1 << 1);
#else
#error Host endianness not defined
#endif
/* Check port for UD address vector: */
- *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1);
+ *(inbox + INIT_HCA_FLAGS2_OFFSET / 4) |= cpu_to_be32(1);
/* We leave wqe_quota, responder_exu, etc as 0 (default) */
@@ -1438,11 +1546,11 @@ int mthca_SET_ICM_SIZE(struct mthca_dev *dev, u64 icm_size, u64 *aux_pages,
return ret;
/*
- * Arbel page size is always 4 KB; round up number of system
- * pages needed.
+ * Round up number of system pages needed in case
+ * MTHCA_ICM_PAGE_SIZE < PAGE_SIZE.
*/
- *aux_pages = (*aux_pages + (1 << (PAGE_SHIFT - 12)) - 1) >> (PAGE_SHIFT - 12);
- *aux_pages = ALIGN(*aux_pages, PAGE_SIZE >> 12) >> (PAGE_SHIFT - 12);
+ *aux_pages = ALIGN(*aux_pages, PAGE_SIZE / MTHCA_ICM_PAGE_SIZE) >>
+ (PAGE_SHIFT - MTHCA_ICM_PAGE_SHIFT);
return 0;
}
@@ -1514,6 +1622,37 @@ int mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
CMD_TIME_CLASS_A, status);
}
+int mthca_RESIZE_CQ(struct mthca_dev *dev, int cq_num, u32 lkey, u8 log_size,
+ u8 *status)
+{
+ struct mthca_mailbox *mailbox;
+ __be32 *inbox;
+ int err;
+
+#define RESIZE_CQ_IN_SIZE 0x40
+#define RESIZE_CQ_LOG_SIZE_OFFSET 0x0c
+#define RESIZE_CQ_LKEY_OFFSET 0x1c
+
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ inbox = mailbox->buf;
+
+ memset(inbox, 0, RESIZE_CQ_IN_SIZE);
+ /*
+ * Leave start address fields zeroed out -- mthca assumes that
+ * MRs for CQs always start at virtual address 0.
+ */
+ MTHCA_PUT(inbox, log_size, RESIZE_CQ_LOG_SIZE_OFFSET);
+ MTHCA_PUT(inbox, lkey, RESIZE_CQ_LKEY_OFFSET);
+
+ err = mthca_cmd(dev, mailbox->dma, cq_num, 1, CMD_RESIZE_CQ,
+ CMD_TIME_CLASS_B, status);
+
+ mthca_free_mailbox(dev, mailbox);
+ return err;
+}
+
int mthca_SW2HW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int srq_num, u8 *status)
{
@@ -1529,37 +1668,69 @@ int mthca_HW2SW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
CMD_TIME_CLASS_A, status);
}
+int mthca_QUERY_SRQ(struct mthca_dev *dev, u32 num,
+ struct mthca_mailbox *mailbox, u8 *status)
+{
+ return mthca_cmd_box(dev, 0, mailbox->dma, num, 0,
+ CMD_QUERY_SRQ, CMD_TIME_CLASS_A, status);
+}
+
int mthca_ARM_SRQ(struct mthca_dev *dev, int srq_num, int limit, u8 *status)
{
return mthca_cmd(dev, limit, srq_num, 0, CMD_ARM_SRQ,
CMD_TIME_CLASS_B, status);
}
-int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
- int is_ee, struct mthca_mailbox *mailbox, u32 optmask,
+int mthca_MODIFY_QP(struct mthca_dev *dev, enum ib_qp_state cur,
+ enum ib_qp_state next, u32 num, int is_ee,
+ struct mthca_mailbox *mailbox, u32 optmask,
u8 *status)
{
- static const u16 op[] = {
- [MTHCA_TRANS_RST2INIT] = CMD_RST2INIT_QPEE,
- [MTHCA_TRANS_INIT2INIT] = CMD_INIT2INIT_QPEE,
- [MTHCA_TRANS_INIT2RTR] = CMD_INIT2RTR_QPEE,
- [MTHCA_TRANS_RTR2RTS] = CMD_RTR2RTS_QPEE,
- [MTHCA_TRANS_RTS2RTS] = CMD_RTS2RTS_QPEE,
- [MTHCA_TRANS_SQERR2RTS] = CMD_SQERR2RTS_QPEE,
- [MTHCA_TRANS_ANY2ERR] = CMD_2ERR_QPEE,
- [MTHCA_TRANS_RTS2SQD] = CMD_RTS2SQD_QPEE,
- [MTHCA_TRANS_SQD2SQD] = CMD_SQD2SQD_QPEE,
- [MTHCA_TRANS_SQD2RTS] = CMD_SQD2RTS_QPEE,
- [MTHCA_TRANS_ANY2RST] = CMD_ERR2RST_QPEE
+ static const u16 op[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
+ [IB_QPS_RESET] = {
+ [IB_QPS_RESET] = CMD_ERR2RST_QPEE,
+ [IB_QPS_ERR] = CMD_2ERR_QPEE,
+ [IB_QPS_INIT] = CMD_RST2INIT_QPEE,
+ },
+ [IB_QPS_INIT] = {
+ [IB_QPS_RESET] = CMD_ERR2RST_QPEE,
+ [IB_QPS_ERR] = CMD_2ERR_QPEE,
+ [IB_QPS_INIT] = CMD_INIT2INIT_QPEE,
+ [IB_QPS_RTR] = CMD_INIT2RTR_QPEE,
+ },
+ [IB_QPS_RTR] = {
+ [IB_QPS_RESET] = CMD_ERR2RST_QPEE,
+ [IB_QPS_ERR] = CMD_2ERR_QPEE,
+ [IB_QPS_RTS] = CMD_RTR2RTS_QPEE,
+ },
+ [IB_QPS_RTS] = {
+ [IB_QPS_RESET] = CMD_ERR2RST_QPEE,
+ [IB_QPS_ERR] = CMD_2ERR_QPEE,
+ [IB_QPS_RTS] = CMD_RTS2RTS_QPEE,
+ [IB_QPS_SQD] = CMD_RTS2SQD_QPEE,
+ },
+ [IB_QPS_SQD] = {
+ [IB_QPS_RESET] = CMD_ERR2RST_QPEE,
+ [IB_QPS_ERR] = CMD_2ERR_QPEE,
+ [IB_QPS_RTS] = CMD_SQD2RTS_QPEE,
+ [IB_QPS_SQD] = CMD_SQD2SQD_QPEE,
+ },
+ [IB_QPS_SQE] = {
+ [IB_QPS_RESET] = CMD_ERR2RST_QPEE,
+ [IB_QPS_ERR] = CMD_2ERR_QPEE,
+ [IB_QPS_RTS] = CMD_SQERR2RTS_QPEE,
+ },
+ [IB_QPS_ERR] = {
+ [IB_QPS_RESET] = CMD_ERR2RST_QPEE,
+ [IB_QPS_ERR] = CMD_2ERR_QPEE,
+ }
};
+
u8 op_mod = 0;
int my_mailbox = 0;
int err;
- if (trans < 0 || trans >= ARRAY_SIZE(op))
- return -EINVAL;
-
- if (trans == MTHCA_TRANS_ANY2RST) {
+ if (op[cur][next] == CMD_ERR2RST_QPEE) {
op_mod = 3; /* don't write outbox, any->reset */
/* For debugging */
@@ -1571,34 +1742,35 @@ int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
} else
mailbox = NULL;
}
- } else {
- if (0) {
+
+ err = mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0,
+ (!!is_ee << 24) | num, op_mod,
+ op[cur][next], CMD_TIME_CLASS_C, status);
+
+ if (0 && mailbox) {
int i;
mthca_dbg(dev, "Dumping QP context:\n");
- printk(" opt param mask: %08x\n", be32_to_cpup(mailbox->buf));
+ printk(" %08x\n", be32_to_cpup(mailbox->buf));
for (i = 0; i < 0x100 / 4; ++i) {
if (i % 8 == 0)
- printk(" [%02x] ", i * 4);
+ printk("[%02x] ", i * 4);
printk(" %08x",
be32_to_cpu(((__be32 *) mailbox->buf)[i + 2]));
if ((i + 1) % 8 == 0)
printk("\n");
}
}
- }
-
- if (trans == MTHCA_TRANS_ANY2RST) {
- err = mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0,
- (!!is_ee << 24) | num, op_mod,
- op[trans], CMD_TIME_CLASS_C, status);
- if (0 && mailbox) {
+ if (my_mailbox)
+ mthca_free_mailbox(dev, mailbox);
+ } else {
+ if (0) {
int i;
mthca_dbg(dev, "Dumping QP context:\n");
- printk(" %08x\n", be32_to_cpup(mailbox->buf));
+ printk(" opt param mask: %08x\n", be32_to_cpup(mailbox->buf));
for (i = 0; i < 0x100 / 4; ++i) {
if (i % 8 == 0)
- printk("[%02x] ", i * 4);
+ printk(" [%02x] ", i * 4);
printk(" %08x",
be32_to_cpu(((__be32 *) mailbox->buf)[i + 2]));
if ((i + 1) % 8 == 0)
@@ -1606,12 +1778,9 @@ int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
}
}
- } else
- err = mthca_cmd(dev, mailbox->dma, (!!is_ee << 24) | num,
- op_mod, op[trans], CMD_TIME_CLASS_C, status);
-
- if (my_mailbox)
- mthca_free_mailbox(dev, mailbox);
+ err = mthca_cmd(dev, mailbox->dma, optmask | (!!is_ee << 24) | num,
+ op_mod, op[cur][next], CMD_TIME_CLASS_C, status);
+ }
return err;
}
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.h b/drivers/infiniband/hw/mthca/mthca_cmd.h
index 18175bec84c..e4ec35c40dd 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.h
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.h
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
* Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2006 Cisco Systems. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -73,9 +74,9 @@ enum {
MTHCA_CMD_STAT_REG_BOUND = 0x21,
/* HCA local attached memory not present: */
MTHCA_CMD_STAT_LAM_NOT_PRE = 0x22,
- /* Bad management packet (silently discarded): */
+ /* Bad management packet (silently discarded): */
MTHCA_CMD_STAT_BAD_PKT = 0x30,
- /* More outstanding CQEs in CQ than new CQ size: */
+ /* More outstanding CQEs in CQ than new CQ size: */
MTHCA_CMD_STAT_BAD_SIZE = 0x40
};
@@ -298,13 +299,18 @@ int mthca_SW2HW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int cq_num, u8 *status);
int mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int cq_num, u8 *status);
+int mthca_RESIZE_CQ(struct mthca_dev *dev, int cq_num, u32 lkey, u8 log_size,
+ u8 *status);
int mthca_SW2HW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int srq_num, u8 *status);
int mthca_HW2SW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int srq_num, u8 *status);
+int mthca_QUERY_SRQ(struct mthca_dev *dev, u32 num,
+ struct mthca_mailbox *mailbox, u8 *status);
int mthca_ARM_SRQ(struct mthca_dev *dev, int srq_num, int limit, u8 *status);
-int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
- int is_ee, struct mthca_mailbox *mailbox, u32 optmask,
+int mthca_MODIFY_QP(struct mthca_dev *dev, enum ib_qp_state cur,
+ enum ib_qp_state next, u32 num, int is_ee,
+ struct mthca_mailbox *mailbox, u32 optmask,
u8 *status);
int mthca_QUERY_QP(struct mthca_dev *dev, u32 num, int is_ee,
struct mthca_mailbox *mailbox, u8 *status);
diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c
index 96f1a86bf04..76aabc5bf37 100644
--- a/drivers/infiniband/hw/mthca/mthca_cq.c
+++ b/drivers/infiniband/hw/mthca/mthca_cq.c
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
* Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
- * Copyright (c) 2005 Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems, Inc. All rights reserved.
* Copyright (c) 2005 Mellanox Technologies. All rights reserved.
* Copyright (c) 2004 Voltaire, Inc. All rights reserved.
*
@@ -150,24 +150,29 @@ struct mthca_err_cqe {
#define MTHCA_ARBEL_CQ_DB_REQ_NOT (2 << 24)
#define MTHCA_ARBEL_CQ_DB_REQ_NOT_MULT (3 << 24)
-static inline struct mthca_cqe *get_cqe(struct mthca_cq *cq, int entry)
+static inline struct mthca_cqe *get_cqe_from_buf(struct mthca_cq_buf *buf,
+ int entry)
{
- if (cq->is_direct)
- return cq->queue.direct.buf + (entry * MTHCA_CQ_ENTRY_SIZE);
+ if (buf->is_direct)
+ return buf->queue.direct.buf + (entry * MTHCA_CQ_ENTRY_SIZE);
else
- return cq->queue.page_list[entry * MTHCA_CQ_ENTRY_SIZE / PAGE_SIZE].buf
+ return buf->queue.page_list[entry * MTHCA_CQ_ENTRY_SIZE / PAGE_SIZE].buf
+ (entry * MTHCA_CQ_ENTRY_SIZE) % PAGE_SIZE;
}
-static inline struct mthca_cqe *cqe_sw(struct mthca_cq *cq, int i)
+static inline struct mthca_cqe *get_cqe(struct mthca_cq *cq, int entry)
+{
+ return get_cqe_from_buf(&cq->buf, entry);
+}
+
+static inline struct mthca_cqe *cqe_sw(struct mthca_cqe *cqe)
{
- struct mthca_cqe *cqe = get_cqe(cq, i);
return MTHCA_CQ_ENTRY_OWNER_HW & cqe->owner ? NULL : cqe;
}
static inline struct mthca_cqe *next_cqe_sw(struct mthca_cq *cq)
{
- return cqe_sw(cq, cq->cons_index & cq->ibcq.cqe);
+ return cqe_sw(get_cqe(cq, cq->cons_index & cq->ibcq.cqe));
}
static inline void set_cqe_hw(struct mthca_cqe *cqe)
@@ -289,7 +294,7 @@ void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn,
* from our QP and therefore don't need to be checked.
*/
for (prod_index = cq->cons_index;
- cqe_sw(cq, prod_index & cq->ibcq.cqe);
+ cqe_sw(get_cqe(cq, prod_index & cq->ibcq.cqe));
++prod_index)
if (prod_index == cq->cons_index + cq->ibcq.cqe)
break;
@@ -324,12 +329,58 @@ void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn,
wake_up(&cq->wait);
}
-static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
- struct mthca_qp *qp, int wqe_index, int is_send,
- struct mthca_err_cqe *cqe,
- struct ib_wc *entry, int *free_cqe)
+void mthca_cq_resize_copy_cqes(struct mthca_cq *cq)
+{
+ int i;
+
+ /*
+ * In Tavor mode, the hardware keeps the consumer and producer
+ * indices mod the CQ size. Since we might be making the CQ
+ * bigger, we need to deal with the case where the producer
+ * index wrapped around before the CQ was resized.
+ */
+ if (!mthca_is_memfree(to_mdev(cq->ibcq.device)) &&
+ cq->ibcq.cqe < cq->resize_buf->cqe) {
+ cq->cons_index &= cq->ibcq.cqe;
+ if (cqe_sw(get_cqe(cq, cq->ibcq.cqe)))
+ cq->cons_index -= cq->ibcq.cqe + 1;
+ }
+
+ for (i = cq->cons_index; cqe_sw(get_cqe(cq, i & cq->ibcq.cqe)); ++i)
+ memcpy(get_cqe_from_buf(&cq->resize_buf->buf,
+ i & cq->resize_buf->cqe),
+ get_cqe(cq, i & cq->ibcq.cqe), MTHCA_CQ_ENTRY_SIZE);
+}
+
+int mthca_alloc_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int nent)
+{
+ int ret;
+ int i;
+
+ ret = mthca_buf_alloc(dev, nent * MTHCA_CQ_ENTRY_SIZE,
+ MTHCA_MAX_DIRECT_CQ_SIZE,
+ &buf->queue, &buf->is_direct,
+ &dev->driver_pd, 1, &buf->mr);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < nent; ++i)
+ set_cqe_hw(get_cqe_from_buf(buf, i));
+
+ return 0;
+}
+
+void mthca_free_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int cqe)
+{
+ mthca_buf_free(dev, (cqe + 1) * MTHCA_CQ_ENTRY_SIZE, &buf->queue,
+ buf->is_direct, &buf->mr);
+}
+
+static void handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
+ struct mthca_qp *qp, int wqe_index, int is_send,
+ struct mthca_err_cqe *cqe,
+ struct ib_wc *entry, int *free_cqe)
{
- int err;
int dbd;
__be32 new_wqe;
@@ -412,11 +463,9 @@ static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
* error case, so we don't have to check the doorbell count, etc.
*/
if (mthca_is_memfree(dev))
- return 0;
+ return;
- err = mthca_free_err_wqe(dev, qp, is_send, wqe_index, &dbd, &new_wqe);
- if (err)
- return err;
+ mthca_free_err_wqe(dev, qp, is_send, wqe_index, &dbd, &new_wqe);
/*
* If we're at the end of the WQE chain, or we've used up our
@@ -424,15 +473,13 @@ static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
* the next poll operation.
*/
if (!(new_wqe & cpu_to_be32(0x3f)) || (!cqe->db_cnt && dbd))
- return 0;
+ return;
cqe->db_cnt = cpu_to_be16(be16_to_cpu(cqe->db_cnt) - dbd);
cqe->wqe = new_wqe;
cqe->syndrome = SYNDROME_WR_FLUSH_ERR;
*free_cqe = 0;
-
- return 0;
}
static inline int mthca_poll_one(struct mthca_dev *dev,
@@ -518,9 +565,9 @@ static inline int mthca_poll_one(struct mthca_dev *dev,
}
if (is_error) {
- err = handle_error_cqe(dev, cq, *cur_qp, wqe_index, is_send,
- (struct mthca_err_cqe *) cqe,
- entry, &free_cqe);
+ handle_error_cqe(dev, cq, *cur_qp, wqe_index, is_send,
+ (struct mthca_err_cqe *) cqe,
+ entry, &free_cqe);
goto out;
}
@@ -614,11 +661,14 @@ int mthca_poll_cq(struct ib_cq *ibcq, int num_entries,
spin_lock_irqsave(&cq->lock, flags);
- for (npolled = 0; npolled < num_entries; ++npolled) {
+ npolled = 0;
+repoll:
+ while (npolled < num_entries) {
err = mthca_poll_one(dev, cq, &qp,
&freed, entry + npolled);
if (err)
break;
+ ++npolled;
}
if (freed) {
@@ -626,6 +676,42 @@ int mthca_poll_cq(struct ib_cq *ibcq, int num_entries,
update_cons_index(dev, cq, freed);
}
+ /*
+ * If a CQ resize is in progress and we discovered that the
+ * old buffer is empty, then peek in the new buffer, and if
+ * it's not empty, switch to the new buffer and continue
+ * polling there.
+ */
+ if (unlikely(err == -EAGAIN && cq->resize_buf &&
+ cq->resize_buf->state == CQ_RESIZE_READY)) {
+ /*
+ * In Tavor mode, the hardware keeps the producer
+ * index modulo the CQ size. Since we might be making
+ * the CQ bigger, we need to mask our consumer index
+ * using the size of the old CQ buffer before looking
+ * in the new CQ buffer.
+ */
+ if (!mthca_is_memfree(dev))
+ cq->cons_index &= cq->ibcq.cqe;
+
+ if (cqe_sw(get_cqe_from_buf(&cq->resize_buf->buf,
+ cq->cons_index & cq->resize_buf->cqe))) {
+ struct mthca_cq_buf tbuf;
+ int tcqe;
+
+ tbuf = cq->buf;
+ tcqe = cq->ibcq.cqe;
+ cq->buf = cq->resize_buf->buf;
+ cq->ibcq.cqe = cq->resize_buf->cqe;
+
+ cq->resize_buf->buf = tbuf;
+ cq->resize_buf->cqe = tcqe;
+ cq->resize_buf->state = CQ_RESIZE_SWAPPED;
+
+ goto repoll;
+ }
+ }
+
spin_unlock_irqrestore(&cq->lock, flags);
return err == 0 || err == -EAGAIN ? npolled : err;
@@ -684,24 +770,14 @@ int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
return 0;
}
-static void mthca_free_cq_buf(struct mthca_dev *dev, struct mthca_cq *cq)
-{
- mthca_buf_free(dev, (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE,
- &cq->queue, cq->is_direct, &cq->mr);
-}
-
int mthca_init_cq(struct mthca_dev *dev, int nent,
struct mthca_ucontext *ctx, u32 pdn,
struct mthca_cq *cq)
{
- int size = nent * MTHCA_CQ_ENTRY_SIZE;
struct mthca_mailbox *mailbox;
struct mthca_cq_context *cq_context;
int err = -ENOMEM;
u8 status;
- int i;
-
- might_sleep();
cq->ibcq.cqe = nent - 1;
cq->is_kernel = !ctx;
@@ -739,14 +815,9 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
cq_context = mailbox->buf;
if (cq->is_kernel) {
- err = mthca_buf_alloc(dev, size, MTHCA_MAX_DIRECT_CQ_SIZE,
- &cq->queue, &cq->is_direct,
- &dev->driver_pd, 1, &cq->mr);
+ err = mthca_alloc_cq_buf(dev, &cq->buf, nent);
if (err)
goto err_out_mailbox;
-
- for (i = 0; i < nent; ++i)
- set_cqe_hw(get_cqe(cq, i));
}
spin_lock_init(&cq->lock);
@@ -765,7 +836,7 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
cq_context->error_eqn = cpu_to_be32(dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn);
cq_context->comp_eqn = cpu_to_be32(dev->eq_table.eq[MTHCA_EQ_COMP].eqn);
cq_context->pd = cpu_to_be32(pdn);
- cq_context->lkey = cpu_to_be32(cq->mr.ibmr.lkey);
+ cq_context->lkey = cpu_to_be32(cq->buf.mr.ibmr.lkey);
cq_context->cqn = cpu_to_be32(cq->cqn);
if (mthca_is_memfree(dev)) {
@@ -803,7 +874,7 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
err_out_free_mr:
if (cq->is_kernel)
- mthca_free_cq_buf(dev, cq);
+ mthca_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe);
err_out_mailbox:
mthca_free_mailbox(dev, mailbox);
@@ -832,8 +903,6 @@ void mthca_free_cq(struct mthca_dev *dev,
int err;
u8 status;
- might_sleep();
-
mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
if (IS_ERR(mailbox)) {
mthca_warn(dev, "No memory for mailbox to free CQ.\n");
@@ -871,7 +940,7 @@ void mthca_free_cq(struct mthca_dev *dev,
wait_event(cq->wait, !atomic_read(&cq->refcount));
if (cq->is_kernel) {
- mthca_free_cq_buf(dev, cq);
+ mthca_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe);
if (mthca_is_memfree(dev)) {
mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM, cq->arm_db_index);
mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index);
diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h
index e481037288d..ad52edbefe9 100644
--- a/drivers/infiniband/hw/mthca/mthca_dev.h
+++ b/drivers/infiniband/hw/mthca/mthca_dev.h
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
* Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
- * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved.
* Copyright (c) 2005 Mellanox Technologies. All rights reserved.
* Copyright (c) 2004 Voltaire, Inc. All rights reserved.
*
@@ -53,8 +53,8 @@
#define DRV_NAME "ib_mthca"
#define PFX DRV_NAME ": "
-#define DRV_VERSION "0.07"
-#define DRV_RELDATE "February 13, 2006"
+#define DRV_VERSION "0.08"
+#define DRV_RELDATE "February 14, 2006"
enum {
MTHCA_FLAG_DDR_HIDDEN = 1 << 1,
@@ -64,7 +64,8 @@ enum {
MTHCA_FLAG_NO_LAM = 1 << 5,
MTHCA_FLAG_FMR = 1 << 6,
MTHCA_FLAG_MEMFREE = 1 << 7,
- MTHCA_FLAG_PCIE = 1 << 8
+ MTHCA_FLAG_PCIE = 1 << 8,
+ MTHCA_FLAG_SINAI_OPT = 1 << 9
};
enum {
@@ -110,9 +111,17 @@ enum {
MTHCA_OPCODE_INVALID = 0xff
};
+enum {
+ MTHCA_CMD_USE_EVENTS = 1 << 0,
+ MTHCA_CMD_POST_DOORBELLS = 1 << 1
+};
+
+enum {
+ MTHCA_CMD_NUM_DBELL_DWORDS = 8
+};
+
struct mthca_cmd {
struct pci_pool *pool;
- int use_events;
struct mutex hcr_mutex;
struct semaphore poll_sem;
struct semaphore event_sem;
@@ -121,6 +130,9 @@ struct mthca_cmd {
int free_head;
struct mthca_cmd_context *context;
u16 token_mask;
+ u32 flags;
+ void __iomem *dbell_map;
+ u16 dbell_offsets[MTHCA_CMD_NUM_DBELL_DWORDS];
};
struct mthca_limits {
@@ -470,12 +482,16 @@ void mthca_cq_event(struct mthca_dev *dev, u32 cqn,
enum ib_event_type event_type);
void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn,
struct mthca_srq *srq);
+void mthca_cq_resize_copy_cqes(struct mthca_cq *cq);
+int mthca_alloc_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int nent);
+void mthca_free_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int cqe);
int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd,
struct ib_srq_attr *attr, struct mthca_srq *srq);
void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq);
int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
enum ib_srq_attr_mask attr_mask);
+int mthca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr);
void mthca_srq_event(struct mthca_dev *dev, u32 srqn,
enum ib_event_type event_type);
void mthca_free_srq_wqe(struct mthca_srq *srq, u32 wqe_addr);
@@ -486,6 +502,8 @@ int mthca_arbel_post_srq_recv(struct ib_srq *srq, struct ib_recv_wr *wr,
void mthca_qp_event(struct mthca_dev *dev, u32 qpn,
enum ib_event_type event_type);
+int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask,
+ struct ib_qp_init_attr *qp_init_attr);
int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask);
int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
struct ib_send_wr **bad_wr);
@@ -495,8 +513,8 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
struct ib_send_wr **bad_wr);
int mthca_arbel_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
struct ib_recv_wr **bad_wr);
-int mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send,
- int index, int *dbd, __be32 *new_wqe);
+void mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send,
+ int index, int *dbd, __be32 *new_wqe);
int mthca_alloc_qp(struct mthca_dev *dev,
struct mthca_pd *pd,
struct mthca_cq *send_cq,
@@ -522,6 +540,7 @@ int mthca_create_ah(struct mthca_dev *dev,
int mthca_destroy_ah(struct mthca_dev *dev, struct mthca_ah *ah);
int mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah,
struct ib_ud_header *header);
+int mthca_ah_query(struct ib_ah *ibah, struct ib_ah_attr *attr);
int mthca_ah_grh_present(struct mthca_ah *ah);
int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid);
diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c
index 2eabb27804c..cbdc348fb68 100644
--- a/drivers/infiniband/hw/mthca/mthca_eq.c
+++ b/drivers/infiniband/hw/mthca/mthca_eq.c
@@ -497,7 +497,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
eq->dev = dev;
eq->nent = roundup_pow_of_two(max(nent, 2));
- npages = ALIGN(eq->nent * MTHCA_EQ_ENTRY_SIZE, PAGE_SIZE) / PAGE_SIZE;
+ npages = ALIGN(eq->nent * MTHCA_EQ_ENTRY_SIZE, PAGE_SIZE) / PAGE_SIZE;
eq->page_list = kmalloc(npages * sizeof *eq->page_list,
GFP_KERNEL);
@@ -825,7 +825,7 @@ void __devexit mthca_unmap_eq_icm(struct mthca_dev *dev)
{
u8 status;
- mthca_UNMAP_ICM(dev, dev->eq_table.icm_virt, PAGE_SIZE / 4096, &status);
+ mthca_UNMAP_ICM(dev, dev->eq_table.icm_virt, 1, &status);
pci_unmap_page(dev->pdev, dev->eq_table.icm_dma, PAGE_SIZE,
PCI_DMA_BIDIRECTIONAL);
__free_page(dev->eq_table.icm_page);
@@ -928,7 +928,7 @@ int __devinit mthca_init_eq_table(struct mthca_dev *dev)
mthca_warn(dev, "MAP_EQ for cmd EQ %d returned status 0x%02x\n",
dev->eq_table.eq[MTHCA_EQ_CMD].eqn, status);
- for (i = 0; i < MTHCA_EQ_CMD; ++i)
+ for (i = 0; i < MTHCA_NUM_EQ; ++i)
if (mthca_is_memfree(dev))
arbel_eq_req_not(dev, dev->eq_table.eq[i].eqn_mask);
else
diff --git a/drivers/infiniband/hw/mthca/mthca_mad.c b/drivers/infiniband/hw/mthca/mthca_mad.c
index 1229c604c6e..4ace6a392f4 100644
--- a/drivers/infiniband/hw/mthca/mthca_mad.c
+++ b/drivers/infiniband/hw/mthca/mthca_mad.c
@@ -109,6 +109,19 @@ static void smp_snoop(struct ib_device *ibdev,
}
}
+static void node_desc_override(struct ib_device *dev,
+ struct ib_mad *mad)
+{
+ if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
+ mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) &&
+ mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP &&
+ mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) {
+ mutex_lock(&to_mdev(dev)->cap_mask_mutex);
+ memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 64);
+ mutex_unlock(&to_mdev(dev)->cap_mask_mutex);
+ }
+}
+
static void forward_trap(struct mthca_dev *dev,
u8 port_num,
struct ib_mad *mad)
@@ -207,8 +220,10 @@ int mthca_process_mad(struct ib_device *ibdev,
return IB_MAD_RESULT_FAILURE;
}
- if (!out_mad->mad_hdr.status)
+ if (!out_mad->mad_hdr.status) {
smp_snoop(ibdev, port_num, in_mad);
+ node_desc_override(ibdev, out_mad);
+ }
/* set return bit in status of directed route responses */
if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
index 9c849d27b06..266f347c670 100644
--- a/drivers/infiniband/hw/mthca/mthca_main.c
+++ b/drivers/infiniband/hw/mthca/mthca_main.c
@@ -935,13 +935,19 @@ enum {
static struct {
u64 latest_fw;
- int is_memfree;
- int is_pcie;
+ u32 flags;
} mthca_hca_table[] = {
- [TAVOR] = { .latest_fw = MTHCA_FW_VER(3, 3, 3), .is_memfree = 0, .is_pcie = 0 },
- [ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 7, 0), .is_memfree = 0, .is_pcie = 1 },
- [ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 1, 0), .is_memfree = 1, .is_pcie = 1 },
- [SINAI] = { .latest_fw = MTHCA_FW_VER(1, 0, 1), .is_memfree = 1, .is_pcie = 1 }
+ [TAVOR] = { .latest_fw = MTHCA_FW_VER(3, 4, 0),
+ .flags = 0 },
+ [ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 7, 400),
+ .flags = MTHCA_FLAG_PCIE },
+ [ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 1, 0),
+ .flags = MTHCA_FLAG_MEMFREE |
+ MTHCA_FLAG_PCIE },
+ [SINAI] = { .latest_fw = MTHCA_FW_VER(1, 0, 800),
+ .flags = MTHCA_FLAG_MEMFREE |
+ MTHCA_FLAG_PCIE |
+ MTHCA_FLAG_SINAI_OPT }
};
static int __devinit mthca_init_one(struct pci_dev *pdev,
@@ -1031,12 +1037,9 @@ static int __devinit mthca_init_one(struct pci_dev *pdev,
mdev->pdev = pdev;
+ mdev->mthca_flags = mthca_hca_table[id->driver_data].flags;
if (ddr_hidden)
mdev->mthca_flags |= MTHCA_FLAG_DDR_HIDDEN;
- if (mthca_hca_table[id->driver_data].is_memfree)
- mdev->mthca_flags |= MTHCA_FLAG_MEMFREE;
- if (mthca_hca_table[id->driver_data].is_pcie)
- mdev->mthca_flags |= MTHCA_FLAG_PCIE;
/*
* Now reset the HCA before we touch the PCI capabilities or
diff --git a/drivers/infiniband/hw/mthca/mthca_mcg.c b/drivers/infiniband/hw/mthca/mthca_mcg.c
index 321f11e707f..9965bda9afe 100644
--- a/drivers/infiniband/hw/mthca/mthca_mcg.c
+++ b/drivers/infiniband/hw/mthca/mthca_mcg.c
@@ -187,7 +187,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
for (i = 0; i < MTHCA_QP_PER_MGM; ++i)
if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31))) {
- mthca_dbg(dev, "QP %06x already a member of MGM\n",
+ mthca_dbg(dev, "QP %06x already a member of MGM\n",
ibqp->qp_num);
err = 0;
goto out;
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c
index d709cb162a7..15cc2f6eb47 100644
--- a/drivers/infiniband/hw/mthca/mthca_memfree.c
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.c
@@ -202,7 +202,8 @@ void mthca_table_put(struct mthca_dev *dev, struct mthca_icm_table *table, int o
if (--table->icm[i]->refcount == 0) {
mthca_UNMAP_ICM(dev, table->virt + i * MTHCA_TABLE_CHUNK_SIZE,
- MTHCA_TABLE_CHUNK_SIZE >> 12, &status);
+ MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE,
+ &status);
mthca_free_icm(dev, table->icm[i]);
table->icm[i] = NULL;
}
@@ -336,7 +337,8 @@ err:
for (i = 0; i < num_icm; ++i)
if (table->icm[i]) {
mthca_UNMAP_ICM(dev, virt + i * MTHCA_TABLE_CHUNK_SIZE,
- MTHCA_TABLE_CHUNK_SIZE >> 12, &status);
+ MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE,
+ &status);
mthca_free_icm(dev, table->icm[i]);
}
@@ -353,7 +355,8 @@ void mthca_free_icm_table(struct mthca_dev *dev, struct mthca_icm_table *table)
for (i = 0; i < table->num_icm; ++i)
if (table->icm[i]) {
mthca_UNMAP_ICM(dev, table->virt + i * MTHCA_TABLE_CHUNK_SIZE,
- MTHCA_TABLE_CHUNK_SIZE >> 12, &status);
+ MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE,
+ &status);
mthca_free_icm(dev, table->icm[i]);
}
@@ -364,7 +367,7 @@ static u64 mthca_uarc_virt(struct mthca_dev *dev, struct mthca_uar *uar, int pag
{
return dev->uar_table.uarc_base +
uar->index * dev->uar_table.uarc_size +
- page * 4096;
+ page * MTHCA_ICM_PAGE_SIZE;
}
int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
@@ -401,7 +404,7 @@ int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
if (ret < 0)
goto out;
- db_tab->page[i].mem.length = 4096;
+ db_tab->page[i].mem.length = MTHCA_ICM_PAGE_SIZE;
db_tab->page[i].mem.offset = uaddr & ~PAGE_MASK;
ret = pci_map_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
@@ -455,7 +458,7 @@ struct mthca_user_db_table *mthca_init_user_db_tab(struct mthca_dev *dev)
if (!mthca_is_memfree(dev))
return NULL;
- npages = dev->uar_table.uarc_size / 4096;
+ npages = dev->uar_table.uarc_size / MTHCA_ICM_PAGE_SIZE;
db_tab = kmalloc(sizeof *db_tab + npages * sizeof *db_tab->page, GFP_KERNEL);
if (!db_tab)
return ERR_PTR(-ENOMEM);
@@ -478,7 +481,7 @@ void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar,
if (!mthca_is_memfree(dev))
return;
- for (i = 0; i < dev->uar_table.uarc_size / 4096; ++i) {
+ for (i = 0; i < dev->uar_table.uarc_size / MTHCA_ICM_PAGE_SIZE; ++i) {
if (db_tab->page[i].uvirt) {
mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, uar, i), 1, &status);
pci_unmap_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
@@ -551,20 +554,20 @@ int mthca_alloc_db(struct mthca_dev *dev, enum mthca_db_type type,
page = dev->db_tab->page + end;
alloc:
- page->db_rec = dma_alloc_coherent(&dev->pdev->dev, 4096,
+ page->db_rec = dma_alloc_coherent(&dev->pdev->dev, MTHCA_ICM_PAGE_SIZE,
&page->mapping, GFP_KERNEL);
if (!page->db_rec) {
ret = -ENOMEM;
goto out;
}
- memset(page->db_rec, 0, 4096);
+ memset(page->db_rec, 0, MTHCA_ICM_PAGE_SIZE);
ret = mthca_MAP_ICM_page(dev, page->mapping,
mthca_uarc_virt(dev, &dev->driver_uar, i), &status);
if (!ret && status)
ret = -EINVAL;
if (ret) {
- dma_free_coherent(&dev->pdev->dev, 4096,
+ dma_free_coherent(&dev->pdev->dev, MTHCA_ICM_PAGE_SIZE,
page->db_rec, page->mapping);
goto out;
}
@@ -612,7 +615,7 @@ void mthca_free_db(struct mthca_dev *dev, int type, int db_index)
i >= dev->db_tab->max_group1 - 1) {
mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, &dev->driver_uar, i), 1, &status);
- dma_free_coherent(&dev->pdev->dev, 4096,
+ dma_free_coherent(&dev->pdev->dev, MTHCA_ICM_PAGE_SIZE,
page->db_rec, page->mapping);
page->db_rec = NULL;
@@ -640,7 +643,7 @@ int mthca_init_db_tab(struct mthca_dev *dev)
mutex_init(&dev->db_tab->mutex);
- dev->db_tab->npages = dev->uar_table.uarc_size / 4096;
+ dev->db_tab->npages = dev->uar_table.uarc_size / MTHCA_ICM_PAGE_SIZE;
dev->db_tab->max_group1 = 0;
dev->db_tab->min_group2 = dev->db_tab->npages - 1;
@@ -681,7 +684,7 @@ void mthca_cleanup_db_tab(struct mthca_dev *dev)
mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, &dev->driver_uar, i), 1, &status);
- dma_free_coherent(&dev->pdev->dev, 4096,
+ dma_free_coherent(&dev->pdev->dev, MTHCA_ICM_PAGE_SIZE,
dev->db_tab->page[i].db_rec,
dev->db_tab->page[i].mapping);
}
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.h b/drivers/infiniband/hw/mthca/mthca_memfree.h
index 36f1141a08a..6d42947e1dc 100644
--- a/drivers/infiniband/hw/mthca/mthca_memfree.h
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.h
@@ -45,6 +45,12 @@
((256 - sizeof (struct list_head) - 2 * sizeof (int)) / \
(sizeof (struct scatterlist)))
+enum {
+ MTHCA_ICM_PAGE_SHIFT = 12,
+ MTHCA_ICM_PAGE_SIZE = 1 << MTHCA_ICM_PAGE_SHIFT,
+ MTHCA_DB_REC_PER_PAGE = MTHCA_ICM_PAGE_SIZE / 8
+};
+
struct mthca_icm_chunk {
struct list_head list;
int npages;
@@ -131,10 +137,6 @@ static inline unsigned long mthca_icm_size(struct mthca_icm_iter *iter)
return sg_dma_len(&iter->chunk->mem[iter->page_idx]);
}
-enum {
- MTHCA_DB_REC_PER_PAGE = 4096 / 8
-};
-
struct mthca_db_page {
DECLARE_BITMAP(used, MTHCA_DB_REC_PER_PAGE);
__be64 *db_rec;
diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c
index e995e2aa016..698b6212576 100644
--- a/drivers/infiniband/hw/mthca/mthca_mr.c
+++ b/drivers/infiniband/hw/mthca/mthca_mr.c
@@ -76,6 +76,8 @@ struct mthca_mpt_entry {
#define MTHCA_MPT_STATUS_SW 0xF0
#define MTHCA_MPT_STATUS_HW 0x00
+#define SINAI_FMR_KEY_INC 0x1000000
+
/*
* Buddy allocator for MTT segments (currently not very efficient
* since it doesn't keep a free list and just searches linearly
@@ -330,6 +332,14 @@ static inline u32 key_to_hw_index(struct mthca_dev *dev, u32 key)
return tavor_key_to_hw_index(key);
}
+static inline u32 adjust_key(struct mthca_dev *dev, u32 key)
+{
+ if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT)
+ return ((key << 20) & 0x800000) | (key & 0x7fffff);
+ else
+ return key;
+}
+
int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift,
u64 iova, u64 total_size, u32 access, struct mthca_mr *mr)
{
@@ -340,13 +350,12 @@ int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift,
int err;
u8 status;
- might_sleep();
-
WARN_ON(buffer_size_shift >= 32);
key = mthca_alloc(&dev->mr_table.mpt_alloc);
if (key == -1)
return -ENOMEM;
+ key = adjust_key(dev, key);
mr->ibmr.rkey = mr->ibmr.lkey = hw_index_to_key(dev, key);
if (mthca_is_memfree(dev)) {
@@ -467,8 +476,6 @@ void mthca_free_mr(struct mthca_dev *dev, struct mthca_mr *mr)
int err;
u8 status;
- might_sleep();
-
err = mthca_HW2SW_MPT(dev, NULL,
key_to_hw_index(dev, mr->ibmr.lkey) &
(dev->limits.num_mpts - 1),
@@ -495,9 +502,7 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
int err = -ENOMEM;
int i;
- might_sleep();
-
- if (mr->attr.page_size < 12 || mr->attr.page_size >= 32)
+ if (mr->attr.page_shift < 12 || mr->attr.page_shift >= 32)
return -EINVAL;
/* For Arbel, all MTTs must fit in the same page. */
@@ -510,6 +515,7 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
key = mthca_alloc(&dev->mr_table.mpt_alloc);
if (key == -1)
return -ENOMEM;
+ key = adjust_key(dev, key);
idx = key & (dev->limits.num_mpts - 1);
mr->ibmr.rkey = mr->ibmr.lkey = hw_index_to_key(dev, key);
@@ -523,7 +529,7 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
BUG_ON(!mr->mem.arbel.mpt);
} else
mr->mem.tavor.mpt = dev->mr_table.tavor_fmr.mpt_base +
- sizeof *(mr->mem.tavor.mpt) * idx;
+ sizeof *(mr->mem.tavor.mpt) * idx;
mr->mtt = __mthca_alloc_mtt(dev, list_len, dev->mr_table.fmr_mtt_buddy);
if (IS_ERR(mr->mtt))
@@ -549,7 +555,7 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
MTHCA_MPT_FLAG_REGION |
access);
- mpt_entry->page_size = cpu_to_be32(mr->attr.page_size - 12);
+ mpt_entry->page_size = cpu_to_be32(mr->attr.page_shift - 12);
mpt_entry->key = cpu_to_be32(key);
mpt_entry->pd = cpu_to_be32(pd);
memset(&mpt_entry->start, 0,
@@ -617,7 +623,7 @@ static inline int mthca_check_fmr(struct mthca_fmr *fmr, u64 *page_list,
if (list_len > fmr->attr.max_pages)
return -EINVAL;
- page_mask = (1 << fmr->attr.page_size) - 1;
+ page_mask = (1 << fmr->attr.page_shift) - 1;
/* We are getting page lists, so va must be page aligned. */
if (iova & page_mask)
@@ -665,7 +671,7 @@ int mthca_tavor_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
}
mpt_entry.lkey = cpu_to_be32(key);
- mpt_entry.length = cpu_to_be64(list_len * (1ull << fmr->attr.page_size));
+ mpt_entry.length = cpu_to_be64(list_len * (1ull << fmr->attr.page_shift));
mpt_entry.start = cpu_to_be64(iova);
__raw_writel((__force u32) mpt_entry.lkey, &fmr->mem.tavor.mpt->key);
@@ -693,7 +699,10 @@ int mthca_arbel_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
++fmr->maps;
key = arbel_key_to_hw_index(fmr->ibmr.lkey);
- key += dev->limits.num_mpts;
+ if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT)
+ key += SINAI_FMR_KEY_INC;
+ else
+ key += dev->limits.num_mpts;
fmr->ibmr.lkey = fmr->ibmr.rkey = arbel_hw_index_to_key(key);
*(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_SW;
@@ -706,7 +715,7 @@ int mthca_arbel_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
fmr->mem.arbel.mpt->key = cpu_to_be32(key);
fmr->mem.arbel.mpt->lkey = cpu_to_be32(key);
- fmr->mem.arbel.mpt->length = cpu_to_be64(list_len * (1ull << fmr->attr.page_size));
+ fmr->mem.arbel.mpt->length = cpu_to_be64(list_len * (1ull << fmr->attr.page_shift));
fmr->mem.arbel.mpt->start = cpu_to_be64(iova);
wmb();
@@ -766,6 +775,9 @@ int __devinit mthca_init_mr_table(struct mthca_dev *dev)
else
dev->mthca_flags |= MTHCA_FLAG_FMR;
+ if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT)
+ mthca_dbg(dev, "Memory key throughput optimization activated.\n");
+
err = mthca_buddy_init(&dev->mr_table.mtt_buddy,
fls(dev->limits.num_mtt_segs - 1));
@@ -785,7 +797,7 @@ int __devinit mthca_init_mr_table(struct mthca_dev *dev)
}
dev->mr_table.tavor_fmr.mpt_base =
- ioremap(dev->mr_table.mpt_base,
+ ioremap(dev->mr_table.mpt_base,
(1 << i) * sizeof (struct mthca_mpt_entry));
if (!dev->mr_table.tavor_fmr.mpt_base) {
@@ -813,7 +825,7 @@ int __devinit mthca_init_mr_table(struct mthca_dev *dev)
goto err_reserve_fmr;
dev->mr_table.fmr_mtt_buddy =
- &dev->mr_table.tavor_fmr.mtt_buddy;
+ &dev->mr_table.tavor_fmr.mtt_buddy;
} else
dev->mr_table.fmr_mtt_buddy = &dev->mr_table.mtt_buddy;
diff --git a/drivers/infiniband/hw/mthca/mthca_pd.c b/drivers/infiniband/hw/mthca/mthca_pd.c
index 3dbf06a6e6f..105fc5faadd 100644
--- a/drivers/infiniband/hw/mthca/mthca_pd.c
+++ b/drivers/infiniband/hw/mthca/mthca_pd.c
@@ -43,8 +43,6 @@ int mthca_pd_alloc(struct mthca_dev *dev, int privileged, struct mthca_pd *pd)
{
int err = 0;
- might_sleep();
-
pd->privileged = privileged;
atomic_set(&pd->sqp_count, 0);
@@ -66,7 +64,6 @@ int mthca_pd_alloc(struct mthca_dev *dev, int privileged, struct mthca_pd *pd)
void mthca_pd_free(struct mthca_dev *dev, struct mthca_pd *pd)
{
- might_sleep();
if (pd->privileged)
mthca_free_mr(dev, &pd->ntmr);
mthca_free(&dev->pd_table.alloc, pd->pd_num);
diff --git a/drivers/infiniband/hw/mthca/mthca_profile.c b/drivers/infiniband/hw/mthca/mthca_profile.c
index 08a909371b0..58d44aa3c30 100644
--- a/drivers/infiniband/hw/mthca/mthca_profile.c
+++ b/drivers/infiniband/hw/mthca/mthca_profile.c
@@ -152,7 +152,7 @@ u64 mthca_make_profile(struct mthca_dev *dev,
}
if (total_size > mem_avail) {
mthca_err(dev, "Profile requires 0x%llx bytes; "
- "won't in 0x%llx bytes of context memory.\n",
+ "won't fit in 0x%llx bytes of context memory.\n",
(unsigned long long) total_size,
(unsigned long long) mem_avail);
kfree(profile);
@@ -262,6 +262,14 @@ u64 mthca_make_profile(struct mthca_dev *dev,
*/
dev->limits.num_pds = MTHCA_NUM_PDS;
+ if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT &&
+ init_hca->log_mpt_sz > 23) {
+ mthca_warn(dev, "MPT table too large (requested size 2^%d >= 2^24)\n",
+ init_hca->log_mpt_sz);
+ mthca_warn(dev, "Disabling memory key throughput optimization.\n");
+ dev->mthca_flags &= ~MTHCA_FLAG_SINAI_OPT;
+ }
+
/*
* For Tavor, FMRs use ioremapped PCI memory. For 32 bit
* systems it may use too much vmalloc space to map all MTT
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index e88e39aef85..2c250bc11c3 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
* Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
- * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved.
* Copyright (c) 2005 Mellanox Technologies. All rights reserved.
* Copyright (c) 2004 Voltaire, Inc. All rights reserved.
*
@@ -108,12 +108,12 @@ static int mthca_query_device(struct ib_device *ibdev,
props->max_srq_wr = mdev->limits.max_srq_wqes;
props->max_srq_sge = mdev->limits.max_sg;
props->local_ca_ack_delay = mdev->limits.local_ca_ack_delay;
- props->atomic_cap = mdev->limits.flags & DEV_LIM_FLAG_ATOMIC ?
+ props->atomic_cap = mdev->limits.flags & DEV_LIM_FLAG_ATOMIC ?
IB_ATOMIC_HCA : IB_ATOMIC_NONE;
props->max_pkeys = mdev->limits.pkey_table_len;
props->max_mcast_grp = mdev->limits.num_mgms + mdev->limits.num_amgms;
props->max_mcast_qp_attach = MTHCA_QP_PER_MGM;
- props->max_total_mcast_qp_attach = props->max_mcast_qp_attach *
+ props->max_total_mcast_qp_attach = props->max_mcast_qp_attach *
props->max_mcast_grp;
err = 0;
@@ -176,6 +176,23 @@ static int mthca_query_port(struct ib_device *ibdev,
return err;
}
+static int mthca_modify_device(struct ib_device *ibdev,
+ int mask,
+ struct ib_device_modify *props)
+{
+ if (mask & ~IB_DEVICE_MODIFY_NODE_DESC)
+ return -EOPNOTSUPP;
+
+ if (mask & IB_DEVICE_MODIFY_NODE_DESC) {
+ if (mutex_lock_interruptible(&to_mdev(ibdev)->cap_mask_mutex))
+ return -ERESTARTSYS;
+ memcpy(ibdev->node_desc, props->node_desc, 64);
+ mutex_unlock(&to_mdev(ibdev)->cap_mask_mutex);
+ }
+
+ return 0;
+}
+
static int mthca_modify_port(struct ib_device *ibdev,
u8 port, int port_modify_mask,
struct ib_port_modify *props)
@@ -669,9 +686,9 @@ static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries,
}
if (context) {
- cq->mr.ibmr.lkey = ucmd.lkey;
- cq->set_ci_db_index = ucmd.set_db_index;
- cq->arm_db_index = ucmd.arm_db_index;
+ cq->buf.mr.ibmr.lkey = ucmd.lkey;
+ cq->set_ci_db_index = ucmd.set_db_index;
+ cq->arm_db_index = ucmd.arm_db_index;
}
for (nent = 1; nent <= entries; nent <<= 1)
@@ -689,6 +706,8 @@ static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries,
goto err_free;
}
+ cq->resize_buf = NULL;
+
return &cq->ibcq;
err_free:
@@ -707,6 +726,121 @@ err_unmap_set:
return ERR_PTR(err);
}
+static int mthca_alloc_resize_buf(struct mthca_dev *dev, struct mthca_cq *cq,
+ int entries)
+{
+ int ret;
+
+ spin_lock_irq(&cq->lock);
+ if (cq->resize_buf) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ cq->resize_buf = kmalloc(sizeof *cq->resize_buf, GFP_ATOMIC);
+ if (!cq->resize_buf) {
+ ret = -ENOMEM;
+ goto unlock;
+ }
+
+ cq->resize_buf->state = CQ_RESIZE_ALLOC;
+
+ ret = 0;
+
+unlock:
+ spin_unlock_irq(&cq->lock);
+
+ if (ret)
+ return ret;
+
+ ret = mthca_alloc_cq_buf(dev, &cq->resize_buf->buf, entries);
+ if (ret) {
+ spin_lock_irq(&cq->lock);
+ kfree(cq->resize_buf);
+ cq->resize_buf = NULL;
+ spin_unlock_irq(&cq->lock);
+ return ret;
+ }
+
+ cq->resize_buf->cqe = entries - 1;
+
+ spin_lock_irq(&cq->lock);
+ cq->resize_buf->state = CQ_RESIZE_READY;
+ spin_unlock_irq(&cq->lock);
+
+ return 0;
+}
+
+static int mthca_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
+{
+ struct mthca_dev *dev = to_mdev(ibcq->device);
+ struct mthca_cq *cq = to_mcq(ibcq);
+ struct mthca_resize_cq ucmd;
+ u32 lkey;
+ u8 status;
+ int ret;
+
+ if (entries < 1 || entries > dev->limits.max_cqes)
+ return -EINVAL;
+
+ entries = roundup_pow_of_two(entries + 1);
+ if (entries == ibcq->cqe + 1)
+ return 0;
+
+ if (cq->is_kernel) {
+ ret = mthca_alloc_resize_buf(dev, cq, entries);
+ if (ret)
+ return ret;
+ lkey = cq->resize_buf->buf.mr.ibmr.lkey;
+ } else {
+ if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd))
+ return -EFAULT;
+ lkey = ucmd.lkey;
+ }
+
+ ret = mthca_RESIZE_CQ(dev, cq->cqn, lkey, long_log2(entries), &status);
+ if (status)
+ ret = -EINVAL;
+
+ if (ret) {
+ if (cq->resize_buf) {
+ mthca_free_cq_buf(dev, &cq->resize_buf->buf,
+ cq->resize_buf->cqe);
+ kfree(cq->resize_buf);
+ spin_lock_irq(&cq->lock);
+ cq->resize_buf = NULL;
+ spin_unlock_irq(&cq->lock);
+ }
+ return ret;
+ }
+
+ if (cq->is_kernel) {
+ struct mthca_cq_buf tbuf;
+ int tcqe;
+
+ spin_lock_irq(&cq->lock);
+ if (cq->resize_buf->state == CQ_RESIZE_READY) {
+ mthca_cq_resize_copy_cqes(cq);
+ tbuf = cq->buf;
+ tcqe = cq->ibcq.cqe;
+ cq->buf = cq->resize_buf->buf;
+ cq->ibcq.cqe = cq->resize_buf->cqe;
+ } else {
+ tbuf = cq->resize_buf->buf;
+ tcqe = cq->resize_buf->cqe;
+ }
+
+ kfree(cq->resize_buf);
+ cq->resize_buf = NULL;
+ spin_unlock_irq(&cq->lock);
+
+ mthca_free_cq_buf(dev, &tbuf, tcqe);
+ } else
+ ibcq->cqe = entries - 1;
+
+ return 0;
+}
+
static int mthca_destroy_cq(struct ib_cq *cq)
{
if (cq->uobject) {
@@ -1070,6 +1204,20 @@ static int mthca_init_node_data(struct mthca_dev *dev)
goto out;
init_query_mad(in_mad);
+ in_mad->attr_id = IB_SMP_ATTR_NODE_DESC;
+
+ err = mthca_MAD_IFC(dev, 1, 1,
+ 1, NULL, NULL, in_mad, out_mad,
+ &status);
+ if (err)
+ goto out;
+ if (status) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ memcpy(dev->ib_dev.node_desc, out_mad->data, 64);
+
in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
err = mthca_MAD_IFC(dev, 1, 1,
@@ -1113,14 +1261,17 @@ int mthca_register_device(struct mthca_dev *dev)
(1ull << IB_USER_VERBS_CMD_DEREG_MR) |
(1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
(1ull << IB_USER_VERBS_CMD_CREATE_CQ) |
+ (1ull << IB_USER_VERBS_CMD_RESIZE_CQ) |
(1ull << IB_USER_VERBS_CMD_DESTROY_CQ) |
(1ull << IB_USER_VERBS_CMD_CREATE_QP) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_QP) |
(1ull << IB_USER_VERBS_CMD_MODIFY_QP) |
(1ull << IB_USER_VERBS_CMD_DESTROY_QP) |
(1ull << IB_USER_VERBS_CMD_ATTACH_MCAST) |
(1ull << IB_USER_VERBS_CMD_DETACH_MCAST) |
(1ull << IB_USER_VERBS_CMD_CREATE_SRQ) |
(1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_SRQ) |
(1ull << IB_USER_VERBS_CMD_DESTROY_SRQ);
dev->ib_dev.node_type = IB_NODE_CA;
dev->ib_dev.phys_port_cnt = dev->limits.num_ports;
@@ -1128,6 +1279,7 @@ int mthca_register_device(struct mthca_dev *dev)
dev->ib_dev.class_dev.dev = &dev->pdev->dev;
dev->ib_dev.query_device = mthca_query_device;
dev->ib_dev.query_port = mthca_query_port;
+ dev->ib_dev.modify_device = mthca_modify_device;
dev->ib_dev.modify_port = mthca_modify_port;
dev->ib_dev.query_pkey = mthca_query_pkey;
dev->ib_dev.query_gid = mthca_query_gid;
@@ -1137,11 +1289,13 @@ int mthca_register_device(struct mthca_dev *dev)
dev->ib_dev.alloc_pd = mthca_alloc_pd;
dev->ib_dev.dealloc_pd = mthca_dealloc_pd;
dev->ib_dev.create_ah = mthca_ah_create;
+ dev->ib_dev.query_ah = mthca_ah_query;
dev->ib_dev.destroy_ah = mthca_ah_destroy;
if (dev->mthca_flags & MTHCA_FLAG_SRQ) {
dev->ib_dev.create_srq = mthca_create_srq;
- dev->ib_dev.modify_srq = mthca_modify_srq;
+ dev->ib_dev.modify_srq = mthca_modify_srq;
+ dev->ib_dev.query_srq = mthca_query_srq;
dev->ib_dev.destroy_srq = mthca_destroy_srq;
if (mthca_is_memfree(dev))
@@ -1152,8 +1306,10 @@ int mthca_register_device(struct mthca_dev *dev)
dev->ib_dev.create_qp = mthca_create_qp;
dev->ib_dev.modify_qp = mthca_modify_qp;
+ dev->ib_dev.query_qp = mthca_query_qp;
dev->ib_dev.destroy_qp = mthca_destroy_qp;
dev->ib_dev.create_cq = mthca_create_cq;
+ dev->ib_dev.resize_cq = mthca_resize_cq;
dev->ib_dev.destroy_cq = mthca_destroy_cq;
dev->ib_dev.poll_cq = mthca_poll_cq;
dev->ib_dev.get_dma_mr = mthca_get_dma_mr;
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h
index 1e73947b470..2e7f5213696 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.h
+++ b/drivers/infiniband/hw/mthca/mthca_provider.h
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2004 Topspin Communications. All rights reserved.
- * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved.
* Copyright (c) 2005 Mellanox Technologies. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -164,9 +164,11 @@ struct mthca_ah {
* - wait_event until ref count is zero
*
* It is the consumer's responsibilty to make sure that no QP
- * operations (WQE posting or state modification) are pending when the
+ * operations (WQE posting or state modification) are pending when a
* QP is destroyed. Also, the consumer must make sure that calls to
- * qp_modify are serialized.
+ * qp_modify are serialized. Similarly, the consumer is responsible
+ * for ensuring that no CQ resize operations are pending when a CQ
+ * is destroyed.
*
* Possible optimizations (wait for profile data to see if/where we
* have locks bouncing between CPUs):
@@ -176,25 +178,40 @@ struct mthca_ah {
* send queue and one for the receive queue)
*/
+struct mthca_cq_buf {
+ union mthca_buf queue;
+ struct mthca_mr mr;
+ int is_direct;
+};
+
+struct mthca_cq_resize {
+ struct mthca_cq_buf buf;
+ int cqe;
+ enum {
+ CQ_RESIZE_ALLOC,
+ CQ_RESIZE_READY,
+ CQ_RESIZE_SWAPPED
+ } state;
+};
+
struct mthca_cq {
- struct ib_cq ibcq;
- spinlock_t lock;
- atomic_t refcount;
- int cqn;
- u32 cons_index;
- int is_direct;
- int is_kernel;
+ struct ib_cq ibcq;
+ spinlock_t lock;
+ atomic_t refcount;
+ int cqn;
+ u32 cons_index;
+ struct mthca_cq_buf buf;
+ struct mthca_cq_resize *resize_buf;
+ int is_kernel;
/* Next fields are Arbel only */
- int set_ci_db_index;
- __be32 *set_ci_db;
- int arm_db_index;
- __be32 *arm_db;
- int arm_sn;
+ int set_ci_db_index;
+ __be32 *set_ci_db;
+ int arm_db_index;
+ __be32 *arm_db;
+ int arm_sn;
- union mthca_buf queue;
- struct mthca_mr mr;
- wait_queue_head_t wait;
+ wait_queue_head_t wait;
};
struct mthca_srq {
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index fba608ed7df..f673c461e30 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -2,7 +2,7 @@
* Copyright (c) 2004 Topspin Communications. All rights reserved.
* Copyright (c) 2005 Cisco Systems. All rights reserved.
* Copyright (c) 2005 Mellanox Technologies. All rights reserved.
- * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -286,207 +286,6 @@ static int to_mthca_st(int transport)
}
}
-static const struct {
- int trans;
- u32 req_param[NUM_TRANS];
- u32 opt_param[NUM_TRANS];
-} state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
- [IB_QPS_RESET] = {
- [IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
- [IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR },
- [IB_QPS_INIT] = {
- .trans = MTHCA_TRANS_RST2INIT,
- .req_param = {
- [UD] = (IB_QP_PKEY_INDEX |
- IB_QP_PORT |
- IB_QP_QKEY),
- [UC] = (IB_QP_PKEY_INDEX |
- IB_QP_PORT |
- IB_QP_ACCESS_FLAGS),
- [RC] = (IB_QP_PKEY_INDEX |
- IB_QP_PORT |
- IB_QP_ACCESS_FLAGS),
- [MLX] = (IB_QP_PKEY_INDEX |
- IB_QP_QKEY),
- },
- /* bug-for-bug compatibility with VAPI: */
- .opt_param = {
- [MLX] = IB_QP_PORT
- }
- },
- },
- [IB_QPS_INIT] = {
- [IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
- [IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR },
- [IB_QPS_INIT] = {
- .trans = MTHCA_TRANS_INIT2INIT,
- .opt_param = {
- [UD] = (IB_QP_PKEY_INDEX |
- IB_QP_PORT |
- IB_QP_QKEY),
- [UC] = (IB_QP_PKEY_INDEX |
- IB_QP_PORT |
- IB_QP_ACCESS_FLAGS),
- [RC] = (IB_QP_PKEY_INDEX |
- IB_QP_PORT |
- IB_QP_ACCESS_FLAGS),
- [MLX] = (IB_QP_PKEY_INDEX |
- IB_QP_QKEY),
- }
- },
- [IB_QPS_RTR] = {
- .trans = MTHCA_TRANS_INIT2RTR,
- .req_param = {
- [UC] = (IB_QP_AV |
- IB_QP_PATH_MTU |
- IB_QP_DEST_QPN |
- IB_QP_RQ_PSN),
- [RC] = (IB_QP_AV |
- IB_QP_PATH_MTU |
- IB_QP_DEST_QPN |
- IB_QP_RQ_PSN |
- IB_QP_MAX_DEST_RD_ATOMIC |
- IB_QP_MIN_RNR_TIMER),
- },
- .opt_param = {
- [UD] = (IB_QP_PKEY_INDEX |
- IB_QP_QKEY),
- [UC] = (IB_QP_ALT_PATH |
- IB_QP_ACCESS_FLAGS |
- IB_QP_PKEY_INDEX),
- [RC] = (IB_QP_ALT_PATH |
- IB_QP_ACCESS_FLAGS |
- IB_QP_PKEY_INDEX),
- [MLX] = (IB_QP_PKEY_INDEX |
- IB_QP_QKEY),
- }
- }
- },
- [IB_QPS_RTR] = {
- [IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
- [IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR },
- [IB_QPS_RTS] = {
- .trans = MTHCA_TRANS_RTR2RTS,
- .req_param = {
- [UD] = IB_QP_SQ_PSN,
- [UC] = IB_QP_SQ_PSN,
- [RC] = (IB_QP_TIMEOUT |
- IB_QP_RETRY_CNT |
- IB_QP_RNR_RETRY |
- IB_QP_SQ_PSN |
- IB_QP_MAX_QP_RD_ATOMIC),
- [MLX] = IB_QP_SQ_PSN,
- },
- .opt_param = {
- [UD] = (IB_QP_CUR_STATE |
- IB_QP_QKEY),
- [UC] = (IB_QP_CUR_STATE |
- IB_QP_ALT_PATH |
- IB_QP_ACCESS_FLAGS |
- IB_QP_PATH_MIG_STATE),
- [RC] = (IB_QP_CUR_STATE |
- IB_QP_ALT_PATH |
- IB_QP_ACCESS_FLAGS |
- IB_QP_MIN_RNR_TIMER |
- IB_QP_PATH_MIG_STATE),
- [MLX] = (IB_QP_CUR_STATE |
- IB_QP_QKEY),
- }
- }
- },
- [IB_QPS_RTS] = {
- [IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
- [IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR },
- [IB_QPS_RTS] = {
- .trans = MTHCA_TRANS_RTS2RTS,
- .opt_param = {
- [UD] = (IB_QP_CUR_STATE |
- IB_QP_QKEY),
- [UC] = (IB_QP_ACCESS_FLAGS |
- IB_QP_ALT_PATH |
- IB_QP_PATH_MIG_STATE),
- [RC] = (IB_QP_ACCESS_FLAGS |
- IB_QP_ALT_PATH |
- IB_QP_PATH_MIG_STATE |
- IB_QP_MIN_RNR_TIMER),
- [MLX] = (IB_QP_CUR_STATE |
- IB_QP_QKEY),
- }
- },
- [IB_QPS_SQD] = {
- .trans = MTHCA_TRANS_RTS2SQD,
- },
- },
- [IB_QPS_SQD] = {
- [IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
- [IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR },
- [IB_QPS_RTS] = {
- .trans = MTHCA_TRANS_SQD2RTS,
- .opt_param = {
- [UD] = (IB_QP_CUR_STATE |
- IB_QP_QKEY),
- [UC] = (IB_QP_CUR_STATE |
- IB_QP_ALT_PATH |
- IB_QP_ACCESS_FLAGS |
- IB_QP_PATH_MIG_STATE),
- [RC] = (IB_QP_CUR_STATE |
- IB_QP_ALT_PATH |
- IB_QP_ACCESS_FLAGS |
- IB_QP_MIN_RNR_TIMER |
- IB_QP_PATH_MIG_STATE),
- [MLX] = (IB_QP_CUR_STATE |
- IB_QP_QKEY),
- }
- },
- [IB_QPS_SQD] = {
- .trans = MTHCA_TRANS_SQD2SQD,
- .opt_param = {
- [UD] = (IB_QP_PKEY_INDEX |
- IB_QP_QKEY),
- [UC] = (IB_QP_AV |
- IB_QP_CUR_STATE |
- IB_QP_ALT_PATH |
- IB_QP_ACCESS_FLAGS |
- IB_QP_PKEY_INDEX |
- IB_QP_PATH_MIG_STATE),
- [RC] = (IB_QP_AV |
- IB_QP_TIMEOUT |
- IB_QP_RETRY_CNT |
- IB_QP_RNR_RETRY |
- IB_QP_MAX_QP_RD_ATOMIC |
- IB_QP_MAX_DEST_RD_ATOMIC |
- IB_QP_CUR_STATE |
- IB_QP_ALT_PATH |
- IB_QP_ACCESS_FLAGS |
- IB_QP_PKEY_INDEX |
- IB_QP_MIN_RNR_TIMER |
- IB_QP_PATH_MIG_STATE),
- [MLX] = (IB_QP_PKEY_INDEX |
- IB_QP_QKEY),
- }
- }
- },
- [IB_QPS_SQE] = {
- [IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
- [IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR },
- [IB_QPS_RTS] = {
- .trans = MTHCA_TRANS_SQERR2RTS,
- .opt_param = {
- [UD] = (IB_QP_CUR_STATE |
- IB_QP_QKEY),
- [UC] = (IB_QP_CUR_STATE |
- IB_QP_ACCESS_FLAGS),
- [MLX] = (IB_QP_CUR_STATE |
- IB_QP_QKEY),
- }
- }
- },
- [IB_QPS_ERR] = {
- [IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
- [IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR }
- }
-};
-
static void store_attrs(struct mthca_sqp *sqp, struct ib_qp_attr *attr,
int attr_mask)
{
@@ -549,6 +348,141 @@ static __be32 get_hw_access_flags(struct mthca_qp *qp, struct ib_qp_attr *attr,
return cpu_to_be32(hw_access_flags);
}
+static inline enum ib_qp_state to_ib_qp_state(int mthca_state)
+{
+ switch (mthca_state) {
+ case MTHCA_QP_STATE_RST: return IB_QPS_RESET;
+ case MTHCA_QP_STATE_INIT: return IB_QPS_INIT;
+ case MTHCA_QP_STATE_RTR: return IB_QPS_RTR;
+ case MTHCA_QP_STATE_RTS: return IB_QPS_RTS;
+ case MTHCA_QP_STATE_DRAINING:
+ case MTHCA_QP_STATE_SQD: return IB_QPS_SQD;
+ case MTHCA_QP_STATE_SQE: return IB_QPS_SQE;
+ case MTHCA_QP_STATE_ERR: return IB_QPS_ERR;
+ default: return -1;
+ }
+}
+
+static inline enum ib_mig_state to_ib_mig_state(int mthca_mig_state)
+{
+ switch (mthca_mig_state) {
+ case 0: return IB_MIG_ARMED;
+ case 1: return IB_MIG_REARM;
+ case 3: return IB_MIG_MIGRATED;
+ default: return -1;
+ }
+}
+
+static int to_ib_qp_access_flags(int mthca_flags)
+{
+ int ib_flags = 0;
+
+ if (mthca_flags & MTHCA_QP_BIT_RRE)
+ ib_flags |= IB_ACCESS_REMOTE_READ;
+ if (mthca_flags & MTHCA_QP_BIT_RWE)
+ ib_flags |= IB_ACCESS_REMOTE_WRITE;
+ if (mthca_flags & MTHCA_QP_BIT_RAE)
+ ib_flags |= IB_ACCESS_REMOTE_ATOMIC;
+
+ return ib_flags;
+}
+
+static void to_ib_ah_attr(struct mthca_dev *dev, struct ib_ah_attr *ib_ah_attr,
+ struct mthca_qp_path *path)
+{
+ memset(ib_ah_attr, 0, sizeof *path);
+ ib_ah_attr->port_num = (be32_to_cpu(path->port_pkey) >> 24) & 0x3;
+ ib_ah_attr->dlid = be16_to_cpu(path->rlid);
+ ib_ah_attr->sl = be32_to_cpu(path->sl_tclass_flowlabel) >> 28;
+ ib_ah_attr->src_path_bits = path->g_mylmc & 0x7f;
+ ib_ah_attr->static_rate = path->static_rate & 0x7;
+ ib_ah_attr->ah_flags = (path->g_mylmc & (1 << 7)) ? IB_AH_GRH : 0;
+ if (ib_ah_attr->ah_flags) {
+ ib_ah_attr->grh.sgid_index = path->mgid_index & (dev->limits.gid_table_len - 1);
+ ib_ah_attr->grh.hop_limit = path->hop_limit;
+ ib_ah_attr->grh.traffic_class =
+ (be32_to_cpu(path->sl_tclass_flowlabel) >> 20) & 0xff;
+ ib_ah_attr->grh.flow_label =
+ be32_to_cpu(path->sl_tclass_flowlabel) & 0xfffff;
+ memcpy(ib_ah_attr->grh.dgid.raw,
+ path->rgid, sizeof ib_ah_attr->grh.dgid.raw);
+ }
+}
+
+int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask,
+ struct ib_qp_init_attr *qp_init_attr)
+{
+ struct mthca_dev *dev = to_mdev(ibqp->device);
+ struct mthca_qp *qp = to_mqp(ibqp);
+ int err;
+ struct mthca_mailbox *mailbox;
+ struct mthca_qp_param *qp_param;
+ struct mthca_qp_context *context;
+ int mthca_state;
+ u8 status;
+
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+
+ err = mthca_QUERY_QP(dev, qp->qpn, 0, mailbox, &status);
+ if (err)
+ goto out;
+ if (status) {
+ mthca_warn(dev, "QUERY_QP returned status %02x\n", status);
+ err = -EINVAL;
+ goto out;
+ }
+
+ qp_param = mailbox->buf;
+ context = &qp_param->context;
+ mthca_state = be32_to_cpu(context->flags) >> 28;
+
+ qp_attr->qp_state = to_ib_qp_state(mthca_state);
+ qp_attr->cur_qp_state = qp_attr->qp_state;
+ qp_attr->path_mtu = context->mtu_msgmax >> 5;
+ qp_attr->path_mig_state =
+ to_ib_mig_state((be32_to_cpu(context->flags) >> 11) & 0x3);
+ qp_attr->qkey = be32_to_cpu(context->qkey);
+ qp_attr->rq_psn = be32_to_cpu(context->rnr_nextrecvpsn) & 0xffffff;
+ qp_attr->sq_psn = be32_to_cpu(context->next_send_psn) & 0xffffff;
+ qp_attr->dest_qp_num = be32_to_cpu(context->remote_qpn) & 0xffffff;
+ qp_attr->qp_access_flags =
+ to_ib_qp_access_flags(be32_to_cpu(context->params2));
+ qp_attr->cap.max_send_wr = qp->sq.max;
+ qp_attr->cap.max_recv_wr = qp->rq.max;
+ qp_attr->cap.max_send_sge = qp->sq.max_gs;
+ qp_attr->cap.max_recv_sge = qp->rq.max_gs;
+ qp_attr->cap.max_inline_data = qp->max_inline_data;
+
+ to_ib_ah_attr(dev, &qp_attr->ah_attr, &context->pri_path);
+ to_ib_ah_attr(dev, &qp_attr->alt_ah_attr, &context->alt_path);
+
+ qp_attr->pkey_index = be32_to_cpu(context->pri_path.port_pkey) & 0x7f;
+ qp_attr->alt_pkey_index = be32_to_cpu(context->alt_path.port_pkey) & 0x7f;
+
+ /* qp_attr->en_sqd_async_notify is only applicable in modify qp */
+ qp_attr->sq_draining = mthca_state == MTHCA_QP_STATE_DRAINING;
+
+ qp_attr->max_rd_atomic = 1 << ((be32_to_cpu(context->params1) >> 21) & 0x7);
+
+ qp_attr->max_dest_rd_atomic =
+ 1 << ((be32_to_cpu(context->params2) >> 21) & 0x7);
+ qp_attr->min_rnr_timer =
+ (be32_to_cpu(context->rnr_nextrecvpsn) >> 24) & 0x1f;
+ qp_attr->port_num = qp_attr->ah_attr.port_num;
+ qp_attr->timeout = context->pri_path.ackto >> 3;
+ qp_attr->retry_cnt = (be32_to_cpu(context->params1) >> 16) & 0x7;
+ qp_attr->rnr_retry = context->pri_path.rnr_retry >> 5;
+ qp_attr->alt_port_num = qp_attr->alt_ah_attr.port_num;
+ qp_attr->alt_timeout = context->alt_path.ackto >> 3;
+ qp_init_attr->cap = qp_attr->cap;
+
+out:
+ mthca_free_mailbox(dev, mailbox);
+ return err;
+}
+
static void mthca_path_set(struct ib_ah_attr *ah, struct mthca_qp_path *path)
{
path->g_mylmc = ah->src_path_bits & 0x7f;
@@ -559,9 +493,9 @@ static void mthca_path_set(struct ib_ah_attr *ah, struct mthca_qp_path *path)
path->g_mylmc |= 1 << 7;
path->mgid_index = ah->grh.sgid_index;
path->hop_limit = ah->grh.hop_limit;
- path->sl_tclass_flowlabel =
+ path->sl_tclass_flowlabel =
cpu_to_be32((ah->sl << 28) |
- (ah->grh.traffic_class << 20) |
+ (ah->grh.traffic_class << 20) |
(ah->grh.flow_label));
memcpy(path->rgid, ah->grh.dgid.raw, 16);
} else
@@ -576,18 +510,12 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
struct mthca_mailbox *mailbox;
struct mthca_qp_param *qp_param;
struct mthca_qp_context *qp_context;
- u32 req_param, opt_param;
+ u32 sqd_event = 0;
u8 status;
int err;
if (attr_mask & IB_QP_CUR_STATE) {
- if (attr->cur_qp_state != IB_QPS_RTR &&
- attr->cur_qp_state != IB_QPS_RTS &&
- attr->cur_qp_state != IB_QPS_SQD &&
- attr->cur_qp_state != IB_QPS_SQE)
- return -EINVAL;
- else
- cur_state = attr->cur_qp_state;
+ cur_state = attr->cur_qp_state;
} else {
spin_lock_irq(&qp->sq.lock);
spin_lock(&qp->rq.lock);
@@ -596,44 +524,20 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
spin_unlock_irq(&qp->sq.lock);
}
- if (attr_mask & IB_QP_STATE) {
- if (attr->qp_state < 0 || attr->qp_state > IB_QPS_ERR)
- return -EINVAL;
- new_state = attr->qp_state;
- } else
- new_state = cur_state;
-
- if (state_table[cur_state][new_state].trans == MTHCA_TRANS_INVALID) {
- mthca_dbg(dev, "Illegal QP transition "
- "%d->%d\n", cur_state, new_state);
- return -EINVAL;
- }
-
- req_param = state_table[cur_state][new_state].req_param[qp->transport];
- opt_param = state_table[cur_state][new_state].opt_param[qp->transport];
+ new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state;
- if ((req_param & attr_mask) != req_param) {
- mthca_dbg(dev, "QP transition "
- "%d->%d missing req attr 0x%08x\n",
- cur_state, new_state,
- req_param & ~attr_mask);
+ if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, attr_mask)) {
+ mthca_dbg(dev, "Bad QP transition (transport %d) "
+ "%d->%d with attr 0x%08x\n",
+ qp->transport, cur_state, new_state,
+ attr_mask);
return -EINVAL;
}
- if (attr_mask & ~(req_param | opt_param | IB_QP_STATE)) {
- mthca_dbg(dev, "QP transition (transport %d) "
- "%d->%d has extra attr 0x%08x\n",
- qp->transport,
- cur_state, new_state,
- attr_mask & ~(req_param | opt_param |
- IB_QP_STATE));
- return -EINVAL;
- }
-
- if ((attr_mask & IB_QP_PKEY_INDEX) &&
+ if ((attr_mask & IB_QP_PKEY_INDEX) &&
attr->pkey_index >= dev->limits.pkey_table_len) {
- mthca_dbg(dev, "PKey index (%u) too large. max is %d\n",
- attr->pkey_index,dev->limits.pkey_table_len-1);
+ mthca_dbg(dev, "P_Key index (%u) too large. max is %d\n",
+ attr->pkey_index, dev->limits.pkey_table_len-1);
return -EINVAL;
}
@@ -733,7 +637,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
if (attr_mask & IB_QP_RNR_RETRY) {
qp_context->alt_path.rnr_retry = qp_context->pri_path.rnr_retry =
attr->rnr_retry << 5;
- qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RNR_RETRY |
+ qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RNR_RETRY |
MTHCA_QP_OPTPAR_ALT_RNR_RETRY);
}
@@ -748,14 +652,20 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
}
if (attr_mask & IB_QP_ALT_PATH) {
+ if (attr->alt_pkey_index >= dev->limits.pkey_table_len) {
+ mthca_dbg(dev, "Alternate P_Key index (%u) too large. max is %d\n",
+ attr->alt_pkey_index, dev->limits.pkey_table_len-1);
+ return -EINVAL;
+ }
+
if (attr->alt_port_num == 0 || attr->alt_port_num > dev->limits.num_ports) {
- mthca_dbg(dev, "Alternate port number (%u) is invalid\n",
+ mthca_dbg(dev, "Alternate port number (%u) is invalid\n",
attr->alt_port_num);
return -EINVAL;
}
mthca_path_set(&attr->alt_ah_attr, &qp_context->alt_path);
- qp_context->alt_path.port_pkey |= cpu_to_be32(attr->alt_pkey_index |
+ qp_context->alt_path.port_pkey |= cpu_to_be32(attr->alt_pkey_index |
attr->alt_port_num << 24);
qp_context->alt_path.ackto = attr->alt_timeout << 3;
qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_ALT_ADDR_PATH);
@@ -841,11 +751,16 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
qp_context->srqn = cpu_to_be32(1 << 24 |
to_msrq(ibqp->srq)->srqn);
- err = mthca_MODIFY_QP(dev, state_table[cur_state][new_state].trans,
- qp->qpn, 0, mailbox, 0, &status);
+ if (cur_state == IB_QPS_RTS && new_state == IB_QPS_SQD &&
+ attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY &&
+ attr->en_sqd_async_notify)
+ sqd_event = 1 << 31;
+
+ err = mthca_MODIFY_QP(dev, cur_state, new_state, qp->qpn, 0,
+ mailbox, sqd_event, &status);
if (status) {
- mthca_warn(dev, "modify QP %d returned status %02x.\n",
- state_table[cur_state][new_state].trans, status);
+ mthca_warn(dev, "modify QP %d->%d returned status %02x.\n",
+ cur_state, new_state, status);
err = -EINVAL;
}
@@ -1078,10 +993,10 @@ static int mthca_map_memfree(struct mthca_dev *dev,
if (ret)
goto err_qpc;
- ret = mthca_table_get(dev, dev->qp_table.rdb_table,
- qp->qpn << dev->qp_table.rdb_shift);
- if (ret)
- goto err_eqpc;
+ ret = mthca_table_get(dev, dev->qp_table.rdb_table,
+ qp->qpn << dev->qp_table.rdb_shift);
+ if (ret)
+ goto err_eqpc;
}
@@ -1393,7 +1308,8 @@ void mthca_free_qp(struct mthca_dev *dev,
wait_event(qp->wait, !atomic_read(&qp->refcount));
if (qp->state != IB_QPS_RESET)
- mthca_MODIFY_QP(dev, MTHCA_TRANS_ANY2RST, qp->qpn, 0, NULL, 0, &status);
+ mthca_MODIFY_QP(dev, qp->state, IB_QPS_RESET, qp->qpn, 0,
+ NULL, 0, &status);
/*
* If this is a userspace QP, the buffers, MR, CQs and so on
@@ -1699,7 +1615,9 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
mthca_opcode[wr->opcode]);
wmb();
((struct mthca_next_seg *) prev_wqe)->ee_nds =
- cpu_to_be32((size0 ? 0 : MTHCA_NEXT_DBD) | size);
+ cpu_to_be32((size0 ? 0 : MTHCA_NEXT_DBD) | size |
+ ((wr->send_flags & IB_SEND_FENCE) ?
+ MTHCA_NEXT_FENCE : 0));
if (!size0) {
size0 = size;
@@ -2061,7 +1979,9 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
mthca_opcode[wr->opcode]);
wmb();
((struct mthca_next_seg *) prev_wqe)->ee_nds =
- cpu_to_be32(MTHCA_NEXT_DBD | size);
+ cpu_to_be32(MTHCA_NEXT_DBD | size |
+ ((wr->send_flags & IB_SEND_FENCE) ?
+ MTHCA_NEXT_FENCE : 0));
if (!size0) {
size0 = size;
@@ -2115,7 +2035,7 @@ int mthca_arbel_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
int i;
void *wqe;
- spin_lock_irqsave(&qp->rq.lock, flags);
+ spin_lock_irqsave(&qp->rq.lock, flags);
/* XXX check that state is OK to post receive */
@@ -2182,8 +2102,8 @@ out:
return err;
}
-int mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send,
- int index, int *dbd, __be32 *new_wqe)
+void mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send,
+ int index, int *dbd, __be32 *new_wqe)
{
struct mthca_next_seg *next;
@@ -2193,7 +2113,7 @@ int mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send,
*/
if (qp->ibqp.srq) {
*new_wqe = 0;
- return 0;
+ return;
}
if (is_send)
@@ -2207,8 +2127,6 @@ int mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send,
(next->ee_nds & cpu_to_be32(0x3f));
else
*new_wqe = 0;
-
- return 0;
}
int __devinit mthca_init_qp_table(struct mthca_dev *dev)
diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c
index e7e153d9c4c..47a6a754a59 100644
--- a/drivers/infiniband/hw/mthca/mthca_srq.c
+++ b/drivers/infiniband/hw/mthca/mthca_srq.c
@@ -49,7 +49,8 @@ struct mthca_tavor_srq_context {
__be32 state_pd;
__be32 lkey;
__be32 uar;
- __be32 wqe_cnt;
+ __be16 limit_watermark;
+ __be16 wqe_cnt;
u32 reserved[2];
};
@@ -271,6 +272,9 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd,
srq->first_free = 0;
srq->last_free = srq->max - 1;
+ attr->max_wr = (mthca_is_memfree(dev)) ? srq->max - 1 : srq->max;
+ attr->max_sge = srq->max_gs;
+
return 0;
err_out_free_srq:
@@ -339,7 +343,7 @@ void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq)
int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
enum ib_srq_attr_mask attr_mask)
-{
+{
struct mthca_dev *dev = to_mdev(ibsrq->device);
struct mthca_srq *srq = to_msrq(ibsrq);
int ret;
@@ -360,6 +364,41 @@ int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
return 0;
}
+int mthca_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr)
+{
+ struct mthca_dev *dev = to_mdev(ibsrq->device);
+ struct mthca_srq *srq = to_msrq(ibsrq);
+ struct mthca_mailbox *mailbox;
+ struct mthca_arbel_srq_context *arbel_ctx;
+ struct mthca_tavor_srq_context *tavor_ctx;
+ u8 status;
+ int err;
+
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+
+ err = mthca_QUERY_SRQ(dev, srq->srqn, mailbox, &status);
+ if (err)
+ goto out;
+
+ if (mthca_is_memfree(dev)) {
+ arbel_ctx = mailbox->buf;
+ srq_attr->srq_limit = be16_to_cpu(arbel_ctx->limit_watermark);
+ } else {
+ tavor_ctx = mailbox->buf;
+ srq_attr->srq_limit = be16_to_cpu(tavor_ctx->limit_watermark);
+ }
+
+ srq_attr->max_wr = (mthca_is_memfree(dev)) ? srq->max - 1 : srq->max;
+ srq_attr->max_sge = srq->max_gs;
+
+out:
+ mthca_free_mailbox(dev, mailbox);
+
+ return err;
+}
+
void mthca_srq_event(struct mthca_dev *dev, u32 srqn,
enum ib_event_type event_type)
{
diff --git a/drivers/infiniband/hw/mthca/mthca_user.h b/drivers/infiniband/hw/mthca/mthca_user.h
index bb015c6494c..02cc0a766f3 100644
--- a/drivers/infiniband/hw/mthca/mthca_user.h
+++ b/drivers/infiniband/hw/mthca/mthca_user.h
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2005 Topspin Communications. All rights reserved.
- * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -75,6 +75,11 @@ struct mthca_create_cq_resp {
__u32 reserved;
};
+struct mthca_resize_cq {
+ __u32 lkey;
+ __u32 reserved;
+};
+
struct mthca_create_srq {
__u32 lkey;
__u32 db_index;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 2f85a9a831b..1251f86ec85 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -217,10 +217,16 @@ struct ipoib_neigh {
struct list_head list;
};
+/*
+ * We stash a pointer to our private neighbour information after our
+ * hardware address in neigh->ha. The ALIGN() expression here makes
+ * sure that this pointer is stored aligned so that an unaligned
+ * load is not needed to dereference it.
+ */
static inline struct ipoib_neigh **to_ipoib_neigh(struct neighbour *neigh)
{
- return (struct ipoib_neigh **) (neigh->ha + 24 -
- (offsetof(struct neighbour, ha) & 4));
+ return (void*) neigh + ALIGN(offsetof(struct neighbour, ha) +
+ INFINIBAND_ALEN, sizeof(void *));
}
extern struct workqueue_struct *ipoib_workqueue;
@@ -253,7 +259,7 @@ void ipoib_ib_dev_cleanup(struct net_device *dev);
int ipoib_ib_dev_open(struct net_device *dev);
int ipoib_ib_dev_up(struct net_device *dev);
-int ipoib_ib_dev_down(struct net_device *dev);
+int ipoib_ib_dev_down(struct net_device *dev, int flush);
int ipoib_ib_dev_stop(struct net_device *dev);
int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index 86bcdd72a10..a1f5a05f2f3 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -416,6 +416,7 @@ int ipoib_ib_dev_open(struct net_device *dev)
ret = ipoib_ib_post_receives(dev);
if (ret) {
ipoib_warn(priv, "ipoib_ib_post_receives returned %d\n", ret);
+ ipoib_ib_dev_stop(dev);
return -1;
}
@@ -434,7 +435,7 @@ int ipoib_ib_dev_up(struct net_device *dev)
return ipoib_mcast_start_thread(dev);
}
-int ipoib_ib_dev_down(struct net_device *dev)
+int ipoib_ib_dev_down(struct net_device *dev, int flush)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -449,10 +450,11 @@ int ipoib_ib_dev_down(struct net_device *dev)
set_bit(IPOIB_PKEY_STOP, &priv->flags);
cancel_delayed_work(&priv->pkey_task);
mutex_unlock(&pkey_mutex);
- flush_workqueue(ipoib_workqueue);
+ if (flush)
+ flush_workqueue(ipoib_workqueue);
}
- ipoib_mcast_stop_thread(dev, 1);
+ ipoib_mcast_stop_thread(dev, flush);
ipoib_mcast_dev_flush(dev);
ipoib_flush_paths(dev);
@@ -590,7 +592,7 @@ void ipoib_ib_dev_flush(void *_dev)
ipoib_dbg(priv, "flushing\n");
- ipoib_ib_dev_down(dev);
+ ipoib_ib_dev_down(dev, 0);
/*
* The device could have been brought down between the start and when
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index c3b5f79d116..0ebacd558ff 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -133,7 +133,13 @@ static int ipoib_stop(struct net_device *dev)
netif_stop_queue(dev);
- ipoib_ib_dev_down(dev);
+ /*
+ * Now flush workqueue to make sure a scheduled task doesn't
+ * bring our internal state back up.
+ */
+ flush_workqueue(ipoib_workqueue);
+
+ ipoib_ib_dev_down(dev, 1);
ipoib_ib_dev_stop(dev);
if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) {
@@ -513,12 +519,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
be32_to_cpup((__be32 *) skb->dst->neighbour->ha));
} else {
neigh->ah = NULL;
- if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
- __skb_queue_tail(&neigh->queue, skb);
- } else {
- ++priv->stats.tx_dropped;
- dev_kfree_skb_any(skb);
- }
+ __skb_queue_tail(&neigh->queue, skb);
if (!path->query && path_rec_start(dev, path))
goto err;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index a2408d7ec59..93c462eaf4f 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -115,7 +115,6 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast)
if (neigh->ah)
ipoib_put_ah(neigh->ah);
*to_ipoib_neigh(neigh->neighbour) = NULL;
- neigh->neighbour->ops->destructor = NULL;
kfree(neigh);
}
@@ -213,6 +212,7 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
{
struct net_device *dev = mcast->dev;
struct ipoib_dev_priv *priv = netdev_priv(dev);
+ struct ipoib_ah *ah;
int ret;
mcast->mcmember = *mcmember;
@@ -269,8 +269,8 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
av.static_rate, priv->local_rate,
ib_sa_rate_enum_to_int(mcast->mcmember.rate));
- mcast->ah = ipoib_create_ah(dev, priv->pd, &av);
- if (!mcast->ah) {
+ ah = ipoib_create_ah(dev, priv->pd, &av);
+ if (!ah) {
ipoib_warn(priv, "ib_address_create failed\n");
} else {
ipoib_dbg_mcast(priv, "MGID " IPOIB_GID_FMT
@@ -280,6 +280,10 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
be16_to_cpu(mcast->mcmember.mlid),
mcast->mcmember.sl);
}
+
+ spin_lock_irq(&priv->lock);
+ mcast->ah = ah;
+ spin_unlock_irq(&priv->lock);
}
/* actually send any queued packets */
@@ -432,9 +436,11 @@ static void ipoib_mcast_join_complete(int status,
if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS)
mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS;
+ mutex_lock(&mcast_mutex);
+
+ spin_lock_irq(&priv->lock);
mcast->query = NULL;
- mutex_lock(&mcast_mutex);
if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) {
if (status == -ETIMEDOUT)
queue_work(ipoib_workqueue, &priv->mcast_task);
@@ -443,6 +449,7 @@ static void ipoib_mcast_join_complete(int status,
mcast->backoff * HZ);
} else
complete(&mcast->done);
+ spin_unlock_irq(&priv->lock);
mutex_unlock(&mcast_mutex);
return;
@@ -630,21 +637,27 @@ int ipoib_mcast_stop_thread(struct net_device *dev, int flush)
if (flush)
flush_workqueue(ipoib_workqueue);
+ spin_lock_irq(&priv->lock);
if (priv->broadcast && priv->broadcast->query) {
ib_sa_cancel_query(priv->broadcast->query_id, priv->broadcast->query);
priv->broadcast->query = NULL;
+ spin_unlock_irq(&priv->lock);
ipoib_dbg_mcast(priv, "waiting for bcast\n");
wait_for_completion(&priv->broadcast->done);
- }
+ } else
+ spin_unlock_irq(&priv->lock);
list_for_each_entry(mcast, &priv->multicast_list, list) {
+ spin_lock_irq(&priv->lock);
if (mcast->query) {
ib_sa_cancel_query(mcast->query_id, mcast->query);
mcast->query = NULL;
+ spin_unlock_irq(&priv->lock);
ipoib_dbg_mcast(priv, "waiting for MGID " IPOIB_GID_FMT "\n",
IPOIB_GID_ARG(mcast->mcmember.mgid));
wait_for_completion(&mcast->done);
- }
+ } else
+ spin_unlock_irq(&priv->lock);
}
return 0;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
index faaf10e5fc7..18d2f53ec34 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
@@ -255,6 +255,6 @@ void ipoib_event(struct ib_event_handler *handler,
record->event == IB_EVENT_LID_CHANGE ||
record->event == IB_EVENT_SM_CHANGE) {
ipoib_dbg(priv, "Port active event\n");
- schedule_work(&priv->flush_task);
+ queue_work(ipoib_workqueue, &priv->flush_task);
}
}
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 960dae5c87d..a13dcdf90a4 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -1237,6 +1237,87 @@ static int srp_reset_host(struct scsi_cmnd *scmnd)
return ret;
}
+static ssize_t show_id_ext(struct class_device *cdev, char *buf)
+{
+ struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+ if (target->state == SRP_TARGET_DEAD ||
+ target->state == SRP_TARGET_REMOVED)
+ return -ENODEV;
+
+ return sprintf(buf, "0x%016llx\n",
+ (unsigned long long) be64_to_cpu(target->id_ext));
+}
+
+static ssize_t show_ioc_guid(struct class_device *cdev, char *buf)
+{
+ struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+ if (target->state == SRP_TARGET_DEAD ||
+ target->state == SRP_TARGET_REMOVED)
+ return -ENODEV;
+
+ return sprintf(buf, "0x%016llx\n",
+ (unsigned long long) be64_to_cpu(target->ioc_guid));
+}
+
+static ssize_t show_service_id(struct class_device *cdev, char *buf)
+{
+ struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+ if (target->state == SRP_TARGET_DEAD ||
+ target->state == SRP_TARGET_REMOVED)
+ return -ENODEV;
+
+ return sprintf(buf, "0x%016llx\n",
+ (unsigned long long) be64_to_cpu(target->service_id));
+}
+
+static ssize_t show_pkey(struct class_device *cdev, char *buf)
+{
+ struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+ if (target->state == SRP_TARGET_DEAD ||
+ target->state == SRP_TARGET_REMOVED)
+ return -ENODEV;
+
+ return sprintf(buf, "0x%04x\n", be16_to_cpu(target->path.pkey));
+}
+
+static ssize_t show_dgid(struct class_device *cdev, char *buf)
+{
+ struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+ if (target->state == SRP_TARGET_DEAD ||
+ target->state == SRP_TARGET_REMOVED)
+ return -ENODEV;
+
+ return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+ be16_to_cpu(((__be16 *) target->path.dgid.raw)[0]),
+ be16_to_cpu(((__be16 *) target->path.dgid.raw)[1]),
+ be16_to_cpu(((__be16 *) target->path.dgid.raw)[2]),
+ be16_to_cpu(((__be16 *) target->path.dgid.raw)[3]),
+ be16_to_cpu(((__be16 *) target->path.dgid.raw)[4]),
+ be16_to_cpu(((__be16 *) target->path.dgid.raw)[5]),
+ be16_to_cpu(((__be16 *) target->path.dgid.raw)[6]),
+ be16_to_cpu(((__be16 *) target->path.dgid.raw)[7]));
+}
+
+static CLASS_DEVICE_ATTR(id_ext, S_IRUGO, show_id_ext, NULL);
+static CLASS_DEVICE_ATTR(ioc_guid, S_IRUGO, show_ioc_guid, NULL);
+static CLASS_DEVICE_ATTR(service_id, S_IRUGO, show_service_id, NULL);
+static CLASS_DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
+static CLASS_DEVICE_ATTR(dgid, S_IRUGO, show_dgid, NULL);
+
+static struct class_device_attribute *srp_host_attrs[] = {
+ &class_device_attr_id_ext,
+ &class_device_attr_ioc_guid,
+ &class_device_attr_service_id,
+ &class_device_attr_pkey,
+ &class_device_attr_dgid,
+ NULL
+};
+
static struct scsi_host_template srp_template = {
.module = THIS_MODULE,
.name = DRV_NAME,
@@ -1249,7 +1330,8 @@ static struct scsi_host_template srp_template = {
.this_id = -1,
.sg_tablesize = SRP_MAX_INDIRECT,
.cmd_per_lun = SRP_SQ_SIZE,
- .use_clustering = ENABLE_CLUSTERING
+ .use_clustering = ENABLE_CLUSTERING,
+ .shost_attrs = srp_host_attrs
};
static int srp_add_target(struct srp_host *host, struct srp_target_port *target)
@@ -1366,6 +1448,7 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
strlcpy(dgid, p + i * 2, 3);
target->path.dgid.raw[i] = simple_strtoul(dgid, NULL, 16);
}
+ kfree(p);
break;
case SRP_OPT_PKEY:
diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile
index bd458cb9b4e..61b89617a96 100644
--- a/drivers/media/common/Makefile
+++ b/drivers/media/common/Makefile
@@ -1,5 +1,6 @@
saa7146-objs := saa7146_i2c.o saa7146_core.o
saa7146_vv-objs := saa7146_vv_ksyms.o saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
+ir-common-objs := ir-functions.o ir-keymaps.o
obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o
obj-$(CONFIG_VIDEO_SAA7146_VV) += saa7146_vv.o
diff --git a/drivers/media/common/ir-common.c b/drivers/media/common/ir-common.c
deleted file mode 100644
index 97fa3fc571c..00000000000
--- a/drivers/media/common/ir-common.c
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- *
- * some common structs and functions to handle infrared remotes via
- * input layer ...
- *
- * (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/string.h>
-#include <media/ir-common.h>
-
-/* -------------------------------------------------------------------------- */
-
-MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
-MODULE_LICENSE("GPL");
-
-static int repeat = 1;
-module_param(repeat, int, 0444);
-MODULE_PARM_DESC(repeat,"auto-repeat for IR keys (default: on)");
-
-static int debug = 0; /* debug level (0,1,2) */
-module_param(debug, int, 0644);
-
-#define dprintk(level, fmt, arg...) if (debug >= level) \
- printk(KERN_DEBUG fmt , ## arg)
-
-/* -------------------------------------------------------------------------- */
-
-/* generic RC5 keytable */
-/* see http://users.pandora.be/nenya/electronics/rc5/codes00.htm */
-/* used by old (black) Hauppauge remotes */
-IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE] = {
- /* Keys 0 to 9 */
- [ 0x00 ] = KEY_KP0,
- [ 0x01 ] = KEY_KP1,
- [ 0x02 ] = KEY_KP2,
- [ 0x03 ] = KEY_KP3,
- [ 0x04 ] = KEY_KP4,
- [ 0x05 ] = KEY_KP5,
- [ 0x06 ] = KEY_KP6,
- [ 0x07 ] = KEY_KP7,
- [ 0x08 ] = KEY_KP8,
- [ 0x09 ] = KEY_KP9,
-
- [ 0x0b ] = KEY_CHANNEL, /* channel / program (japan: 11) */
- [ 0x0c ] = KEY_POWER, /* standby */
- [ 0x0d ] = KEY_MUTE, /* mute / demute */
- [ 0x0f ] = KEY_TV, /* display */
- [ 0x10 ] = KEY_VOLUMEUP,
- [ 0x11 ] = KEY_VOLUMEDOWN,
- [ 0x12 ] = KEY_BRIGHTNESSUP,
- [ 0x13 ] = KEY_BRIGHTNESSDOWN,
- [ 0x1e ] = KEY_SEARCH, /* search + */
- [ 0x20 ] = KEY_CHANNELUP, /* channel / program + */
- [ 0x21 ] = KEY_CHANNELDOWN, /* channel / program - */
- [ 0x22 ] = KEY_CHANNEL, /* alt / channel */
- [ 0x23 ] = KEY_LANGUAGE, /* 1st / 2nd language */
- [ 0x26 ] = KEY_SLEEP, /* sleeptimer */
- [ 0x2e ] = KEY_MENU, /* 2nd controls (USA: menu) */
- [ 0x30 ] = KEY_PAUSE,
- [ 0x32 ] = KEY_REWIND,
- [ 0x33 ] = KEY_GOTO,
- [ 0x35 ] = KEY_PLAY,
- [ 0x36 ] = KEY_STOP,
- [ 0x37 ] = KEY_RECORD, /* recording */
- [ 0x3c ] = KEY_TEXT, /* teletext submode (Japan: 12) */
- [ 0x3d ] = KEY_SUSPEND, /* system standby */
-
-};
-EXPORT_SYMBOL_GPL(ir_codes_rc5_tv);
-
-/* Table for Leadtek Winfast Remote Controls - used by both bttv and cx88 */
-IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
- /* Keys 0 to 9 */
- [ 18 ] = KEY_KP0,
- [ 5 ] = KEY_KP1,
- [ 6 ] = KEY_KP2,
- [ 7 ] = KEY_KP3,
- [ 9 ] = KEY_KP4,
- [ 10 ] = KEY_KP5,
- [ 11 ] = KEY_KP6,
- [ 13 ] = KEY_KP7,
- [ 14 ] = KEY_KP8,
- [ 15 ] = KEY_KP9,
-
- [ 0 ] = KEY_POWER,
- [ 2 ] = KEY_TUNER, /* TV/FM */
- [ 30 ] = KEY_VIDEO,
- [ 4 ] = KEY_VOLUMEUP,
- [ 8 ] = KEY_VOLUMEDOWN,
- [ 12 ] = KEY_CHANNELUP,
- [ 16 ] = KEY_CHANNELDOWN,
- [ 3 ] = KEY_ZOOM, /* fullscreen */
- [ 31 ] = KEY_SUBTITLE, /* closed caption/teletext */
- [ 32 ] = KEY_SLEEP,
- [ 20 ] = KEY_MUTE,
- [ 43 ] = KEY_RED,
- [ 44 ] = KEY_GREEN,
- [ 45 ] = KEY_YELLOW,
- [ 46 ] = KEY_BLUE,
- [ 24 ] = KEY_KPPLUS, /* fine tune + */
- [ 25 ] = KEY_KPMINUS, /* fine tune - */
- [ 33 ] = KEY_KPDOT,
- [ 19 ] = KEY_KPENTER,
- [ 34 ] = KEY_BACK,
- [ 35 ] = KEY_PLAYPAUSE,
- [ 36 ] = KEY_NEXT,
- [ 38 ] = KEY_STOP,
- [ 39 ] = KEY_RECORD
-};
-EXPORT_SYMBOL_GPL(ir_codes_winfast);
-
-IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
- [ 0x59 ] = KEY_MUTE,
- [ 0x4a ] = KEY_POWER,
-
- [ 0x18 ] = KEY_TEXT,
- [ 0x26 ] = KEY_TV,
- [ 0x3d ] = KEY_PRINT,
-
- [ 0x48 ] = KEY_RED,
- [ 0x04 ] = KEY_GREEN,
- [ 0x11 ] = KEY_YELLOW,
- [ 0x00 ] = KEY_BLUE,
-
- [ 0x2d ] = KEY_VOLUMEUP,
- [ 0x1e ] = KEY_VOLUMEDOWN,
-
- [ 0x49 ] = KEY_MENU,
-
- [ 0x16 ] = KEY_CHANNELUP,
- [ 0x17 ] = KEY_CHANNELDOWN,
-
- [ 0x20 ] = KEY_UP,
- [ 0x21 ] = KEY_DOWN,
- [ 0x22 ] = KEY_LEFT,
- [ 0x23 ] = KEY_RIGHT,
- [ 0x0d ] = KEY_SELECT,
-
-
-
- [ 0x08 ] = KEY_BACK,
- [ 0x07 ] = KEY_REFRESH,
-
- [ 0x2f ] = KEY_ZOOM,
- [ 0x29 ] = KEY_RECORD,
-
- [ 0x4b ] = KEY_PAUSE,
- [ 0x4d ] = KEY_REWIND,
- [ 0x2e ] = KEY_PLAY,
- [ 0x4e ] = KEY_FORWARD,
- [ 0x53 ] = KEY_PREVIOUS,
- [ 0x4c ] = KEY_STOP,
- [ 0x54 ] = KEY_NEXT,
-
- [ 0x69 ] = KEY_KP0,
- [ 0x6a ] = KEY_KP1,
- [ 0x6b ] = KEY_KP2,
- [ 0x6c ] = KEY_KP3,
- [ 0x6d ] = KEY_KP4,
- [ 0x6e ] = KEY_KP5,
- [ 0x6f ] = KEY_KP6,
- [ 0x70 ] = KEY_KP7,
- [ 0x71 ] = KEY_KP8,
- [ 0x72 ] = KEY_KP9,
-
- [ 0x74 ] = KEY_CHANNEL,
- [ 0x0a ] = KEY_BACKSPACE,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_pinnacle);
-
-/* empty keytable, can be used as placeholder for not-yet created keytables */
-IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE] = {
- [ 42 ] = KEY_COFFEE,
-};
-EXPORT_SYMBOL_GPL(ir_codes_empty);
-
-/* Hauppauge: the newer, gray remotes (seems there are multiple
- * slightly different versions), shipped with cx88+ivtv cards.
- * almost rc5 coding, but some non-standard keys */
-IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE] = {
- /* Keys 0 to 9 */
- [ 0x00 ] = KEY_KP0,
- [ 0x01 ] = KEY_KP1,
- [ 0x02 ] = KEY_KP2,
- [ 0x03 ] = KEY_KP3,
- [ 0x04 ] = KEY_KP4,
- [ 0x05 ] = KEY_KP5,
- [ 0x06 ] = KEY_KP6,
- [ 0x07 ] = KEY_KP7,
- [ 0x08 ] = KEY_KP8,
- [ 0x09 ] = KEY_KP9,
-
- [ 0x0a ] = KEY_TEXT, /* keypad asterisk as well */
- [ 0x0b ] = KEY_RED, /* red button */
- [ 0x0c ] = KEY_RADIO,
- [ 0x0d ] = KEY_MENU,
- [ 0x0e ] = KEY_SUBTITLE, /* also the # key */
- [ 0x0f ] = KEY_MUTE,
- [ 0x10 ] = KEY_VOLUMEUP,
- [ 0x11 ] = KEY_VOLUMEDOWN,
- [ 0x12 ] = KEY_PREVIOUS, /* previous channel */
- [ 0x14 ] = KEY_UP,
- [ 0x15 ] = KEY_DOWN,
- [ 0x16 ] = KEY_LEFT,
- [ 0x17 ] = KEY_RIGHT,
- [ 0x18 ] = KEY_VIDEO, /* Videos */
- [ 0x19 ] = KEY_AUDIO, /* Music */
- /* 0x1a: Pictures - presume this means
- "Multimedia Home Platform" -
- no "PICTURES" key in input.h
- */
- [ 0x1a ] = KEY_MHP,
-
- [ 0x1b ] = KEY_EPG, /* Guide */
- [ 0x1c ] = KEY_TV,
- [ 0x1e ] = KEY_NEXTSONG, /* skip >| */
- [ 0x1f ] = KEY_EXIT, /* back/exit */
- [ 0x20 ] = KEY_CHANNELUP, /* channel / program + */
- [ 0x21 ] = KEY_CHANNELDOWN, /* channel / program - */
- [ 0x22 ] = KEY_CHANNEL, /* source (old black remote) */
- [ 0x24 ] = KEY_PREVIOUSSONG, /* replay |< */
- [ 0x25 ] = KEY_ENTER, /* OK */
- [ 0x26 ] = KEY_SLEEP, /* minimize (old black remote) */
- [ 0x29 ] = KEY_BLUE, /* blue key */
- [ 0x2e ] = KEY_GREEN, /* green button */
- [ 0x30 ] = KEY_PAUSE, /* pause */
- [ 0x32 ] = KEY_REWIND, /* backward << */
- [ 0x34 ] = KEY_FASTFORWARD, /* forward >> */
- [ 0x35 ] = KEY_PLAY,
- [ 0x36 ] = KEY_STOP,
- [ 0x37 ] = KEY_RECORD, /* recording */
- [ 0x38 ] = KEY_YELLOW, /* yellow key */
- [ 0x3b ] = KEY_SELECT, /* top right button */
- [ 0x3c ] = KEY_ZOOM, /* full */
- [ 0x3d ] = KEY_POWER, /* system power (green button) */
-};
-EXPORT_SYMBOL(ir_codes_hauppauge_new);
-
-IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE] = {
- [ 2 ] = KEY_KP0,
- [ 1 ] = KEY_KP1,
- [ 11 ] = KEY_KP2,
- [ 27 ] = KEY_KP3,
- [ 5 ] = KEY_KP4,
- [ 9 ] = KEY_KP5,
- [ 21 ] = KEY_KP6,
- [ 6 ] = KEY_KP7,
- [ 10 ] = KEY_KP8,
- [ 18 ] = KEY_KP9,
-
- [ 3 ] = KEY_TUNER, /* TV/FM */
- [ 7 ] = KEY_SEARCH, /* scan */
- [ 28 ] = KEY_ZOOM, /* full screen */
- [ 30 ] = KEY_POWER,
- [ 23 ] = KEY_VOLUMEDOWN,
- [ 31 ] = KEY_VOLUMEUP,
- [ 20 ] = KEY_CHANNELDOWN,
- [ 22 ] = KEY_CHANNELUP,
- [ 24 ] = KEY_MUTE,
-
- [ 0 ] = KEY_LIST, /* source */
- [ 19 ] = KEY_INFO, /* loop */
- [ 16 ] = KEY_LAST, /* +100 */
- [ 13 ] = KEY_CLEAR, /* reset */
- [ 12 ] = BTN_RIGHT, /* fun++ */
- [ 4 ] = BTN_LEFT, /* fun-- */
- [ 14 ] = KEY_GOTO, /* function */
- [ 15 ] = KEY_STOP, /* freeze */
-};
-EXPORT_SYMBOL(ir_codes_pixelview);
-
-/* -------------------------------------------------------------------------- */
-
-static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir)
-{
- if (KEY_RESERVED == ir->keycode) {
- printk(KERN_INFO "%s: unknown key: key=0x%02x raw=0x%02x down=%d\n",
- dev->name,ir->ir_key,ir->ir_raw,ir->keypressed);
- return;
- }
- dprintk(1,"%s: key event code=%d down=%d\n",
- dev->name,ir->keycode,ir->keypressed);
- input_report_key(dev,ir->keycode,ir->keypressed);
- input_sync(dev);
-}
-
-/* -------------------------------------------------------------------------- */
-
-void ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
- int ir_type, IR_KEYTAB_TYPE *ir_codes)
-{
- int i;
-
- ir->ir_type = ir_type;
- if (ir_codes)
- memcpy(ir->ir_codes, ir_codes, sizeof(ir->ir_codes));
-
-
- dev->keycode = ir->ir_codes;
- dev->keycodesize = sizeof(IR_KEYTAB_TYPE);
- dev->keycodemax = IR_KEYTAB_SIZE;
- for (i = 0; i < IR_KEYTAB_SIZE; i++)
- set_bit(ir->ir_codes[i], dev->keybit);
- clear_bit(0, dev->keybit);
-
- set_bit(EV_KEY, dev->evbit);
- if (repeat)
- set_bit(EV_REP, dev->evbit);
-}
-
-void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir)
-{
- if (ir->keypressed) {
- ir->keypressed = 0;
- ir_input_key_event(dev,ir);
- }
-}
-
-void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
- u32 ir_key, u32 ir_raw)
-{
- u32 keycode = IR_KEYCODE(ir->ir_codes, ir_key);
-
- if (ir->keypressed && ir->keycode != keycode) {
- ir->keypressed = 0;
- ir_input_key_event(dev,ir);
- }
- if (!ir->keypressed) {
- ir->ir_key = ir_key;
- ir->ir_raw = ir_raw;
- ir->keycode = keycode;
- ir->keypressed = 1;
- ir_input_key_event(dev,ir);
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-u32 ir_extract_bits(u32 data, u32 mask)
-{
- int mbit, vbit;
- u32 value;
-
- value = 0;
- vbit = 0;
- for (mbit = 0; mbit < 32; mbit++) {
- if (!(mask & ((u32)1 << mbit)))
- continue;
- if (data & ((u32)1 << mbit))
- value |= (1 << vbit);
- vbit++;
- }
- return value;
-}
-
-static int inline getbit(u32 *samples, int bit)
-{
- return (samples[bit/32] & (1 << (31-(bit%32)))) ? 1 : 0;
-}
-
-/* sump raw samples for visual debugging ;) */
-int ir_dump_samples(u32 *samples, int count)
-{
- int i, bit, start;
-
- printk(KERN_DEBUG "ir samples: ");
- start = 0;
- for (i = 0; i < count * 32; i++) {
- bit = getbit(samples,i);
- if (bit)
- start = 1;
- if (0 == start)
- continue;
- printk("%s", bit ? "#" : "_");
- }
- printk("\n");
- return 0;
-}
-
-/* decode raw samples, pulse distance coding used by NEC remotes */
-int ir_decode_pulsedistance(u32 *samples, int count, int low, int high)
-{
- int i,last,bit,len;
- u32 curBit;
- u32 value;
-
- /* find start burst */
- for (i = len = 0; i < count * 32; i++) {
- bit = getbit(samples,i);
- if (bit) {
- len++;
- } else {
- if (len >= 29)
- break;
- len = 0;
- }
- }
-
- /* start burst to short */
- if (len < 29)
- return 0xffffffff;
-
- /* find start silence */
- for (len = 0; i < count * 32; i++) {
- bit = getbit(samples,i);
- if (bit) {
- break;
- } else {
- len++;
- }
- }
-
- /* silence to short */
- if (len < 7)
- return 0xffffffff;
-
- /* go decoding */
- len = 0;
- last = 1;
- value = 0; curBit = 1;
- for (; i < count * 32; i++) {
- bit = getbit(samples,i);
- if (last) {
- if(bit) {
- continue;
- } else {
- len = 1;
- }
- } else {
- if (bit) {
- if (len > (low + high) /2)
- value |= curBit;
- curBit <<= 1;
- if (curBit == 1)
- break;
- } else {
- len++;
- }
- }
- last = bit;
- }
-
- return value;
-}
-
-/* decode raw samples, biphase coding, used by rc5 for example */
-int ir_decode_biphase(u32 *samples, int count, int low, int high)
-{
- int i,last,bit,len,flips;
- u32 value;
-
- /* find start bit (1) */
- for (i = 0; i < 32; i++) {
- bit = getbit(samples,i);
- if (bit)
- break;
- }
-
- /* go decoding */
- len = 0;
- flips = 0;
- value = 1;
- for (; i < count * 32; i++) {
- if (len > high)
- break;
- if (flips > 1)
- break;
- last = bit;
- bit = getbit(samples,i);
- if (last == bit) {
- len++;
- continue;
- }
- if (len < low) {
- len++;
- flips++;
- continue;
- }
- value <<= 1;
- value |= bit;
- flips = 0;
- len = 1;
- }
- return value;
-}
-
-EXPORT_SYMBOL_GPL(ir_input_init);
-EXPORT_SYMBOL_GPL(ir_input_nokey);
-EXPORT_SYMBOL_GPL(ir_input_keydown);
-
-EXPORT_SYMBOL_GPL(ir_extract_bits);
-EXPORT_SYMBOL_GPL(ir_dump_samples);
-EXPORT_SYMBOL_GPL(ir_decode_biphase);
-EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
-
diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c
new file mode 100644
index 00000000000..397cff8b345
--- /dev/null
+++ b/drivers/media/common/ir-functions.c
@@ -0,0 +1,272 @@
+/*
+ *
+ * some common structs and functions to handle infrared remotes via
+ * input layer ...
+ *
+ * (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <media/ir-common.h>
+
+/* -------------------------------------------------------------------------- */
+
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+
+static int repeat = 1;
+module_param(repeat, int, 0444);
+MODULE_PARM_DESC(repeat,"auto-repeat for IR keys (default: on)");
+
+static int debug = 0; /* debug level (0,1,2) */
+module_param(debug, int, 0644);
+
+#define dprintk(level, fmt, arg...) if (debug >= level) \
+ printk(KERN_DEBUG fmt , ## arg)
+
+/* -------------------------------------------------------------------------- */
+
+static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir)
+{
+ if (KEY_RESERVED == ir->keycode) {
+ printk(KERN_INFO "%s: unknown key: key=0x%02x raw=0x%02x down=%d\n",
+ dev->name,ir->ir_key,ir->ir_raw,ir->keypressed);
+ return;
+ }
+ dprintk(1,"%s: key event code=%d down=%d\n",
+ dev->name,ir->keycode,ir->keypressed);
+ input_report_key(dev,ir->keycode,ir->keypressed);
+ input_sync(dev);
+}
+
+/* -------------------------------------------------------------------------- */
+
+void ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
+ int ir_type, IR_KEYTAB_TYPE *ir_codes)
+{
+ int i;
+
+ ir->ir_type = ir_type;
+ if (ir_codes)
+ memcpy(ir->ir_codes, ir_codes, sizeof(ir->ir_codes));
+
+
+ dev->keycode = ir->ir_codes;
+ dev->keycodesize = sizeof(IR_KEYTAB_TYPE);
+ dev->keycodemax = IR_KEYTAB_SIZE;
+ for (i = 0; i < IR_KEYTAB_SIZE; i++)
+ set_bit(ir->ir_codes[i], dev->keybit);
+ clear_bit(0, dev->keybit);
+
+ set_bit(EV_KEY, dev->evbit);
+ if (repeat)
+ set_bit(EV_REP, dev->evbit);
+}
+
+void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir)
+{
+ if (ir->keypressed) {
+ ir->keypressed = 0;
+ ir_input_key_event(dev,ir);
+ }
+}
+
+void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
+ u32 ir_key, u32 ir_raw)
+{
+ u32 keycode = IR_KEYCODE(ir->ir_codes, ir_key);
+
+ if (ir->keypressed && ir->keycode != keycode) {
+ ir->keypressed = 0;
+ ir_input_key_event(dev,ir);
+ }
+ if (!ir->keypressed) {
+ ir->ir_key = ir_key;
+ ir->ir_raw = ir_raw;
+ ir->keycode = keycode;
+ ir->keypressed = 1;
+ ir_input_key_event(dev,ir);
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+u32 ir_extract_bits(u32 data, u32 mask)
+{
+ int mbit, vbit;
+ u32 value;
+
+ value = 0;
+ vbit = 0;
+ for (mbit = 0; mbit < 32; mbit++) {
+ if (!(mask & ((u32)1 << mbit)))
+ continue;
+ if (data & ((u32)1 << mbit))
+ value |= (1 << vbit);
+ vbit++;
+ }
+ return value;
+}
+
+static int inline getbit(u32 *samples, int bit)
+{
+ return (samples[bit/32] & (1 << (31-(bit%32)))) ? 1 : 0;
+}
+
+/* sump raw samples for visual debugging ;) */
+int ir_dump_samples(u32 *samples, int count)
+{
+ int i, bit, start;
+
+ printk(KERN_DEBUG "ir samples: ");
+ start = 0;
+ for (i = 0; i < count * 32; i++) {
+ bit = getbit(samples,i);
+ if (bit)
+ start = 1;
+ if (0 == start)
+ continue;
+ printk("%s", bit ? "#" : "_");
+ }
+ printk("\n");
+ return 0;
+}
+
+/* decode raw samples, pulse distance coding used by NEC remotes */
+int ir_decode_pulsedistance(u32 *samples, int count, int low, int high)
+{
+ int i,last,bit,len;
+ u32 curBit;
+ u32 value;
+
+ /* find start burst */
+ for (i = len = 0; i < count * 32; i++) {
+ bit = getbit(samples,i);
+ if (bit) {
+ len++;
+ } else {
+ if (len >= 29)
+ break;
+ len = 0;
+ }
+ }
+
+ /* start burst to short */
+ if (len < 29)
+ return 0xffffffff;
+
+ /* find start silence */
+ for (len = 0; i < count * 32; i++) {
+ bit = getbit(samples,i);
+ if (bit) {
+ break;
+ } else {
+ len++;
+ }
+ }
+
+ /* silence to short */
+ if (len < 7)
+ return 0xffffffff;
+
+ /* go decoding */
+ len = 0;
+ last = 1;
+ value = 0; curBit = 1;
+ for (; i < count * 32; i++) {
+ bit = getbit(samples,i);
+ if (last) {
+ if(bit) {
+ continue;
+ } else {
+ len = 1;
+ }
+ } else {
+ if (bit) {
+ if (len > (low + high) /2)
+ value |= curBit;
+ curBit <<= 1;
+ if (curBit == 1)
+ break;
+ } else {
+ len++;
+ }
+ }
+ last = bit;
+ }
+
+ return value;
+}
+
+/* decode raw samples, biphase coding, used by rc5 for example */
+int ir_decode_biphase(u32 *samples, int count, int low, int high)
+{
+ int i,last,bit,len,flips;
+ u32 value;
+
+ /* find start bit (1) */
+ for (i = 0; i < 32; i++) {
+ bit = getbit(samples,i);
+ if (bit)
+ break;
+ }
+
+ /* go decoding */
+ len = 0;
+ flips = 0;
+ value = 1;
+ for (; i < count * 32; i++) {
+ if (len > high)
+ break;
+ if (flips > 1)
+ break;
+ last = bit;
+ bit = getbit(samples,i);
+ if (last == bit) {
+ len++;
+ continue;
+ }
+ if (len < low) {
+ len++;
+ flips++;
+ continue;
+ }
+ value <<= 1;
+ value |= bit;
+ flips = 0;
+ len = 1;
+ }
+ return value;
+}
+
+EXPORT_SYMBOL_GPL(ir_input_init);
+EXPORT_SYMBOL_GPL(ir_input_nokey);
+EXPORT_SYMBOL_GPL(ir_input_keydown);
+
+EXPORT_SYMBOL_GPL(ir_extract_bits);
+EXPORT_SYMBOL_GPL(ir_dump_samples);
+EXPORT_SYMBOL_GPL(ir_decode_biphase);
+EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
new file mode 100644
index 00000000000..a294d5c2c73
--- /dev/null
+++ b/drivers/media/common/ir-keymaps.c
@@ -0,0 +1,1415 @@
+/*
+
+
+ Keytables for supported remote controls. This file is part of
+ video4linux.
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <linux/input.h>
+#include <media/ir-common.h>
+
+/* empty keytable, can be used as placeholder for not-yet created keytables */
+IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE] = {
+ [ 0x2a ] = KEY_COFFEE,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_empty);
+
+/* Matt Jesson <dvb@jesson.eclipse.co.uk */
+IR_KEYTAB_TYPE ir_codes_avermedia_dvbt[IR_KEYTAB_SIZE] = {
+ [ 0x28 ] = KEY_0, //'0' / 'enter'
+ [ 0x22 ] = KEY_1, //'1'
+ [ 0x12 ] = KEY_2, //'2' / 'up arrow'
+ [ 0x32 ] = KEY_3, //'3'
+ [ 0x24 ] = KEY_4, //'4' / 'left arrow'
+ [ 0x14 ] = KEY_5, //'5'
+ [ 0x34 ] = KEY_6, //'6' / 'right arrow'
+ [ 0x26 ] = KEY_7, //'7'
+ [ 0x16 ] = KEY_8, //'8' / 'down arrow'
+ [ 0x36 ] = KEY_9, //'9'
+
+ [ 0x20 ] = KEY_LIST, // 'source'
+ [ 0x10 ] = KEY_TEXT, // 'teletext'
+ [ 0x00 ] = KEY_POWER, // 'power'
+ [ 0x04 ] = KEY_AUDIO, // 'audio'
+ [ 0x06 ] = KEY_ZOOM, // 'full screen'
+ [ 0x18 ] = KEY_VIDEO, // 'display'
+ [ 0x38 ] = KEY_SEARCH, // 'loop'
+ [ 0x08 ] = KEY_INFO, // 'preview'
+ [ 0x2a ] = KEY_REWIND, // 'backward <<'
+ [ 0x1a ] = KEY_FASTFORWARD, // 'forward >>'
+ [ 0x3a ] = KEY_RECORD, // 'capture'
+ [ 0x0a ] = KEY_MUTE, // 'mute'
+ [ 0x2c ] = KEY_RECORD, // 'record'
+ [ 0x1c ] = KEY_PAUSE, // 'pause'
+ [ 0x3c ] = KEY_STOP, // 'stop'
+ [ 0x0c ] = KEY_PLAY, // 'play'
+ [ 0x2e ] = KEY_RED, // 'red'
+ [ 0x01 ] = KEY_BLUE, // 'blue' / 'cancel'
+ [ 0x0e ] = KEY_YELLOW, // 'yellow' / 'ok'
+ [ 0x21 ] = KEY_GREEN, // 'green'
+ [ 0x11 ] = KEY_CHANNELDOWN, // 'channel -'
+ [ 0x31 ] = KEY_CHANNELUP, // 'channel +'
+ [ 0x1e ] = KEY_VOLUMEDOWN, // 'volume -'
+ [ 0x3e ] = KEY_VOLUMEUP, // 'volume +'
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_avermedia_dvbt);
+
+/* Attila Kondoros <attila.kondoros@chello.hu> */
+IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = {
+
+ [ 0x01 ] = KEY_1,
+ [ 0x02 ] = KEY_2,
+ [ 0x03 ] = KEY_3,
+ [ 0x04 ] = KEY_4,
+ [ 0x05 ] = KEY_5,
+ [ 0x06 ] = KEY_6,
+ [ 0x07 ] = KEY_7,
+ [ 0x08 ] = KEY_8,
+ [ 0x09 ] = KEY_9,
+ [ 0x00 ] = KEY_0,
+ [ 0x17 ] = KEY_LAST, // +100
+ [ 0x0a ] = KEY_LIST, // recall
+
+
+ [ 0x1c ] = KEY_TUNER, // TV/FM
+ [ 0x15 ] = KEY_SEARCH, // scan
+ [ 0x12 ] = KEY_POWER, // power
+ [ 0x1f ] = KEY_VOLUMEDOWN, // vol up
+ [ 0x1b ] = KEY_VOLUMEUP, // vol down
+ [ 0x1e ] = KEY_CHANNELDOWN, // chn up
+ [ 0x1a ] = KEY_CHANNELUP, // chn down
+
+ [ 0x11 ] = KEY_VIDEO, // video
+ [ 0x0f ] = KEY_ZOOM, // full screen
+ [ 0x13 ] = KEY_MUTE, // mute/unmute
+ [ 0x10 ] = KEY_TEXT, // min
+
+ [ 0x0d ] = KEY_STOP, // freeze
+ [ 0x0e ] = KEY_RECORD, // record
+ [ 0x1d ] = KEY_PLAYPAUSE, // stop
+ [ 0x19 ] = KEY_PLAY, // play
+
+ [ 0x16 ] = KEY_GOTO, // osd
+ [ 0x14 ] = KEY_REFRESH, // default
+ [ 0x0c ] = KEY_KPPLUS, // fine tune >>>>
+ [ 0x18 ] = KEY_KPMINUS // fine tune <<<<
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_apac_viewcomp);
+
+/* ---------------------------------------------------------------------- */
+
+IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE] = {
+
+ [ 0x1e ] = KEY_POWER, // power
+ [ 0x07 ] = KEY_MEDIA, // source
+ [ 0x1c ] = KEY_SEARCH, // scan
+
+/* FIXME: duplicate keycodes?
+ *
+ * These four keys seem to share the same GPIO as CH+, CH-, <<< and >>>
+ * The GPIO values are
+ * 6397fb for both "Scan <" and "CH -",
+ * 639ffb for "Scan >" and "CH+",
+ * 6384fb for "Tune <" and "<<<",
+ * 638cfb for "Tune >" and ">>>", regardless of the mask.
+ *
+ * [ 0x17 ] = KEY_BACK, // fm scan <<
+ * [ 0x1f ] = KEY_FORWARD, // fm scan >>
+ *
+ * [ 0x04 ] = KEY_LEFT, // fm tuning <
+ * [ 0x0c ] = KEY_RIGHT, // fm tuning >
+ *
+ * For now, these four keys are disabled. Pressing them will generate
+ * the CH+/CH-/<<</>>> events
+ */
+
+ [ 0x03 ] = KEY_TUNER, // TV/FM
+
+ [ 0x00 ] = KEY_RECORD,
+ [ 0x08 ] = KEY_STOP,
+ [ 0x11 ] = KEY_PLAY,
+
+ [ 0x1a ] = KEY_PLAYPAUSE, // freeze
+ [ 0x19 ] = KEY_ZOOM, // zoom
+ [ 0x0f ] = KEY_TEXT, // min
+
+ [ 0x01 ] = KEY_1,
+ [ 0x0b ] = KEY_2,
+ [ 0x1b ] = KEY_3,
+ [ 0x05 ] = KEY_4,
+ [ 0x09 ] = KEY_5,
+ [ 0x15 ] = KEY_6,
+ [ 0x06 ] = KEY_7,
+ [ 0x0a ] = KEY_8,
+ [ 0x12 ] = KEY_9,
+ [ 0x02 ] = KEY_0,
+ [ 0x10 ] = KEY_LAST, // +100
+ [ 0x13 ] = KEY_LIST, // recall
+
+ [ 0x1f ] = KEY_CHANNELUP, // chn down
+ [ 0x17 ] = KEY_CHANNELDOWN, // chn up
+ [ 0x16 ] = KEY_VOLUMEUP, // vol down
+ [ 0x14 ] = KEY_VOLUMEDOWN, // vol up
+
+ [ 0x04 ] = KEY_KPMINUS, // <<<
+ [ 0x0e ] = KEY_SETUP, // function
+ [ 0x0c ] = KEY_KPPLUS, // >>>
+
+ [ 0x0d ] = KEY_GOTO, // mts
+ [ 0x1d ] = KEY_REFRESH, // reset
+ [ 0x18 ] = KEY_MUTE // mute/unmute
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_pixelview);
+
+IR_KEYTAB_TYPE ir_codes_nebula[IR_KEYTAB_SIZE] = {
+ [ 0x00 ] = KEY_0,
+ [ 0x01 ] = KEY_1,
+ [ 0x02 ] = KEY_2,
+ [ 0x03 ] = KEY_3,
+ [ 0x04 ] = KEY_4,
+ [ 0x05 ] = KEY_5,
+ [ 0x06 ] = KEY_6,
+ [ 0x07 ] = KEY_7,
+ [ 0x08 ] = KEY_8,
+ [ 0x09 ] = KEY_9,
+ [ 0x0a ] = KEY_TV,
+ [ 0x0b ] = KEY_AUX,
+ [ 0x0c ] = KEY_DVD,
+ [ 0x0d ] = KEY_POWER,
+ [ 0x0e ] = KEY_MHP, /* labelled 'Picture' */
+ [ 0x0f ] = KEY_AUDIO,
+ [ 0x10 ] = KEY_INFO,
+ [ 0x11 ] = KEY_F13, /* 16:9 */
+ [ 0x12 ] = KEY_F14, /* 14:9 */
+ [ 0x13 ] = KEY_EPG,
+ [ 0x14 ] = KEY_EXIT,
+ [ 0x15 ] = KEY_MENU,
+ [ 0x16 ] = KEY_UP,
+ [ 0x17 ] = KEY_DOWN,
+ [ 0x18 ] = KEY_LEFT,
+ [ 0x19 ] = KEY_RIGHT,
+ [ 0x1a ] = KEY_ENTER,
+ [ 0x1b ] = KEY_CHANNELUP,
+ [ 0x1c ] = KEY_CHANNELDOWN,
+ [ 0x1d ] = KEY_VOLUMEUP,
+ [ 0x1e ] = KEY_VOLUMEDOWN,
+ [ 0x1f ] = KEY_RED,
+ [ 0x20 ] = KEY_GREEN,
+ [ 0x21 ] = KEY_YELLOW,
+ [ 0x22 ] = KEY_BLUE,
+ [ 0x23 ] = KEY_SUBTITLE,
+ [ 0x24 ] = KEY_F15, /* AD */
+ [ 0x25 ] = KEY_TEXT,
+ [ 0x26 ] = KEY_MUTE,
+ [ 0x27 ] = KEY_REWIND,
+ [ 0x28 ] = KEY_STOP,
+ [ 0x29 ] = KEY_PLAY,
+ [ 0x2a ] = KEY_FASTFORWARD,
+ [ 0x2b ] = KEY_F16, /* chapter */
+ [ 0x2c ] = KEY_PAUSE,
+ [ 0x2d ] = KEY_PLAY,
+ [ 0x2e ] = KEY_RECORD,
+ [ 0x2f ] = KEY_F17, /* picture in picture */
+ [ 0x30 ] = KEY_KPPLUS, /* zoom in */
+ [ 0x31 ] = KEY_KPMINUS, /* zoom out */
+ [ 0x32 ] = KEY_F18, /* capture */
+ [ 0x33 ] = KEY_F19, /* web */
+ [ 0x34 ] = KEY_EMAIL,
+ [ 0x35 ] = KEY_PHONE,
+ [ 0x36 ] = KEY_PC
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_nebula);
+
+/* DigitalNow DNTV Live DVB-T Remote */
+IR_KEYTAB_TYPE ir_codes_dntv_live_dvb_t[IR_KEYTAB_SIZE] = {
+ [ 0x00 ] = KEY_ESC, /* 'go up a level?' */
+ /* Keys 0 to 9 */
+ [ 0x0a ] = KEY_0,
+ [ 0x01 ] = KEY_1,
+ [ 0x02 ] = KEY_2,
+ [ 0x03 ] = KEY_3,
+ [ 0x04 ] = KEY_4,
+ [ 0x05 ] = KEY_5,
+ [ 0x06 ] = KEY_6,
+ [ 0x07 ] = KEY_7,
+ [ 0x08 ] = KEY_8,
+ [ 0x09 ] = KEY_9,
+
+ [ 0x0b ] = KEY_TUNER, /* tv/fm */
+ [ 0x0c ] = KEY_SEARCH, /* scan */
+ [ 0x0d ] = KEY_STOP,
+ [ 0x0e ] = KEY_PAUSE,
+ [ 0x0f ] = KEY_LIST, /* source */
+
+ [ 0x10 ] = KEY_MUTE,
+ [ 0x11 ] = KEY_REWIND, /* backward << */
+ [ 0x12 ] = KEY_POWER,
+ [ 0x13 ] = KEY_S, /* snap */
+ [ 0x14 ] = KEY_AUDIO, /* stereo */
+ [ 0x15 ] = KEY_CLEAR, /* reset */
+ [ 0x16 ] = KEY_PLAY,
+ [ 0x17 ] = KEY_ENTER,
+ [ 0x18 ] = KEY_ZOOM, /* full screen */
+ [ 0x19 ] = KEY_FASTFORWARD, /* forward >> */
+ [ 0x1a ] = KEY_CHANNELUP,
+ [ 0x1b ] = KEY_VOLUMEUP,
+ [ 0x1c ] = KEY_INFO, /* preview */
+ [ 0x1d ] = KEY_RECORD, /* record */
+ [ 0x1e ] = KEY_CHANNELDOWN,
+ [ 0x1f ] = KEY_VOLUMEDOWN,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_dntv_live_dvb_t);
+
+/* ---------------------------------------------------------------------- */
+
+/* IO-DATA BCTV7E Remote */
+IR_KEYTAB_TYPE ir_codes_iodata_bctv7e[IR_KEYTAB_SIZE] = {
+ [ 0x40 ] = KEY_TV,
+ [ 0x20 ] = KEY_RADIO, /* FM */
+ [ 0x60 ] = KEY_EPG,
+ [ 0x00 ] = KEY_POWER,
+
+ /* Keys 0 to 9 */
+ [ 0x44 ] = KEY_0, /* 10 */
+ [ 0x50 ] = KEY_1,
+ [ 0x30 ] = KEY_2,
+ [ 0x70 ] = KEY_3,
+ [ 0x48 ] = KEY_4,
+ [ 0x28 ] = KEY_5,
+ [ 0x68 ] = KEY_6,
+ [ 0x58 ] = KEY_7,
+ [ 0x38 ] = KEY_8,
+ [ 0x78 ] = KEY_9,
+
+ [ 0x10 ] = KEY_L, /* Live */
+ [ 0x08 ] = KEY_T, /* Time Shift */
+
+ [ 0x18 ] = KEY_PLAYPAUSE, /* Play */
+
+ [ 0x24 ] = KEY_ENTER, /* 11 */
+ [ 0x64 ] = KEY_ESC, /* 12 */
+ [ 0x04 ] = KEY_M, /* Multi */
+
+ [ 0x54 ] = KEY_VIDEO,
+ [ 0x34 ] = KEY_CHANNELUP,
+ [ 0x74 ] = KEY_VOLUMEUP,
+ [ 0x14 ] = KEY_MUTE,
+
+ [ 0x4c ] = KEY_S, /* SVIDEO */
+ [ 0x2c ] = KEY_CHANNELDOWN,
+ [ 0x6c ] = KEY_VOLUMEDOWN,
+ [ 0x0c ] = KEY_ZOOM,
+
+ [ 0x5c ] = KEY_PAUSE,
+ [ 0x3c ] = KEY_C, /* || (red) */
+ [ 0x7c ] = KEY_RECORD, /* recording */
+ [ 0x1c ] = KEY_STOP,
+
+ [ 0x41 ] = KEY_REWIND, /* backward << */
+ [ 0x21 ] = KEY_PLAY,
+ [ 0x61 ] = KEY_FASTFORWARD, /* forward >> */
+ [ 0x01 ] = KEY_NEXT, /* skip >| */
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_iodata_bctv7e);
+
+/* ---------------------------------------------------------------------- */
+
+/* ADS Tech Instant TV DVB-T PCI Remote */
+IR_KEYTAB_TYPE ir_codes_adstech_dvb_t_pci[IR_KEYTAB_SIZE] = {
+ /* Keys 0 to 9 */
+ [ 0x4d ] = KEY_0,
+ [ 0x57 ] = KEY_1,
+ [ 0x4f ] = KEY_2,
+ [ 0x53 ] = KEY_3,
+ [ 0x56 ] = KEY_4,
+ [ 0x4e ] = KEY_5,
+ [ 0x5e ] = KEY_6,
+ [ 0x54 ] = KEY_7,
+ [ 0x4c ] = KEY_8,
+ [ 0x5c ] = KEY_9,
+
+ [ 0x5b ] = KEY_POWER,
+ [ 0x5f ] = KEY_MUTE,
+ [ 0x55 ] = KEY_GOTO,
+ [ 0x5d ] = KEY_SEARCH,
+ [ 0x17 ] = KEY_EPG, /* Guide */
+ [ 0x1f ] = KEY_MENU,
+ [ 0x0f ] = KEY_UP,
+ [ 0x46 ] = KEY_DOWN,
+ [ 0x16 ] = KEY_LEFT,
+ [ 0x1e ] = KEY_RIGHT,
+ [ 0x0e ] = KEY_SELECT, /* Enter */
+ [ 0x5a ] = KEY_INFO,
+ [ 0x52 ] = KEY_EXIT,
+ [ 0x59 ] = KEY_PREVIOUS,
+ [ 0x51 ] = KEY_NEXT,
+ [ 0x58 ] = KEY_REWIND,
+ [ 0x50 ] = KEY_FORWARD,
+ [ 0x44 ] = KEY_PLAYPAUSE,
+ [ 0x07 ] = KEY_STOP,
+ [ 0x1b ] = KEY_RECORD,
+ [ 0x13 ] = KEY_TUNER, /* Live */
+ [ 0x0a ] = KEY_A,
+ [ 0x12 ] = KEY_B,
+ [ 0x03 ] = KEY_PROG1, /* 1 */
+ [ 0x01 ] = KEY_PROG2, /* 2 */
+ [ 0x00 ] = KEY_PROG3, /* 3 */
+ [ 0x06 ] = KEY_DVD,
+ [ 0x48 ] = KEY_AUX, /* Photo */
+ [ 0x40 ] = KEY_VIDEO,
+ [ 0x19 ] = KEY_AUDIO, /* Music */
+ [ 0x0b ] = KEY_CHANNELUP,
+ [ 0x08 ] = KEY_CHANNELDOWN,
+ [ 0x15 ] = KEY_VOLUMEUP,
+ [ 0x1c ] = KEY_VOLUMEDOWN,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_adstech_dvb_t_pci);
+
+/* ---------------------------------------------------------------------- */
+
+/* MSI TV@nywhere remote */
+IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE] = {
+ /* Keys 0 to 9 */
+ [ 0x00 ] = KEY_0,
+ [ 0x01 ] = KEY_1,
+ [ 0x02 ] = KEY_2,
+ [ 0x03 ] = KEY_3,
+ [ 0x04 ] = KEY_4,
+ [ 0x05 ] = KEY_5,
+ [ 0x06 ] = KEY_6,
+ [ 0x07 ] = KEY_7,
+ [ 0x08 ] = KEY_8,
+ [ 0x09 ] = KEY_9,
+
+ [ 0x0c ] = KEY_MUTE,
+ [ 0x0f ] = KEY_SCREEN, /* Full Screen */
+ [ 0x10 ] = KEY_F, /* Funtion */
+ [ 0x11 ] = KEY_T, /* Time shift */
+ [ 0x12 ] = KEY_POWER,
+ [ 0x13 ] = KEY_MEDIA, /* MTS */
+ [ 0x14 ] = KEY_SLOW,
+ [ 0x16 ] = KEY_REWIND, /* backward << */
+ [ 0x17 ] = KEY_ENTER, /* Return */
+ [ 0x18 ] = KEY_FASTFORWARD, /* forward >> */
+ [ 0x1a ] = KEY_CHANNELUP,
+ [ 0x1b ] = KEY_VOLUMEUP,
+ [ 0x1e ] = KEY_CHANNELDOWN,
+ [ 0x1f ] = KEY_VOLUMEDOWN,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_msi_tvanywhere);
+
+/* ---------------------------------------------------------------------- */
+
+/* Cinergy 1400 DVB-T */
+IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE] = {
+ [ 0x01 ] = KEY_POWER,
+ [ 0x02 ] = KEY_1,
+ [ 0x03 ] = KEY_2,
+ [ 0x04 ] = KEY_3,
+ [ 0x05 ] = KEY_4,
+ [ 0x06 ] = KEY_5,
+ [ 0x07 ] = KEY_6,
+ [ 0x08 ] = KEY_7,
+ [ 0x09 ] = KEY_8,
+ [ 0x0a ] = KEY_9,
+ [ 0x0c ] = KEY_0,
+
+ [ 0x0b ] = KEY_VIDEO,
+ [ 0x0d ] = KEY_REFRESH,
+ [ 0x0e ] = KEY_SELECT,
+ [ 0x0f ] = KEY_EPG,
+ [ 0x10 ] = KEY_UP,
+ [ 0x11 ] = KEY_LEFT,
+ [ 0x12 ] = KEY_OK,
+ [ 0x13 ] = KEY_RIGHT,
+ [ 0x14 ] = KEY_DOWN,
+ [ 0x15 ] = KEY_TEXT,
+ [ 0x16 ] = KEY_INFO,
+
+ [ 0x17 ] = KEY_RED,
+ [ 0x18 ] = KEY_GREEN,
+ [ 0x19 ] = KEY_YELLOW,
+ [ 0x1a ] = KEY_BLUE,
+
+ [ 0x1b ] = KEY_CHANNELUP,
+ [ 0x1c ] = KEY_VOLUMEUP,
+ [ 0x1d ] = KEY_MUTE,
+ [ 0x1e ] = KEY_VOLUMEDOWN,
+ [ 0x1f ] = KEY_CHANNELDOWN,
+
+ [ 0x40 ] = KEY_PAUSE,
+ [ 0x4c ] = KEY_PLAY,
+ [ 0x58 ] = KEY_RECORD,
+ [ 0x54 ] = KEY_PREVIOUS,
+ [ 0x48 ] = KEY_STOP,
+ [ 0x5c ] = KEY_NEXT,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_cinergy_1400);
+
+/* ---------------------------------------------------------------------- */
+
+/* AVERTV STUDIO 303 Remote */
+IR_KEYTAB_TYPE ir_codes_avertv_303[IR_KEYTAB_SIZE] = {
+ [ 0x2a ] = KEY_1,
+ [ 0x32 ] = KEY_2,
+ [ 0x3a ] = KEY_3,
+ [ 0x4a ] = KEY_4,
+ [ 0x52 ] = KEY_5,
+ [ 0x5a ] = KEY_6,
+ [ 0x6a ] = KEY_7,
+ [ 0x72 ] = KEY_8,
+ [ 0x7a ] = KEY_9,
+ [ 0x0e ] = KEY_0,
+
+ [ 0x02 ] = KEY_POWER,
+ [ 0x22 ] = KEY_VIDEO,
+ [ 0x42 ] = KEY_AUDIO,
+ [ 0x62 ] = KEY_ZOOM,
+ [ 0x0a ] = KEY_TV,
+ [ 0x12 ] = KEY_CD,
+ [ 0x1a ] = KEY_TEXT,
+
+ [ 0x16 ] = KEY_SUBTITLE,
+ [ 0x1e ] = KEY_REWIND,
+ [ 0x06 ] = KEY_PRINT,
+
+ [ 0x2e ] = KEY_SEARCH,
+ [ 0x36 ] = KEY_SLEEP,
+ [ 0x3e ] = KEY_SHUFFLE,
+ [ 0x26 ] = KEY_MUTE,
+
+ [ 0x4e ] = KEY_RECORD,
+ [ 0x56 ] = KEY_PAUSE,
+ [ 0x5e ] = KEY_STOP,
+ [ 0x46 ] = KEY_PLAY,
+
+ [ 0x6e ] = KEY_RED,
+ [ 0x0b ] = KEY_GREEN,
+ [ 0x66 ] = KEY_YELLOW,
+ [ 0x03 ] = KEY_BLUE,
+
+ [ 0x76 ] = KEY_LEFT,
+ [ 0x7e ] = KEY_RIGHT,
+ [ 0x13 ] = KEY_DOWN,
+ [ 0x1b ] = KEY_UP,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_avertv_303);
+
+/* ---------------------------------------------------------------------- */
+
+/* DigitalNow DNTV Live! DVB-T Pro Remote */
+IR_KEYTAB_TYPE ir_codes_dntv_live_dvbt_pro[IR_KEYTAB_SIZE] = {
+ [ 0x16 ] = KEY_POWER,
+ [ 0x5b ] = KEY_HOME,
+
+ [ 0x55 ] = KEY_TV, /* live tv */
+ [ 0x58 ] = KEY_TUNER, /* digital Radio */
+ [ 0x5a ] = KEY_RADIO, /* FM radio */
+ [ 0x59 ] = KEY_DVD, /* dvd menu */
+ [ 0x03 ] = KEY_1,
+ [ 0x01 ] = KEY_2,
+ [ 0x06 ] = KEY_3,
+ [ 0x09 ] = KEY_4,
+ [ 0x1d ] = KEY_5,
+ [ 0x1f ] = KEY_6,
+ [ 0x0d ] = KEY_7,
+ [ 0x19 ] = KEY_8,
+ [ 0x1b ] = KEY_9,
+ [ 0x0c ] = KEY_CANCEL,
+ [ 0x15 ] = KEY_0,
+ [ 0x4a ] = KEY_CLEAR,
+ [ 0x13 ] = KEY_BACK,
+ [ 0x00 ] = KEY_TAB,
+ [ 0x4b ] = KEY_UP,
+ [ 0x4e ] = KEY_LEFT,
+ [ 0x4f ] = KEY_OK,
+ [ 0x52 ] = KEY_RIGHT,
+ [ 0x51 ] = KEY_DOWN,
+ [ 0x1e ] = KEY_VOLUMEUP,
+ [ 0x0a ] = KEY_VOLUMEDOWN,
+ [ 0x02 ] = KEY_CHANNELDOWN,
+ [ 0x05 ] = KEY_CHANNELUP,
+ [ 0x11 ] = KEY_RECORD,
+ [ 0x14 ] = KEY_PLAY,
+ [ 0x4c ] = KEY_PAUSE,
+ [ 0x1a ] = KEY_STOP,
+ [ 0x40 ] = KEY_REWIND,
+ [ 0x12 ] = KEY_FASTFORWARD,
+ [ 0x41 ] = KEY_PREVIOUSSONG, /* replay |< */
+ [ 0x42 ] = KEY_NEXTSONG, /* skip >| */
+ [ 0x54 ] = KEY_CAMERA, /* capture */
+ [ 0x50 ] = KEY_LANGUAGE, /* sap */
+ [ 0x47 ] = KEY_TV2, /* pip */
+ [ 0x4d ] = KEY_SCREEN,
+ [ 0x43 ] = KEY_SUBTITLE,
+ [ 0x10 ] = KEY_MUTE,
+ [ 0x49 ] = KEY_AUDIO, /* l/r */
+ [ 0x07 ] = KEY_SLEEP,
+ [ 0x08 ] = KEY_VIDEO, /* a/v */
+ [ 0x0e ] = KEY_PREVIOUS, /* recall */
+ [ 0x45 ] = KEY_ZOOM, /* zoom + */
+ [ 0x46 ] = KEY_ANGLE, /* zoom - */
+ [ 0x56 ] = KEY_RED,
+ [ 0x57 ] = KEY_GREEN,
+ [ 0x5c ] = KEY_YELLOW,
+ [ 0x5d ] = KEY_BLUE,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_dntv_live_dvbt_pro);
+
+IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE] = {
+ [ 0x01 ] = KEY_CHANNEL,
+ [ 0x02 ] = KEY_SELECT,
+ [ 0x03 ] = KEY_MUTE,
+ [ 0x04 ] = KEY_POWER,
+ [ 0x05 ] = KEY_1,
+ [ 0x06 ] = KEY_2,
+ [ 0x07 ] = KEY_3,
+ [ 0x08 ] = KEY_CHANNELUP,
+ [ 0x09 ] = KEY_4,
+ [ 0x0a ] = KEY_5,
+ [ 0x0b ] = KEY_6,
+ [ 0x0c ] = KEY_CHANNELDOWN,
+ [ 0x0d ] = KEY_7,
+ [ 0x0e ] = KEY_8,
+ [ 0x0f ] = KEY_9,
+ [ 0x10 ] = KEY_VOLUMEUP,
+ [ 0x11 ] = KEY_0,
+ [ 0x12 ] = KEY_MENU,
+ [ 0x13 ] = KEY_PRINT,
+ [ 0x14 ] = KEY_VOLUMEDOWN,
+ [ 0x16 ] = KEY_PAUSE,
+ [ 0x18 ] = KEY_RECORD,
+ [ 0x19 ] = KEY_REWIND,
+ [ 0x1a ] = KEY_PLAY,
+ [ 0x1b ] = KEY_FORWARD,
+ [ 0x1c ] = KEY_BACKSPACE,
+ [ 0x1e ] = KEY_STOP,
+ [ 0x40 ] = KEY_ZOOM,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_em_terratec);
+
+IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE] = {
+ [ 0x3a ] = KEY_0,
+ [ 0x31 ] = KEY_1,
+ [ 0x32 ] = KEY_2,
+ [ 0x33 ] = KEY_3,
+ [ 0x34 ] = KEY_4,
+ [ 0x35 ] = KEY_5,
+ [ 0x36 ] = KEY_6,
+ [ 0x37 ] = KEY_7,
+ [ 0x38 ] = KEY_8,
+ [ 0x39 ] = KEY_9,
+
+ [ 0x2f ] = KEY_POWER,
+
+ [ 0x2e ] = KEY_P,
+ [ 0x1f ] = KEY_L,
+ [ 0x2b ] = KEY_I,
+
+ [ 0x2d ] = KEY_ZOOM,
+ [ 0x1e ] = KEY_ZOOM,
+ [ 0x1b ] = KEY_VOLUMEUP,
+ [ 0x0f ] = KEY_VOLUMEDOWN,
+ [ 0x17 ] = KEY_CHANNELUP,
+ [ 0x1c ] = KEY_CHANNELDOWN,
+ [ 0x25 ] = KEY_INFO,
+
+ [ 0x3c ] = KEY_MUTE,
+
+ [ 0x3d ] = KEY_LEFT,
+ [ 0x3b ] = KEY_RIGHT,
+
+ [ 0x3f ] = KEY_UP,
+ [ 0x3e ] = KEY_DOWN,
+ [ 0x1a ] = KEY_PAUSE,
+
+ [ 0x1d ] = KEY_MENU,
+ [ 0x19 ] = KEY_PLAY,
+ [ 0x16 ] = KEY_REWIND,
+ [ 0x13 ] = KEY_FORWARD,
+ [ 0x15 ] = KEY_PAUSE,
+ [ 0x0e ] = KEY_REWIND,
+ [ 0x0d ] = KEY_PLAY,
+ [ 0x0b ] = KEY_STOP,
+ [ 0x07 ] = KEY_FORWARD,
+ [ 0x27 ] = KEY_RECORD,
+ [ 0x26 ] = KEY_TUNER,
+ [ 0x29 ] = KEY_TEXT,
+ [ 0x2a ] = KEY_MEDIA,
+ [ 0x18 ] = KEY_EPG,
+ [ 0x27 ] = KEY_RECORD,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_em_pinnacle_usb);
+
+IR_KEYTAB_TYPE ir_codes_flyvideo[IR_KEYTAB_SIZE] = {
+ [ 0x0f ] = KEY_0,
+ [ 0x03 ] = KEY_1,
+ [ 0x04 ] = KEY_2,
+ [ 0x05 ] = KEY_3,
+ [ 0x07 ] = KEY_4,
+ [ 0x08 ] = KEY_5,
+ [ 0x09 ] = KEY_6,
+ [ 0x0b ] = KEY_7,
+ [ 0x0c ] = KEY_8,
+ [ 0x0d ] = KEY_9,
+
+ [ 0x0e ] = KEY_MODE, // Air/Cable
+ [ 0x11 ] = KEY_VIDEO, // Video
+ [ 0x15 ] = KEY_AUDIO, // Audio
+ [ 0x00 ] = KEY_POWER, // Power
+ [ 0x18 ] = KEY_TUNER, // AV Source
+ [ 0x02 ] = KEY_ZOOM, // Fullscreen
+ [ 0x1a ] = KEY_LANGUAGE, // Stereo
+ [ 0x1b ] = KEY_MUTE, // Mute
+ [ 0x14 ] = KEY_VOLUMEUP, // Volume +
+ [ 0x17 ] = KEY_VOLUMEDOWN, // Volume -
+ [ 0x12 ] = KEY_CHANNELUP, // Channel +
+ [ 0x13 ] = KEY_CHANNELDOWN, // Channel -
+ [ 0x06 ] = KEY_AGAIN, // Recall
+ [ 0x10 ] = KEY_ENTER, // Enter
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_flyvideo);
+
+IR_KEYTAB_TYPE ir_codes_flydvb[IR_KEYTAB_SIZE] = {
+ [ 0x01 ] = KEY_ZOOM, // Full Screen
+ [ 0x00 ] = KEY_POWER, // Power
+
+ [ 0x03 ] = KEY_1,
+ [ 0x04 ] = KEY_2,
+ [ 0x05 ] = KEY_3,
+ [ 0x07 ] = KEY_4,
+ [ 0x08 ] = KEY_5,
+ [ 0x09 ] = KEY_6,
+ [ 0x0b ] = KEY_7,
+ [ 0x0c ] = KEY_8,
+ [ 0x0d ] = KEY_9,
+ [ 0x06 ] = KEY_AGAIN, // Recall
+ [ 0x0f ] = KEY_0,
+ [ 0x10 ] = KEY_MUTE, // Mute
+ [ 0x02 ] = KEY_RADIO, // TV/Radio
+ [ 0x1b ] = KEY_LANGUAGE, // SAP (Second Audio Program)
+
+ [ 0x14 ] = KEY_VOLUMEUP, // VOL+
+ [ 0x17 ] = KEY_VOLUMEDOWN, // VOL-
+ [ 0x12 ] = KEY_CHANNELUP, // CH+
+ [ 0x13 ] = KEY_CHANNELDOWN, // CH-
+ [ 0x1d ] = KEY_ENTER, // Enter
+
+ [ 0x1a ] = KEY_MODE, // PIP
+ [ 0x18 ] = KEY_TUNER, // Source
+
+ [ 0x1e ] = KEY_RECORD, // Record/Pause
+ [ 0x15 ] = KEY_ANGLE, // Swap (no label on key)
+ [ 0x1c ] = KEY_PAUSE, // Timeshift/Pause
+ [ 0x19 ] = KEY_BACK, // Rewind <<
+ [ 0x0a ] = KEY_PLAYPAUSE, // Play/Pause
+ [ 0x1f ] = KEY_FORWARD, // Forward >>
+ [ 0x16 ] = KEY_PREVIOUS, // Back |<<
+ [ 0x11 ] = KEY_STOP, // Stop
+ [ 0x0e ] = KEY_NEXT, // End >>|
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_flydvb);
+
+IR_KEYTAB_TYPE ir_codes_cinergy[IR_KEYTAB_SIZE] = {
+ [ 0x00 ] = KEY_0,
+ [ 0x01 ] = KEY_1,
+ [ 0x02 ] = KEY_2,
+ [ 0x03 ] = KEY_3,
+ [ 0x04 ] = KEY_4,
+ [ 0x05 ] = KEY_5,
+ [ 0x06 ] = KEY_6,
+ [ 0x07 ] = KEY_7,
+ [ 0x08 ] = KEY_8,
+ [ 0x09 ] = KEY_9,
+
+ [ 0x0a ] = KEY_POWER,
+ [ 0x0b ] = KEY_PROG1, // app
+ [ 0x0c ] = KEY_ZOOM, // zoom/fullscreen
+ [ 0x0d ] = KEY_CHANNELUP, // channel
+ [ 0x0e ] = KEY_CHANNELDOWN, // channel-
+ [ 0x0f ] = KEY_VOLUMEUP,
+ [ 0x10 ] = KEY_VOLUMEDOWN,
+ [ 0x11 ] = KEY_TUNER, // AV
+ [ 0x12 ] = KEY_NUMLOCK, // -/--
+ [ 0x13 ] = KEY_AUDIO, // audio
+ [ 0x14 ] = KEY_MUTE,
+ [ 0x15 ] = KEY_UP,
+ [ 0x16 ] = KEY_DOWN,
+ [ 0x17 ] = KEY_LEFT,
+ [ 0x18 ] = KEY_RIGHT,
+ [ 0x19 ] = BTN_LEFT,
+ [ 0x1a ] = BTN_RIGHT,
+ [ 0x1b ] = KEY_WWW, // text
+ [ 0x1c ] = KEY_REWIND,
+ [ 0x1d ] = KEY_FORWARD,
+ [ 0x1e ] = KEY_RECORD,
+ [ 0x1f ] = KEY_PLAY,
+ [ 0x20 ] = KEY_PREVIOUSSONG,
+ [ 0x21 ] = KEY_NEXTSONG,
+ [ 0x22 ] = KEY_PAUSE,
+ [ 0x23 ] = KEY_STOP,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_cinergy);
+
+/* Alfons Geser <a.geser@cox.net>
+ * updates from Job D. R. Borges <jobdrb@ig.com.br> */
+IR_KEYTAB_TYPE ir_codes_eztv[IR_KEYTAB_SIZE] = {
+ [ 0x12 ] = KEY_POWER,
+ [ 0x01 ] = KEY_TV, // DVR
+ [ 0x15 ] = KEY_DVD, // DVD
+ [ 0x17 ] = KEY_AUDIO, // music
+ // DVR mode / DVD mode / music mode
+
+ [ 0x1b ] = KEY_MUTE, // mute
+ [ 0x02 ] = KEY_LANGUAGE, // MTS/SAP / audio / autoseek
+ [ 0x1e ] = KEY_SUBTITLE, // closed captioning / subtitle / seek
+ [ 0x16 ] = KEY_ZOOM, // full screen
+ [ 0x1c ] = KEY_VIDEO, // video source / eject / delall
+ [ 0x1d ] = KEY_RESTART, // playback / angle / del
+ [ 0x2f ] = KEY_SEARCH, // scan / menu / playlist
+ [ 0x30 ] = KEY_CHANNEL, // CH surfing / bookmark / memo
+
+ [ 0x31 ] = KEY_HELP, // help
+ [ 0x32 ] = KEY_MODE, // num/memo
+ [ 0x33 ] = KEY_ESC, // cancel
+
+ [ 0x0c ] = KEY_UP, // up
+ [ 0x10 ] = KEY_DOWN, // down
+ [ 0x08 ] = KEY_LEFT, // left
+ [ 0x04 ] = KEY_RIGHT, // right
+ [ 0x03 ] = KEY_SELECT, // select
+
+ [ 0x1f ] = KEY_REWIND, // rewind
+ [ 0x20 ] = KEY_PLAYPAUSE, // play/pause
+ [ 0x29 ] = KEY_FORWARD, // forward
+ [ 0x14 ] = KEY_AGAIN, // repeat
+ [ 0x2b ] = KEY_RECORD, // recording
+ [ 0x2c ] = KEY_STOP, // stop
+ [ 0x2d ] = KEY_PLAY, // play
+ [ 0x2e ] = KEY_SHUFFLE, // snapshot / shuffle
+
+ [ 0x00 ] = KEY_0,
+ [ 0x05 ] = KEY_1,
+ [ 0x06 ] = KEY_2,
+ [ 0x07 ] = KEY_3,
+ [ 0x09 ] = KEY_4,
+ [ 0x0a ] = KEY_5,
+ [ 0x0b ] = KEY_6,
+ [ 0x0d ] = KEY_7,
+ [ 0x0e ] = KEY_8,
+ [ 0x0f ] = KEY_9,
+
+ [ 0x2a ] = KEY_VOLUMEUP,
+ [ 0x11 ] = KEY_VOLUMEDOWN,
+ [ 0x18 ] = KEY_CHANNELUP, // CH.tracking up
+ [ 0x19 ] = KEY_CHANNELDOWN, // CH.tracking down
+
+ [ 0x13 ] = KEY_ENTER, // enter
+ [ 0x21 ] = KEY_DOT, // . (decimal dot)
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_eztv);
+
+/* Alex Hermann <gaaf@gmx.net> */
+IR_KEYTAB_TYPE ir_codes_avermedia[IR_KEYTAB_SIZE] = {
+ [ 0x28 ] = KEY_1,
+ [ 0x18 ] = KEY_2,
+ [ 0x38 ] = KEY_3,
+ [ 0x24 ] = KEY_4,
+ [ 0x14 ] = KEY_5,
+ [ 0x34 ] = KEY_6,
+ [ 0x2c ] = KEY_7,
+ [ 0x1c ] = KEY_8,
+ [ 0x3c ] = KEY_9,
+ [ 0x22 ] = KEY_0,
+
+ [ 0x20 ] = KEY_TV, /* TV/FM */
+ [ 0x10 ] = KEY_CD, /* CD */
+ [ 0x30 ] = KEY_TEXT, /* TELETEXT */
+ [ 0x00 ] = KEY_POWER, /* POWER */
+
+ [ 0x08 ] = KEY_VIDEO, /* VIDEO */
+ [ 0x04 ] = KEY_AUDIO, /* AUDIO */
+ [ 0x0c ] = KEY_ZOOM, /* FULL SCREEN */
+
+ [ 0x12 ] = KEY_SUBTITLE, /* DISPLAY */
+ [ 0x32 ] = KEY_REWIND, /* LOOP */
+ [ 0x02 ] = KEY_PRINT, /* PREVIEW */
+
+ [ 0x2a ] = KEY_SEARCH, /* AUTOSCAN */
+ [ 0x1a ] = KEY_SLEEP, /* FREEZE */
+ [ 0x3a ] = KEY_SHUFFLE, /* SNAPSHOT */
+ [ 0x0a ] = KEY_MUTE, /* MUTE */
+
+ [ 0x26 ] = KEY_RECORD, /* RECORD */
+ [ 0x16 ] = KEY_PAUSE, /* PAUSE */
+ [ 0x36 ] = KEY_STOP, /* STOP */
+ [ 0x06 ] = KEY_PLAY, /* PLAY */
+
+ [ 0x2e ] = KEY_RED, /* RED */
+ [ 0x21 ] = KEY_GREEN, /* GREEN */
+ [ 0x0e ] = KEY_YELLOW, /* YELLOW */
+ [ 0x01 ] = KEY_BLUE, /* BLUE */
+
+ [ 0x1e ] = KEY_VOLUMEDOWN, /* VOLUME- */
+ [ 0x3e ] = KEY_VOLUMEUP, /* VOLUME+ */
+ [ 0x11 ] = KEY_CHANNELDOWN, /* CHANNEL/PAGE- */
+ [ 0x31 ] = KEY_CHANNELUP /* CHANNEL/PAGE+ */
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_avermedia);
+
+IR_KEYTAB_TYPE ir_codes_videomate_tv_pvr[IR_KEYTAB_SIZE] = {
+ [ 0x14 ] = KEY_MUTE,
+ [ 0x24 ] = KEY_ZOOM,
+
+ [ 0x01 ] = KEY_DVD,
+ [ 0x23 ] = KEY_RADIO,
+ [ 0x00 ] = KEY_TV,
+
+ [ 0x0a ] = KEY_REWIND,
+ [ 0x08 ] = KEY_PLAYPAUSE,
+ [ 0x0f ] = KEY_FORWARD,
+
+ [ 0x02 ] = KEY_PREVIOUS,
+ [ 0x07 ] = KEY_STOP,
+ [ 0x06 ] = KEY_NEXT,
+
+ [ 0x0c ] = KEY_UP,
+ [ 0x0e ] = KEY_DOWN,
+ [ 0x0b ] = KEY_LEFT,
+ [ 0x0d ] = KEY_RIGHT,
+ [ 0x11 ] = KEY_OK,
+
+ [ 0x03 ] = KEY_MENU,
+ [ 0x09 ] = KEY_SETUP,
+ [ 0x05 ] = KEY_VIDEO,
+ [ 0x22 ] = KEY_CHANNEL,
+
+ [ 0x12 ] = KEY_VOLUMEUP,
+ [ 0x15 ] = KEY_VOLUMEDOWN,
+ [ 0x10 ] = KEY_CHANNELUP,
+ [ 0x13 ] = KEY_CHANNELDOWN,
+
+ [ 0x04 ] = KEY_RECORD,
+
+ [ 0x16 ] = KEY_1,
+ [ 0x17 ] = KEY_2,
+ [ 0x18 ] = KEY_3,
+ [ 0x19 ] = KEY_4,
+ [ 0x1a ] = KEY_5,
+ [ 0x1b ] = KEY_6,
+ [ 0x1c ] = KEY_7,
+ [ 0x1d ] = KEY_8,
+ [ 0x1e ] = KEY_9,
+ [ 0x1f ] = KEY_0,
+
+ [ 0x20 ] = KEY_LANGUAGE,
+ [ 0x21 ] = KEY_SLEEP,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_videomate_tv_pvr);
+
+/* Michael Tokarev <mjt@tls.msk.ru>
+ http://www.corpit.ru/mjt/beholdTV/remote_control.jpg
+ keytable is used by MANLI MTV00[ 0x0c ] and BeholdTV 40[13] at
+ least, and probably other cards too.
+ The "ascii-art picture" below (in comments, first row
+ is the keycode in hex, and subsequent row(s) shows
+ the button labels (several variants when appropriate)
+ helps to descide which keycodes to assign to the buttons.
+ */
+IR_KEYTAB_TYPE ir_codes_manli[IR_KEYTAB_SIZE] = {
+
+ /* 0x1c 0x12 *
+ * FUNCTION POWER *
+ * FM (|) *
+ * */
+ [ 0x1c ] = KEY_RADIO, /*XXX*/
+ [ 0x12 ] = KEY_POWER,
+
+ /* 0x01 0x02 0x03 *
+ * 1 2 3 *
+ * *
+ * 0x04 0x05 0x06 *
+ * 4 5 6 *
+ * *
+ * 0x07 0x08 0x09 *
+ * 7 8 9 *
+ * */
+ [ 0x01 ] = KEY_1,
+ [ 0x02 ] = KEY_2,
+ [ 0x03 ] = KEY_3,
+ [ 0x04 ] = KEY_4,
+ [ 0x05 ] = KEY_5,
+ [ 0x06 ] = KEY_6,
+ [ 0x07 ] = KEY_7,
+ [ 0x08 ] = KEY_8,
+ [ 0x09 ] = KEY_9,
+
+ /* 0x0a 0x00 0x17 *
+ * RECALL 0 +100 *
+ * PLUS *
+ * */
+ [ 0x0a ] = KEY_AGAIN, /*XXX KEY_REWIND? */
+ [ 0x00 ] = KEY_0,
+ [ 0x17 ] = KEY_DIGITS, /*XXX*/
+
+ /* 0x14 0x10 *
+ * MENU INFO *
+ * OSD */
+ [ 0x14 ] = KEY_MENU,
+ [ 0x10 ] = KEY_INFO,
+
+ /* 0x0b *
+ * Up *
+ * *
+ * 0x18 0x16 0x0c *
+ * Left Ok Right *
+ * *
+ * 0x015 *
+ * Down *
+ * */
+ [ 0x0b ] = KEY_UP, /*XXX KEY_SCROLLUP? */
+ [ 0x18 ] = KEY_LEFT, /*XXX KEY_BACK? */
+ [ 0x16 ] = KEY_OK, /*XXX KEY_SELECT? KEY_ENTER? */
+ [ 0x0c ] = KEY_RIGHT, /*XXX KEY_FORWARD? */
+ [ 0x15 ] = KEY_DOWN, /*XXX KEY_SCROLLDOWN? */
+
+ /* 0x11 0x0d *
+ * TV/AV MODE *
+ * SOURCE STEREO *
+ * */
+ [ 0x11 ] = KEY_TV, /*XXX*/
+ [ 0x0d ] = KEY_MODE, /*XXX there's no KEY_STEREO */
+
+ /* 0x0f 0x1b 0x1a *
+ * AUDIO Vol+ Chan+ *
+ * TIMESHIFT??? *
+ * *
+ * 0x0e 0x1f 0x1e *
+ * SLEEP Vol- Chan- *
+ * */
+ [ 0x0f ] = KEY_AUDIO,
+ [ 0x1b ] = KEY_VOLUMEUP,
+ [ 0x1a ] = KEY_CHANNELUP,
+ [ 0x0e ] = KEY_SLEEP, /*XXX maybe KEY_PAUSE */
+ [ 0x1f ] = KEY_VOLUMEDOWN,
+ [ 0x1e ] = KEY_CHANNELDOWN,
+
+ /* 0x13 0x19 *
+ * MUTE SNAPSHOT*
+ * */
+ [ 0x13 ] = KEY_MUTE,
+ [ 0x19 ] = KEY_RECORD, /*XXX*/
+
+ // 0x1d unused ?
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_manli);
+
+/* Mike Baikov <mike@baikov.com> */
+IR_KEYTAB_TYPE ir_codes_gotview7135[IR_KEYTAB_SIZE] = {
+
+ [ 0x21 ] = KEY_POWER,
+ [ 0x69 ] = KEY_TV,
+ [ 0x33 ] = KEY_0,
+ [ 0x51 ] = KEY_1,
+ [ 0x31 ] = KEY_2,
+ [ 0x71 ] = KEY_3,
+ [ 0x3b ] = KEY_4,
+ [ 0x58 ] = KEY_5,
+ [ 0x41 ] = KEY_6,
+ [ 0x48 ] = KEY_7,
+ [ 0x30 ] = KEY_8,
+ [ 0x53 ] = KEY_9,
+ [ 0x73 ] = KEY_AGAIN, /* LOOP */
+ [ 0x0a ] = KEY_AUDIO,
+ [ 0x61 ] = KEY_PRINT, /* PREVIEW */
+ [ 0x7a ] = KEY_VIDEO,
+ [ 0x20 ] = KEY_CHANNELUP,
+ [ 0x40 ] = KEY_CHANNELDOWN,
+ [ 0x18 ] = KEY_VOLUMEDOWN,
+ [ 0x50 ] = KEY_VOLUMEUP,
+ [ 0x10 ] = KEY_MUTE,
+ [ 0x4a ] = KEY_SEARCH,
+ [ 0x7b ] = KEY_SHUFFLE, /* SNAPSHOT */
+ [ 0x22 ] = KEY_RECORD,
+ [ 0x62 ] = KEY_STOP,
+ [ 0x78 ] = KEY_PLAY,
+ [ 0x39 ] = KEY_REWIND,
+ [ 0x59 ] = KEY_PAUSE,
+ [ 0x19 ] = KEY_FORWARD,
+ [ 0x09 ] = KEY_ZOOM,
+
+ [ 0x52 ] = KEY_F21, /* LIVE TIMESHIFT */
+ [ 0x1a ] = KEY_F22, /* MIN TIMESHIFT */
+ [ 0x3a ] = KEY_F23, /* TIMESHIFT */
+ [ 0x70 ] = KEY_F24, /* NORMAL TIMESHIFT */
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_gotview7135);
+
+IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = {
+ [ 0x03 ] = KEY_POWER,
+ [ 0x6f ] = KEY_MUTE,
+ [ 0x10 ] = KEY_BACKSPACE, /* Recall */
+
+ [ 0x11 ] = KEY_0,
+ [ 0x04 ] = KEY_1,
+ [ 0x05 ] = KEY_2,
+ [ 0x06 ] = KEY_3,
+ [ 0x08 ] = KEY_4,
+ [ 0x09 ] = KEY_5,
+ [ 0x0a ] = KEY_6,
+ [ 0x0c ] = KEY_7,
+ [ 0x0d ] = KEY_8,
+ [ 0x0e ] = KEY_9,
+ [ 0x12 ] = KEY_DOT, /* 100+ */
+
+ [ 0x07 ] = KEY_VOLUMEUP,
+ [ 0x0b ] = KEY_VOLUMEDOWN,
+ [ 0x1a ] = KEY_KPPLUS,
+ [ 0x18 ] = KEY_KPMINUS,
+ [ 0x15 ] = KEY_UP,
+ [ 0x1d ] = KEY_DOWN,
+ [ 0x0f ] = KEY_CHANNELUP,
+ [ 0x13 ] = KEY_CHANNELDOWN,
+ [ 0x48 ] = KEY_ZOOM,
+
+ [ 0x1b ] = KEY_VIDEO, /* Video source */
+ [ 0x49 ] = KEY_LANGUAGE, /* MTS Select */
+ [ 0x19 ] = KEY_SEARCH, /* Auto Scan */
+
+ [ 0x4b ] = KEY_RECORD,
+ [ 0x46 ] = KEY_PLAY,
+ [ 0x45 ] = KEY_PAUSE, /* Pause */
+ [ 0x44 ] = KEY_STOP,
+ [ 0x40 ] = KEY_FORWARD, /* Forward ? */
+ [ 0x42 ] = KEY_REWIND, /* Backward ? */
+
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_purpletv);
+
+/* Mapping for the 28 key remote control as seen at
+ http://www.sednacomputer.com/photo/cardbus-tv.jpg
+ Pavel Mihaylov <bin@bash.info> */
+IR_KEYTAB_TYPE ir_codes_pctv_sedna[IR_KEYTAB_SIZE] = {
+ [ 0x00 ] = KEY_0,
+ [ 0x01 ] = KEY_1,
+ [ 0x02 ] = KEY_2,
+ [ 0x03 ] = KEY_3,
+ [ 0x04 ] = KEY_4,
+ [ 0x05 ] = KEY_5,
+ [ 0x06 ] = KEY_6,
+ [ 0x07 ] = KEY_7,
+ [ 0x08 ] = KEY_8,
+ [ 0x09 ] = KEY_9,
+
+ [ 0x0a ] = KEY_AGAIN, /* Recall */
+ [ 0x0b ] = KEY_CHANNELUP,
+ [ 0x0c ] = KEY_VOLUMEUP,
+ [ 0x0d ] = KEY_MODE, /* Stereo */
+ [ 0x0e ] = KEY_STOP,
+ [ 0x0f ] = KEY_PREVIOUSSONG,
+ [ 0x10 ] = KEY_ZOOM,
+ [ 0x11 ] = KEY_TUNER, /* Source */
+ [ 0x12 ] = KEY_POWER,
+ [ 0x13 ] = KEY_MUTE,
+ [ 0x15 ] = KEY_CHANNELDOWN,
+ [ 0x18 ] = KEY_VOLUMEDOWN,
+ [ 0x19 ] = KEY_SHUFFLE, /* Snapshot */
+ [ 0x1a ] = KEY_NEXTSONG,
+ [ 0x1b ] = KEY_TEXT, /* Time Shift */
+ [ 0x1c ] = KEY_RADIO, /* FM Radio */
+ [ 0x1d ] = KEY_RECORD,
+ [ 0x1e ] = KEY_PAUSE,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_pctv_sedna);
+
+/* Mark Phalan <phalanm@o2.ie> */
+IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE] = {
+ [ 0x00 ] = KEY_0,
+ [ 0x01 ] = KEY_1,
+ [ 0x02 ] = KEY_2,
+ [ 0x03 ] = KEY_3,
+ [ 0x04 ] = KEY_4,
+ [ 0x05 ] = KEY_5,
+ [ 0x06 ] = KEY_6,
+ [ 0x07 ] = KEY_7,
+ [ 0x08 ] = KEY_8,
+ [ 0x09 ] = KEY_9,
+
+ [ 0x12 ] = KEY_POWER,
+ [ 0x10 ] = KEY_MUTE,
+ [ 0x1f ] = KEY_VOLUMEDOWN,
+ [ 0x1b ] = KEY_VOLUMEUP,
+ [ 0x1a ] = KEY_CHANNELUP,
+ [ 0x1e ] = KEY_CHANNELDOWN,
+ [ 0x0e ] = KEY_PAGEUP,
+ [ 0x1d ] = KEY_PAGEDOWN,
+ [ 0x13 ] = KEY_SOUND,
+
+ [ 0x18 ] = KEY_KPPLUSMINUS, /* CH +/- */
+ [ 0x16 ] = KEY_SUBTITLE, /* CC */
+ [ 0x0d ] = KEY_TEXT, /* TTX */
+ [ 0x0b ] = KEY_TV, /* AIR/CBL */
+ [ 0x11 ] = KEY_PC, /* PC/TV */
+ [ 0x17 ] = KEY_OK, /* CH RTN */
+ [ 0x19 ] = KEY_MODE, /* FUNC */
+ [ 0x0c ] = KEY_SEARCH, /* AUTOSCAN */
+
+ /* Not sure what to do with these ones! */
+ [ 0x0f ] = KEY_SELECT, /* SOURCE */
+ [ 0x0a ] = KEY_KPPLUS, /* +100 */
+ [ 0x14 ] = KEY_EQUAL, /* SYNC */
+ [ 0x1c ] = KEY_MEDIA, /* PC/TV */
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_pv951);
+
+/* generic RC5 keytable */
+/* see http://users.pandora.be/nenya/electronics/rc5/codes00.htm */
+/* used by old (black) Hauppauge remotes */
+IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE] = {
+ /* Keys 0 to 9 */
+ [ 0x00 ] = KEY_0,
+ [ 0x01 ] = KEY_1,
+ [ 0x02 ] = KEY_2,
+ [ 0x03 ] = KEY_3,
+ [ 0x04 ] = KEY_4,
+ [ 0x05 ] = KEY_5,
+ [ 0x06 ] = KEY_6,
+ [ 0x07 ] = KEY_7,
+ [ 0x08 ] = KEY_8,
+ [ 0x09 ] = KEY_9,
+
+ [ 0x0b ] = KEY_CHANNEL, /* channel / program (japan: 11) */
+ [ 0x0c ] = KEY_POWER, /* standby */
+ [ 0x0d ] = KEY_MUTE, /* mute / demute */
+ [ 0x0f ] = KEY_TV, /* display */
+ [ 0x10 ] = KEY_VOLUMEUP,
+ [ 0x11 ] = KEY_VOLUMEDOWN,
+ [ 0x12 ] = KEY_BRIGHTNESSUP,
+ [ 0x13 ] = KEY_BRIGHTNESSDOWN,
+ [ 0x1e ] = KEY_SEARCH, /* search + */
+ [ 0x20 ] = KEY_CHANNELUP, /* channel / program + */
+ [ 0x21 ] = KEY_CHANNELDOWN, /* channel / program - */
+ [ 0x22 ] = KEY_CHANNEL, /* alt / channel */
+ [ 0x23 ] = KEY_LANGUAGE, /* 1st / 2nd language */
+ [ 0x26 ] = KEY_SLEEP, /* sleeptimer */
+ [ 0x2e ] = KEY_MENU, /* 2nd controls (USA: menu) */
+ [ 0x30 ] = KEY_PAUSE,
+ [ 0x32 ] = KEY_REWIND,
+ [ 0x33 ] = KEY_GOTO,
+ [ 0x35 ] = KEY_PLAY,
+ [ 0x36 ] = KEY_STOP,
+ [ 0x37 ] = KEY_RECORD, /* recording */
+ [ 0x3c ] = KEY_TEXT, /* teletext submode (Japan: 12) */
+ [ 0x3d ] = KEY_SUSPEND, /* system standby */
+
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_rc5_tv);
+
+/* Table for Leadtek Winfast Remote Controls - used by both bttv and cx88 */
+IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
+ /* Keys 0 to 9 */
+ [ 0x12 ] = KEY_0,
+ [ 0x05 ] = KEY_1,
+ [ 0x06 ] = KEY_2,
+ [ 0x07 ] = KEY_3,
+ [ 0x09 ] = KEY_4,
+ [ 0x0a ] = KEY_5,
+ [ 0x0b ] = KEY_6,
+ [ 0x0d ] = KEY_7,
+ [ 0x0e ] = KEY_8,
+ [ 0x0f ] = KEY_9,
+
+ [ 0x00 ] = KEY_POWER,
+ [ 0x02 ] = KEY_TUNER, /* TV/FM */
+ [ 0x1e ] = KEY_VIDEO,
+ [ 0x04 ] = KEY_VOLUMEUP,
+ [ 0x08 ] = KEY_VOLUMEDOWN,
+ [ 0x0c ] = KEY_CHANNELUP,
+ [ 0x10 ] = KEY_CHANNELDOWN,
+ [ 0x03 ] = KEY_ZOOM, /* fullscreen */
+ [ 0x1f ] = KEY_SUBTITLE, /* closed caption/teletext */
+ [ 0x20 ] = KEY_SLEEP,
+ [ 0x14 ] = KEY_MUTE,
+ [ 0x2b ] = KEY_RED,
+ [ 0x2c ] = KEY_GREEN,
+ [ 0x2d ] = KEY_YELLOW,
+ [ 0x2e ] = KEY_BLUE,
+ [ 0x18 ] = KEY_KPPLUS, /* fine tune + */
+ [ 0x19 ] = KEY_KPMINUS, /* fine tune - */
+ [ 0x21 ] = KEY_DOT,
+ [ 0x13 ] = KEY_ENTER,
+ [ 0x22 ] = KEY_BACK,
+ [ 0x23 ] = KEY_PLAYPAUSE,
+ [ 0x24 ] = KEY_NEXT,
+ [ 0x26 ] = KEY_STOP,
+ [ 0x27 ] = KEY_RECORD
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_winfast);
+
+IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
+ [ 0x59 ] = KEY_MUTE,
+ [ 0x4a ] = KEY_POWER,
+
+ [ 0x18 ] = KEY_TEXT,
+ [ 0x26 ] = KEY_TV,
+ [ 0x3d ] = KEY_PRINT,
+
+ [ 0x48 ] = KEY_RED,
+ [ 0x04 ] = KEY_GREEN,
+ [ 0x11 ] = KEY_YELLOW,
+ [ 0x00 ] = KEY_BLUE,
+
+ [ 0x2d ] = KEY_VOLUMEUP,
+ [ 0x1e ] = KEY_VOLUMEDOWN,
+
+ [ 0x49 ] = KEY_MENU,
+
+ [ 0x16 ] = KEY_CHANNELUP,
+ [ 0x17 ] = KEY_CHANNELDOWN,
+
+ [ 0x20 ] = KEY_UP,
+ [ 0x21 ] = KEY_DOWN,
+ [ 0x22 ] = KEY_LEFT,
+ [ 0x23 ] = KEY_RIGHT,
+ [ 0x0d ] = KEY_SELECT,
+
+
+
+ [ 0x08 ] = KEY_BACK,
+ [ 0x07 ] = KEY_REFRESH,
+
+ [ 0x2f ] = KEY_ZOOM,
+ [ 0x29 ] = KEY_RECORD,
+
+ [ 0x4b ] = KEY_PAUSE,
+ [ 0x4d ] = KEY_REWIND,
+ [ 0x2e ] = KEY_PLAY,
+ [ 0x4e ] = KEY_FORWARD,
+ [ 0x53 ] = KEY_PREVIOUS,
+ [ 0x4c ] = KEY_STOP,
+ [ 0x54 ] = KEY_NEXT,
+
+ [ 0x69 ] = KEY_0,
+ [ 0x6a ] = KEY_1,
+ [ 0x6b ] = KEY_2,
+ [ 0x6c ] = KEY_3,
+ [ 0x6d ] = KEY_4,
+ [ 0x6e ] = KEY_5,
+ [ 0x6f ] = KEY_6,
+ [ 0x70 ] = KEY_7,
+ [ 0x71 ] = KEY_8,
+ [ 0x72 ] = KEY_9,
+
+ [ 0x74 ] = KEY_CHANNEL,
+ [ 0x0a ] = KEY_BACKSPACE,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle);
+
+/* Hauppauge: the newer, gray remotes (seems there are multiple
+ * slightly different versions), shipped with cx88+ivtv cards.
+ * almost rc5 coding, but some non-standard keys */
+IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE] = {
+ /* Keys 0 to 9 */
+ [ 0x00 ] = KEY_0,
+ [ 0x01 ] = KEY_1,
+ [ 0x02 ] = KEY_2,
+ [ 0x03 ] = KEY_3,
+ [ 0x04 ] = KEY_4,
+ [ 0x05 ] = KEY_5,
+ [ 0x06 ] = KEY_6,
+ [ 0x07 ] = KEY_7,
+ [ 0x08 ] = KEY_8,
+ [ 0x09 ] = KEY_9,
+
+ [ 0x0a ] = KEY_TEXT, /* keypad asterisk as well */
+ [ 0x0b ] = KEY_RED, /* red button */
+ [ 0x0c ] = KEY_RADIO,
+ [ 0x0d ] = KEY_MENU,
+ [ 0x0e ] = KEY_SUBTITLE, /* also the # key */
+ [ 0x0f ] = KEY_MUTE,
+ [ 0x10 ] = KEY_VOLUMEUP,
+ [ 0x11 ] = KEY_VOLUMEDOWN,
+ [ 0x12 ] = KEY_PREVIOUS, /* previous channel */
+ [ 0x14 ] = KEY_UP,
+ [ 0x15 ] = KEY_DOWN,
+ [ 0x16 ] = KEY_LEFT,
+ [ 0x17 ] = KEY_RIGHT,
+ [ 0x18 ] = KEY_VIDEO, /* Videos */
+ [ 0x19 ] = KEY_AUDIO, /* Music */
+ /* 0x1a: Pictures - presume this means
+ "Multimedia Home Platform" -
+ no "PICTURES" key in input.h
+ */
+ [ 0x1a ] = KEY_MHP,
+
+ [ 0x1b ] = KEY_EPG, /* Guide */
+ [ 0x1c ] = KEY_TV,
+ [ 0x1e ] = KEY_NEXTSONG, /* skip >| */
+ [ 0x1f ] = KEY_EXIT, /* back/exit */
+ [ 0x20 ] = KEY_CHANNELUP, /* channel / program + */
+ [ 0x21 ] = KEY_CHANNELDOWN, /* channel / program - */
+ [ 0x22 ] = KEY_CHANNEL, /* source (old black remote) */
+ [ 0x24 ] = KEY_PREVIOUSSONG, /* replay |< */
+ [ 0x25 ] = KEY_ENTER, /* OK */
+ [ 0x26 ] = KEY_SLEEP, /* minimize (old black remote) */
+ [ 0x29 ] = KEY_BLUE, /* blue key */
+ [ 0x2e ] = KEY_GREEN, /* green button */
+ [ 0x30 ] = KEY_PAUSE, /* pause */
+ [ 0x32 ] = KEY_REWIND, /* backward << */
+ [ 0x34 ] = KEY_FASTFORWARD, /* forward >> */
+ [ 0x35 ] = KEY_PLAY,
+ [ 0x36 ] = KEY_STOP,
+ [ 0x37 ] = KEY_RECORD, /* recording */
+ [ 0x38 ] = KEY_YELLOW, /* yellow key */
+ [ 0x3b ] = KEY_SELECT, /* top right button */
+ [ 0x3c ] = KEY_ZOOM, /* full */
+ [ 0x3d ] = KEY_POWER, /* system power (green button) */
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_hauppauge_new);
+
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
index 04c1938b9c9..8cdd4d265ff 100644
--- a/drivers/media/common/saa7146_core.c
+++ b/drivers/media/common/saa7146_core.c
@@ -21,7 +21,7 @@
#include <media/saa7146.h>
LIST_HEAD(saa7146_devices);
-DECLARE_MUTEX(saa7146_devices_lock);
+DEFINE_MUTEX(saa7146_devices_lock);
static int saa7146_num;
@@ -116,8 +116,7 @@ static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages)
pg = vmalloc_to_page(virt);
if (NULL == pg)
goto err;
- if (PageHighMem(pg))
- BUG();
+ BUG_ON(PageHighMem(pg));
sglist[i].page = pg;
sglist[i].length = PAGE_SIZE;
}
@@ -402,11 +401,11 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
pci_set_drvdata(pci, dev);
- init_MUTEX(&dev->lock);
+ mutex_init(&dev->lock);
spin_lock_init(&dev->int_slock);
spin_lock_init(&dev->slock);
- init_MUTEX(&dev->i2c_lock);
+ mutex_init(&dev->i2c_lock);
dev->module = THIS_MODULE;
init_waitqueue_head(&dev->i2c_wq);
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index f8cf73ed49a..3870fa948cc 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -17,18 +17,18 @@ int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit)
}
/* is it free? */
- down(&dev->lock);
+ mutex_lock(&dev->lock);
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);
+ mutex_unlock(&dev->lock);
return 0;
}
/* it's free, grab it */
fh->resources |= bit;
vv->resources |= bit;
DEB_D(("res: get 0x%02x, cur:0x%02x\n",bit,vv->resources));
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
return 1;
}
@@ -37,14 +37,13 @@ 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();
+ BUG_ON((fh->resources & bits) != bits);
- down(&dev->lock);
+ mutex_lock(&dev->lock);
fh->resources &= ~bits;
vv->resources &= ~bits;
DEB_D(("res: put 0x%02x, cur:0x%02x\n",bits,vv->resources));
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
}
@@ -55,8 +54,7 @@ void saa7146_dma_free(struct saa7146_dev *dev,struct saa7146_buf *buf)
{
DEB_EE(("dev:%p, buf:%p\n",dev,buf));
- if (in_interrupt())
- BUG();
+ BUG_ON(in_interrupt());
videobuf_waiton(&buf->vb,0,0);
videobuf_dma_pci_unmap(dev->pci, &buf->vb.dma);
@@ -204,7 +202,7 @@ static int fops_open(struct inode *inode, struct file *file)
DEB_EE(("inode:%p, file:%p, minor:%d\n",inode,file,minor));
- if (down_interruptible(&saa7146_devices_lock))
+ if (mutex_lock_interruptible(&saa7146_devices_lock))
return -ERESTARTSYS;
list_for_each(list,&saa7146_devices) {
@@ -276,7 +274,7 @@ out:
kfree(fh);
file->private_data = NULL;
}
- up(&saa7146_devices_lock);
+ mutex_unlock(&saa7146_devices_lock);
return result;
}
@@ -287,7 +285,7 @@ static int fops_release(struct inode *inode, struct file *file)
DEB_EE(("inode:%p, file:%p\n",inode,file));
- if (down_interruptible(&saa7146_devices_lock))
+ if (mutex_lock_interruptible(&saa7146_devices_lock))
return -ERESTARTSYS;
if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
@@ -303,7 +301,7 @@ static int fops_release(struct inode *inode, struct file *file)
file->private_data = NULL;
kfree(fh);
- up(&saa7146_devices_lock);
+ mutex_unlock(&saa7146_devices_lock);
return 0;
}
diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c
index 8aabdd8fb3c..d9953f7a8b6 100644
--- a/drivers/media/common/saa7146_i2c.c
+++ b/drivers/media/common/saa7146_i2c.c
@@ -279,7 +279,7 @@ int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, in
int address_err = 0;
int short_delay = 0;
- if (down_interruptible (&dev->i2c_lock))
+ if (mutex_lock_interruptible(&dev->i2c_lock))
return -ERESTARTSYS;
for(i=0;i<num;i++) {
@@ -366,7 +366,7 @@ out:
}
}
- up(&dev->i2c_lock);
+ mutex_unlock(&dev->i2c_lock);
return err;
}
diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c
index 468d3c95907..500bd3f05e1 100644
--- a/drivers/media/common/saa7146_vbi.c
+++ b/drivers/media/common/saa7146_vbi.c
@@ -410,7 +410,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
V4L2_FIELD_SEQ_TB, // FIXME: does this really work?
sizeof(struct saa7146_buf),
file);
- init_MUTEX(&fh->vbi_q.lock);
+ mutex_init(&fh->vbi_q.lock);
init_timer(&fh->vbi_read_timeout);
fh->vbi_read_timeout.function = vbi_read_timeout;
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index 7ebac7949df..6b42713d97f 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -378,20 +378,20 @@ static int s_fmt(struct saa7146_fh *fh, struct v4l2_format *f)
err = try_win(dev,&f->fmt.win);
if (0 != err)
return err;
- down(&dev->lock);
+ mutex_lock(&dev->lock);
fh->ov.win = f->fmt.win;
fh->ov.nclips = f->fmt.win.clipcount;
if (fh->ov.nclips > 16)
fh->ov.nclips = 16;
if (copy_from_user(fh->ov.clips,f->fmt.win.clips,sizeof(struct v4l2_clip)*fh->ov.nclips)) {
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
return -EFAULT;
}
/* fh->ov.fh is used to indicate that we have valid overlay informations, too */
fh->ov.fh = fh;
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
/* check if our current overlay is active */
if (IS_OVERLAY_ACTIVE(fh) != 0) {
@@ -516,7 +516,7 @@ static int set_control(struct saa7146_fh *fh, struct v4l2_control *c)
return -EINVAL;
}
- down(&dev->lock);
+ mutex_lock(&dev->lock);
switch (ctrl->type) {
case V4L2_CTRL_TYPE_BOOLEAN:
@@ -560,7 +560,7 @@ static int set_control(struct saa7146_fh *fh, struct v4l2_control *c)
/* fixme: we can support changing VFLIP and HFLIP here... */
if (IS_CAPTURE_ACTIVE(fh) != 0) {
DEB_D(("V4L2_CID_HFLIP while active capture.\n"));
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
return -EINVAL;
}
vv->hflip = c->value;
@@ -568,7 +568,7 @@ static int set_control(struct saa7146_fh *fh, struct v4l2_control *c)
case V4L2_CID_VFLIP:
if (IS_CAPTURE_ACTIVE(fh) != 0) {
DEB_D(("V4L2_CID_VFLIP while active capture.\n"));
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
return -EINVAL;
}
vv->vflip = c->value;
@@ -577,7 +577,7 @@ static int set_control(struct saa7146_fh *fh, struct v4l2_control *c)
return -EINVAL;
}
}
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
if (IS_OVERLAY_ACTIVE(fh) != 0) {
saa7146_stop_preview(fh);
@@ -939,7 +939,7 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
}
}
- down(&dev->lock);
+ mutex_lock(&dev->lock);
/* ok, accept it */
vv->ov_fb = *fb;
@@ -948,7 +948,7 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
vv->ov_fb.fmt.bytesperline =
vv->ov_fb.fmt.width*fmt->depth/8;
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
return 0;
}
@@ -1086,7 +1086,7 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
}
}
- down(&dev->lock);
+ mutex_lock(&dev->lock);
for(i = 0; i < dev->ext_vv_data->num_stds; i++)
if (*id & dev->ext_vv_data->stds[i].id)
@@ -1098,7 +1098,7 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
found = 1;
}
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
if (vv->ov_suspend != NULL) {
saa7146_start_preview(vv->ov_suspend);
@@ -1201,11 +1201,11 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
DEB_D(("VIDIOCGMBUF \n"));
q = &fh->video_q;
- down(&q->lock);
+ mutex_lock(&q->lock);
err = videobuf_mmap_setup(q,gbuffers,gbufsize,
V4L2_MEMORY_MMAP);
if (err < 0) {
- up(&q->lock);
+ mutex_unlock(&q->lock);
return err;
}
memset(mbuf,0,sizeof(*mbuf));
@@ -1213,7 +1213,7 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
mbuf->size = gbuffers * gbufsize;
for (i = 0; i < gbuffers; i++)
mbuf->offsets[i] = i * gbufsize;
- up(&q->lock);
+ mutex_unlock(&q->lock);
return 0;
}
default:
@@ -1414,7 +1414,7 @@ static int video_open(struct saa7146_dev *dev, struct file *file)
sizeof(struct saa7146_buf),
file);
- init_MUTEX(&fh->video_q.lock);
+ mutex_init(&fh->video_q.lock);
return 0;
}
diff --git a/drivers/media/dvb/b2c2/flexcop-common.h b/drivers/media/dvb/b2c2/flexcop-common.h
index 7d7e1613c5a..b3dd0603cd9 100644
--- a/drivers/media/dvb/b2c2/flexcop-common.h
+++ b/drivers/media/dvb/b2c2/flexcop-common.h
@@ -10,6 +10,7 @@
#include <linux/config.h>
#include <linux/pci.h>
+#include <linux/mutex.h>
#include "flexcop-reg.h"
@@ -73,8 +74,7 @@ struct flexcop_device {
int (*fe_sleep) (struct dvb_frontend *);
struct i2c_adapter i2c_adap;
- struct semaphore i2c_sem;
-
+ struct mutex i2c_mutex;
struct module *owner;
/* options and status */
diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c
index 56495cb6cd0..e0bd2d8f0f0 100644
--- a/drivers/media/dvb/b2c2/flexcop-i2c.c
+++ b/drivers/media/dvb/b2c2/flexcop-i2c.c
@@ -135,7 +135,7 @@ static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs
struct flexcop_device *fc = i2c_get_adapdata(i2c_adap);
int i, ret = 0;
- if (down_interruptible(&fc->i2c_sem))
+ if (mutex_lock_interruptible(&fc->i2c_mutex))
return -ERESTARTSYS;
/* reading */
@@ -161,7 +161,7 @@ static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs
else
ret = num;
- up(&fc->i2c_sem);
+ mutex_unlock(&fc->i2c_mutex);
return ret;
}
@@ -180,7 +180,7 @@ int flexcop_i2c_init(struct flexcop_device *fc)
{
int ret;
- sema_init(&fc->i2c_sem,1);
+ mutex_init(&fc->i2c_mutex);
memset(&fc->i2c_adap, 0, sizeof(struct i2c_adapter));
strncpy(fc->i2c_adap.name, "B2C2 FlexCop device",I2C_NAME_SIZE);
diff --git a/drivers/media/dvb/bt8xx/Makefile b/drivers/media/dvb/bt8xx/Makefile
index d188e4c670b..9d197efb481 100644
--- a/drivers/media/dvb/bt8xx/Makefile
+++ b/drivers/media/dvb/bt8xx/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video/bt8xx -Idrivers/media/dvb/frontends
diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c
index 356f447ee2a..5500f8a0ffe 100644
--- a/drivers/media/dvb/bt8xx/bt878.c
+++ b/drivers/media/dvb/bt8xx/bt878.c
@@ -344,7 +344,7 @@ bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *
int retval;
retval = 0;
- if (down_interruptible (&bt->gpio_lock))
+ if (mutex_lock_interruptible(&bt->gpio_lock))
return -ERESTARTSYS;
/* special gpio signal */
switch (cmd) {
@@ -375,7 +375,7 @@ bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *
retval = -EINVAL;
break;
}
- up(&bt->gpio_lock);
+ mutex_unlock(&bt->gpio_lock);
return retval;
}
diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h
index 9faf93770d0..f685bc12960 100644
--- a/drivers/media/dvb/bt8xx/bt878.h
+++ b/drivers/media/dvb/bt8xx/bt878.h
@@ -25,6 +25,8 @@
#include <linux/pci.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
+#include <linux/mutex.h>
+
#include "bt848.h"
#include "bttv.h"
@@ -108,7 +110,7 @@ struct cards {
extern int bt878_num;
struct bt878 {
- struct semaphore gpio_lock;
+ struct mutex gpio_lock;
unsigned int nr;
unsigned int bttv_nr;
struct i2c_adapter *adapter;
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index 0310e3dd07e..1cfa5e5035d 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -910,7 +910,7 @@ static int dst_get_device_id(struct dst_state *state)
static int dst_probe(struct dst_state *state)
{
- sema_init(&state->dst_mutex, 1);
+ mutex_init(&state->dst_mutex);
if ((rdc_8820_reset(state)) < 0) {
dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed.");
return -1;
@@ -962,7 +962,7 @@ int dst_command(struct dst_state *state, u8 *data, u8 len)
{
u8 reply;
- down(&state->dst_mutex);
+ mutex_lock(&state->dst_mutex);
if ((dst_comm_init(state)) < 0) {
dprintk(verbose, DST_NOTICE, 1, "DST Communication Initialization Failed.");
goto error;
@@ -1013,11 +1013,11 @@ int dst_command(struct dst_state *state, u8 *data, u8 len)
dprintk(verbose, DST_INFO, 1, "checksum failure");
goto error;
}
- up(&state->dst_mutex);
+ mutex_unlock(&state->dst_mutex);
return 0;
error:
- up(&state->dst_mutex);
+ mutex_unlock(&state->dst_mutex);
return -EIO;
}
@@ -1128,7 +1128,7 @@ static int dst_write_tuna(struct dvb_frontend *fe)
dst_set_voltage(fe, SEC_VOLTAGE_13);
}
state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE);
- down(&state->dst_mutex);
+ mutex_lock(&state->dst_mutex);
if ((dst_comm_init(state)) < 0) {
dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed.");
goto error;
@@ -1160,11 +1160,11 @@ static int dst_write_tuna(struct dvb_frontend *fe)
state->diseq_flags |= ATTEMPT_TUNE;
retval = dst_get_tuna(state);
werr:
- up(&state->dst_mutex);
+ mutex_unlock(&state->dst_mutex);
return retval;
error:
- up(&state->dst_mutex);
+ mutex_unlock(&state->dst_mutex);
return -EIO;
}
diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
index c650b4bf7f5..f6b49a801eb 100644
--- a/drivers/media/dvb/bt8xx/dst_ca.c
+++ b/drivers/media/dvb/bt8xx/dst_ca.c
@@ -81,7 +81,7 @@ static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8
{
u8 reply;
- down(&state->dst_mutex);
+ mutex_lock(&state->dst_mutex);
dst_comm_init(state);
msleep(65);
@@ -110,11 +110,11 @@ static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8
goto error;
}
}
- up(&state->dst_mutex);
+ mutex_unlock(&state->dst_mutex);
return 0;
error:
- up(&state->dst_mutex);
+ mutex_unlock(&state->dst_mutex);
return -EIO;
}
diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h
index 81557f38fe3..51d4e043716 100644
--- a/drivers/media/dvb/bt8xx/dst_common.h
+++ b/drivers/media/dvb/bt8xx/dst_common.h
@@ -25,6 +25,7 @@
#include <linux/smp_lock.h>
#include <linux/dvb/frontend.h>
#include <linux/device.h>
+#include <linux/mutex.h>
#include "bt878.h"
#include "dst_ca.h"
@@ -121,7 +122,7 @@ struct dst_state {
u8 vendor[8];
u8 board_info[8];
- struct semaphore dst_mutex;
+ struct mutex dst_mutex;
};
struct dst_types {
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index ea27b15007e..baa8227ef87 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -76,13 +76,13 @@ static int dvb_bt8xx_start_feed(struct dvb_demux_feed *dvbdmxfeed)
if (!dvbdmx->dmx.frontend)
return -EINVAL;
- down(&card->lock);
+ mutex_lock(&card->lock);
card->nfeeds++;
rc = card->nfeeds;
if (card->nfeeds == 1)
bt878_start(card->bt, card->gpio_mode,
card->op_sync_orin, card->irq_err_ignore);
- up(&card->lock);
+ mutex_unlock(&card->lock);
return rc;
}
@@ -96,11 +96,11 @@ static int dvb_bt8xx_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
if (!dvbdmx->dmx.frontend)
return -EINVAL;
- down(&card->lock);
+ mutex_lock(&card->lock);
card->nfeeds--;
if (card->nfeeds == 0)
bt878_stop(card->bt);
- up(&card->lock);
+ mutex_unlock(&card->lock);
return 0;
}
@@ -239,6 +239,20 @@ static int cx24108_pll_set(struct dvb_frontend* fe, struct dvb_frontend_paramete
static int pinnsat_pll_init(struct dvb_frontend* fe)
{
+ struct dvb_bt8xx_card *card = fe->dvb->priv;
+
+ bttv_gpio_enable(card->bttv_nr, 1, 1); /* output */
+ bttv_write_gpio(card->bttv_nr, 1, 1); /* relay on */
+
+ return 0;
+}
+
+static int pinnsat_pll_sleep(struct dvb_frontend* fe)
+{
+ struct dvb_bt8xx_card *card = fe->dvb->priv;
+
+ bttv_write_gpio(card->bttv_nr, 1, 0); /* relay off */
+
return 0;
}
@@ -246,6 +260,7 @@ static struct cx24110_config pctvsat_config = {
.demod_address = 0x55,
.pll_init = pinnsat_pll_init,
.pll_set = cx24108_pll_set,
+ .pll_sleep = pinnsat_pll_sleep,
};
static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
@@ -788,7 +803,7 @@ static int dvb_bt8xx_probe(struct bttv_sub_device *sub)
if (!(card = kzalloc(sizeof(struct dvb_bt8xx_card), GFP_KERNEL)))
return -ENOMEM;
- init_MUTEX(&card->lock);
+ mutex_init(&card->lock);
card->bttv_nr = sub->core->nr;
strncpy(card->card_name, sub->core->name, sizeof(sub->core->name));
card->i2c_adapter = &sub->core->i2c_adap;
@@ -798,14 +813,14 @@ static int dvb_bt8xx_probe(struct bttv_sub_device *sub)
card->gpio_mode = 0x0400c060;
/* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR,
BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */
- card->op_sync_orin = 0;
- card->irq_err_ignore = 0;
+ card->op_sync_orin = BT878_RISC_SYNC_MASK;
+ card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
break;
case BTTV_BOARD_DVICO_DVBT_LITE:
card->gpio_mode = 0x0400C060;
- card->op_sync_orin = 0;
- card->irq_err_ignore = 0;
+ card->op_sync_orin = BT878_RISC_SYNC_MASK;
+ card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
/* 26, 15, 14, 6, 5
* A_PWRDN DA_DPM DA_SBR DA_IOM_DA
* DA_APP(parallel) */
@@ -820,15 +835,15 @@ static int dvb_bt8xx_probe(struct bttv_sub_device *sub)
case BTTV_BOARD_NEBULA_DIGITV:
case BTTV_BOARD_AVDVBT_761:
card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5);
- card->op_sync_orin = 0;
- card->irq_err_ignore = 0;
+ card->op_sync_orin = BT878_RISC_SYNC_MASK;
+ card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
/* A_PWRDN DA_SBR DA_APP (high speed serial) */
break;
case BTTV_BOARD_AVDVBT_771: //case 0x07711461:
card->gpio_mode = 0x0400402B;
card->op_sync_orin = BT878_RISC_SYNC_MASK;
- card->irq_err_ignore = 0;
+ card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
/* A_PWRDN DA_SBR DA_APP[0] PKTP=10 RISC_ENABLE FIFO_ENABLE*/
break;
@@ -852,8 +867,8 @@ static int dvb_bt8xx_probe(struct bttv_sub_device *sub)
case BTTV_BOARD_PC_HDTV:
card->gpio_mode = 0x0100EC7B;
- card->op_sync_orin = 0;
- card->irq_err_ignore = 0;
+ card->op_sync_orin = BT878_RISC_SYNC_MASK;
+ card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
break;
default:
@@ -881,7 +896,7 @@ static int dvb_bt8xx_probe(struct bttv_sub_device *sub)
return -EFAULT;
}
- init_MUTEX(&card->bt->gpio_lock);
+ mutex_init(&card->bt->gpio_lock);
card->bt->bttv_nr = sub->core->nr;
if ( (ret = dvb_bt8xx_load_card(card, sub->core->type)) ) {
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.h b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
index cf035a80361..00dd9fa54c8 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.h
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
@@ -26,6 +26,7 @@
#define DVB_BT8XX_H
#include <linux/i2c.h>
+#include <linux/mutex.h>
#include "dvbdev.h"
#include "dvb_net.h"
#include "bttv.h"
@@ -38,7 +39,7 @@
#include "lgdt330x.h"
struct dvb_bt8xx_card {
- struct semaphore lock;
+ struct mutex lock;
int nfeeds;
char card_name[32];
struct dvb_adapter dvb_adapter;
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index c4b4c5b6b7c..71b575dc22b 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -30,6 +30,7 @@
#include <linux/pci.h>
#include <linux/input.h>
#include <linux/dvb/frontend.h>
+#include <linux/mutex.h>
#include "dmxdev.h"
#include "dvb_demux.h"
@@ -116,7 +117,7 @@ static struct dvb_frontend_info cinergyt2_fe_info = {
struct cinergyt2 {
struct dvb_demux demux;
struct usb_device *udev;
- struct semaphore sem;
+ struct mutex sem;
struct dvb_adapter adapter;
struct dvb_device *fedev;
struct dmxdev dmxdev;
@@ -345,14 +346,14 @@ static int cinergyt2_start_feed(struct dvb_demux_feed *dvbdmxfeed)
struct dvb_demux *demux = dvbdmxfeed->demux;
struct cinergyt2 *cinergyt2 = demux->priv;
- if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+ if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
if (cinergyt2->streaming == 0)
cinergyt2_start_stream_xfer(cinergyt2);
cinergyt2->streaming++;
- up(&cinergyt2->sem);
+ mutex_unlock(&cinergyt2->sem);
return 0;
}
@@ -361,13 +362,13 @@ static int cinergyt2_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
struct dvb_demux *demux = dvbdmxfeed->demux;
struct cinergyt2 *cinergyt2 = demux->priv;
- if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+ if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
if (--cinergyt2->streaming == 0)
cinergyt2_stop_stream_xfer(cinergyt2);
- up(&cinergyt2->sem);
+ mutex_unlock(&cinergyt2->sem);
return 0;
}
@@ -483,11 +484,11 @@ static int cinergyt2_open (struct inode *inode, struct file *file)
struct cinergyt2 *cinergyt2 = dvbdev->priv;
int err = -ERESTARTSYS;
- if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+ if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
if ((err = dvb_generic_open(inode, file))) {
- up(&cinergyt2->sem);
+ mutex_unlock(&cinergyt2->sem);
return err;
}
@@ -499,12 +500,15 @@ static int cinergyt2_open (struct inode *inode, struct file *file)
atomic_inc(&cinergyt2->inuse);
- up(&cinergyt2->sem);
+ mutex_unlock(&cinergyt2->sem);
return 0;
}
static void cinergyt2_unregister(struct cinergyt2 *cinergyt2)
{
+ dvb_net_release(&cinergyt2->dvbnet);
+ dvb_dmxdev_release(&cinergyt2->dmxdev);
+ dvb_dmx_release(&cinergyt2->demux);
dvb_unregister_device(cinergyt2->fedev);
dvb_unregister_adapter(&cinergyt2->adapter);
@@ -517,7 +521,7 @@ static int cinergyt2_release (struct inode *inode, struct file *file)
struct dvb_device *dvbdev = file->private_data;
struct cinergyt2 *cinergyt2 = dvbdev->priv;
- if (down_interruptible(&cinergyt2->sem))
+ if (mutex_lock_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
if (!cinergyt2->disconnect_pending && (file->f_flags & O_ACCMODE) != O_RDONLY) {
@@ -526,7 +530,7 @@ static int cinergyt2_release (struct inode *inode, struct file *file)
cinergyt2_sleep(cinergyt2, 1);
}
- up(&cinergyt2->sem);
+ mutex_unlock(&cinergyt2->sem);
if (atomic_dec_and_test(&cinergyt2->inuse) && cinergyt2->disconnect_pending) {
warn("delayed unregister in release");
@@ -541,12 +545,12 @@ static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct
struct dvb_device *dvbdev = file->private_data;
struct cinergyt2 *cinergyt2 = dvbdev->priv;
- if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+ if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
poll_wait(file, &cinergyt2->poll_wq, wait);
- up(&cinergyt2->sem);
+ mutex_unlock(&cinergyt2->sem);
return (POLLIN | POLLRDNORM | POLLPRI);
}
@@ -613,7 +617,7 @@ static int cinergyt2_ioctl (struct inode *inode, struct file *file,
if (copy_from_user(&p, (void __user*) arg, sizeof(p)))
return -EFAULT;
- if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+ if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
@@ -629,7 +633,7 @@ static int cinergyt2_ioctl (struct inode *inode, struct file *file,
(char *) param, sizeof(*param),
NULL, 0);
- up(&cinergyt2->sem);
+ mutex_unlock(&cinergyt2->sem);
return (err < 0) ? err : 0;
}
@@ -724,7 +728,7 @@ static void cinergyt2_query_rc (void *data)
struct cinergyt2_rc_event rc_events[12];
int n, len, i;
- if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+ if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
return;
len = cinergyt2_command(cinergyt2, buf, sizeof(buf),
@@ -784,7 +788,7 @@ out:
schedule_delayed_work(&cinergyt2->rc_query_work,
msecs_to_jiffies(RC_QUERY_INTERVAL));
- up(&cinergyt2->sem);
+ mutex_unlock(&cinergyt2->sem);
}
static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
@@ -849,7 +853,7 @@ static void cinergyt2_query (void *data)
uint8_t lock_bits;
uint32_t unc;
- if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+ if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
return;
unc = s->uncorrected_block_count;
@@ -868,7 +872,7 @@ static void cinergyt2_query (void *data)
schedule_delayed_work(&cinergyt2->query_work,
msecs_to_jiffies(QUERY_INTERVAL));
- up(&cinergyt2->sem);
+ mutex_unlock(&cinergyt2->sem);
}
static int cinergyt2_probe (struct usb_interface *intf,
@@ -885,7 +889,7 @@ static int cinergyt2_probe (struct usb_interface *intf,
memset (cinergyt2, 0, sizeof (struct cinergyt2));
usb_set_intfdata (intf, (void *) cinergyt2);
- init_MUTEX(&cinergyt2->sem);
+ mutex_init(&cinergyt2->sem);
init_waitqueue_head (&cinergyt2->poll_wq);
INIT_WORK(&cinergyt2->query_work, cinergyt2_query, cinergyt2);
@@ -937,6 +941,7 @@ static int cinergyt2_probe (struct usb_interface *intf,
return 0;
bailout:
+ dvb_net_release(&cinergyt2->dvbnet);
dvb_dmxdev_release(&cinergyt2->dmxdev);
dvb_dmx_release(&cinergyt2->demux);
dvb_unregister_adapter(&cinergyt2->adapter);
@@ -967,7 +972,7 @@ static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state)
{
struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
- if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+ if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
if (state.event > PM_EVENT_ON) {
@@ -981,7 +986,7 @@ static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state)
cinergyt2_sleep(cinergyt2, 1);
}
- up(&cinergyt2->sem);
+ mutex_unlock(&cinergyt2->sem);
return 0;
}
@@ -990,7 +995,7 @@ static int cinergyt2_resume (struct usb_interface *intf)
struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
struct dvbt_set_parameters_msg *param = &cinergyt2->param;
- if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+ if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
if (!cinergyt2->sleeping) {
@@ -1003,7 +1008,7 @@ static int cinergyt2_resume (struct usb_interface *intf)
cinergyt2_resume_rc(cinergyt2);
- up(&cinergyt2->sem);
+ mutex_unlock(&cinergyt2->sem);
return 0;
}
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 7b8373ad121..09e96e9ddbd 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -1,9 +1,8 @@
/*
* dmxdev.c - DVB demultiplexer device
*
- * Copyright (C) 2000 Ralph Metzler <ralph@convergence.de>
- * & Marcus Metzler <marcus@convergence.de>
- for convergence integrated media GmbH
+ * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
+ * for convergence integrated media GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -32,7 +31,6 @@
#include <linux/wait.h>
#include <asm/uaccess.h>
#include <asm/system.h>
-
#include "dmxdev.h"
static int debug;
@@ -42,177 +40,133 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
#define dprintk if (debug) printk
-static inline void dvb_dmxdev_buffer_init(struct dmxdev_buffer *buffer)
+static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf,
+ const u8 *src, size_t len)
{
- buffer->data=NULL;
- buffer->size=8192;
- buffer->pread=0;
- buffer->pwrite=0;
- buffer->error=0;
- init_waitqueue_head(&buffer->queue);
-}
-
-static inline int dvb_dmxdev_buffer_write(struct dmxdev_buffer *buf, const u8 *src, int len)
-{
- int split;
- int free;
- int todo;
+ ssize_t free;
if (!len)
return 0;
if (!buf->data)
return 0;
- free=buf->pread-buf->pwrite;
- split=0;
- if (free<=0) {
- free+=buf->size;
- split=buf->size-buf->pwrite;
- }
- if (len>=free) {
+ free = dvb_ringbuffer_free(buf);
+ if (len > free) {
dprintk("dmxdev: buffer overflow\n");
- return -1;
+ return -EOVERFLOW;
}
- if (split>=len)
- split=0;
- todo=len;
- if (split) {
- memcpy(buf->data + buf->pwrite, src, split);
- todo-=split;
- buf->pwrite=0;
- }
- memcpy(buf->data + buf->pwrite, src+split, todo);
- buf->pwrite=(buf->pwrite+todo)%buf->size;
- return len;
+
+ return dvb_ringbuffer_write(buf, src, len);
}
-static ssize_t dvb_dmxdev_buffer_read(struct dmxdev_buffer *src,
- int non_blocking, char __user *buf, size_t count, loff_t *ppos)
+static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
+ int non_blocking, char __user *buf,
+ size_t count, loff_t *ppos)
{
- unsigned long todo=count;
- int split, avail, error;
+ size_t todo;
+ ssize_t avail;
+ ssize_t ret = 0;
if (!src->data)
return 0;
- if ((error=src->error)) {
- src->pwrite=src->pread;
- src->error=0;
- return error;
+ if (src->error) {
+ ret = src->error;
+ dvb_ringbuffer_flush(src);
+ return ret;
}
- if (non_blocking && (src->pwrite==src->pread))
- return -EWOULDBLOCK;
-
- while (todo>0) {
- if (non_blocking && (src->pwrite==src->pread))
- return (count-todo) ? (count-todo) : -EWOULDBLOCK;
+ for (todo = count; todo > 0; todo -= ret) {
+ if (non_blocking && dvb_ringbuffer_empty(src)) {
+ ret = -EWOULDBLOCK;
+ break;
+ }
- if (wait_event_interruptible(src->queue,
- (src->pread!=src->pwrite) ||
- (src->error))<0)
- return count-todo;
+ ret = wait_event_interruptible(src->queue,
+ !dvb_ringbuffer_empty(src) ||
+ (src->error != 0));
+ if (ret < 0)
+ break;
- if ((error=src->error)) {
- src->pwrite=src->pread;
- src->error=0;
- return error;
+ if (src->error) {
+ ret = src->error;
+ dvb_ringbuffer_flush(src);
+ break;
}
- split=src->size;
- avail=src->pwrite - src->pread;
- if (avail<0) {
- avail+=src->size;
- split=src->size - src->pread;
- }
- if (avail>todo)
- avail=todo;
- if (split<avail) {
- if (copy_to_user(buf, src->data+src->pread, split))
- return -EFAULT;
- buf+=split;
- src->pread=0;
- todo-=split;
- avail-=split;
- }
- if (avail) {
- if (copy_to_user(buf, src->data+src->pread, avail))
- return -EFAULT;
- src->pread = (src->pread + avail) % src->size;
- todo-=avail;
- buf+=avail;
- }
+ avail = dvb_ringbuffer_avail(src);
+ if (avail > todo)
+ avail = todo;
+
+ ret = dvb_ringbuffer_read(src, buf, avail, 1);
+ if (ret < 0)
+ break;
+
+ buf += ret;
}
- return count;
+
+ return (count - todo) ? (count - todo) : ret;
}
-static struct dmx_frontend * get_fe(struct dmx_demux *demux, int type)
+static struct dmx_frontend *get_fe(struct dmx_demux *demux, int type)
{
struct list_head *head, *pos;
- head=demux->get_frontends(demux);
+ head = demux->get_frontends(demux);
if (!head)
return NULL;
list_for_each(pos, head)
- if (DMX_FE_ENTRY(pos)->source==type)
+ if (DMX_FE_ENTRY(pos)->source == type)
return DMX_FE_ENTRY(pos);
return NULL;
}
-static inline void dvb_dmxdev_dvr_state_set(struct dmxdev_dvr *dmxdevdvr, int state)
-{
- spin_lock_irq(&dmxdevdvr->dev->lock);
- dmxdevdvr->state=state;
- spin_unlock_irq(&dmxdevdvr->dev->lock);
-}
-
static int dvb_dvr_open(struct inode *inode, struct file *file)
{
struct dvb_device *dvbdev = file->private_data;
struct dmxdev *dmxdev = dvbdev->priv;
struct dmx_frontend *front;
- dprintk ("function : %s\n", __FUNCTION__);
+ dprintk("function : %s\n", __FUNCTION__);
- if (down_interruptible (&dmxdev->mutex))
+ if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
- if ((file->f_flags&O_ACCMODE)==O_RDWR) {
- if (!(dmxdev->capabilities&DMXDEV_CAP_DUPLEX)) {
- up(&dmxdev->mutex);
+ if ((file->f_flags & O_ACCMODE) == O_RDWR) {
+ if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) {
+ mutex_unlock(&dmxdev->mutex);
return -EOPNOTSUPP;
}
}
- if ((file->f_flags&O_ACCMODE)==O_RDONLY) {
- dvb_dmxdev_buffer_init(&dmxdev->dvr_buffer);
- dmxdev->dvr_buffer.size=DVR_BUFFER_SIZE;
- dmxdev->dvr_buffer.data=vmalloc(DVR_BUFFER_SIZE);
- if (!dmxdev->dvr_buffer.data) {
- up(&dmxdev->mutex);
- return -ENOMEM;
- }
+ if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+ void *mem = vmalloc(DVR_BUFFER_SIZE);
+ if (!mem) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ENOMEM;
+ }
+ dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
}
- if ((file->f_flags&O_ACCMODE)==O_WRONLY) {
- dmxdev->dvr_orig_fe=dmxdev->demux->frontend;
+ if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
+ dmxdev->dvr_orig_fe = dmxdev->demux->frontend;
if (!dmxdev->demux->write) {
- up(&dmxdev->mutex);
+ mutex_unlock(&dmxdev->mutex);
return -EOPNOTSUPP;
}
- front=get_fe(dmxdev->demux, DMX_MEMORY_FE);
+ front = get_fe(dmxdev->demux, DMX_MEMORY_FE);
if (!front) {
- up(&dmxdev->mutex);
+ mutex_unlock(&dmxdev->mutex);
return -EINVAL;
}
dmxdev->demux->disconnect_frontend(dmxdev->demux);
dmxdev->demux->connect_frontend(dmxdev->demux, front);
}
- up(&dmxdev->mutex);
+ mutex_unlock(&dmxdev->mutex);
return 0;
}
@@ -221,30 +175,30 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)
struct dvb_device *dvbdev = file->private_data;
struct dmxdev *dmxdev = dvbdev->priv;
- if (down_interruptible (&dmxdev->mutex))
+ if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
- if ((file->f_flags&O_ACCMODE)==O_WRONLY) {
+ if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
dmxdev->demux->disconnect_frontend(dmxdev->demux);
dmxdev->demux->connect_frontend(dmxdev->demux,
dmxdev->dvr_orig_fe);
}
- if ((file->f_flags&O_ACCMODE)==O_RDONLY) {
+ if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
if (dmxdev->dvr_buffer.data) {
- void *mem=dmxdev->dvr_buffer.data;
+ void *mem = dmxdev->dvr_buffer.data;
mb();
spin_lock_irq(&dmxdev->lock);
- dmxdev->dvr_buffer.data=NULL;
+ dmxdev->dvr_buffer.data = NULL;
spin_unlock_irq(&dmxdev->lock);
vfree(mem);
}
}
- up(&dmxdev->mutex);
+ mutex_unlock(&dmxdev->mutex);
return 0;
}
static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
+ size_t count, loff_t *ppos)
{
struct dvb_device *dvbdev = file->private_data;
struct dmxdev *dmxdev = dvbdev->priv;
@@ -252,60 +206,62 @@ static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,
if (!dmxdev->demux->write)
return -EOPNOTSUPP;
- if ((file->f_flags&O_ACCMODE)!=O_WRONLY)
+ if ((file->f_flags & O_ACCMODE) != O_WRONLY)
return -EINVAL;
- if (down_interruptible (&dmxdev->mutex))
+ if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
- ret=dmxdev->demux->write(dmxdev->demux, buf, count);
- up(&dmxdev->mutex);
+ ret = dmxdev->demux->write(dmxdev->demux, buf, count);
+ mutex_unlock(&dmxdev->mutex);
return ret;
}
static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
- loff_t *ppos)
+ loff_t *ppos)
{
struct dvb_device *dvbdev = file->private_data;
struct dmxdev *dmxdev = dvbdev->priv;
int ret;
- //down(&dmxdev->mutex);
- ret= dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
- file->f_flags&O_NONBLOCK,
- buf, count, ppos);
- //up(&dmxdev->mutex);
+ //mutex_lock(&dmxdev->mutex);
+ ret = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
+ file->f_flags & O_NONBLOCK,
+ buf, count, ppos);
+ //mutex_unlock(&dmxdev->mutex);
return ret;
}
-static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter *dmxdevfilter, int state)
+static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter
+ *dmxdevfilter, int state)
{
spin_lock_irq(&dmxdevfilter->dev->lock);
- dmxdevfilter->state=state;
+ dmxdevfilter->state = state;
spin_unlock_irq(&dmxdevfilter->dev->lock);
}
-static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter, unsigned long size)
+static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter,
+ unsigned long size)
{
- struct dmxdev_buffer *buf=&dmxdevfilter->buffer;
+ struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;
void *mem;
- if (buf->size==size)
+ if (buf->size == size)
return 0;
- if (dmxdevfilter->state>=DMXDEV_STATE_GO)
+ if (dmxdevfilter->state >= DMXDEV_STATE_GO)
return -EBUSY;
spin_lock_irq(&dmxdevfilter->dev->lock);
- mem=buf->data;
- buf->data=NULL;
- buf->size=size;
- buf->pwrite=buf->pread=0;
+ mem = buf->data;
+ buf->data = NULL;
+ buf->size = size;
+ dvb_ringbuffer_flush(buf);
spin_unlock_irq(&dmxdevfilter->dev->lock);
vfree(mem);
if (buf->size) {
- mem=vmalloc(dmxdevfilter->buffer.size);
+ mem = vmalloc(dmxdevfilter->buffer.size);
if (!mem)
return -ENOMEM;
spin_lock_irq(&dmxdevfilter->dev->lock);
- buf->data=mem;
+ buf->data = mem;
spin_unlock_irq(&dmxdevfilter->dev->lock);
}
return 0;
@@ -313,31 +269,33 @@ static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter, unsign
static void dvb_dmxdev_filter_timeout(unsigned long data)
{
- struct dmxdev_filter *dmxdevfilter=(struct dmxdev_filter *)data;
+ struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data;
- dmxdevfilter->buffer.error=-ETIMEDOUT;
+ dmxdevfilter->buffer.error = -ETIMEDOUT;
spin_lock_irq(&dmxdevfilter->dev->lock);
- dmxdevfilter->state=DMXDEV_STATE_TIMEDOUT;
+ dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT;
spin_unlock_irq(&dmxdevfilter->dev->lock);
wake_up(&dmxdevfilter->buffer.queue);
}
static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
{
- struct dmx_sct_filter_params *para=&dmxdevfilter->params.sec;
+ struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec;
del_timer(&dmxdevfilter->timer);
if (para->timeout) {
- dmxdevfilter->timer.function=dvb_dmxdev_filter_timeout;
- dmxdevfilter->timer.data=(unsigned long) dmxdevfilter;
- dmxdevfilter->timer.expires=jiffies+1+(HZ/2+HZ*para->timeout)/1000;
+ dmxdevfilter->timer.function = dvb_dmxdev_filter_timeout;
+ dmxdevfilter->timer.data = (unsigned long)dmxdevfilter;
+ dmxdevfilter->timer.expires =
+ jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000;
add_timer(&dmxdevfilter->timer);
}
}
static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
- const u8 *buffer2, size_t buffer2_len,
- struct dmx_section_filter *filter, enum dmx_success success)
+ const u8 *buffer2, size_t buffer2_len,
+ struct dmx_section_filter *filter,
+ enum dmx_success success)
{
struct dmxdev_filter *dmxdevfilter = filter->priv;
int ret;
@@ -347,68 +305,68 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
return 0;
}
spin_lock(&dmxdevfilter->dev->lock);
- if (dmxdevfilter->state!=DMXDEV_STATE_GO) {
+ if (dmxdevfilter->state != DMXDEV_STATE_GO) {
spin_unlock(&dmxdevfilter->dev->lock);
return 0;
}
del_timer(&dmxdevfilter->timer);
dprintk("dmxdev: section callback %02x %02x %02x %02x %02x %02x\n",
buffer1[0], buffer1[1],
- buffer1[2], buffer1[3],
- buffer1[4], buffer1[5]);
- ret=dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1, buffer1_len);
- if (ret==buffer1_len) {
- ret=dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2, buffer2_len);
+ buffer1[2], buffer1[3], buffer1[4], buffer1[5]);
+ ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1,
+ buffer1_len);
+ if (ret == buffer1_len) {
+ ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2,
+ buffer2_len);
}
- if (ret<0) {
- dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread;
- dmxdevfilter->buffer.error=-EOVERFLOW;
+ if (ret < 0) {
+ dvb_ringbuffer_flush(&dmxdevfilter->buffer);
+ dmxdevfilter->buffer.error = ret;
}
- if (dmxdevfilter->params.sec.flags&DMX_ONESHOT)
- dmxdevfilter->state=DMXDEV_STATE_DONE;
+ if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
+ dmxdevfilter->state = DMXDEV_STATE_DONE;
spin_unlock(&dmxdevfilter->dev->lock);
wake_up(&dmxdevfilter->buffer.queue);
return 0;
}
static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
- const u8 *buffer2, size_t buffer2_len,
- struct dmx_ts_feed *feed, enum dmx_success success)
+ const u8 *buffer2, size_t buffer2_len,
+ struct dmx_ts_feed *feed,
+ enum dmx_success success)
{
struct dmxdev_filter *dmxdevfilter = feed->priv;
- struct dmxdev_buffer *buffer;
+ struct dvb_ringbuffer *buffer;
int ret;
spin_lock(&dmxdevfilter->dev->lock);
- if (dmxdevfilter->params.pes.output==DMX_OUT_DECODER) {
+ if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) {
spin_unlock(&dmxdevfilter->dev->lock);
return 0;
}
- if (dmxdevfilter->params.pes.output==DMX_OUT_TAP)
- buffer=&dmxdevfilter->buffer;
+ if (dmxdevfilter->params.pes.output == DMX_OUT_TAP)
+ buffer = &dmxdevfilter->buffer;
else
- buffer=&dmxdevfilter->dev->dvr_buffer;
+ buffer = &dmxdevfilter->dev->dvr_buffer;
if (buffer->error) {
spin_unlock(&dmxdevfilter->dev->lock);
wake_up(&buffer->queue);
return 0;
}
- ret=dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
- if (ret==buffer1_len)
- ret=dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);
- if (ret<0) {
- buffer->pwrite=buffer->pread;
- buffer->error=-EOVERFLOW;
+ ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
+ if (ret == buffer1_len)
+ ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);
+ if (ret < 0) {
+ dvb_ringbuffer_flush(buffer);
+ buffer->error = ret;
}
spin_unlock(&dmxdevfilter->dev->lock);
wake_up(&buffer->queue);
return 0;
}
-
/* stop feed but only mark the specified filter as stopped (state set) */
-
static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
{
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
@@ -427,20 +385,16 @@ static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
return 0;
}
-
/* start feed associated with the specified filter */
-
static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter)
{
- dvb_dmxdev_filter_state_set (filter, DMXDEV_STATE_GO);
+ dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
switch (filter->type) {
case DMXDEV_TYPE_SEC:
return filter->feed.sec->start_filtering(filter->feed.sec);
- break;
case DMXDEV_TYPE_PES:
return filter->feed.ts->start_filtering(filter->feed.ts);
- break;
default:
return -EINVAL;
}
@@ -448,32 +402,31 @@ static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter)
return 0;
}
-
/* restart section feed if it has filters left associated with it,
otherwise release the feed */
-
static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter)
{
int i;
struct dmxdev *dmxdev = filter->dev;
u16 pid = filter->params.sec.pid;
- for (i=0; i<dmxdev->filternum; i++)
- if (dmxdev->filter[i].state>=DMXDEV_STATE_GO &&
- dmxdev->filter[i].type==DMXDEV_TYPE_SEC &&
- dmxdev->filter[i].pid==pid) {
+ for (i = 0; i < dmxdev->filternum; i++)
+ if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
+ dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&
+ dmxdev->filter[i].params.sec.pid == pid) {
dvb_dmxdev_feed_start(&dmxdev->filter[i]);
return 0;
}
- filter->dev->demux->release_section_feed(dmxdev->demux, filter->feed.sec);
+ filter->dev->demux->release_section_feed(dmxdev->demux,
+ filter->feed.sec);
return 0;
}
static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
{
- if (dmxdevfilter->state<DMXDEV_STATE_GO)
+ if (dmxdevfilter->state < DMXDEV_STATE_GO)
return 0;
switch (dmxdevfilter->type) {
@@ -483,36 +436,36 @@ static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
dvb_dmxdev_feed_stop(dmxdevfilter);
if (dmxdevfilter->filter.sec)
dmxdevfilter->feed.sec->
- release_filter(dmxdevfilter->feed.sec,
- dmxdevfilter->filter.sec);
+ release_filter(dmxdevfilter->feed.sec,
+ dmxdevfilter->filter.sec);
dvb_dmxdev_feed_restart(dmxdevfilter);
- dmxdevfilter->feed.sec=NULL;
+ dmxdevfilter->feed.sec = NULL;
break;
case DMXDEV_TYPE_PES:
if (!dmxdevfilter->feed.ts)
break;
dvb_dmxdev_feed_stop(dmxdevfilter);
dmxdevfilter->dev->demux->
- release_ts_feed(dmxdevfilter->dev->demux,
- dmxdevfilter->feed.ts);
- dmxdevfilter->feed.ts=NULL;
+ release_ts_feed(dmxdevfilter->dev->demux,
+ dmxdevfilter->feed.ts);
+ dmxdevfilter->feed.ts = NULL;
break;
default:
- if (dmxdevfilter->state==DMXDEV_STATE_ALLOCATED)
+ if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED)
return 0;
return -EINVAL;
}
- dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread=0;
+
+ dvb_ringbuffer_flush(&dmxdevfilter->buffer);
return 0;
}
static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter)
{
- if (dmxdevfilter->state<DMXDEV_STATE_SET)
+ if (dmxdevfilter->state < DMXDEV_STATE_SET)
return 0;
- dmxdevfilter->type=DMXDEV_TYPE_NONE;
- dmxdevfilter->pid=0xffff;
+ dmxdevfilter->type = DMXDEV_TYPE_NONE;
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
return 0;
}
@@ -529,32 +482,33 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
if (filter->state >= DMXDEV_STATE_GO)
dvb_dmxdev_filter_stop(filter);
- if (!(mem = filter->buffer.data)) {
+ if (!filter->buffer.data) {
mem = vmalloc(filter->buffer.size);
+ if (!mem)
+ return -ENOMEM;
spin_lock_irq(&filter->dev->lock);
- filter->buffer.data=mem;
+ filter->buffer.data = mem;
spin_unlock_irq(&filter->dev->lock);
- if (!filter->buffer.data)
- return -ENOMEM;
}
- filter->buffer.pwrite = filter->buffer.pread = 0;
+ dvb_ringbuffer_flush(&filter->buffer);
switch (filter->type) {
case DMXDEV_TYPE_SEC:
{
- struct dmx_sct_filter_params *para=&filter->params.sec;
- struct dmx_section_filter **secfilter=&filter->filter.sec;
- struct dmx_section_feed **secfeed=&filter->feed.sec;
+ struct dmx_sct_filter_params *para = &filter->params.sec;
+ struct dmx_section_filter **secfilter = &filter->filter.sec;
+ struct dmx_section_feed **secfeed = &filter->feed.sec;
+
+ *secfilter = NULL;
+ *secfeed = NULL;
- *secfilter=NULL;
- *secfeed=NULL;
/* find active filter/feed with same PID */
- for (i=0; i<dmxdev->filternum; i++) {
+ for (i = 0; i < dmxdev->filternum; i++) {
if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
- dmxdev->filter[i].pid == para->pid &&
- dmxdev->filter[i].type == DMXDEV_TYPE_SEC) {
+ dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&
+ dmxdev->filter[i].params.sec.pid == para->pid) {
*secfeed = dmxdev->filter[i].feed.sec;
break;
}
@@ -562,21 +516,20 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
/* if no feed found, try to allocate new one */
if (!*secfeed) {
- ret=dmxdev->demux->allocate_section_feed(dmxdev->demux,
- secfeed,
- dvb_dmxdev_section_callback);
- if (ret<0) {
- printk ("DVB (%s): could not alloc feed\n",
- __FUNCTION__);
+ ret = dmxdev->demux->allocate_section_feed(dmxdev->demux,
+ secfeed,
+ dvb_dmxdev_section_callback);
+ if (ret < 0) {
+ printk("DVB (%s): could not alloc feed\n",
+ __FUNCTION__);
return ret;
}
- ret=(*secfeed)->set(*secfeed, para->pid, 32768,
- (para->flags & DMX_CHECK_CRC) ? 1 : 0);
-
- if (ret<0) {
- printk ("DVB (%s): could not set feed\n",
- __FUNCTION__);
+ ret = (*secfeed)->set(*secfeed, para->pid, 32768,
+ (para->flags & DMX_CHECK_CRC) ? 1 : 0);
+ if (ret < 0) {
+ printk("DVB (%s): could not set feed\n",
+ __FUNCTION__);
dvb_dmxdev_feed_restart(filter);
return ret;
}
@@ -584,41 +537,38 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
dvb_dmxdev_feed_stop(filter);
}
- ret=(*secfeed)->allocate_filter(*secfeed, secfilter);
-
+ ret = (*secfeed)->allocate_filter(*secfeed, secfilter);
if (ret < 0) {
dvb_dmxdev_feed_restart(filter);
filter->feed.sec->start_filtering(*secfeed);
- dprintk ("could not get filter\n");
+ dprintk("could not get filter\n");
return ret;
}
(*secfilter)->priv = filter;
memcpy(&((*secfilter)->filter_value[3]),
- &(para->filter.filter[1]), DMX_FILTER_SIZE-1);
+ &(para->filter.filter[1]), DMX_FILTER_SIZE - 1);
memcpy(&(*secfilter)->filter_mask[3],
- &para->filter.mask[1], DMX_FILTER_SIZE-1);
+ &para->filter.mask[1], DMX_FILTER_SIZE - 1);
memcpy(&(*secfilter)->filter_mode[3],
- &para->filter.mode[1], DMX_FILTER_SIZE-1);
+ &para->filter.mode[1], DMX_FILTER_SIZE - 1);
- (*secfilter)->filter_value[0]=para->filter.filter[0];
- (*secfilter)->filter_mask[0]=para->filter.mask[0];
- (*secfilter)->filter_mode[0]=para->filter.mode[0];
- (*secfilter)->filter_mask[1]=0;
- (*secfilter)->filter_mask[2]=0;
+ (*secfilter)->filter_value[0] = para->filter.filter[0];
+ (*secfilter)->filter_mask[0] = para->filter.mask[0];
+ (*secfilter)->filter_mode[0] = para->filter.mode[0];
+ (*secfilter)->filter_mask[1] = 0;
+ (*secfilter)->filter_mask[2] = 0;
filter->todo = 0;
- ret = filter->feed.sec->start_filtering (filter->feed.sec);
-
+ ret = filter->feed.sec->start_filtering(filter->feed.sec);
if (ret < 0)
return ret;
dvb_dmxdev_filter_timer(filter);
break;
}
-
case DMXDEV_TYPE_PES:
{
struct timespec timeout = { 0 };
@@ -630,41 +580,41 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
struct dmx_ts_feed **tsfeed = &filter->feed.ts;
filter->feed.ts = NULL;
- otype=para->output;
+ otype = para->output;
- ts_pes=(enum dmx_ts_pes) para->pes_type;
+ ts_pes = (enum dmx_ts_pes)para->pes_type;
- if (ts_pes<DMX_PES_OTHER)
- ts_type=TS_DECODER;
+ if (ts_pes < DMX_PES_OTHER)
+ ts_type = TS_DECODER;
else
- ts_type=0;
+ ts_type = 0;
if (otype == DMX_OUT_TS_TAP)
ts_type |= TS_PACKET;
if (otype == DMX_OUT_TAP)
- ts_type |= TS_PAYLOAD_ONLY|TS_PACKET;
+ ts_type |= TS_PAYLOAD_ONLY | TS_PACKET;
- ret=dmxdev->demux->allocate_ts_feed(dmxdev->demux,
- tsfeed,
- dvb_dmxdev_ts_callback);
- if (ret<0)
+ ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux,
+ tsfeed,
+ dvb_dmxdev_ts_callback);
+ if (ret < 0)
return ret;
- (*tsfeed)->priv = (void *) filter;
+ (*tsfeed)->priv = filter;
ret = (*tsfeed)->set(*tsfeed, para->pid, ts_type, ts_pes,
32768, timeout);
-
if (ret < 0) {
- dmxdev->demux->release_ts_feed(dmxdev->demux, *tsfeed);
+ dmxdev->demux->release_ts_feed(dmxdev->demux,
+ *tsfeed);
return ret;
}
ret = filter->feed.ts->start_filtering(filter->feed.ts);
-
if (ret < 0) {
- dmxdev->demux->release_ts_feed(dmxdev->demux, *tsfeed);
+ dmxdev->demux->release_ts_feed(dmxdev->demux,
+ *tsfeed);
return ret;
}
@@ -688,41 +638,40 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
if (!dmxdev->filter)
return -EINVAL;
- if (down_interruptible(&dmxdev->mutex))
+ if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
- for (i=0; i<dmxdev->filternum; i++)
- if (dmxdev->filter[i].state==DMXDEV_STATE_FREE)
+ for (i = 0; i < dmxdev->filternum; i++)
+ if (dmxdev->filter[i].state == DMXDEV_STATE_FREE)
break;
- if (i==dmxdev->filternum) {
- up(&dmxdev->mutex);
+ if (i == dmxdev->filternum) {
+ mutex_unlock(&dmxdev->mutex);
return -EMFILE;
}
- dmxdevfilter=&dmxdev->filter[i];
- sema_init(&dmxdevfilter->mutex, 1);
- dmxdevfilter->dvbdev=dmxdev->dvbdev;
- file->private_data=dmxdevfilter;
+ dmxdevfilter = &dmxdev->filter[i];
+ mutex_init(&dmxdevfilter->mutex);
+ file->private_data = dmxdevfilter;
- dvb_dmxdev_buffer_init(&dmxdevfilter->buffer);
- dmxdevfilter->type=DMXDEV_TYPE_NONE;
+ dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
+ dmxdevfilter->type = DMXDEV_TYPE_NONE;
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
- dmxdevfilter->feed.ts=NULL;
+ dmxdevfilter->feed.ts = NULL;
init_timer(&dmxdevfilter->timer);
- up(&dmxdev->mutex);
+ mutex_unlock(&dmxdev->mutex);
return 0;
}
-
-static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev, struct dmxdev_filter *dmxdevfilter)
+static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
+ struct dmxdev_filter *dmxdevfilter)
{
- if (down_interruptible(&dmxdev->mutex))
+ if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
- if (down_interruptible(&dmxdevfilter->mutex)) {
- up(&dmxdev->mutex);
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
return -ERESTARTSYS;
}
@@ -730,18 +679,18 @@ static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev, struct dmxdev_filter *d
dvb_dmxdev_filter_reset(dmxdevfilter);
if (dmxdevfilter->buffer.data) {
- void *mem=dmxdevfilter->buffer.data;
+ void *mem = dmxdevfilter->buffer.data;
spin_lock_irq(&dmxdev->lock);
- dmxdevfilter->buffer.data=NULL;
+ dmxdevfilter->buffer.data = NULL;
spin_unlock_irq(&dmxdev->lock);
vfree(mem);
}
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE);
wake_up(&dmxdevfilter->buffer.queue);
- up(&dmxdevfilter->mutex);
- up(&dmxdev->mutex);
+ mutex_unlock(&dmxdevfilter->mutex);
+ mutex_unlock(&dmxdev->mutex);
return 0;
}
@@ -749,173 +698,171 @@ static inline void invert_mode(dmx_filter_t *filter)
{
int i;
- for (i=0; i<DMX_FILTER_SIZE; i++)
- filter->mode[i]^=0xff;
+ for (i = 0; i < DMX_FILTER_SIZE; i++)
+ filter->mode[i] ^= 0xff;
}
-
static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev,
- struct dmxdev_filter *dmxdevfilter,
- struct dmx_sct_filter_params *params)
+ struct dmxdev_filter *dmxdevfilter,
+ struct dmx_sct_filter_params *params)
{
- dprintk ("function : %s\n", __FUNCTION__);
+ dprintk("function : %s\n", __FUNCTION__);
dvb_dmxdev_filter_stop(dmxdevfilter);
- dmxdevfilter->type=DMXDEV_TYPE_SEC;
- dmxdevfilter->pid=params->pid;
+ dmxdevfilter->type = DMXDEV_TYPE_SEC;
memcpy(&dmxdevfilter->params.sec,
params, sizeof(struct dmx_sct_filter_params));
invert_mode(&dmxdevfilter->params.sec.filter);
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
- if (params->flags&DMX_IMMEDIATE_START)
+ if (params->flags & DMX_IMMEDIATE_START)
return dvb_dmxdev_filter_start(dmxdevfilter);
return 0;
}
static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
- struct dmxdev_filter *dmxdevfilter,
- struct dmx_pes_filter_params *params)
+ struct dmxdev_filter *dmxdevfilter,
+ struct dmx_pes_filter_params *params)
{
dvb_dmxdev_filter_stop(dmxdevfilter);
- if (params->pes_type>DMX_PES_OTHER || params->pes_type<0)
+ if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0)
return -EINVAL;
- dmxdevfilter->type=DMXDEV_TYPE_PES;
- dmxdevfilter->pid=params->pid;
- memcpy(&dmxdevfilter->params, params, sizeof(struct dmx_pes_filter_params));
+ dmxdevfilter->type = DMXDEV_TYPE_PES;
+ memcpy(&dmxdevfilter->params, params,
+ sizeof(struct dmx_pes_filter_params));
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
- if (params->flags&DMX_IMMEDIATE_START)
+ if (params->flags & DMX_IMMEDIATE_START)
return dvb_dmxdev_filter_start(dmxdevfilter);
return 0;
}
static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil,
- struct file *file, char __user *buf, size_t count, loff_t *ppos)
+ struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
{
int result, hcount;
- int done=0;
-
- if (dfil->todo<=0) {
- hcount=3+dfil->todo;
- if (hcount>count)
- hcount=count;
- result=dvb_dmxdev_buffer_read(&dfil->buffer, file->f_flags&O_NONBLOCK,
- buf, hcount, ppos);
- if (result<0) {
- dfil->todo=0;
+ int done = 0;
+
+ if (dfil->todo <= 0) {
+ hcount = 3 + dfil->todo;
+ if (hcount > count)
+ hcount = count;
+ result = dvb_dmxdev_buffer_read(&dfil->buffer,
+ file->f_flags & O_NONBLOCK,
+ buf, hcount, ppos);
+ if (result < 0) {
+ dfil->todo = 0;
return result;
}
- if (copy_from_user(dfil->secheader-dfil->todo, buf, result))
+ if (copy_from_user(dfil->secheader - dfil->todo, buf, result))
return -EFAULT;
- buf+=result;
- done=result;
- count-=result;
- dfil->todo-=result;
- if (dfil->todo>-3)
+ buf += result;
+ done = result;
+ count -= result;
+ dfil->todo -= result;
+ if (dfil->todo > -3)
return done;
- dfil->todo=((dfil->secheader[1]<<8)|dfil->secheader[2])&0xfff;
+ dfil->todo = ((dfil->secheader[1] << 8) | dfil->secheader[2]) & 0xfff;
if (!count)
return done;
}
- if (count>dfil->todo)
- count=dfil->todo;
- result=dvb_dmxdev_buffer_read(&dfil->buffer, file->f_flags&O_NONBLOCK,
- buf, count, ppos);
- if (result<0)
+ if (count > dfil->todo)
+ count = dfil->todo;
+ result = dvb_dmxdev_buffer_read(&dfil->buffer,
+ file->f_flags & O_NONBLOCK,
+ buf, count, ppos);
+ if (result < 0)
return result;
- dfil->todo-=result;
- return (result+done);
+ dfil->todo -= result;
+ return (result + done);
}
-
static ssize_t
-dvb_demux_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+dvb_demux_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
{
- struct dmxdev_filter *dmxdevfilter= file->private_data;
- int ret=0;
+ struct dmxdev_filter *dmxdevfilter = file->private_data;
+ int ret;
- if (down_interruptible(&dmxdevfilter->mutex))
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex))
return -ERESTARTSYS;
- if (dmxdevfilter->type==DMXDEV_TYPE_SEC)
- ret=dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos);
+ if (dmxdevfilter->type == DMXDEV_TYPE_SEC)
+ ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos);
else
- ret=dvb_dmxdev_buffer_read(&dmxdevfilter->buffer,
- file->f_flags&O_NONBLOCK,
- buf, count, ppos);
+ ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer,
+ file->f_flags & O_NONBLOCK,
+ buf, count, ppos);
- up(&dmxdevfilter->mutex);
+ mutex_unlock(&dmxdevfilter->mutex);
return ret;
}
-
static int dvb_demux_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *parg)
{
struct dmxdev_filter *dmxdevfilter = file->private_data;
- struct dmxdev *dmxdev=dmxdevfilter->dev;
- unsigned long arg=(unsigned long) parg;
- int ret=0;
+ struct dmxdev *dmxdev = dmxdevfilter->dev;
+ unsigned long arg = (unsigned long)parg;
+ int ret = 0;
- if (down_interruptible (&dmxdev->mutex))
+ if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
switch (cmd) {
case DMX_START:
- if (down_interruptible(&dmxdevfilter->mutex)) {
- up(&dmxdev->mutex);
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
return -ERESTARTSYS;
}
- if (dmxdevfilter->state<DMXDEV_STATE_SET)
+ if (dmxdevfilter->state < DMXDEV_STATE_SET)
ret = -EINVAL;
else
ret = dvb_dmxdev_filter_start(dmxdevfilter);
- up(&dmxdevfilter->mutex);
+ mutex_unlock(&dmxdevfilter->mutex);
break;
case DMX_STOP:
- if (down_interruptible(&dmxdevfilter->mutex)) {
- up(&dmxdev->mutex);
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
return -ERESTARTSYS;
}
- ret=dvb_dmxdev_filter_stop(dmxdevfilter);
- up(&dmxdevfilter->mutex);
+ ret = dvb_dmxdev_filter_stop(dmxdevfilter);
+ mutex_unlock(&dmxdevfilter->mutex);
break;
case DMX_SET_FILTER:
- if (down_interruptible(&dmxdevfilter->mutex)) {
- up(&dmxdev->mutex);
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
return -ERESTARTSYS;
}
- ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter,
- (struct dmx_sct_filter_params *)parg);
- up(&dmxdevfilter->mutex);
+ ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, parg);
+ mutex_unlock(&dmxdevfilter->mutex);
break;
case DMX_SET_PES_FILTER:
- if (down_interruptible(&dmxdevfilter->mutex)) {
- up(&dmxdev->mutex);
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
return -ERESTARTSYS;
}
- ret=dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter,
- (struct dmx_pes_filter_params *)parg);
- up(&dmxdevfilter->mutex);
+ ret = dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, parg);
+ mutex_unlock(&dmxdevfilter->mutex);
break;
case DMX_SET_BUFFER_SIZE:
- if (down_interruptible(&dmxdevfilter->mutex)) {
- up(&dmxdev->mutex);
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
return -ERESTARTSYS;
}
- ret=dvb_dmxdev_set_buffer_size(dmxdevfilter, arg);
- up(&dmxdevfilter->mutex);
+ ret = dvb_dmxdev_set_buffer_size(dmxdevfilter, arg);
+ mutex_unlock(&dmxdevfilter->mutex);
break;
case DMX_GET_EVENT:
@@ -923,10 +870,10 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file,
case DMX_GET_PES_PIDS:
if (!dmxdev->demux->get_pes_pids) {
- ret=-EINVAL;
+ ret = -EINVAL;
break;
}
- dmxdev->demux->get_pes_pids(dmxdev->demux, (u16 *)parg);
+ dmxdev->demux->get_pes_pids(dmxdev->demux, parg);
break;
case DMX_GET_CAPS:
@@ -947,19 +894,20 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file,
case DMX_GET_STC:
if (!dmxdev->demux->get_stc) {
- ret=-EINVAL;
+ ret = -EINVAL;
break;
}
ret = dmxdev->demux->get_stc(dmxdev->demux,
- ((struct dmx_stc *)parg)->num,
- &((struct dmx_stc *)parg)->stc,
- &((struct dmx_stc *)parg)->base);
+ ((struct dmx_stc *)parg)->num,
+ &((struct dmx_stc *)parg)->stc,
+ &((struct dmx_stc *)parg)->base);
break;
default:
- ret=-EINVAL;
+ ret = -EINVAL;
+ break;
}
- up(&dmxdev->mutex);
+ mutex_unlock(&dmxdev->mutex);
return ret;
}
@@ -969,8 +917,7 @@ static int dvb_demux_ioctl(struct inode *inode, struct file *file,
return dvb_usercopy(inode, file, cmd, arg, dvb_demux_do_ioctl);
}
-
-static unsigned int dvb_demux_poll (struct file *file, poll_table *wait)
+static unsigned int dvb_demux_poll(struct file *file, poll_table *wait)
{
struct dmxdev_filter *dmxdevfilter = file->private_data;
unsigned int mask = 0;
@@ -988,13 +935,12 @@ static unsigned int dvb_demux_poll (struct file *file, poll_table *wait)
if (dmxdevfilter->buffer.error)
mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
- if (dmxdevfilter->buffer.pread != dmxdevfilter->buffer.pwrite)
+ if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer))
mask |= (POLLIN | POLLRDNORM | POLLPRI);
return mask;
}
-
static int dvb_demux_release(struct inode *inode, struct file *file)
{
struct dmxdev_filter *dmxdevfilter = file->private_data;
@@ -1003,72 +949,67 @@ static int dvb_demux_release(struct inode *inode, struct file *file)
return dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
}
-
static struct file_operations dvb_demux_fops = {
- .owner = THIS_MODULE,
- .read = dvb_demux_read,
- .ioctl = dvb_demux_ioctl,
- .open = dvb_demux_open,
- .release = dvb_demux_release,
- .poll = dvb_demux_poll,
+ .owner = THIS_MODULE,
+ .read = dvb_demux_read,
+ .ioctl = dvb_demux_ioctl,
+ .open = dvb_demux_open,
+ .release = dvb_demux_release,
+ .poll = dvb_demux_poll,
};
-
static struct dvb_device dvbdev_demux = {
- .priv = NULL,
- .users = 1,
- .writers = 1,
- .fops = &dvb_demux_fops
+ .priv = NULL,
+ .users = 1,
+ .writers = 1,
+ .fops = &dvb_demux_fops
};
-
static int dvb_dvr_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *parg)
+ unsigned int cmd, void *parg)
{
struct dvb_device *dvbdev = file->private_data;
struct dmxdev *dmxdev = dvbdev->priv;
+ int ret;
- int ret=0;
-
- if (down_interruptible (&dmxdev->mutex))
+ if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
switch (cmd) {
case DMX_SET_BUFFER_SIZE:
// FIXME: implement
- ret=0;
+ ret = 0;
break;
default:
- ret=-EINVAL;
+ ret = -EINVAL;
+ break;
}
- up(&dmxdev->mutex);
+ mutex_unlock(&dmxdev->mutex);
return ret;
}
-
static int dvb_dvr_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+ unsigned int cmd, unsigned long arg)
{
return dvb_usercopy(inode, file, cmd, arg, dvb_dvr_do_ioctl);
}
-
-static unsigned int dvb_dvr_poll (struct file *file, poll_table *wait)
+static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait)
{
struct dvb_device *dvbdev = file->private_data;
struct dmxdev *dmxdev = dvbdev->priv;
unsigned int mask = 0;
- dprintk ("function : %s\n", __FUNCTION__);
+ dprintk("function : %s\n", __FUNCTION__);
poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
- if ((file->f_flags&O_ACCMODE) == O_RDONLY) {
+ if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
if (dmxdev->dvr_buffer.error)
mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
- if (dmxdev->dvr_buffer.pread!=dmxdev->dvr_buffer.pwrite)
+ if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer))
mask |= (POLLIN | POLLRDNORM | POLLPRI);
} else
mask |= (POLLOUT | POLLWRNORM | POLLPRI);
@@ -1076,73 +1017,63 @@ static unsigned int dvb_dvr_poll (struct file *file, poll_table *wait)
return mask;
}
-
static struct file_operations dvb_dvr_fops = {
- .owner = THIS_MODULE,
- .read = dvb_dvr_read,
- .write = dvb_dvr_write,
- .ioctl = dvb_dvr_ioctl,
- .open = dvb_dvr_open,
- .release = dvb_dvr_release,
- .poll = dvb_dvr_poll,
+ .owner = THIS_MODULE,
+ .read = dvb_dvr_read,
+ .write = dvb_dvr_write,
+ .ioctl = dvb_dvr_ioctl,
+ .open = dvb_dvr_open,
+ .release = dvb_dvr_release,
+ .poll = dvb_dvr_poll,
};
static struct dvb_device dvbdev_dvr = {
- .priv = NULL,
- .users = 1,
- .writers = 1,
- .fops = &dvb_dvr_fops
+ .priv = NULL,
+ .users = 1,
+ .writers = 1,
+ .fops = &dvb_dvr_fops
};
-int
-dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
+int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
{
int i;
if (dmxdev->demux->open(dmxdev->demux) < 0)
return -EUSERS;
- dmxdev->filter = vmalloc(dmxdev->filternum*sizeof(struct dmxdev_filter));
+ dmxdev->filter = vmalloc(dmxdev->filternum * sizeof(struct dmxdev_filter));
if (!dmxdev->filter)
return -ENOMEM;
- dmxdev->dvr = vmalloc(dmxdev->filternum*sizeof(struct dmxdev_dvr));
- if (!dmxdev->dvr) {
- vfree(dmxdev->filter);
- dmxdev->filter = NULL;
- return -ENOMEM;
- }
-
- sema_init(&dmxdev->mutex, 1);
+ mutex_init(&dmxdev->mutex);
spin_lock_init(&dmxdev->lock);
- for (i=0; i<dmxdev->filternum; i++) {
- dmxdev->filter[i].dev=dmxdev;
- dmxdev->filter[i].buffer.data=NULL;
- dvb_dmxdev_filter_state_set(&dmxdev->filter[i], DMXDEV_STATE_FREE);
- dmxdev->dvr[i].dev=dmxdev;
- dmxdev->dvr[i].buffer.data=NULL;
- dvb_dmxdev_dvr_state_set(&dmxdev->dvr[i], DMXDEV_STATE_FREE);
+ for (i = 0; i < dmxdev->filternum; i++) {
+ dmxdev->filter[i].dev = dmxdev;
+ dmxdev->filter[i].buffer.data = NULL;
+ dvb_dmxdev_filter_state_set(&dmxdev->filter[i],
+ DMXDEV_STATE_FREE);
}
- dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev, DVB_DEVICE_DEMUX);
- dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr, dmxdev, DVB_DEVICE_DVR);
+ dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev,
+ DVB_DEVICE_DEMUX);
+ dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,
+ dmxdev, DVB_DEVICE_DVR);
- dvb_dmxdev_buffer_init(&dmxdev->dvr_buffer);
+ dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192);
return 0;
}
+
EXPORT_SYMBOL(dvb_dmxdev_init);
-void
-dvb_dmxdev_release(struct dmxdev *dmxdev)
+void dvb_dmxdev_release(struct dmxdev *dmxdev)
{
dvb_unregister_device(dmxdev->dvbdev);
dvb_unregister_device(dmxdev->dvr_dvbdev);
vfree(dmxdev->filter);
- dmxdev->filter=NULL;
- vfree(dmxdev->dvr);
- dmxdev->dvr=NULL;
+ dmxdev->filter = NULL;
dmxdev->demux->close(dmxdev->demux);
}
+
EXPORT_SYMBOL(dvb_dmxdev_release);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index fd72920c219..d2bee9ffe43 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -30,14 +30,15 @@
#include <linux/wait.h>
#include <linux/fs.h>
#include <linux/string.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
#include <linux/dvb/dmx.h>
#include "dvbdev.h"
#include "demux.h"
+#include "dvb_ringbuffer.h"
-enum dmxdevype {
+enum dmxdev_type {
DMXDEV_TYPE_NONE,
DMXDEV_TYPE_SEC,
DMXDEV_TYPE_PES,
@@ -52,18 +53,7 @@ enum dmxdev_state {
DMXDEV_STATE_TIMEDOUT
};
-struct dmxdev_buffer {
- u8 *data;
- int size;
- int pread;
- int pwrite;
- wait_queue_head_t queue;
- int error;
-};
-
struct dmxdev_filter {
- struct dvb_device *dvbdev;
-
union {
struct dmx_section_filter *sec;
} filter;
@@ -78,26 +68,17 @@ struct dmxdev_filter {
struct dmx_pes_filter_params pes;
} params;
- int type;
+ enum dmxdev_type type;
enum dmxdev_state state;
struct dmxdev *dev;
- struct dmxdev_buffer buffer;
+ struct dvb_ringbuffer buffer;
- struct semaphore mutex;
+ struct mutex mutex;
/* only for sections */
struct timer_list timer;
int todo;
u8 secheader[3];
-
- u16 pid;
-};
-
-
-struct dmxdev_dvr {
- int state;
- struct dmxdev *dev;
- struct dmxdev_buffer buffer;
};
@@ -106,7 +87,6 @@ struct dmxdev {
struct dvb_device *dvr_dvbdev;
struct dmxdev_filter *filter;
- struct dmxdev_dvr *dvr;
struct dmx_demux *demux;
int filternum;
@@ -114,10 +94,10 @@ struct dmxdev {
#define DMXDEV_CAP_DUPLEX 1
struct dmx_frontend *dvr_orig_fe;
- struct dmxdev_buffer dvr_buffer;
+ struct dvb_ringbuffer dvr_buffer;
#define DVR_BUFFER_SIZE (10*188*1024)
- struct semaphore mutex;
+ struct mutex mutex;
spinlock_t lock;
};
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index b4c899b1595..83ec5e06c48 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -589,18 +589,18 @@ static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type,
if (pid > DMX_MAX_PID)
return -EINVAL;
- if (down_interruptible(&demux->mutex))
+ if (mutex_lock_interruptible(&demux->mutex))
return -ERESTARTSYS;
if (ts_type & TS_DECODER) {
if (pes_type >= DMX_TS_PES_OTHER) {
- up(&demux->mutex);
+ mutex_unlock(&demux->mutex);
return -EINVAL;
}
if (demux->pesfilter[pes_type] &&
demux->pesfilter[pes_type] != feed) {
- up(&demux->mutex);
+ mutex_unlock(&demux->mutex);
return -EINVAL;
}
@@ -622,14 +622,14 @@ static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type,
#else
feed->buffer = vmalloc(feed->buffer_size);
if (!feed->buffer) {
- up(&demux->mutex);
+ mutex_unlock(&demux->mutex);
return -ENOMEM;
}
#endif
}
feed->state = DMX_STATE_READY;
- up(&demux->mutex);
+ mutex_unlock(&demux->mutex);
return 0;
}
@@ -640,21 +640,21 @@ static int dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed)
struct dvb_demux *demux = feed->demux;
int ret;
- if (down_interruptible(&demux->mutex))
+ if (mutex_lock_interruptible(&demux->mutex))
return -ERESTARTSYS;
if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_TS) {
- up(&demux->mutex);
+ mutex_unlock(&demux->mutex);
return -EINVAL;
}
if (!demux->start_feed) {
- up(&demux->mutex);
+ mutex_unlock(&demux->mutex);
return -ENODEV;
}
if ((ret = demux->start_feed(feed)) < 0) {
- up(&demux->mutex);
+ mutex_unlock(&demux->mutex);
return ret;
}
@@ -662,7 +662,7 @@ static int dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed)
ts_feed->is_filtering = 1;
feed->state = DMX_STATE_GO;
spin_unlock_irq(&demux->lock);
- up(&demux->mutex);
+ mutex_unlock(&demux->mutex);
return 0;
}
@@ -673,16 +673,16 @@ static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed *ts_feed)
struct dvb_demux *demux = feed->demux;
int ret;
- if (down_interruptible(&demux->mutex))
+ if (mutex_lock_interruptible(&demux->mutex))
return -ERESTARTSYS;
if (feed->state < DMX_STATE_GO) {
- up(&demux->mutex);
+ mutex_unlock(&demux->mutex);
return -EINVAL;
}
if (!demux->stop_feed) {
- up(&demux->mutex);
+ mutex_unlock(&demux->mutex);
return -ENODEV;
}
@@ -692,7 +692,7 @@ static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed *ts_feed)
ts_feed->is_filtering = 0;
feed->state = DMX_STATE_ALLOCATED;
spin_unlock_irq(&demux->lock);
- up(&demux->mutex);
+ mutex_unlock(&demux->mutex);
return ret;
}
@@ -704,11 +704,11 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
struct dvb_demux *demux = (struct dvb_demux *)dmx;
struct dvb_demux_feed *feed;
- if (down_interruptible(&demux->mutex))
+ if (mutex_lock_interruptible(&demux->mutex))
return -ERESTARTSYS;
if (!(feed = dvb_dmx_feed_alloc(demux))) {
- up(&demux->mutex);
+ mutex_unlock(&demux->mutex);
return -EBUSY;
}
@@ -729,7 +729,7 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
feed->state = DMX_STATE_FREE;
- up(&demux->mutex);
+ mutex_unlock(&demux->mutex);
return -EBUSY;
}
@@ -737,7 +737,7 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
feed->filter->feed = feed;
feed->filter->state = DMX_STATE_READY;
- up(&demux->mutex);
+ mutex_unlock(&demux->mutex);
return 0;
}
@@ -748,11 +748,11 @@ static int dvbdmx_release_ts_feed(struct dmx_demux *dmx,
struct dvb_demux *demux = (struct dvb_demux *)dmx;
struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
- if (down_interruptible(&demux->mutex))
+ if (mutex_lock_interruptible(&demux->mutex))
return -ERESTARTSYS;
if (feed->state == DMX_STATE_FREE) {
- up(&demux->mutex);
+ mutex_unlock(&demux->mutex);
return -EINVAL;
}
#ifndef NOBUFS
@@ -770,7 +770,7 @@ static int dvbdmx_release_ts_feed(struct dmx_demux *dmx,
if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER)
demux->pesfilter[feed->pes_type] = NULL;
- up(&demux->mutex);
+ mutex_unlock(&demux->mutex);
return 0;
}
@@ -785,12 +785,12 @@ static int dmx_section_feed_allocate_filter(struct dmx_section_feed *feed,
struct dvb_demux *dvbdemux = dvbdmxfeed->demux;
struct dvb_demux_filter *dvbdmxfilter;
- if (down_interruptible(&dvbdemux->mutex))
+ if (mutex_lock_interruptible(&dvbdemux->mutex))
return -ERESTARTSYS;
dvbdmxfilter = dvb_dmx_filter_alloc(dvbdemux);
if (!dvbdmxfilter) {
- up(&dvbdemux->mutex);
+ mutex_unlock(&dvbdemux->mutex);
return -EBUSY;
}
@@ -805,7 +805,7 @@ static int dmx_section_feed_allocate_filter(struct dmx_section_feed *feed,
dvbdmxfeed->filter = dvbdmxfilter;
spin_unlock_irq(&dvbdemux->lock);
- up(&dvbdemux->mutex);
+ mutex_unlock(&dvbdemux->mutex);
return 0;
}
@@ -819,7 +819,7 @@ static int dmx_section_feed_set(struct dmx_section_feed *feed,
if (pid > 0x1fff)
return -EINVAL;
- if (down_interruptible(&dvbdmx->mutex))
+ if (mutex_lock_interruptible(&dvbdmx->mutex))
return -ERESTARTSYS;
dvb_demux_feed_add(dvbdmxfeed);
@@ -833,13 +833,13 @@ static int dmx_section_feed_set(struct dmx_section_feed *feed,
#else
dvbdmxfeed->buffer = vmalloc(dvbdmxfeed->buffer_size);
if (!dvbdmxfeed->buffer) {
- up(&dvbdmx->mutex);
+ mutex_unlock(&dvbdmx->mutex);
return -ENOMEM;
}
#endif
dvbdmxfeed->state = DMX_STATE_READY;
- up(&dvbdmx->mutex);
+ mutex_unlock(&dvbdmx->mutex);
return 0;
}
@@ -871,16 +871,16 @@ static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed)
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
int ret;
- if (down_interruptible(&dvbdmx->mutex))
+ if (mutex_lock_interruptible(&dvbdmx->mutex))
return -ERESTARTSYS;
if (feed->is_filtering) {
- up(&dvbdmx->mutex);
+ mutex_unlock(&dvbdmx->mutex);
return -EBUSY;
}
if (!dvbdmxfeed->filter) {
- up(&dvbdmx->mutex);
+ mutex_unlock(&dvbdmx->mutex);
return -EINVAL;
}
@@ -890,14 +890,14 @@ static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed)
dvbdmxfeed->feed.sec.seclen = 0;
if (!dvbdmx->start_feed) {
- up(&dvbdmx->mutex);
+ mutex_unlock(&dvbdmx->mutex);
return -ENODEV;
}
prepare_secfilters(dvbdmxfeed);
if ((ret = dvbdmx->start_feed(dvbdmxfeed)) < 0) {
- up(&dvbdmx->mutex);
+ mutex_unlock(&dvbdmx->mutex);
return ret;
}
@@ -906,7 +906,7 @@ static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed)
dvbdmxfeed->state = DMX_STATE_GO;
spin_unlock_irq(&dvbdmx->lock);
- up(&dvbdmx->mutex);
+ mutex_unlock(&dvbdmx->mutex);
return 0;
}
@@ -916,11 +916,11 @@ static int dmx_section_feed_stop_filtering(struct dmx_section_feed *feed)
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
int ret;
- if (down_interruptible(&dvbdmx->mutex))
+ if (mutex_lock_interruptible(&dvbdmx->mutex))
return -ERESTARTSYS;
if (!dvbdmx->stop_feed) {
- up(&dvbdmx->mutex);
+ mutex_unlock(&dvbdmx->mutex);
return -ENODEV;
}
@@ -931,7 +931,7 @@ static int dmx_section_feed_stop_filtering(struct dmx_section_feed *feed)
feed->is_filtering = 0;
spin_unlock_irq(&dvbdmx->lock);
- up(&dvbdmx->mutex);
+ mutex_unlock(&dvbdmx->mutex);
return ret;
}
@@ -942,11 +942,11 @@ static int dmx_section_feed_release_filter(struct dmx_section_feed *feed,
struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
- if (down_interruptible(&dvbdmx->mutex))
+ if (mutex_lock_interruptible(&dvbdmx->mutex))
return -ERESTARTSYS;
if (dvbdmxfilter->feed != dvbdmxfeed) {
- up(&dvbdmx->mutex);
+ mutex_unlock(&dvbdmx->mutex);
return -EINVAL;
}
@@ -966,7 +966,7 @@ static int dmx_section_feed_release_filter(struct dmx_section_feed *feed,
dvbdmxfilter->state = DMX_STATE_FREE;
spin_unlock_irq(&dvbdmx->lock);
- up(&dvbdmx->mutex);
+ mutex_unlock(&dvbdmx->mutex);
return 0;
}
@@ -977,11 +977,11 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
struct dvb_demux_feed *dvbdmxfeed;
- if (down_interruptible(&dvbdmx->mutex))
+ if (mutex_lock_interruptible(&dvbdmx->mutex))
return -ERESTARTSYS;
if (!(dvbdmxfeed = dvb_dmx_feed_alloc(dvbdmx))) {
- up(&dvbdmx->mutex);
+ mutex_unlock(&dvbdmx->mutex);
return -EBUSY;
}
@@ -1006,7 +1006,7 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
(*feed)->stop_filtering = dmx_section_feed_stop_filtering;
(*feed)->release_filter = dmx_section_feed_release_filter;
- up(&dvbdmx->mutex);
+ mutex_unlock(&dvbdmx->mutex);
return 0;
}
@@ -1016,11 +1016,11 @@ static int dvbdmx_release_section_feed(struct dmx_demux *demux,
struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
- if (down_interruptible(&dvbdmx->mutex))
+ if (mutex_lock_interruptible(&dvbdmx->mutex))
return -ERESTARTSYS;
if (dvbdmxfeed->state == DMX_STATE_FREE) {
- up(&dvbdmx->mutex);
+ mutex_unlock(&dvbdmx->mutex);
return -EINVAL;
}
#ifndef NOBUFS
@@ -1033,7 +1033,7 @@ static int dvbdmx_release_section_feed(struct dmx_demux *demux,
dvbdmxfeed->pid = 0xffff;
- up(&dvbdmx->mutex);
+ mutex_unlock(&dvbdmx->mutex);
return 0;
}
@@ -1071,10 +1071,10 @@ static int dvbdmx_write(struct dmx_demux *demux, const char *buf, size_t count)
if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE))
return -EINVAL;
- if (down_interruptible(&dvbdemux->mutex))
+ if (mutex_lock_interruptible(&dvbdemux->mutex))
return -ERESTARTSYS;
dvb_dmx_swfilter(dvbdemux, buf, count);
- up(&dvbdemux->mutex);
+ mutex_unlock(&dvbdemux->mutex);
if (signal_pending(current))
return -EINTR;
@@ -1126,11 +1126,11 @@ static int dvbdmx_connect_frontend(struct dmx_demux *demux,
if (demux->frontend)
return -EINVAL;
- if (down_interruptible(&dvbdemux->mutex))
+ if (mutex_lock_interruptible(&dvbdemux->mutex))
return -ERESTARTSYS;
demux->frontend = frontend;
- up(&dvbdemux->mutex);
+ mutex_unlock(&dvbdemux->mutex);
return 0;
}
@@ -1138,11 +1138,11 @@ static int dvbdmx_disconnect_frontend(struct dmx_demux *demux)
{
struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
- if (down_interruptible(&dvbdemux->mutex))
+ if (mutex_lock_interruptible(&dvbdemux->mutex))
return -ERESTARTSYS;
demux->frontend = NULL;
- up(&dvbdemux->mutex);
+ mutex_unlock(&dvbdemux->mutex);
return 0;
}
@@ -1215,7 +1215,7 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
dmx->disconnect_frontend = dvbdmx_disconnect_frontend;
dmx->get_pes_pids = dvbdmx_get_pes_pids;
- sema_init(&dvbdemux->mutex, 1);
+ mutex_init(&dvbdemux->mutex);
spin_lock_init(&dvbdemux->lock);
return 0;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index 0cc888339d5..2c5f915329c 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -26,7 +26,7 @@
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/spinlock.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
#include "demux.h"
@@ -125,7 +125,7 @@ struct dvb_demux {
u8 tsbuf[204];
int tsbufp;
- struct semaphore mutex;
+ struct mutex mutex;
spinlock_t lock;
};
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 771f32d889e..2c3ea8f95dc 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -37,7 +37,6 @@
#include <linux/suspend.h>
#include <linux/jiffies.h>
#include <asm/processor.h>
-#include <asm/semaphore.h>
#include "dvb_frontend.h"
#include "dvbdev.h"
@@ -50,13 +49,13 @@ static int dvb_powerdown_on_sleep = 1;
module_param_named(frontend_debug, dvb_frontend_debug, int, 0644);
MODULE_PARM_DESC(frontend_debug, "Turn on/off frontend core debugging (default:off).");
-module_param(dvb_shutdown_timeout, int, 0444);
+module_param(dvb_shutdown_timeout, int, 0644);
MODULE_PARM_DESC(dvb_shutdown_timeout, "wait <shutdown_timeout> seconds after close() before suspending hardware");
-module_param(dvb_force_auto_inversion, int, 0444);
+module_param(dvb_force_auto_inversion, int, 0644);
MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AUTO forced always");
-module_param(dvb_override_tune_delay, int, 0444);
+module_param(dvb_override_tune_delay, int, 0644);
MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
-module_param(dvb_powerdown_on_sleep, int, 0444);
+module_param(dvb_powerdown_on_sleep, int, 0644);
MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB volatage off on sleep (default)");
#define dprintk if (dvb_frontend_debug) printk
@@ -88,7 +87,7 @@ MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB vola
* FESTATE_LOSTLOCK. When the lock has been lost, and we're searching it again.
*/
-static DECLARE_MUTEX(frontend_mutex);
+static DEFINE_MUTEX(frontend_mutex);
struct dvb_frontend_private {
@@ -1021,12 +1020,12 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
dprintk ("%s\n", __FUNCTION__);
- if (down_interruptible (&frontend_mutex))
+ if (mutex_lock_interruptible(&frontend_mutex))
return -ERESTARTSYS;
fe->frontend_priv = kzalloc(sizeof(struct dvb_frontend_private), GFP_KERNEL);
if (fe->frontend_priv == NULL) {
- up(&frontend_mutex);
+ mutex_unlock(&frontend_mutex);
return -ENOMEM;
}
fepriv = fe->frontend_priv;
@@ -1045,7 +1044,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
fe, DVB_DEVICE_FRONTEND);
- up (&frontend_mutex);
+ mutex_unlock(&frontend_mutex);
return 0;
}
EXPORT_SYMBOL(dvb_register_frontend);
@@ -1055,7 +1054,7 @@ int dvb_unregister_frontend(struct dvb_frontend* fe)
struct dvb_frontend_private *fepriv = fe->frontend_priv;
dprintk ("%s\n", __FUNCTION__);
- down (&frontend_mutex);
+ mutex_lock(&frontend_mutex);
dvb_unregister_device (fepriv->dvbdev);
dvb_frontend_stop (fe);
if (fe->ops->release)
@@ -1064,7 +1063,7 @@ int dvb_unregister_frontend(struct dvb_frontend* fe)
printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops->info.name);
/* fe is invalid now */
kfree(fepriv);
- up (&frontend_mutex);
+ mutex_unlock(&frontend_mutex);
return 0;
}
EXPORT_SYMBOL(dvb_unregister_frontend);
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index 70a6d14efda..d5aee5ad67a 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -104,6 +104,7 @@ struct dvb_frontend {
struct dvb_adapter *dvb;
void* demodulator_priv;
void* frontend_priv;
+ void* misc_priv;
};
extern int dvb_register_frontend(struct dvb_adapter* dvb,
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 6711eb6a058..2f0f35811bf 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -62,6 +62,7 @@
#include <linux/uio.h>
#include <asm/uaccess.h>
#include <linux/crc32.h>
+#include <linux/mutex.h>
#include "dvb_demux.h"
#include "dvb_net.h"
@@ -151,8 +152,7 @@ struct dvb_net_priv {
unsigned char ule_bridged; /* Whether the ULE_BRIDGED extension header was found. */
int ule_sndu_remain; /* Nr. of bytes still required for current ULE SNDU. */
unsigned long ts_count; /* Current ts cell counter. */
-
- struct semaphore mutex;
+ struct mutex mutex;
};
@@ -889,7 +889,7 @@ static int dvb_net_feed_start(struct net_device *dev)
unsigned char *mac = (unsigned char *) dev->dev_addr;
dprintk("%s: rx_mode %i\n", __FUNCTION__, priv->rx_mode);
- down(&priv->mutex);
+ mutex_lock(&priv->mutex);
if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0])
printk("%s: BUG %d\n", __FUNCTION__, __LINE__);
@@ -974,7 +974,7 @@ static int dvb_net_feed_start(struct net_device *dev)
ret = -EINVAL;
error:
- up(&priv->mutex);
+ mutex_unlock(&priv->mutex);
return ret;
}
@@ -984,7 +984,7 @@ static int dvb_net_feed_stop(struct net_device *dev)
int i, ret = 0;
dprintk("%s\n", __FUNCTION__);
- down(&priv->mutex);
+ mutex_lock(&priv->mutex);
if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) {
if (priv->secfeed) {
if (priv->secfeed->is_filtering) {
@@ -1026,7 +1026,7 @@ static int dvb_net_feed_stop(struct net_device *dev)
printk("%s: no ts feed to stop\n", dev->name);
} else
ret = -EINVAL;
- up(&priv->mutex);
+ mutex_unlock(&priv->mutex);
return ret;
}
@@ -1208,7 +1208,7 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype)
INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list, net);
INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed, net);
- init_MUTEX(&priv->mutex);
+ mutex_init(&priv->mutex);
net->base_addr = pid;
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
index 77ad2410f4d..c972fe014c5 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
@@ -45,6 +45,7 @@ void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len)
rbuf->pread=rbuf->pwrite=0;
rbuf->data=data;
rbuf->size=len;
+ rbuf->error=0;
init_waitqueue_head(&rbuf->queue);
@@ -87,6 +88,7 @@ ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf)
void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf)
{
rbuf->pread = rbuf->pwrite;
+ rbuf->error = 0;
}
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
index 6d256097277..d97714e7573 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
@@ -35,6 +35,7 @@ struct dvb_ringbuffer {
ssize_t size;
ssize_t pread;
ssize_t pwrite;
+ int error;
wait_queue_head_t queue;
spinlock_t lock;
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index 162f9795cd8..e14bf43941e 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -77,7 +77,7 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
struct dvb_usb_device *d = i2c_get_adapdata(adap);
int i;
- if (down_interruptible(&d->i2c_sem) < 0)
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
return -EAGAIN;
if (num > 2)
@@ -126,7 +126,7 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
}
}
- up(&d->i2c_sem);
+ mutex_unlock(&d->i2c_mutex);
return i;
}
diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c
index 269d899da48..2d52b76671d 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-common.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-common.c
@@ -128,7 +128,7 @@ static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num
struct dvb_usb_device *d = i2c_get_adapdata(adap);
int i;
- if (down_interruptible(&d->i2c_sem) < 0)
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
return -EAGAIN;
if (num > 2)
@@ -146,7 +146,7 @@ static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num
break;
}
- up(&d->i2c_sem);
+ mutex_unlock(&d->i2c_mutex);
return i;
}
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index caa1346e306..91136c00ce9 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -48,7 +48,7 @@ static int digitv_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num
struct dvb_usb_device *d = i2c_get_adapdata(adap);
int i;
- if (down_interruptible(&d->i2c_sem) < 0)
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
return -EAGAIN;
if (num > 2)
@@ -67,7 +67,7 @@ static int digitv_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num
break;
}
- up(&d->i2c_sem);
+ mutex_unlock(&d->i2c_mutex);
return i;
}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
index ce34a55e5c2..a1705ecb9a5 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
@@ -42,8 +42,8 @@ static int dvb_usb_init(struct dvb_usb_device *d)
{
int ret = 0;
- sema_init(&d->usb_sem, 1);
- sema_init(&d->i2c_sem, 1);
+ mutex_init(&d->usb_mutex);
+ mutex_init(&d->i2c_mutex);
d->state = DVB_USB_STATE_INIT;
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
index ee821974dc6..9002f35aa95 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
@@ -21,7 +21,7 @@ int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
if (wbuf == NULL || wlen == 0)
return -EINVAL;
- if ((ret = down_interruptible(&d->usb_sem)))
+ if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
return ret;
deb_xfer(">>> ");
@@ -53,7 +53,7 @@ int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
}
}
- up(&d->usb_sem);
+ mutex_unlock(&d->usb_mutex);
return ret;
}
EXPORT_SYMBOL(dvb_usb_generic_rw);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index d4909e5c67e..fead958a57e 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -12,6 +12,7 @@
#include <linux/input.h>
#include <linux/usb.h>
#include <linux/firmware.h>
+#include <linux/mutex.h>
#include "dvb_frontend.h"
#include "dvb_demux.h"
@@ -227,8 +228,8 @@ struct dvb_usb_properties {
* @feedcount: number of reqested feeds (used for streaming-activation)
* @pid_filtering: is hardware pid_filtering used or not.
*
- * @usb_sem: semaphore of USB control messages (reading needs two messages)
- * @i2c_sem: semaphore for i2c-transfers
+ * @usb_mutex: semaphore of USB control messages (reading needs two messages)
+ * @i2c_mutex: semaphore for i2c-transfers
*
* @i2c_adap: device's i2c_adapter if it uses I2CoverUSB
* @pll_addr: I2C address of the tuner for programming
@@ -283,10 +284,10 @@ struct dvb_usb_device {
int pid_filtering;
/* locking */
- struct semaphore usb_sem;
+ struct mutex usb_mutex;
/* i2c */
- struct semaphore i2c_sem;
+ struct mutex i2c_mutex;
struct i2c_adapter i2c_adap;
/* tuner programming information */
diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c
index 4a95eca81c5..b2f098a2d5f 100644
--- a/drivers/media/dvb/dvb-usb/vp702x.c
+++ b/drivers/media/dvb/dvb-usb/vp702x.c
@@ -75,7 +75,7 @@ int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int il
{
int ret;
- if ((ret = down_interruptible(&d->usb_sem)))
+ if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
return ret;
if ((ret = vp702x_usb_out_op(d,REQUEST_OUT,0,0,o,olen)) < 0)
@@ -84,7 +84,7 @@ int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int il
ret = vp702x_usb_in_op(d,REQUEST_IN,0,0,i,ilen);
unlock:
- up(&d->usb_sem);
+ mutex_unlock(&d->usb_mutex);
return ret;
}
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
index 3835235b68d..8ea3834a6cf 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.c
+++ b/drivers/media/dvb/dvb-usb/vp7045.c
@@ -38,7 +38,7 @@ int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in,
deb_xfer("out buffer: ");
debug_dump(outbuf,outlen+1,deb_xfer);
- if ((ret = down_interruptible(&d->usb_sem)))
+ if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
return ret;
if (usb_control_msg(d->udev,
@@ -68,7 +68,7 @@ int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in,
memcpy(in,&inbuf[1],inlen);
unlock:
- up(&d->usb_sem);
+ mutex_unlock(&d->usb_mutex);
return ret;
}
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index c676b1e23ab..94233168d24 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -116,6 +116,12 @@ config DVB_MT352
help
A DVB-T tuner module. Say Y when you want to support this frontend.
+config DVB_ZL10353
+ tristate "Zarlink ZL10353 based"
+ depends on DVB_CORE
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
config DVB_DIB3000MB
tristate "DiBcom 3000M-B"
depends on DVB_CORE
@@ -155,7 +161,7 @@ comment "ATSC (North American/Korean Terresterial DTV) frontends"
depends on DVB_CORE
config DVB_NXT200X
- tristate "Nextwave NXT2002/NXT2004 based"
+ tristate "NxtWave Communications NXT2002/NXT2004 based"
depends on DVB_CORE
select FW_LOADER
help
@@ -169,14 +175,14 @@ config DVB_NXT200X
or /lib/firmware (depending on configuration of firmware hotplug).
config DVB_OR51211
- tristate "or51211 based (pcHDTV HD2000 card)"
+ tristate "Oren OR51211 based"
depends on DVB_CORE
select FW_LOADER
help
An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
config DVB_OR51132
- tristate "OR51132 based (pcHDTV HD3000 card)"
+ tristate "Oren OR51132 based"
depends on DVB_CORE
select FW_LOADER
help
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 1af769cd90c..d09b6071fba 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_DVB_TDA1004X) += tda1004x.o
obj-$(CONFIG_DVB_SP887X) += sp887x.o
obj-$(CONFIG_DVB_NXT6000) += nxt6000.o
obj-$(CONFIG_DVB_MT352) += mt352.o
+obj-$(CONFIG_DVB_ZL10353) += zl10353.o
obj-$(CONFIG_DVB_CX22702) += cx22702.o
obj-$(CONFIG_DVB_TDA10021) += tda10021.o
obj-$(CONFIG_DVB_STV0297) += stv0297.o
diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c
index caaee893ca7..1708a1d4893 100644
--- a/drivers/media/dvb/frontends/bcm3510.c
+++ b/drivers/media/dvb/frontends/bcm3510.c
@@ -39,6 +39,7 @@
#include <linux/jiffies.h>
#include <linux/string.h>
#include <linux/slab.h>
+#include <linux/mutex.h>
#include "dvb_frontend.h"
#include "bcm3510.h"
@@ -52,7 +53,7 @@ struct bcm3510_state {
struct dvb_frontend frontend;
/* demodulator private data */
- struct semaphore hab_sem;
+ struct mutex hab_mutex;
u8 firmware_loaded:1;
unsigned long next_status_check;
@@ -213,7 +214,7 @@ static int bcm3510_do_hab_cmd(struct bcm3510_state *st, u8 cmd, u8 msgid, u8 *ob
dbufout(ob,olen+2,deb_hab);
deb_hab("\n");
- if (down_interruptible(&st->hab_sem) < 0)
+ if (mutex_lock_interruptible(&st->hab_mutex) < 0)
return -EAGAIN;
if ((ret = bcm3510_hab_send_request(st, ob, olen+2)) < 0 ||
@@ -226,7 +227,7 @@ static int bcm3510_do_hab_cmd(struct bcm3510_state *st, u8 cmd, u8 msgid, u8 *ob
memcpy(ibuf,&ib[2],ilen);
error:
- up(&st->hab_sem);
+ mutex_unlock(&st->hab_mutex);
return ret;
}
@@ -796,7 +797,7 @@ struct dvb_frontend* bcm3510_attach(const struct bcm3510_config *config,
state->frontend.ops = &state->ops;
state->frontend.demodulator_priv = state;
- sema_init(&state->hab_sem, 1);
+ mutex_init(&state->hab_mutex);
if ((ret = bcm3510_readB(state,0xe0,&v)) < 0)
goto error;
diff --git a/drivers/media/dvb/frontends/bsbe1.h b/drivers/media/dvb/frontends/bsbe1.h
new file mode 100644
index 00000000000..78573b22ada
--- /dev/null
+++ b/drivers/media/dvb/frontends/bsbe1.h
@@ -0,0 +1,123 @@
+/*
+ * bsbe1.h - ALPS BSBE1 tuner support (moved from av7110.c)
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef BSBE1_H
+#define BSBE1_H
+
+static u8 alps_bsbe1_inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x30,
+ 0x03, 0x00,
+ 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+ 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
+ 0x06, 0x40, /* DAC not used, set to high impendance mode */
+ 0x07, 0x00, /* DAC LSB */
+ 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
+ 0x09, 0x00, /* FIFO */
+ 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+ 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
+ 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
+ 0x10, 0x3f, // AGC2 0x3d
+ 0x11, 0x84,
+ 0x12, 0xb9,
+ 0x15, 0xc9, // lock detector threshold
+ 0x16, 0x00,
+ 0x17, 0x00,
+ 0x18, 0x00,
+ 0x19, 0x00,
+ 0x1a, 0x00,
+ 0x1f, 0x50,
+ 0x20, 0x00,
+ 0x21, 0x00,
+ 0x22, 0x00,
+ 0x23, 0x00,
+ 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
+ 0x29, 0x1e, // 1/2 threshold
+ 0x2a, 0x14, // 2/3 threshold
+ 0x2b, 0x0f, // 3/4 threshold
+ 0x2c, 0x09, // 5/6 threshold
+ 0x2d, 0x05, // 7/8 threshold
+ 0x2e, 0x01,
+ 0x31, 0x1f, // test all FECs
+ 0x32, 0x19, // viterbi and synchro search
+ 0x33, 0xfc, // rs control
+ 0x34, 0x93, // error control
+ 0x0f, 0x92,
+ 0xff, 0xff
+};
+
+
+static int alps_bsbe1_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
+{
+ u8 aclk = 0;
+ u8 bclk = 0;
+
+ if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
+ else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
+ else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
+ else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
+ else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
+ else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
+
+ stv0299_writereg(fe, 0x13, aclk);
+ stv0299_writereg(fe, 0x14, bclk);
+ stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+ stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
+ stv0299_writereg(fe, 0x21, (ratio ) & 0xf0);
+
+ return 0;
+}
+
+static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
+{
+ int ret;
+ u8 data[4];
+ u32 div;
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ if ((params->frequency < 950000) || (params->frequency > 2150000))
+ return -EINVAL;
+
+ div = (params->frequency + (125 - 1)) / 125; // round correctly
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+ data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4;
+
+ ret = i2c_transfer(i2c, &msg, 1);
+ return (ret != 1) ? -EIO : 0;
+}
+
+static struct stv0299_config alps_bsbe1_config = {
+ .demod_address = 0x68,
+ .inittab = alps_bsbe1_inittab,
+ .mclk = 88000000UL,
+ .invert = 1,
+ .skip_reinit = 0,
+ .min_delay_ms = 100,
+ .set_symbol_rate = alps_bsbe1_set_symbol_rate,
+ .pll_set = alps_bsbe1_pll_set,
+};
+
+#endif
diff --git a/drivers/media/dvb/frontends/bsru6.h b/drivers/media/dvb/frontends/bsru6.h
new file mode 100644
index 00000000000..2a5366ce79c
--- /dev/null
+++ b/drivers/media/dvb/frontends/bsru6.h
@@ -0,0 +1,140 @@
+/*
+ * bsru6.h - ALPS BSRU6 tuner support (moved from budget-ci.c)
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef BSRU6_H
+#define BSRU6_H
+
+static u8 alps_bsru6_inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x00,
+ 0x03, 0x00,
+ 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+ 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
+ 0x06, 0x40, /* DAC not used, set to high impendance mode */
+ 0x07, 0x00, /* DAC LSB */
+ 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
+ 0x09, 0x00, /* FIFO */
+ 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+ 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
+ 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
+ 0x10, 0x3f, // AGC2 0x3d
+ 0x11, 0x84,
+ 0x12, 0xb9,
+ 0x15, 0xc9, // lock detector threshold
+ 0x16, 0x00,
+ 0x17, 0x00,
+ 0x18, 0x00,
+ 0x19, 0x00,
+ 0x1a, 0x00,
+ 0x1f, 0x50,
+ 0x20, 0x00,
+ 0x21, 0x00,
+ 0x22, 0x00,
+ 0x23, 0x00,
+ 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
+ 0x29, 0x1e, // 1/2 threshold
+ 0x2a, 0x14, // 2/3 threshold
+ 0x2b, 0x0f, // 3/4 threshold
+ 0x2c, 0x09, // 5/6 threshold
+ 0x2d, 0x05, // 7/8 threshold
+ 0x2e, 0x01,
+ 0x31, 0x1f, // test all FECs
+ 0x32, 0x19, // viterbi and synchro search
+ 0x33, 0xfc, // rs control
+ 0x34, 0x93, // error control
+ 0x0f, 0x52,
+ 0xff, 0xff
+};
+
+static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
+{
+ u8 aclk = 0;
+ u8 bclk = 0;
+
+ if (srate < 1500000) {
+ aclk = 0xb7;
+ bclk = 0x47;
+ } else if (srate < 3000000) {
+ aclk = 0xb7;
+ bclk = 0x4b;
+ } else if (srate < 7000000) {
+ aclk = 0xb7;
+ bclk = 0x4f;
+ } else if (srate < 14000000) {
+ aclk = 0xb7;
+ bclk = 0x53;
+ } else if (srate < 30000000) {
+ aclk = 0xb6;
+ bclk = 0x53;
+ } else if (srate < 45000000) {
+ aclk = 0xb4;
+ bclk = 0x51;
+ }
+
+ stv0299_writereg(fe, 0x13, aclk);
+ stv0299_writereg(fe, 0x14, bclk);
+ stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+ stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
+ stv0299_writereg(fe, 0x21, ratio & 0xf0);
+
+ return 0;
+}
+
+static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params)
+{
+ u8 buf[4];
+ u32 div;
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+
+ if ((params->frequency < 950000) || (params->frequency > 2150000))
+ return -EINVAL;
+
+ div = (params->frequency + (125 - 1)) / 125; // round correctly
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+ buf[3] = 0xC4;
+
+ if (params->frequency > 1530000)
+ buf[3] = 0xc0;
+
+ if (i2c_transfer(i2c, &msg, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
+static struct stv0299_config alps_bsru6_config = {
+ .demod_address = 0x68,
+ .inittab = alps_bsru6_inittab,
+ .mclk = 88000000UL,
+ .invert = 1,
+ .skip_reinit = 0,
+ .lock_output = STV0229_LOCKOUTPUT_1,
+ .volt13_op0_op1 = STV0299_VOLT13_OP1,
+ .min_delay_ms = 100,
+ .set_symbol_rate = alps_bsru6_set_symbol_rate,
+ .pll_set = alps_bsru6_pll_set,
+};
+
+#endif
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
index d15d32c51dc..f3edf8b517d 100644
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb/frontends/cx24110.c
@@ -371,6 +371,15 @@ static int cx24110_initfe(struct dvb_frontend* fe)
return 0;
}
+static int cx24110_sleep(struct dvb_frontend *fe)
+{
+ struct cx24110_state *state = fe->demodulator_priv;
+
+ if (state->config->pll_sleep)
+ return state->config->pll_sleep(fe);
+ return 0;
+}
+
static int cx24110_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
{
struct cx24110_state *state = fe->demodulator_priv;
@@ -418,6 +427,9 @@ static int cx24110_send_diseqc_msg(struct dvb_frontend* fe,
struct cx24110_state *state = fe->demodulator_priv;
unsigned long timeout;
+ if (cmd->msg_len < 3 || cmd->msg_len > 6)
+ return -EINVAL; /* not implemented */
+
for (i = 0; i < cmd->msg_len; i++)
cx24110_writereg(state, 0x79 + i, cmd->msg[i]);
@@ -639,6 +651,7 @@ static struct dvb_frontend_ops cx24110_ops = {
.release = cx24110_release,
.init = cx24110_initfe,
+ .sleep = cx24110_sleep,
.set_frontend = cx24110_set_frontend,
.get_frontend = cx24110_get_frontend,
.read_status = cx24110_read_status,
diff --git a/drivers/media/dvb/frontends/cx24110.h b/drivers/media/dvb/frontends/cx24110.h
index b63ecf26421..609ac642b40 100644
--- a/drivers/media/dvb/frontends/cx24110.h
+++ b/drivers/media/dvb/frontends/cx24110.h
@@ -35,6 +35,7 @@ struct cx24110_config
/* PLL maintenance */
int (*pll_init)(struct dvb_frontend* fe);
int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+ int (*pll_sleep)(struct dvb_frontend* fe);
};
extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index 4dcb6050d4f..b6e2c387a04 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -362,6 +362,63 @@ struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
};
EXPORT_SYMBOL(dvb_pll_philips_sd1878_tda8261);
+/*
+ * Philips TD1316 Tuner.
+ */
+static void td1316_bw(u8 *buf, u32 freq, int bandwidth)
+{
+ u8 band;
+
+ /* determine band */
+ if (freq < 161000000)
+ band = 1;
+ else if (freq < 444000000)
+ band = 2;
+ else
+ band = 4;
+
+ buf[3] |= band;
+
+ /* setup PLL filter */
+ if (bandwidth == BANDWIDTH_8_MHZ)
+ buf[3] |= 1 << 3;
+}
+
+struct dvb_pll_desc dvb_pll_philips_td1316 = {
+ .name = "Philips TD1316",
+ .min = 87000000,
+ .max = 895000000,
+ .setbw = td1316_bw,
+ .count = 9,
+ .entries = {
+ { 93834000, 36166000, 166666, 0xca, 0x60},
+ { 123834000, 36166000, 166666, 0xca, 0xa0},
+ { 163834000, 36166000, 166666, 0xca, 0xc0},
+ { 253834000, 36166000, 166666, 0xca, 0x60},
+ { 383834000, 36166000, 166666, 0xca, 0xa0},
+ { 443834000, 36166000, 166666, 0xca, 0xc0},
+ { 583834000, 36166000, 166666, 0xca, 0x60},
+ { 793834000, 36166000, 166666, 0xca, 0xa0},
+ { 858834000, 36166000, 166666, 0xca, 0xe0},
+ },
+};
+EXPORT_SYMBOL(dvb_pll_philips_td1316);
+
+/* FE6600 used on DViCO Hybrid */
+struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
+ .name = "Thomson FE6600",
+ .min = 44250000,
+ .max = 858000000,
+ .count = 4,
+ .entries = {
+ { 250000000, 36213333, 166667, 0xb4, 0x12 },
+ { 455000000, 36213333, 166667, 0xfe, 0x11 },
+ { 775500000, 36213333, 166667, 0xbc, 0x18 },
+ { 999999999, 36213333, 166667, 0xf4, 0x18 },
+ }
+};
+EXPORT_SYMBOL(dvb_pll_thomson_fe6600);
+
/* ----------------------------------------------------------- */
/* code */
@@ -391,8 +448,8 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
div = (freq + desc->entries[i].offset) / desc->entries[i].stepsize;
buf[0] = div >> 8;
buf[1] = div & 0xff;
- buf[2] = desc->entries[i].cb1;
- buf[3] = desc->entries[i].cb2;
+ buf[2] = desc->entries[i].config;
+ buf[3] = desc->entries[i].cb;
if (desc->setbw)
desc->setbw(buf, freq, bandwidth);
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index bb8d4b4eb18..2b846178498 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -15,8 +15,8 @@ struct dvb_pll_desc {
u32 limit;
u32 offset;
u32 stepsize;
- u8 cb1;
- u8 cb2;
+ u8 config;
+ u8 cb;
} entries[12];
};
@@ -40,6 +40,9 @@ extern struct dvb_pll_desc dvb_pll_tuv1236d;
extern struct dvb_pll_desc dvb_pll_tdhu2;
extern struct dvb_pll_desc dvb_pll_samsung_tbmv;
extern struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261;
+extern struct dvb_pll_desc dvb_pll_philips_td1316;
+
+extern struct dvb_pll_desc dvb_pll_thomson_fe6600;
int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
u32 freq, int bandwidth);
diff --git a/drivers/media/dvb/frontends/lnbp21.h b/drivers/media/dvb/frontends/lnbp21.h
new file mode 100644
index 00000000000..0dcbe61b61b
--- /dev/null
+++ b/drivers/media/dvb/frontends/lnbp21.h
@@ -0,0 +1,139 @@
+/*
+ * lnbp21.h - driver for lnb supply and control ic lnbp21
+ *
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef _LNBP21_H
+#define _LNBP21_H
+
+/* system register */
+#define LNBP21_OLF 0x01
+#define LNBP21_OTF 0x02
+#define LNBP21_EN 0x04
+#define LNBP21_VSEL 0x08
+#define LNBP21_LLC 0x10
+#define LNBP21_TEN 0x20
+#define LNBP21_ISEL 0x40
+#define LNBP21_PCL 0x80
+
+struct lnbp21 {
+ u8 config;
+ u8 override_or;
+ u8 override_and;
+ struct i2c_adapter *i2c;
+ void (*release_chain)(struct dvb_frontend* fe);
+};
+
+static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+ struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+ struct i2c_msg msg = { .addr = 0x08, .flags = 0,
+ .buf = &lnbp21->config,
+ .len = sizeof(lnbp21->config) };
+
+ lnbp21->config &= ~(LNBP21_VSEL | LNBP21_EN);
+
+ switch(voltage) {
+ case SEC_VOLTAGE_OFF:
+ break;
+ case SEC_VOLTAGE_13:
+ lnbp21->config |= LNBP21_EN;
+ break;
+ case SEC_VOLTAGE_18:
+ lnbp21->config |= (LNBP21_EN | LNBP21_VSEL);
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ lnbp21->config |= lnbp21->override_or;
+ lnbp21->config &= lnbp21->override_and;
+
+ return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+ struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+ struct i2c_msg msg = { .addr = 0x08, .flags = 0,
+ .buf = &lnbp21->config,
+ .len = sizeof(lnbp21->config) };
+
+ if (arg)
+ lnbp21->config |= LNBP21_LLC;
+ else
+ lnbp21->config &= ~LNBP21_LLC;
+
+ lnbp21->config |= lnbp21->override_or;
+ lnbp21->config &= lnbp21->override_and;
+
+ return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void lnbp21_exit(struct dvb_frontend *fe)
+{
+ struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+
+ /* LNBP power off */
+ lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+ /* free data & call next release routine */
+ fe->ops->release = lnbp21->release_chain;
+ kfree(fe->misc_priv);
+ fe->misc_priv = NULL;
+ if (fe->ops->release)
+ fe->ops->release(fe);
+}
+
+static int lnbp21_init(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
+{
+ struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);
+
+ if (!lnbp21)
+ return -ENOMEM;
+
+ /* default configuration */
+ lnbp21->config = LNBP21_ISEL;
+
+ /* bits which should be forced to '1' */
+ lnbp21->override_or = override_set;
+
+ /* bits which should be forced to '0' */
+ lnbp21->override_and = ~override_clear;
+
+ /* install release callback */
+ lnbp21->release_chain = fe->ops->release;
+ fe->ops->release = lnbp21_exit;
+
+ /* override frontend ops */
+ fe->ops->set_voltage = lnbp21_set_voltage;
+ fe->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
+
+ lnbp21->i2c = i2c;
+ fe->misc_priv = lnbp21;
+
+ return lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
+}
+
+#endif
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index c63e9a5084e..8e8df7b4ca0 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -229,7 +229,7 @@ static int tda1004x_enable_tuner_i2c(struct tda1004x_state *state)
dprintk("%s\n", __FUNCTION__);
result = tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 2);
- msleep(1);
+ msleep(20);
return result;
}
@@ -502,7 +502,12 @@ static int tda10046_fwupload(struct dvb_frontend* fe)
const struct firmware *fw;
/* reset + wake up chip */
- tda1004x_write_byteI(state, TDA1004X_CONFC4, 0);
+ if (state->config->xtal_freq == TDA10046_XTAL_4M) {
+ tda1004x_write_byteI(state, TDA1004X_CONFC4, 0);
+ } else {
+ dprintk("%s: 16MHz Xtal, reducing I2C speed\n", __FUNCTION__);
+ tda1004x_write_byteI(state, TDA1004X_CONFC4, 0x80);
+ }
tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0);
/* let the clocks recover from sleep */
msleep(5);
@@ -651,7 +656,7 @@ static int tda10046_init(struct dvb_frontend* fe)
// tda setup
tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87); // 100 ppm crystal, select HP stream
- tda1004x_write_byteI(state, TDA1004X_CONFC1, 8); // disable pulse killer
+ tda1004x_write_byteI(state, TDA1004X_CONFC1, 0x88); // enable pulse killer
switch (state->config->agc_config) {
case TDA10046_AGC_DEFAULT:
@@ -672,6 +677,12 @@ static int tda10046_init(struct dvb_frontend* fe)
tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x6a); // set AGC polarities
break;
+ case TDA10046_AGC_TDA827X_GPL:
+ tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup
+ tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold
+ tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
+ tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities
+ break;
}
tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38);
tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on
@@ -683,6 +694,7 @@ static int tda10046_init(struct dvb_frontend* fe)
tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits
tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config
tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config
+ // tda1004x_write_mask(state, 0x50, 0x80, 0x80); // handle out of guard echoes
tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7);
state->initialised = 1;
@@ -1027,6 +1039,7 @@ static int tda1004x_read_status(struct dvb_frontend* fe, fe_status_t * fe_status
if (status == -1)
return -EIO;
cber |= (status << 8);
+ // The address 0x20 should be read to cope with a TDA10046 bug
tda1004x_read_byte(state, TDA1004X_CBER_RESET);
if (cber != 65535)
@@ -1047,7 +1060,8 @@ static int tda1004x_read_status(struct dvb_frontend* fe, fe_status_t * fe_status
status = tda1004x_read_byte(state, TDA1004X_VBER_MSB);
if (status == -1)
return -EIO;
- vber |= ((status << 16) & 0x0f);
+ vber |= (status & 0x0f) << 16;
+ // The CVBER_LUT should be read to cope with TDA10046 hardware bug
tda1004x_read_byte(state, TDA1004X_CVBER_LUT);
// if RS has passed some valid TS packets, then we must be
@@ -1161,6 +1175,7 @@ static int tda1004x_read_ber(struct dvb_frontend* fe, u32* ber)
if (tmp < 0)
return -EIO;
*ber |= (tmp << 9);
+ // The address 0x20 should be read to cope with a TDA10046 bug
tda1004x_read_byte(state, TDA1004X_CBER_RESET);
dprintk("%s: ber=0x%x\n", __FUNCTION__, *ber);
@@ -1187,6 +1202,8 @@ static int tda1004x_sleep(struct dvb_frontend* fe)
tda1004x_disable_tuner_i2c(state);
}
}
+ /* set outputs to tristate */
+ tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xff);
tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
break;
}
diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h
index 8659c52647a..cc0c4af6406 100644
--- a/drivers/media/dvb/frontends/tda1004x.h
+++ b/drivers/media/dvb/frontends/tda1004x.h
@@ -35,7 +35,8 @@ enum tda10046_agc {
TDA10046_AGC_DEFAULT, /* original configuration */
TDA10046_AGC_IFO_AUTO_NEG, /* IF AGC only, automatic, negtive */
TDA10046_AGC_IFO_AUTO_POS, /* IF AGC only, automatic, positive */
- TDA10046_AGC_TDA827X, /* IF AGC only, special setup for tda827x */
+ TDA10046_AGC_TDA827X, /* IF AGC only, special setup for tda827x */
+ TDA10046_AGC_TDA827X_GPL, /* same as above, but GPIOs 0 */
};
enum tda10046_if {
diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
new file mode 100644
index 00000000000..d7d9f59d76d
--- /dev/null
+++ b/drivers/media/dvb/frontends/zl10353.c
@@ -0,0 +1,311 @@
+/*
+ * Driver for Zarlink DVB-T ZL10353 demodulator
+ *
+ * Copyright (C) 2006 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "zl10353_priv.h"
+#include "zl10353.h"
+
+struct zl10353_state {
+ struct i2c_adapter *i2c;
+ struct dvb_frontend frontend;
+ struct dvb_frontend_ops ops;
+
+ struct zl10353_config config;
+};
+
+static int debug_regs = 0;
+
+static int zl10353_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
+{
+ struct zl10353_state *state = fe->demodulator_priv;
+ u8 buf[2] = { reg, val };
+ struct i2c_msg msg = { .addr = state->config.demod_address, .flags = 0,
+ .buf = buf, .len = 2 };
+ int err = i2c_transfer(state->i2c, &msg, 1);
+ if (err != 1) {
+ printk("zl10353: write to reg %x failed (err = %d)!\n", reg, err);
+ return err;
+ }
+ return 0;
+}
+
+int zl10353_write(struct dvb_frontend *fe, u8 *ibuf, int ilen)
+{
+ int err, i;
+ for (i = 0; i < ilen - 1; i++)
+ if ((err = zl10353_single_write(fe, ibuf[0] + i, ibuf[i + 1])))
+ return err;
+
+ return 0;
+}
+
+static int zl10353_read_register(struct zl10353_state *state, u8 reg)
+{
+ int ret;
+ u8 b0[1] = { reg };
+ u8 b1[1] = { 0 };
+ struct i2c_msg msg[2] = { { .addr = state->config.demod_address,
+ .flags = 0,
+ .buf = b0, .len = 1 },
+ { .addr = state->config.demod_address,
+ .flags = I2C_M_RD,
+ .buf = b1, .len = 1 } };
+
+ ret = i2c_transfer(state->i2c, msg, 2);
+
+ if (ret != 2) {
+ printk("%s: readreg error (reg=%d, ret==%i)\n",
+ __FUNCTION__, reg, ret);
+ return ret;
+ }
+
+ return b1[0];
+}
+
+static void zl10353_dump_regs(struct dvb_frontend *fe)
+{
+ struct zl10353_state *state = fe->demodulator_priv;
+ char buf[52], buf2[4];
+ int ret;
+ u8 reg;
+
+ /* Dump all registers. */
+ for (reg = 0; ; reg++) {
+ if (reg % 16 == 0) {
+ if (reg)
+ printk(KERN_DEBUG "%s\n", buf);
+ sprintf(buf, "%02x: ", reg);
+ }
+ ret = zl10353_read_register(state, reg);
+ if (ret >= 0)
+ sprintf(buf2, "%02x ", (u8)ret);
+ else
+ strcpy(buf2, "-- ");
+ strcat(buf, buf2);
+ if (reg == 0xff)
+ break;
+ }
+ printk(KERN_DEBUG "%s\n", buf);
+}
+
+static int zl10353_sleep(struct dvb_frontend *fe)
+{
+ static u8 zl10353_softdown[] = { 0x50, 0x0C, 0x44 };
+
+ zl10353_write(fe, zl10353_softdown, sizeof(zl10353_softdown));
+ return 0;
+}
+
+static int zl10353_set_parameters(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *param)
+{
+ struct zl10353_state *state = fe->demodulator_priv;
+ u8 pllbuf[6] = { 0x67 };
+
+ /* These settings set "auto-everything" and start the FSM. */
+ zl10353_single_write(fe, 0x55, 0x80);
+ udelay(200);
+ zl10353_single_write(fe, 0xEA, 0x01);
+ udelay(200);
+ zl10353_single_write(fe, 0xEA, 0x00);
+
+ zl10353_single_write(fe, 0x56, 0x28);
+ zl10353_single_write(fe, 0x89, 0x20);
+ zl10353_single_write(fe, 0x5E, 0x00);
+ zl10353_single_write(fe, 0x65, 0x5A);
+ zl10353_single_write(fe, 0x66, 0xE9);
+ zl10353_single_write(fe, 0x62, 0x0A);
+
+ state->config.pll_set(fe, param, pllbuf + 1);
+ zl10353_write(fe, pllbuf, sizeof(pllbuf));
+
+ zl10353_single_write(fe, 0x70, 0x01);
+ udelay(250);
+ zl10353_single_write(fe, 0xE4, 0x00);
+ zl10353_single_write(fe, 0xE5, 0x2A);
+ zl10353_single_write(fe, 0xE9, 0x02);
+ zl10353_single_write(fe, 0xE7, 0x40);
+ zl10353_single_write(fe, 0xE8, 0x10);
+
+ return 0;
+}
+
+static int zl10353_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct zl10353_state *state = fe->demodulator_priv;
+ int s6, s7, s8;
+
+ if ((s6 = zl10353_read_register(state, STATUS_6)) < 0)
+ return -EREMOTEIO;
+ if ((s7 = zl10353_read_register(state, STATUS_7)) < 0)
+ return -EREMOTEIO;
+ if ((s8 = zl10353_read_register(state, STATUS_8)) < 0)
+ return -EREMOTEIO;
+
+ *status = 0;
+ if (s6 & (1 << 2))
+ *status |= FE_HAS_CARRIER;
+ if (s6 & (1 << 1))
+ *status |= FE_HAS_VITERBI;
+ if (s6 & (1 << 5))
+ *status |= FE_HAS_LOCK;
+ if (s7 & (1 << 4))
+ *status |= FE_HAS_SYNC;
+ if (s8 & (1 << 6))
+ *status |= FE_HAS_SIGNAL;
+
+ if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=
+ (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))
+ *status &= ~FE_HAS_LOCK;
+
+ return 0;
+}
+
+static int zl10353_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ struct zl10353_state *state = fe->demodulator_priv;
+ u8 _snr;
+
+ if (debug_regs)
+ zl10353_dump_regs(fe);
+
+ _snr = zl10353_read_register(state, SNR);
+ *snr = (_snr << 8) | _snr;
+
+ return 0;
+}
+
+static int zl10353_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings
+ *fe_tune_settings)
+{
+ fe_tune_settings->min_delay_ms = 1000;
+ fe_tune_settings->step_size = 0;
+ fe_tune_settings->max_drift = 0;
+
+ return 0;
+}
+
+static int zl10353_init(struct dvb_frontend *fe)
+{
+ struct zl10353_state *state = fe->demodulator_priv;
+ u8 zl10353_reset_attach[6] = { 0x50, 0x03, 0x64, 0x46, 0x15, 0x0F };
+ int rc = 0;
+
+ if (debug_regs)
+ zl10353_dump_regs(fe);
+
+ /* Do a "hard" reset if not already done */
+ if (zl10353_read_register(state, 0x50) != 0x03) {
+ rc = zl10353_write(fe, zl10353_reset_attach,
+ sizeof(zl10353_reset_attach));
+ if (debug_regs)
+ zl10353_dump_regs(fe);
+ }
+
+ return 0;
+}
+
+static void zl10353_release(struct dvb_frontend *fe)
+{
+ struct zl10353_state *state = fe->demodulator_priv;
+
+ kfree(state);
+}
+
+static struct dvb_frontend_ops zl10353_ops;
+
+struct dvb_frontend *zl10353_attach(const struct zl10353_config *config,
+ struct i2c_adapter *i2c)
+{
+ struct zl10353_state *state = NULL;
+
+ /* allocate memory for the internal state */
+ state = kzalloc(sizeof(struct zl10353_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ /* setup the state */
+ state->i2c = i2c;
+ memcpy(&state->config, config, sizeof(struct zl10353_config));
+ memcpy(&state->ops, &zl10353_ops, sizeof(struct dvb_frontend_ops));
+
+ /* check if the demod is there */
+ if (zl10353_read_register(state, CHIP_ID) != ID_ZL10353)
+ goto error;
+
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+
+ return &state->frontend;
+error:
+ kfree(state);
+ return NULL;
+}
+
+static struct dvb_frontend_ops zl10353_ops = {
+
+ .info = {
+ .name = "Zarlink ZL10353 DVB-T",
+ .type = FE_OFDM,
+ .frequency_min = 174000000,
+ .frequency_max = 862000000,
+ .frequency_stepsize = 166667,
+ .frequency_tolerance = 0,
+ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+ FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+ FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER |
+ FE_CAN_MUTE_TS
+ },
+
+ .release = zl10353_release,
+
+ .init = zl10353_init,
+ .sleep = zl10353_sleep,
+
+ .set_frontend = zl10353_set_parameters,
+ .get_tune_settings = zl10353_get_tune_settings,
+
+ .read_status = zl10353_read_status,
+ .read_snr = zl10353_read_snr,
+};
+
+module_param(debug_regs, int, 0644);
+MODULE_PARM_DESC(debug_regs, "Turn on/off frontend register dumps (default:off).");
+
+MODULE_DESCRIPTION("Zarlink ZL10353 DVB-T demodulator driver");
+MODULE_AUTHOR("Chris Pascoe");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(zl10353_attach);
+EXPORT_SYMBOL(zl10353_write);
diff --git a/drivers/media/dvb/frontends/zl10353.h b/drivers/media/dvb/frontends/zl10353.h
new file mode 100644
index 00000000000..5cc4ae718d8
--- /dev/null
+++ b/drivers/media/dvb/frontends/zl10353.h
@@ -0,0 +1,43 @@
+/*
+ * Driver for Zarlink DVB-T ZL10353 demodulator
+ *
+ * Copyright (C) 2006 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef ZL10353_H
+#define ZL10353_H
+
+#include <linux/dvb/frontend.h>
+
+struct zl10353_config
+{
+ /* demodulator's I2C address */
+ u8 demod_address;
+
+ /* function which configures the PLL buffer (for secondary I2C
+ * connected tuner) or tunes the PLL (for direct connected tuner) */
+ int (*pll_set)(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params, u8 *pllbuf);
+};
+
+extern struct dvb_frontend* zl10353_attach(const struct zl10353_config *config,
+ struct i2c_adapter *i2c);
+
+extern int zl10353_write(struct dvb_frontend *fe, u8 *ibuf, int ilen);
+
+#endif /* ZL10353_H */
diff --git a/drivers/media/dvb/frontends/zl10353_priv.h b/drivers/media/dvb/frontends/zl10353_priv.h
new file mode 100644
index 00000000000..b72224bd7dd
--- /dev/null
+++ b/drivers/media/dvb/frontends/zl10353_priv.h
@@ -0,0 +1,42 @@
+/*
+ * Driver for Zarlink DVB-T ZL10353 demodulator
+ *
+ * Copyright (C) 2006 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef _ZL10353_PRIV_
+#define _ZL10353_PRIV_
+
+#define ID_ZL10353 0x14
+
+enum zl10353_reg_addr {
+ INTERRUPT_0 = 0x00,
+ INTERRUPT_1 = 0x01,
+ INTERRUPT_2 = 0x02,
+ INTERRUPT_3 = 0x03,
+ INTERRUPT_4 = 0x04,
+ INTERRUPT_5 = 0x05,
+ STATUS_6 = 0x06,
+ STATUS_7 = 0x07,
+ STATUS_8 = 0x08,
+ STATUS_9 = 0x09,
+ SNR = 0x10,
+ CHIP_ID = 0x7F,
+};
+
+#endif /* _ZL10353_PRIV_ */
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 7c6ccb96b15..840efec32cb 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -54,7 +54,6 @@
#include <linux/i2c.h>
#include <asm/system.h>
-#include <asm/semaphore.h>
#include <linux/dvb/frontend.h>
@@ -67,6 +66,10 @@
#include "av7110_ca.h"
#include "av7110_ipack.h"
+#include "bsbe1.h"
+#include "lnbp21.h"
+#include "bsru6.h"
+
#define TS_WIDTH 376
#define TS_HEIGHT 512
#define TS_BUFLEN (TS_WIDTH*TS_HEIGHT)
@@ -82,6 +85,8 @@ static int hw_sections;
static int rgb_on;
static int volume = 255;
static int budgetpatch;
+static int wss_cfg_4_3 = 0x4008;
+static int wss_cfg_16_9 = 0x0007;
module_param_named(debug, av7110_debug, int, 0644);
MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)");
@@ -100,6 +105,10 @@ module_param(volume, int, 0444);
MODULE_PARM_DESC(volume, "initial volume: default 255 (range 0-255)");
module_param(budgetpatch, int, 0444);
MODULE_PARM_DESC(budgetpatch, "use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always)");
+module_param(wss_cfg_4_3, int, 0444);
+MODULE_PARM_DESC(wss_cfg_4_3, "WSS 4:3 - default 0x4008 - bit 15: disable, 14: burst mode, 13..0: wss data");
+module_param(wss_cfg_16_9, int, 0444);
+MODULE_PARM_DESC(wss_cfg_16_9, "WSS 16:9 - default 0x0007 - bit 15: disable, 14: burst mode, 13..0: wss data");
static void restart_feeds(struct av7110 *av7110);
@@ -125,6 +134,13 @@ static void init_av7110_av(struct av7110 *av7110)
if (ret < 0)
printk("dvb-ttpci:cannot set internal volume to maximum:%d\n",ret);
+ ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 2, wss_cfg_4_3);
+ if (ret < 0)
+ printk("dvb-ttpci: unable to configure 4:3 wss\n");
+ ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 3, wss_cfg_16_9);
+ if (ret < 0)
+ printk("dvb-ttpci: unable to configure 16:9 wss\n");
+
ret = av7710_set_video_mode(av7110, vidmode);
if (ret < 0)
printk("dvb-ttpci:cannot set video mode:%d\n",ret);
@@ -242,10 +258,10 @@ static int arm_thread(void *data)
if (!av7110->arm_ready)
continue;
- if (down_interruptible(&av7110->dcomlock))
+ if (mutex_lock_interruptible(&av7110->dcomlock))
break;
newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2);
- up(&av7110->dcomlock);
+ mutex_unlock(&av7110->dcomlock);
if (newloops == av7110->arm_loops || av7110->arm_errors > 3) {
printk(KERN_ERR "dvb-ttpci: ARM crashed @ card %d\n",
@@ -253,10 +269,10 @@ static int arm_thread(void *data)
recover_arm(av7110);
- if (down_interruptible(&av7110->dcomlock))
+ if (mutex_lock_interruptible(&av7110->dcomlock))
break;
newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2) - 1;
- up(&av7110->dcomlock);
+ mutex_unlock(&av7110->dcomlock);
}
av7110->arm_loops = newloops;
av7110->arm_errors = 0;
@@ -741,7 +757,7 @@ int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
int ret = 0;
dprintk(4, "%p\n", av7110);
- if (down_interruptible(&av7110->pid_mutex))
+ if (mutex_lock_interruptible(&av7110->pid_mutex))
return -ERESTARTSYS;
if (!(vpid & 0x8000))
@@ -760,7 +776,7 @@ int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
ret = SetPIDs(av7110, vpid, apid, ttpid, subpid, pcrpid);
}
- up(&av7110->pid_mutex);
+ mutex_unlock(&av7110->pid_mutex);
return ret;
}
@@ -1088,11 +1104,9 @@ static int dvb_get_stc(struct dmx_demux *demux, unsigned int num,
struct av7110 *av7110;
/* pointer casting paranoia... */
- if (!demux)
- BUG();
+ BUG_ON(!demux);
dvbdemux = (struct dvb_demux *) demux->priv;
- if (!dvbdemux)
- BUG();
+ BUG_ON(!dvbdemux);
av7110 = (struct av7110 *) dvbdemux->priv;
dprintk(4, "%p\n", av7110);
@@ -1570,208 +1584,6 @@ static struct ves1x93_config alps_bsrv2_config = {
.pll_set = alps_bsrv2_pll_set,
};
-
-static u8 alps_bsru6_inittab[] = {
- 0x01, 0x15,
- 0x02, 0x30,
- 0x03, 0x00,
- 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
- 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
- 0x06, 0x40, /* DAC not used, set to high impendance mode */
- 0x07, 0x00, /* DAC LSB */
- 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
- 0x09, 0x00, /* FIFO */
- 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
- 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
- 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
- 0x10, 0x3f, // AGC2 0x3d
- 0x11, 0x84,
- 0x12, 0xb9,
- 0x15, 0xc9, // lock detector threshold
- 0x16, 0x00,
- 0x17, 0x00,
- 0x18, 0x00,
- 0x19, 0x00,
- 0x1a, 0x00,
- 0x1f, 0x50,
- 0x20, 0x00,
- 0x21, 0x00,
- 0x22, 0x00,
- 0x23, 0x00,
- 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
- 0x29, 0x1e, // 1/2 threshold
- 0x2a, 0x14, // 2/3 threshold
- 0x2b, 0x0f, // 3/4 threshold
- 0x2c, 0x09, // 5/6 threshold
- 0x2d, 0x05, // 7/8 threshold
- 0x2e, 0x01,
- 0x31, 0x1f, // test all FECs
- 0x32, 0x19, // viterbi and synchro search
- 0x33, 0xfc, // rs control
- 0x34, 0x93, // error control
- 0x0f, 0x52,
- 0xff, 0xff
-};
-
-static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
-{
- u8 aclk = 0;
- u8 bclk = 0;
-
- if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
- else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
- else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
- else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
- else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
- else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
-
- stv0299_writereg(fe, 0x13, aclk);
- stv0299_writereg(fe, 0x14, bclk);
- stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
- stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
- stv0299_writereg(fe, 0x21, (ratio ) & 0xf0);
-
- return 0;
-}
-
-static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
-{
- int ret;
- u8 data[4];
- u32 div;
- struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
-
- if ((params->frequency < 950000) || (params->frequency > 2150000))
- return -EINVAL;
-
- div = (params->frequency + (125 - 1)) / 125; // round correctly
- data[0] = (div >> 8) & 0x7f;
- data[1] = div & 0xff;
- data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
- data[3] = 0xC4;
-
- if (params->frequency > 1530000) data[3] = 0xc0;
-
- ret = i2c_transfer(i2c, &msg, 1);
- if (ret != 1)
- return -EIO;
- return 0;
-}
-
-static struct stv0299_config alps_bsru6_config = {
-
- .demod_address = 0x68,
- .inittab = alps_bsru6_inittab,
- .mclk = 88000000UL,
- .invert = 1,
- .skip_reinit = 0,
- .lock_output = STV0229_LOCKOUTPUT_1,
- .volt13_op0_op1 = STV0299_VOLT13_OP1,
- .min_delay_ms = 100,
- .set_symbol_rate = alps_bsru6_set_symbol_rate,
- .pll_set = alps_bsru6_pll_set,
-};
-
-
-static u8 alps_bsbe1_inittab[] = {
- 0x01, 0x15,
- 0x02, 0x30,
- 0x03, 0x00,
- 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
- 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
- 0x06, 0x40, /* DAC not used, set to high impendance mode */
- 0x07, 0x00, /* DAC LSB */
- 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
- 0x09, 0x00, /* FIFO */
- 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
- 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
- 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
- 0x10, 0x3f, // AGC2 0x3d
- 0x11, 0x84,
- 0x12, 0xb9,
- 0x15, 0xc9, // lock detector threshold
- 0x16, 0x00,
- 0x17, 0x00,
- 0x18, 0x00,
- 0x19, 0x00,
- 0x1a, 0x00,
- 0x1f, 0x50,
- 0x20, 0x00,
- 0x21, 0x00,
- 0x22, 0x00,
- 0x23, 0x00,
- 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
- 0x29, 0x1e, // 1/2 threshold
- 0x2a, 0x14, // 2/3 threshold
- 0x2b, 0x0f, // 3/4 threshold
- 0x2c, 0x09, // 5/6 threshold
- 0x2d, 0x05, // 7/8 threshold
- 0x2e, 0x01,
- 0x31, 0x1f, // test all FECs
- 0x32, 0x19, // viterbi and synchro search
- 0x33, 0xfc, // rs control
- 0x34, 0x93, // error control
- 0x0f, 0x92,
- 0xff, 0xff
-};
-
-static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
-{
- int ret;
- u8 data[4];
- u32 div;
- struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
-
- if ((params->frequency < 950000) || (params->frequency > 2150000))
- return -EINVAL;
-
- div = (params->frequency + (125 - 1)) / 125; // round correctly
- data[0] = (div >> 8) & 0x7f;
- data[1] = div & 0xff;
- data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
- data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4;
-
- ret = i2c_transfer(i2c, &msg, 1);
- return (ret != 1) ? -EIO : 0;
-}
-
-static struct stv0299_config alps_bsbe1_config = {
- .demod_address = 0x68,
- .inittab = alps_bsbe1_inittab,
- .mclk = 88000000UL,
- .invert = 1,
- .skip_reinit = 0,
- .min_delay_ms = 100,
- .set_symbol_rate = alps_bsru6_set_symbol_rate,
- .pll_set = alps_bsbe1_pll_set,
-};
-
-static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
-{
- struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
- int ret;
- u8 data[1];
- struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = data, .len = sizeof(data) };
-
- switch(voltage) {
- case SEC_VOLTAGE_OFF:
- data[0] = 0x00;
- break;
- case SEC_VOLTAGE_13:
- data[0] = 0x44;
- break;
- case SEC_VOLTAGE_18:
- data[0] = 0x4c;
- break;
- default:
- return -EINVAL;
- };
-
- ret = i2c_transfer(&av7110->i2c_adap, &msg, 1);
- return (ret != 1) ? -EIO : 0;
-}
-
-
static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct av7110* av7110 = fe->dvb->priv;
@@ -2096,7 +1908,7 @@ static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status)
if (av7110->playing)
return 0;
- if (down_interruptible(&av7110->pid_mutex))
+ if (mutex_lock_interruptible(&av7110->pid_mutex))
return -ERESTARTSYS;
if (synced) {
@@ -2118,7 +1930,7 @@ static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status)
if (!ret)
av7110->fe_synced = synced;
- up(&av7110->pid_mutex);
+ mutex_unlock(&av7110->pid_mutex);
return ret;
}
@@ -2374,9 +2186,15 @@ static int frontend_init(struct av7110 *av7110)
/* ALPS BSBE1 */
av7110->fe = stv0299_attach(&alps_bsbe1_config, &av7110->i2c_adap);
if (av7110->fe) {
- av7110->fe->ops->set_voltage = lnbp21_set_voltage;
- av7110->fe->ops->dishnetwork_send_legacy_command = NULL;
- av7110->recover = dvb_s_recover;
+ if (lnbp21_init(av7110->fe, &av7110->i2c_adap, 0, 0)) {
+ printk("dvb-ttpci: LNBP21 not found!\n");
+ if (av7110->fe->ops->release)
+ av7110->fe->ops->release(av7110->fe);
+ av7110->fe = NULL;
+ } else {
+ av7110->fe->ops->dishnetwork_send_legacy_command = NULL;
+ av7110->recover = dvb_s_recover;
+ }
}
break;
}
@@ -2714,16 +2532,16 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
tasklet_init (&av7110->debi_tasklet, debiirq, (unsigned long) av7110);
tasklet_init (&av7110->gpio_tasklet, gpioirq, (unsigned long) av7110);
- sema_init(&av7110->pid_mutex, 1);
+ mutex_init(&av7110->pid_mutex);
/* locks for data transfers from/to AV7110 */
spin_lock_init(&av7110->debilock);
- sema_init(&av7110->dcomlock, 1);
+ mutex_init(&av7110->dcomlock);
av7110->debitype = -1;
/* default OSD window */
av7110->osdwin = 1;
- sema_init(&av7110->osd_sema, 1);
+ mutex_init(&av7110->osd_mutex);
/* ARM "watchdog" */
init_waitqueue_head(&av7110->arm_wait);
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
index fafd25fab83..3e2e12124ba 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -16,6 +16,7 @@
#include <linux/dvb/ca.h>
#include <linux/dvb/osd.h>
#include <linux/dvb/net.h>
+#include <linux/mutex.h>
#include "dvbdev.h"
#include "demux.h"
@@ -127,7 +128,7 @@ struct av7110 {
/* DEBI and polled command interface */
spinlock_t debilock;
- struct semaphore dcomlock;
+ struct mutex dcomlock;
volatile int debitype;
volatile int debilen;
@@ -146,7 +147,7 @@ struct av7110 {
int osdwin; /* currently active window */
u16 osdbpp[8];
- struct semaphore osd_sema;
+ struct mutex osd_mutex;
/* CA */
@@ -172,7 +173,7 @@ struct av7110 {
struct tasklet_struct vpe_tasklet;
int fe_synced;
- struct semaphore pid_mutex;
+ struct mutex pid_mutex;
int video_blank;
struct video_status videostate;
diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c
index 0bb6e74ae7f..75736f2fe83 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/drivers/media/dvb/ttpci/av7110_hw.c
@@ -327,10 +327,10 @@ int av7110_wait_msgstate(struct av7110 *av7110, u16 flags)
start = jiffies;
for (;;) {
err = time_after(jiffies, start + ARM_WAIT_FREE);
- if (down_interruptible(&av7110->dcomlock))
+ if (mutex_lock_interruptible(&av7110->dcomlock))
return -ERESTARTSYS;
stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
- up(&av7110->dcomlock);
+ mutex_unlock(&av7110->dcomlock);
if ((stat & flags) == 0)
break;
if (err) {
@@ -487,11 +487,11 @@ static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
dprintk(1, "arm not ready.\n");
return -1;
}
- if (down_interruptible(&av7110->dcomlock))
+ if (mutex_lock_interruptible(&av7110->dcomlock))
return -ERESTARTSYS;
ret = __av7110_send_fw_cmd(av7110, buf, length);
- up(&av7110->dcomlock);
+ mutex_unlock(&av7110->dcomlock);
if (ret && ret!=-ERESTARTSYS)
printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
__FUNCTION__, ret);
@@ -563,11 +563,11 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
return -1;
}
- if (down_interruptible(&av7110->dcomlock))
+ if (mutex_lock_interruptible(&av7110->dcomlock))
return -ERESTARTSYS;
if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) {
- up(&av7110->dcomlock);
+ mutex_unlock(&av7110->dcomlock);
printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err);
return err;
}
@@ -579,7 +579,7 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
break;
if (err) {
printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __FUNCTION__);
- up(&av7110->dcomlock);
+ mutex_unlock(&av7110->dcomlock);
return -ETIMEDOUT;
}
#ifdef _NOHANDSHAKE
@@ -595,7 +595,7 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
break;
if (err) {
printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
- up(&av7110->dcomlock);
+ mutex_unlock(&av7110->dcomlock);
return -ETIMEDOUT;
}
msleep(1);
@@ -606,12 +606,12 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
if (stat & GPMQOver) {
printk(KERN_ERR "%s: GPMQOver\n", __FUNCTION__);
- up(&av7110->dcomlock);
+ mutex_unlock(&av7110->dcomlock);
return -1;
}
else if (stat & OSDQOver) {
printk(KERN_ERR "%s: OSDQOver\n", __FUNCTION__);
- up(&av7110->dcomlock);
+ mutex_unlock(&av7110->dcomlock);
return -1;
}
#endif
@@ -619,7 +619,7 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
for (i = 0; i < reply_buf_len; i++)
reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2);
- up(&av7110->dcomlock);
+ mutex_unlock(&av7110->dcomlock);
return 0;
}
@@ -735,7 +735,7 @@ static int FlushText(struct av7110 *av7110)
unsigned long start;
int err;
- if (down_interruptible(&av7110->dcomlock))
+ if (mutex_lock_interruptible(&av7110->dcomlock))
return -ERESTARTSYS;
start = jiffies;
while (1) {
@@ -745,12 +745,12 @@ static int FlushText(struct av7110 *av7110)
if (err) {
printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n",
__FUNCTION__);
- up(&av7110->dcomlock);
+ mutex_unlock(&av7110->dcomlock);
return -ETIMEDOUT;
}
msleep(1);
}
- up(&av7110->dcomlock);
+ mutex_unlock(&av7110->dcomlock);
return 0;
}
@@ -761,7 +761,7 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
int length = strlen(buf) + 1;
u16 cbuf[5] = { (COMTYPE_OSD << 8) + DText, 3, win, x, y };
- if (down_interruptible(&av7110->dcomlock))
+ if (mutex_lock_interruptible(&av7110->dcomlock))
return -ERESTARTSYS;
start = jiffies;
@@ -772,7 +772,7 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
if (ret) {
printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n",
__FUNCTION__);
- up(&av7110->dcomlock);
+ mutex_unlock(&av7110->dcomlock);
return -ETIMEDOUT;
}
msleep(1);
@@ -786,7 +786,7 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
if (ret) {
printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n",
__FUNCTION__);
- up(&av7110->dcomlock);
+ mutex_unlock(&av7110->dcomlock);
return -ETIMEDOUT;
}
msleep(1);
@@ -798,7 +798,7 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
if (length & 1)
wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2);
ret = __av7110_send_fw_cmd(av7110, cbuf, 5);
- up(&av7110->dcomlock);
+ mutex_unlock(&av7110->dcomlock);
if (ret && ret!=-ERESTARTSYS)
printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret);
return ret;
@@ -1062,7 +1062,7 @@ int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
{
int ret;
- if (down_interruptible(&av7110->osd_sema))
+ if (mutex_lock_interruptible(&av7110->osd_mutex))
return -ERESTARTSYS;
switch (dc->cmd) {
@@ -1198,7 +1198,7 @@ int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
break;
}
- up(&av7110->osd_sema);
+ mutex_unlock(&av7110->osd_mutex);
if (ret==-ERESTARTSYS)
dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd);
else if (ret)
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index 94cf38c7e8a..2f23ceab8d4 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -579,14 +579,11 @@ static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size
return -EFAULT;
if ((d.id != 0 && d.id != V4L2_SLICED_WSS_625) || d.field != 0 || d.line != 23)
return -EINVAL;
- if (d.id) {
+ if (d.id)
av7110->wssData = ((d.data[1] << 8) & 0x3f00) | d.data[0];
- rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig,
- 2, 1, av7110->wssData);
- } else {
- av7110->wssData = 0;
- rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0);
- }
+ else
+ av7110->wssData = 0x8000;
+ rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 1, av7110->wssData);
return (rc < 0) ? rc : count;
}
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 1465c04e49a..9dd4745f531 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -1000,6 +1000,7 @@ static u8 read_pwm(struct budget_av *budget_av)
#define SUBID_DVBS_TV_STAR 0x0014
#define SUBID_DVBS_TV_STAR_CI 0x0016
+#define SUBID_DVBS_EASYWATCH 0x001e
#define SUBID_DVBC_KNC1 0x0020
#define SUBID_DVBC_KNC1_PLUS 0x0021
#define SUBID_DVBC_CINERGY1200 0x1156
@@ -1038,6 +1039,7 @@ static void frontend_init(struct budget_av *budget_av)
case SUBID_DVBS_TV_STAR:
case SUBID_DVBS_TV_STAR_CI:
case SUBID_DVBS_CYNERGY1200N:
+ case SUBID_DVBS_EASYWATCH:
fe = stv0299_attach(&philips_sd1878_config,
&budget_av->budget.i2c_adap);
break;
@@ -1285,6 +1287,7 @@ MAKE_BUDGET_INFO(knc1s, "KNC1 DVB-S", BUDGET_KNC1S);
MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C);
MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);
MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);
+MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);
MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP);
MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP);
@@ -1300,6 +1303,7 @@ static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011),
MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014),
MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
+ MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),
MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030),
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index b9b3cd9c036..5f91036f5b8 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -42,6 +42,9 @@
#include "stv0299.h"
#include "stv0297.h"
#include "tda1004x.h"
+#include "lnbp21.h"
+#include "bsbe1.h"
+#include "bsru6.h"
#define DEBIADDR_IR 0x1234
#define DEBIADDR_CICONTROL 0x0000
@@ -474,123 +477,6 @@ static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
}
-
-static u8 alps_bsru6_inittab[] = {
- 0x01, 0x15,
- 0x02, 0x00,
- 0x03, 0x00,
- 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
- 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
- 0x06, 0x40, /* DAC not used, set to high impendance mode */
- 0x07, 0x00, /* DAC LSB */
- 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
- 0x09, 0x00, /* FIFO */
- 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
- 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
- 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
- 0x10, 0x3f, // AGC2 0x3d
- 0x11, 0x84,
- 0x12, 0xb9,
- 0x15, 0xc9, // lock detector threshold
- 0x16, 0x00,
- 0x17, 0x00,
- 0x18, 0x00,
- 0x19, 0x00,
- 0x1a, 0x00,
- 0x1f, 0x50,
- 0x20, 0x00,
- 0x21, 0x00,
- 0x22, 0x00,
- 0x23, 0x00,
- 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
- 0x29, 0x1e, // 1/2 threshold
- 0x2a, 0x14, // 2/3 threshold
- 0x2b, 0x0f, // 3/4 threshold
- 0x2c, 0x09, // 5/6 threshold
- 0x2d, 0x05, // 7/8 threshold
- 0x2e, 0x01,
- 0x31, 0x1f, // test all FECs
- 0x32, 0x19, // viterbi and synchro search
- 0x33, 0xfc, // rs control
- 0x34, 0x93, // error control
- 0x0f, 0x52,
- 0xff, 0xff
-};
-
-static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
-{
- u8 aclk = 0;
- u8 bclk = 0;
-
- if (srate < 1500000) {
- aclk = 0xb7;
- bclk = 0x47;
- } else if (srate < 3000000) {
- aclk = 0xb7;
- bclk = 0x4b;
- } else if (srate < 7000000) {
- aclk = 0xb7;
- bclk = 0x4f;
- } else if (srate < 14000000) {
- aclk = 0xb7;
- bclk = 0x53;
- } else if (srate < 30000000) {
- aclk = 0xb6;
- bclk = 0x53;
- } else if (srate < 45000000) {
- aclk = 0xb4;
- bclk = 0x51;
- }
-
- stv0299_writereg(fe, 0x13, aclk);
- stv0299_writereg(fe, 0x14, bclk);
- stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
- stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
- stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
-
- return 0;
-}
-
-static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params)
-{
- u8 buf[4];
- u32 div;
- struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
-
- if ((params->frequency < 950000) || (params->frequency > 2150000))
- return -EINVAL;
-
- div = (params->frequency + (125 - 1)) / 125; // round correctly
- buf[0] = (div >> 8) & 0x7f;
- buf[1] = div & 0xff;
- buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
- buf[3] = 0xC4;
-
- if (params->frequency > 1530000)
- buf[3] = 0xc0;
-
- if (i2c_transfer(i2c, &msg, 1) != 1)
- return -EIO;
- return 0;
-}
-
-static struct stv0299_config alps_bsru6_config = {
-
- .demod_address = 0x68,
- .inittab = alps_bsru6_inittab,
- .mclk = 88000000UL,
- .invert = 1,
- .skip_reinit = 0,
- .lock_output = STV0229_LOCKOUTPUT_1,
- .volt13_op0_op1 = STV0299_VOLT13_OP1,
- .min_delay_ms = 100,
- .set_symbol_rate = alps_bsru6_set_symbol_rate,
- .pll_set = alps_bsru6_pll_set,
-};
-
-
-
-
static u8 philips_su1278_tt_inittab[] = {
0x01, 0x0f,
0x02, 0x30,
@@ -1069,6 +955,20 @@ static void frontend_init(struct budget_ci *budget_ci)
break;
}
break;
+
+ case 0x1017: // TT S-1500 PCI
+ budget_ci->budget.dvb_frontend = stv0299_attach(&alps_bsbe1_config, &budget_ci->budget.i2c_adap);
+ if (budget_ci->budget.dvb_frontend) {
+ budget_ci->budget.dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
+ if (lnbp21_init(budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0)) {
+ printk("%s: No LNBP21 found!\n", __FUNCTION__);
+ if (budget_ci->budget.dvb_frontend->ops->release)
+ budget_ci->budget.dvb_frontend->ops->release(budget_ci->budget.dvb_frontend);
+ budget_ci->budget.dvb_frontend = NULL;
+ }
+ }
+
+ break;
}
if (budget_ci->budget.dvb_frontend == NULL) {
@@ -1146,6 +1046,7 @@ static int budget_ci_detach(struct saa7146_dev *dev)
static struct saa7146_extension budget_extension;
+MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT);
MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
@@ -1157,6 +1058,7 @@ static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
+ MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
{
.vendor = 0,
}
diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c
index fc416cf5253..9fc9185a842 100644
--- a/drivers/media/dvb/ttpci/budget-patch.c
+++ b/drivers/media/dvb/ttpci/budget-patch.c
@@ -37,6 +37,8 @@
#include "ves1x93.h"
#include "tda8083.h"
+#include "bsru6.h"
+
#define budget_patch budget
static struct saa7146_extension budget_extension;
@@ -290,103 +292,6 @@ static struct ves1x93_config alps_bsrv2_config = {
.pll_set = alps_bsrv2_pll_set,
};
-static u8 alps_bsru6_inittab[] = {
- 0x01, 0x15,
- 0x02, 0x00,
- 0x03, 0x00,
- 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
- 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
- 0x06, 0x40, /* DAC not used, set to high impendance mode */
- 0x07, 0x00, /* DAC LSB */
- 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
- 0x09, 0x00, /* FIFO */
- 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
- 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
- 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
- 0x10, 0x3f, // AGC2 0x3d
- 0x11, 0x84,
- 0x12, 0xb9,
- 0x15, 0xc9, // lock detector threshold
- 0x16, 0x00,
- 0x17, 0x00,
- 0x18, 0x00,
- 0x19, 0x00,
- 0x1a, 0x00,
- 0x1f, 0x50,
- 0x20, 0x00,
- 0x21, 0x00,
- 0x22, 0x00,
- 0x23, 0x00,
- 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
- 0x29, 0x1e, // 1/2 threshold
- 0x2a, 0x14, // 2/3 threshold
- 0x2b, 0x0f, // 3/4 threshold
- 0x2c, 0x09, // 5/6 threshold
- 0x2d, 0x05, // 7/8 threshold
- 0x2e, 0x01,
- 0x31, 0x1f, // test all FECs
- 0x32, 0x19, // viterbi and synchro search
- 0x33, 0xfc, // rs control
- 0x34, 0x93, // error control
- 0x0f, 0x52,
- 0xff, 0xff
-};
-
-static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
-{
- u8 aclk = 0;
- u8 bclk = 0;
-
- if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
- else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
- else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
- else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
- else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
- else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
-
- stv0299_writereg (fe, 0x13, aclk);
- stv0299_writereg (fe, 0x14, bclk);
- stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
- stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff);
- stv0299_writereg (fe, 0x21, (ratio ) & 0xf0);
-
- return 0;
-}
-
-static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
-{
- u8 data[4];
- u32 div;
- struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
-
- if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL;
-
- div = (params->frequency + (125 - 1)) / 125; // round correctly
- data[0] = (div >> 8) & 0x7f;
- data[1] = div & 0xff;
- data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
- data[3] = 0xC4;
-
- if (params->frequency > 1530000) data[3] = 0xc0;
-
- if (i2c_transfer(i2c, &msg, 1) != 1) return -EIO;
- return 0;
-}
-
-static struct stv0299_config alps_bsru6_config = {
-
- .demod_address = 0x68,
- .inittab = alps_bsru6_inittab,
- .mclk = 88000000UL,
- .invert = 1,
- .skip_reinit = 0,
- .lock_output = STV0229_LOCKOUTPUT_1,
- .volt13_op0_op1 = STV0299_VOLT13_OP1,
- .min_delay_ms = 100,
- .set_symbol_rate = alps_bsru6_set_symbol_rate,
- .pll_set = alps_bsru6_pll_set,
-};
-
static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index 238c77b52f8..c23c02d9564 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -41,6 +41,8 @@
#include "l64781.h"
#include "tda8083.h"
#include "s5h1420.h"
+#include "lnbp21.h"
+#include "bsru6.h"
static void Set22K (struct budget *budget, int state)
{
@@ -184,64 +186,6 @@ static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t m
return 0;
}
-static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
-{
- struct budget* budget = (struct budget*) fe->dvb->priv;
- u8 buf;
- struct i2c_msg msg = { .addr = 0x08, .flags = I2C_M_RD, .buf = &buf, .len = sizeof(buf) };
-
- if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
-
- switch(voltage) {
- case SEC_VOLTAGE_13:
- buf = (buf & 0xf7) | 0x04;
- break;
-
- case SEC_VOLTAGE_18:
- buf = (buf & 0xf7) | 0x0c;
- break;
-
- case SEC_VOLTAGE_OFF:
- buf = buf & 0xf0;
- break;
- }
-
- msg.flags = 0;
- if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
-
- return 0;
-}
-
-static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend* fe, long arg)
-{
- struct budget* budget = (struct budget*) fe->dvb->priv;
- u8 buf;
- struct i2c_msg msg = { .addr = 0x08, .flags = I2C_M_RD, .buf = &buf, .len = sizeof(buf) };
-
- if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
-
- if (arg) {
- buf = buf | 0x10;
- } else {
- buf = buf & 0xef;
- }
-
- msg.flags = 0;
- if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
-
- return 0;
-}
-
-static int lnbp21_init(struct budget* budget)
-{
- u8 buf = 0x00;
- struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = &buf, .len = sizeof(buf) };
-
- if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1)
- return -EIO;
- return 0;
-}
-
static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget* budget = (struct budget*) fe->dvb->priv;
@@ -277,176 +221,6 @@ static struct ves1x93_config alps_bsrv2_config =
.pll_set = alps_bsrv2_pll_set,
};
-static u8 alps_bsru6_inittab[] = {
- 0x01, 0x15,
- 0x02, 0x00,
- 0x03, 0x00,
- 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
- 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
- 0x06, 0x40, /* DAC not used, set to high impendance mode */
- 0x07, 0x00, /* DAC LSB */
- 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
- 0x09, 0x00, /* FIFO */
- 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
- 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
- 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
- 0x10, 0x3f, // AGC2 0x3d
- 0x11, 0x84,
- 0x12, 0xb9,
- 0x15, 0xc9, // lock detector threshold
- 0x16, 0x00,
- 0x17, 0x00,
- 0x18, 0x00,
- 0x19, 0x00,
- 0x1a, 0x00,
- 0x1f, 0x50,
- 0x20, 0x00,
- 0x21, 0x00,
- 0x22, 0x00,
- 0x23, 0x00,
- 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
- 0x29, 0x1e, // 1/2 threshold
- 0x2a, 0x14, // 2/3 threshold
- 0x2b, 0x0f, // 3/4 threshold
- 0x2c, 0x09, // 5/6 threshold
- 0x2d, 0x05, // 7/8 threshold
- 0x2e, 0x01,
- 0x31, 0x1f, // test all FECs
- 0x32, 0x19, // viterbi and synchro search
- 0x33, 0xfc, // rs control
- 0x34, 0x93, // error control
- 0x0f, 0x52,
- 0xff, 0xff
-};
-
-static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
-{
- u8 aclk = 0;
- u8 bclk = 0;
-
- if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
- else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
- else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
- else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
- else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
- else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
-
- stv0299_writereg (fe, 0x13, aclk);
- stv0299_writereg (fe, 0x14, bclk);
- stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
- stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff);
- stv0299_writereg (fe, 0x21, (ratio ) & 0xf0);
-
- return 0;
-}
-
-static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
-{
- u8 data[4];
- u32 div;
- struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
-
- if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL;
-
- div = (params->frequency + (125 - 1)) / 125; // round correctly
- data[0] = (div >> 8) & 0x7f;
- data[1] = div & 0xff;
- data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
- data[3] = 0xC4;
-
- if (params->frequency > 1530000) data[3] = 0xc0;
-
- if (i2c_transfer(i2c, &msg, 1) != 1) return -EIO;
- return 0;
-}
-
-static struct stv0299_config alps_bsru6_config = {
-
- .demod_address = 0x68,
- .inittab = alps_bsru6_inittab,
- .mclk = 88000000UL,
- .invert = 1,
- .skip_reinit = 0,
- .lock_output = STV0229_LOCKOUTPUT_1,
- .volt13_op0_op1 = STV0299_VOLT13_OP1,
- .min_delay_ms = 100,
- .set_symbol_rate = alps_bsru6_set_symbol_rate,
- .pll_set = alps_bsru6_pll_set,
-};
-
-static u8 alps_bsbe1_inittab[] = {
- 0x01, 0x15,
- 0x02, 0x30,
- 0x03, 0x00,
- 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
- 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
- 0x06, 0x40, /* DAC not used, set to high impendance mode */
- 0x07, 0x00, /* DAC LSB */
- 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
- 0x09, 0x00, /* FIFO */
- 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
- 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
- 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
- 0x10, 0x3f, // AGC2 0x3d
- 0x11, 0x84,
- 0x12, 0xb9,
- 0x15, 0xc9, // lock detector threshold
- 0x16, 0x00,
- 0x17, 0x00,
- 0x18, 0x00,
- 0x19, 0x00,
- 0x1a, 0x00,
- 0x1f, 0x50,
- 0x20, 0x00,
- 0x21, 0x00,
- 0x22, 0x00,
- 0x23, 0x00,
- 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
- 0x29, 0x1e, // 1/2 threshold
- 0x2a, 0x14, // 2/3 threshold
- 0x2b, 0x0f, // 3/4 threshold
- 0x2c, 0x09, // 5/6 threshold
- 0x2d, 0x05, // 7/8 threshold
- 0x2e, 0x01,
- 0x31, 0x1f, // test all FECs
- 0x32, 0x19, // viterbi and synchro search
- 0x33, 0xfc, // rs control
- 0x34, 0x93, // error control
- 0x0f, 0x92, // 0x80 = inverse AGC
- 0xff, 0xff
-};
-
-static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
-{
- int ret;
- u8 data[4];
- u32 div;
- struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
-
- if ((params->frequency < 950000) || (params->frequency > 2150000))
- return -EINVAL;
-
- div = (params->frequency + (125 - 1)) / 125; // round correctly
- data[0] = (div >> 8) & 0x7f;
- data[1] = div & 0xff;
- data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
- data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4;
-
- ret = i2c_transfer(i2c, &msg, 1);
- return (ret != 1) ? -EIO : 0;
-}
-
-static struct stv0299_config alps_bsbe1_config = {
- .demod_address = 0x68,
- .inittab = alps_bsbe1_inittab,
- .mclk = 88000000UL,
- .invert = 1,
- .skip_reinit = 0,
- .min_delay_ms = 100,
- .set_symbol_rate = alps_bsru6_set_symbol_rate,
- .pll_set = alps_bsbe1_pll_set,
-};
-
static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget* budget = (struct budget*) fe->dvb->priv;
@@ -580,20 +354,6 @@ static u8 read_pwm(struct budget* budget)
static void frontend_init(struct budget *budget)
{
switch(budget->dev->pci->subsystem_device) {
- case 0x1017:
- // try the ALPS BSBE1 now
- budget->dvb_frontend = stv0299_attach(&alps_bsbe1_config, &budget->i2c_adap);
- if (budget->dvb_frontend) {
- budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage;
- budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
- budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
- if (lnbp21_init(budget)) {
- printk("%s: No LNBP21 found!\n", __FUNCTION__);
- goto error_out;
- }
- }
-
- break;
case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659))
case 0x1013:
// try the ALPS BSRV2 first of all
@@ -646,9 +406,7 @@ static void frontend_init(struct budget *budget)
case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260))
budget->dvb_frontend = s5h1420_attach(&s5h1420_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
- budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage;
- budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
- if (lnbp21_init(budget)) {
+ if (lnbp21_init(budget->dvb_frontend, &budget->i2c_adap, 0, 0)) {
printk("%s: No LNBP21 found!\n", __FUNCTION__);
goto error_out;
}
@@ -719,7 +477,6 @@ static int budget_detach (struct saa7146_dev* dev)
static struct saa7146_extension budget_extension;
-MAKE_BUDGET_INFO(ttbs2, "TT-Budget/WinTV-NOVA-S PCI (rev AL/alps bsbe1 lnbp21 frontend)", BUDGET_TT);
MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-NOVA-S PCI", BUDGET_TT);
MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C PCI", BUDGET_TT);
MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
@@ -732,7 +489,6 @@ static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004),
MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005),
MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
- MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1016),
MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
diff --git a/drivers/media/dvb/ttpci/budget.h b/drivers/media/dvb/ttpci/budget.h
index c7bb63c4d98..4ac0f4d0802 100644
--- a/drivers/media/dvb/ttpci/budget.h
+++ b/drivers/media/dvb/ttpci/budget.h
@@ -10,6 +10,8 @@
#include "dvb_net.h"
#include <linux/module.h>
+#include <linux/mutex.h>
+
#include <media/saa7146.h>
extern int budget_debug;
@@ -51,7 +53,7 @@ struct budget {
struct dmx_frontend mem_frontend;
int fe_synced;
- struct semaphore pid_mutex;
+ struct mutex pid_mutex;
int ci_present;
int video_port;
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index 5a13c4744f6..248fdc7accf 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -19,7 +19,7 @@
#include <linux/time.h>
#include <linux/errno.h>
#include <linux/jiffies.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
#include "dvb_frontend.h"
#include "dmxdev.h"
@@ -35,7 +35,6 @@
#include <linux/dvb/dmx.h>
#include <linux/pci.h>
-
/*
TTUSB_HWSECTIONS:
the DSP supports filtering in hardware, however, since the "muxstream"
@@ -83,8 +82,8 @@ struct ttusb {
struct dvb_net dvbnet;
/* and one for USB access. */
- struct semaphore semi2c;
- struct semaphore semusb;
+ struct mutex semi2c;
+ struct mutex semusb;
struct dvb_adapter adapter;
struct usb_device *dev;
@@ -150,7 +149,7 @@ static int ttusb_cmd(struct ttusb *ttusb,
printk("\n");
#endif
- if (down_interruptible(&ttusb->semusb) < 0)
+ if (mutex_lock_interruptible(&ttusb->semusb) < 0)
return -EAGAIN;
err = usb_bulk_msg(ttusb->dev, ttusb->bulk_out_pipe,
@@ -158,13 +157,13 @@ static int ttusb_cmd(struct ttusb *ttusb,
if (err != 0) {
dprintk("%s: usb_bulk_msg(send) failed, err == %i!\n",
__FUNCTION__, err);
- up(&ttusb->semusb);
+ mutex_unlock(&ttusb->semusb);
return err;
}
if (actual_len != len) {
dprintk("%s: only wrote %d of %d bytes\n", __FUNCTION__,
actual_len, len);
- up(&ttusb->semusb);
+ mutex_unlock(&ttusb->semusb);
return -1;
}
@@ -174,7 +173,7 @@ static int ttusb_cmd(struct ttusb *ttusb,
if (err != 0) {
printk("%s: failed, receive error %d\n", __FUNCTION__,
err);
- up(&ttusb->semusb);
+ mutex_unlock(&ttusb->semusb);
return err;
}
#if DEBUG >= 3
@@ -185,14 +184,14 @@ static int ttusb_cmd(struct ttusb *ttusb,
printk("\n");
#endif
if (!needresult)
- up(&ttusb->semusb);
+ mutex_unlock(&ttusb->semusb);
return 0;
}
static int ttusb_result(struct ttusb *ttusb, u8 * data, int len)
{
memcpy(data, ttusb->last_result, len);
- up(&ttusb->semusb);
+ mutex_unlock(&ttusb->semusb);
return 0;
}
@@ -250,7 +249,7 @@ static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num
int i = 0;
int inc;
- if (down_interruptible(&ttusb->semi2c) < 0)
+ if (mutex_lock_interruptible(&ttusb->semi2c) < 0)
return -EAGAIN;
while (i < num) {
@@ -284,7 +283,7 @@ static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num
i += inc;
}
- up(&ttusb->semi2c);
+ mutex_unlock(&ttusb->semi2c);
return i;
}
@@ -689,8 +688,7 @@ static void ttusb_process_frame(struct ttusb *ttusb, u8 * data, int len)
memcpy(ttusb->muxpack + ttusb->muxpack_ptr,
data, avail);
ttusb->muxpack_ptr += avail;
- if (ttusb->muxpack_ptr > 264)
- BUG();
+ BUG_ON(ttusb->muxpack_ptr > 264);
data += avail;
len -= avail;
/* determine length */
@@ -1495,8 +1493,11 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
ttusb->dev = udev;
ttusb->c = 0;
ttusb->mux_state = 0;
- sema_init(&ttusb->semi2c, 0);
- sema_init(&ttusb->semusb, 1);
+ mutex_init(&ttusb->semi2c);
+
+ mutex_lock(&ttusb->semi2c);
+
+ mutex_init(&ttusb->semusb);
ttusb_setup_interfaces(ttusb);
@@ -1504,7 +1505,7 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
if (ttusb_init_controller(ttusb))
printk("ttusb_init_controller: error\n");
- up(&ttusb->semi2c);
+ mutex_unlock(&ttusb->semi2c);
dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE);
ttusb->adapter.priv = ttusb;
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index df831171e03..44dea321184 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -20,7 +20,8 @@
*
*/
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+
#include <linux/list.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -115,7 +116,7 @@ struct ttusb_dec {
unsigned int out_pipe;
unsigned int irq_pipe;
enum ttusb_dec_interface interface;
- struct semaphore usb_sem;
+ struct mutex usb_mutex;
void *irq_buffer;
struct urb *irq_urb;
@@ -124,7 +125,7 @@ struct ttusb_dec {
dma_addr_t iso_dma_handle;
struct urb *iso_urb[ISO_BUF_COUNT];
int iso_stream_count;
- struct semaphore iso_sem;
+ struct mutex iso_mutex;
u8 packet[MAX_PVA_LENGTH + 4];
enum ttusb_dec_packet_type packet_type;
@@ -273,9 +274,9 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
if (!b)
return -ENOMEM;
- if ((result = down_interruptible(&dec->usb_sem))) {
+ if ((result = mutex_lock_interruptible(&dec->usb_mutex))) {
kfree(b);
- printk("%s: Failed to down usb semaphore.\n", __FUNCTION__);
+ printk("%s: Failed to lock usb mutex.\n", __FUNCTION__);
return result;
}
@@ -300,7 +301,7 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
if (result) {
printk("%s: command bulk message failed: error %d\n",
__FUNCTION__, result);
- up(&dec->usb_sem);
+ mutex_unlock(&dec->usb_mutex);
kfree(b);
return result;
}
@@ -311,7 +312,7 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
if (result) {
printk("%s: result bulk message failed: error %d\n",
__FUNCTION__, result);
- up(&dec->usb_sem);
+ mutex_unlock(&dec->usb_mutex);
kfree(b);
return result;
} else {
@@ -327,7 +328,7 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
if (cmd_result && b[3] > 0)
memcpy(cmd_result, &b[4], b[3]);
- up(&dec->usb_sem);
+ mutex_unlock(&dec->usb_mutex);
kfree(b);
return 0;
@@ -835,7 +836,7 @@ static void ttusb_dec_stop_iso_xfer(struct ttusb_dec *dec)
dprintk("%s\n", __FUNCTION__);
- if (down_interruptible(&dec->iso_sem))
+ if (mutex_lock_interruptible(&dec->iso_mutex))
return;
dec->iso_stream_count--;
@@ -845,7 +846,7 @@ static void ttusb_dec_stop_iso_xfer(struct ttusb_dec *dec)
usb_kill_urb(dec->iso_urb[i]);
}
- up(&dec->iso_sem);
+ mutex_unlock(&dec->iso_mutex);
}
/* Setting the interface of the DEC tends to take down the USB communications
@@ -890,7 +891,7 @@ static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec)
dprintk("%s\n", __FUNCTION__);
- if (down_interruptible(&dec->iso_sem))
+ if (mutex_lock_interruptible(&dec->iso_mutex))
return -EAGAIN;
if (!dec->iso_stream_count) {
@@ -911,7 +912,7 @@ static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec)
i--;
}
- up(&dec->iso_sem);
+ mutex_unlock(&dec->iso_mutex);
return result;
}
}
@@ -919,7 +920,7 @@ static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec)
dec->iso_stream_count++;
- up(&dec->iso_sem);
+ mutex_unlock(&dec->iso_mutex);
return 0;
}
@@ -1229,8 +1230,8 @@ static int ttusb_dec_init_usb(struct ttusb_dec *dec)
{
dprintk("%s\n", __FUNCTION__);
- sema_init(&dec->usb_sem, 1);
- sema_init(&dec->iso_sem, 1);
+ mutex_init(&dec->usb_mutex);
+ mutex_init(&dec->iso_mutex);
dec->command_pipe = usb_sndbulkpipe(dec->udev, COMMAND_PIPE);
dec->result_pipe = usb_rcvbulkpipe(dec->udev, RESULT_PIPE);
diff --git a/drivers/media/radio/miropcm20-rds-core.c b/drivers/media/radio/miropcm20-rds-core.c
index a917a90cb5d..b602c73e230 100644
--- a/drivers/media/radio/miropcm20-rds-core.c
+++ b/drivers/media/radio/miropcm20-rds-core.c
@@ -18,14 +18,15 @@
#include <linux/string.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+
#include <asm/io.h>
#include "../../../sound/oss/aci.h"
#include "miropcm20-rds-core.h"
#define DEBUG 0
-static struct semaphore aci_rds_sem;
+static struct mutex aci_rds_mutex;
#define RDS_DATASHIFT 2 /* Bit 2 */
#define RDS_DATAMASK (1 << RDS_DATASHIFT)
@@ -181,7 +182,7 @@ int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize)
{
int ret;
- if (down_interruptible(&aci_rds_sem))
+ if (mutex_lock_interruptible(&aci_rds_mutex))
return -EINTR;
rds_write(cmd);
@@ -192,7 +193,7 @@ int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize)
else
ret = 0;
- up(&aci_rds_sem);
+ mutex_unlock(&aci_rds_mutex);
return ret;
}
@@ -200,7 +201,7 @@ EXPORT_SYMBOL(aci_rds_cmd);
int __init attach_aci_rds(void)
{
- init_MUTEX(&aci_rds_sem);
+ mutex_init(&aci_rds_mutex);
return 0;
}
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index 914deab4e04..557fb5c4af3 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -43,7 +43,7 @@
static int io = CONFIG_RADIO_RTRACK_PORT;
static int radio_nr = -1;
-static struct semaphore lock;
+static struct mutex lock;
struct rt_device
{
@@ -83,23 +83,23 @@ static void rt_incvol(void)
static void rt_mute(struct rt_device *dev)
{
dev->muted = 1;
- down(&lock);
+ mutex_lock(&lock);
outb(0xd0, io); /* volume steady, off */
- up(&lock);
+ mutex_unlock(&lock);
}
static int rt_setvol(struct rt_device *dev, int vol)
{
int i;
- down(&lock);
+ mutex_lock(&lock);
if(vol == dev->curvol) { /* requested volume = current */
if (dev->muted) { /* user is unmuting the card */
dev->muted = 0;
outb (0xd8, io); /* enable card */
}
- up(&lock);
+ mutex_unlock(&lock);
return 0;
}
@@ -108,7 +108,7 @@ static int rt_setvol(struct rt_device *dev, int vol)
sleep_delay(2000000); /* make sure it's totally down */
outb(0xd0, io); /* volume steady, off */
dev->curvol = 0; /* track the volume state! */
- up(&lock);
+ mutex_unlock(&lock);
return 0;
}
@@ -121,7 +121,7 @@ static int rt_setvol(struct rt_device *dev, int vol)
rt_decvol();
dev->curvol = vol;
- up(&lock);
+ mutex_unlock(&lock);
return 0;
}
@@ -168,7 +168,7 @@ static int rt_setfreq(struct rt_device *dev, unsigned long freq)
freq += 171200; /* Add 10.7 MHz IF */
freq /= 800; /* Convert to 50 kHz units */
- down(&lock); /* Stop other ops interfering */
+ mutex_lock(&lock); /* Stop other ops interfering */
send_0_byte (io, dev); /* 0: LSB of frequency */
@@ -196,7 +196,7 @@ static int rt_setfreq(struct rt_device *dev, unsigned long freq)
else
outb (0xd8, io); /* volume steady + sigstr + on */
- up(&lock);
+ mutex_unlock(&lock);
return 0;
}
@@ -337,7 +337,7 @@ static int __init rtrack_init(void)
/* Set up the I/O locking */
- init_MUTEX(&lock);
+ mutex_init(&lock);
/* mute card - prevents noisy bootups */
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index 523be820f9c..83bdae23417 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -42,7 +42,7 @@
static int io = CONFIG_RADIO_AZTECH_PORT;
static int radio_nr = -1;
static int radio_wait_time = 1000;
-static struct semaphore lock;
+static struct mutex lock;
struct az_device
{
@@ -87,9 +87,9 @@ static void send_1_byte (struct az_device *dev)
static int az_setvol(struct az_device *dev, int vol)
{
- down(&lock);
+ mutex_lock(&lock);
outb (volconvert(vol), io);
- up(&lock);
+ mutex_unlock(&lock);
return 0;
}
@@ -122,7 +122,7 @@ static int az_setfreq(struct az_device *dev, unsigned long frequency)
frequency += 171200; /* Add 10.7 MHz IF */
frequency /= 800; /* Convert to 50 kHz units */
- down(&lock);
+ mutex_lock(&lock);
send_0_byte (dev); /* 0: LSB of frequency */
@@ -152,7 +152,7 @@ static int az_setfreq(struct az_device *dev, unsigned long frequency)
udelay (radio_wait_time);
outb_p(128+64+volconvert(dev->curvol), io);
- up(&lock);
+ mutex_unlock(&lock);
return 0;
}
@@ -283,7 +283,7 @@ static int __init aztech_init(void)
return -EBUSY;
}
- init_MUTEX(&lock);
+ mutex_init(&lock);
aztech_radio.priv=&aztech_unit;
if(video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr)==-1)
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
index 36c9f5bf8cd..39c1d911863 100644
--- a/drivers/media/radio/radio-maestro.c
+++ b/drivers/media/radio/radio-maestro.c
@@ -23,10 +23,11 @@
#include <linux/sched.h>
#include <asm/io.h>
#include <asm/uaccess.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/videodev.h>
+
#define DRIVER_VERSION "0.05"
#define GPIO_DATA 0x60 /* port offset from ESS_IO_BASE */
@@ -104,7 +105,7 @@ struct radio_device {
muted, /* VIDEO_AUDIO_MUTE */
stereo, /* VIDEO_TUNER_STEREO_ON */
tuned; /* signal strength (0 or 0xffff) */
- struct semaphore lock;
+ struct mutex lock;
};
static u32 radio_bits_get(struct radio_device *dev)
@@ -258,9 +259,9 @@ static int radio_ioctl(struct inode *inode, struct file *file,
struct radio_device *card = video_get_drvdata(dev);
int ret;
- down(&card->lock);
+ mutex_lock(&card->lock);
ret = video_usercopy(inode, file, cmd, arg, radio_function);
- up(&card->lock);
+ mutex_unlock(&card->lock);
return ret;
}
@@ -311,7 +312,7 @@ static int __devinit maestro_probe(struct pci_dev *pdev,
}
radio_unit->io = pci_resource_start(pdev, 0) + GPIO_DATA;
- init_MUTEX(&radio_unit->lock);
+ mutex_init(&radio_unit->lock);
maestro_radio_inst = video_device_alloc();
if (maestro_radio_inst == NULL) {
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index c975ddd86cd..f0bf47bcb64 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -37,7 +37,8 @@
#include <linux/sched.h>
#include <asm/io.h>
#include <asm/uaccess.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+
#include <linux/pci.h>
#include <linux/videodev.h>
@@ -101,7 +102,7 @@ static struct radio_device
unsigned long freq;
- struct semaphore lock;
+ struct mutex lock;
} radio_unit = {0, 0, 0, 0, };
@@ -267,9 +268,9 @@ static int radio_ioctl(struct inode *inode, struct file *file,
struct radio_device *card=dev->priv;
int ret;
- down(&card->lock);
+ mutex_lock(&card->lock);
ret = video_usercopy(inode, file, cmd, arg, radio_function);
- up(&card->lock);
+ mutex_unlock(&card->lock);
return ret;
}
@@ -290,7 +291,7 @@ static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_d
goto err_out_free_region;
radio_unit.io = pci_resource_start(pdev, 0);
- init_MUTEX(&radio_unit.lock);
+ mutex_init(&radio_unit.lock);
maxiradio_radio.priv = &radio_unit;
if(video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) {
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index 0229f792a05..53073b42410 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -24,7 +24,7 @@
#include <linux/isapnp.h>
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
struct fmi_device
{
@@ -37,7 +37,7 @@ struct fmi_device
static int io = -1;
static int radio_nr = -1;
static struct pnp_dev *dev = NULL;
-static struct semaphore lock;
+static struct mutex lock;
/* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
/* It is only useful to give freq in intervall of 800 (=0.05Mhz),
@@ -68,16 +68,16 @@ static void outbits(int bits, unsigned int data, int port)
static inline void fmi_mute(int port)
{
- down(&lock);
+ mutex_lock(&lock);
outb(0x00, port);
- up(&lock);
+ mutex_unlock(&lock);
}
static inline void fmi_unmute(int port)
{
- down(&lock);
+ mutex_lock(&lock);
outb(0x08, port);
- up(&lock);
+ mutex_unlock(&lock);
}
static inline int fmi_setfreq(struct fmi_device *dev)
@@ -85,12 +85,12 @@ static inline int fmi_setfreq(struct fmi_device *dev)
int myport = dev->port;
unsigned long freq = dev->curfreq;
- down(&lock);
+ mutex_lock(&lock);
outbits(16, RSF16_ENCODE(freq), myport);
outbits(8, 0xC0, myport);
msleep(143); /* was schedule_timeout(HZ/7) */
- up(&lock);
+ mutex_unlock(&lock);
if (dev->curvol) fmi_unmute(myport);
return 0;
}
@@ -102,7 +102,7 @@ static inline int fmi_getsigstr(struct fmi_device *dev)
int myport = dev->port;
- down(&lock);
+ mutex_lock(&lock);
val = dev->curvol ? 0x08 : 0x00; /* unmute/mute */
outb(val, myport);
outb(val | 0x10, myport);
@@ -110,7 +110,7 @@ static inline int fmi_getsigstr(struct fmi_device *dev)
res = (int)inb(myport+1);
outb(val, myport);
- up(&lock);
+ mutex_unlock(&lock);
return (res & 2) ? 0 : 0xFFFF;
}
@@ -296,7 +296,7 @@ static int __init fmi_init(void)
fmi_unit.flags = VIDEO_TUNER_LOW;
fmi_radio.priv = &fmi_unit;
- init_MUTEX(&lock);
+ mutex_init(&lock);
if (video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr) == -1) {
release_region(io, 2);
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index 099ffb3b9c7..bcebd8cb19a 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -19,9 +19,9 @@
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
-static struct semaphore lock;
+static struct mutex lock;
#undef DEBUG
//#define DEBUG 1
@@ -238,9 +238,9 @@ static int fmr2_do_ioctl(struct inode *inode, struct file *file,
if (fmr2->mute)
v->flags |= VIDEO_AUDIO_MUTE;
v->mode=VIDEO_MODE_AUTO;
- down(&lock);
+ mutex_lock(&lock);
v->signal = fmr2_getsigstr(fmr2);
- up(&lock);
+ mutex_unlock(&lock);
return 0;
}
case VIDIOCSTUNER:
@@ -274,9 +274,9 @@ static int fmr2_do_ioctl(struct inode *inode, struct file *file,
/* set card freq (if not muted) */
if (fmr2->curvol && !fmr2->mute)
{
- down(&lock);
+ mutex_lock(&lock);
fmr2_setfreq(fmr2);
- up(&lock);
+ mutex_unlock(&lock);
}
return 0;
}
@@ -318,14 +318,14 @@ static int fmr2_do_ioctl(struct inode *inode, struct file *file,
else
printk(KERN_DEBUG "mute\n");
#endif
- down(&lock);
+ mutex_lock(&lock);
if (fmr2->curvol && !fmr2->mute)
{
fmr2_setvolume(fmr2);
fmr2_setfreq(fmr2);
}
else fmr2_mute(fmr2->port);
- up(&lock);
+ mutex_unlock(&lock);
return 0;
}
case VIDIOCGUNIT:
@@ -380,7 +380,7 @@ static int __init fmr2_init(void)
fmr2_unit.card_type = 0;
fmr2_radio.priv = &fmr2_unit;
- init_MUTEX(&lock);
+ mutex_init(&lock);
if (request_region(io, 2, "sf16fmr2"))
{
@@ -397,10 +397,10 @@ static int __init fmr2_init(void)
printk(KERN_INFO "SF16FMR2 radio card driver at 0x%x.\n", io);
debug_print((KERN_DEBUG "Mute %d Low %d\n",VIDEO_AUDIO_MUTE,VIDEO_TUNER_LOW));
/* mute card - prevents noisy bootups */
- down(&lock);
+ mutex_lock(&lock);
fmr2_mute(io);
fmr2_product_info(&fmr2_unit);
- up(&lock);
+ mutex_unlock(&lock);
debug_print((KERN_DEBUG "card_type %d\n", fmr2_unit.card_type));
return 0;
}
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
index 8ac9a8ef909..e50955836d6 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -59,7 +59,7 @@ struct typhoon_device {
int muted;
unsigned long curfreq;
unsigned long mutefreq;
- struct semaphore lock;
+ struct mutex lock;
};
static void typhoon_setvol_generic(struct typhoon_device *dev, int vol);
@@ -77,12 +77,12 @@ static int typhoon_get_info(char *buf, char **start, off_t offset, int len);
static void typhoon_setvol_generic(struct typhoon_device *dev, int vol)
{
- down(&dev->lock);
+ mutex_lock(&dev->lock);
vol >>= 14; /* Map 16 bit to 2 bit */
vol &= 3;
outb_p(vol / 2, dev->iobase); /* Set the volume, high bit. */
outb_p(vol % 2, dev->iobase + 2); /* Set the volume, low bit. */
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
}
static int typhoon_setfreq_generic(struct typhoon_device *dev,
@@ -102,7 +102,7 @@ static int typhoon_setfreq_generic(struct typhoon_device *dev,
*
*/
- down(&dev->lock);
+ mutex_lock(&dev->lock);
x = frequency / 160;
outval = (x * x + 2500) / 5000;
outval = (outval * x + 5000) / 10000;
@@ -112,7 +112,7 @@ static int typhoon_setfreq_generic(struct typhoon_device *dev,
outb_p((outval >> 8) & 0x01, dev->iobase + 4);
outb_p(outval >> 9, dev->iobase + 6);
outb_p(outval & 0xff, dev->iobase + 8);
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
return 0;
}
@@ -337,7 +337,7 @@ static int __init typhoon_init(void)
#endif /* MODULE */
printk(KERN_INFO BANNER);
- init_MUTEX(&typhoon_unit.lock);
+ mutex_init(&typhoon_unit.lock);
io = typhoon_unit.iobase;
if (!request_region(io, 8, "typhoon")) {
printk(KERN_ERR "radio-typhoon: port 0x%x already in use\n",
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
index d590e80c922..7bf1a426489 100644
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -48,7 +48,7 @@ struct zol_device {
unsigned long curfreq;
int muted;
unsigned int stereo;
- struct semaphore lock;
+ struct mutex lock;
};
static int zol_setvol(struct zol_device *dev, int vol)
@@ -57,30 +57,30 @@ static int zol_setvol(struct zol_device *dev, int vol)
if (dev->muted)
return 0;
- down(&dev->lock);
+ mutex_lock(&dev->lock);
if (vol == 0) {
outb(0, io);
outb(0, io);
inb(io + 3); /* Zoltrix needs to be read to confirm */
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
return 0;
}
outb(dev->curvol-1, io);
msleep(10);
inb(io + 2);
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
return 0;
}
static void zol_mute(struct zol_device *dev)
{
dev->muted = 1;
- down(&dev->lock);
+ mutex_lock(&dev->lock);
outb(0, io);
outb(0, io);
inb(io + 3); /* Zoltrix needs to be read to confirm */
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
}
static void zol_unmute(struct zol_device *dev)
@@ -104,7 +104,7 @@ static int zol_setfreq(struct zol_device *dev, unsigned long freq)
bitmask = 0xc480402c10080000ull;
i = 45;
- down(&dev->lock);
+ mutex_lock(&dev->lock);
outb(0, io);
outb(0, io);
@@ -149,7 +149,7 @@ static int zol_setfreq(struct zol_device *dev, unsigned long freq)
udelay(1000);
}
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
if(!dev->muted)
{
@@ -164,7 +164,7 @@ static int zol_getsigstr(struct zol_device *dev)
{
int a, b;
- down(&dev->lock);
+ mutex_lock(&dev->lock);
outb(0x00, io); /* This stuff I found to do nothing */
outb(dev->curvol, io);
msleep(20);
@@ -173,7 +173,7 @@ static int zol_getsigstr(struct zol_device *dev)
msleep(10);
b = inb(io);
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
if (a != b)
return (0);
@@ -188,7 +188,7 @@ static int zol_is_stereo (struct zol_device *dev)
{
int x1, x2;
- down(&dev->lock);
+ mutex_lock(&dev->lock);
outb(0x00, io);
outb(dev->curvol, io);
@@ -198,7 +198,7 @@ static int zol_is_stereo (struct zol_device *dev)
msleep(10);
x2 = inb(io);
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
if ((x1 == x2) && (x1 == 0xcf))
return 1;
@@ -350,7 +350,7 @@ static int __init zoltrix_init(void)
}
printk(KERN_INFO "Zoltrix Radio Plus card driver.\n");
- init_MUTEX(&zoltrix_unit.lock);
+ mutex_init(&zoltrix_unit.lock);
/* mute card - prevents noisy bootups */
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index d82c8a30ba4..c622a4da566 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -26,6 +26,7 @@ config VIDEO_BT848
select VIDEO_IR
select VIDEO_TUNER
select VIDEO_TVEEPROM
+ select VIDEO_MSP3400
---help---
Support for BT848 based frame grabber/overlay boards. This includes
the Miro, Hauppauge and STB boards. Please read the material in
@@ -142,6 +143,8 @@ config VIDEO_CPIA_USB
otherwise say N. This will not work with the Creative Webcam III.
It is also available as a module (cpia_usb).
+source "drivers/media/video/cpia2/Kconfig"
+
config VIDEO_SAA5246A
tristate "SAA5246A, SAA5281 Teletext processor"
depends on VIDEO_DEV && I2C
@@ -339,18 +342,53 @@ config VIDEO_M32R_AR_M64278
Say Y here to use the Renesas M64278E-800 camera module,
which supports VGA(640x480 pixcels) size of images.
-config VIDEO_AUDIO_DECODER
- tristate "Add support for additional audio chipsets"
+config VIDEO_MSP3400
+ tristate "Micronas MSP34xx audio decoders"
+ depends on VIDEO_DEV && I2C
+ ---help---
+ Support for the Micronas MSP34xx series of audio decoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called msp3400
+
+config VIDEO_CS53L32A
+ tristate "Cirrus Logic CS53L32A audio ADC"
depends on VIDEO_DEV && I2C && EXPERIMENTAL
---help---
- Say Y here to compile drivers for WM8775 and CS53L32A audio
- decoders.
+ Support for the Cirrus Logic CS53L32A low voltage
+ stereo A/D converter.
-config VIDEO_DECODER
- tristate "Add support for additional video chipsets"
+ To compile this driver as a module, choose M here: the
+ module will be called cs53l32a
+
+config VIDEO_WM8775
+ tristate "Wolfson Microelectronics WM8775 audio ADC"
depends on VIDEO_DEV && I2C && EXPERIMENTAL
---help---
- Say Y here to compile drivers for SAA7115, SAA7127 and CX25840
- video decoders.
+ Support for the Wolfson Microelectronics WM8775
+ high performance stereo A/D Converter.
+
+ To compile this driver as a module, choose M here: the
+ module will be called wm8775
+
+source "drivers/media/video/cx25840/Kconfig"
+
+config VIDEO_SAA711X
+ tristate "Philips SAA7113/4/5 video decoders"
+ depends on VIDEO_DEV && I2C && EXPERIMENTAL
+ ---help---
+ Support for the Philips SAA7113/4/5 video decoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7115
+
+config VIDEO_SAA7127
+ tristate "Philips SAA7127/9 digital video encoders"
+ depends on VIDEO_DEV && I2C && EXPERIMENTAL
+ ---help---
+ Support for the Philips SAA7127/9 digital video encoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7127
endmenu
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index faf728366c4..f2bd4c0c4f1 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -15,7 +15,7 @@ msp3400-objs := msp3400-driver.o msp3400-kthreads.o
obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o compat_ioctl32.o
-obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \
+obj-$(CONFIG_VIDEO_BT848) += bttv.o tvaudio.o \
tda7432.o tda9875.o ir-kbd-i2c.o
obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
@@ -44,10 +44,13 @@ obj-$(CONFIG_VIDEO_MEYE) += meye.o
obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/
obj-$(CONFIG_VIDEO_CX88) += cx88/
obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
-obj-$(CONFIG_VIDEO_EM28XX) += saa711x.o tvp5150.o
-obj-$(CONFIG_VIDEO_AUDIO_DECODER) += wm8775.o cs53l32a.o
+obj-$(CONFIG_VIDEO_EM28XX) += tvp5150.o
+obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
+obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
+obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
-obj-$(CONFIG_VIDEO_MXB) += saa7111.o tuner.o tda9840.o tea6415c.o tea6420.o mxb.o
+obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
+obj-$(CONFIG_VIDEO_MXB) += saa7111.o tda9840.o tea6415c.o tea6420.o mxb.o
obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
obj-$(CONFIG_VIDEO_DPC) += saa7111.o dpc7146.o
@@ -61,6 +64,8 @@ obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
-obj-$(CONFIG_VIDEO_DECODER) += saa7115.o cx25840/ saa7127.o
+obj-$(CONFIG_VIDEO_CX25840) += cx25840/
+obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o
+obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
index 994b75fe165..c586f64b6b7 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/video/arv.c
@@ -31,8 +31,8 @@
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/videodev.h>
+#include <linux/mutex.h>
-#include <asm/semaphore.h>
#include <asm/uaccess.h>
#include <asm/m32r.h>
#include <asm/io.h>
@@ -117,7 +117,7 @@ struct ar_device {
int width, height;
int frame_bytes, line_bytes;
wait_queue_head_t wait;
- struct semaphore lock;
+ struct mutex lock;
};
static int video_nr = -1; /* video device number (first free) */
@@ -288,7 +288,7 @@ static ssize_t ar_read(struct file *file, char *buf, size_t count, loff_t *ppos)
if (ar->mode == AR_MODE_NORMAL)
arvcr1 |= ARVCR1_NORMAL;
- down(&ar->lock);
+ mutex_lock(&ar->lock);
#if USE_INT
local_irq_save(flags);
@@ -392,7 +392,7 @@ static ssize_t ar_read(struct file *file, char *buf, size_t count, loff_t *ppos)
}
DEBUG(1, "ret = %d\n", ret);
out_up:
- up(&ar->lock);
+ mutex_unlock(&ar->lock);
return ret;
}
@@ -456,7 +456,7 @@ static int ar_do_ioctl(struct inode *inode, struct file *file,
(w->width != AR_WIDTH_QVGA || w->height != AR_HEIGHT_QVGA))
return -EINVAL;
- down(&ar->lock);
+ mutex_lock(&ar->lock);
ar->width = w->width;
ar->height = w->height;
if (ar->width == AR_WIDTH_VGA) {
@@ -473,7 +473,7 @@ static int ar_do_ioctl(struct inode *inode, struct file *file,
ar->line_bytes = AR_LINE_BYTES_QVGA;
ar->mode = AR_MODE_INTERLACE;
}
- up(&ar->lock);
+ mutex_unlock(&ar->lock);
return 0;
}
case VIDIOCGFBUF:
@@ -734,7 +734,7 @@ static int ar_initialize(struct video_device *dev)
void ar_release(struct video_device *vfd)
{
struct ar_device *ar = vfd->priv;
- down(&ar->lock);
+ mutex_lock(&ar->lock);
video_device_release(vfd);
}
@@ -824,7 +824,7 @@ static int __init ar_init(void)
ar->line_bytes = AR_LINE_BYTES_QVGA;
ar->mode = AR_MODE_INTERLACE;
}
- init_MUTEX(&ar->lock);
+ mutex_init(&ar->lock);
init_waitqueue_head(&ar->wait);
#if USE_INT
diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c
index 9749d6ed623..abfa6ad857a 100644
--- a/drivers/media/video/bttv-cards.c
+++ b/drivers/media/video/bttv-cards.c
@@ -137,6 +137,8 @@ MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a li
MODULE_PARM_DESC(pll,"specify installed crystal (0=none, 28=28 MHz, 35=35 MHz)");
MODULE_PARM_DESC(tuner,"specify installed tuner type");
MODULE_PARM_DESC(autoload,"automatically load i2c modules like tuner.o, default is 1 (yes)");
+MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)"
+ " [some VIA/SIS chipsets are known to have problem with overlay]");
/* ----------------------------------------------------------------------- */
/* list of card IDs for bt878+ cards */
@@ -275,7 +277,6 @@ static struct CARD {
{ 0x03116000, BTTV_BOARD_SENSORAY311, "Sensoray 311" },
{ 0x00790e11, BTTV_BOARD_WINDVR, "Canopus WinDVR PCI" },
{ 0xa0fca1a0, BTTV_BOARD_ZOLTRIX, "Face to Face Tvmax" },
- { 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV"},
{ 0x82b2aa6a, BTTV_BOARD_SIMUS_GVC1100, "SIMUS GVC1100" },
{ 0x146caa0c, BTTV_BOARD_PV951, "ituner spectra8" },
{ 0x200a1295, BTTV_BOARD_PXC200, "ImageNation PXC200A" },
@@ -297,13 +298,14 @@ static struct CARD {
* { 0x13eb0070, BTTV_BOARD_HAUPPAUGE_IMPACTVCB, "Hauppauge ImpactVCB" }, */
/* DVB cards (using pci function .1 for mpeg data xfer) */
- { 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
- { 0x07611461, BTTV_BOARD_AVDVBT_761, "AverMedia AverTV DVB-T 761" },
{ 0x001c11bd, BTTV_BOARD_PINNACLESAT, "Pinnacle PCTV Sat" },
+ { 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
+ { 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV"},
{ 0x002611bd, BTTV_BOARD_TWINHAN_DST, "Pinnacle PCTV SAT CI" },
{ 0x00011822, BTTV_BOARD_TWINHAN_DST, "Twinhan VisionPlus DVB" },
{ 0xfc00270f, BTTV_BOARD_TWINHAN_DST, "ChainTech digitop DST-1000 DVB-S" },
{ 0x07711461, BTTV_BOARD_AVDVBT_771, "AVermedia AverTV DVB-T 771" },
+ { 0x07611461, BTTV_BOARD_AVDVBT_761, "AverMedia AverTV DVB-T 761" },
{ 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" },
{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" },
@@ -4944,12 +4946,14 @@ void __devinit bttv_check_chipset(void)
if (vsfx)
printk(KERN_INFO "bttv: Host bridge needs VSFX enabled.\n");
if (pcipci_fail) {
- printk(KERN_WARNING "bttv: BT848 and your chipset may not work together.\n");
+ printk(KERN_INFO "bttv: bttv and your chipset may not work "
+ "together.\n");
if (!no_overlay) {
- printk(KERN_WARNING "bttv: overlay will be disabled.\n");
+ printk(KERN_INFO "bttv: overlay will be disabled.\n");
no_overlay = 1;
} else {
- printk(KERN_WARNING "bttv: overlay forced. Use this option at your own risk.\n");
+ printk(KERN_INFO "bttv: overlay forced. Use this "
+ "option at your own risk.\n");
}
}
if (UNSET != latency)
diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c
index 578b2008508..c0415d6e7fe 100644
--- a/drivers/media/video/bttv-driver.c
+++ b/drivers/media/video/bttv-driver.c
@@ -1965,7 +1965,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
BUG();
}
- down(&fh->cap.lock);
+ mutex_lock(&fh->cap.lock);
kfree(fh->ov.clips);
fh->ov.clips = clips;
fh->ov.nclips = n;
@@ -1986,7 +1986,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
retval = bttv_switch_overlay(btv,fh,new);
}
- up(&fh->cap.lock);
+ mutex_unlock(&fh->cap.lock);
return retval;
}
@@ -2166,7 +2166,7 @@ static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
/* update our state informations */
- down(&fh->cap.lock);
+ mutex_lock(&fh->cap.lock);
fh->fmt = fmt;
fh->cap.field = f->fmt.pix.field;
fh->cap.last = V4L2_FIELD_NONE;
@@ -2175,7 +2175,7 @@ static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
btv->init.fmt = fmt;
btv->init.width = f->fmt.pix.width;
btv->init.height = f->fmt.pix.height;
- up(&fh->cap.lock);
+ mutex_unlock(&fh->cap.lock);
return 0;
}
@@ -2282,7 +2282,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
fmt = format_by_palette(pic->palette);
if (NULL == fmt)
return -EINVAL;
- down(&fh->cap.lock);
+ mutex_lock(&fh->cap.lock);
if (fmt->depth != pic->depth) {
retval = -EINVAL;
goto fh_unlock_and_return;
@@ -2313,7 +2313,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
bt848_contrast(btv,pic->contrast);
bt848_hue(btv,pic->hue);
bt848_sat(btv,pic->colour);
- up(&fh->cap.lock);
+ mutex_unlock(&fh->cap.lock);
return 0;
}
@@ -2379,7 +2379,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
return -EPERM;
end = (unsigned long)fbuf->base +
fbuf->height * fbuf->bytesperline;
- down(&fh->cap.lock);
+ mutex_lock(&fh->cap.lock);
retval = -EINVAL;
switch (fbuf->depth) {
@@ -2417,7 +2417,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
btv->fbuf.fmt.bytesperline = fbuf->bytesperline;
else
btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8;
- up(&fh->cap.lock);
+ mutex_unlock(&fh->cap.lock);
return 0;
}
@@ -2440,7 +2440,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))
return -EBUSY;
- down(&fh->cap.lock);
+ mutex_lock(&fh->cap.lock);
if (*on) {
fh->ov.tvnorm = btv->tvnorm;
new = videobuf_alloc(sizeof(*new));
@@ -2451,7 +2451,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
/* switch over */
retval = bttv_switch_overlay(btv,fh,new);
- up(&fh->cap.lock);
+ mutex_unlock(&fh->cap.lock);
return retval;
}
@@ -2460,7 +2460,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
struct video_mbuf *mbuf = arg;
unsigned int i;
- down(&fh->cap.lock);
+ mutex_lock(&fh->cap.lock);
retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize,
V4L2_MEMORY_MMAP);
if (retval < 0)
@@ -2470,7 +2470,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
mbuf->size = gbuffers * gbufsize;
for (i = 0; i < gbuffers; i++)
mbuf->offsets[i] = i * gbufsize;
- up(&fh->cap.lock);
+ mutex_unlock(&fh->cap.lock);
return 0;
}
case VIDIOCMCAPTURE:
@@ -2482,7 +2482,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
if (vm->frame >= VIDEO_MAX_FRAME)
return -EINVAL;
- down(&fh->cap.lock);
+ mutex_lock(&fh->cap.lock);
retval = -EINVAL;
buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame];
if (NULL == buf)
@@ -2504,7 +2504,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
spin_lock_irqsave(&btv->s_lock,flags);
buffer_queue(&fh->cap,&buf->vb);
spin_unlock_irqrestore(&btv->s_lock,flags);
- up(&fh->cap.lock);
+ mutex_unlock(&fh->cap.lock);
return 0;
}
case VIDIOCSYNC:
@@ -2515,7 +2515,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
if (*frame >= VIDEO_MAX_FRAME)
return -EINVAL;
- down(&fh->cap.lock);
+ mutex_lock(&fh->cap.lock);
retval = -EINVAL;
buf = (struct bttv_buffer *)fh->cap.bufs[*frame];
if (NULL == buf)
@@ -2535,7 +2535,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
retval = -EINVAL;
break;
}
- up(&fh->cap.lock);
+ mutex_unlock(&fh->cap.lock);
return retval;
}
@@ -2719,7 +2719,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
return -EINVAL;
- down(&fh->cap.lock);
+ mutex_lock(&fh->cap.lock);
retval = -EINVAL;
if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
if (fb->fmt.width > bttv_tvnorms[btv->tvnorm].swidth)
@@ -2759,7 +2759,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
retval = bttv_switch_overlay(btv,fh,new);
}
}
- up(&fh->cap.lock);
+ mutex_unlock(&fh->cap.lock);
return retval;
}
@@ -2890,7 +2890,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
return 0;
fh_unlock_and_return:
- up(&fh->cap.lock);
+ mutex_unlock(&fh->cap.lock);
return retval;
}
@@ -2957,16 +2957,16 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
} else {
/* read() capture */
- down(&fh->cap.lock);
+ mutex_lock(&fh->cap.lock);
if (NULL == fh->cap.read_buf) {
/* need to capture a new frame */
if (locked_btres(fh->btv,RESOURCE_VIDEO)) {
- up(&fh->cap.lock);
+ mutex_unlock(&fh->cap.lock);
return POLLERR;
}
fh->cap.read_buf = videobuf_alloc(fh->cap.msize);
if (NULL == fh->cap.read_buf) {
- up(&fh->cap.lock);
+ mutex_unlock(&fh->cap.lock);
return POLLERR;
}
fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR;
@@ -2974,13 +2974,13 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) {
kfree (fh->cap.read_buf);
fh->cap.read_buf = NULL;
- up(&fh->cap.lock);
+ mutex_unlock(&fh->cap.lock);
return POLLERR;
}
fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
fh->cap.read_off = 0;
}
- up(&fh->cap.lock);
+ mutex_unlock(&fh->cap.lock);
buf = (struct bttv_buffer*)fh->cap.read_buf;
}
diff --git a/drivers/media/video/bttv-input.c b/drivers/media/video/bttv-input.c
index 221b36e7f39..69efa0e5174 100644
--- a/drivers/media/video/bttv-input.c
+++ b/drivers/media/video/bttv-input.c
@@ -28,251 +28,6 @@
#include "bttv.h"
#include "bttvp.h"
-/* ---------------------------------------------------------------------- */
-
-static IR_KEYTAB_TYPE ir_codes_avermedia[IR_KEYTAB_SIZE] = {
- [ 34 ] = KEY_KP0,
- [ 40 ] = KEY_KP1,
- [ 24 ] = KEY_KP2,
- [ 56 ] = KEY_KP3,
- [ 36 ] = KEY_KP4,
- [ 20 ] = KEY_KP5,
- [ 52 ] = KEY_KP6,
- [ 44 ] = KEY_KP7,
- [ 28 ] = KEY_KP8,
- [ 60 ] = KEY_KP9,
-
- [ 48 ] = KEY_EJECTCD, // Unmarked on my controller
- [ 0 ] = KEY_POWER,
- [ 18 ] = BTN_LEFT, // DISPLAY/L
- [ 50 ] = BTN_RIGHT, // LOOP/R
- [ 10 ] = KEY_MUTE,
- [ 38 ] = KEY_RECORD,
- [ 22 ] = KEY_PAUSE,
- [ 54 ] = KEY_STOP,
- [ 30 ] = KEY_VOLUMEDOWN,
- [ 62 ] = KEY_VOLUMEUP,
-
- [ 32 ] = KEY_TUNER, // TV/FM
- [ 16 ] = KEY_CD,
- [ 8 ] = KEY_VIDEO,
- [ 4 ] = KEY_AUDIO,
- [ 12 ] = KEY_ZOOM, // full screen
- [ 2 ] = KEY_INFO, // preview
- [ 42 ] = KEY_SEARCH, // autoscan
- [ 26 ] = KEY_STOP, // freeze
- [ 58 ] = KEY_RECORD, // capture
- [ 6 ] = KEY_PLAY, // unmarked
- [ 46 ] = KEY_RED, // unmarked
- [ 14 ] = KEY_GREEN, // unmarked
-
- [ 33 ] = KEY_YELLOW, // unmarked
- [ 17 ] = KEY_CHANNELDOWN,
- [ 49 ] = KEY_CHANNELUP,
- [ 1 ] = KEY_BLUE, // unmarked
-};
-
-/* Matt Jesson <dvb@jesson.eclipse.co.uk */
-static IR_KEYTAB_TYPE ir_codes_avermedia_dvbt[IR_KEYTAB_SIZE] = {
- [ 0x28 ] = KEY_KP0, //'0' / 'enter'
- [ 0x22 ] = KEY_KP1, //'1'
- [ 0x12 ] = KEY_KP2, //'2' / 'up arrow'
- [ 0x32 ] = KEY_KP3, //'3'
- [ 0x24 ] = KEY_KP4, //'4' / 'left arrow'
- [ 0x14 ] = KEY_KP5, //'5'
- [ 0x34 ] = KEY_KP6, //'6' / 'right arrow'
- [ 0x26 ] = KEY_KP7, //'7'
- [ 0x16 ] = KEY_KP8, //'8' / 'down arrow'
- [ 0x36 ] = KEY_KP9, //'9'
-
- [ 0x20 ] = KEY_LIST, // 'source'
- [ 0x10 ] = KEY_TEXT, // 'teletext'
- [ 0x00 ] = KEY_POWER, // 'power'
- [ 0x04 ] = KEY_AUDIO, // 'audio'
- [ 0x06 ] = KEY_ZOOM, // 'full screen'
- [ 0x18 ] = KEY_VIDEO, // 'display'
- [ 0x38 ] = KEY_SEARCH, // 'loop'
- [ 0x08 ] = KEY_INFO, // 'preview'
- [ 0x2a ] = KEY_REWIND, // 'backward <<'
- [ 0x1a ] = KEY_FASTFORWARD, // 'forward >>'
- [ 0x3a ] = KEY_RECORD, // 'capture'
- [ 0x0a ] = KEY_MUTE, // 'mute'
- [ 0x2c ] = KEY_RECORD, // 'record'
- [ 0x1c ] = KEY_PAUSE, // 'pause'
- [ 0x3c ] = KEY_STOP, // 'stop'
- [ 0x0c ] = KEY_PLAY, // 'play'
- [ 0x2e ] = KEY_RED, // 'red'
- [ 0x01 ] = KEY_BLUE, // 'blue' / 'cancel'
- [ 0x0e ] = KEY_YELLOW, // 'yellow' / 'ok'
- [ 0x21 ] = KEY_GREEN, // 'green'
- [ 0x11 ] = KEY_CHANNELDOWN, // 'channel -'
- [ 0x31 ] = KEY_CHANNELUP, // 'channel +'
- [ 0x1e ] = KEY_VOLUMEDOWN, // 'volume -'
- [ 0x3e ] = KEY_VOLUMEUP, // 'volume +'
-};
-
-/* Attila Kondoros <attila.kondoros@chello.hu> */
-static IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = {
-
- [ 1 ] = KEY_KP1,
- [ 2 ] = KEY_KP2,
- [ 3 ] = KEY_KP3,
- [ 4 ] = KEY_KP4,
- [ 5 ] = KEY_KP5,
- [ 6 ] = KEY_KP6,
- [ 7 ] = KEY_KP7,
- [ 8 ] = KEY_KP8,
- [ 9 ] = KEY_KP9,
- [ 0 ] = KEY_KP0,
- [ 23 ] = KEY_LAST, // +100
- [ 10 ] = KEY_LIST, // recall
-
-
- [ 28 ] = KEY_TUNER, // TV/FM
- [ 21 ] = KEY_SEARCH, // scan
- [ 18 ] = KEY_POWER, // power
- [ 31 ] = KEY_VOLUMEDOWN, // vol up
- [ 27 ] = KEY_VOLUMEUP, // vol down
- [ 30 ] = KEY_CHANNELDOWN, // chn up
- [ 26 ] = KEY_CHANNELUP, // chn down
-
- [ 17 ] = KEY_VIDEO, // video
- [ 15 ] = KEY_ZOOM, // full screen
- [ 19 ] = KEY_MUTE, // mute/unmute
- [ 16 ] = KEY_TEXT, // min
-
- [ 13 ] = KEY_STOP, // freeze
- [ 14 ] = KEY_RECORD, // record
- [ 29 ] = KEY_PLAYPAUSE, // stop
- [ 25 ] = KEY_PLAY, // play
-
- [ 22 ] = KEY_GOTO, // osd
- [ 20 ] = KEY_REFRESH, // default
- [ 12 ] = KEY_KPPLUS, // fine tune >>>>
- [ 24 ] = KEY_KPMINUS // fine tune <<<<
-};
-
-/* ---------------------------------------------------------------------- */
-
-static IR_KEYTAB_TYPE ir_codes_conceptronic[IR_KEYTAB_SIZE] = {
-
- [ 30 ] = KEY_POWER, // power
- [ 7 ] = KEY_MEDIA, // source
- [ 28 ] = KEY_SEARCH, // scan
-
-/* FIXME: duplicate keycodes?
- *
- * These four keys seem to share the same GPIO as CH+, CH-, <<< and >>>
- * The GPIO values are
- * 6397fb for both "Scan <" and "CH -",
- * 639ffb for "Scan >" and "CH+",
- * 6384fb for "Tune <" and "<<<",
- * 638cfb for "Tune >" and ">>>", regardless of the mask.
- *
- * [ 23 ] = KEY_BACK, // fm scan <<
- * [ 31 ] = KEY_FORWARD, // fm scan >>
- *
- * [ 4 ] = KEY_LEFT, // fm tuning <
- * [ 12 ] = KEY_RIGHT, // fm tuning >
- *
- * For now, these four keys are disabled. Pressing them will generate
- * the CH+/CH-/<<</>>> events
- */
-
- [ 3 ] = KEY_TUNER, // TV/FM
-
- [ 0 ] = KEY_RECORD,
- [ 8 ] = KEY_STOP,
- [ 17 ] = KEY_PLAY,
-
- [ 26 ] = KEY_PLAYPAUSE, // freeze
- [ 25 ] = KEY_ZOOM, // zoom
- [ 15 ] = KEY_TEXT, // min
-
- [ 1 ] = KEY_KP1,
- [ 11 ] = KEY_KP2,
- [ 27 ] = KEY_KP3,
- [ 5 ] = KEY_KP4,
- [ 9 ] = KEY_KP5,
- [ 21 ] = KEY_KP6,
- [ 6 ] = KEY_KP7,
- [ 10 ] = KEY_KP8,
- [ 18 ] = KEY_KP9,
- [ 2 ] = KEY_KP0,
- [ 16 ] = KEY_LAST, // +100
- [ 19 ] = KEY_LIST, // recall
-
- [ 31 ] = KEY_CHANNELUP, // chn down
- [ 23 ] = KEY_CHANNELDOWN, // chn up
- [ 22 ] = KEY_VOLUMEUP, // vol down
- [ 20 ] = KEY_VOLUMEDOWN, // vol up
-
- [ 4 ] = KEY_KPMINUS, // <<<
- [ 14 ] = KEY_SETUP, // function
- [ 12 ] = KEY_KPPLUS, // >>>
-
- [ 13 ] = KEY_GOTO, // mts
- [ 29 ] = KEY_REFRESH, // reset
- [ 24 ] = KEY_MUTE // mute/unmute
-};
-
-static IR_KEYTAB_TYPE ir_codes_nebula[IR_KEYTAB_SIZE] = {
- [0x00] = KEY_KP0,
- [0x01] = KEY_KP1,
- [0x02] = KEY_KP2,
- [0x03] = KEY_KP3,
- [0x04] = KEY_KP4,
- [0x05] = KEY_KP5,
- [0x06] = KEY_KP6,
- [0x07] = KEY_KP7,
- [0x08] = KEY_KP8,
- [0x09] = KEY_KP9,
- [0x0a] = KEY_TV,
- [0x0b] = KEY_AUX,
- [0x0c] = KEY_DVD,
- [0x0d] = KEY_POWER,
- [0x0e] = KEY_MHP, /* labelled 'Picture' */
- [0x0f] = KEY_AUDIO,
- [0x10] = KEY_INFO,
- [0x11] = KEY_F13, /* 16:9 */
- [0x12] = KEY_F14, /* 14:9 */
- [0x13] = KEY_EPG,
- [0x14] = KEY_EXIT,
- [0x15] = KEY_MENU,
- [0x16] = KEY_UP,
- [0x17] = KEY_DOWN,
- [0x18] = KEY_LEFT,
- [0x19] = KEY_RIGHT,
- [0x1a] = KEY_ENTER,
- [0x1b] = KEY_CHANNELUP,
- [0x1c] = KEY_CHANNELDOWN,
- [0x1d] = KEY_VOLUMEUP,
- [0x1e] = KEY_VOLUMEDOWN,
- [0x1f] = KEY_RED,
- [0x20] = KEY_GREEN,
- [0x21] = KEY_YELLOW,
- [0x22] = KEY_BLUE,
- [0x23] = KEY_SUBTITLE,
- [0x24] = KEY_F15, /* AD */
- [0x25] = KEY_TEXT,
- [0x26] = KEY_MUTE,
- [0x27] = KEY_REWIND,
- [0x28] = KEY_STOP,
- [0x29] = KEY_PLAY,
- [0x2a] = KEY_FASTFORWARD,
- [0x2b] = KEY_F16, /* chapter */
- [0x2c] = KEY_PAUSE,
- [0x2d] = KEY_PLAY,
- [0x2e] = KEY_RECORD,
- [0x2f] = KEY_F17, /* picture in picture */
- [0x30] = KEY_KPPLUS, /* zoom in */
- [0x31] = KEY_KPMINUS, /* zoom out */
- [0x32] = KEY_F18, /* capture */
- [0x33] = KEY_F19, /* web */
- [0x34] = KEY_EMAIL,
- [0x35] = KEY_PHONE,
- [0x36] = KEY_PC
-};
static int debug;
module_param(debug, int, 0644); /* debug level (0,1,2) */
@@ -573,7 +328,8 @@ int bttv_input_init(struct bttv *btv)
ir->polling = 50; // ms
break;
case BTTV_BOARD_CONCEPTRONIC_CTVFMI2:
- ir_codes = ir_codes_conceptronic;
+ case BTTV_BOARD_CONTVFMI:
+ ir_codes = ir_codes_pixelview;
ir->mask_keycode = 0x001F00;
ir->mask_keyup = 0x006000;
ir->polling = 50; // ms
diff --git a/drivers/media/video/bttv-risc.c b/drivers/media/video/bttv-risc.c
index b40e9734bf0..344f84e9af0 100644
--- a/drivers/media/video/bttv-risc.c
+++ b/drivers/media/video/bttv-risc.c
@@ -51,8 +51,10 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
int rc;
/* estimate risc mem: worst case is one write per page border +
- one write per scan line + sync + jump (all 2 dwords) */
- instructions = (bpl * lines) / PAGE_SIZE + lines;
+ one write per scan line + sync + jump (all 2 dwords). padding
+ can cause next bpl to start close to a page border. First DMA
+ region may be smaller than PAGE_SIZE */
+ instructions = 1 + ((bpl + padding) * lines) / PAGE_SIZE + lines;
instructions += 2;
if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0)
return rc;
@@ -104,7 +106,7 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
/* save pointer to jmp instruction address */
risc->jmp = rp;
- BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size);
+ BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
return 0;
}
@@ -222,7 +224,7 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
/* save pointer to jmp instruction address */
risc->jmp = rp;
- BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size);
+ BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
return 0;
}
@@ -274,6 +276,8 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
if (line > maxy)
btcx_calc_skips(line, ov->w.width, &maxy,
skips, &nskips, ov->clips, ov->nclips);
+ else
+ nskips = 0;
/* write out risc code */
for (start = 0, skip = 0; start < ov->w.width; start = end) {
@@ -307,7 +311,7 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
/* save pointer to jmp instruction address */
risc->jmp = rp;
- BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size);
+ BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
kfree(skips);
return 0;
}
@@ -507,8 +511,7 @@ bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
void
bttv_dma_free(struct bttv *btv, struct bttv_buffer *buf)
{
- if (in_interrupt())
- BUG();
+ BUG_ON(in_interrupt());
videobuf_waiton(&buf->vb,0,0);
videobuf_dma_pci_unmap(btv->c.pci, &buf->vb.dma);
videobuf_dma_free(&buf->vb.dma);
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index 6bad93ef969..d97b7d8ac33 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -73,7 +73,7 @@ OTHER DEALINGS IN THE SOFTWARE.
#include <linux/parport.h>
#include <linux/sched.h>
#include <linux/videodev.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
#include "bw-qcam.h"
@@ -168,7 +168,7 @@ static struct qcam_device *qcam_init(struct parport *port)
memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
- init_MUTEX(&q->lock);
+ mutex_init(&q->lock);
q->port_mode = (QC_ANY | QC_NOTSET);
q->width = 320;
@@ -772,9 +772,9 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
qcam->whitebal = p->whiteness>>8;
qcam->bpp = p->depth;
- down(&qcam->lock);
+ mutex_lock(&qcam->lock);
qc_setscanmode(qcam);
- up(&qcam->lock);
+ mutex_unlock(&qcam->lock);
qcam->status |= QC_PARAM_CHANGE;
return 0;
@@ -805,9 +805,9 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
qcam->height = 240;
qcam->transfer_scale = 1;
}
- down(&qcam->lock);
+ mutex_lock(&qcam->lock);
qc_setscanmode(qcam);
- up(&qcam->lock);
+ mutex_unlock(&qcam->lock);
/* We must update the camera before we grab. We could
just have changed the grab size */
@@ -854,7 +854,7 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
int len;
parport_claim_or_block(qcam->pdev);
- down(&qcam->lock);
+ mutex_lock(&qcam->lock);
qc_reset(qcam);
@@ -864,7 +864,7 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
len=qc_capture(qcam, buf,count);
- up(&qcam->lock);
+ mutex_unlock(&qcam->lock);
parport_release(qcam->pdev);
return len;
diff --git a/drivers/media/video/bw-qcam.h b/drivers/media/video/bw-qcam.h
index 723e8ad9e56..6701dafbc0d 100644
--- a/drivers/media/video/bw-qcam.h
+++ b/drivers/media/video/bw-qcam.h
@@ -55,7 +55,7 @@ struct qcam_device {
struct video_device vdev;
struct pardevice *pdev;
struct parport *pport;
- struct semaphore lock;
+ struct mutex lock;
int width, height;
int bpp;
int mode;
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index 9976db4f6da..8211fd8d7cb 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -34,7 +34,8 @@
#include <linux/parport.h>
#include <linux/sched.h>
#include <linux/videodev.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+
#include <asm/uaccess.h>
struct qcam_device {
@@ -47,7 +48,7 @@ struct qcam_device {
int contrast, brightness, whitebal;
int top, left;
unsigned int bidirectional;
- struct semaphore lock;
+ struct mutex lock;
};
/* cameras maximum */
@@ -581,11 +582,11 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
qcam->contrast = p->contrast>>8;
qcam->whitebal = p->whiteness>>8;
- down(&qcam->lock);
+ mutex_lock(&qcam->lock);
parport_claim_or_block(qcam->pdev);
qc_setup(qcam);
parport_release(qcam->pdev);
- up(&qcam->lock);
+ mutex_unlock(&qcam->lock);
return 0;
}
case VIDIOCSWIN:
@@ -628,11 +629,11 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
#endif
/* Ok we figured out what to use from our
wide choice */
- down(&qcam->lock);
+ mutex_lock(&qcam->lock);
parport_claim_or_block(qcam->pdev);
qc_setup(qcam);
parport_release(qcam->pdev);
- up(&qcam->lock);
+ mutex_unlock(&qcam->lock);
return 0;
}
case VIDIOCGWIN:
@@ -672,12 +673,12 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
struct qcam_device *qcam=(struct qcam_device *)v;
int len;
- down(&qcam->lock);
+ mutex_lock(&qcam->lock);
parport_claim_or_block(qcam->pdev);
/* Probably should have a semaphore against multiple users */
len = qc_capture(qcam, buf,count);
parport_release(qcam->pdev);
- up(&qcam->lock);
+ mutex_unlock(&qcam->lock);
return len;
}
@@ -727,7 +728,7 @@ static struct qcam_device *qcam_init(struct parport *port)
memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
- init_MUTEX(&q->lock);
+ mutex_init(&q->lock);
q->width = q->ccd_width = 320;
q->height = q->ccd_height = 240;
q->mode = QC_MILLIONS | QC_DECIMATION_1;
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
index 85d964b5b33..d93a561e6b8 100644
--- a/drivers/media/video/cpia.c
+++ b/drivers/media/video/cpia.c
@@ -39,7 +39,7 @@
#include <linux/pagemap.h>
#include <linux/delay.h>
#include <asm/io.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
@@ -622,7 +622,7 @@ static int cpia_write_proc(struct file *file, const char __user *buf,
buffer = page;
- if (down_interruptible(&cam->param_lock))
+ if (mutex_lock_interruptible(&cam->param_lock))
return -ERESTARTSYS;
/*
@@ -1350,7 +1350,7 @@ static int cpia_write_proc(struct file *file, const char __user *buf,
} else
DBG("error: %d\n", retval);
- up(&cam->param_lock);
+ mutex_unlock(&cam->param_lock);
out:
free_page((unsigned long)page);
@@ -1664,7 +1664,7 @@ static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
case CPIA_COMMAND_GetColourParams:
case CPIA_COMMAND_GetColourBalance:
case CPIA_COMMAND_GetExposure:
- down(&cam->param_lock);
+ mutex_lock(&cam->param_lock);
datasize=8;
break;
case CPIA_COMMAND_ReadMCPorts:
@@ -1691,7 +1691,7 @@ static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
if (command == CPIA_COMMAND_GetColourParams ||
command == CPIA_COMMAND_GetColourBalance ||
command == CPIA_COMMAND_GetExposure)
- up(&cam->param_lock);
+ mutex_unlock(&cam->param_lock);
} else {
switch(command) {
case CPIA_COMMAND_GetCPIAVersion:
@@ -1726,13 +1726,13 @@ static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
cam->params.colourParams.brightness = data[0];
cam->params.colourParams.contrast = data[1];
cam->params.colourParams.saturation = data[2];
- up(&cam->param_lock);
+ mutex_unlock(&cam->param_lock);
break;
case CPIA_COMMAND_GetColourBalance:
cam->params.colourBalance.redGain = data[0];
cam->params.colourBalance.greenGain = data[1];
cam->params.colourBalance.blueGain = data[2];
- up(&cam->param_lock);
+ mutex_unlock(&cam->param_lock);
break;
case CPIA_COMMAND_GetExposure:
cam->params.exposure.gain = data[0];
@@ -1743,7 +1743,7 @@ static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
cam->params.exposure.green1Comp = data[5];
cam->params.exposure.green2Comp = data[6];
cam->params.exposure.blueComp = data[7];
- up(&cam->param_lock);
+ mutex_unlock(&cam->param_lock);
break;
case CPIA_COMMAND_ReadMCPorts:
@@ -2059,7 +2059,7 @@ static int parse_picture(struct cam_data *cam, int size)
int rows, cols, linesize, subsample_422;
/* make sure params don't change while we are decoding */
- down(&cam->param_lock);
+ mutex_lock(&cam->param_lock);
obuf = cam->decompressed_frame.data;
end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
@@ -2069,26 +2069,26 @@ static int parse_picture(struct cam_data *cam, int size)
if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
LOG("header not found\n");
- up(&cam->param_lock);
+ mutex_unlock(&cam->param_lock);
return -1;
}
if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
LOG("wrong video size\n");
- up(&cam->param_lock);
+ mutex_unlock(&cam->param_lock);
return -1;
}
if (ibuf[17] != SUBSAMPLE_420 && ibuf[17] != SUBSAMPLE_422) {
LOG("illegal subtype %d\n",ibuf[17]);
- up(&cam->param_lock);
+ mutex_unlock(&cam->param_lock);
return -1;
}
subsample_422 = ibuf[17] == SUBSAMPLE_422;
if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
LOG("illegal yuvorder %d\n",ibuf[18]);
- up(&cam->param_lock);
+ mutex_unlock(&cam->param_lock);
return -1;
}
in_uyvy = ibuf[18] == YUVORDER_UYVY;
@@ -2098,7 +2098,7 @@ static int parse_picture(struct cam_data *cam, int size)
(ibuf[26] != cam->params.roi.rowStart) ||
(ibuf[27] != cam->params.roi.rowEnd)) {
LOG("ROI mismatch\n");
- up(&cam->param_lock);
+ mutex_unlock(&cam->param_lock);
return -1;
}
cols = 8*(ibuf[25] - ibuf[24]);
@@ -2107,14 +2107,14 @@ static int parse_picture(struct cam_data *cam, int size)
if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
LOG("illegal compression %d\n",ibuf[28]);
- up(&cam->param_lock);
+ mutex_unlock(&cam->param_lock);
return -1;
}
compressed = (ibuf[28] == COMPRESSED);
if (ibuf[29] != NO_DECIMATION && ibuf[29] != DECIMATION_ENAB) {
LOG("illegal decimation %d\n",ibuf[29]);
- up(&cam->param_lock);
+ mutex_unlock(&cam->param_lock);
return -1;
}
decimation = (ibuf[29] == DECIMATION_ENAB);
@@ -2130,7 +2130,7 @@ static int parse_picture(struct cam_data *cam, int size)
cam->params.status.vpStatus = ibuf[38];
cam->params.status.errorCode = ibuf[39];
cam->fps = ibuf[41];
- up(&cam->param_lock);
+ mutex_unlock(&cam->param_lock);
linesize = skipcount(cols, out_fmt);
ibuf += FRAME_HEADER_SIZE;
@@ -2271,9 +2271,9 @@ static int find_over_exposure(int brightness)
/* update various camera modes and settings */
static void dispatch_commands(struct cam_data *cam)
{
- down(&cam->param_lock);
+ mutex_lock(&cam->param_lock);
if (cam->cmd_queue==COMMAND_NONE) {
- up(&cam->param_lock);
+ mutex_unlock(&cam->param_lock);
return;
}
DEB_BYTE(cam->cmd_queue);
@@ -2415,7 +2415,7 @@ static void dispatch_commands(struct cam_data *cam)
}
cam->cmd_queue = COMMAND_NONE;
- up(&cam->param_lock);
+ mutex_unlock(&cam->param_lock);
return;
}
@@ -2562,7 +2562,7 @@ static void monitor_exposure(struct cam_data *cam)
gain = data[2];
coarseL = data[3];
- down(&cam->param_lock);
+ mutex_lock(&cam->param_lock);
light_exp = cam->params.colourParams.brightness +
TC - 50 + EXP_ACC_LIGHT;
if(light_exp > 255)
@@ -2762,7 +2762,7 @@ static void monitor_exposure(struct cam_data *cam)
LOG("Automatically increasing sensor_fps\n");
}
}
- up(&cam->param_lock);
+ mutex_unlock(&cam->param_lock);
}
/*-----------------------------------------------------------------*/
@@ -2778,10 +2778,10 @@ static void restart_flicker(struct cam_data *cam)
int cam_exposure, old_exp;
if(!FIRMWARE_VERSION(1,2))
return;
- down(&cam->param_lock);
+ mutex_lock(&cam->param_lock);
if(cam->params.flickerControl.flickerMode == 0 ||
cam->raw_image[39] == 0) {
- up(&cam->param_lock);
+ mutex_unlock(&cam->param_lock);
return;
}
cam_exposure = cam->raw_image[39]*2;
@@ -2810,7 +2810,7 @@ static void restart_flicker(struct cam_data *cam)
cam->exposure_status = EXPOSURE_NORMAL;
}
- up(&cam->param_lock);
+ mutex_unlock(&cam->param_lock);
}
#undef FIRMWARE_VERSION
@@ -3186,7 +3186,7 @@ static int cpia_open(struct inode *inode, struct file *file)
if (!try_module_get(cam->ops->owner))
return -ENODEV;
- down(&cam->busy_lock);
+ mutex_lock(&cam->busy_lock);
err = -ENOMEM;
if (!cam->raw_image) {
cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
@@ -3227,7 +3227,7 @@ static int cpia_open(struct inode *inode, struct file *file)
++cam->open_count;
file->private_data = dev;
- up(&cam->busy_lock);
+ mutex_unlock(&cam->busy_lock);
return 0;
oops:
@@ -3239,7 +3239,7 @@ static int cpia_open(struct inode *inode, struct file *file)
rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
cam->raw_image = NULL;
}
- up(&cam->busy_lock);
+ mutex_unlock(&cam->busy_lock);
put_cam(cam->ops);
return err;
}
@@ -3303,24 +3303,24 @@ static ssize_t cpia_read(struct file *file, char __user *buf,
int err;
/* make this _really_ smp and multithread-safe */
- if (down_interruptible(&cam->busy_lock))
+ if (mutex_lock_interruptible(&cam->busy_lock))
return -EINTR;
if (!buf) {
DBG("buf NULL\n");
- up(&cam->busy_lock);
+ mutex_unlock(&cam->busy_lock);
return -EINVAL;
}
if (!count) {
DBG("count 0\n");
- up(&cam->busy_lock);
+ mutex_unlock(&cam->busy_lock);
return 0;
}
if (!cam->ops) {
DBG("ops NULL\n");
- up(&cam->busy_lock);
+ mutex_unlock(&cam->busy_lock);
return -ENODEV;
}
@@ -3329,7 +3329,7 @@ static ssize_t cpia_read(struct file *file, char __user *buf,
cam->mmap_kludge=0;
if((err = fetch_frame(cam)) != 0) {
DBG("ERROR from fetch_frame: %d\n", err);
- up(&cam->busy_lock);
+ mutex_unlock(&cam->busy_lock);
return err;
}
cam->decompressed_frame.state = FRAME_UNUSED;
@@ -3338,17 +3338,17 @@ static ssize_t cpia_read(struct file *file, char __user *buf,
if (cam->decompressed_frame.count > count) {
DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
(unsigned long) count);
- up(&cam->busy_lock);
+ mutex_unlock(&cam->busy_lock);
return -EFAULT;
}
if (copy_to_user(buf, cam->decompressed_frame.data,
cam->decompressed_frame.count)) {
DBG("copy_to_user failed\n");
- up(&cam->busy_lock);
+ mutex_unlock(&cam->busy_lock);
return -EFAULT;
}
- up(&cam->busy_lock);
+ mutex_unlock(&cam->busy_lock);
return cam->decompressed_frame.count;
}
@@ -3363,7 +3363,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
return -ENODEV;
/* make this _really_ smp-safe */
- if (down_interruptible(&cam->busy_lock))
+ if (mutex_lock_interruptible(&cam->busy_lock))
return -EINTR;
//DBG("cpia_ioctl: %u\n", ioctlnr);
@@ -3439,7 +3439,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
break;
}
- down(&cam->param_lock);
+ mutex_lock(&cam->param_lock);
/* brightness, colour, contrast need no check 0-65535 */
cam->vp = *vp;
/* update cam->params.colourParams */
@@ -3466,7 +3466,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
/* queue command to update camera */
cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
- up(&cam->param_lock);
+ mutex_unlock(&cam->param_lock);
DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
vp->depth, vp->palette, vp->brightness, vp->hue, vp->colour,
vp->contrast);
@@ -3501,13 +3501,13 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
/* we set the video window to something smaller or equal to what
* is requested by the user???
*/
- down(&cam->param_lock);
+ mutex_lock(&cam->param_lock);
if (vw->width != cam->vw.width || vw->height != cam->vw.height) {
int video_size = match_videosize(vw->width, vw->height);
if (video_size < 0) {
retval = -EINVAL;
- up(&cam->param_lock);
+ mutex_unlock(&cam->param_lock);
break;
}
cam->video_size = video_size;
@@ -3520,7 +3520,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
cam->cmd_queue |= COMMAND_SETFORMAT;
}
- up(&cam->param_lock);
+ mutex_unlock(&cam->param_lock);
/* setformat ignored by camera during streaming,
* so stop/dispatch/start */
@@ -3682,7 +3682,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
DBG("%d,%d/%dx%d\n", vc->x,vc->y,vc->width, vc->height);
- down(&cam->param_lock);
+ mutex_lock(&cam->param_lock);
cam->vc.x = vc->x;
cam->vc.y = vc->y;
@@ -3692,7 +3692,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
set_vw_size(cam);
cam->cmd_queue |= COMMAND_SETFORMAT;
- up(&cam->param_lock);
+ mutex_unlock(&cam->param_lock);
/* setformat ignored by camera during streaming,
* so stop/dispatch/start */
@@ -3736,7 +3736,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
break;
}
- up(&cam->busy_lock);
+ mutex_unlock(&cam->busy_lock);
return retval;
}
@@ -3769,12 +3769,12 @@ static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
return -ENODEV;
/* make this _really_ smp-safe */
- if (down_interruptible(&cam->busy_lock))
+ if (mutex_lock_interruptible(&cam->busy_lock))
return -EINTR;
if (!cam->frame_buf) { /* we do lazy allocation */
if ((retval = allocate_frame_buf(cam))) {
- up(&cam->busy_lock);
+ mutex_unlock(&cam->busy_lock);
return retval;
}
}
@@ -3783,7 +3783,7 @@ static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
while (size > 0) {
page = vmalloc_to_pfn((void *)pos);
if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
- up(&cam->busy_lock);
+ mutex_unlock(&cam->busy_lock);
return -EAGAIN;
}
start += PAGE_SIZE;
@@ -3795,7 +3795,7 @@ static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
}
DBG("cpia_mmap: %ld\n", size);
- up(&cam->busy_lock);
+ mutex_unlock(&cam->busy_lock);
return 0;
}
@@ -3936,8 +3936,8 @@ static void init_camera_struct(struct cam_data *cam,
memset(cam, 0, sizeof(struct cam_data));
cam->ops = ops;
- init_MUTEX(&cam->param_lock);
- init_MUTEX(&cam->busy_lock);
+ mutex_init(&cam->param_lock);
+ mutex_init(&cam->busy_lock);
reset_camera_struct(cam);
diff --git a/drivers/media/video/cpia.h b/drivers/media/video/cpia.h
index f629b693ee6..de6678200a5 100644
--- a/drivers/media/video/cpia.h
+++ b/drivers/media/video/cpia.h
@@ -47,6 +47,7 @@
#include <linux/videodev.h>
#include <linux/list.h>
#include <linux/smp_lock.h>
+#include <linux/mutex.h>
struct cpia_camera_ops
{
@@ -246,7 +247,7 @@ enum v4l_camstates {
struct cam_data {
struct list_head cam_data_list;
- struct semaphore busy_lock; /* guard against SMP multithreading */
+ struct mutex busy_lock; /* guard against SMP multithreading */
struct cpia_camera_ops *ops; /* lowlevel driver operations */
void *lowlevel_data; /* private data for lowlevel driver */
u8 *raw_image; /* buffer for raw image data */
@@ -261,7 +262,7 @@ struct cam_data {
u8 mainsFreq; /* for flicker control */
/* proc interface */
- struct semaphore param_lock; /* params lock for this camera */
+ struct mutex param_lock; /* params lock for this camera */
struct cam_params params; /* camera settings */
struct proc_dir_entry *proc_entry; /* /proc/cpia/videoX */
diff --git a/drivers/media/video/cpia2/Kconfig b/drivers/media/video/cpia2/Kconfig
new file mode 100644
index 00000000000..513cc092738
--- /dev/null
+++ b/drivers/media/video/cpia2/Kconfig
@@ -0,0 +1,9 @@
+config VIDEO_CPIA2
+ tristate "CPiA2 Video For Linux"
+ depends on VIDEO_DEV && USB
+ ---help---
+ This is the video4linux driver for cameras based on Vision's CPiA2
+ (Colour Processor Interface ASIC), such as the Digital Blue QX5
+ Microscope. If you have one of these cameras, say Y here
+
+ This driver is also available as a module (cpia2).
diff --git a/drivers/media/video/cpia2/Makefile b/drivers/media/video/cpia2/Makefile
new file mode 100644
index 00000000000..828cf1b1df8
--- /dev/null
+++ b/drivers/media/video/cpia2/Makefile
@@ -0,0 +1,3 @@
+cpia2-objs := cpia2_v4l.o cpia2_usb.o cpia2_core.o
+
+obj-$(CONFIG_VIDEO_CPIA2) += cpia2.o
diff --git a/drivers/media/video/cpia2/cpia2.h b/drivers/media/video/cpia2/cpia2.h
new file mode 100644
index 00000000000..95d3afa94a3
--- /dev/null
+++ b/drivers/media/video/cpia2/cpia2.h
@@ -0,0 +1,497 @@
+/****************************************************************************
+ *
+ * Filename: cpia2.h
+ *
+ * Copyright 2001, STMicrolectronics, Inc.
+ *
+ * Contact: steve.miller@st.com
+ *
+ * Description:
+ * This is a USB driver for CPiA2 based video cameras.
+ *
+ * This driver is modelled on the cpia usb driver by
+ * Jochen Scharrlach and Johannes Erdfeldt.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ****************************************************************************/
+
+#ifndef __CPIA2_H__
+#define __CPIA2_H__
+
+#include <linux/version.h>
+#include <linux/videodev.h>
+#include <linux/usb.h>
+#include <linux/poll.h>
+
+#include "cpia2dev.h"
+#include "cpia2_registers.h"
+
+/* define for verbose debug output */
+//#define _CPIA2_DEBUG_
+
+#define CPIA2_MAJ_VER 2
+#define CPIA2_MIN_VER 0
+#define CPIA2_PATCH_VER 0
+
+/***
+ * Image defines
+ ***/
+#ifndef true
+#define true 1
+#define false 0
+#endif
+
+/* Misc constants */
+#define ALLOW_CORRUPT 0 /* Causes collater to discard checksum */
+
+/* USB Transfer mode */
+#define XFER_ISOC 0
+#define XFER_BULK 1
+
+/* USB Alternates */
+#define USBIF_CMDONLY 0
+#define USBIF_BULK 1
+#define USBIF_ISO_1 2 /* 128 bytes/ms */
+#define USBIF_ISO_2 3 /* 384 bytes/ms */
+#define USBIF_ISO_3 4 /* 640 bytes/ms */
+#define USBIF_ISO_4 5 /* 768 bytes/ms */
+#define USBIF_ISO_5 6 /* 896 bytes/ms */
+#define USBIF_ISO_6 7 /* 1023 bytes/ms */
+
+/* Flicker Modes */
+#define NEVER_FLICKER 0
+#define ANTI_FLICKER_ON 1
+#define FLICKER_60 60
+#define FLICKER_50 50
+
+/* Debug flags */
+#define DEBUG_NONE 0
+#define DEBUG_REG 0x00000001
+#define DEBUG_DUMP_PATCH 0x00000002
+#define DEBUG_DUMP_REGS 0x00000004
+
+/***
+ * Video frame sizes
+ ***/
+enum {
+ VIDEOSIZE_VGA = 0, /* 640x480 */
+ VIDEOSIZE_CIF, /* 352x288 */
+ VIDEOSIZE_QVGA, /* 320x240 */
+ VIDEOSIZE_QCIF, /* 176x144 */
+ VIDEOSIZE_288_216,
+ VIDEOSIZE_256_192,
+ VIDEOSIZE_224_168,
+ VIDEOSIZE_192_144,
+};
+
+#define STV_IMAGE_CIF_ROWS 288
+#define STV_IMAGE_CIF_COLS 352
+
+#define STV_IMAGE_QCIF_ROWS 144
+#define STV_IMAGE_QCIF_COLS 176
+
+#define STV_IMAGE_VGA_ROWS 480
+#define STV_IMAGE_VGA_COLS 640
+
+#define STV_IMAGE_QVGA_ROWS 240
+#define STV_IMAGE_QVGA_COLS 320
+
+#define JPEG_MARKER_COM (1<<6) /* Comment segment */
+
+/***
+ * Enums
+ ***/
+/* Sensor types available with cpia2 asics */
+enum sensors {
+ CPIA2_SENSOR_410,
+ CPIA2_SENSOR_500
+};
+
+/* Asic types available in the CPiA2 architecture */
+#define CPIA2_ASIC_672 0x67
+
+/* Device types (stv672, stv676, etc) */
+#define DEVICE_STV_672 0x0001
+#define DEVICE_STV_676 0x0002
+
+enum frame_status {
+ FRAME_EMPTY,
+ FRAME_READING, /* In the process of being grabbed into */
+ FRAME_READY, /* Ready to be read */
+ FRAME_ERROR,
+};
+
+/***
+ * Register access (for USB request byte)
+ ***/
+enum {
+ CAMERAACCESS_SYSTEM = 0,
+ CAMERAACCESS_VC,
+ CAMERAACCESS_VP,
+ CAMERAACCESS_IDATA
+};
+
+#define CAMERAACCESS_TYPE_BLOCK 0x00
+#define CAMERAACCESS_TYPE_RANDOM 0x04
+#define CAMERAACCESS_TYPE_MASK 0x08
+#define CAMERAACCESS_TYPE_REPEAT 0x0C
+
+#define TRANSFER_READ 0
+#define TRANSFER_WRITE 1
+
+#define DEFAULT_ALT USBIF_ISO_6
+#define DEFAULT_BRIGHTNESS 0x46
+#define DEFAULT_CONTRAST 0x93
+#define DEFAULT_SATURATION 0x7f
+#define DEFAULT_TARGET_KB 0x30
+
+/* Power state */
+#define HI_POWER_MODE CPIA2_SYSTEM_CONTROL_HIGH_POWER
+#define LO_POWER_MODE CPIA2_SYSTEM_CONTROL_LOW_POWER
+
+
+/********
+ * Commands
+ *******/
+enum {
+ CPIA2_CMD_NONE = 0,
+ CPIA2_CMD_GET_VERSION,
+ CPIA2_CMD_GET_PNP_ID,
+ CPIA2_CMD_GET_ASIC_TYPE,
+ CPIA2_CMD_GET_SENSOR,
+ CPIA2_CMD_GET_VP_DEVICE,
+ CPIA2_CMD_GET_VP_BRIGHTNESS,
+ CPIA2_CMD_SET_VP_BRIGHTNESS,
+ CPIA2_CMD_GET_CONTRAST,
+ CPIA2_CMD_SET_CONTRAST,
+ CPIA2_CMD_GET_VP_SATURATION,
+ CPIA2_CMD_SET_VP_SATURATION,
+ CPIA2_CMD_GET_VP_GPIO_DIRECTION,
+ CPIA2_CMD_SET_VP_GPIO_DIRECTION,
+ CPIA2_CMD_GET_VP_GPIO_DATA,
+ CPIA2_CMD_SET_VP_GPIO_DATA,
+ CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION,
+ CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
+ CPIA2_CMD_GET_VC_MP_GPIO_DATA,
+ CPIA2_CMD_SET_VC_MP_GPIO_DATA,
+ CPIA2_CMD_ENABLE_PACKET_CTRL,
+ CPIA2_CMD_GET_FLICKER_MODES,
+ CPIA2_CMD_SET_FLICKER_MODES,
+ CPIA2_CMD_RESET_FIFO, /* clear fifo and enable stream block */
+ CPIA2_CMD_SET_HI_POWER,
+ CPIA2_CMD_SET_LOW_POWER,
+ CPIA2_CMD_CLEAR_V2W_ERR,
+ CPIA2_CMD_SET_USER_MODE,
+ CPIA2_CMD_GET_USER_MODE,
+ CPIA2_CMD_FRAMERATE_REQ,
+ CPIA2_CMD_SET_COMPRESSION_STATE,
+ CPIA2_CMD_GET_WAKEUP,
+ CPIA2_CMD_SET_WAKEUP,
+ CPIA2_CMD_GET_PW_CONTROL,
+ CPIA2_CMD_SET_PW_CONTROL,
+ CPIA2_CMD_GET_SYSTEM_CTRL,
+ CPIA2_CMD_SET_SYSTEM_CTRL,
+ CPIA2_CMD_GET_VP_SYSTEM_STATE,
+ CPIA2_CMD_GET_VP_SYSTEM_CTRL,
+ CPIA2_CMD_SET_VP_SYSTEM_CTRL,
+ CPIA2_CMD_GET_VP_EXP_MODES,
+ CPIA2_CMD_SET_VP_EXP_MODES,
+ CPIA2_CMD_GET_DEVICE_CONFIG,
+ CPIA2_CMD_SET_DEVICE_CONFIG,
+ CPIA2_CMD_SET_SERIAL_ADDR,
+ CPIA2_CMD_SET_SENSOR_CR1,
+ CPIA2_CMD_GET_VC_CONTROL,
+ CPIA2_CMD_SET_VC_CONTROL,
+ CPIA2_CMD_SET_TARGET_KB,
+ CPIA2_CMD_SET_DEF_JPEG_OPT,
+ CPIA2_CMD_REHASH_VP4,
+ CPIA2_CMD_GET_USER_EFFECTS,
+ CPIA2_CMD_SET_USER_EFFECTS
+};
+
+enum user_cmd {
+ COMMAND_NONE = 0x00000001,
+ COMMAND_SET_FPS = 0x00000002,
+ COMMAND_SET_COLOR_PARAMS = 0x00000004,
+ COMMAND_GET_COLOR_PARAMS = 0x00000008,
+ COMMAND_SET_FORMAT = 0x00000010, /* size, etc */
+ COMMAND_SET_FLICKER = 0x00000020
+};
+
+/***
+ * Some defines specific to the 676 chip
+ ***/
+#define CAMACC_CIF 0x01
+#define CAMACC_VGA 0x02
+#define CAMACC_QCIF 0x04
+#define CAMACC_QVGA 0x08
+
+
+struct cpia2_register {
+ u8 index;
+ u8 value;
+};
+
+struct cpia2_reg_mask {
+ u8 index;
+ u8 and_mask;
+ u8 or_mask;
+ u8 fill;
+};
+
+struct cpia2_command {
+ u32 command;
+ u8 req_mode; /* (Block or random) | registerBank */
+ u8 reg_count;
+ u8 direction;
+ u8 start;
+ union reg_types {
+ struct cpia2_register registers[32];
+ struct cpia2_reg_mask masks[16];
+ u8 block_data[64];
+ u8 *patch_data; /* points to function defined block */
+ } buffer;
+};
+
+struct camera_params {
+ struct {
+ u8 firmware_revision_hi; /* For system register set (bank 0) */
+ u8 firmware_revision_lo;
+ u8 asic_id; /* Video Compressor set (bank 1) */
+ u8 asic_rev;
+ u8 vp_device_hi; /* Video Processor set (bank 2) */
+ u8 vp_device_lo;
+ u8 sensor_flags;
+ u8 sensor_rev;
+ } version;
+
+ struct {
+ u32 device_type; /* enumerated from vendor/product ids.
+ * Currently, either STV_672 or STV_676 */
+ u16 vendor;
+ u16 product;
+ u16 device_revision;
+ } pnp_id;
+
+ struct {
+ u8 brightness; /* CPIA2_VP_EXPOSURE_TARGET */
+ u8 contrast; /* Note: this is CPIA2_VP_YRANGE */
+ u8 saturation; /* CPIA2_VP_SATURATION */
+ } color_params;
+
+ struct {
+ u8 cam_register;
+ u8 flicker_mode_req; /* 1 if flicker on, else never flicker */
+ int mains_frequency;
+ } flicker_control;
+
+ struct {
+ u8 jpeg_options;
+ u8 creep_period;
+ u8 user_squeeze;
+ u8 inhibit_htables;
+ } compression;
+
+ struct {
+ u8 ohsize; /* output image size */
+ u8 ovsize;
+ u8 hcrop; /* cropping start_pos/4 */
+ u8 vcrop;
+ u8 hphase; /* scaling registers */
+ u8 vphase;
+ u8 hispan;
+ u8 vispan;
+ u8 hicrop;
+ u8 vicrop;
+ u8 hifraction;
+ u8 vifraction;
+ } image_size;
+
+ struct {
+ int width; /* actual window width */
+ int height; /* actual window height */
+ } roi;
+
+ struct {
+ u8 video_mode;
+ u8 frame_rate;
+ u8 video_size; /* Not a register, just a convenience for cropped sizes */
+ u8 gpio_direction;
+ u8 gpio_data;
+ u8 system_ctrl;
+ u8 system_state;
+ u8 lowlight_boost; /* Bool: 0 = off, 1 = on */
+ u8 device_config;
+ u8 exposure_modes;
+ u8 user_effects;
+ } vp_params;
+
+ struct {
+ u8 pw_control;
+ u8 wakeup;
+ u8 vc_control;
+ u8 vc_mp_direction;
+ u8 vc_mp_data;
+ u8 target_kb;
+ } vc_params;
+
+ struct {
+ u8 power_mode;
+ u8 system_ctrl;
+ u8 stream_mode; /* This is the current alternate for usb drivers */
+ u8 allow_corrupt;
+ } camera_state;
+};
+
+#define NUM_SBUF 2
+
+struct cpia2_sbuf {
+ char *data;
+ struct urb *urb;
+};
+
+struct framebuf {
+ struct timeval timestamp;
+ unsigned long seq;
+ int num;
+ int length;
+ int max_length;
+ volatile enum frame_status status;
+ u8 *data;
+ struct framebuf *next;
+};
+
+struct cpia2_fh {
+ enum v4l2_priority prio;
+ u8 mmapped;
+};
+
+struct camera_data {
+ /* locks */
+ struct semaphore busy_lock; /* guard against SMP multithreading */
+ struct v4l2_prio_state prio;
+
+ /* camera status */
+ volatile int present; /* Is the camera still present? */
+ int open_count; /* # of process that have camera open */
+ int first_image_seen;
+ u8 mains_freq; /* for flicker control */
+ enum sensors sensor_type;
+ u8 flush;
+ u8 mmapped;
+ int streaming; /* 0 = no, 1 = yes */
+ int xfer_mode; /* XFER_BULK or XFER_ISOC */
+ struct camera_params params; /* camera settings */
+
+ /* v4l */
+ int video_size; /* VIDEO_SIZE_ */
+ struct video_device *vdev; /* v4l videodev */
+ struct video_picture vp; /* v4l camera settings */
+ struct video_window vw; /* v4l capture area */
+ __u32 pixelformat; /* Format fourcc */
+
+ /* USB */
+ struct usb_device *dev;
+ unsigned char iface;
+ unsigned int cur_alt;
+ unsigned int old_alt;
+ struct cpia2_sbuf sbuf[NUM_SBUF]; /* Double buffering */
+
+ wait_queue_head_t wq_stream;
+
+ /* Buffering */
+ u32 frame_size;
+ int num_frames;
+ unsigned long frame_count;
+ u8 *frame_buffer; /* frame buffer data */
+ struct framebuf *buffers;
+ struct framebuf * volatile curbuff;
+ struct framebuf *workbuff;
+
+ /* MJPEG Extension */
+ int APPn; /* Number of APP segment to be written, must be 0..15 */
+ int APP_len; /* Length of data in JPEG APPn segment */
+ char APP_data[60]; /* Data in the JPEG APPn segment. */
+
+ int COM_len; /* Length of data in JPEG COM segment */
+ char COM_data[60]; /* Data in JPEG COM segment */
+};
+
+/* v4l */
+int cpia2_register_camera(struct camera_data *cam);
+void cpia2_unregister_camera(struct camera_data *cam);
+
+/* core */
+int cpia2_reset_camera(struct camera_data *cam);
+int cpia2_set_low_power(struct camera_data *cam);
+void cpia2_dbg_dump_registers(struct camera_data *cam);
+int cpia2_match_video_size(int width, int height);
+void cpia2_set_camera_state(struct camera_data *cam);
+void cpia2_save_camera_state(struct camera_data *cam);
+void cpia2_set_color_params(struct camera_data *cam);
+void cpia2_set_brightness(struct camera_data *cam, unsigned char value);
+void cpia2_set_contrast(struct camera_data *cam, unsigned char value);
+void cpia2_set_saturation(struct camera_data *cam, unsigned char value);
+int cpia2_set_flicker_mode(struct camera_data *cam, int mode);
+void cpia2_set_format(struct camera_data *cam);
+int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd);
+int cpia2_do_command(struct camera_data *cam,
+ unsigned int command,
+ unsigned char direction, unsigned char param);
+struct camera_data *cpia2_init_camera_struct(void);
+int cpia2_init_camera(struct camera_data *cam);
+int cpia2_allocate_buffers(struct camera_data *cam);
+void cpia2_free_buffers(struct camera_data *cam);
+long cpia2_read(struct camera_data *cam,
+ char *buf, unsigned long count, int noblock);
+unsigned int cpia2_poll(struct camera_data *cam,
+ struct file *filp, poll_table *wait);
+int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma);
+void cpia2_set_property_flip(struct camera_data *cam, int prop_val);
+void cpia2_set_property_mirror(struct camera_data *cam, int prop_val);
+int cpia2_set_target_kb(struct camera_data *cam, unsigned char value);
+int cpia2_set_gpio(struct camera_data *cam, unsigned char setting);
+int cpia2_set_fps(struct camera_data *cam, int framerate);
+
+/* usb */
+int cpia2_usb_init(void);
+void cpia2_usb_cleanup(void);
+int cpia2_usb_transfer_cmd(struct camera_data *cam, void *registers,
+ u8 request, u8 start, u8 count, u8 direction);
+int cpia2_usb_stream_start(struct camera_data *cam, unsigned int alternate);
+int cpia2_usb_stream_stop(struct camera_data *cam);
+int cpia2_usb_stream_pause(struct camera_data *cam);
+int cpia2_usb_stream_resume(struct camera_data *cam);
+int cpia2_usb_change_streaming_alternate(struct camera_data *cam,
+ unsigned int alt);
+
+
+/* ----------------------- debug functions ---------------------- */
+#ifdef _CPIA2_DEBUG_
+#define ALOG(lev, fmt, args...) printk(lev "%s:%d %s(): " fmt, __FILE__, __LINE__, __func__, ## args)
+#define LOG(fmt, args...) ALOG(KERN_INFO, fmt, ## args)
+#define ERR(fmt, args...) ALOG(KERN_ERR, fmt, ## args)
+#define DBG(fmt, args...) ALOG(KERN_DEBUG, fmt, ## args)
+#else
+#define ALOG(fmt,args...) printk(fmt,##args)
+#define LOG(fmt,args...) ALOG(KERN_INFO "cpia2: "fmt,##args)
+#define ERR(fmt,args...) ALOG(KERN_ERR "cpia2: "fmt,##args)
+#define DBG(fmn,args...) do {} while(0)
+#endif
+/* No function or lineno, for shorter lines */
+#define KINFO(fmt, args...) printk(KERN_INFO fmt,##args)
+
+#endif
diff --git a/drivers/media/video/cpia2/cpia2_core.c b/drivers/media/video/cpia2/cpia2_core.c
new file mode 100644
index 00000000000..5dfb242d5b8
--- /dev/null
+++ b/drivers/media/video/cpia2/cpia2_core.c
@@ -0,0 +1,2525 @@
+/****************************************************************************
+ *
+ * Filename: cpia2_core.c
+ *
+ * Copyright 2001, STMicrolectronics, Inc.
+ * Contact: steve.miller@st.com
+ *
+ * Description:
+ * This is a USB driver for CPia2 based video cameras.
+ * The infrastructure of this driver is based on the cpia usb driver by
+ * Jochen Scharrlach and Johannes Erdfeldt.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Stripped of 2.4 stuff ready for main kernel submit by
+ * Alan Cox <alan@redhat.com>
+ *
+ ****************************************************************************/
+
+#include "cpia2.h"
+
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+//#define _CPIA2_DEBUG_
+
+#include "cpia2patch.h"
+
+#ifdef _CPIA2_DEBUG_
+
+static const char *block_name[] = {
+ "System",
+ "VC",
+ "VP",
+ "IDATA"
+};
+#endif
+
+static unsigned int debugs_on = 0;//DEBUG_REG;
+
+
+/******************************************************************************
+ *
+ * Forward Declarations
+ *
+ *****************************************************************************/
+static int apply_vp_patch(struct camera_data *cam);
+static int set_default_user_mode(struct camera_data *cam);
+static int set_vw_size(struct camera_data *cam, int size);
+static int configure_sensor(struct camera_data *cam,
+ int reqwidth, int reqheight);
+static int config_sensor_410(struct camera_data *cam,
+ int reqwidth, int reqheight);
+static int config_sensor_500(struct camera_data *cam,
+ int reqwidth, int reqheight);
+static int set_all_properties(struct camera_data *cam);
+static void get_color_params(struct camera_data *cam);
+static void wake_system(struct camera_data *cam);
+static void set_lowlight_boost(struct camera_data *cam);
+static void reset_camera_struct(struct camera_data *cam);
+static int cpia2_set_high_power(struct camera_data *cam);
+
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved.
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr)
+{
+ unsigned long kva, ret;
+
+ kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+ kva |= adr & (PAGE_SIZE-1); /* restore the offset */
+ ret = __pa(kva);
+ return ret;
+}
+
+static void *rvmalloc(unsigned long size)
+{
+ void *mem;
+ unsigned long adr;
+
+ /* Round it off to PAGE_SIZE */
+ size = PAGE_ALIGN(size);
+
+ mem = vmalloc_32(size);
+ if (!mem)
+ return NULL;
+
+ memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+ adr = (unsigned long) mem;
+
+ while ((long)size > 0) {
+ SetPageReserved(vmalloc_to_page((void *)adr));
+ adr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ return mem;
+}
+
+static void rvfree(void *mem, unsigned long size)
+{
+ unsigned long adr;
+
+ if (!mem)
+ return;
+
+ size = PAGE_ALIGN(size);
+
+ adr = (unsigned long) mem;
+ while ((long)size > 0) {
+ ClearPageReserved(vmalloc_to_page((void *)adr));
+ adr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ vfree(mem);
+}
+
+/******************************************************************************
+ *
+ * cpia2_do_command
+ *
+ * Send an arbitrary command to the camera. For commands that read from
+ * the camera, copy the buffers into the proper param structures.
+ *****************************************************************************/
+int cpia2_do_command(struct camera_data *cam,
+ u32 command, u8 direction, u8 param)
+{
+ int retval = 0;
+ struct cpia2_command cmd;
+ unsigned int device = cam->params.pnp_id.device_type;
+
+ cmd.command = command;
+ cmd.reg_count = 2; /* default */
+ cmd.direction = direction;
+
+ /***
+ * Set up the command.
+ ***/
+ switch (command) {
+ case CPIA2_CMD_GET_VERSION:
+ cmd.req_mode =
+ CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+ cmd.start = CPIA2_SYSTEM_DEVICE_HI;
+ break;
+ case CPIA2_CMD_GET_PNP_ID:
+ cmd.req_mode =
+ CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+ cmd.reg_count = 8;
+ cmd.start = CPIA2_SYSTEM_DESCRIP_VID_HI;
+ break;
+ case CPIA2_CMD_GET_ASIC_TYPE:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+ cmd.start = CPIA2_VC_ASIC_ID;
+ break;
+ case CPIA2_CMD_GET_SENSOR:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.start = CPIA2_VP_SENSOR_FLAGS;
+ break;
+ case CPIA2_CMD_GET_VP_DEVICE:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.start = CPIA2_VP_DEVICEH;
+ break;
+ case CPIA2_CMD_SET_VP_BRIGHTNESS:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_VP_BRIGHTNESS:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ if (device == DEVICE_STV_672)
+ cmd.start = CPIA2_VP4_EXPOSURE_TARGET;
+ else
+ cmd.start = CPIA2_VP5_EXPOSURE_TARGET;
+ break;
+ case CPIA2_CMD_SET_CONTRAST:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_CONTRAST:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VP_YRANGE;
+ break;
+ case CPIA2_CMD_SET_VP_SATURATION:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_VP_SATURATION:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ if (device == DEVICE_STV_672)
+ cmd.start = CPIA2_VP_SATURATION;
+ else
+ cmd.start = CPIA2_VP5_MCUVSATURATION;
+ break;
+ case CPIA2_CMD_SET_VP_GPIO_DATA:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_VP_GPIO_DATA:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VP_GPIO_DATA;
+ break;
+ case CPIA2_CMD_SET_VP_GPIO_DIRECTION:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_VP_GPIO_DIRECTION:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VP_GPIO_DIRECTION;
+ break;
+ case CPIA2_CMD_SET_VC_MP_GPIO_DATA:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_VC_MP_GPIO_DATA:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VC_MP_DATA;
+ break;
+ case CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VC_MP_DIR;
+ break;
+ case CPIA2_CMD_ENABLE_PACKET_CTRL:
+ cmd.req_mode =
+ CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+ cmd.start = CPIA2_SYSTEM_INT_PACKET_CTRL;
+ cmd.reg_count = 1;
+ cmd.buffer.block_data[0] = param;
+ break;
+ case CPIA2_CMD_SET_FLICKER_MODES:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_FLICKER_MODES:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VP_FLICKER_MODES;
+ break;
+ case CPIA2_CMD_RESET_FIFO: /* clear fifo and enable stream block */
+ cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+ cmd.reg_count = 2;
+ cmd.start = 0;
+ cmd.buffer.registers[0].index = CPIA2_VC_ST_CTRL;
+ cmd.buffer.registers[0].value = CPIA2_VC_ST_CTRL_SRC_VC |
+ CPIA2_VC_ST_CTRL_DST_USB | CPIA2_VC_ST_CTRL_EOF_DETECT;
+ cmd.buffer.registers[1].index = CPIA2_VC_ST_CTRL;
+ cmd.buffer.registers[1].value = CPIA2_VC_ST_CTRL_SRC_VC |
+ CPIA2_VC_ST_CTRL_DST_USB |
+ CPIA2_VC_ST_CTRL_EOF_DETECT |
+ CPIA2_VC_ST_CTRL_FIFO_ENABLE;
+ break;
+ case CPIA2_CMD_SET_HI_POWER:
+ cmd.req_mode =
+ CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_SYSTEM;
+ cmd.reg_count = 2;
+ cmd.buffer.registers[0].index =
+ CPIA2_SYSTEM_SYSTEM_CONTROL;
+ cmd.buffer.registers[1].index =
+ CPIA2_SYSTEM_SYSTEM_CONTROL;
+ cmd.buffer.registers[0].value = CPIA2_SYSTEM_CONTROL_CLEAR_ERR;
+ cmd.buffer.registers[1].value =
+ CPIA2_SYSTEM_CONTROL_HIGH_POWER;
+ break;
+ case CPIA2_CMD_SET_LOW_POWER:
+ cmd.req_mode =
+ CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL;
+ cmd.buffer.block_data[0] = 0;
+ break;
+ case CPIA2_CMD_CLEAR_V2W_ERR:
+ cmd.req_mode =
+ CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL;
+ cmd.buffer.block_data[0] = CPIA2_SYSTEM_CONTROL_CLEAR_ERR;
+ break;
+ case CPIA2_CMD_SET_USER_MODE: /* Then fall through */
+ cmd.buffer.block_data[0] = param;
+ case CPIA2_CMD_GET_USER_MODE:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ if (device == DEVICE_STV_672)
+ cmd.start = CPIA2_VP4_USER_MODE;
+ else
+ cmd.start = CPIA2_VP5_USER_MODE;
+ break;
+ case CPIA2_CMD_FRAMERATE_REQ:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ if (device == DEVICE_STV_672)
+ cmd.start = CPIA2_VP4_FRAMERATE_REQUEST;
+ else
+ cmd.start = CPIA2_VP5_FRAMERATE_REQUEST;
+ cmd.buffer.block_data[0] = param;
+ break;
+ case CPIA2_CMD_SET_WAKEUP:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_WAKEUP:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VC_WAKEUP;
+ break;
+ case CPIA2_CMD_SET_PW_CONTROL:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_PW_CONTROL:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VC_PW_CTRL;
+ break;
+ case CPIA2_CMD_GET_VP_SYSTEM_STATE:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VP_SYSTEMSTATE;
+ break;
+ case CPIA2_CMD_SET_SYSTEM_CTRL:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_SYSTEM_CTRL:
+ cmd.req_mode =
+ CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL;
+ break;
+ case CPIA2_CMD_SET_VP_SYSTEM_CTRL:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_VP_SYSTEM_CTRL:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VP_SYSTEMCTRL;
+ break;
+ case CPIA2_CMD_SET_VP_EXP_MODES:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_VP_EXP_MODES:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VP_EXPOSURE_MODES;
+ break;
+ case CPIA2_CMD_SET_DEVICE_CONFIG:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_DEVICE_CONFIG:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VP_DEVICE_CONFIG;
+ break;
+ case CPIA2_CMD_SET_SERIAL_ADDR:
+ cmd.buffer.block_data[0] = param;
+ cmd.req_mode =
+ CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_SYSTEM_VP_SERIAL_ADDR;
+ break;
+ case CPIA2_CMD_SET_SENSOR_CR1:
+ cmd.buffer.block_data[0] = param;
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_SENSOR_CR1;
+ break;
+ case CPIA2_CMD_SET_VC_CONTROL:
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_VC_CONTROL:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VC_VC_CTRL;
+ break;
+ case CPIA2_CMD_SET_TARGET_KB:
+ cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+ cmd.reg_count = 1;
+ cmd.buffer.registers[0].index = CPIA2_VC_VC_TARGET_KB;
+ cmd.buffer.registers[0].value = param;
+ break;
+ case CPIA2_CMD_SET_DEF_JPEG_OPT:
+ cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+ cmd.reg_count = 4;
+ cmd.buffer.registers[0].index = CPIA2_VC_VC_JPEG_OPT;
+ cmd.buffer.registers[0].value =
+ CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE;
+ cmd.buffer.registers[1].index = CPIA2_VC_VC_USER_SQUEEZE;
+ cmd.buffer.registers[1].value = 20;
+ cmd.buffer.registers[2].index = CPIA2_VC_VC_CREEP_PERIOD;
+ cmd.buffer.registers[2].value = 2;
+ cmd.buffer.registers[3].index = CPIA2_VC_VC_JPEG_OPT;
+ cmd.buffer.registers[3].value = CPIA2_VC_VC_JPEG_OPT_DEFAULT;
+ break;
+ case CPIA2_CMD_REHASH_VP4:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VP_REHASH_VALUES;
+ cmd.buffer.block_data[0] = param;
+ break;
+ case CPIA2_CMD_SET_USER_EFFECTS: /* Note: Be careful with this as
+ this register can also affect
+ flicker modes */
+ cmd.buffer.block_data[0] = param; /* Then fall through */
+ case CPIA2_CMD_GET_USER_EFFECTS:
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 1;
+ if (device == DEVICE_STV_672)
+ cmd.start = CPIA2_VP4_USER_EFFECTS;
+ else
+ cmd.start = CPIA2_VP5_USER_EFFECTS;
+ break;
+ default:
+ LOG("DoCommand received invalid command\n");
+ return -EINVAL;
+ }
+
+ retval = cpia2_send_command(cam, &cmd);
+ if (retval) {
+ return retval;
+ }
+
+ /***
+ * Now copy any results from a read into the appropriate param struct.
+ ***/
+ switch (command) {
+ case CPIA2_CMD_GET_VERSION:
+ cam->params.version.firmware_revision_hi =
+ cmd.buffer.block_data[0];
+ cam->params.version.firmware_revision_lo =
+ cmd.buffer.block_data[1];
+ break;
+ case CPIA2_CMD_GET_PNP_ID:
+ cam->params.pnp_id.vendor = (cmd.buffer.block_data[0] << 8) |
+ cmd.buffer.block_data[1];
+ cam->params.pnp_id.product = (cmd.buffer.block_data[2] << 8) |
+ cmd.buffer.block_data[3];
+ cam->params.pnp_id.device_revision =
+ (cmd.buffer.block_data[4] << 8) |
+ cmd.buffer.block_data[5];
+ if (cam->params.pnp_id.vendor == 0x553) {
+ if (cam->params.pnp_id.product == 0x100) {
+ cam->params.pnp_id.device_type = DEVICE_STV_672;
+ } else if (cam->params.pnp_id.product == 0x140 ||
+ cam->params.pnp_id.product == 0x151) {
+ cam->params.pnp_id.device_type = DEVICE_STV_676;
+ }
+ }
+ break;
+ case CPIA2_CMD_GET_ASIC_TYPE:
+ cam->params.version.asic_id = cmd.buffer.block_data[0];
+ cam->params.version.asic_rev = cmd.buffer.block_data[1];
+ break;
+ case CPIA2_CMD_GET_SENSOR:
+ cam->params.version.sensor_flags = cmd.buffer.block_data[0];
+ cam->params.version.sensor_rev = cmd.buffer.block_data[1];
+ break;
+ case CPIA2_CMD_GET_VP_DEVICE:
+ cam->params.version.vp_device_hi = cmd.buffer.block_data[0];
+ cam->params.version.vp_device_lo = cmd.buffer.block_data[1];
+ break;
+ case CPIA2_CMD_GET_VP_BRIGHTNESS:
+ cam->params.color_params.brightness = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_CONTRAST:
+ cam->params.color_params.contrast = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_VP_SATURATION:
+ cam->params.color_params.saturation = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_VP_GPIO_DATA:
+ cam->params.vp_params.gpio_data = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_VP_GPIO_DIRECTION:
+ cam->params.vp_params.gpio_direction = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION:
+ cam->params.vc_params.vc_mp_direction =cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_VC_MP_GPIO_DATA:
+ cam->params.vc_params.vc_mp_data = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_FLICKER_MODES:
+ cam->params.flicker_control.cam_register =
+ cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_WAKEUP:
+ cam->params.vc_params.wakeup = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_PW_CONTROL:
+ cam->params.vc_params.pw_control = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_SYSTEM_CTRL:
+ cam->params.camera_state.system_ctrl = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_VP_SYSTEM_STATE:
+ cam->params.vp_params.system_state = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_VP_SYSTEM_CTRL:
+ cam->params.vp_params.system_ctrl = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_VP_EXP_MODES:
+ cam->params.vp_params.exposure_modes = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_DEVICE_CONFIG:
+ cam->params.vp_params.device_config = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_VC_CONTROL:
+ cam->params.vc_params.vc_control = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_USER_MODE:
+ cam->params.vp_params.video_mode = cmd.buffer.block_data[0];
+ break;
+ case CPIA2_CMD_GET_USER_EFFECTS:
+ cam->params.vp_params.user_effects = cmd.buffer.block_data[0];
+ break;
+ default:
+ break;
+ }
+ return retval;
+}
+
+/******************************************************************************
+ *
+ * cpia2_send_command
+ *
+ *****************************************************************************/
+int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd)
+{
+ u8 count;
+ u8 start;
+ u8 block_index;
+ u8 *buffer;
+ int retval;
+ const char* dir;
+
+ if (cmd->direction == TRANSFER_WRITE) {
+ dir = "Write";
+ } else {
+ dir = "Read";
+ }
+
+ block_index = cmd->req_mode & 0x03;
+
+ switch (cmd->req_mode & 0x0c) {
+ case CAMERAACCESS_TYPE_RANDOM:
+ count = cmd->reg_count * sizeof(struct cpia2_register);
+ start = 0;
+ buffer = (u8 *) & cmd->buffer;
+ if (debugs_on & DEBUG_REG)
+ DBG("%s Random: Register block %s\n", dir,
+ block_name[block_index]);
+ break;
+ case CAMERAACCESS_TYPE_BLOCK:
+ count = cmd->reg_count;
+ start = cmd->start;
+ buffer = cmd->buffer.block_data;
+ if (debugs_on & DEBUG_REG)
+ DBG("%s Block: Register block %s\n", dir,
+ block_name[block_index]);
+ break;
+ case CAMERAACCESS_TYPE_MASK:
+ count = cmd->reg_count * sizeof(struct cpia2_reg_mask);
+ start = 0;
+ buffer = (u8 *) & cmd->buffer;
+ if (debugs_on & DEBUG_REG)
+ DBG("%s Mask: Register block %s\n", dir,
+ block_name[block_index]);
+ break;
+ case CAMERAACCESS_TYPE_REPEAT: /* For patch blocks only */
+ count = cmd->reg_count;
+ start = cmd->start;
+ buffer = cmd->buffer.block_data;
+ if (debugs_on & DEBUG_REG)
+ DBG("%s Repeat: Register block %s\n", dir,
+ block_name[block_index]);
+ break;
+ default:
+ LOG("%s: invalid request mode\n",__FUNCTION__);
+ return -EINVAL;
+ }
+
+ retval = cpia2_usb_transfer_cmd(cam,
+ buffer,
+ cmd->req_mode,
+ start, count, cmd->direction);
+#ifdef _CPIA2_DEBUG_
+ if (debugs_on & DEBUG_REG) {
+ int i;
+ for (i = 0; i < cmd->reg_count; i++) {
+ if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_BLOCK)
+ KINFO("%s Block: [0x%02X] = 0x%02X\n",
+ dir, start + i, buffer[i]);
+ if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_RANDOM)
+ KINFO("%s Random: [0x%02X] = 0x%02X\n",
+ dir, cmd->buffer.registers[i].index,
+ cmd->buffer.registers[i].value);
+ }
+ }
+#endif
+
+ return retval;
+};
+
+/*************
+ * Functions to implement camera functionality
+ *************/
+/******************************************************************************
+ *
+ * cpia2_get_version_info
+ *
+ *****************************************************************************/
+static void cpia2_get_version_info(struct camera_data *cam)
+{
+ cpia2_do_command(cam, CPIA2_CMD_GET_VERSION, TRANSFER_READ, 0);
+ cpia2_do_command(cam, CPIA2_CMD_GET_PNP_ID, TRANSFER_READ, 0);
+ cpia2_do_command(cam, CPIA2_CMD_GET_ASIC_TYPE, TRANSFER_READ, 0);
+ cpia2_do_command(cam, CPIA2_CMD_GET_SENSOR, TRANSFER_READ, 0);
+ cpia2_do_command(cam, CPIA2_CMD_GET_VP_DEVICE, TRANSFER_READ, 0);
+}
+
+/******************************************************************************
+ *
+ * cpia2_reset_camera
+ *
+ * Called at least during the open process, sets up initial params.
+ *****************************************************************************/
+int cpia2_reset_camera(struct camera_data *cam)
+{
+ u8 tmp_reg;
+ int retval = 0;
+ int i;
+ struct cpia2_command cmd;
+
+ /***
+ * VC setup
+ ***/
+ retval = configure_sensor(cam,
+ cam->params.roi.width,
+ cam->params.roi.height);
+ if (retval < 0) {
+ ERR("Couldn't configure sensor, error=%d\n", retval);
+ return retval;
+ }
+
+ /* Clear FIFO and route/enable stream block */
+ cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+ cmd.direction = TRANSFER_WRITE;
+ cmd.reg_count = 2;
+ cmd.buffer.registers[0].index = CPIA2_VC_ST_CTRL;
+ cmd.buffer.registers[0].value = CPIA2_VC_ST_CTRL_SRC_VC |
+ CPIA2_VC_ST_CTRL_DST_USB | CPIA2_VC_ST_CTRL_EOF_DETECT;
+ cmd.buffer.registers[1].index = CPIA2_VC_ST_CTRL;
+ cmd.buffer.registers[1].value = CPIA2_VC_ST_CTRL_SRC_VC |
+ CPIA2_VC_ST_CTRL_DST_USB |
+ CPIA2_VC_ST_CTRL_EOF_DETECT | CPIA2_VC_ST_CTRL_FIFO_ENABLE;
+
+ cpia2_send_command(cam, &cmd);
+
+ cpia2_set_high_power(cam);
+
+ if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
+ /* Enable button notification */
+ cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_SYSTEM;
+ cmd.buffer.registers[0].index = CPIA2_SYSTEM_INT_PACKET_CTRL;
+ cmd.buffer.registers[0].value =
+ CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_SW_XX;
+ cmd.reg_count = 1;
+ cpia2_send_command(cam, &cmd);
+ }
+
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(100 * HZ / 1000); /* wait for 100 msecs */
+
+ if (cam->params.pnp_id.device_type == DEVICE_STV_672)
+ retval = apply_vp_patch(cam);
+
+ /* wait for vp to go to sleep */
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(100 * HZ / 1000); /* wait for 100 msecs */
+
+ /***
+ * If this is a 676, apply VP5 fixes before we start streaming
+ ***/
+ if (cam->params.pnp_id.device_type == DEVICE_STV_676) {
+ cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP;
+
+ /* The following writes improve the picture */
+ cmd.buffer.registers[0].index = CPIA2_VP5_MYBLACK_LEVEL;
+ cmd.buffer.registers[0].value = 0; /* reduce from the default
+ * rec 601 pedestal of 16 */
+ cmd.buffer.registers[1].index = CPIA2_VP5_MCYRANGE;
+ cmd.buffer.registers[1].value = 0x92; /* increase from 100% to
+ * (256/256 - 31) to fill
+ * available range */
+ cmd.buffer.registers[2].index = CPIA2_VP5_MYCEILING;
+ cmd.buffer.registers[2].value = 0xFF; /* Increase from the
+ * default rec 601 ceiling
+ * of 240 */
+ cmd.buffer.registers[3].index = CPIA2_VP5_MCUVSATURATION;
+ cmd.buffer.registers[3].value = 0xFF; /* Increase from the rec
+ * 601 100% level (128)
+ * to 145-192 */
+ cmd.buffer.registers[4].index = CPIA2_VP5_ANTIFLKRSETUP;
+ cmd.buffer.registers[4].value = 0x80; /* Inhibit the
+ * anti-flicker */
+
+ /* The following 4 writes are a fix to allow QVGA to work at 30 fps */
+ cmd.buffer.registers[5].index = CPIA2_VP_RAM_ADDR_H;
+ cmd.buffer.registers[5].value = 0x01;
+ cmd.buffer.registers[6].index = CPIA2_VP_RAM_ADDR_L;
+ cmd.buffer.registers[6].value = 0xE3;
+ cmd.buffer.registers[7].index = CPIA2_VP_RAM_DATA;
+ cmd.buffer.registers[7].value = 0x02;
+ cmd.buffer.registers[8].index = CPIA2_VP_RAM_DATA;
+ cmd.buffer.registers[8].value = 0xFC;
+
+ cmd.direction = TRANSFER_WRITE;
+ cmd.reg_count = 9;
+
+ cpia2_send_command(cam, &cmd);
+ }
+
+ /* Activate all settings and start the data stream */
+ /* Set user mode */
+ set_default_user_mode(cam);
+
+ /* Give VP time to wake up */
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(100 * HZ / 1000); /* wait for 100 msecs */
+
+ set_all_properties(cam);
+
+ cpia2_do_command(cam, CPIA2_CMD_GET_USER_MODE, TRANSFER_READ, 0);
+ DBG("After SetAllProperties(cam), user mode is 0x%0X\n",
+ cam->params.vp_params.video_mode);
+
+ /***
+ * Set audio regulator off. This and the code to set the compresison
+ * state are too complex to form a CPIA2_CMD_, and seem to be somewhat
+ * intertwined. This stuff came straight from the windows driver.
+ ***/
+ /* Turn AutoExposure off in VP and enable the serial bridge to the sensor */
+ cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_CTRL, TRANSFER_READ, 0);
+ tmp_reg = cam->params.vp_params.system_ctrl;
+ cmd.buffer.registers[0].value = tmp_reg &
+ (tmp_reg & (CPIA2_VP_SYSTEMCTRL_HK_CONTROL ^ 0xFF));
+
+ cpia2_do_command(cam, CPIA2_CMD_GET_DEVICE_CONFIG, TRANSFER_READ, 0);
+ cmd.buffer.registers[1].value = cam->params.vp_params.device_config |
+ CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE;
+ cmd.buffer.registers[0].index = CPIA2_VP_SYSTEMCTRL;
+ cmd.buffer.registers[1].index = CPIA2_VP_DEVICE_CONFIG;
+ cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP;
+ cmd.reg_count = 2;
+ cmd.direction = TRANSFER_WRITE;
+ cmd.start = 0;
+ cpia2_send_command(cam, &cmd);
+
+ /* Set the correct I2C address in the CPiA-2 system register */
+ cpia2_do_command(cam,
+ CPIA2_CMD_SET_SERIAL_ADDR,
+ TRANSFER_WRITE,
+ CPIA2_SYSTEM_VP_SERIAL_ADDR_SENSOR);
+
+ /* Now have sensor access - set bit to turn the audio regulator off */
+ cpia2_do_command(cam,
+ CPIA2_CMD_SET_SENSOR_CR1,
+ TRANSFER_WRITE, CPIA2_SENSOR_CR1_DOWN_AUDIO_REGULATOR);
+
+ /* Set the correct I2C address in the CPiA-2 system register */
+ if (cam->params.pnp_id.device_type == DEVICE_STV_672)
+ cpia2_do_command(cam,
+ CPIA2_CMD_SET_SERIAL_ADDR,
+ TRANSFER_WRITE,
+ CPIA2_SYSTEM_VP_SERIAL_ADDR_VP); // 0x88
+ else
+ cpia2_do_command(cam,
+ CPIA2_CMD_SET_SERIAL_ADDR,
+ TRANSFER_WRITE,
+ CPIA2_SYSTEM_VP_SERIAL_ADDR_676_VP); // 0x8a
+
+ /* increase signal drive strength */
+ if (cam->params.pnp_id.device_type == DEVICE_STV_676)
+ cpia2_do_command(cam,
+ CPIA2_CMD_SET_VP_EXP_MODES,
+ TRANSFER_WRITE,
+ CPIA2_VP_EXPOSURE_MODES_COMPILE_EXP);
+
+ /* Start autoexposure */
+ cpia2_do_command(cam, CPIA2_CMD_GET_DEVICE_CONFIG, TRANSFER_READ, 0);
+ cmd.buffer.registers[0].value = cam->params.vp_params.device_config &
+ (CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE ^ 0xFF);
+
+ cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_CTRL, TRANSFER_READ, 0);
+ cmd.buffer.registers[1].value =
+ cam->params.vp_params.system_ctrl | CPIA2_VP_SYSTEMCTRL_HK_CONTROL;
+
+ cmd.buffer.registers[0].index = CPIA2_VP_DEVICE_CONFIG;
+ cmd.buffer.registers[1].index = CPIA2_VP_SYSTEMCTRL;
+ cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP;
+ cmd.reg_count = 2;
+ cmd.direction = TRANSFER_WRITE;
+
+ cpia2_send_command(cam, &cmd);
+
+ /* Set compression state */
+ cpia2_do_command(cam, CPIA2_CMD_GET_VC_CONTROL, TRANSFER_READ, 0);
+ if (cam->params.compression.inhibit_htables) {
+ tmp_reg = cam->params.vc_params.vc_control |
+ CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES;
+ } else {
+ tmp_reg = cam->params.vc_params.vc_control &
+ ~CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES;
+ }
+ cpia2_do_command(cam, CPIA2_CMD_SET_VC_CONTROL, TRANSFER_WRITE,tmp_reg);
+
+ /* Set target size (kb) on vc */
+ cpia2_do_command(cam, CPIA2_CMD_SET_TARGET_KB,
+ TRANSFER_WRITE, cam->params.vc_params.target_kb);
+
+ /* Wiggle VC Reset */
+ /***
+ * First read and wait a bit.
+ ***/
+ for (i = 0; i < 50; i++) {
+ cpia2_do_command(cam, CPIA2_CMD_GET_PW_CONTROL,
+ TRANSFER_READ, 0);
+ }
+
+ tmp_reg = cam->params.vc_params.pw_control;
+ tmp_reg &= ~CPIA2_VC_PW_CTRL_VC_RESET_N;
+
+ cpia2_do_command(cam, CPIA2_CMD_SET_PW_CONTROL, TRANSFER_WRITE,tmp_reg);
+
+ tmp_reg |= CPIA2_VC_PW_CTRL_VC_RESET_N;
+ cpia2_do_command(cam, CPIA2_CMD_SET_PW_CONTROL, TRANSFER_WRITE,tmp_reg);
+
+ cpia2_do_command(cam, CPIA2_CMD_SET_DEF_JPEG_OPT, TRANSFER_WRITE, 0);
+
+ cpia2_do_command(cam, CPIA2_CMD_GET_USER_MODE, TRANSFER_READ, 0);
+ DBG("After VC RESET, user mode is 0x%0X\n",
+ cam->params.vp_params.video_mode);
+
+ return retval;
+}
+
+/******************************************************************************
+ *
+ * cpia2_set_high_power
+ *
+ *****************************************************************************/
+static int cpia2_set_high_power(struct camera_data *cam)
+{
+ int i;
+ for (i = 0; i <= 50; i++) {
+ /* Read system status */
+ cpia2_do_command(cam,CPIA2_CMD_GET_SYSTEM_CTRL,TRANSFER_READ,0);
+
+ /* If there is an error, clear it */
+ if(cam->params.camera_state.system_ctrl &
+ CPIA2_SYSTEM_CONTROL_V2W_ERR)
+ cpia2_do_command(cam, CPIA2_CMD_CLEAR_V2W_ERR,
+ TRANSFER_WRITE, 0);
+
+ /* Try to set high power mode */
+ cpia2_do_command(cam, CPIA2_CMD_SET_SYSTEM_CTRL,
+ TRANSFER_WRITE, 1);
+
+ /* Try to read something in VP to check if everything is awake */
+ cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_STATE,
+ TRANSFER_READ, 0);
+ if (cam->params.vp_params.system_state &
+ CPIA2_VP_SYSTEMSTATE_HK_ALIVE) {
+ break;
+ } else if (i == 50) {
+ cam->params.camera_state.power_mode = LO_POWER_MODE;
+ ERR("Camera did not wake up\n");
+ return -EIO;
+ }
+ }
+
+ DBG("System now in high power state\n");
+ cam->params.camera_state.power_mode = HI_POWER_MODE;
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * cpia2_set_low_power
+ *
+ *****************************************************************************/
+int cpia2_set_low_power(struct camera_data *cam)
+{
+ cam->params.camera_state.power_mode = LO_POWER_MODE;
+ cpia2_do_command(cam, CPIA2_CMD_SET_SYSTEM_CTRL, TRANSFER_WRITE, 0);
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * apply_vp_patch
+ *
+ *****************************************************************************/
+static int apply_vp_patch(struct camera_data *cam)
+{
+ int i, j;
+ struct cpia2_command cmd;
+
+ cmd.req_mode = CAMERAACCESS_TYPE_REPEAT | CAMERAACCESS_VP;
+ cmd.direction = TRANSFER_WRITE;
+
+ for (i = 0; i < PATCH_DATA_SIZE; i++) {
+ for (j = 0; j < patch_data[i].count; j++) {
+ cmd.buffer.block_data[j] = patch_data[i].data[j];
+ }
+
+ cmd.start = patch_data[i].reg;
+ cmd.reg_count = patch_data[i].count;
+ cpia2_send_command(cam, &cmd);
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * set_default_user_mode
+ *
+ *****************************************************************************/
+static int set_default_user_mode(struct camera_data *cam)
+{
+ unsigned char user_mode;
+ unsigned char frame_rate;
+ int width = cam->params.roi.width;
+ int height = cam->params.roi.height;
+
+ switch (cam->params.version.sensor_flags) {
+ case CPIA2_VP_SENSOR_FLAGS_404:
+ case CPIA2_VP_SENSOR_FLAGS_407:
+ case CPIA2_VP_SENSOR_FLAGS_409:
+ case CPIA2_VP_SENSOR_FLAGS_410:
+ if ((width > STV_IMAGE_QCIF_COLS)
+ || (height > STV_IMAGE_QCIF_ROWS)) {
+ user_mode = CPIA2_VP_USER_MODE_CIF;
+ } else {
+ user_mode = CPIA2_VP_USER_MODE_QCIFDS;
+ }
+ frame_rate = CPIA2_VP_FRAMERATE_30;
+ break;
+ case CPIA2_VP_SENSOR_FLAGS_500:
+ if ((width > STV_IMAGE_CIF_COLS)
+ || (height > STV_IMAGE_CIF_ROWS)) {
+ user_mode = CPIA2_VP_USER_MODE_VGA;
+ } else {
+ user_mode = CPIA2_VP_USER_MODE_QVGADS;
+ }
+ if (cam->params.pnp_id.device_type == DEVICE_STV_672)
+ frame_rate = CPIA2_VP_FRAMERATE_15;
+ else
+ frame_rate = CPIA2_VP_FRAMERATE_30;
+ break;
+ default:
+ LOG("%s: Invalid sensor flag value 0x%0X\n",__FUNCTION__,
+ cam->params.version.sensor_flags);
+ return -EINVAL;
+ }
+
+ DBG("Sensor flag = 0x%0x, user mode = 0x%0x, frame rate = 0x%X\n",
+ cam->params.version.sensor_flags, user_mode, frame_rate);
+ cpia2_do_command(cam, CPIA2_CMD_SET_USER_MODE, TRANSFER_WRITE,
+ user_mode);
+ if(cam->params.vp_params.frame_rate > 0 &&
+ frame_rate > cam->params.vp_params.frame_rate)
+ frame_rate = cam->params.vp_params.frame_rate;
+
+ cpia2_set_fps(cam, frame_rate);
+
+// if (cam->params.pnp_id.device_type == DEVICE_STV_676)
+// cpia2_do_command(cam,
+// CPIA2_CMD_SET_VP_SYSTEM_CTRL,
+// TRANSFER_WRITE,
+// CPIA2_VP_SYSTEMCTRL_HK_CONTROL |
+// CPIA2_VP_SYSTEMCTRL_POWER_CONTROL);
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * cpia2_match_video_size
+ *
+ * return the best match, where 'best' is as always
+ * the largest that is not bigger than what is requested.
+ *****************************************************************************/
+int cpia2_match_video_size(int width, int height)
+{
+ if (width >= STV_IMAGE_VGA_COLS && height >= STV_IMAGE_VGA_ROWS)
+ return VIDEOSIZE_VGA;
+
+ if (width >= STV_IMAGE_CIF_COLS && height >= STV_IMAGE_CIF_ROWS)
+ return VIDEOSIZE_CIF;
+
+ if (width >= STV_IMAGE_QVGA_COLS && height >= STV_IMAGE_QVGA_ROWS)
+ return VIDEOSIZE_QVGA;
+
+ if (width >= 288 && height >= 216)
+ return VIDEOSIZE_288_216;
+
+ if (width >= 256 && height >= 192)
+ return VIDEOSIZE_256_192;
+
+ if (width >= 224 && height >= 168)
+ return VIDEOSIZE_224_168;
+
+ if (width >= 192 && height >= 144)
+ return VIDEOSIZE_192_144;
+
+ if (width >= STV_IMAGE_QCIF_COLS && height >= STV_IMAGE_QCIF_ROWS)
+ return VIDEOSIZE_QCIF;
+
+ return -1;
+}
+
+/******************************************************************************
+ *
+ * SetVideoSize
+ *
+ *****************************************************************************/
+static int set_vw_size(struct camera_data *cam, int size)
+{
+ int retval = 0;
+
+ cam->params.vp_params.video_size = size;
+
+ switch (size) {
+ case VIDEOSIZE_VGA:
+ DBG("Setting size to VGA\n");
+ cam->params.roi.width = STV_IMAGE_VGA_COLS;
+ cam->params.roi.height = STV_IMAGE_VGA_ROWS;
+ cam->vw.width = STV_IMAGE_VGA_COLS;
+ cam->vw.height = STV_IMAGE_VGA_ROWS;
+ break;
+ case VIDEOSIZE_CIF:
+ DBG("Setting size to CIF\n");
+ cam->params.roi.width = STV_IMAGE_CIF_COLS;
+ cam->params.roi.height = STV_IMAGE_CIF_ROWS;
+ cam->vw.width = STV_IMAGE_CIF_COLS;
+ cam->vw.height = STV_IMAGE_CIF_ROWS;
+ break;
+ case VIDEOSIZE_QVGA:
+ DBG("Setting size to QVGA\n");
+ cam->params.roi.width = STV_IMAGE_QVGA_COLS;
+ cam->params.roi.height = STV_IMAGE_QVGA_ROWS;
+ cam->vw.width = STV_IMAGE_QVGA_COLS;
+ cam->vw.height = STV_IMAGE_QVGA_ROWS;
+ break;
+ case VIDEOSIZE_288_216:
+ cam->params.roi.width = 288;
+ cam->params.roi.height = 216;
+ cam->vw.width = 288;
+ cam->vw.height = 216;
+ break;
+ case VIDEOSIZE_256_192:
+ cam->vw.width = 256;
+ cam->vw.height = 192;
+ cam->params.roi.width = 256;
+ cam->params.roi.height = 192;
+ break;
+ case VIDEOSIZE_224_168:
+ cam->vw.width = 224;
+ cam->vw.height = 168;
+ cam->params.roi.width = 224;
+ cam->params.roi.height = 168;
+ break;
+ case VIDEOSIZE_192_144:
+ cam->vw.width = 192;
+ cam->vw.height = 144;
+ cam->params.roi.width = 192;
+ cam->params.roi.height = 144;
+ break;
+ case VIDEOSIZE_QCIF:
+ DBG("Setting size to QCIF\n");
+ cam->params.roi.width = STV_IMAGE_QCIF_COLS;
+ cam->params.roi.height = STV_IMAGE_QCIF_ROWS;
+ cam->vw.width = STV_IMAGE_QCIF_COLS;
+ cam->vw.height = STV_IMAGE_QCIF_ROWS;
+ break;
+ default:
+ retval = -EINVAL;
+ }
+ return retval;
+}
+
+/******************************************************************************
+ *
+ * configure_sensor
+ *
+ *****************************************************************************/
+static int configure_sensor(struct camera_data *cam,
+ int req_width, int req_height)
+{
+ int retval;
+
+ switch (cam->params.version.sensor_flags) {
+ case CPIA2_VP_SENSOR_FLAGS_404:
+ case CPIA2_VP_SENSOR_FLAGS_407:
+ case CPIA2_VP_SENSOR_FLAGS_409:
+ case CPIA2_VP_SENSOR_FLAGS_410:
+ retval = config_sensor_410(cam, req_width, req_height);
+ break;
+ case CPIA2_VP_SENSOR_FLAGS_500:
+ retval = config_sensor_500(cam, req_width, req_height);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return retval;
+}
+
+/******************************************************************************
+ *
+ * config_sensor_410
+ *
+ *****************************************************************************/
+static int config_sensor_410(struct camera_data *cam,
+ int req_width, int req_height)
+{
+ struct cpia2_command cmd;
+ int i = 0;
+ int image_size;
+ int image_type;
+ int width = req_width;
+ int height = req_height;
+
+ /***
+ * Make sure size doesn't exceed CIF.
+ ***/
+ if (width > STV_IMAGE_CIF_COLS)
+ width = STV_IMAGE_CIF_COLS;
+ if (height > STV_IMAGE_CIF_ROWS)
+ height = STV_IMAGE_CIF_ROWS;
+
+ image_size = cpia2_match_video_size(width, height);
+
+ DBG("Config 410: width = %d, height = %d\n", width, height);
+ DBG("Image size returned is %d\n", image_size);
+ if (image_size >= 0) {
+ set_vw_size(cam, image_size);
+ width = cam->params.roi.width;
+ height = cam->params.roi.height;
+
+ DBG("After set_vw_size(), width = %d, height = %d\n",
+ width, height);
+ if (width <= 176 && height <= 144) {
+ DBG("image type = VIDEOSIZE_QCIF\n");
+ image_type = VIDEOSIZE_QCIF;
+ }
+ else if (width <= 320 && height <= 240) {
+ DBG("image type = VIDEOSIZE_QVGA\n");
+ image_type = VIDEOSIZE_QVGA;
+ }
+ else {
+ DBG("image type = VIDEOSIZE_CIF\n");
+ image_type = VIDEOSIZE_CIF;
+ }
+ } else {
+ ERR("ConfigSensor410 failed\n");
+ return -EINVAL;
+ }
+
+ cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+ cmd.direction = TRANSFER_WRITE;
+
+ /* VC Format */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_FORMAT;
+ if (image_type == VIDEOSIZE_CIF) {
+ cmd.buffer.registers[i++].value =
+ (u8) (CPIA2_VC_VC_FORMAT_UFIRST |
+ CPIA2_VC_VC_FORMAT_SHORTLINE);
+ } else {
+ cmd.buffer.registers[i++].value =
+ (u8) CPIA2_VC_VC_FORMAT_UFIRST;
+ }
+
+ /* VC Clocks */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_CLOCKS;
+ if (image_type == VIDEOSIZE_QCIF) {
+ if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
+ cmd.buffer.registers[i++].value=
+ (u8)(CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 |
+ CPIA2_VC_VC_672_CLOCKS_SCALING |
+ CPIA2_VC_VC_CLOCKS_LOGDIV2);
+ DBG("VC_Clocks (0xc4) should be B\n");
+ }
+ else {
+ cmd.buffer.registers[i++].value=
+ (u8)(CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 |
+ CPIA2_VC_VC_CLOCKS_LOGDIV2);
+ }
+ } else {
+ if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
+ cmd.buffer.registers[i++].value =
+ (u8) (CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 |
+ CPIA2_VC_VC_CLOCKS_LOGDIV0);
+ }
+ else {
+ cmd.buffer.registers[i++].value =
+ (u8) (CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 |
+ CPIA2_VC_VC_676_CLOCKS_SCALING |
+ CPIA2_VC_VC_CLOCKS_LOGDIV0);
+ }
+ }
+ DBG("VC_Clocks (0xc4) = 0x%0X\n", cmd.buffer.registers[i-1].value);
+
+ /* Input reqWidth from VC */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_IHSIZE_LO;
+ if (image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value =
+ (u8) (STV_IMAGE_QCIF_COLS / 4);
+ else
+ cmd.buffer.registers[i++].value =
+ (u8) (STV_IMAGE_CIF_COLS / 4);
+
+ /* Timings */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_HI;
+ if (image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value = (u8) 0;
+ else
+ cmd.buffer.registers[i++].value = (u8) 1;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_LO;
+ if (image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value = (u8) 208;
+ else
+ cmd.buffer.registers[i++].value = (u8) 160;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_HI;
+ if (image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value = (u8) 0;
+ else
+ cmd.buffer.registers[i++].value = (u8) 1;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_LO;
+ if (image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value = (u8) 160;
+ else
+ cmd.buffer.registers[i++].value = (u8) 64;
+
+ /* Output Image Size */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_OHSIZE;
+ cmd.buffer.registers[i++].value = cam->params.roi.width / 4;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_OVSIZE;
+ cmd.buffer.registers[i++].value = cam->params.roi.height / 4;
+
+ /* Cropping */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_HCROP;
+ if (image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value =
+ (u8) (((STV_IMAGE_QCIF_COLS / 4) - (width / 4)) / 2);
+ else
+ cmd.buffer.registers[i++].value =
+ (u8) (((STV_IMAGE_CIF_COLS / 4) - (width / 4)) / 2);
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_VCROP;
+ if (image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value =
+ (u8) (((STV_IMAGE_QCIF_ROWS / 4) - (height / 4)) / 2);
+ else
+ cmd.buffer.registers[i++].value =
+ (u8) (((STV_IMAGE_CIF_ROWS / 4) - (height / 4)) / 2);
+
+ /* Scaling registers (defaults) */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_HPHASE;
+ cmd.buffer.registers[i++].value = (u8) 0;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_VPHASE;
+ cmd.buffer.registers[i++].value = (u8) 0;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_HISPAN;
+ cmd.buffer.registers[i++].value = (u8) 31;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_VISPAN;
+ cmd.buffer.registers[i++].value = (u8) 31;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_HICROP;
+ cmd.buffer.registers[i++].value = (u8) 0;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_VICROP;
+ cmd.buffer.registers[i++].value = (u8) 0;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_HFRACT;
+ cmd.buffer.registers[i++].value = (u8) 0x81; /* = 8/1 = 8 (HIBYTE/LOBYTE) */
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_VFRACT;
+ cmd.buffer.registers[i++].value = (u8) 0x81; /* = 8/1 = 8 (HIBYTE/LOBYTE) */
+
+ cmd.reg_count = i;
+
+ cpia2_send_command(cam, &cmd);
+
+ return i;
+}
+
+
+/******************************************************************************
+ *
+ * config_sensor_500(cam)
+ *
+ *****************************************************************************/
+static int config_sensor_500(struct camera_data *cam,
+ int req_width, int req_height)
+{
+ struct cpia2_command cmd;
+ int i = 0;
+ int image_size = VIDEOSIZE_CIF;
+ int image_type = VIDEOSIZE_VGA;
+ int width = req_width;
+ int height = req_height;
+ unsigned int device = cam->params.pnp_id.device_type;
+
+ image_size = cpia2_match_video_size(width, height);
+
+ if (width > STV_IMAGE_CIF_COLS || height > STV_IMAGE_CIF_ROWS)
+ image_type = VIDEOSIZE_VGA;
+ else if (width > STV_IMAGE_QVGA_COLS || height > STV_IMAGE_QVGA_ROWS)
+ image_type = VIDEOSIZE_CIF;
+ else if (width > STV_IMAGE_QCIF_COLS || height > STV_IMAGE_QCIF_ROWS)
+ image_type = VIDEOSIZE_QVGA;
+ else
+ image_type = VIDEOSIZE_QCIF;
+
+ if (image_size >= 0) {
+ set_vw_size(cam, image_size);
+ width = cam->params.roi.width;
+ height = cam->params.roi.height;
+ } else {
+ ERR("ConfigSensor500 failed\n");
+ return -EINVAL;
+ }
+
+ DBG("image_size = %d, width = %d, height = %d, type = %d\n",
+ image_size, width, height, image_type);
+
+ cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+ cmd.direction = TRANSFER_WRITE;
+ i = 0;
+
+ /* VC Format */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_FORMAT;
+ cmd.buffer.registers[i].value = (u8) CPIA2_VC_VC_FORMAT_UFIRST;
+ if (image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i].value |= (u8) CPIA2_VC_VC_FORMAT_DECIMATING;
+ i++;
+
+ /* VC Clocks */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_CLOCKS;
+ if (device == DEVICE_STV_672) {
+ if (image_type == VIDEOSIZE_VGA)
+ cmd.buffer.registers[i].value =
+ (u8)CPIA2_VC_VC_CLOCKS_LOGDIV1;
+ else
+ cmd.buffer.registers[i].value =
+ (u8)(CPIA2_VC_VC_672_CLOCKS_SCALING |
+ CPIA2_VC_VC_CLOCKS_LOGDIV3);
+ } else {
+ if (image_type == VIDEOSIZE_VGA)
+ cmd.buffer.registers[i].value =
+ (u8)CPIA2_VC_VC_CLOCKS_LOGDIV0;
+ else
+ cmd.buffer.registers[i].value =
+ (u8)(CPIA2_VC_VC_676_CLOCKS_SCALING |
+ CPIA2_VC_VC_CLOCKS_LOGDIV2);
+ }
+ i++;
+
+ DBG("VC_CLOCKS = 0x%X\n", cmd.buffer.registers[i-1].value);
+
+ /* Input width from VP */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_IHSIZE_LO;
+ if (image_type == VIDEOSIZE_VGA)
+ cmd.buffer.registers[i].value =
+ (u8) (STV_IMAGE_VGA_COLS / 4);
+ else
+ cmd.buffer.registers[i].value =
+ (u8) (STV_IMAGE_QVGA_COLS / 4);
+ i++;
+ DBG("Input width = %d\n", cmd.buffer.registers[i-1].value);
+
+ /* Timings */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_HI;
+ if (image_type == VIDEOSIZE_VGA)
+ cmd.buffer.registers[i++].value = (u8) 2;
+ else
+ cmd.buffer.registers[i++].value = (u8) 1;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_LO;
+ if (image_type == VIDEOSIZE_VGA)
+ cmd.buffer.registers[i++].value = (u8) 250;
+ else if (image_type == VIDEOSIZE_QVGA)
+ cmd.buffer.registers[i++].value = (u8) 125;
+ else
+ cmd.buffer.registers[i++].value = (u8) 160;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_HI;
+ if (image_type == VIDEOSIZE_VGA)
+ cmd.buffer.registers[i++].value = (u8) 2;
+ else
+ cmd.buffer.registers[i++].value = (u8) 1;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_LO;
+ if (image_type == VIDEOSIZE_VGA)
+ cmd.buffer.registers[i++].value = (u8) 12;
+ else if (image_type == VIDEOSIZE_QVGA)
+ cmd.buffer.registers[i++].value = (u8) 64;
+ else
+ cmd.buffer.registers[i++].value = (u8) 6;
+
+ /* Output Image Size */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_OHSIZE;
+ if (image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value = STV_IMAGE_CIF_COLS / 4;
+ else
+ cmd.buffer.registers[i++].value = width / 4;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_OVSIZE;
+ if (image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value = STV_IMAGE_CIF_ROWS / 4;
+ else
+ cmd.buffer.registers[i++].value = height / 4;
+
+ /* Cropping */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_HCROP;
+ if (image_type == VIDEOSIZE_VGA)
+ cmd.buffer.registers[i++].value =
+ (u8) (((STV_IMAGE_VGA_COLS / 4) - (width / 4)) / 2);
+ else if (image_type == VIDEOSIZE_QVGA)
+ cmd.buffer.registers[i++].value =
+ (u8) (((STV_IMAGE_QVGA_COLS / 4) - (width / 4)) / 2);
+ else if (image_type == VIDEOSIZE_CIF)
+ cmd.buffer.registers[i++].value =
+ (u8) (((STV_IMAGE_CIF_COLS / 4) - (width / 4)) / 2);
+ else /*if (image_type == VIDEOSIZE_QCIF)*/
+ cmd.buffer.registers[i++].value =
+ (u8) (((STV_IMAGE_QCIF_COLS / 4) - (width / 4)) / 2);
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_VCROP;
+ if (image_type == VIDEOSIZE_VGA)
+ cmd.buffer.registers[i++].value =
+ (u8) (((STV_IMAGE_VGA_ROWS / 4) - (height / 4)) / 2);
+ else if (image_type == VIDEOSIZE_QVGA)
+ cmd.buffer.registers[i++].value =
+ (u8) (((STV_IMAGE_QVGA_ROWS / 4) - (height / 4)) / 2);
+ else if (image_type == VIDEOSIZE_CIF)
+ cmd.buffer.registers[i++].value =
+ (u8) (((STV_IMAGE_CIF_ROWS / 4) - (height / 4)) / 2);
+ else /*if (image_type == VIDEOSIZE_QCIF)*/
+ cmd.buffer.registers[i++].value =
+ (u8) (((STV_IMAGE_QCIF_ROWS / 4) - (height / 4)) / 2);
+
+ /* Scaling registers (defaults) */
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_HPHASE;
+ if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value = (u8) 36;
+ else
+ cmd.buffer.registers[i++].value = (u8) 0;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_VPHASE;
+ if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value = (u8) 32;
+ else
+ cmd.buffer.registers[i++].value = (u8) 0;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_HISPAN;
+ if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value = (u8) 26;
+ else
+ cmd.buffer.registers[i++].value = (u8) 31;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_VISPAN;
+ if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value = (u8) 21;
+ else
+ cmd.buffer.registers[i++].value = (u8) 31;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_HICROP;
+ cmd.buffer.registers[i++].value = (u8) 0;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_VICROP;
+ cmd.buffer.registers[i++].value = (u8) 0;
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_HFRACT;
+ if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value = (u8) 0x2B; /* 2/11 */
+ else
+ cmd.buffer.registers[i++].value = (u8) 0x81; /* 8/1 */
+
+ cmd.buffer.registers[i].index = CPIA2_VC_VC_VFRACT;
+ if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+ cmd.buffer.registers[i++].value = (u8) 0x13; /* 1/3 */
+ else
+ cmd.buffer.registers[i++].value = (u8) 0x81; /* 8/1 */
+
+ cmd.reg_count = i;
+
+ cpia2_send_command(cam, &cmd);
+
+ return i;
+}
+
+
+/******************************************************************************
+ *
+ * setallproperties
+ *
+ * This sets all user changeable properties to the values in cam->params.
+ *****************************************************************************/
+int set_all_properties(struct camera_data *cam)
+{
+ /**
+ * Don't set target_kb here, it will be set later.
+ * framerate and user_mode were already set (set_default_user_mode).
+ **/
+
+ cpia2_set_color_params(cam);
+
+ cpia2_usb_change_streaming_alternate(cam,
+ cam->params.camera_state.stream_mode);
+
+ cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
+ cam->params.vp_params.user_effects);
+
+ cpia2_set_flicker_mode(cam,
+ cam->params.flicker_control.flicker_mode_req);
+
+ cpia2_do_command(cam,
+ CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
+ TRANSFER_WRITE, cam->params.vp_params.gpio_direction);
+ cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DATA, TRANSFER_WRITE,
+ cam->params.vp_params.gpio_data);
+
+ wake_system(cam);
+
+ set_lowlight_boost(cam);
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * cpia2_save_camera_state
+ *
+ *****************************************************************************/
+void cpia2_save_camera_state(struct camera_data *cam)
+{
+ get_color_params(cam);
+ cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0);
+ cpia2_do_command(cam, CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION, TRANSFER_READ,
+ 0);
+ cpia2_do_command(cam, CPIA2_CMD_GET_VC_MP_GPIO_DATA, TRANSFER_READ, 0);
+ /* Don't get framerate or target_kb. Trust the values we already have */
+}
+
+/******************************************************************************
+ *
+ * get_color_params
+ *
+ *****************************************************************************/
+void get_color_params(struct camera_data *cam)
+{
+ cpia2_do_command(cam, CPIA2_CMD_GET_VP_BRIGHTNESS, TRANSFER_READ, 0);
+ cpia2_do_command(cam, CPIA2_CMD_GET_VP_SATURATION, TRANSFER_READ, 0);
+ cpia2_do_command(cam, CPIA2_CMD_GET_CONTRAST, TRANSFER_READ, 0);
+}
+
+/******************************************************************************
+ *
+ * cpia2_set_color_params
+ *
+ *****************************************************************************/
+void cpia2_set_color_params(struct camera_data *cam)
+{
+ DBG("Setting color params\n");
+ cpia2_set_brightness(cam, cam->params.color_params.brightness);
+ cpia2_set_contrast(cam, cam->params.color_params.contrast);
+ cpia2_set_saturation(cam, cam->params.color_params.saturation);
+}
+
+/******************************************************************************
+ *
+ * cpia2_set_flicker_mode
+ *
+ *****************************************************************************/
+int cpia2_set_flicker_mode(struct camera_data *cam, int mode)
+{
+ unsigned char cam_reg;
+ int err = 0;
+
+ if(cam->params.pnp_id.device_type != DEVICE_STV_672)
+ return -EINVAL;
+
+ /* Set the appropriate bits in FLICKER_MODES, preserving the rest */
+ if((err = cpia2_do_command(cam, CPIA2_CMD_GET_FLICKER_MODES,
+ TRANSFER_READ, 0)))
+ return err;
+ cam_reg = cam->params.flicker_control.cam_register;
+
+ switch(mode) {
+ case NEVER_FLICKER:
+ cam_reg |= CPIA2_VP_FLICKER_MODES_NEVER_FLICKER;
+ cam_reg &= ~CPIA2_VP_FLICKER_MODES_50HZ;
+ break;
+ case FLICKER_60:
+ cam_reg &= ~CPIA2_VP_FLICKER_MODES_NEVER_FLICKER;
+ cam_reg &= ~CPIA2_VP_FLICKER_MODES_50HZ;
+ break;
+ case FLICKER_50:
+ cam_reg &= ~CPIA2_VP_FLICKER_MODES_NEVER_FLICKER;
+ cam_reg |= CPIA2_VP_FLICKER_MODES_50HZ;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if((err = cpia2_do_command(cam, CPIA2_CMD_SET_FLICKER_MODES,
+ TRANSFER_WRITE, cam_reg)))
+ return err;
+
+ /* Set the appropriate bits in EXP_MODES, preserving the rest */
+ if((err = cpia2_do_command(cam, CPIA2_CMD_GET_VP_EXP_MODES,
+ TRANSFER_READ, 0)))
+ return err;
+ cam_reg = cam->params.vp_params.exposure_modes;
+
+ if (mode == NEVER_FLICKER) {
+ cam_reg |= CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER;
+ } else {
+ cam_reg &= ~CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER;
+ }
+
+ if((err = cpia2_do_command(cam, CPIA2_CMD_SET_VP_EXP_MODES,
+ TRANSFER_WRITE, cam_reg)))
+ return err;
+
+ if((err = cpia2_do_command(cam, CPIA2_CMD_REHASH_VP4,
+ TRANSFER_WRITE, 1)))
+ return err;
+
+ switch(mode) {
+ case NEVER_FLICKER:
+ cam->params.flicker_control.flicker_mode_req = mode;
+ break;
+ case FLICKER_60:
+ cam->params.flicker_control.flicker_mode_req = mode;
+ cam->params.flicker_control.mains_frequency = 60;
+ break;
+ case FLICKER_50:
+ cam->params.flicker_control.flicker_mode_req = mode;
+ cam->params.flicker_control.mains_frequency = 50;
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+/******************************************************************************
+ *
+ * cpia2_set_property_flip
+ *
+ *****************************************************************************/
+void cpia2_set_property_flip(struct camera_data *cam, int prop_val)
+{
+ unsigned char cam_reg;
+
+ cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0);
+ cam_reg = cam->params.vp_params.user_effects;
+
+ if (prop_val)
+ {
+ cam_reg |= CPIA2_VP_USER_EFFECTS_FLIP;
+ }
+ else
+ {
+ cam_reg &= ~CPIA2_VP_USER_EFFECTS_FLIP;
+ }
+ cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
+ cam_reg);
+}
+
+/******************************************************************************
+ *
+ * cpia2_set_property_mirror
+ *
+ *****************************************************************************/
+void cpia2_set_property_mirror(struct camera_data *cam, int prop_val)
+{
+ unsigned char cam_reg;
+
+ cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0);
+ cam_reg = cam->params.vp_params.user_effects;
+
+ if (prop_val)
+ {
+ cam_reg |= CPIA2_VP_USER_EFFECTS_MIRROR;
+ }
+ else
+ {
+ cam_reg &= ~CPIA2_VP_USER_EFFECTS_MIRROR;
+ }
+ cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
+ cam_reg);
+}
+
+/******************************************************************************
+ *
+ * set_target_kb
+ *
+ * The new Target KB is set in cam->params.vc_params.target_kb and
+ * activates on reset.
+ *****************************************************************************/
+
+int cpia2_set_target_kb(struct camera_data *cam, unsigned char value)
+{
+ DBG("Requested target_kb = %d\n", value);
+ if (value != cam->params.vc_params.target_kb) {
+
+ cpia2_usb_stream_pause(cam);
+
+ /* reset camera for new target_kb */
+ cam->params.vc_params.target_kb = value;
+ cpia2_reset_camera(cam);
+
+ cpia2_usb_stream_resume(cam);
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * cpia2_set_gpio
+ *
+ *****************************************************************************/
+int cpia2_set_gpio(struct camera_data *cam, unsigned char setting)
+{
+ int ret;
+
+ /* Set the microport direction (register 0x90, should be defined
+ * already) to 1 (user output), and set the microport data (0x91) to
+ * the value in the ioctl argument.
+ */
+
+ ret = cpia2_do_command(cam,
+ CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
+ CPIA2_VC_MP_DIR_OUTPUT,
+ 255);
+ if (ret < 0)
+ return ret;
+ cam->params.vp_params.gpio_direction = 255;
+
+ ret = cpia2_do_command(cam,
+ CPIA2_CMD_SET_VC_MP_GPIO_DATA,
+ CPIA2_VC_MP_DIR_OUTPUT,
+ setting);
+ if (ret < 0)
+ return ret;
+ cam->params.vp_params.gpio_data = setting;
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * cpia2_set_fps
+ *
+ *****************************************************************************/
+int cpia2_set_fps(struct camera_data *cam, int framerate)
+{
+ int retval;
+
+ switch(framerate) {
+ case CPIA2_VP_FRAMERATE_30:
+ case CPIA2_VP_FRAMERATE_25:
+ if(cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+ cam->params.version.sensor_flags ==
+ CPIA2_VP_SENSOR_FLAGS_500) {
+ return -EINVAL;
+ }
+ /* Fall through */
+ case CPIA2_VP_FRAMERATE_15:
+ case CPIA2_VP_FRAMERATE_12_5:
+ case CPIA2_VP_FRAMERATE_7_5:
+ case CPIA2_VP_FRAMERATE_6_25:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+ framerate == CPIA2_VP_FRAMERATE_15)
+ framerate = 0; /* Work around bug in VP4 */
+
+ retval = cpia2_do_command(cam,
+ CPIA2_CMD_FRAMERATE_REQ,
+ TRANSFER_WRITE,
+ framerate);
+
+ if(retval == 0)
+ cam->params.vp_params.frame_rate = framerate;
+
+ return retval;
+}
+
+/******************************************************************************
+ *
+ * cpia2_set_brightness
+ *
+ *****************************************************************************/
+void cpia2_set_brightness(struct camera_data *cam, unsigned char value)
+{
+ /***
+ * Don't let the register be set to zero - bug in VP4 - flash of full
+ * brightness
+ ***/
+ if (cam->params.pnp_id.device_type == DEVICE_STV_672 && value == 0)
+ value++;
+ DBG("Setting brightness to %d (0x%0x)\n", value, value);
+ cpia2_do_command(cam,CPIA2_CMD_SET_VP_BRIGHTNESS, TRANSFER_WRITE,value);
+}
+
+/******************************************************************************
+ *
+ * cpia2_set_contrast
+ *
+ *****************************************************************************/
+void cpia2_set_contrast(struct camera_data *cam, unsigned char value)
+{
+ DBG("Setting contrast to %d (0x%0x)\n", value, value);
+ cam->params.color_params.contrast = value;
+ cpia2_do_command(cam, CPIA2_CMD_SET_CONTRAST, TRANSFER_WRITE, value);
+}
+
+/******************************************************************************
+ *
+ * cpia2_set_saturation
+ *
+ *****************************************************************************/
+void cpia2_set_saturation(struct camera_data *cam, unsigned char value)
+{
+ DBG("Setting saturation to %d (0x%0x)\n", value, value);
+ cam->params.color_params.saturation = value;
+ cpia2_do_command(cam,CPIA2_CMD_SET_VP_SATURATION, TRANSFER_WRITE,value);
+}
+
+/******************************************************************************
+ *
+ * wake_system
+ *
+ *****************************************************************************/
+void wake_system(struct camera_data *cam)
+{
+ cpia2_do_command(cam, CPIA2_CMD_SET_WAKEUP, TRANSFER_WRITE, 0);
+}
+
+/******************************************************************************
+ *
+ * set_lowlight_boost
+ *
+ * Valid for STV500 sensor only
+ *****************************************************************************/
+void set_lowlight_boost(struct camera_data *cam)
+{
+ struct cpia2_command cmd;
+
+ if (cam->params.pnp_id.device_type != DEVICE_STV_672 ||
+ cam->params.version.sensor_flags != CPIA2_VP_SENSOR_FLAGS_500)
+ return;
+
+ cmd.direction = TRANSFER_WRITE;
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 3;
+ cmd.start = CPIA2_VP_RAM_ADDR_H;
+
+ cmd.buffer.block_data[0] = 0; /* High byte of address to write to */
+ cmd.buffer.block_data[1] = 0x59; /* Low byte of address to write to */
+ cmd.buffer.block_data[2] = 0; /* High byte of data to write */
+
+ cpia2_send_command(cam, &cmd);
+
+ if (cam->params.vp_params.lowlight_boost) {
+ cmd.buffer.block_data[0] = 0x02; /* Low byte data to write */
+ } else {
+ cmd.buffer.block_data[0] = 0x06;
+ }
+ cmd.start = CPIA2_VP_RAM_DATA;
+ cmd.reg_count = 1;
+ cpia2_send_command(cam, &cmd);
+
+ /* Rehash the VP4 values */
+ cpia2_do_command(cam, CPIA2_CMD_REHASH_VP4, TRANSFER_WRITE, 1);
+}
+
+/******************************************************************************
+ *
+ * cpia2_set_format
+ *
+ * Assumes that new size is already set in param struct.
+ *****************************************************************************/
+void cpia2_set_format(struct camera_data *cam)
+{
+ cam->flush = true;
+
+ cpia2_usb_stream_pause(cam);
+
+ /* reset camera to new size */
+ cpia2_set_low_power(cam);
+ cpia2_reset_camera(cam);
+ cam->flush = false;
+
+ cpia2_dbg_dump_registers(cam);
+
+ cpia2_usb_stream_resume(cam);
+}
+
+/******************************************************************************
+ *
+ * cpia2_dbg_dump_registers
+ *
+ *****************************************************************************/
+void cpia2_dbg_dump_registers(struct camera_data *cam)
+{
+#ifdef _CPIA2_DEBUG_
+ struct cpia2_command cmd;
+
+ if (!(debugs_on & DEBUG_DUMP_REGS))
+ return;
+
+ cmd.direction = TRANSFER_READ;
+
+ /* Start with bank 0 (SYSTEM) */
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+ cmd.reg_count = 3;
+ cmd.start = 0;
+ cpia2_send_command(cam, &cmd);
+ printk(KERN_DEBUG "System Device Hi = 0x%X\n",
+ cmd.buffer.block_data[0]);
+ printk(KERN_DEBUG "System Device Lo = 0x%X\n",
+ cmd.buffer.block_data[1]);
+ printk(KERN_DEBUG "System_system control = 0x%X\n",
+ cmd.buffer.block_data[2]);
+
+ /* Bank 1 (VC) */
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+ cmd.reg_count = 4;
+ cmd.start = 0x80;
+ cpia2_send_command(cam, &cmd);
+ printk(KERN_DEBUG "ASIC_ID = 0x%X\n",
+ cmd.buffer.block_data[0]);
+ printk(KERN_DEBUG "ASIC_REV = 0x%X\n",
+ cmd.buffer.block_data[1]);
+ printk(KERN_DEBUG "PW_CONTRL = 0x%X\n",
+ cmd.buffer.block_data[2]);
+ printk(KERN_DEBUG "WAKEUP = 0x%X\n",
+ cmd.buffer.block_data[3]);
+
+ cmd.start = 0xA0; /* ST_CTRL */
+ cmd.reg_count = 1;
+ cpia2_send_command(cam, &cmd);
+ printk(KERN_DEBUG "Stream ctrl = 0x%X\n",
+ cmd.buffer.block_data[0]);
+
+ cmd.start = 0xA4; /* Stream status */
+ cpia2_send_command(cam, &cmd);
+ printk(KERN_DEBUG "Stream status = 0x%X\n",
+ cmd.buffer.block_data[0]);
+
+ cmd.start = 0xA8; /* USB status */
+ cmd.reg_count = 3;
+ cpia2_send_command(cam, &cmd);
+ printk(KERN_DEBUG "USB_CTRL = 0x%X\n",
+ cmd.buffer.block_data[0]);
+ printk(KERN_DEBUG "USB_STRM = 0x%X\n",
+ cmd.buffer.block_data[1]);
+ printk(KERN_DEBUG "USB_STATUS = 0x%X\n",
+ cmd.buffer.block_data[2]);
+
+ cmd.start = 0xAF; /* USB settings */
+ cmd.reg_count = 1;
+ cpia2_send_command(cam, &cmd);
+ printk(KERN_DEBUG "USB settings = 0x%X\n",
+ cmd.buffer.block_data[0]);
+
+ cmd.start = 0xC0; /* VC stuff */
+ cmd.reg_count = 26;
+ cpia2_send_command(cam, &cmd);
+ printk(KERN_DEBUG "VC Control = 0x%0X\n",
+ cmd.buffer.block_data[0]);
+ printk(KERN_DEBUG "VC Format = 0x%0X\n",
+ cmd.buffer.block_data[3]);
+ printk(KERN_DEBUG "VC Clocks = 0x%0X\n",
+ cmd.buffer.block_data[4]);
+ printk(KERN_DEBUG "VC IHSize = 0x%0X\n",
+ cmd.buffer.block_data[5]);
+ printk(KERN_DEBUG "VC Xlim Hi = 0x%0X\n",
+ cmd.buffer.block_data[6]);
+ printk(KERN_DEBUG "VC XLim Lo = 0x%0X\n",
+ cmd.buffer.block_data[7]);
+ printk(KERN_DEBUG "VC YLim Hi = 0x%0X\n",
+ cmd.buffer.block_data[8]);
+ printk(KERN_DEBUG "VC YLim Lo = 0x%0X\n",
+ cmd.buffer.block_data[9]);
+ printk(KERN_DEBUG "VC OHSize = 0x%0X\n",
+ cmd.buffer.block_data[10]);
+ printk(KERN_DEBUG "VC OVSize = 0x%0X\n",
+ cmd.buffer.block_data[11]);
+ printk(KERN_DEBUG "VC HCrop = 0x%0X\n",
+ cmd.buffer.block_data[12]);
+ printk(KERN_DEBUG "VC VCrop = 0x%0X\n",
+ cmd.buffer.block_data[13]);
+ printk(KERN_DEBUG "VC HPhase = 0x%0X\n",
+ cmd.buffer.block_data[14]);
+ printk(KERN_DEBUG "VC VPhase = 0x%0X\n",
+ cmd.buffer.block_data[15]);
+ printk(KERN_DEBUG "VC HIspan = 0x%0X\n",
+ cmd.buffer.block_data[16]);
+ printk(KERN_DEBUG "VC VIspan = 0x%0X\n",
+ cmd.buffer.block_data[17]);
+ printk(KERN_DEBUG "VC HiCrop = 0x%0X\n",
+ cmd.buffer.block_data[18]);
+ printk(KERN_DEBUG "VC ViCrop = 0x%0X\n",
+ cmd.buffer.block_data[19]);
+ printk(KERN_DEBUG "VC HiFract = 0x%0X\n",
+ cmd.buffer.block_data[20]);
+ printk(KERN_DEBUG "VC ViFract = 0x%0X\n",
+ cmd.buffer.block_data[21]);
+ printk(KERN_DEBUG "VC JPeg Opt = 0x%0X\n",
+ cmd.buffer.block_data[22]);
+ printk(KERN_DEBUG "VC Creep Per = 0x%0X\n",
+ cmd.buffer.block_data[23]);
+ printk(KERN_DEBUG "VC User Sq. = 0x%0X\n",
+ cmd.buffer.block_data[24]);
+ printk(KERN_DEBUG "VC Target KB = 0x%0X\n",
+ cmd.buffer.block_data[25]);
+
+ /*** VP ***/
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+ cmd.reg_count = 14;
+ cmd.start = 0;
+ cpia2_send_command(cam, &cmd);
+
+ printk(KERN_DEBUG "VP Dev Hi = 0x%0X\n",
+ cmd.buffer.block_data[0]);
+ printk(KERN_DEBUG "VP Dev Lo = 0x%0X\n",
+ cmd.buffer.block_data[1]);
+ printk(KERN_DEBUG "VP Sys State = 0x%0X\n",
+ cmd.buffer.block_data[2]);
+ printk(KERN_DEBUG "VP Sys Ctrl = 0x%0X\n",
+ cmd.buffer.block_data[3]);
+ printk(KERN_DEBUG "VP Sensor flg = 0x%0X\n",
+ cmd.buffer.block_data[5]);
+ printk(KERN_DEBUG "VP Sensor Rev = 0x%0X\n",
+ cmd.buffer.block_data[6]);
+ printk(KERN_DEBUG "VP Dev Config = 0x%0X\n",
+ cmd.buffer.block_data[7]);
+ printk(KERN_DEBUG "VP GPIO_DIR = 0x%0X\n",
+ cmd.buffer.block_data[8]);
+ printk(KERN_DEBUG "VP GPIO_DATA = 0x%0X\n",
+ cmd.buffer.block_data[9]);
+ printk(KERN_DEBUG "VP Ram ADDR H = 0x%0X\n",
+ cmd.buffer.block_data[10]);
+ printk(KERN_DEBUG "VP Ram ADDR L = 0x%0X\n",
+ cmd.buffer.block_data[11]);
+ printk(KERN_DEBUG "VP RAM Data = 0x%0X\n",
+ cmd.buffer.block_data[12]);
+ printk(KERN_DEBUG "Do Call = 0x%0X\n",
+ cmd.buffer.block_data[13]);
+
+ if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
+ cmd.reg_count = 9;
+ cmd.start = 0x0E;
+ cpia2_send_command(cam, &cmd);
+ printk(KERN_DEBUG "VP Clock Ctrl = 0x%0X\n",
+ cmd.buffer.block_data[0]);
+ printk(KERN_DEBUG "VP Patch Rev = 0x%0X\n",
+ cmd.buffer.block_data[1]);
+ printk(KERN_DEBUG "VP Vid Mode = 0x%0X\n",
+ cmd.buffer.block_data[2]);
+ printk(KERN_DEBUG "VP Framerate = 0x%0X\n",
+ cmd.buffer.block_data[3]);
+ printk(KERN_DEBUG "VP UserEffect = 0x%0X\n",
+ cmd.buffer.block_data[4]);
+ printk(KERN_DEBUG "VP White Bal = 0x%0X\n",
+ cmd.buffer.block_data[5]);
+ printk(KERN_DEBUG "VP WB thresh = 0x%0X\n",
+ cmd.buffer.block_data[6]);
+ printk(KERN_DEBUG "VP Exp Modes = 0x%0X\n",
+ cmd.buffer.block_data[7]);
+ printk(KERN_DEBUG "VP Exp Target = 0x%0X\n",
+ cmd.buffer.block_data[8]);
+
+ cmd.reg_count = 1;
+ cmd.start = 0x1B;
+ cpia2_send_command(cam, &cmd);
+ printk(KERN_DEBUG "VP FlickerMds = 0x%0X\n",
+ cmd.buffer.block_data[0]);
+ } else {
+ cmd.reg_count = 8 ;
+ cmd.start = 0x0E;
+ cpia2_send_command(cam, &cmd);
+ printk(KERN_DEBUG "VP Clock Ctrl = 0x%0X\n",
+ cmd.buffer.block_data[0]);
+ printk(KERN_DEBUG "VP Patch Rev = 0x%0X\n",
+ cmd.buffer.block_data[1]);
+ printk(KERN_DEBUG "VP Vid Mode = 0x%0X\n",
+ cmd.buffer.block_data[5]);
+ printk(KERN_DEBUG "VP Framerate = 0x%0X\n",
+ cmd.buffer.block_data[6]);
+ printk(KERN_DEBUG "VP UserEffect = 0x%0X\n",
+ cmd.buffer.block_data[7]);
+
+ cmd.reg_count = 1;
+ cmd.start = CPIA2_VP5_EXPOSURE_TARGET;
+ cpia2_send_command(cam, &cmd);
+ printk(KERN_DEBUG "VP5 Exp Target= 0x%0X\n",
+ cmd.buffer.block_data[0]);
+
+ cmd.reg_count = 4;
+ cmd.start = 0x3A;
+ cpia2_send_command(cam, &cmd);
+ printk(KERN_DEBUG "VP5 MY Black = 0x%0X\n",
+ cmd.buffer.block_data[0]);
+ printk(KERN_DEBUG "VP5 MCY Range = 0x%0X\n",
+ cmd.buffer.block_data[1]);
+ printk(KERN_DEBUG "VP5 MYCEILING = 0x%0X\n",
+ cmd.buffer.block_data[2]);
+ printk(KERN_DEBUG "VP5 MCUV Sat = 0x%0X\n",
+ cmd.buffer.block_data[3]);
+ }
+#endif
+}
+
+/******************************************************************************
+ *
+ * reset_camera_struct
+ *
+ * Sets all values to the defaults
+ *****************************************************************************/
+void reset_camera_struct(struct camera_data *cam)
+{
+ /***
+ * The following parameter values are the defaults from the register map.
+ ***/
+ cam->params.color_params.brightness = DEFAULT_BRIGHTNESS;
+ cam->params.color_params.contrast = DEFAULT_CONTRAST;
+ cam->params.color_params.saturation = DEFAULT_SATURATION;
+ cam->params.vp_params.lowlight_boost = 0;
+
+ /* FlickerModes */
+ cam->params.flicker_control.flicker_mode_req = NEVER_FLICKER;
+ cam->params.flicker_control.mains_frequency = 60;
+
+ /* jpeg params */
+ cam->params.compression.jpeg_options = CPIA2_VC_VC_JPEG_OPT_DEFAULT;
+ cam->params.compression.creep_period = 2;
+ cam->params.compression.user_squeeze = 20;
+ cam->params.compression.inhibit_htables = false;
+
+ /* gpio params */
+ cam->params.vp_params.gpio_direction = 0; /* write, the default safe mode */
+ cam->params.vp_params.gpio_data = 0;
+
+ /* Target kb params */
+ cam->params.vc_params.target_kb = DEFAULT_TARGET_KB;
+
+ /***
+ * Set Sensor FPS as fast as possible.
+ ***/
+ if(cam->params.pnp_id.device_type == DEVICE_STV_672) {
+ if(cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500)
+ cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_15;
+ else
+ cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_30;
+ } else {
+ cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_30;
+ }
+
+ /***
+ * Set default video mode as large as possible :
+ * for vga sensor set to vga, for cif sensor set to CIF.
+ ***/
+ if (cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500) {
+ cam->sensor_type = CPIA2_SENSOR_500;
+ cam->video_size = VIDEOSIZE_VGA;
+ cam->params.roi.width = STV_IMAGE_VGA_COLS;
+ cam->params.roi.height = STV_IMAGE_VGA_ROWS;
+ } else {
+ cam->sensor_type = CPIA2_SENSOR_410;
+ cam->video_size = VIDEOSIZE_CIF;
+ cam->params.roi.width = STV_IMAGE_CIF_COLS;
+ cam->params.roi.height = STV_IMAGE_CIF_ROWS;
+ }
+
+ /***
+ * Fill in the v4l structures. video_cap is filled in inside the VIDIOCCAP
+ * Ioctl. Here, just do the window and picture stucts.
+ ***/
+ cam->vp.palette = (u16) VIDEO_PALETTE_RGB24; /* Is this right? */
+ cam->vp.brightness = (u16) cam->params.color_params.brightness * 256;
+ cam->vp.colour = (u16) cam->params.color_params.saturation * 256;
+ cam->vp.contrast = (u16) cam->params.color_params.contrast * 256;
+
+ cam->vw.x = 0;
+ cam->vw.y = 0;
+ cam->vw.width = cam->params.roi.width;
+ cam->vw.height = cam->params.roi.height;
+ cam->vw.flags = 0;
+ cam->vw.clipcount = 0;
+
+ return;
+}
+
+/******************************************************************************
+ *
+ * cpia2_init_camera_struct
+ *
+ * Initializes camera struct, does not call reset to fill in defaults.
+ *****************************************************************************/
+struct camera_data *cpia2_init_camera_struct(void)
+{
+ struct camera_data *cam;
+
+ cam = kmalloc(sizeof(*cam), GFP_KERNEL);
+
+ if (!cam) {
+ ERR("couldn't kmalloc cpia2 struct\n");
+ return NULL;
+ }
+
+ /* Default everything to 0 */
+ memset(cam, 0, sizeof(struct camera_data));
+
+ cam->present = 1;
+ init_MUTEX(&cam->busy_lock);
+ init_waitqueue_head(&cam->wq_stream);
+
+ return cam;
+}
+
+/******************************************************************************
+ *
+ * cpia2_init_camera
+ *
+ * Initializes camera.
+ *****************************************************************************/
+int cpia2_init_camera(struct camera_data *cam)
+{
+ DBG("Start\n");
+
+ cam->mmapped = false;
+
+ /* Get sensor and asic types before reset. */
+ cpia2_set_high_power(cam);
+ cpia2_get_version_info(cam);
+ if (cam->params.version.asic_id != CPIA2_ASIC_672) {
+ ERR("Device IO error (asicID has incorrect value of 0x%X\n",
+ cam->params.version.asic_id);
+ return -ENODEV;
+ }
+
+ /* Set GPIO direction and data to a safe state. */
+ cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
+ TRANSFER_WRITE, 0);
+ cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DATA,
+ TRANSFER_WRITE, 0);
+
+ /* resetting struct requires version info for sensor and asic types */
+ reset_camera_struct(cam);
+
+ cpia2_set_low_power(cam);
+
+ DBG("End\n");
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * cpia2_allocate_buffers
+ *
+ *****************************************************************************/
+int cpia2_allocate_buffers(struct camera_data *cam)
+{
+ int i;
+
+ if(!cam->buffers) {
+ u32 size = cam->num_frames*sizeof(struct framebuf);
+ cam->buffers = kmalloc(size, GFP_KERNEL);
+ if(!cam->buffers) {
+ ERR("couldn't kmalloc frame buffer structures\n");
+ return -ENOMEM;
+ }
+ }
+
+ if(!cam->frame_buffer) {
+ cam->frame_buffer = rvmalloc(cam->frame_size*cam->num_frames);
+ if (!cam->frame_buffer) {
+ ERR("couldn't vmalloc frame buffer data area\n");
+ kfree(cam->buffers);
+ cam->buffers = NULL;
+ return -ENOMEM;
+ }
+ }
+
+ for(i=0; i<cam->num_frames-1; ++i) {
+ cam->buffers[i].next = &cam->buffers[i+1];
+ cam->buffers[i].data = cam->frame_buffer +i*cam->frame_size;
+ cam->buffers[i].status = FRAME_EMPTY;
+ cam->buffers[i].length = 0;
+ cam->buffers[i].max_length = 0;
+ cam->buffers[i].num = i;
+ }
+ cam->buffers[i].next = cam->buffers;
+ cam->buffers[i].data = cam->frame_buffer +i*cam->frame_size;
+ cam->buffers[i].status = FRAME_EMPTY;
+ cam->buffers[i].length = 0;
+ cam->buffers[i].max_length = 0;
+ cam->buffers[i].num = i;
+ cam->curbuff = cam->buffers;
+ cam->workbuff = cam->curbuff->next;
+ DBG("buffers=%p, curbuff=%p, workbuff=%p\n", cam->buffers, cam->curbuff,
+ cam->workbuff);
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * cpia2_free_buffers
+ *
+ *****************************************************************************/
+void cpia2_free_buffers(struct camera_data *cam)
+{
+ if(cam->buffers) {
+ kfree(cam->buffers);
+ cam->buffers = NULL;
+ }
+ if(cam->frame_buffer) {
+ rvfree(cam->frame_buffer, cam->frame_size*cam->num_frames);
+ cam->frame_buffer = NULL;
+ }
+}
+
+/******************************************************************************
+ *
+ * cpia2_read
+ *
+ *****************************************************************************/
+long cpia2_read(struct camera_data *cam,
+ char __user *buf, unsigned long count, int noblock)
+{
+ struct framebuf *frame;
+ if (!count) {
+ return 0;
+ }
+
+ if (!buf) {
+ ERR("%s: buffer NULL\n",__FUNCTION__);
+ return -EINVAL;
+ }
+
+ if (!cam) {
+ ERR("%s: Internal error, camera_data NULL!\n",__FUNCTION__);
+ return -EINVAL;
+ }
+
+ /* make this _really_ smp and multithread-safe */
+ if (down_interruptible(&cam->busy_lock))
+ return -ERESTARTSYS;
+
+ if (!cam->present) {
+ LOG("%s: camera removed\n",__FUNCTION__);
+ up(&cam->busy_lock);
+ return 0; /* EOF */
+ }
+
+ if(!cam->streaming) {
+ /* Start streaming */
+ cpia2_usb_stream_start(cam,
+ cam->params.camera_state.stream_mode);
+ }
+
+ /* Copy cam->curbuff in case it changes while we're processing */
+ frame = cam->curbuff;
+ if (noblock && frame->status != FRAME_READY) {
+ up(&cam->busy_lock);
+ return -EAGAIN;
+ }
+
+ if(frame->status != FRAME_READY) {
+ up(&cam->busy_lock);
+ wait_event_interruptible(cam->wq_stream,
+ !cam->present ||
+ (frame = cam->curbuff)->status == FRAME_READY);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ /* make this _really_ smp and multithread-safe */
+ if (down_interruptible(&cam->busy_lock)) {
+ return -ERESTARTSYS;
+ }
+ if(!cam->present) {
+ up(&cam->busy_lock);
+ return 0;
+ }
+ }
+
+ /* copy data to user space */
+ if (frame->length > count) {
+ up(&cam->busy_lock);
+ return -EFAULT;
+ }
+ if (copy_to_user(buf, frame->data, frame->length)) {
+ up(&cam->busy_lock);
+ return -EFAULT;
+ }
+
+ count = frame->length;
+
+ frame->status = FRAME_EMPTY;
+
+ up(&cam->busy_lock);
+ return count;
+}
+
+/******************************************************************************
+ *
+ * cpia2_poll
+ *
+ *****************************************************************************/
+unsigned int cpia2_poll(struct camera_data *cam, struct file *filp,
+ poll_table *wait)
+{
+ unsigned int status=0;
+
+ if(!cam) {
+ ERR("%s: Internal error, camera_data not found!\n",__FUNCTION__);
+ return POLLERR;
+ }
+
+ down(&cam->busy_lock);
+
+ if(!cam->present) {
+ up(&cam->busy_lock);
+ return POLLHUP;
+ }
+
+ if(!cam->streaming) {
+ /* Start streaming */
+ cpia2_usb_stream_start(cam,
+ cam->params.camera_state.stream_mode);
+ }
+
+ up(&cam->busy_lock);
+ poll_wait(filp, &cam->wq_stream, wait);
+ down(&cam->busy_lock);
+
+ if(!cam->present)
+ status = POLLHUP;
+ else if(cam->curbuff->status == FRAME_READY)
+ status = POLLIN | POLLRDNORM;
+
+ up(&cam->busy_lock);
+ return status;
+}
+
+/******************************************************************************
+ *
+ * cpia2_remap_buffer
+ *
+ *****************************************************************************/
+int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma)
+{
+ const char *adr = (const char *)vma->vm_start;
+ unsigned long size = vma->vm_end-vma->vm_start;
+ unsigned long start_offset = vma->vm_pgoff << PAGE_SHIFT;
+ unsigned long start = (unsigned long) adr;
+ unsigned long page, pos;
+
+ if (!cam)
+ return -ENODEV;
+
+ DBG("mmap offset:%ld size:%ld\n", start_offset, size);
+
+ /* make this _really_ smp-safe */
+ if (down_interruptible(&cam->busy_lock))
+ return -ERESTARTSYS;
+
+ if (!cam->present) {
+ up(&cam->busy_lock);
+ return -ENODEV;
+ }
+
+ if (size > cam->frame_size*cam->num_frames ||
+ (start_offset % cam->frame_size) != 0 ||
+ (start_offset+size > cam->frame_size*cam->num_frames)) {
+ up(&cam->busy_lock);
+ return -EINVAL;
+ }
+
+ pos = ((unsigned long) (cam->frame_buffer)) + start_offset;
+ while (size > 0) {
+ page = kvirt_to_pa(pos);
+ if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED)) {
+ up(&cam->busy_lock);
+ return -EAGAIN;
+ }
+ start += PAGE_SIZE;
+ pos += PAGE_SIZE;
+ if (size > PAGE_SIZE)
+ size -= PAGE_SIZE;
+ else
+ size = 0;
+ }
+
+ cam->mmapped = true;
+ up(&cam->busy_lock);
+ return 0;
+}
+
diff --git a/drivers/media/video/cpia2/cpia2_registers.h b/drivers/media/video/cpia2/cpia2_registers.h
new file mode 100644
index 00000000000..3bbec514a96
--- /dev/null
+++ b/drivers/media/video/cpia2/cpia2_registers.h
@@ -0,0 +1,476 @@
+/****************************************************************************
+ *
+ * Filename: cpia2registers.h
+ *
+ * Copyright 2001, STMicrolectronics, Inc.
+ *
+ * Description:
+ * Definitions for the CPia2 register set
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ****************************************************************************/
+
+#ifndef CPIA2_REGISTER_HEADER
+#define CPIA2_REGISTER_HEADER
+
+/***
+ * System register set (Bank 0)
+ ***/
+#define CPIA2_SYSTEM_DEVICE_HI 0x00
+#define CPIA2_SYSTEM_DEVICE_LO 0x01
+
+#define CPIA2_SYSTEM_SYSTEM_CONTROL 0x02
+#define CPIA2_SYSTEM_CONTROL_LOW_POWER 0x00
+#define CPIA2_SYSTEM_CONTROL_HIGH_POWER 0x01
+#define CPIA2_SYSTEM_CONTROL_SUSPEND 0x02
+#define CPIA2_SYSTEM_CONTROL_V2W_ERR 0x10
+#define CPIA2_SYSTEM_CONTROL_RB_ERR 0x10
+#define CPIA2_SYSTEM_CONTROL_CLEAR_ERR 0x80
+
+#define CPIA2_SYSTEM_INT_PACKET_CTRL 0x04
+#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_SW_XX 0x01
+#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_EOF 0x02
+#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_INT1 0x04
+
+#define CPIA2_SYSTEM_CACHE_CTRL 0x05
+#define CPIA2_SYSTEM_CACHE_CTRL_CACHE_RESET 0x01
+#define CPIA2_SYSTEM_CACHE_CTRL_CACHE_FLUSH 0x02
+
+#define CPIA2_SYSTEM_SERIAL_CTRL 0x06
+#define CPIA2_SYSTEM_SERIAL_CTRL_NULL_CMD 0x00
+#define CPIA2_SYSTEM_SERIAL_CTRL_START_CMD 0x01
+#define CPIA2_SYSTEM_SERIAL_CTRL_STOP_CMD 0x02
+#define CPIA2_SYSTEM_SERIAL_CTRL_WRITE_CMD 0x03
+#define CPIA2_SYSTEM_SERIAL_CTRL_READ_ACK_CMD 0x04
+#define CPIA2_SYSTEM_SERIAL_CTRL_READ_NACK_CMD 0x05
+
+#define CPIA2_SYSTEM_SERIAL_DATA 0x07
+
+#define CPIA2_SYSTEM_VP_SERIAL_ADDR 0x08
+
+/***
+ * I2C addresses for various devices in CPiA2
+ ***/
+#define CPIA2_SYSTEM_VP_SERIAL_ADDR_SENSOR 0x20
+#define CPIA2_SYSTEM_VP_SERIAL_ADDR_VP 0x88
+#define CPIA2_SYSTEM_VP_SERIAL_ADDR_676_VP 0x8A
+
+#define CPIA2_SYSTEM_SPARE_REG1 0x09
+#define CPIA2_SYSTEM_SPARE_REG2 0x0A
+#define CPIA2_SYSTEM_SPARE_REG3 0x0B
+
+#define CPIA2_SYSTEM_MC_PORT_0 0x0C
+#define CPIA2_SYSTEM_MC_PORT_1 0x0D
+#define CPIA2_SYSTEM_MC_PORT_2 0x0E
+#define CPIA2_SYSTEM_MC_PORT_3 0x0F
+
+#define CPIA2_SYSTEM_STATUS_PKT 0x20
+#define CPIA2_SYSTEM_STATUS_PKT_END 0x27
+
+#define CPIA2_SYSTEM_DESCRIP_VID_HI 0x30
+#define CPIA2_SYSTEM_DESCRIP_VID_LO 0x31
+#define CPIA2_SYSTEM_DESCRIP_PID_HI 0x32
+#define CPIA2_SYSTEM_DESCRIP_PID_LO 0x33
+
+#define CPIA2_SYSTEM_FW_VERSION_HI 0x34
+#define CPIA2_SYSTEM_FW_VERSION_LO 0x35
+
+#define CPIA2_SYSTEM_CACHE_START_INDEX 0x80
+#define CPIA2_SYSTEM_CACHE_MAX_WRITES 0x10
+
+/***
+ * VC register set (Bank 1)
+ ***/
+#define CPIA2_VC_ASIC_ID 0x80
+
+#define CPIA2_VC_ASIC_REV 0x81
+
+#define CPIA2_VC_PW_CTRL 0x82
+#define CPIA2_VC_PW_CTRL_COLDSTART 0x01
+#define CPIA2_VC_PW_CTRL_CP_CLK_EN 0x02
+#define CPIA2_VC_PW_CTRL_VP_RESET_N 0x04
+#define CPIA2_VC_PW_CTRL_VC_CLK_EN 0x08
+#define CPIA2_VC_PW_CTRL_VC_RESET_N 0x10
+#define CPIA2_VC_PW_CTRL_GOTO_SUSPEND 0x20
+#define CPIA2_VC_PW_CTRL_UDC_SUSPEND 0x40
+#define CPIA2_VC_PW_CTRL_PWR_DOWN 0x80
+
+#define CPIA2_VC_WAKEUP 0x83
+#define CPIA2_VC_WAKEUP_SW_ENABLE 0x01
+#define CPIA2_VC_WAKEUP_XX_ENABLE 0x02
+#define CPIA2_VC_WAKEUP_SW_ATWAKEUP 0x04
+#define CPIA2_VC_WAKEUP_XX_ATWAKEUP 0x08
+
+#define CPIA2_VC_CLOCK_CTRL 0x84
+#define CPIA2_VC_CLOCK_CTRL_TESTUP72 0x01
+
+#define CPIA2_VC_INT_ENABLE 0x88
+#define CPIA2_VC_INT_ENABLE_XX_IE 0x01
+#define CPIA2_VC_INT_ENABLE_SW_IE 0x02
+#define CPIA2_VC_INT_ENABLE_VC_IE 0x04
+#define CPIA2_VC_INT_ENABLE_USBDATA_IE 0x08
+#define CPIA2_VC_INT_ENABLE_USBSETUP_IE 0x10
+#define CPIA2_VC_INT_ENABLE_USBCFG_IE 0x20
+
+#define CPIA2_VC_INT_FLAG 0x89
+#define CPIA2_VC_INT_ENABLE_XX_FLAG 0x01
+#define CPIA2_VC_INT_ENABLE_SW_FLAG 0x02
+#define CPIA2_VC_INT_ENABLE_VC_FLAG 0x04
+#define CPIA2_VC_INT_ENABLE_USBDATA_FLAG 0x08
+#define CPIA2_VC_INT_ENABLE_USBSETUP_FLAG 0x10
+#define CPIA2_VC_INT_ENABLE_USBCFG_FLAG 0x20
+#define CPIA2_VC_INT_ENABLE_SET_RESET_BIT 0x80
+
+#define CPIA2_VC_INT_STATE 0x8A
+#define CPIA2_VC_INT_STATE_XX_STATE 0x01
+#define CPIA2_VC_INT_STATE_SW_STATE 0x02
+
+#define CPIA2_VC_MP_DIR 0x90
+#define CPIA2_VC_MP_DIR_INPUT 0x00
+#define CPIA2_VC_MP_DIR_OUTPUT 0x01
+
+#define CPIA2_VC_MP_DATA 0x91
+
+#define CPIA2_VC_DP_CTRL 0x98
+#define CPIA2_VC_DP_CTRL_MODE_0 0x00
+#define CPIA2_VC_DP_CTRL_MODE_A 0x01
+#define CPIA2_VC_DP_CTRL_MODE_B 0x02
+#define CPIA2_VC_DP_CTRL_MODE_C 0x03
+#define CPIA2_VC_DP_CTRL_FAKE_FST 0x04
+
+#define CPIA2_VC_AD_CTRL 0x99
+#define CPIA2_VC_AD_CTRL_SRC_0 0x00
+#define CPIA2_VC_AD_CTRL_SRC_DIGI_A 0x01
+#define CPIA2_VC_AD_CTRL_SRC_REG 0x02
+#define CPIA2_VC_AD_CTRL_DST_USB 0x00
+#define CPIA2_VC_AD_CTRL_DST_REG 0x04
+
+#define CPIA2_VC_AD_TEST_IN 0x9B
+
+#define CPIA2_VC_AD_TEST_OUT 0x9C
+
+#define CPIA2_VC_AD_STATUS 0x9D
+#define CPIA2_VC_AD_STATUS_EMPTY 0x01
+#define CPIA2_VC_AD_STATUS_FULL 0x02
+
+#define CPIA2_VC_DP_DATA 0x9E
+
+#define CPIA2_VC_ST_CTRL 0xA0
+#define CPIA2_VC_ST_CTRL_SRC_VC 0x00
+#define CPIA2_VC_ST_CTRL_SRC_DP 0x01
+#define CPIA2_VC_ST_CTRL_SRC_REG 0x02
+
+#define CPIA2_VC_ST_CTRL_RAW_SELECT 0x04
+
+#define CPIA2_VC_ST_CTRL_DST_USB 0x00
+#define CPIA2_VC_ST_CTRL_DST_DP 0x08
+#define CPIA2_VC_ST_CTRL_DST_REG 0x10
+
+#define CPIA2_VC_ST_CTRL_FIFO_ENABLE 0x20
+#define CPIA2_VC_ST_CTRL_EOF_DETECT 0x40
+
+#define CPIA2_VC_ST_TEST 0xA1
+#define CPIA2_VC_ST_TEST_MODE_MANUAL 0x00
+#define CPIA2_VC_ST_TEST_MODE_INCREMENT 0x02
+
+#define CPIA2_VC_ST_TEST_AUTO_FILL 0x08
+
+#define CPIA2_VC_ST_TEST_REPEAT_FIFO 0x10
+
+#define CPIA2_VC_ST_TEST_IN 0xA2
+
+#define CPIA2_VC_ST_TEST_OUT 0xA3
+
+#define CPIA2_VC_ST_STATUS 0xA4
+#define CPIA2_VC_ST_STATUS_EMPTY 0x01
+#define CPIA2_VC_ST_STATUS_FULL 0x02
+
+#define CPIA2_VC_ST_FRAME_DETECT_1 0xA5
+
+#define CPIA2_VC_ST_FRAME_DETECT_2 0xA6
+
+#define CPIA2_VC_USB_CTRL 0xA8
+#define CPIA2_VC_USB_CTRL_CMD_STALLED 0x01
+#define CPIA2_VC_USB_CTRL_CMD_READY 0x02
+#define CPIA2_VC_USB_CTRL_CMD_STATUS 0x04
+#define CPIA2_VC_USB_CTRL_CMD_STATUS_DIR 0x08
+#define CPIA2_VC_USB_CTRL_CMD_NO_CLASH 0x10
+#define CPIA2_VC_USB_CTRL_CMD_MICRO_ACCESS 0x80
+
+#define CPIA2_VC_USB_STRM 0xA9
+#define CPIA2_VC_USB_STRM_ISO_ENABLE 0x01
+#define CPIA2_VC_USB_STRM_BLK_ENABLE 0x02
+#define CPIA2_VC_USB_STRM_INT_ENABLE 0x04
+#define CPIA2_VC_USB_STRM_AUD_ENABLE 0x08
+
+#define CPIA2_VC_USB_STATUS 0xAA
+#define CPIA2_VC_USB_STATUS_CMD_IN_PROGRESS 0x01
+#define CPIA2_VC_USB_STATUS_CMD_STATUS_STALL 0x02
+#define CPIA2_VC_USB_STATUS_CMD_HANDSHAKE 0x04
+#define CPIA2_VC_USB_STATUS_CMD_OVERRIDE 0x08
+#define CPIA2_VC_USB_STATUS_CMD_FIFO_BUSY 0x10
+#define CPIA2_VC_USB_STATUS_BULK_REPEAT_TXN 0x20
+#define CPIA2_VC_USB_STATUS_CONFIG_DONE 0x40
+#define CPIA2_VC_USB_STATUS_USB_SUSPEND 0x80
+
+#define CPIA2_VC_USB_CMDW 0xAB
+
+#define CPIA2_VC_USB_DATARW 0xAC
+
+#define CPIA2_VC_USB_INFO 0xAD
+
+#define CPIA2_VC_USB_CONFIG 0xAE
+
+#define CPIA2_VC_USB_SETTINGS 0xAF
+#define CPIA2_VC_USB_SETTINGS_CONFIG_MASK 0x03
+#define CPIA2_VC_USB_SETTINGS_INTERFACE_MASK 0x0C
+#define CPIA2_VC_USB_SETTINGS_ALTERNATE_MASK 0x70
+
+#define CPIA2_VC_USB_ISOLIM 0xB0
+
+#define CPIA2_VC_USB_ISOFAILS 0xB1
+
+#define CPIA2_VC_USB_ISOMAXPKTHI 0xB2
+
+#define CPIA2_VC_USB_ISOMAXPKTLO 0xB3
+
+#define CPIA2_VC_V2W_CTRL 0xB8
+#define CPIA2_VC_V2W_SELECT 0x01
+
+#define CPIA2_VC_V2W_SCL 0xB9
+
+#define CPIA2_VC_V2W_SDA 0xBA
+
+#define CPIA2_VC_VC_CTRL 0xC0
+#define CPIA2_VC_VC_CTRL_RUN 0x01
+#define CPIA2_VC_VC_CTRL_SINGLESHOT 0x02
+#define CPIA2_VC_VC_CTRL_IDLING 0x04
+#define CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES 0x10
+#define CPIA2_VC_VC_CTRL_INHIBIT_Q_TABLES 0x20
+#define CPIA2_VC_VC_CTRL_INHIBIT_PRIVATE 0x40
+
+#define CPIA2_VC_VC_RESTART_IVAL_HI 0xC1
+
+#define CPIA2_VC_VC_RESTART_IVAL_LO 0xC2
+
+#define CPIA2_VC_VC_FORMAT 0xC3
+#define CPIA2_VC_VC_FORMAT_UFIRST 0x01
+#define CPIA2_VC_VC_FORMAT_MONO 0x02
+#define CPIA2_VC_VC_FORMAT_DECIMATING 0x04
+#define CPIA2_VC_VC_FORMAT_SHORTLINE 0x08
+#define CPIA2_VC_VC_FORMAT_SELFTEST 0x10
+
+#define CPIA2_VC_VC_CLOCKS 0xC4
+#define CPIA2_VC_VC_CLOCKS_CLKDIV_MASK 0x03
+#define CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 0x04
+#define CPIA2_VC_VC_672_CLOCKS_SCALING 0x08
+#define CPIA2_VC_VC_CLOCKS_LOGDIV0 0x00
+#define CPIA2_VC_VC_CLOCKS_LOGDIV1 0x01
+#define CPIA2_VC_VC_CLOCKS_LOGDIV2 0x02
+#define CPIA2_VC_VC_CLOCKS_LOGDIV3 0x03
+#define CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 0x08
+#define CPIA2_VC_VC_676_CLOCKS_SCALING 0x10
+
+#define CPIA2_VC_VC_IHSIZE_LO 0xC5
+
+#define CPIA2_VC_VC_XLIM_HI 0xC6
+
+#define CPIA2_VC_VC_XLIM_LO 0xC7
+
+#define CPIA2_VC_VC_YLIM_HI 0xC8
+
+#define CPIA2_VC_VC_YLIM_LO 0xC9
+
+#define CPIA2_VC_VC_OHSIZE 0xCA
+
+#define CPIA2_VC_VC_OVSIZE 0xCB
+
+#define CPIA2_VC_VC_HCROP 0xCC
+
+#define CPIA2_VC_VC_VCROP 0xCD
+
+#define CPIA2_VC_VC_HPHASE 0xCE
+
+#define CPIA2_VC_VC_VPHASE 0xCF
+
+#define CPIA2_VC_VC_HISPAN 0xD0
+
+#define CPIA2_VC_VC_VISPAN 0xD1
+
+#define CPIA2_VC_VC_HICROP 0xD2
+
+#define CPIA2_VC_VC_VICROP 0xD3
+
+#define CPIA2_VC_VC_HFRACT 0xD4
+#define CPIA2_VC_VC_HFRACT_DEN_MASK 0x0F
+#define CPIA2_VC_VC_HFRACT_NUM_MASK 0xF0
+
+#define CPIA2_VC_VC_VFRACT 0xD5
+#define CPIA2_VC_VC_VFRACT_DEN_MASK 0x0F
+#define CPIA2_VC_VC_VFRACT_NUM_MASK 0xF0
+
+#define CPIA2_VC_VC_JPEG_OPT 0xD6
+#define CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE 0x01
+#define CPIA2_VC_VC_JPEG_OPT_NO_DC_AUTO_SQUEEZE 0x02
+#define CPIA2_VC_VC_JPEG_OPT_AUTO_SQUEEZE 0x04
+#define CPIA2_VC_VC_JPEG_OPT_DEFAULT (CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE|\
+ CPIA2_VC_VC_JPEG_OPT_AUTO_SQUEEZE)
+
+
+#define CPIA2_VC_VC_CREEP_PERIOD 0xD7
+#define CPIA2_VC_VC_USER_SQUEEZE 0xD8
+#define CPIA2_VC_VC_TARGET_KB 0xD9
+
+#define CPIA2_VC_VC_AUTO_SQUEEZE 0xE6
+
+
+/***
+ * VP register set (Bank 2)
+ ***/
+#define CPIA2_VP_DEVICEH 0
+#define CPIA2_VP_DEVICEL 1
+
+#define CPIA2_VP_SYSTEMSTATE 0x02
+#define CPIA2_VP_SYSTEMSTATE_HK_ALIVE 0x01
+
+#define CPIA2_VP_SYSTEMCTRL 0x03
+#define CPIA2_VP_SYSTEMCTRL_REQ_CLEAR_ERROR 0x80
+#define CPIA2_VP_SYSTEMCTRL_POWER_DOWN_PLL 0x20
+#define CPIA2_VP_SYSTEMCTRL_REQ_SUSPEND_STATE 0x10
+#define CPIA2_VP_SYSTEMCTRL_REQ_SERIAL_WAKEUP 0x08
+#define CPIA2_VP_SYSTEMCTRL_REQ_AUTOLOAD 0x04
+#define CPIA2_VP_SYSTEMCTRL_HK_CONTROL 0x02
+#define CPIA2_VP_SYSTEMCTRL_POWER_CONTROL 0x01
+
+#define CPIA2_VP_SENSOR_FLAGS 0x05
+#define CPIA2_VP_SENSOR_FLAGS_404 0x01
+#define CPIA2_VP_SENSOR_FLAGS_407 0x02
+#define CPIA2_VP_SENSOR_FLAGS_409 0x04
+#define CPIA2_VP_SENSOR_FLAGS_410 0x08
+#define CPIA2_VP_SENSOR_FLAGS_500 0x10
+
+#define CPIA2_VP_SENSOR_REV 0x06
+
+#define CPIA2_VP_DEVICE_CONFIG 0x07
+#define CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE 0x01
+
+#define CPIA2_VP_GPIO_DIRECTION 0x08
+#define CPIA2_VP_GPIO_READ 0xFF
+#define CPIA2_VP_GPIO_WRITE 0x00
+
+#define CPIA2_VP_GPIO_DATA 0x09
+
+#define CPIA2_VP_RAM_ADDR_H 0x0A
+#define CPIA2_VP_RAM_ADDR_L 0x0B
+#define CPIA2_VP_RAM_DATA 0x0C
+
+#define CPIA2_VP_PATCH_REV 0x0F
+
+#define CPIA2_VP4_USER_MODE 0x10
+#define CPIA2_VP5_USER_MODE 0x13
+#define CPIA2_VP_USER_MODE_CIF 0x01
+#define CPIA2_VP_USER_MODE_QCIFDS 0x02
+#define CPIA2_VP_USER_MODE_QCIFPTC 0x04
+#define CPIA2_VP_USER_MODE_QVGADS 0x08
+#define CPIA2_VP_USER_MODE_QVGAPTC 0x10
+#define CPIA2_VP_USER_MODE_VGA 0x20
+
+#define CPIA2_VP4_FRAMERATE_REQUEST 0x11
+#define CPIA2_VP5_FRAMERATE_REQUEST 0x14
+#define CPIA2_VP_FRAMERATE_60 0x80
+#define CPIA2_VP_FRAMERATE_50 0x40
+#define CPIA2_VP_FRAMERATE_30 0x20
+#define CPIA2_VP_FRAMERATE_25 0x10
+#define CPIA2_VP_FRAMERATE_15 0x08
+#define CPIA2_VP_FRAMERATE_12_5 0x04
+#define CPIA2_VP_FRAMERATE_7_5 0x02
+#define CPIA2_VP_FRAMERATE_6_25 0x01
+
+#define CPIA2_VP4_USER_EFFECTS 0x12
+#define CPIA2_VP5_USER_EFFECTS 0x15
+#define CPIA2_VP_USER_EFFECTS_COLBARS 0x01
+#define CPIA2_VP_USER_EFFECTS_COLBARS_GRAD 0x02
+#define CPIA2_VP_USER_EFFECTS_MIRROR 0x04
+#define CPIA2_VP_USER_EFFECTS_FLIP 0x40 // VP5 only
+
+/* NOTE: CPIA2_VP_EXPOSURE_MODES shares the same register as VP5 User
+ * Effects */
+#define CPIA2_VP_EXPOSURE_MODES 0x15
+#define CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER 0x20
+#define CPIA2_VP_EXPOSURE_MODES_COMPILE_EXP 0x10
+
+#define CPIA2_VP4_EXPOSURE_TARGET 0x16 // VP4
+#define CPIA2_VP5_EXPOSURE_TARGET 0x20 // VP5
+
+#define CPIA2_VP_FLICKER_MODES 0x1B
+#define CPIA2_VP_FLICKER_MODES_50HZ 0x80
+#define CPIA2_VP_FLICKER_MODES_CUSTOM_FLT_FFREQ 0x40
+#define CPIA2_VP_FLICKER_MODES_NEVER_FLICKER 0x20
+#define CPIA2_VP_FLICKER_MODES_INHIBIT_RUB 0x10
+#define CPIA2_VP_FLICKER_MODES_ADJUST_LINE_FREQ 0x08
+#define CPIA2_VP_FLICKER_MODES_CUSTOM_INT_FFREQ 0x04
+
+#define CPIA2_VP_UMISC 0x1D
+#define CPIA2_VP_UMISC_FORCE_MONO 0x80
+#define CPIA2_VP_UMISC_FORCE_ID_MASK 0x40
+#define CPIA2_VP_UMISC_INHIBIT_AUTO_FGS 0x20
+#define CPIA2_VP_UMISC_INHIBIT_AUTO_DIMS 0x08
+#define CPIA2_VP_UMISC_OPT_FOR_SENSOR_DS 0x04
+#define CPIA2_VP_UMISC_INHIBIT_AUTO_MODE_INT 0x02
+
+#define CPIA2_VP5_ANTIFLKRSETUP 0x22 //34
+
+#define CPIA2_VP_INTERPOLATION 0x24
+#define CPIA2_VP_INTERPOLATION_EVEN_FIRST 0x40
+#define CPIA2_VP_INTERPOLATION_HJOG 0x20
+#define CPIA2_VP_INTERPOLATION_VJOG 0x10
+
+#define CPIA2_VP_GAMMA 0x25
+#define CPIA2_VP_DEFAULT_GAMMA 0x10
+
+#define CPIA2_VP_YRANGE 0x26
+
+#define CPIA2_VP_SATURATION 0x27
+
+#define CPIA2_VP5_MYBLACK_LEVEL 0x3A //58
+#define CPIA2_VP5_MCYRANGE 0x3B //59
+#define CPIA2_VP5_MYCEILING 0x3C //60
+#define CPIA2_VP5_MCUVSATURATION 0x3D //61
+
+
+#define CPIA2_VP_REHASH_VALUES 0x60
+
+
+/***
+ * Common sensor registers
+ ***/
+#define CPIA2_SENSOR_DEVICE_H 0x00
+#define CPIA2_SENSOR_DEVICE_L 0x01
+
+#define CPIA2_SENSOR_DATA_FORMAT 0x16
+#define CPIA2_SENSOR_DATA_FORMAT_HMIRROR 0x08
+#define CPIA2_SENSOR_DATA_FORMAT_VMIRROR 0x10
+
+#define CPIA2_SENSOR_CR1 0x76
+#define CPIA2_SENSOR_CR1_STAND_BY 0x01
+#define CPIA2_SENSOR_CR1_DOWN_RAMP_GEN 0x02
+#define CPIA2_SENSOR_CR1_DOWN_COLUMN_ADC 0x04
+#define CPIA2_SENSOR_CR1_DOWN_CAB_REGULATOR 0x08
+#define CPIA2_SENSOR_CR1_DOWN_AUDIO_REGULATOR 0x10
+#define CPIA2_SENSOR_CR1_DOWN_VRT_AMP 0x20
+#define CPIA2_SENSOR_CR1_DOWN_BAND_GAP 0x40
+
+#endif
diff --git a/drivers/media/video/cpia2/cpia2_usb.c b/drivers/media/video/cpia2/cpia2_usb.c
new file mode 100644
index 00000000000..f4da0294149
--- /dev/null
+++ b/drivers/media/video/cpia2/cpia2_usb.c
@@ -0,0 +1,907 @@
+/****************************************************************************
+ *
+ * Filename: cpia2_usb.c
+ *
+ * Copyright 2001, STMicrolectronics, Inc.
+ * Contact: steve.miller@st.com
+ *
+ * Description:
+ * This is a USB driver for CPia2 based video cameras.
+ * The infrastructure of this driver is based on the cpia usb driver by
+ * Jochen Scharrlach and Johannes Erdfeldt.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Stripped of 2.4 stuff ready for main kernel submit by
+ * Alan Cox <alan@redhat.com>
+ ****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include "cpia2.h"
+
+static int frame_sizes[] = {
+ 0, // USBIF_CMDONLY
+ 0, // USBIF_BULK
+ 128, // USBIF_ISO_1
+ 384, // USBIF_ISO_2
+ 640, // USBIF_ISO_3
+ 768, // USBIF_ISO_4
+ 896, // USBIF_ISO_5
+ 1023, // USBIF_ISO_6
+};
+
+#define FRAMES_PER_DESC 10
+#define FRAME_SIZE_PER_DESC frame_sizes[cam->cur_alt]
+
+static void process_frame(struct camera_data *cam);
+static void cpia2_usb_complete(struct urb *urb, struct pt_regs *);
+static int cpia2_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id);
+static void cpia2_usb_disconnect(struct usb_interface *intf);
+
+static void free_sbufs(struct camera_data *cam);
+static void add_APPn(struct camera_data *cam);
+static void add_COM(struct camera_data *cam);
+static int submit_urbs(struct camera_data *cam);
+static int set_alternate(struct camera_data *cam, unsigned int alt);
+static int configure_transfer_mode(struct camera_data *cam, unsigned int alt);
+
+static struct usb_device_id cpia2_id_table[] = {
+ {USB_DEVICE(0x0553, 0x0100)},
+ {USB_DEVICE(0x0553, 0x0140)},
+ {USB_DEVICE(0x0553, 0x0151)}, /* STV0676 */
+ {} /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, cpia2_id_table);
+
+static struct usb_driver cpia2_driver = {
+ .name = "cpia2",
+ .probe = cpia2_usb_probe,
+ .disconnect = cpia2_usb_disconnect,
+ .id_table = cpia2_id_table
+};
+
+
+/******************************************************************************
+ *
+ * process_frame
+ *
+ *****************************************************************************/
+static void process_frame(struct camera_data *cam)
+{
+ static int frame_count = 0;
+
+ unsigned char *inbuff = cam->workbuff->data;
+
+ DBG("Processing frame #%d, current:%d\n",
+ cam->workbuff->num, cam->curbuff->num);
+
+ if(cam->workbuff->length > cam->workbuff->max_length)
+ cam->workbuff->max_length = cam->workbuff->length;
+
+ if ((inbuff[0] == 0xFF) && (inbuff[1] == 0xD8)) {
+ frame_count++;
+ } else {
+ cam->workbuff->status = FRAME_ERROR;
+ DBG("Start of frame not found\n");
+ return;
+ }
+
+ /***
+ * Now the output buffer should have a JPEG image in it.
+ ***/
+ if(!cam->first_image_seen) {
+ /* Always skip the first image after streaming
+ * starts. It is almost certainly corrupt. */
+ cam->first_image_seen = 1;
+ cam->workbuff->status = FRAME_EMPTY;
+ return;
+ }
+ if (cam->workbuff->length > 3) {
+ if(cam->mmapped &&
+ cam->workbuff->length < cam->workbuff->max_length) {
+ /* No junk in the buffers */
+ memset(cam->workbuff->data+cam->workbuff->length,
+ 0, cam->workbuff->max_length-
+ cam->workbuff->length);
+ }
+ cam->workbuff->max_length = cam->workbuff->length;
+ cam->workbuff->status = FRAME_READY;
+
+ if(!cam->mmapped && cam->num_frames > 2) {
+ /* During normal reading, the most recent
+ * frame will be read. If the current frame
+ * hasn't started reading yet, it will never
+ * be read, so mark it empty. If the buffer is
+ * mmapped, or we have few buffers, we need to
+ * wait for the user to free the buffer.
+ *
+ * NOTE: This is not entirely foolproof with 3
+ * buffers, but it would take an EXTREMELY
+ * overloaded system to cause problems (possible
+ * image data corruption). Basically, it would
+ * need to take more time to execute cpia2_read
+ * than it would for the camera to send
+ * cam->num_frames-2 frames before problems
+ * could occur.
+ */
+ cam->curbuff->status = FRAME_EMPTY;
+ }
+ cam->curbuff = cam->workbuff;
+ cam->workbuff = cam->workbuff->next;
+ DBG("Changed buffers, work:%d, current:%d\n",
+ cam->workbuff->num, cam->curbuff->num);
+ return;
+ } else {
+ DBG("Not enough data for an image.\n");
+ }
+
+ cam->workbuff->status = FRAME_ERROR;
+ return;
+}
+
+/******************************************************************************
+ *
+ * add_APPn
+ *
+ * Adds a user specified APPn record
+ *****************************************************************************/
+static void add_APPn(struct camera_data *cam)
+{
+ if(cam->APP_len > 0) {
+ cam->workbuff->data[cam->workbuff->length++] = 0xFF;
+ cam->workbuff->data[cam->workbuff->length++] = 0xE0+cam->APPn;
+ cam->workbuff->data[cam->workbuff->length++] = 0;
+ cam->workbuff->data[cam->workbuff->length++] = cam->APP_len+2;
+ memcpy(cam->workbuff->data+cam->workbuff->length,
+ cam->APP_data, cam->APP_len);
+ cam->workbuff->length += cam->APP_len;
+ }
+}
+
+/******************************************************************************
+ *
+ * add_COM
+ *
+ * Adds a user specified COM record
+ *****************************************************************************/
+static void add_COM(struct camera_data *cam)
+{
+ if(cam->COM_len > 0) {
+ cam->workbuff->data[cam->workbuff->length++] = 0xFF;
+ cam->workbuff->data[cam->workbuff->length++] = 0xFE;
+ cam->workbuff->data[cam->workbuff->length++] = 0;
+ cam->workbuff->data[cam->workbuff->length++] = cam->COM_len+2;
+ memcpy(cam->workbuff->data+cam->workbuff->length,
+ cam->COM_data, cam->COM_len);
+ cam->workbuff->length += cam->COM_len;
+ }
+}
+
+/******************************************************************************
+ *
+ * cpia2_usb_complete
+ *
+ * callback when incoming packet is received
+ *****************************************************************************/
+static void cpia2_usb_complete(struct urb *urb, struct pt_regs *regs)
+{
+ int i;
+ unsigned char *cdata;
+ static int frame_ready = false;
+ struct camera_data *cam = (struct camera_data *) urb->context;
+
+ if (urb->status!=0) {
+ if (!(urb->status == -ENOENT ||
+ urb->status == -ECONNRESET ||
+ urb->status == -ESHUTDOWN))
+ {
+ DBG("urb->status = %d!\n", urb->status);
+ }
+ DBG("Stopping streaming\n");
+ return;
+ }
+
+ if (!cam->streaming || !cam->present || cam->open_count == 0) {
+ LOG("Will now stop the streaming: streaming = %d, "
+ "present=%d, open_count=%d\n",
+ cam->streaming, cam->present, cam->open_count);
+ return;
+ }
+
+ /***
+ * Packet collater
+ ***/
+ //DBG("Collating %d packets\n", urb->number_of_packets);
+ for (i = 0; i < urb->number_of_packets; i++) {
+ u16 checksum, iso_checksum;
+ int j;
+ int n = urb->iso_frame_desc[i].actual_length;
+ int st = urb->iso_frame_desc[i].status;
+
+ if(cam->workbuff->status == FRAME_READY) {
+ struct framebuf *ptr;
+ /* Try to find an available buffer */
+ DBG("workbuff full, searching\n");
+ for (ptr = cam->workbuff->next;
+ ptr != cam->workbuff;
+ ptr = ptr->next)
+ {
+ if (ptr->status == FRAME_EMPTY) {
+ ptr->status = FRAME_READING;
+ ptr->length = 0;
+ break;
+ }
+ }
+ if (ptr == cam->workbuff)
+ break; /* No READING or EMPTY buffers left */
+
+ cam->workbuff = ptr;
+ }
+
+ if (cam->workbuff->status == FRAME_EMPTY ||
+ cam->workbuff->status == FRAME_ERROR) {
+ cam->workbuff->status = FRAME_READING;
+ cam->workbuff->length = 0;
+ }
+
+ //DBG(" Packet %d length = %d, status = %d\n", i, n, st);
+ cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+ if (st) {
+ LOG("cpia2 data error: [%d] len=%d, status = %d\n",
+ i, n, st);
+ if(!ALLOW_CORRUPT)
+ cam->workbuff->status = FRAME_ERROR;
+ continue;
+ }
+
+ if(n<=2)
+ continue;
+
+ checksum = 0;
+ for(j=0; j<n-2; ++j)
+ checksum += cdata[j];
+ iso_checksum = cdata[j] + cdata[j+1]*256;
+ if(checksum != iso_checksum) {
+ LOG("checksum mismatch: [%d] len=%d, calculated = %x, checksum = %x\n",
+ i, n, (int)checksum, (int)iso_checksum);
+ if(!ALLOW_CORRUPT) {
+ cam->workbuff->status = FRAME_ERROR;
+ continue;
+ }
+ }
+ n -= 2;
+
+ if(cam->workbuff->status != FRAME_READING) {
+ if((0xFF == cdata[0] && 0xD8 == cdata[1]) ||
+ (0xD8 == cdata[0] && 0xFF == cdata[1] &&
+ 0 != cdata[2])) {
+ /* frame is skipped, but increment total
+ * frame count anyway */
+ cam->frame_count++;
+ }
+ DBG("workbuff not reading, status=%d\n",
+ cam->workbuff->status);
+ continue;
+ }
+
+ if (cam->frame_size < cam->workbuff->length + n) {
+ ERR("buffer overflow! length: %d, n: %d\n",
+ cam->workbuff->length, n);
+ cam->workbuff->status = FRAME_ERROR;
+ if(cam->workbuff->length > cam->workbuff->max_length)
+ cam->workbuff->max_length =
+ cam->workbuff->length;
+ continue;
+ }
+
+ if (cam->workbuff->length == 0) {
+ int data_offset;
+ if ((0xD8 == cdata[0]) && (0xFF == cdata[1])) {
+ data_offset = 1;
+ } else if((0xFF == cdata[0]) && (0xD8 == cdata[1])
+ && (0xFF == cdata[2])) {
+ data_offset = 2;
+ } else {
+ DBG("Ignoring packet, not beginning!\n");
+ continue;
+ }
+ DBG("Start of frame pattern found\n");
+ do_gettimeofday(&cam->workbuff->timestamp);
+ cam->workbuff->seq = cam->frame_count++;
+ cam->workbuff->data[0] = 0xFF;
+ cam->workbuff->data[1] = 0xD8;
+ cam->workbuff->length = 2;
+ add_APPn(cam);
+ add_COM(cam);
+ memcpy(cam->workbuff->data+cam->workbuff->length,
+ cdata+data_offset, n-data_offset);
+ cam->workbuff->length += n-data_offset;
+ } else if (cam->workbuff->length > 0) {
+ memcpy(cam->workbuff->data + cam->workbuff->length,
+ cdata, n);
+ cam->workbuff->length += n;
+ }
+
+ if ((cam->workbuff->length >= 3) &&
+ (cam->workbuff->data[cam->workbuff->length - 3] == 0xFF) &&
+ (cam->workbuff->data[cam->workbuff->length - 2] == 0xD9) &&
+ (cam->workbuff->data[cam->workbuff->length - 1] == 0xFF)) {
+ frame_ready = true;
+ cam->workbuff->data[cam->workbuff->length - 1] = 0;
+ cam->workbuff->length -= 1;
+ } else if ((cam->workbuff->length >= 2) &&
+ (cam->workbuff->data[cam->workbuff->length - 2] == 0xFF) &&
+ (cam->workbuff->data[cam->workbuff->length - 1] == 0xD9)) {
+ frame_ready = true;
+ }
+
+ if (frame_ready) {
+ DBG("Workbuff image size = %d\n",cam->workbuff->length);
+ process_frame(cam);
+
+ frame_ready = false;
+
+ if (waitqueue_active(&cam->wq_stream))
+ wake_up_interruptible(&cam->wq_stream);
+ }
+ }
+
+ if(cam->streaming) {
+ /* resubmit */
+ urb->dev = cam->dev;
+ if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0)
+ ERR("%s: usb_submit_urb ret %d!\n", __func__, i);
+ }
+}
+
+/******************************************************************************
+ *
+ * configure_transfer_mode
+ *
+ *****************************************************************************/
+static int configure_transfer_mode(struct camera_data *cam, unsigned int alt)
+{
+ static unsigned char iso_regs[8][4] = {
+ {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00},
+ {0xB9, 0x00, 0x00, 0x7E},
+ {0xB9, 0x00, 0x01, 0x7E},
+ {0xB9, 0x00, 0x02, 0x7E},
+ {0xB9, 0x00, 0x02, 0xFE},
+ {0xB9, 0x00, 0x03, 0x7E},
+ {0xB9, 0x00, 0x03, 0xFD}
+ };
+ struct cpia2_command cmd;
+ unsigned char reg;
+
+ if(!cam->present)
+ return -ENODEV;
+
+ /***
+ * Write the isoc registers according to the alternate selected
+ ***/
+ cmd.direction = TRANSFER_WRITE;
+ cmd.buffer.block_data[0] = iso_regs[alt][0];
+ cmd.buffer.block_data[1] = iso_regs[alt][1];
+ cmd.buffer.block_data[2] = iso_regs[alt][2];
+ cmd.buffer.block_data[3] = iso_regs[alt][3];
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+ cmd.start = CPIA2_VC_USB_ISOLIM;
+ cmd.reg_count = 4;
+ cpia2_send_command(cam, &cmd);
+
+ /***
+ * Enable relevant streams before starting polling.
+ * First read USB Stream Config Register.
+ ***/
+ cmd.direction = TRANSFER_READ;
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+ cmd.start = CPIA2_VC_USB_STRM;
+ cmd.reg_count = 1;
+ cpia2_send_command(cam, &cmd);
+ reg = cmd.buffer.block_data[0];
+
+ /* Clear iso, bulk, and int */
+ reg &= ~(CPIA2_VC_USB_STRM_BLK_ENABLE |
+ CPIA2_VC_USB_STRM_ISO_ENABLE |
+ CPIA2_VC_USB_STRM_INT_ENABLE);
+
+ if (alt == USBIF_BULK) {
+ DBG("Enabling bulk xfer\n");
+ reg |= CPIA2_VC_USB_STRM_BLK_ENABLE; /* Enable Bulk */
+ cam->xfer_mode = XFER_BULK;
+ } else if (alt >= USBIF_ISO_1) {
+ DBG("Enabling ISOC xfer\n");
+ reg |= CPIA2_VC_USB_STRM_ISO_ENABLE;
+ cam->xfer_mode = XFER_ISOC;
+ }
+
+ cmd.buffer.block_data[0] = reg;
+ cmd.direction = TRANSFER_WRITE;
+ cmd.start = CPIA2_VC_USB_STRM;
+ cmd.reg_count = 1;
+ cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+ cpia2_send_command(cam, &cmd);
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * cpia2_usb_change_streaming_alternate
+ *
+ *****************************************************************************/
+int cpia2_usb_change_streaming_alternate(struct camera_data *cam,
+ unsigned int alt)
+{
+ int ret = 0;
+
+ if(alt < USBIF_ISO_1 || alt > USBIF_ISO_6)
+ return -EINVAL;
+
+ if(alt == cam->params.camera_state.stream_mode)
+ return 0;
+
+ cpia2_usb_stream_pause(cam);
+
+ configure_transfer_mode(cam, alt);
+
+ cam->params.camera_state.stream_mode = alt;
+
+ /* Reset the camera to prevent image quality degradation */
+ cpia2_reset_camera(cam);
+
+ cpia2_usb_stream_resume(cam);
+
+ return ret;
+}
+
+/******************************************************************************
+ *
+ * set_alternate
+ *
+ *****************************************************************************/
+int set_alternate(struct camera_data *cam, unsigned int alt)
+{
+ int ret = 0;
+
+ if(alt == cam->cur_alt)
+ return 0;
+
+ if (cam->cur_alt != USBIF_CMDONLY) {
+ DBG("Changing from alt %d to %d\n", cam->cur_alt, USBIF_CMDONLY);
+ ret = usb_set_interface(cam->dev, cam->iface, USBIF_CMDONLY);
+ if (ret != 0)
+ return ret;
+ }
+ if (alt != USBIF_CMDONLY) {
+ DBG("Changing from alt %d to %d\n", USBIF_CMDONLY, alt);
+ ret = usb_set_interface(cam->dev, cam->iface, alt);
+ if (ret != 0)
+ return ret;
+ }
+
+ cam->old_alt = cam->cur_alt;
+ cam->cur_alt = alt;
+
+ return ret;
+}
+
+/******************************************************************************
+ *
+ * free_sbufs
+ *
+ * Free all cam->sbuf[]. All non-NULL .data and .urb members that are non-NULL
+ * are assumed to be allocated. Non-NULL .urb members are also assumed to be
+ * submitted (and must therefore be killed before they are freed).
+ *****************************************************************************/
+static void free_sbufs(struct camera_data *cam)
+{
+ int i;
+
+ for (i = 0; i < NUM_SBUF; i++) {
+ if(cam->sbuf[i].urb) {
+ usb_kill_urb(cam->sbuf[i].urb);
+ usb_free_urb(cam->sbuf[i].urb);
+ cam->sbuf[i].urb = NULL;
+ }
+ if(cam->sbuf[i].data) {
+ kfree(cam->sbuf[i].data);
+ cam->sbuf[i].data = NULL;
+ }
+ }
+}
+
+/*******
+* Convenience functions
+*******/
+/****************************************************************************
+ *
+ * write_packet
+ *
+ ***************************************************************************/
+static int write_packet(struct usb_device *udev,
+ u8 request, u8 * registers, u16 start, size_t size)
+{
+ if (!registers || size <= 0)
+ return -EINVAL;
+
+ return usb_control_msg(udev,
+ usb_sndctrlpipe(udev, 0),
+ request,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ start, /* value */
+ 0, /* index */
+ registers, /* buffer */
+ size,
+ HZ);
+}
+
+/****************************************************************************
+ *
+ * read_packet
+ *
+ ***************************************************************************/
+static int read_packet(struct usb_device *udev,
+ u8 request, u8 * registers, u16 start, size_t size)
+{
+ if (!registers || size <= 0)
+ return -EINVAL;
+
+ return usb_control_msg(udev,
+ usb_rcvctrlpipe(udev, 0),
+ request,
+ USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_DEVICE,
+ start, /* value */
+ 0, /* index */
+ registers, /* buffer */
+ size,
+ HZ);
+}
+
+/******************************************************************************
+ *
+ * cpia2_usb_transfer_cmd
+ *
+ *****************************************************************************/
+int cpia2_usb_transfer_cmd(struct camera_data *cam,
+ void *registers,
+ u8 request, u8 start, u8 count, u8 direction)
+{
+ int err = 0;
+ struct usb_device *udev = cam->dev;
+
+ if (!udev) {
+ ERR("%s: Internal driver error: udev is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!registers) {
+ ERR("%s: Internal driver error: register array is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ if (direction == TRANSFER_READ) {
+ err = read_packet(udev, request, (u8 *)registers, start, count);
+ if (err > 0)
+ err = 0;
+ } else if (direction == TRANSFER_WRITE) {
+ err =write_packet(udev, request, (u8 *)registers, start, count);
+ if (err < 0) {
+ LOG("Control message failed, err val = %d\n", err);
+ LOG("Message: request = 0x%0X, start = 0x%0X\n",
+ request, start);
+ LOG("Message: count = %d, register[0] = 0x%0X\n",
+ count, ((unsigned char *) registers)[0]);
+ } else
+ err=0;
+ } else {
+ LOG("Unexpected first byte of direction: %d\n",
+ direction);
+ return -EINVAL;
+ }
+
+ if(err != 0)
+ LOG("Unexpected error: %d\n", err);
+ return err;
+}
+
+
+/******************************************************************************
+ *
+ * submit_urbs
+ *
+ *****************************************************************************/
+static int submit_urbs(struct camera_data *cam)
+{
+ struct urb *urb;
+ int fx, err, i;
+
+ for(i=0; i<NUM_SBUF; ++i) {
+ if (cam->sbuf[i].data)
+ continue;
+ cam->sbuf[i].data =
+ kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
+ if (!cam->sbuf[i].data) {
+ return -ENOMEM;
+ }
+ }
+
+ /* We double buffer the Isoc lists, and also know the polling
+ * interval is every frame (1 == (1 << (bInterval -1))).
+ */
+ for(i=0; i<NUM_SBUF; ++i) {
+ if(cam->sbuf[i].urb) {
+ continue;
+ }
+ urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
+ if (!urb) {
+ return -ENOMEM;
+ }
+
+ cam->sbuf[i].urb = urb;
+ urb->dev = cam->dev;
+ urb->context = cam;
+ urb->pipe = usb_rcvisocpipe(cam->dev, 1 /*ISOC endpoint*/);
+ urb->transfer_flags = URB_ISO_ASAP;
+ urb->transfer_buffer = cam->sbuf[i].data;
+ urb->complete = cpia2_usb_complete;
+ urb->number_of_packets = FRAMES_PER_DESC;
+ urb->interval = 1;
+ urb->transfer_buffer_length =
+ FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
+
+ for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
+ urb->iso_frame_desc[fx].offset =
+ FRAME_SIZE_PER_DESC * fx;
+ urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
+ }
+ }
+
+
+ /* Queue the ISO urbs, and resubmit in the completion handler */
+ for(i=0; i<NUM_SBUF; ++i) {
+ err = usb_submit_urb(cam->sbuf[i].urb, GFP_KERNEL);
+ if (err) {
+ ERR("usb_submit_urb[%d]() = %d\n", i, err);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * cpia2_usb_stream_start
+ *
+ *****************************************************************************/
+int cpia2_usb_stream_start(struct camera_data *cam, unsigned int alternate)
+{
+ int ret;
+ int old_alt;
+
+ if(cam->streaming)
+ return 0;
+
+ if (cam->flush) {
+ int i;
+ DBG("Flushing buffers\n");
+ for(i=0; i<cam->num_frames; ++i) {
+ cam->buffers[i].status = FRAME_EMPTY;
+ cam->buffers[i].length = 0;
+ }
+ cam->curbuff = &cam->buffers[0];
+ cam->workbuff = cam->curbuff->next;
+ cam->flush = false;
+ }
+
+ old_alt = cam->params.camera_state.stream_mode;
+ cam->params.camera_state.stream_mode = 0;
+ ret = cpia2_usb_change_streaming_alternate(cam, alternate);
+ if (ret < 0) {
+ int ret2;
+ ERR("cpia2_usb_change_streaming_alternate() = %d!\n", ret);
+ cam->params.camera_state.stream_mode = old_alt;
+ ret2 = set_alternate(cam, USBIF_CMDONLY);
+ if (ret2 < 0) {
+ ERR("cpia2_usb_change_streaming_alternate(%d) =%d has already "
+ "failed. Then tried to call "
+ "set_alternate(USBIF_CMDONLY) = %d.\n",
+ alternate, ret, ret2);
+ }
+ } else {
+ cam->frame_count = 0;
+ cam->streaming = 1;
+ ret = cpia2_usb_stream_resume(cam);
+ }
+ return ret;
+}
+
+/******************************************************************************
+ *
+ * cpia2_usb_stream_pause
+ *
+ *****************************************************************************/
+int cpia2_usb_stream_pause(struct camera_data *cam)
+{
+ int ret = 0;
+ if(cam->streaming) {
+ ret = set_alternate(cam, USBIF_CMDONLY);
+ free_sbufs(cam);
+ }
+ return ret;
+}
+
+/******************************************************************************
+ *
+ * cpia2_usb_stream_resume
+ *
+ *****************************************************************************/
+int cpia2_usb_stream_resume(struct camera_data *cam)
+{
+ int ret = 0;
+ if(cam->streaming) {
+ cam->first_image_seen = 0;
+ ret = set_alternate(cam, cam->params.camera_state.stream_mode);
+ if(ret == 0) {
+ ret = submit_urbs(cam);
+ }
+ }
+ return ret;
+}
+
+/******************************************************************************
+ *
+ * cpia2_usb_stream_stop
+ *
+ *****************************************************************************/
+int cpia2_usb_stream_stop(struct camera_data *cam)
+{
+ int ret;
+ ret = cpia2_usb_stream_pause(cam);
+ cam->streaming = 0;
+ configure_transfer_mode(cam, 0);
+ return ret;
+}
+
+/******************************************************************************
+ *
+ * cpia2_usb_probe
+ *
+ * Probe and initialize.
+ *****************************************************************************/
+static int cpia2_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct usb_interface_descriptor *interface;
+ struct camera_data *cam;
+ int ret;
+
+ /* A multi-config CPiA2 camera? */
+ if (udev->descriptor.bNumConfigurations != 1)
+ return -ENODEV;
+ interface = &intf->cur_altsetting->desc;
+
+ /* If we get to this point, we found a CPiA2 camera */
+ LOG("CPiA2 USB camera found\n");
+
+ if((cam = cpia2_init_camera_struct()) == NULL)
+ return -ENOMEM;
+
+ cam->dev = udev;
+ cam->iface = interface->bInterfaceNumber;
+
+ ret = set_alternate(cam, USBIF_CMDONLY);
+ if (ret < 0) {
+ ERR("%s: usb_set_interface error (ret = %d)\n", __func__, ret);
+ kfree(cam);
+ return ret;
+ }
+
+ if ((ret = cpia2_register_camera(cam)) < 0) {
+ ERR("%s: Failed to register cpia2 camera (ret = %d)\n", __func__, ret);
+ kfree(cam);
+ return ret;
+ }
+
+
+ if((ret = cpia2_init_camera(cam)) < 0) {
+ ERR("%s: failed to initialize cpia2 camera (ret = %d)\n", __func__, ret);
+ cpia2_unregister_camera(cam);
+ kfree(cam);
+ return ret;
+ }
+ LOG(" CPiA Version: %d.%02d (%d.%d)\n",
+ cam->params.version.firmware_revision_hi,
+ cam->params.version.firmware_revision_lo,
+ cam->params.version.asic_id,
+ cam->params.version.asic_rev);
+ LOG(" CPiA PnP-ID: %04x:%04x:%04x\n",
+ cam->params.pnp_id.vendor,
+ cam->params.pnp_id.product,
+ cam->params.pnp_id.device_revision);
+ LOG(" SensorID: %d.(version %d)\n",
+ cam->params.version.sensor_flags,
+ cam->params.version.sensor_rev);
+
+ usb_set_intfdata(intf, cam);
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * cpia2_disconnect
+ *
+ *****************************************************************************/
+static void cpia2_usb_disconnect(struct usb_interface *intf)
+{
+ struct camera_data *cam = usb_get_intfdata(intf);
+ usb_set_intfdata(intf, NULL);
+ cam->present = 0;
+
+ DBG("Stopping stream\n");
+ cpia2_usb_stream_stop(cam);
+
+ DBG("Unregistering camera\n");
+ cpia2_unregister_camera(cam);
+
+ if(cam->buffers) {
+ DBG("Wakeup waiting processes\n");
+ cam->curbuff->status = FRAME_READY;
+ cam->curbuff->length = 0;
+ if (waitqueue_active(&cam->wq_stream))
+ wake_up_interruptible(&cam->wq_stream);
+ }
+
+ DBG("Releasing interface\n");
+ usb_driver_release_interface(&cpia2_driver, intf);
+
+ if (cam->open_count == 0) {
+ DBG("Freeing camera structure\n");
+ kfree(cam);
+ }
+
+ LOG("CPiA2 camera disconnected.\n");
+}
+
+
+/******************************************************************************
+ *
+ * usb_cpia2_init
+ *
+ *****************************************************************************/
+int cpia2_usb_init(void)
+{
+ return usb_register(&cpia2_driver);
+}
+
+/******************************************************************************
+ *
+ * usb_cpia_cleanup
+ *
+ *****************************************************************************/
+void cpia2_usb_cleanup(void)
+{
+ schedule_timeout(2 * HZ);
+ usb_deregister(&cpia2_driver);
+}
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
new file mode 100644
index 00000000000..08f8be345fa
--- /dev/null
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -0,0 +1,2079 @@
+/****************************************************************************
+ *
+ * Filename: cpia2_v4l.c
+ *
+ * Copyright 2001, STMicrolectronics, Inc.
+ * Contact: steve.miller@st.com
+ * Copyright 2001,2005, Scott J. Bertin <scottbertin@yahoo.com>
+ *
+ * Description:
+ * This is a USB driver for CPia2 based video cameras.
+ * The infrastructure of this driver is based on the cpia usb driver by
+ * Jochen Scharrlach and Johannes Erdfeldt.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Stripped of 2.4 stuff ready for main kernel submit by
+ * Alan Cox <alan@redhat.com>
+ ****************************************************************************/
+
+#include <linux/version.h>
+
+#include <linux/config.h>
+
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+
+#include "cpia2.h"
+#include "cpia2dev.h"
+
+
+//#define _CPIA2_DEBUG_
+
+#define MAKE_STRING_1(x) #x
+#define MAKE_STRING(x) MAKE_STRING_1(x)
+
+static int video_nr = -1;
+module_param(video_nr, int, 0);
+MODULE_PARM_DESC(video_nr,"video device to register (0=/dev/video0, etc)");
+
+static int buffer_size = 68*1024;
+module_param(buffer_size, int, 0);
+MODULE_PARM_DESC(buffer_size, "Size for each frame buffer in bytes (default 68k)");
+
+static int num_buffers = 3;
+module_param(num_buffers, int, 0);
+MODULE_PARM_DESC(num_buffers, "Number of frame buffers (1-"
+ MAKE_STRING(VIDEO_MAX_FRAME) ", default 3)");
+
+static int alternate = DEFAULT_ALT;
+module_param(alternate, int, 0);
+MODULE_PARM_DESC(alternate, "USB Alternate (" MAKE_STRING(USBIF_ISO_1) "-"
+ MAKE_STRING(USBIF_ISO_6) ", default "
+ MAKE_STRING(DEFAULT_ALT) ")");
+
+static int flicker_freq = 60;
+module_param(flicker_freq, int, 0);
+MODULE_PARM_DESC(flicker_freq, "Flicker frequency (" MAKE_STRING(50) "or"
+ MAKE_STRING(60) ", default "
+ MAKE_STRING(60) ")");
+
+static int flicker_mode = NEVER_FLICKER;
+module_param(flicker_mode, int, 0);
+MODULE_PARM_DESC(flicker_mode,
+ "Flicker supression (" MAKE_STRING(NEVER_FLICKER) "or"
+ MAKE_STRING(ANTI_FLICKER_ON) ", default "
+ MAKE_STRING(NEVER_FLICKER) ")");
+
+MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>");
+MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras");
+MODULE_SUPPORTED_DEVICE("video");
+MODULE_LICENSE("GPL");
+
+#define ABOUT "V4L-Driver for Vision CPiA2 based cameras"
+
+#ifndef VID_HARDWARE_CPIA2
+#error "VID_HARDWARE_CPIA2 should have been defined in linux/videodev.h"
+#endif
+
+struct control_menu_info {
+ int value;
+ char name[32];
+};
+
+static struct control_menu_info framerate_controls[] =
+{
+ { CPIA2_VP_FRAMERATE_6_25, "6.25 fps" },
+ { CPIA2_VP_FRAMERATE_7_5, "7.5 fps" },
+ { CPIA2_VP_FRAMERATE_12_5, "12.5 fps" },
+ { CPIA2_VP_FRAMERATE_15, "15 fps" },
+ { CPIA2_VP_FRAMERATE_25, "25 fps" },
+ { CPIA2_VP_FRAMERATE_30, "30 fps" },
+};
+#define NUM_FRAMERATE_CONTROLS (sizeof(framerate_controls)/sizeof(framerate_controls[0]))
+
+static struct control_menu_info flicker_controls[] =
+{
+ { NEVER_FLICKER, "Off" },
+ { FLICKER_50, "50 Hz" },
+ { FLICKER_60, "60 Hz" },
+};
+#define NUM_FLICKER_CONTROLS (sizeof(flicker_controls)/sizeof(flicker_controls[0]))
+
+static struct control_menu_info lights_controls[] =
+{
+ { 0, "Off" },
+ { 64, "Top" },
+ { 128, "Bottom" },
+ { 192, "Both" },
+};
+#define NUM_LIGHTS_CONTROLS (sizeof(lights_controls)/sizeof(lights_controls[0]))
+#define GPIO_LIGHTS_MASK 192
+
+static struct v4l2_queryctrl controls[] = {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = DEFAULT_BRIGHTNESS,
+ },
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = DEFAULT_CONTRAST,
+ },
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = DEFAULT_SATURATION,
+ },
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Mirror Horizontally",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Flip Vertically",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = CPIA2_CID_TARGET_KB,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Target KB",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = DEFAULT_TARGET_KB,
+ },
+ {
+ .id = CPIA2_CID_GPIO,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "GPIO",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = CPIA2_CID_FLICKER_MODE,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .name = "Flicker Reduction",
+ .minimum = 0,
+ .maximum = NUM_FLICKER_CONTROLS-1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = CPIA2_CID_FRAMERATE,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .name = "Framerate",
+ .minimum = 0,
+ .maximum = NUM_FRAMERATE_CONTROLS-1,
+ .step = 1,
+ .default_value = NUM_FRAMERATE_CONTROLS-1,
+ },
+ {
+ .id = CPIA2_CID_USB_ALT,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "USB Alternate",
+ .minimum = USBIF_ISO_1,
+ .maximum = USBIF_ISO_6,
+ .step = 1,
+ .default_value = DEFAULT_ALT,
+ },
+ {
+ .id = CPIA2_CID_LIGHTS,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .name = "Lights",
+ .minimum = 0,
+ .maximum = NUM_LIGHTS_CONTROLS-1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = CPIA2_CID_RESET_CAMERA,
+ .type = V4L2_CTRL_TYPE_BUTTON,
+ .name = "Reset Camera",
+ .minimum = 0,
+ .maximum = 0,
+ .step = 0,
+ .default_value = 0,
+ },
+};
+#define NUM_CONTROLS (sizeof(controls)/sizeof(controls[0]))
+
+
+/******************************************************************************
+ *
+ * cpia2_open
+ *
+ *****************************************************************************/
+static int cpia2_open(struct inode *inode, struct file *file)
+{
+ struct video_device *dev = video_devdata(file);
+ struct camera_data *cam = video_get_drvdata(dev);
+ int retval = 0;
+
+ if (!cam) {
+ ERR("Internal error, camera_data not found!\n");
+ return -ENODEV;
+ }
+
+ if(down_interruptible(&cam->busy_lock))
+ return -ERESTARTSYS;
+
+ if(!cam->present) {
+ retval = -ENODEV;
+ goto err_return;
+ }
+
+ if (cam->open_count > 0) {
+ goto skip_init;
+ }
+
+ if (cpia2_allocate_buffers(cam)) {
+ retval = -ENOMEM;
+ goto err_return;
+ }
+
+ /* reset the camera */
+ if (cpia2_reset_camera(cam) < 0) {
+ retval = -EIO;
+ goto err_return;
+ }
+
+ cam->APP_len = 0;
+ cam->COM_len = 0;
+
+skip_init:
+ {
+ struct cpia2_fh *fh = kmalloc(sizeof(*fh),GFP_KERNEL);
+ if(!fh) {
+ retval = -ENOMEM;
+ goto err_return;
+ }
+ file->private_data = fh;
+ fh->prio = V4L2_PRIORITY_UNSET;
+ v4l2_prio_open(&cam->prio, &fh->prio);
+ fh->mmapped = 0;
+ }
+
+ ++cam->open_count;
+
+ cpia2_dbg_dump_registers(cam);
+
+err_return:
+ up(&cam->busy_lock);
+ return retval;
+}
+
+/******************************************************************************
+ *
+ * cpia2_close
+ *
+ *****************************************************************************/
+static int cpia2_close(struct inode *inode, struct file *file)
+{
+ struct video_device *dev = video_devdata(file);
+ struct camera_data *cam = video_get_drvdata(dev);
+ struct cpia2_fh *fh = file->private_data;
+
+ down(&cam->busy_lock);
+
+ if (cam->present &&
+ (cam->open_count == 1
+ || fh->prio == V4L2_PRIORITY_RECORD
+ )) {
+ cpia2_usb_stream_stop(cam);
+
+ if(cam->open_count == 1) {
+ /* save camera state for later open */
+ cpia2_save_camera_state(cam);
+
+ cpia2_set_low_power(cam);
+ cpia2_free_buffers(cam);
+ }
+ }
+
+ {
+ if(fh->mmapped)
+ cam->mmapped = 0;
+ v4l2_prio_close(&cam->prio,&fh->prio);
+ file->private_data = NULL;
+ kfree(fh);
+ }
+
+ if (--cam->open_count == 0) {
+ cpia2_free_buffers(cam);
+ if (!cam->present) {
+ video_unregister_device(dev);
+ kfree(cam);
+ }
+ }
+
+ up(&cam->busy_lock);
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * cpia2_v4l_read
+ *
+ *****************************************************************************/
+static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count,
+ loff_t *off)
+{
+ struct video_device *dev = video_devdata(file);
+ struct camera_data *cam = video_get_drvdata(dev);
+ int noblock = file->f_flags&O_NONBLOCK;
+
+ struct cpia2_fh *fh = file->private_data;
+
+ if(!cam)
+ return -EINVAL;
+
+ /* Priority check */
+ if(fh->prio != V4L2_PRIORITY_RECORD) {
+ return -EBUSY;
+ }
+
+ return cpia2_read(cam, buf, count, noblock);
+}
+
+
+/******************************************************************************
+ *
+ * cpia2_v4l_poll
+ *
+ *****************************************************************************/
+static unsigned int cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait)
+{
+ struct video_device *dev = video_devdata(filp);
+ struct camera_data *cam = video_get_drvdata(dev);
+
+ struct cpia2_fh *fh = filp->private_data;
+
+ if(!cam)
+ return POLLERR;
+
+ /* Priority check */
+ if(fh->prio != V4L2_PRIORITY_RECORD) {
+ return POLLERR;
+ }
+
+ return cpia2_poll(cam, filp, wait);
+}
+
+
+/******************************************************************************
+ *
+ * ioctl_cap_query
+ *
+ *****************************************************************************/
+static int ioctl_cap_query(void *arg, struct camera_data *cam)
+{
+ struct video_capability *vc;
+ int retval = 0;
+ vc = arg;
+
+ if (cam->params.pnp_id.product == 0x151)
+ strcpy(vc->name, "QX5 Microscope");
+ else
+ strcpy(vc->name, "CPiA2 Camera");
+
+ vc->type = VID_TYPE_CAPTURE | VID_TYPE_MJPEG_ENCODER;
+ vc->channels = 1;
+ vc->audios = 0;
+ vc->minwidth = 176; /* VIDEOSIZE_QCIF */
+ vc->minheight = 144;
+ switch (cam->params.version.sensor_flags) {
+ case CPIA2_VP_SENSOR_FLAGS_500:
+ vc->maxwidth = STV_IMAGE_VGA_COLS;
+ vc->maxheight = STV_IMAGE_VGA_ROWS;
+ break;
+ case CPIA2_VP_SENSOR_FLAGS_410:
+ vc->maxwidth = STV_IMAGE_CIF_COLS;
+ vc->maxheight = STV_IMAGE_CIF_ROWS;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return retval;
+}
+
+/******************************************************************************
+ *
+ * ioctl_get_channel
+ *
+ *****************************************************************************/
+static int ioctl_get_channel(void *arg)
+{
+ int retval = 0;
+ struct video_channel *v;
+ v = arg;
+
+ if (v->channel != 0)
+ return -EINVAL;
+
+ v->channel = 0;
+ strcpy(v->name, "Camera");
+ v->tuners = 0;
+ v->flags = 0;
+ v->type = VIDEO_TYPE_CAMERA;
+ v->norm = 0;
+
+ return retval;
+}
+
+/******************************************************************************
+ *
+ * ioctl_set_channel
+ *
+ *****************************************************************************/
+static int ioctl_set_channel(void *arg)
+{
+ struct video_channel *v;
+ int retval = 0;
+ v = arg;
+
+ if (retval == 0 && v->channel != 0)
+ retval = -EINVAL;
+
+ return retval;
+}
+
+/******************************************************************************
+ *
+ * ioctl_set_image_prop
+ *
+ *****************************************************************************/
+static int ioctl_set_image_prop(void *arg, struct camera_data *cam)
+{
+ struct video_picture *vp;
+ int retval = 0;
+ vp = arg;
+
+ /* brightness, color, contrast need no check 0-65535 */
+ memcpy(&cam->vp, vp, sizeof(*vp));
+
+ /* update cam->params.colorParams */
+ cam->params.color_params.brightness = vp->brightness / 256;
+ cam->params.color_params.saturation = vp->colour / 256;
+ cam->params.color_params.contrast = vp->contrast / 256;
+
+ DBG("Requested params: bright 0x%X, sat 0x%X, contrast 0x%X\n",
+ cam->params.color_params.brightness,
+ cam->params.color_params.saturation,
+ cam->params.color_params.contrast);
+
+ cpia2_set_color_params(cam);
+
+ return retval;
+}
+
+static int sync(struct camera_data *cam, int frame_nr)
+{
+ struct framebuf *frame = &cam->buffers[frame_nr];
+
+ while (1) {
+ if (frame->status == FRAME_READY)
+ return 0;
+
+ if (!cam->streaming) {
+ frame->status = FRAME_READY;
+ frame->length = 0;
+ return 0;
+ }
+
+ up(&cam->busy_lock);
+ wait_event_interruptible(cam->wq_stream,
+ !cam->streaming ||
+ frame->status == FRAME_READY);
+ down(&cam->busy_lock);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ if(!cam->present)
+ return -ENOTTY;
+ }
+}
+
+/******************************************************************************
+ *
+ * ioctl_set_window_size
+ *
+ *****************************************************************************/
+static int ioctl_set_window_size(void *arg, struct camera_data *cam,
+ struct cpia2_fh *fh)
+{
+ /* copy_from_user, check validity, copy to internal structure */
+ struct video_window *vw;
+ int frame, err;
+ vw = arg;
+
+ if (vw->clipcount != 0) /* clipping not supported */
+ return -EINVAL;
+
+ if (vw->clips != NULL) /* clipping not supported */
+ return -EINVAL;
+
+ /* Ensure that only this process can change the format. */
+ err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD);
+ if(err != 0)
+ return err;
+
+ cam->pixelformat = V4L2_PIX_FMT_JPEG;
+
+ /* Be sure to supply the Huffman tables, this isn't MJPEG */
+ cam->params.compression.inhibit_htables = 0;
+
+ /* we set the video window to something smaller or equal to what
+ * is requested by the user???
+ */
+ DBG("Requested width = %d, height = %d\n", vw->width, vw->height);
+ if (vw->width != cam->vw.width || vw->height != cam->vw.height) {
+ cam->vw.width = vw->width;
+ cam->vw.height = vw->height;
+ cam->params.roi.width = vw->width;
+ cam->params.roi.height = vw->height;
+ cpia2_set_format(cam);
+ }
+
+ for (frame = 0; frame < cam->num_frames; ++frame) {
+ if (cam->buffers[frame].status == FRAME_READING)
+ if ((err = sync(cam, frame)) < 0)
+ return err;
+
+ cam->buffers[frame].status = FRAME_EMPTY;
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_get_mbuf
+ *
+ *****************************************************************************/
+static int ioctl_get_mbuf(void *arg, struct camera_data *cam)
+{
+ struct video_mbuf *vm;
+ int i;
+ vm = arg;
+
+ memset(vm, 0, sizeof(*vm));
+ vm->size = cam->frame_size*cam->num_frames;
+ vm->frames = cam->num_frames;
+ for (i = 0; i < cam->num_frames; i++)
+ vm->offsets[i] = cam->frame_size * i;
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_mcapture
+ *
+ *****************************************************************************/
+static int ioctl_mcapture(void *arg, struct camera_data *cam,
+ struct cpia2_fh *fh)
+{
+ struct video_mmap *vm;
+ int video_size, err;
+ vm = arg;
+
+ if (vm->frame < 0 || vm->frame >= cam->num_frames)
+ return -EINVAL;
+
+ /* set video size */
+ video_size = cpia2_match_video_size(vm->width, vm->height);
+ if (cam->video_size < 0) {
+ return -EINVAL;
+ }
+
+ /* Ensure that only this process can change the format. */
+ err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD);
+ if(err != 0)
+ return err;
+
+ if (video_size != cam->video_size) {
+ cam->video_size = video_size;
+ cam->params.roi.width = vm->width;
+ cam->params.roi.height = vm->height;
+ cpia2_set_format(cam);
+ }
+
+ if (cam->buffers[vm->frame].status == FRAME_READING)
+ if ((err=sync(cam, vm->frame)) < 0)
+ return err;
+
+ cam->buffers[vm->frame].status = FRAME_EMPTY;
+
+ return cpia2_usb_stream_start(cam,cam->params.camera_state.stream_mode);
+}
+
+/******************************************************************************
+ *
+ * ioctl_sync
+ *
+ *****************************************************************************/
+static int ioctl_sync(void *arg, struct camera_data *cam)
+{
+ int frame;
+
+ frame = *(int*)arg;
+
+ if (frame < 0 || frame >= cam->num_frames)
+ return -EINVAL;
+
+ return sync(cam, frame);
+}
+
+
+/******************************************************************************
+ *
+ * ioctl_set_gpio
+ *
+ *****************************************************************************/
+
+static int ioctl_set_gpio(void *arg, struct camera_data *cam)
+{
+ __u32 gpio_val;
+
+ gpio_val = *(__u32*) arg;
+
+ if (gpio_val &~ 0xFFU)
+ return -EINVAL;
+
+ return cpia2_set_gpio(cam, (unsigned char)gpio_val);
+}
+
+/******************************************************************************
+ *
+ * ioctl_querycap
+ *
+ * V4L2 device capabilities
+ *
+ *****************************************************************************/
+
+static int ioctl_querycap(void *arg, struct camera_data *cam)
+{
+ struct v4l2_capability *vc = arg;
+
+ memset(vc, 0, sizeof(*vc));
+ strcpy(vc->driver, "cpia2");
+
+ if (cam->params.pnp_id.product == 0x151)
+ strcpy(vc->card, "QX5 Microscope");
+ else
+ strcpy(vc->card, "CPiA2 Camera");
+ switch (cam->params.pnp_id.device_type) {
+ case DEVICE_STV_672:
+ strcat(vc->card, " (672/");
+ break;
+ case DEVICE_STV_676:
+ strcat(vc->card, " (676/");
+ break;
+ default:
+ strcat(vc->card, " (???/");
+ break;
+ }
+ switch (cam->params.version.sensor_flags) {
+ case CPIA2_VP_SENSOR_FLAGS_404:
+ strcat(vc->card, "404)");
+ break;
+ case CPIA2_VP_SENSOR_FLAGS_407:
+ strcat(vc->card, "407)");
+ break;
+ case CPIA2_VP_SENSOR_FLAGS_409:
+ strcat(vc->card, "409)");
+ break;
+ case CPIA2_VP_SENSOR_FLAGS_410:
+ strcat(vc->card, "410)");
+ break;
+ case CPIA2_VP_SENSOR_FLAGS_500:
+ strcat(vc->card, "500)");
+ break;
+ default:
+ strcat(vc->card, "???)");
+ break;
+ }
+
+ if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0)
+ memset(vc->bus_info,0, sizeof(vc->bus_info));
+
+ vc->version = KERNEL_VERSION(CPIA2_MAJ_VER, CPIA2_MIN_VER,
+ CPIA2_PATCH_VER);
+
+ vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_input
+ *
+ * V4L2 input get/set/enumerate
+ *
+ *****************************************************************************/
+
+static int ioctl_input(unsigned int ioclt_nr,void *arg,struct camera_data *cam)
+{
+ struct v4l2_input *i = arg;
+
+ if(ioclt_nr != VIDIOC_G_INPUT) {
+ if (i->index != 0)
+ return -EINVAL;
+ }
+
+ memset(i, 0, sizeof(*i));
+ strcpy(i->name, "Camera");
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_enum_fmt
+ *
+ * V4L2 format enumerate
+ *
+ *****************************************************************************/
+
+static int ioctl_enum_fmt(void *arg,struct camera_data *cam)
+{
+ struct v4l2_fmtdesc *f = arg;
+ int index = f->index;
+
+ if (index < 0 || index > 1)
+ return -EINVAL;
+
+ memset(f, 0, sizeof(*f));
+ f->index = index;
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->flags = V4L2_FMT_FLAG_COMPRESSED;
+ switch(index) {
+ case 0:
+ strcpy(f->description, "MJPEG");
+ f->pixelformat = V4L2_PIX_FMT_MJPEG;
+ break;
+ case 1:
+ strcpy(f->description, "JPEG");
+ f->pixelformat = V4L2_PIX_FMT_JPEG;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_try_fmt
+ *
+ * V4L2 format try
+ *
+ *****************************************************************************/
+
+static int ioctl_try_fmt(void *arg,struct camera_data *cam)
+{
+ struct v4l2_format *f = arg;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG &&
+ f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
+ return -EINVAL;
+
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage = cam->frame_size;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
+ f->fmt.pix.priv = 0;
+
+ switch (cpia2_match_video_size(f->fmt.pix.width, f->fmt.pix.height)) {
+ case VIDEOSIZE_VGA:
+ f->fmt.pix.width = 640;
+ f->fmt.pix.height = 480;
+ break;
+ case VIDEOSIZE_CIF:
+ f->fmt.pix.width = 352;
+ f->fmt.pix.height = 288;
+ break;
+ case VIDEOSIZE_QVGA:
+ f->fmt.pix.width = 320;
+ f->fmt.pix.height = 240;
+ break;
+ case VIDEOSIZE_288_216:
+ f->fmt.pix.width = 288;
+ f->fmt.pix.height = 216;
+ break;
+ case VIDEOSIZE_256_192:
+ f->fmt.pix.width = 256;
+ f->fmt.pix.height = 192;
+ break;
+ case VIDEOSIZE_224_168:
+ f->fmt.pix.width = 224;
+ f->fmt.pix.height = 168;
+ break;
+ case VIDEOSIZE_192_144:
+ f->fmt.pix.width = 192;
+ f->fmt.pix.height = 144;
+ break;
+ case VIDEOSIZE_QCIF:
+ default:
+ f->fmt.pix.width = 176;
+ f->fmt.pix.height = 144;
+ break;
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_set_fmt
+ *
+ * V4L2 format set
+ *
+ *****************************************************************************/
+
+static int ioctl_set_fmt(void *arg,struct camera_data *cam, struct cpia2_fh *fh)
+{
+ struct v4l2_format *f = arg;
+ int err, frame;
+
+ err = ioctl_try_fmt(arg, cam);
+ if(err != 0)
+ return err;
+
+ /* Ensure that only this process can change the format. */
+ err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD);
+ if(err != 0) {
+ return err;
+ }
+
+ cam->pixelformat = f->fmt.pix.pixelformat;
+
+ /* NOTE: This should be set to 1 for MJPEG, but some apps don't handle
+ * the missing Huffman table properly. */
+ cam->params.compression.inhibit_htables = 0;
+ /*f->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG;*/
+
+ /* we set the video window to something smaller or equal to what
+ * is requested by the user???
+ */
+ DBG("Requested width = %d, height = %d\n",
+ f->fmt.pix.width, f->fmt.pix.height);
+ if (f->fmt.pix.width != cam->vw.width ||
+ f->fmt.pix.height != cam->vw.height) {
+ cam->vw.width = f->fmt.pix.width;
+ cam->vw.height = f->fmt.pix.height;
+ cam->params.roi.width = f->fmt.pix.width;
+ cam->params.roi.height = f->fmt.pix.height;
+ cpia2_set_format(cam);
+ }
+
+ for (frame = 0; frame < cam->num_frames; ++frame) {
+ if (cam->buffers[frame].status == FRAME_READING)
+ if ((err = sync(cam, frame)) < 0)
+ return err;
+
+ cam->buffers[frame].status = FRAME_EMPTY;
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_get_fmt
+ *
+ * V4L2 format get
+ *
+ *****************************************************************************/
+
+static int ioctl_get_fmt(void *arg,struct camera_data *cam)
+{
+ struct v4l2_format *f = arg;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ f->fmt.pix.width = cam->vw.width;
+ f->fmt.pix.height = cam->vw.height;
+ f->fmt.pix.pixelformat = cam->pixelformat;
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage = cam->frame_size;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
+ f->fmt.pix.priv = 0;
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_cropcap
+ *
+ * V4L2 query cropping capabilities
+ * NOTE: cropping is currently disabled
+ *
+ *****************************************************************************/
+
+static int ioctl_cropcap(void *arg,struct camera_data *cam)
+{
+ struct v4l2_cropcap *c = arg;
+
+ if (c->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ c->bounds.left = 0;
+ c->bounds.top = 0;
+ c->bounds.width = cam->vw.width;
+ c->bounds.height = cam->vw.height;
+ c->defrect.left = 0;
+ c->defrect.top = 0;
+ c->defrect.width = cam->vw.width;
+ c->defrect.height = cam->vw.height;
+ c->pixelaspect.numerator = 1;
+ c->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_queryctrl
+ *
+ * V4L2 query possible control variables
+ *
+ *****************************************************************************/
+
+static int ioctl_queryctrl(void *arg,struct camera_data *cam)
+{
+ struct v4l2_queryctrl *c = arg;
+ int i;
+
+ for(i=0; i<NUM_CONTROLS; ++i) {
+ if(c->id == controls[i].id) {
+ memcpy(c, controls+i, sizeof(*c));
+ break;
+ }
+ }
+
+ if(i == NUM_CONTROLS)
+ return -EINVAL;
+
+ /* Some devices have additional limitations */
+ switch(c->id) {
+ case V4L2_CID_BRIGHTNESS:
+ /***
+ * Don't let the register be set to zero - bug in VP4
+ * flash of full brightness
+ ***/
+ if (cam->params.pnp_id.device_type == DEVICE_STV_672)
+ c->minimum = 1;
+ break;
+ case V4L2_CID_VFLIP:
+ // VP5 Only
+ if(cam->params.pnp_id.device_type == DEVICE_STV_672)
+ c->flags |= V4L2_CTRL_FLAG_DISABLED;
+ break;
+ case CPIA2_CID_FRAMERATE:
+ if(cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+ cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){
+ // Maximum 15fps
+ int i;
+ for(i=0; i<c->maximum; ++i) {
+ if(framerate_controls[i].value ==
+ CPIA2_VP_FRAMERATE_15) {
+ c->maximum = i;
+ c->default_value = i;
+ }
+ }
+ }
+ break;
+ case CPIA2_CID_FLICKER_MODE:
+ // Flicker control only valid for 672.
+ if(cam->params.pnp_id.device_type != DEVICE_STV_672)
+ c->flags |= V4L2_CTRL_FLAG_DISABLED;
+ break;
+ case CPIA2_CID_LIGHTS:
+ // Light control only valid for the QX5 Microscope.
+ if(cam->params.pnp_id.product != 0x151)
+ c->flags |= V4L2_CTRL_FLAG_DISABLED;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_querymenu
+ *
+ * V4L2 query possible control variables
+ *
+ *****************************************************************************/
+
+static int ioctl_querymenu(void *arg,struct camera_data *cam)
+{
+ struct v4l2_querymenu *m = arg;
+
+ memset(m->name, 0, sizeof(m->name));
+ m->reserved = 0;
+
+ switch(m->id) {
+ case CPIA2_CID_FLICKER_MODE:
+ if(m->index < 0 || m->index >= NUM_FLICKER_CONTROLS)
+ return -EINVAL;
+
+ strcpy(m->name, flicker_controls[m->index].name);
+ break;
+ case CPIA2_CID_FRAMERATE:
+ {
+ int maximum = NUM_FRAMERATE_CONTROLS - 1;
+ if(cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+ cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){
+ // Maximum 15fps
+ int i;
+ for(i=0; i<maximum; ++i) {
+ if(framerate_controls[i].value ==
+ CPIA2_VP_FRAMERATE_15)
+ maximum = i;
+ }
+ }
+ if(m->index < 0 || m->index > maximum)
+ return -EINVAL;
+
+ strcpy(m->name, framerate_controls[m->index].name);
+ break;
+ }
+ case CPIA2_CID_LIGHTS:
+ if(m->index < 0 || m->index >= NUM_LIGHTS_CONTROLS)
+ return -EINVAL;
+
+ strcpy(m->name, lights_controls[m->index].name);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_g_ctrl
+ *
+ * V4L2 get the value of a control variable
+ *
+ *****************************************************************************/
+
+static int ioctl_g_ctrl(void *arg,struct camera_data *cam)
+{
+ struct v4l2_control *c = arg;
+
+ switch(c->id) {
+ case V4L2_CID_BRIGHTNESS:
+ cpia2_do_command(cam, CPIA2_CMD_GET_VP_BRIGHTNESS,
+ TRANSFER_READ, 0);
+ c->value = cam->params.color_params.brightness;
+ break;
+ case V4L2_CID_CONTRAST:
+ cpia2_do_command(cam, CPIA2_CMD_GET_CONTRAST,
+ TRANSFER_READ, 0);
+ c->value = cam->params.color_params.contrast;
+ break;
+ case V4L2_CID_SATURATION:
+ cpia2_do_command(cam, CPIA2_CMD_GET_VP_SATURATION,
+ TRANSFER_READ, 0);
+ c->value = cam->params.color_params.saturation;
+ break;
+ case V4L2_CID_HFLIP:
+ cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS,
+ TRANSFER_READ, 0);
+ c->value = (cam->params.vp_params.user_effects &
+ CPIA2_VP_USER_EFFECTS_MIRROR) != 0;
+ break;
+ case V4L2_CID_VFLIP:
+ cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS,
+ TRANSFER_READ, 0);
+ c->value = (cam->params.vp_params.user_effects &
+ CPIA2_VP_USER_EFFECTS_FLIP) != 0;
+ break;
+ case CPIA2_CID_TARGET_KB:
+ c->value = cam->params.vc_params.target_kb;
+ break;
+ case CPIA2_CID_GPIO:
+ cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA,
+ TRANSFER_READ, 0);
+ c->value = cam->params.vp_params.gpio_data;
+ break;
+ case CPIA2_CID_FLICKER_MODE:
+ {
+ int i, mode;
+ cpia2_do_command(cam, CPIA2_CMD_GET_FLICKER_MODES,
+ TRANSFER_READ, 0);
+ if(cam->params.flicker_control.cam_register &
+ CPIA2_VP_FLICKER_MODES_NEVER_FLICKER) {
+ mode = NEVER_FLICKER;
+ } else {
+ if(cam->params.flicker_control.cam_register &
+ CPIA2_VP_FLICKER_MODES_50HZ) {
+ mode = FLICKER_50;
+ } else {
+ mode = FLICKER_60;
+ }
+ }
+ for(i=0; i<NUM_FLICKER_CONTROLS; i++) {
+ if(flicker_controls[i].value == mode) {
+ c->value = i;
+ break;
+ }
+ }
+ if(i == NUM_FLICKER_CONTROLS)
+ return -EINVAL;
+ break;
+ }
+ case CPIA2_CID_FRAMERATE:
+ {
+ int maximum = NUM_FRAMERATE_CONTROLS - 1;
+ int i;
+ for(i=0; i<= maximum; i++) {
+ if(cam->params.vp_params.frame_rate ==
+ framerate_controls[i].value)
+ break;
+ }
+ if(i > maximum)
+ return -EINVAL;
+ c->value = i;
+ break;
+ }
+ case CPIA2_CID_USB_ALT:
+ c->value = cam->params.camera_state.stream_mode;
+ break;
+ case CPIA2_CID_LIGHTS:
+ {
+ int i;
+ cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA,
+ TRANSFER_READ, 0);
+ for(i=0; i<NUM_LIGHTS_CONTROLS; i++) {
+ if((cam->params.vp_params.gpio_data&GPIO_LIGHTS_MASK) ==
+ lights_controls[i].value) {
+ break;
+ }
+ }
+ if(i == NUM_LIGHTS_CONTROLS)
+ return -EINVAL;
+ c->value = i;
+ break;
+ }
+ case CPIA2_CID_RESET_CAMERA:
+ return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+
+ DBG("Get control id:%d, value:%d\n", c->id, c->value);
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_s_ctrl
+ *
+ * V4L2 set the value of a control variable
+ *
+ *****************************************************************************/
+
+static int ioctl_s_ctrl(void *arg,struct camera_data *cam)
+{
+ struct v4l2_control *c = arg;
+ int i;
+ int retval = 0;
+
+ DBG("Set control id:%d, value:%d\n", c->id, c->value);
+
+ /* Check that the value is in range */
+ for(i=0; i<NUM_CONTROLS; i++) {
+ if(c->id == controls[i].id) {
+ if(c->value < controls[i].minimum ||
+ c->value > controls[i].maximum) {
+ return -EINVAL;
+ }
+ break;
+ }
+ }
+ if(i == NUM_CONTROLS)
+ return -EINVAL;
+
+ switch(c->id) {
+ case V4L2_CID_BRIGHTNESS:
+ cpia2_set_brightness(cam, c->value);
+ break;
+ case V4L2_CID_CONTRAST:
+ cpia2_set_contrast(cam, c->value);
+ break;
+ case V4L2_CID_SATURATION:
+ cpia2_set_saturation(cam, c->value);
+ break;
+ case V4L2_CID_HFLIP:
+ cpia2_set_property_mirror(cam, c->value);
+ break;
+ case V4L2_CID_VFLIP:
+ cpia2_set_property_flip(cam, c->value);
+ break;
+ case CPIA2_CID_TARGET_KB:
+ retval = cpia2_set_target_kb(cam, c->value);
+ break;
+ case CPIA2_CID_GPIO:
+ retval = cpia2_set_gpio(cam, c->value);
+ break;
+ case CPIA2_CID_FLICKER_MODE:
+ retval = cpia2_set_flicker_mode(cam,
+ flicker_controls[c->value].value);
+ break;
+ case CPIA2_CID_FRAMERATE:
+ retval = cpia2_set_fps(cam, framerate_controls[c->value].value);
+ break;
+ case CPIA2_CID_USB_ALT:
+ retval = cpia2_usb_change_streaming_alternate(cam, c->value);
+ break;
+ case CPIA2_CID_LIGHTS:
+ retval = cpia2_set_gpio(cam, lights_controls[c->value].value);
+ break;
+ case CPIA2_CID_RESET_CAMERA:
+ cpia2_usb_stream_pause(cam);
+ cpia2_reset_camera(cam);
+ cpia2_usb_stream_resume(cam);
+ break;
+ default:
+ retval = -EINVAL;
+ }
+
+ return retval;
+}
+
+/******************************************************************************
+ *
+ * ioctl_g_jpegcomp
+ *
+ * V4L2 get the JPEG compression parameters
+ *
+ *****************************************************************************/
+
+static int ioctl_g_jpegcomp(void *arg,struct camera_data *cam)
+{
+ struct v4l2_jpegcompression *parms = arg;
+
+ memset(parms, 0, sizeof(*parms));
+
+ parms->quality = 80; // TODO: Can this be made meaningful?
+
+ parms->jpeg_markers = V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI;
+ if(!cam->params.compression.inhibit_htables) {
+ parms->jpeg_markers |= V4L2_JPEG_MARKER_DHT;
+ }
+
+ parms->APPn = cam->APPn;
+ parms->APP_len = cam->APP_len;
+ if(cam->APP_len > 0) {
+ memcpy(parms->APP_data, cam->APP_data, cam->APP_len);
+ parms->jpeg_markers |= V4L2_JPEG_MARKER_APP;
+ }
+
+ parms->COM_len = cam->COM_len;
+ if(cam->COM_len > 0) {
+ memcpy(parms->COM_data, cam->COM_data, cam->COM_len);
+ parms->jpeg_markers |= JPEG_MARKER_COM;
+ }
+
+ DBG("G_JPEGCOMP APP_len:%d COM_len:%d\n",
+ parms->APP_len, parms->COM_len);
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_s_jpegcomp
+ *
+ * V4L2 set the JPEG compression parameters
+ * NOTE: quality and some jpeg_markers are ignored.
+ *
+ *****************************************************************************/
+
+static int ioctl_s_jpegcomp(void *arg,struct camera_data *cam)
+{
+ struct v4l2_jpegcompression *parms = arg;
+
+ DBG("S_JPEGCOMP APP_len:%d COM_len:%d\n",
+ parms->APP_len, parms->COM_len);
+
+ cam->params.compression.inhibit_htables =
+ !(parms->jpeg_markers & V4L2_JPEG_MARKER_DHT);
+
+ if(parms->APP_len != 0) {
+ if(parms->APP_len > 0 &&
+ parms->APP_len <= sizeof(cam->APP_data) &&
+ parms->APPn >= 0 && parms->APPn <= 15) {
+ cam->APPn = parms->APPn;
+ cam->APP_len = parms->APP_len;
+ memcpy(cam->APP_data, parms->APP_data, parms->APP_len);
+ } else {
+ LOG("Bad APPn Params n=%d len=%d\n",
+ parms->APPn, parms->APP_len);
+ return -EINVAL;
+ }
+ } else {
+ cam->APP_len = 0;
+ }
+
+ if(parms->COM_len != 0) {
+ if(parms->COM_len > 0 &&
+ parms->COM_len <= sizeof(cam->COM_data)) {
+ cam->COM_len = parms->COM_len;
+ memcpy(cam->COM_data, parms->COM_data, parms->COM_len);
+ } else {
+ LOG("Bad COM_len=%d\n", parms->COM_len);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_reqbufs
+ *
+ * V4L2 Initiate memory mapping.
+ * NOTE: The user's request is ignored. For now the buffers are fixed.
+ *
+ *****************************************************************************/
+
+static int ioctl_reqbufs(void *arg,struct camera_data *cam)
+{
+ struct v4l2_requestbuffers *req = arg;
+
+ if(req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ req->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+
+ DBG("REQBUFS requested:%d returning:%d\n", req->count, cam->num_frames);
+ req->count = cam->num_frames;
+ memset(&req->reserved, 0, sizeof(req->reserved));
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_querybuf
+ *
+ * V4L2 Query memory buffer status.
+ *
+ *****************************************************************************/
+
+static int ioctl_querybuf(void *arg,struct camera_data *cam)
+{
+ struct v4l2_buffer *buf = arg;
+
+ if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ buf->index > cam->num_frames)
+ return -EINVAL;
+
+ buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
+ buf->length = cam->frame_size;
+
+ buf->memory = V4L2_MEMORY_MMAP;
+
+ if(cam->mmapped)
+ buf->flags = V4L2_BUF_FLAG_MAPPED;
+ else
+ buf->flags = 0;
+
+ switch (cam->buffers[buf->index].status) {
+ case FRAME_EMPTY:
+ case FRAME_ERROR:
+ case FRAME_READING:
+ buf->bytesused = 0;
+ buf->flags = V4L2_BUF_FLAG_QUEUED;
+ break;
+ case FRAME_READY:
+ buf->bytesused = cam->buffers[buf->index].length;
+ buf->timestamp = cam->buffers[buf->index].timestamp;
+ buf->sequence = cam->buffers[buf->index].seq;
+ buf->flags = V4L2_BUF_FLAG_DONE;
+ break;
+ }
+
+ DBG("QUERYBUF index:%d offset:%d flags:%d seq:%d bytesused:%d\n",
+ buf->index, buf->m.offset, buf->flags, buf->sequence,
+ buf->bytesused);
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * ioctl_qbuf
+ *
+ * V4L2 User is freeing buffer
+ *
+ *****************************************************************************/
+
+static int ioctl_qbuf(void *arg,struct camera_data *cam)
+{
+ struct v4l2_buffer *buf = arg;
+
+ if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ buf->memory != V4L2_MEMORY_MMAP ||
+ buf->index > cam->num_frames)
+ return -EINVAL;
+
+ DBG("QBUF #%d\n", buf->index);
+
+ if(cam->buffers[buf->index].status == FRAME_READY)
+ cam->buffers[buf->index].status = FRAME_EMPTY;
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * find_earliest_filled_buffer
+ *
+ * Helper for ioctl_dqbuf. Find the next ready buffer.
+ *
+ *****************************************************************************/
+
+static int find_earliest_filled_buffer(struct camera_data *cam)
+{
+ int i;
+ int found = -1;
+ for (i=0; i<cam->num_frames; i++) {
+ if(cam->buffers[i].status == FRAME_READY) {
+ if(found < 0) {
+ found = i;
+ } else {
+ /* find which buffer is earlier */
+ struct timeval *tv1, *tv2;
+ tv1 = &cam->buffers[i].timestamp;
+ tv2 = &cam->buffers[found].timestamp;
+ if(tv1->tv_sec < tv2->tv_sec ||
+ (tv1->tv_sec == tv2->tv_sec &&
+ tv1->tv_usec < tv2->tv_usec))
+ found = i;
+ }
+ }
+ }
+ return found;
+}
+
+/******************************************************************************
+ *
+ * ioctl_dqbuf
+ *
+ * V4L2 User is asking for a filled buffer.
+ *
+ *****************************************************************************/
+
+static int ioctl_dqbuf(void *arg,struct camera_data *cam, struct file *file)
+{
+ struct v4l2_buffer *buf = arg;
+ int frame;
+
+ if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ buf->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+
+ frame = find_earliest_filled_buffer(cam);
+
+ if(frame < 0 && file->f_flags&O_NONBLOCK)
+ return -EAGAIN;
+
+ if(frame < 0) {
+ /* Wait for a frame to become available */
+ struct framebuf *cb=cam->curbuff;
+ up(&cam->busy_lock);
+ wait_event_interruptible(cam->wq_stream,
+ !cam->present ||
+ (cb=cam->curbuff)->status == FRAME_READY);
+ down(&cam->busy_lock);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ if(!cam->present)
+ return -ENOTTY;
+ frame = cb->num;
+ }
+
+
+ buf->index = frame;
+ buf->bytesused = cam->buffers[buf->index].length;
+ buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE;
+ buf->field = V4L2_FIELD_NONE;
+ buf->timestamp = cam->buffers[buf->index].timestamp;
+ buf->sequence = cam->buffers[buf->index].seq;
+ buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
+ buf->length = cam->frame_size;
+ buf->input = 0;
+ buf->reserved = 0;
+ memset(&buf->timecode, 0, sizeof(buf->timecode));
+
+ DBG("DQBUF #%d status:%d seq:%d length:%d\n", buf->index,
+ cam->buffers[buf->index].status, buf->sequence, buf->bytesused);
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * cpia2_ioctl
+ *
+ *****************************************************************************/
+static int cpia2_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int ioctl_nr, void *arg)
+{
+ struct video_device *dev = video_devdata(file);
+ struct camera_data *cam = video_get_drvdata(dev);
+ int retval = 0;
+
+ if (!cam)
+ return -ENOTTY;
+
+ /* make this _really_ smp-safe */
+ if (down_interruptible(&cam->busy_lock))
+ return -ERESTARTSYS;
+
+ if (!cam->present) {
+ up(&cam->busy_lock);
+ return -ENODEV;
+ }
+
+ /* Priority check */
+ switch (ioctl_nr) {
+ case VIDIOCSWIN:
+ case VIDIOCMCAPTURE:
+ case VIDIOC_S_FMT:
+ {
+ struct cpia2_fh *fh = file->private_data;
+ retval = v4l2_prio_check(&cam->prio, &fh->prio);
+ if(retval) {
+ up(&cam->busy_lock);
+ return retval;
+ }
+ break;
+ }
+ case VIDIOCGMBUF:
+ case VIDIOCSYNC:
+ {
+ struct cpia2_fh *fh = file->private_data;
+ if(fh->prio != V4L2_PRIORITY_RECORD) {
+ up(&cam->busy_lock);
+ return -EBUSY;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ switch (ioctl_nr) {
+ case VIDIOCGCAP: /* query capabilities */
+ retval = ioctl_cap_query(arg, cam);
+ break;
+
+ case VIDIOCGCHAN: /* get video source - we are a camera, nothing else */
+ retval = ioctl_get_channel(arg);
+ break;
+ case VIDIOCSCHAN: /* set video source - we are a camera, nothing else */
+ retval = ioctl_set_channel(arg);
+ break;
+ case VIDIOCGPICT: /* image properties */
+ memcpy(arg, &cam->vp, sizeof(struct video_picture));
+ break;
+ case VIDIOCSPICT:
+ retval = ioctl_set_image_prop(arg, cam);
+ break;
+ case VIDIOCGWIN: /* get/set capture window */
+ memcpy(arg, &cam->vw, sizeof(struct video_window));
+ break;
+ case VIDIOCSWIN:
+ retval = ioctl_set_window_size(arg, cam, file->private_data);
+ break;
+ case VIDIOCGMBUF: /* mmap interface */
+ retval = ioctl_get_mbuf(arg, cam);
+ break;
+ case VIDIOCMCAPTURE:
+ retval = ioctl_mcapture(arg, cam, file->private_data);
+ break;
+ case VIDIOCSYNC:
+ retval = ioctl_sync(arg, cam);
+ break;
+ /* pointless to implement overlay with this camera */
+ case VIDIOCCAPTURE:
+ case VIDIOCGFBUF:
+ case VIDIOCSFBUF:
+ case VIDIOCKEY:
+ retval = -EINVAL;
+ break;
+
+ /* tuner interface - we have none */
+ case VIDIOCGTUNER:
+ case VIDIOCSTUNER:
+ case VIDIOCGFREQ:
+ case VIDIOCSFREQ:
+ retval = -EINVAL;
+ break;
+
+ /* audio interface - we have none */
+ case VIDIOCGAUDIO:
+ case VIDIOCSAUDIO:
+ retval = -EINVAL;
+ break;
+
+ /* CPIA2 extension to Video4Linux API */
+ case CPIA2_IOC_SET_GPIO:
+ retval = ioctl_set_gpio(arg, cam);
+ break;
+ case VIDIOC_QUERYCAP:
+ retval = ioctl_querycap(arg,cam);
+ break;
+
+ case VIDIOC_ENUMINPUT:
+ case VIDIOC_G_INPUT:
+ case VIDIOC_S_INPUT:
+ retval = ioctl_input(ioctl_nr, arg,cam);
+ break;
+
+ case VIDIOC_ENUM_FMT:
+ retval = ioctl_enum_fmt(arg,cam);
+ break;
+ case VIDIOC_TRY_FMT:
+ retval = ioctl_try_fmt(arg,cam);
+ break;
+ case VIDIOC_G_FMT:
+ retval = ioctl_get_fmt(arg,cam);
+ break;
+ case VIDIOC_S_FMT:
+ retval = ioctl_set_fmt(arg,cam,file->private_data);
+ break;
+
+ case VIDIOC_CROPCAP:
+ retval = ioctl_cropcap(arg,cam);
+ break;
+ case VIDIOC_G_CROP:
+ case VIDIOC_S_CROP:
+ // TODO: I think cropping can be implemented - SJB
+ retval = -EINVAL;
+ break;
+
+ case VIDIOC_QUERYCTRL:
+ retval = ioctl_queryctrl(arg,cam);
+ break;
+ case VIDIOC_QUERYMENU:
+ retval = ioctl_querymenu(arg,cam);
+ break;
+ case VIDIOC_G_CTRL:
+ retval = ioctl_g_ctrl(arg,cam);
+ break;
+ case VIDIOC_S_CTRL:
+ retval = ioctl_s_ctrl(arg,cam);
+ break;
+
+ case VIDIOC_G_JPEGCOMP:
+ retval = ioctl_g_jpegcomp(arg,cam);
+ break;
+ case VIDIOC_S_JPEGCOMP:
+ retval = ioctl_s_jpegcomp(arg,cam);
+ break;
+
+ case VIDIOC_G_PRIORITY:
+ {
+ struct cpia2_fh *fh = file->private_data;
+ *(enum v4l2_priority*)arg = fh->prio;
+ break;
+ }
+ case VIDIOC_S_PRIORITY:
+ {
+ struct cpia2_fh *fh = file->private_data;
+ enum v4l2_priority prio;
+ prio = *(enum v4l2_priority*)arg;
+ if(cam->streaming &&
+ prio != fh->prio &&
+ fh->prio == V4L2_PRIORITY_RECORD) {
+ /* Can't drop record priority while streaming */
+ retval = -EBUSY;
+ } else if(prio == V4L2_PRIORITY_RECORD &&
+ prio != fh->prio &&
+ v4l2_prio_max(&cam->prio) == V4L2_PRIORITY_RECORD) {
+ /* Only one program can record at a time */
+ retval = -EBUSY;
+ } else {
+ retval = v4l2_prio_change(&cam->prio, &fh->prio, prio);
+ }
+ break;
+ }
+
+ case VIDIOC_REQBUFS:
+ retval = ioctl_reqbufs(arg,cam);
+ break;
+ case VIDIOC_QUERYBUF:
+ retval = ioctl_querybuf(arg,cam);
+ break;
+ case VIDIOC_QBUF:
+ retval = ioctl_qbuf(arg,cam);
+ break;
+ case VIDIOC_DQBUF:
+ retval = ioctl_dqbuf(arg,cam,file);
+ break;
+ case VIDIOC_STREAMON:
+ {
+ int type;
+ DBG("VIDIOC_STREAMON, streaming=%d\n", cam->streaming);
+ type = *(int*)arg;
+ if(!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ retval = -EINVAL;
+
+ if(!cam->streaming) {
+ retval = cpia2_usb_stream_start(cam,
+ cam->params.camera_state.stream_mode);
+ } else {
+ retval = -EINVAL;
+ }
+
+ break;
+ }
+ case VIDIOC_STREAMOFF:
+ {
+ int type;
+ DBG("VIDIOC_STREAMOFF, streaming=%d\n", cam->streaming);
+ type = *(int*)arg;
+ if(!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ retval = -EINVAL;
+
+ if(cam->streaming) {
+ retval = cpia2_usb_stream_stop(cam);
+ } else {
+ retval = -EINVAL;
+ }
+
+ break;
+ }
+
+ case VIDIOC_ENUMOUTPUT:
+ case VIDIOC_G_OUTPUT:
+ case VIDIOC_S_OUTPUT:
+ case VIDIOC_G_MODULATOR:
+ case VIDIOC_S_MODULATOR:
+
+ case VIDIOC_ENUMAUDIO:
+ case VIDIOC_G_AUDIO:
+ case VIDIOC_S_AUDIO:
+
+ case VIDIOC_ENUMAUDOUT:
+ case VIDIOC_G_AUDOUT:
+ case VIDIOC_S_AUDOUT:
+
+ case VIDIOC_ENUMSTD:
+ case VIDIOC_QUERYSTD:
+ case VIDIOC_G_STD:
+ case VIDIOC_S_STD:
+
+ case VIDIOC_G_TUNER:
+ case VIDIOC_S_TUNER:
+ case VIDIOC_G_FREQUENCY:
+ case VIDIOC_S_FREQUENCY:
+
+ case VIDIOC_OVERLAY:
+ case VIDIOC_G_FBUF:
+ case VIDIOC_S_FBUF:
+
+ case VIDIOC_G_PARM:
+ case VIDIOC_S_PARM:
+ retval = -EINVAL;
+ break;
+ default:
+ retval = -ENOIOCTLCMD;
+ break;
+ }
+
+ up(&cam->busy_lock);
+ return retval;
+}
+
+static int cpia2_ioctl(struct inode *inode, struct file *file,
+ unsigned int ioctl_nr, unsigned long iarg)
+{
+ return video_usercopy(inode, file, ioctl_nr, iarg, cpia2_do_ioctl);
+}
+
+/******************************************************************************
+ *
+ * cpia2_mmap
+ *
+ *****************************************************************************/
+static int cpia2_mmap(struct file *file, struct vm_area_struct *area)
+{
+ int retval;
+ struct video_device *dev = video_devdata(file);
+ struct camera_data *cam = video_get_drvdata(dev);
+
+ /* Priority check */
+ struct cpia2_fh *fh = file->private_data;
+ if(fh->prio != V4L2_PRIORITY_RECORD) {
+ return -EBUSY;
+ }
+
+ retval = cpia2_remap_buffer(cam, area);
+
+ if(!retval)
+ fh->mmapped = 1;
+ return retval;
+}
+
+/******************************************************************************
+ *
+ * reset_camera_struct_v4l
+ *
+ * Sets all values to the defaults
+ *****************************************************************************/
+static void reset_camera_struct_v4l(struct camera_data *cam)
+{
+ /***
+ * Fill in the v4l structures. video_cap is filled in inside the VIDIOCCAP
+ * Ioctl. Here, just do the window and picture stucts.
+ ***/
+ cam->vp.palette = (u16) VIDEO_PALETTE_RGB24; /* Is this right? */
+ cam->vp.brightness = (u16) cam->params.color_params.brightness * 256;
+ cam->vp.colour = (u16) cam->params.color_params.saturation * 256;
+ cam->vp.contrast = (u16) cam->params.color_params.contrast * 256;
+
+ cam->vw.x = 0;
+ cam->vw.y = 0;
+ cam->vw.width = cam->params.roi.width;
+ cam->vw.height = cam->params.roi.height;
+ cam->vw.flags = 0;
+ cam->vw.clipcount = 0;
+
+ cam->frame_size = buffer_size;
+ cam->num_frames = num_buffers;
+
+ /* FlickerModes */
+ cam->params.flicker_control.flicker_mode_req = flicker_mode;
+ cam->params.flicker_control.mains_frequency = flicker_freq;
+
+ /* streamMode */
+ cam->params.camera_state.stream_mode = alternate;
+
+ cam->pixelformat = V4L2_PIX_FMT_JPEG;
+ v4l2_prio_init(&cam->prio);
+ return;
+}
+
+/***
+ * The v4l video device structure initialized for this device
+ ***/
+static struct file_operations fops_template = {
+ .owner= THIS_MODULE,
+ .open= cpia2_open,
+ .release= cpia2_close,
+ .read= cpia2_v4l_read,
+ .poll= cpia2_v4l_poll,
+ .ioctl= cpia2_ioctl,
+ .llseek= no_llseek,
+ .mmap= cpia2_mmap,
+};
+
+static struct video_device cpia2_template = {
+ /* I could not find any place for the old .initialize initializer?? */
+ .owner= THIS_MODULE,
+ .name= "CPiA2 Camera",
+ .type= VID_TYPE_CAPTURE,
+ .type2 = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING,
+ .hardware= VID_HARDWARE_CPIA2,
+ .minor= -1,
+ .fops= &fops_template,
+ .release= video_device_release,
+};
+
+/******************************************************************************
+ *
+ * cpia2_register_camera
+ *
+ *****************************************************************************/
+int cpia2_register_camera(struct camera_data *cam)
+{
+ cam->vdev = video_device_alloc();
+ if(!cam->vdev)
+ return -ENOMEM;
+
+ memcpy(cam->vdev, &cpia2_template, sizeof(cpia2_template));
+ video_set_drvdata(cam->vdev, cam);
+
+ reset_camera_struct_v4l(cam);
+
+ /* register v4l device */
+ if (video_register_device
+ (cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+ ERR("video_register_device failed\n");
+ video_device_release(cam->vdev);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * cpia2_unregister_camera
+ *
+ *****************************************************************************/
+void cpia2_unregister_camera(struct camera_data *cam)
+{
+ if (!cam->open_count) {
+ video_unregister_device(cam->vdev);
+ } else {
+ LOG("/dev/video%d removed while open, "
+ "deferring video_unregister_device\n",
+ cam->vdev->minor);
+ }
+}
+
+/******************************************************************************
+ *
+ * check_parameters
+ *
+ * Make sure that all user-supplied parameters are sensible
+ *****************************************************************************/
+static void __init check_parameters(void)
+{
+ if(buffer_size < PAGE_SIZE) {
+ buffer_size = PAGE_SIZE;
+ LOG("buffer_size too small, setting to %d\n", buffer_size);
+ } else if(buffer_size > 1024*1024) {
+ /* arbitrary upper limiit */
+ buffer_size = 1024*1024;
+ LOG("buffer_size ridiculously large, setting to %d\n",
+ buffer_size);
+ } else {
+ buffer_size += PAGE_SIZE-1;
+ buffer_size &= ~(PAGE_SIZE-1);
+ }
+
+ if(num_buffers < 1) {
+ num_buffers = 1;
+ LOG("num_buffers too small, setting to %d\n", num_buffers);
+ } else if(num_buffers > VIDEO_MAX_FRAME) {
+ num_buffers = VIDEO_MAX_FRAME;
+ LOG("num_buffers too large, setting to %d\n", num_buffers);
+ }
+
+ if(alternate < USBIF_ISO_1 || alternate > USBIF_ISO_6) {
+ alternate = DEFAULT_ALT;
+ LOG("alternate specified is invalid, using %d\n", alternate);
+ }
+
+ if (flicker_mode != NEVER_FLICKER && flicker_mode != ANTI_FLICKER_ON) {
+ flicker_mode = NEVER_FLICKER;
+ LOG("Flicker mode specified is invalid, using %d\n",
+ flicker_mode);
+ }
+
+ if (flicker_freq != FLICKER_50 && flicker_freq != FLICKER_60) {
+ flicker_freq = FLICKER_60;
+ LOG("Flicker mode specified is invalid, using %d\n",
+ flicker_freq);
+ }
+
+ if(video_nr < -1 || video_nr > 64) {
+ video_nr = -1;
+ LOG("invalid video_nr specified, must be -1 to 64\n");
+ }
+
+ DBG("Using %d buffers, each %d bytes, alternate=%d\n",
+ num_buffers, buffer_size, alternate);
+}
+
+/************ Module Stuff ***************/
+
+
+/******************************************************************************
+ *
+ * cpia2_init/module_init
+ *
+ *****************************************************************************/
+static int __init cpia2_init(void)
+{
+ LOG("%s v%d.%d.%d\n",
+ ABOUT, CPIA2_MAJ_VER, CPIA2_MIN_VER, CPIA2_PATCH_VER);
+ check_parameters();
+ cpia2_usb_init();
+ return 0;
+}
+
+
+/******************************************************************************
+ *
+ * cpia2_exit/module_exit
+ *
+ *****************************************************************************/
+static void __exit cpia2_exit(void)
+{
+ cpia2_usb_cleanup();
+ schedule_timeout(2 * HZ);
+}
+
+module_init(cpia2_init);
+module_exit(cpia2_exit);
+
diff --git a/drivers/media/video/cpia2/cpia2dev.h b/drivers/media/video/cpia2/cpia2dev.h
new file mode 100644
index 00000000000..d58097ce0d5
--- /dev/null
+++ b/drivers/media/video/cpia2/cpia2dev.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+ *
+ * Filename: cpia2dev.h
+ *
+ * Copyright 2001, STMicrolectronics, Inc.
+ *
+ * Contact: steve.miller@st.com
+ *
+ * Description:
+ * This file provides definitions for applications wanting to use the
+ * cpia2 driver beyond the generic v4l capabilities.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ****************************************************************************/
+
+#ifndef CPIA2_DEV_HEADER
+#define CPIA2_DEV_HEADER
+
+#include <linux/videodev.h>
+
+/***
+ * The following defines are ioctl numbers based on video4linux private ioctls,
+ * which can range from 192 (BASE_VIDIOCPRIVATE) to 255. All of these take int
+ * args
+ */
+#define CPIA2_IOC_SET_GPIO _IOW('v', BASE_VIDIOCPRIVATE + 17, __u32)
+
+/* V4L2 driver specific controls */
+#define CPIA2_CID_TARGET_KB (V4L2_CID_PRIVATE_BASE+0)
+#define CPIA2_CID_GPIO (V4L2_CID_PRIVATE_BASE+1)
+#define CPIA2_CID_FLICKER_MODE (V4L2_CID_PRIVATE_BASE+2)
+#define CPIA2_CID_FRAMERATE (V4L2_CID_PRIVATE_BASE+3)
+#define CPIA2_CID_USB_ALT (V4L2_CID_PRIVATE_BASE+4)
+#define CPIA2_CID_LIGHTS (V4L2_CID_PRIVATE_BASE+5)
+#define CPIA2_CID_RESET_CAMERA (V4L2_CID_PRIVATE_BASE+6)
+
+#endif
diff --git a/drivers/media/video/cpia2/cpia2patch.h b/drivers/media/video/cpia2/cpia2patch.h
new file mode 100644
index 00000000000..7f085fbe76f
--- /dev/null
+++ b/drivers/media/video/cpia2/cpia2patch.h
@@ -0,0 +1,233 @@
+/****************************************************************************
+ *
+ * Filename: cpia2patch.h
+ *
+ * Copyright 2001, STMicrolectronics, Inc.
+ *
+ * Contact: steve.miller@st.com
+ *
+ * Description:
+ * This file contains patch data for the CPiA2 (stv0672) VP4.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ****************************************************************************/
+
+#ifndef CPIA2_PATCH_HEADER
+#define CPIA2_PATCH_HEADER
+
+typedef struct {
+ unsigned char reg;
+ unsigned char count;
+ const unsigned char *data;
+} cpia2_patch;
+
+static const unsigned char start_address_hi[1] = {
+ 0x01
+};
+
+static const unsigned char start_address_lo[1] = {
+ 0xBC
+};
+
+static const unsigned char patch_block0[64] = {
+ 0xE3, 0x02, 0xE3, 0x03, 0xE3, 0x04, 0xE3, 0x05,
+ 0xE3, 0x06, 0xE3, 0x07, 0x93, 0x44, 0x56, 0xD4,
+ 0x93, 0x4E, 0x56, 0x51, 0x93, 0x4E, 0x51, 0xD6,
+ 0x93, 0x4E, 0x4F, 0x54, 0x93, 0x4E, 0x92, 0x4F,
+ 0x92, 0xA4, 0x93, 0x05, 0x92, 0xF4, 0x93, 0x1B,
+ 0x92, 0x92, 0x91, 0xE6, 0x92, 0x36, 0x92, 0x74,
+ 0x92, 0x4A, 0x92, 0x8C, 0x92, 0x8E, 0xC8, 0xD0,
+ 0x0B, 0x42, 0x02, 0xA0, 0xCA, 0x92, 0x09, 0x02
+};
+
+static const unsigned char patch_block1[64] = {
+ 0xC9, 0x10, 0x0A, 0x0A, 0x0A, 0x81, 0xE3, 0xB8,
+ 0xE3, 0xB0, 0xE3, 0xA8, 0xE3, 0xA0, 0xE3, 0x98,
+ 0xE3, 0x90, 0xE1, 0x00, 0xCF, 0xD7, 0x0A, 0x12,
+ 0xCC, 0x95, 0x08, 0xB2, 0x0A, 0x18, 0xE1, 0x00,
+ 0x01, 0xEE, 0x0C, 0x08, 0x4A, 0x12, 0xC8, 0x18,
+ 0xF0, 0x9A, 0xC0, 0x22, 0xF3, 0x1C, 0x4A, 0x13,
+ 0xF3, 0x14, 0xC8, 0xA0, 0xF2, 0x14, 0xF2, 0x1C,
+ 0xEB, 0x13, 0xD3, 0xA2, 0x63, 0x16, 0x48, 0x9E
+};
+
+static const unsigned char patch_block2[64] = {
+ 0xF0, 0x18, 0xA4, 0x03, 0xF3, 0x93, 0xC0, 0x58,
+ 0xF7, 0x13, 0x51, 0x9C, 0xE9, 0x20, 0xCF, 0xEF,
+ 0x63, 0xF9, 0x92, 0x2E, 0xD3, 0x5F, 0x63, 0xFA,
+ 0x92, 0x2E, 0xD3, 0x67, 0x63, 0xFB, 0x92, 0x2E,
+ 0xD3, 0x6F, 0xE9, 0x1A, 0x63, 0x16, 0x48, 0xA7,
+ 0xF0, 0x20, 0xA4, 0x06, 0xF3, 0x94, 0xC0, 0x27,
+ 0xF7, 0x14, 0xF5, 0x13, 0x51, 0x9D, 0xF6, 0x13,
+ 0x63, 0x18, 0xC4, 0x20, 0xCB, 0xEF, 0x63, 0xFC
+};
+
+static const unsigned char patch_block3[64] = {
+ 0x92, 0x2E, 0xD3, 0x77, 0x63, 0xFD, 0x92, 0x2E,
+ 0xD3, 0x7F, 0x63, 0xFE, 0x92, 0x2E, 0xD3, 0x87,
+ 0x63, 0xFF, 0x92, 0x2E, 0xD3, 0x8F, 0x64, 0x38,
+ 0x92, 0x2E, 0xD3, 0x97, 0x64, 0x39, 0x92, 0x2E,
+ 0xD3, 0x9F, 0xE1, 0x00, 0xF5, 0x3A, 0xF4, 0x3B,
+ 0xF7, 0xBF, 0xF2, 0xBC, 0xF2, 0x3D, 0xE1, 0x00,
+ 0x80, 0x87, 0x90, 0x80, 0x51, 0xD5, 0x02, 0x22,
+ 0x02, 0x32, 0x4B, 0xD3, 0xF7, 0x11, 0x0B, 0xDA
+};
+
+static const unsigned char patch_block4[64] = {
+ 0xE1, 0x00, 0x0E, 0x02, 0x02, 0x40, 0x0D, 0xB5,
+ 0xE3, 0x02, 0x48, 0x55, 0xE5, 0x12, 0xA4, 0x01,
+ 0xE8, 0x1B, 0xE3, 0x90, 0xF0, 0x18, 0xA4, 0x01,
+ 0xE8, 0xBF, 0x8D, 0xB8, 0x4B, 0xD1, 0x4B, 0xD8,
+ 0x0B, 0xCB, 0x0B, 0xC2, 0xE1, 0x00, 0xE3, 0x02,
+ 0xE3, 0x03, 0x52, 0xD3, 0x60, 0x59, 0xE6, 0x93,
+ 0x0D, 0x22, 0x52, 0xD4, 0xE6, 0x93, 0x0D, 0x2A,
+ 0xE3, 0x98, 0xE3, 0x90, 0xE1, 0x00, 0x02, 0x5D
+};
+
+static const unsigned char patch_block5[64] = {
+ 0x02, 0x63, 0xE3, 0x02, 0xC8, 0x12, 0x02, 0xCA,
+ 0xC8, 0x52, 0x02, 0xC2, 0x82, 0x68, 0xE3, 0x02,
+ 0xC8, 0x14, 0x02, 0xCA, 0xC8, 0x90, 0x02, 0xC2,
+ 0x0A, 0xD0, 0xC9, 0x93, 0x0A, 0xDA, 0xCC, 0xD2,
+ 0x0A, 0xE2, 0x63, 0x12, 0x02, 0xDA, 0x0A, 0x98,
+ 0x0A, 0xA0, 0x0A, 0xA8, 0xE3, 0x90, 0xE1, 0x00,
+ 0xE3, 0x02, 0x0A, 0xD0, 0xC9, 0x93, 0x0A, 0xDA,
+ 0xCC, 0xD2, 0x0A, 0xE2, 0x63, 0x12, 0x02, 0xDA
+};
+
+static const unsigned char patch_block6[64] = {
+ 0x0A, 0x98, 0x0A, 0xA0, 0x0A, 0xA8, 0x49, 0x91,
+ 0xE5, 0x6A, 0xA4, 0x04, 0xC8, 0x12, 0x02, 0xCA,
+ 0xC8, 0x52, 0x82, 0x89, 0xC8, 0x14, 0x02, 0xCA,
+ 0xC8, 0x90, 0x02, 0xC2, 0xE3, 0x90, 0xE1, 0x00,
+ 0x08, 0x60, 0xE1, 0x00, 0x48, 0x53, 0xE8, 0x97,
+ 0x08, 0x5A, 0xE1, 0x00, 0xE3, 0x02, 0xE3, 0x03,
+ 0x54, 0xD3, 0x60, 0x59, 0xE6, 0x93, 0x0D, 0x52,
+ 0xE3, 0x98, 0xE3, 0x90, 0xE1, 0x00, 0x02, 0x9C
+};
+
+static const unsigned char patch_block7[64] = {
+ 0xE3, 0x02, 0x55, 0x13, 0x93, 0x17, 0x55, 0x13,
+ 0x93, 0x17, 0xE3, 0x90, 0xE1, 0x00, 0x75, 0x30,
+ 0xE3, 0x02, 0xE3, 0x03, 0x55, 0x55, 0x60, 0x59,
+ 0xE6, 0x93, 0x0D, 0xB2, 0xE3, 0x98, 0xE3, 0x90,
+ 0xE1, 0x00, 0x02, 0xAE, 0xE7, 0x92, 0xE9, 0x18,
+ 0xEA, 0x9A, 0xE8, 0x98, 0xE8, 0x10, 0xE8, 0x11,
+ 0xE8, 0x51, 0xD2, 0xDA, 0xD2, 0xF3, 0xE8, 0x13,
+ 0xD2, 0xFA, 0xE8, 0x50, 0xD2, 0xEA, 0xE8, 0xD0
+};
+
+static const unsigned char patch_block8[64] = {
+ 0xE8, 0xD1, 0xD3, 0x0A, 0x03, 0x09, 0x48, 0x23,
+ 0xE5, 0x2C, 0xA0, 0x03, 0x48, 0x24, 0xEA, 0x1C,
+ 0x03, 0x08, 0xD2, 0xE3, 0xD3, 0x03, 0xD3, 0x13,
+ 0xE1, 0x00, 0x02, 0xCB, 0x05, 0x93, 0x57, 0x93,
+ 0xF0, 0x9A, 0xAC, 0x0B, 0xE3, 0x07, 0x92, 0xEA,
+ 0xE2, 0x9F, 0xE5, 0x06, 0xE3, 0xB0, 0xA0, 0x02,
+ 0xEB, 0x1E, 0x82, 0xD7, 0xEA, 0x1E, 0xE2, 0x3B,
+ 0x85, 0x9B, 0xE9, 0x1E, 0xC8, 0x90, 0x85, 0x94
+};
+
+static const unsigned char patch_block9[64] = {
+ 0x02, 0xDE, 0x05, 0x80, 0x57, 0x93, 0xF0, 0xBA,
+ 0xAC, 0x06, 0x92, 0xEA, 0xE2, 0xBF, 0xE5, 0x06,
+ 0xA0, 0x01, 0xEB, 0xBF, 0x85, 0x88, 0xE9, 0x3E,
+ 0xC8, 0x90, 0x85, 0x81, 0xE9, 0x3E, 0xF0, 0xBA,
+ 0xF3, 0x39, 0xF0, 0x3A, 0x60, 0x17, 0xF0, 0x3A,
+ 0xC0, 0x90, 0xF0, 0xBA, 0xE1, 0x00, 0x00, 0x3F,
+ 0xE3, 0x02, 0xE3, 0x03, 0x58, 0x10, 0x60, 0x59,
+ 0xE6, 0x93, 0x0D, 0xA2, 0x58, 0x12, 0xE6, 0x93
+};
+
+static const unsigned char patch_block10[64] = {
+ 0x0D, 0xAA, 0xE3, 0x98, 0xE3, 0x90, 0xE1, 0x00,
+ 0x03, 0x01, 0xE1, 0x00, 0x03, 0x03, 0x9B, 0x7D,
+ 0x8B, 0x8B, 0xE3, 0x02, 0xE3, 0x03, 0x58, 0x56,
+ 0x60, 0x59, 0xE6, 0x93, 0x0D, 0xBA, 0xE3, 0x98,
+ 0xE3, 0x90, 0xE1, 0x00, 0x03, 0x0F, 0x93, 0x11,
+ 0xE1, 0x00, 0xE3, 0x02, 0x4A, 0x11, 0x0B, 0x42,
+ 0x91, 0xAF, 0xE3, 0x90, 0xE1, 0x00, 0xF2, 0x91,
+ 0xF0, 0x91, 0xA3, 0xFE, 0xE1, 0x00, 0x60, 0x92
+};
+
+static const unsigned char patch_block11[64] = {
+ 0xC0, 0x5F, 0xF0, 0x13, 0xF0, 0x13, 0x59, 0x5B,
+ 0xE2, 0x13, 0xF0, 0x11, 0x5A, 0x19, 0xE2, 0x13,
+ 0xE1, 0x00, 0x00, 0x00, 0x03, 0x27, 0x68, 0x61,
+ 0x76, 0x61, 0x6E, 0x61, 0x00, 0x06, 0x03, 0x2C,
+ 0xE3, 0x02, 0xE3, 0x03, 0xE9, 0x38, 0x59, 0x15,
+ 0x59, 0x5A, 0xF2, 0x9A, 0xBC, 0x0B, 0xA4, 0x0A,
+ 0x59, 0x1E, 0xF3, 0x11, 0xF0, 0x1A, 0xE2, 0xBB,
+ 0x59, 0x15, 0xF0, 0x11, 0x19, 0x2A, 0xE5, 0x02
+};
+
+static const unsigned char patch_block12[54] = {
+ 0xA4, 0x01, 0xEB, 0xBF, 0xE3, 0x98, 0xE3, 0x90,
+ 0xE1, 0x00, 0x03, 0x42, 0x19, 0x28, 0xE1, 0x00,
+ 0xE9, 0x30, 0x60, 0x79, 0xE1, 0x00, 0xE3, 0x03,
+ 0xE3, 0x07, 0x60, 0x79, 0x93, 0x4E, 0xE3, 0xB8,
+ 0xE3, 0x98, 0xE1, 0x00, 0xE9, 0x1A, 0xF0, 0x1F,
+ 0xE2, 0x33, 0xF0, 0x91, 0xE2, 0x92, 0xE0, 0x32,
+ 0xF0, 0x31, 0xE1, 0x00, 0x00, 0x00
+};
+
+static const unsigned char do_call[1] = {
+ 0x01
+};
+
+
+#define PATCH_DATA_SIZE 18
+
+static const cpia2_patch patch_data[PATCH_DATA_SIZE] = {
+ {0x0A, sizeof(start_address_hi), start_address_hi}
+ , // 0
+ {0x0B, sizeof(start_address_lo), start_address_lo}
+ , // 1
+ {0x0C, sizeof(patch_block0), patch_block0}
+ , // 2
+ {0x0C, sizeof(patch_block1), patch_block1}
+ , // 3
+ {0x0C, sizeof(patch_block2), patch_block2}
+ , // 4
+ {0x0C, sizeof(patch_block3), patch_block3}
+ , // 5
+ {0x0C, sizeof(patch_block4), patch_block4}
+ , // 6
+ {0x0C, sizeof(patch_block5), patch_block5}
+ , // 7
+ {0x0C, sizeof(patch_block6), patch_block6}
+ , // 8
+ {0x0C, sizeof(patch_block7), patch_block7}
+ , // 9
+ {0x0C, sizeof(patch_block8), patch_block8}
+ , // 10
+ {0x0C, sizeof(patch_block9), patch_block9}
+ , //11
+ {0x0C, sizeof(patch_block10), patch_block10}
+ , // 12
+ {0x0C, sizeof(patch_block11), patch_block11}
+ , // 13
+ {0x0C, sizeof(patch_block12), patch_block12}
+ , // 14
+ {0x0A, sizeof(start_address_hi), start_address_hi}
+ , // 15
+ {0x0B, sizeof(start_address_lo), start_address_lo}
+ , // 16
+ {0x0D, sizeof(do_call), do_call} //17
+};
+
+
+#endif
diff --git a/drivers/media/video/cx25840/Kconfig b/drivers/media/video/cx25840/Kconfig
new file mode 100644
index 00000000000..854264e42ec
--- /dev/null
+++ b/drivers/media/video/cx25840/Kconfig
@@ -0,0 +1,9 @@
+config VIDEO_CX25840
+ tristate "Conexant CX2584x audio/video decoders"
+ depends on VIDEO_DEV && I2C && EXPERIMENTAL
+ select FW_LOADER
+ ---help---
+ Support for the Conexant CX2584x audio/video decoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx25840
diff --git a/drivers/media/video/cx25840/Makefile b/drivers/media/video/cx25840/Makefile
index 543ebacdc9d..32a896c23d1 100644
--- a/drivers/media/video/cx25840/Makefile
+++ b/drivers/media/video/cx25840/Makefile
@@ -1,6 +1,6 @@
cx25840-objs := cx25840-core.o cx25840-audio.o cx25840-firmware.o \
cx25840-vbi.o
-obj-$(CONFIG_VIDEO_DECODER) += cx25840.o
+obj-$(CONFIG_VIDEO_CX25840) += cx25840.o
EXTRA_CFLAGS += -I$(src)/..
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 5588b9a5c43..8a257978056 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -743,6 +743,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
memset(input, 0, sizeof(*input));
input->index = state->aud_input;
+ input->capability = V4L2_AUDCAP_STEREO;
break;
}
@@ -753,7 +754,6 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
case VIDIOC_G_TUNER:
{
u8 mode = cx25840_read(client, 0x804);
- u8 pref = cx25840_read(client, 0x809) & 0xf;
u8 vpres = cx25840_read(client, 0x80a) & 0x10;
int val = 0;
@@ -773,44 +773,49 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
val |= V4L2_TUNER_SUB_MONO;
if (mode == 2 || mode == 4)
- val |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+ val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
if (mode & 0x10)
val |= V4L2_TUNER_SUB_SAP;
vt->rxsubchans = val;
-
- switch (pref) {
- case 0:
- vt->audmode = V4L2_TUNER_MODE_MONO;
- break;
- case 1:
- case 2:
- vt->audmode = V4L2_TUNER_MODE_LANG2;
- break;
- case 4:
- default:
- vt->audmode = V4L2_TUNER_MODE_STEREO;
- }
+ vt->audmode = state->audmode;
break;
}
case VIDIOC_S_TUNER:
+ if (state->radio)
+ break;
+
switch (vt->audmode) {
case V4L2_TUNER_MODE_MONO:
- case V4L2_TUNER_MODE_LANG1:
- /* Force PREF_MODE to MONO */
+ /* mono -> mono
+ stereo -> mono
+ bilingual -> lang1 */
cx25840_and_or(client, 0x809, ~0xf, 0x00);
break;
- case V4L2_TUNER_MODE_STEREO:
- /* Force PREF_MODE to STEREO */
+ case V4L2_TUNER_MODE_LANG1:
+ /* mono -> mono
+ stereo -> stereo
+ bilingual -> lang1 */
cx25840_and_or(client, 0x809, ~0xf, 0x04);
break;
+ case V4L2_TUNER_MODE_STEREO:
+ /* mono -> mono
+ stereo -> stereo
+ bilingual -> lang1/lang2 */
+ cx25840_and_or(client, 0x809, ~0xf, 0x07);
+ break;
case V4L2_TUNER_MODE_LANG2:
- /* Force PREF_MODE to LANG2 */
+ /* mono -> mono
+ stereo ->stereo
+ bilingual -> lang2 */
cx25840_and_or(client, 0x809, ~0xf, 0x01);
break;
+ default:
+ return -EINVAL;
}
+ state->audmode = vt->audmode;
break;
case VIDIOC_G_FMT:
@@ -891,6 +896,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
state->aud_input = CX25840_AUDIO8;
state->audclk_freq = 48000;
state->pvr150_workaround = 0;
+ state->audmode = V4L2_TUNER_MODE_LANG1;
cx25840_initialize(client, 1);
diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c
index 04d879da7d6..e96fd1f1d6d 100644
--- a/drivers/media/video/cx25840/cx25840-vbi.c
+++ b/drivers/media/video/cx25840/cx25840-vbi.c
@@ -151,7 +151,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
case VIDIOC_G_FMT:
{
static u16 lcr2vbi[] = {
- 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
+ 0, V4L2_SLICED_TELETEXT_PAL_B, 0, /* 1 */
0, V4L2_SLICED_WSS_625, 0, /* 4 */
V4L2_SLICED_CAPTION_525, /* 6 */
0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */
@@ -231,7 +231,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
for (i = 7; i <= 23; i++) {
for (x = 0; x <= 1; x++) {
switch (svbi->service_lines[1-x][i]) {
- case V4L2_SLICED_TELETEXT_B:
+ case V4L2_SLICED_TELETEXT_PAL_B:
lcr[i] |= 1 << (4 * x);
break;
case V4L2_SLICED_WSS_625:
@@ -282,7 +282,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
switch (id2) {
case 1:
- id2 = V4L2_SLICED_TELETEXT_B;
+ id2 = V4L2_SLICED_TELETEXT_PAL_B;
break;
case 4:
id2 = V4L2_SLICED_WSS_625;
diff --git a/drivers/media/video/cx25840/cx25840.h b/drivers/media/video/cx25840/cx25840.h
index fd22f30dcc1..dd70664d1dd 100644
--- a/drivers/media/video/cx25840/cx25840.h
+++ b/drivers/media/video/cx25840/cx25840.h
@@ -78,6 +78,7 @@ struct cx25840_state {
enum cx25840_video_input vid_input;
enum cx25840_audio_input aud_input;
u32 audclk_freq;
+ int audmode;
};
/* ----------------------------------------------------------------------- */
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 87d79df0533..e140996e6ee 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -50,6 +50,7 @@ config VIDEO_CX88_DVB_ALL_FRONTENDS
depends on VIDEO_CX88_DVB
select DVB_MT352
select VIDEO_CX88_VP3054
+ select DVB_ZL10353
select DVB_OR51132
select DVB_CX22702
select DVB_LGDT330X
@@ -81,6 +82,16 @@ config VIDEO_CX88_VP3054
which also require support for the VP-3054
Secondary I2C bus, such at DNTV Live! DVB-T Pro.
+config VIDEO_CX88_DVB_ZL10353
+ bool "Zarlink ZL10353 DVB-T Support"
+ default y
+ depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+ select DVB_ZL10353
+ ---help---
+ This adds DVB-T support for cards based on the
+ Connexant 2388x chip and the ZL10353 demodulator,
+ successor to the Zarlink MT352.
+
config VIDEO_CX88_DVB_OR51132
bool "OR51132 ATSC Support"
default y
diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile
index 2b902784fac..6482b9aa6a1 100644
--- a/drivers/media/video/cx88/Makefile
+++ b/drivers/media/video/cx88/Makefile
@@ -17,6 +17,7 @@ extra-cflags-$(CONFIG_DVB_CX22702) += -DHAVE_CX22702=1
extra-cflags-$(CONFIG_DVB_OR51132) += -DHAVE_OR51132=1
extra-cflags-$(CONFIG_DVB_LGDT330X) += -DHAVE_LGDT330X=1
extra-cflags-$(CONFIG_DVB_MT352) += -DHAVE_MT352=1
+extra-cflags-$(CONFIG_DVB_ZL10353) += -DHAVE_ZL10353=1
extra-cflags-$(CONFIG_DVB_NXT200X) += -DHAVE_NXT200X=1
extra-cflags-$(CONFIG_DVB_CX24123) += -DHAVE_CX24123=1
extra-cflags-$(CONFIG_VIDEO_CX88_VP3054)+= -DHAVE_VP3054_I2C=1
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index 2acccd6d49b..bffef1decc8 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -672,6 +672,11 @@ static int __devinit snd_cx88_create(snd_card_t *card, struct pci_dev *pci,
chip = (snd_cx88_card_t *) card->private_data;
core = cx88_core_get(pci);
+ if (NULL == core) {
+ err = -EINVAL;
+ kfree (chip);
+ return err;
+ }
if (!pci_dma_supported(pci,0xffffffff)) {
dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name);
@@ -688,11 +693,6 @@ static int __devinit snd_cx88_create(snd_card_t *card, struct pci_dev *pci,
spin_lock_init(&chip->reg_lock);
cx88_reset(core);
- if (NULL == core) {
- err = -EINVAL;
- kfree (chip);
- return err;
- }
chip->core = core;
/* get irq */
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 1bc999247fd..c7042cf4123 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -184,17 +184,18 @@ struct cx88_board cx88_boards[] = {
.input = {{
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
- .gpio1 = 0x309f,
+ .gpio1 = 0xe09f,
},{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
- .gpio1 = 0x305f,
+ .gpio1 = 0xe05f,
},{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
- .gpio1 = 0x305f,
+ .gpio1 = 0xe05f,
}},
.radio = {
+ .gpio1 = 0xe0df,
.type = CX88_RADIO,
},
},
@@ -322,19 +323,19 @@ struct cx88_board cx88_boards[] = {
.input = {{
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
- .gpio0 = 0xff00,
+ .gpio0 = 0xbff0,
},{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
- .gpio0 = 0xff03,
+ .gpio0 = 0xbff3,
},{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
- .gpio0 = 0xff03,
+ .gpio0 = 0xbff3,
}},
.radio = {
.type = CX88_RADIO,
- .gpio0 = 0xff00,
+ .gpio0 = 0xbff0,
},
},
[CX88_BOARD_ASUS_PVR_416] = {
@@ -1048,6 +1049,50 @@ struct cx88_board cx88_boards[] = {
}},
.dvb = 1,
},
+ [CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = {
+ /* FIXME: Standard video using the cx88 broadcast decoder is
+ * working, but blackbird isn't working yet, audio is only
+ * working correctly for television mode. S-Video and Composite
+ * are working for video-only, so I have them disabled for now.
+ */
+ .name = "KWorld HardwareMpegTV XPert",
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x3de2,
+ .gpio2 = 0x00ff,
+ }},
+ .radio = {
+ .type = CX88_RADIO,
+ .gpio0 = 0x3de6,
+ .gpio2 = 0x00ff,
+ },
+ },
+ [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID] = {
+ .name = "DViCO FusionHDTV DVB-T Hybrid",
+ .tuner_type = TUNER_THOMSON_FE6600,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x0000a75f,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x0000a75b,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x0000a75b,
+ }},
+ .dvb = 1,
+ },
};
const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
@@ -1254,6 +1299,18 @@ struct cx88_subid cx88_subids[] = {
.subdevice = 0xdb11,
.card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS,
/* Re-branded DViCO: UltraView DVB-T Plus */
+ },{
+ .subvendor = 0x17de,
+ .subdevice = 0x0840,
+ .card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
+ },{
+ .subvendor = 0x18ac,
+ .subdevice = 0xdb40,
+ .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID,
+ },{
+ .subvendor = 0x18ac,
+ .subdevice = 0xdb44,
+ .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID,
},
};
const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
@@ -1373,6 +1430,40 @@ static void gdi_eeprom(struct cx88_core *core, u8 *eeprom_data)
}
/* ----------------------------------------------------------------------- */
+/* some DViCO specific stuff */
+
+static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core)
+{
+ struct i2c_msg msg = { .addr = 0x45, .flags = 0 };
+ int i, err;
+ static u8 init_bufs[13][5] = {
+ { 0x10, 0x00, 0x20, 0x01, 0x03 },
+ { 0x10, 0x10, 0x01, 0x00, 0x21 },
+ { 0x10, 0x10, 0x10, 0x00, 0xCA },
+ { 0x10, 0x10, 0x12, 0x00, 0x08 },
+ { 0x10, 0x10, 0x13, 0x00, 0x0A },
+ { 0x10, 0x10, 0x16, 0x01, 0xC0 },
+ { 0x10, 0x10, 0x22, 0x01, 0x3D },
+ { 0x10, 0x10, 0x73, 0x01, 0x2E },
+ { 0x10, 0x10, 0x72, 0x00, 0xC5 },
+ { 0x10, 0x10, 0x71, 0x01, 0x97 },
+ { 0x10, 0x10, 0x70, 0x00, 0x0F },
+ { 0x10, 0x10, 0xB0, 0x00, 0x01 },
+ { 0x03, 0x0C },
+ };
+
+ for (i = 0; i < 13; i++) {
+ msg.buf = init_bufs[i];
+ msg.len = (i != 12 ? 5 : 2);
+ err = i2c_transfer(&core->i2c_adap, &msg, 1);
+ if (err != 1) {
+ printk("dvico_fusionhdtv_hybrid_init buf %d failed (err = %d)!\n", i, err);
+ return;
+ }
+ }
+}
+
+/* ----------------------------------------------------------------------- */
void cx88_card_list(struct cx88_core *core, struct pci_dev *pci)
{
@@ -1438,11 +1529,15 @@ void cx88_card_setup(struct cx88_core *core)
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
/* GPIO0:0 is hooked to mt352 reset pin */
cx_set(MO_GP0_IO, 0x00000101);
cx_clear(MO_GP0_IO, 0x00000001);
msleep(1);
cx_set(MO_GP0_IO, 0x00000101);
+ if (0 == core->i2c_rc &&
+ core->board == CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID)
+ dvico_fusionhdtv_hybrid_init(core);
break;
case CX88_BOARD_KWORLD_DVB_T:
case CX88_BOARD_DNTV_LIVE_DVB_T:
@@ -1460,7 +1555,7 @@ void cx88_card_setup(struct cx88_core *core)
if (0 == core->i2c_rc) {
/* enable tuner */
int i;
- u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 };
+ static const u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 };
core->i2c_client.addr = 0x0a;
for (i = 0; i < 5; i++)
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index 3720f24a25c..c2cdbafdb77 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -163,7 +163,7 @@ int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
/* save pointer to jmp instruction address */
risc->jmp = rp;
- BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size);
+ BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
return 0;
}
@@ -188,7 +188,7 @@ int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
/* save pointer to jmp instruction address */
risc->jmp = rp;
- BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size);
+ BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
return 0;
}
@@ -215,8 +215,7 @@ int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
void
cx88_free_buffer(struct pci_dev *pci, struct cx88_buffer *buf)
{
- if (in_interrupt())
- BUG();
+ BUG_ON(in_interrupt());
videobuf_waiton(&buf->vb,0,0);
videobuf_dma_pci_unmap(pci, &buf->vb.dma);
videobuf_dma_free(&buf->vb.dma);
@@ -1061,7 +1060,7 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci)
core->pci_bus = pci->bus->number;
core->pci_slot = PCI_SLOT(pci->devfn);
core->pci_irqmask = 0x00fc00;
- init_MUTEX(&core->lock);
+ mutex_init(&core->lock);
core->nr = cx88_devcount++;
sprintf(core->name,"cx88[%d]",core->nr);
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index e48aa3f6e50..a9fc2695b15 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -40,6 +40,9 @@
# include "cx88-vp3054-i2c.h"
# endif
#endif
+#ifdef HAVE_ZL10353
+# include "zl10353.h"
+#endif
#ifdef HAVE_CX22702
# include "cx22702.h"
#endif
@@ -111,6 +114,21 @@ static struct videobuf_queue_ops dvb_qops = {
/* ------------------------------------------------------------------ */
+#if defined(HAVE_MT352) || defined(HAVE_ZL10353)
+static int zarlink_pll_set(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params,
+ u8 *pllbuf)
+{
+ struct cx8802_dev *dev = fe->dvb->priv;
+
+ pllbuf[0] = dev->core->pll_addr << 1;
+ dvb_pll_configure(dev->core->pll_desc, pllbuf + 1,
+ params->frequency,
+ params->u.ofdm.bandwidth);
+ return 0;
+}
+#endif
+
#ifdef HAVE_MT352
static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
{
@@ -176,35 +194,22 @@ static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe)
return 0;
}
-static int mt352_pll_set(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params,
- u8* pllbuf)
-{
- struct cx8802_dev *dev= fe->dvb->priv;
-
- pllbuf[0] = dev->core->pll_addr << 1;
- dvb_pll_configure(dev->core->pll_desc, pllbuf+1,
- params->frequency,
- params->u.ofdm.bandwidth);
- return 0;
-}
-
static struct mt352_config dvico_fusionhdtv = {
.demod_address = 0x0F,
.demod_init = dvico_fusionhdtv_demod_init,
- .pll_set = mt352_pll_set,
+ .pll_set = zarlink_pll_set,
};
static struct mt352_config dntv_live_dvbt_config = {
.demod_address = 0x0f,
.demod_init = dntv_live_dvbt_demod_init,
- .pll_set = mt352_pll_set,
+ .pll_set = zarlink_pll_set,
};
static struct mt352_config dvico_fusionhdtv_dual = {
.demod_address = 0x0F,
.demod_init = dvico_dual_demod_init,
- .pll_set = mt352_pll_set,
+ .pll_set = zarlink_pll_set,
};
#ifdef HAVE_VP3054_I2C
@@ -294,6 +299,46 @@ static struct mt352_config dntv_live_dvbt_pro_config = {
#endif
#endif
+#ifdef HAVE_ZL10353
+static int dvico_hybrid_tune_pll(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params,
+ u8 *pllbuf)
+{
+ struct cx8802_dev *dev= fe->dvb->priv;
+ struct i2c_msg msg =
+ { .addr = dev->core->pll_addr, .flags = 0,
+ .buf = pllbuf + 1, .len = 4 };
+ int err;
+
+ pllbuf[0] = dev->core->pll_addr << 1;
+ dvb_pll_configure(dev->core->pll_desc, pllbuf + 1,
+ params->frequency,
+ params->u.ofdm.bandwidth);
+
+ if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
+ printk(KERN_WARNING "cx88-dvb: %s error "
+ "(addr %02x <- %02x, err = %i)\n",
+ __FUNCTION__, pllbuf[0], pllbuf[1], err);
+ if (err < 0)
+ return err;
+ else
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static struct zl10353_config dvico_fusionhdtv_hybrid = {
+ .demod_address = 0x0F,
+ .pll_set = dvico_hybrid_tune_pll,
+};
+
+static struct zl10353_config dvico_fusionhdtv_plus_v1_1 = {
+ .demod_address = 0x0F,
+ .pll_set = zarlink_pll_set,
+};
+#endif
+
#ifdef HAVE_CX22702
static struct cx22702_config connexant_refboard_config = {
.demod_address = 0x43,
@@ -500,16 +545,27 @@ static int dvb_register(struct cx8802_dev *dev)
&dev->core->i2c_adap);
break;
#endif
+#if defined(HAVE_MT352) || defined(HAVE_ZL10353)
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
+ dev->core->pll_addr = 0x60;
+ dev->core->pll_desc = &dvb_pll_thomson_dtt7579;
#ifdef HAVE_MT352
- case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
- dev->core->pll_addr = 0x61;
- dev->core->pll_desc = &dvb_pll_lg_z201;
dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL)
+ break;
+#endif
+#ifdef HAVE_ZL10353
+ /* ZL10353 replaces MT352 on later cards */
+ dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_plus_v1_1,
+ &dev->core->i2c_adap);
+#endif
break;
- case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
- dev->core->pll_addr = 0x60;
- dev->core->pll_desc = &dvb_pll_thomson_dtt7579;
+#endif /* HAVE_MT352 || HAVE_ZL10353 */
+#ifdef HAVE_MT352
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
+ dev->core->pll_addr = 0x61;
+ dev->core->pll_desc = &dvb_pll_lg_z201;
dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
&dev->core->i2c_adap);
break;
@@ -540,6 +596,14 @@ static int dvb_register(struct cx8802_dev *dev)
&dev->core->i2c_adap);
break;
#endif
+#ifdef HAVE_ZL10353
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
+ dev->core->pll_addr = 0x61;
+ dev->core->pll_desc = &dvb_pll_thomson_fe6600;
+ dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_hybrid,
+ &dev->core->i2c_adap);
+ break;
+#endif
#ifdef HAVE_OR51132
case CX88_BOARD_PCHDTV_HD3000:
dev->dvb.frontend = or51132_attach(&pchdtv_hd3000,
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index 165d948624a..78a63b7dd38 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -34,337 +34,6 @@
/* ---------------------------------------------------------------------- */
-/* DigitalNow DNTV Live DVB-T Remote */
-static IR_KEYTAB_TYPE ir_codes_dntv_live_dvb_t[IR_KEYTAB_SIZE] = {
- [0x00] = KEY_ESC, /* 'go up a level?' */
- /* Keys 0 to 9 */
- [0x0a] = KEY_KP0,
- [0x01] = KEY_KP1,
- [0x02] = KEY_KP2,
- [0x03] = KEY_KP3,
- [0x04] = KEY_KP4,
- [0x05] = KEY_KP5,
- [0x06] = KEY_KP6,
- [0x07] = KEY_KP7,
- [0x08] = KEY_KP8,
- [0x09] = KEY_KP9,
-
- [0x0b] = KEY_TUNER, /* tv/fm */
- [0x0c] = KEY_SEARCH, /* scan */
- [0x0d] = KEY_STOP,
- [0x0e] = KEY_PAUSE,
- [0x0f] = KEY_LIST, /* source */
-
- [0x10] = KEY_MUTE,
- [0x11] = KEY_REWIND, /* backward << */
- [0x12] = KEY_POWER,
- [0x13] = KEY_S, /* snap */
- [0x14] = KEY_AUDIO, /* stereo */
- [0x15] = KEY_CLEAR, /* reset */
- [0x16] = KEY_PLAY,
- [0x17] = KEY_ENTER,
- [0x18] = KEY_ZOOM, /* full screen */
- [0x19] = KEY_FASTFORWARD, /* forward >> */
- [0x1a] = KEY_CHANNELUP,
- [0x1b] = KEY_VOLUMEUP,
- [0x1c] = KEY_INFO, /* preview */
- [0x1d] = KEY_RECORD, /* record */
- [0x1e] = KEY_CHANNELDOWN,
- [0x1f] = KEY_VOLUMEDOWN,
-};
-
-/* ---------------------------------------------------------------------- */
-
-/* IO-DATA BCTV7E Remote */
-static IR_KEYTAB_TYPE ir_codes_iodata_bctv7e[IR_KEYTAB_SIZE] = {
- [0x40] = KEY_TV,
- [0x20] = KEY_RADIO, /* FM */
- [0x60] = KEY_EPG,
- [0x00] = KEY_POWER,
-
- /* Keys 0 to 9 */
- [0x44] = KEY_KP0, /* 10 */
- [0x50] = KEY_KP1,
- [0x30] = KEY_KP2,
- [0x70] = KEY_KP3,
- [0x48] = KEY_KP4,
- [0x28] = KEY_KP5,
- [0x68] = KEY_KP6,
- [0x58] = KEY_KP7,
- [0x38] = KEY_KP8,
- [0x78] = KEY_KP9,
-
- [0x10] = KEY_L, /* Live */
- [0x08] = KEY_T, /* Time Shift */
-
- [0x18] = KEY_PLAYPAUSE, /* Play */
-
- [0x24] = KEY_ENTER, /* 11 */
- [0x64] = KEY_ESC, /* 12 */
- [0x04] = KEY_M, /* Multi */
-
- [0x54] = KEY_VIDEO,
- [0x34] = KEY_CHANNELUP,
- [0x74] = KEY_VOLUMEUP,
- [0x14] = KEY_MUTE,
-
- [0x4c] = KEY_S, /* SVIDEO */
- [0x2c] = KEY_CHANNELDOWN,
- [0x6c] = KEY_VOLUMEDOWN,
- [0x0c] = KEY_ZOOM,
-
- [0x5c] = KEY_PAUSE,
- [0x3c] = KEY_C, /* || (red) */
- [0x7c] = KEY_RECORD, /* recording */
- [0x1c] = KEY_STOP,
-
- [0x41] = KEY_REWIND, /* backward << */
- [0x21] = KEY_PLAY,
- [0x61] = KEY_FASTFORWARD, /* forward >> */
- [0x01] = KEY_NEXT, /* skip >| */
-};
-
-/* ---------------------------------------------------------------------- */
-
-/* ADS Tech Instant TV DVB-T PCI Remote */
-static IR_KEYTAB_TYPE ir_codes_adstech_dvb_t_pci[IR_KEYTAB_SIZE] = {
- /* Keys 0 to 9 */
- [0x4d] = KEY_0,
- [0x57] = KEY_1,
- [0x4f] = KEY_2,
- [0x53] = KEY_3,
- [0x56] = KEY_4,
- [0x4e] = KEY_5,
- [0x5e] = KEY_6,
- [0x54] = KEY_7,
- [0x4c] = KEY_8,
- [0x5c] = KEY_9,
-
- [0x5b] = KEY_POWER,
- [0x5f] = KEY_MUTE,
- [0x55] = KEY_GOTO,
- [0x5d] = KEY_SEARCH,
- [0x17] = KEY_EPG, /* Guide */
- [0x1f] = KEY_MENU,
- [0x0f] = KEY_UP,
- [0x46] = KEY_DOWN,
- [0x16] = KEY_LEFT,
- [0x1e] = KEY_RIGHT,
- [0x0e] = KEY_SELECT, /* Enter */
- [0x5a] = KEY_INFO,
- [0x52] = KEY_EXIT,
- [0x59] = KEY_PREVIOUS,
- [0x51] = KEY_NEXT,
- [0x58] = KEY_REWIND,
- [0x50] = KEY_FORWARD,
- [0x44] = KEY_PLAYPAUSE,
- [0x07] = KEY_STOP,
- [0x1b] = KEY_RECORD,
- [0x13] = KEY_TUNER, /* Live */
- [0x0a] = KEY_A,
- [0x12] = KEY_B,
- [0x03] = KEY_PROG1, /* 1 */
- [0x01] = KEY_PROG2, /* 2 */
- [0x00] = KEY_PROG3, /* 3 */
- [0x06] = KEY_DVD,
- [0x48] = KEY_AUX, /* Photo */
- [0x40] = KEY_VIDEO,
- [0x19] = KEY_AUDIO, /* Music */
- [0x0b] = KEY_CHANNELUP,
- [0x08] = KEY_CHANNELDOWN,
- [0x15] = KEY_VOLUMEUP,
- [0x1c] = KEY_VOLUMEDOWN,
-};
-
-/* ---------------------------------------------------------------------- */
-
-/* MSI TV@nywhere remote */
-static IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE] = {
- /* Keys 0 to 9 */
- [0x00] = KEY_0,
- [0x01] = KEY_1,
- [0x02] = KEY_2,
- [0x03] = KEY_3,
- [0x04] = KEY_4,
- [0x05] = KEY_5,
- [0x06] = KEY_6,
- [0x07] = KEY_7,
- [0x08] = KEY_8,
- [0x09] = KEY_9,
-
- [0x0c] = KEY_MUTE,
- [0x0f] = KEY_SCREEN, /* Full Screen */
- [0x10] = KEY_F, /* Funtion */
- [0x11] = KEY_T, /* Time shift */
- [0x12] = KEY_POWER,
- [0x13] = KEY_MEDIA, /* MTS */
- [0x14] = KEY_SLOW,
- [0x16] = KEY_REWIND, /* backward << */
- [0x17] = KEY_ENTER, /* Return */
- [0x18] = KEY_FASTFORWARD, /* forward >> */
- [0x1a] = KEY_CHANNELUP,
- [0x1b] = KEY_VOLUMEUP,
- [0x1e] = KEY_CHANNELDOWN,
- [0x1f] = KEY_VOLUMEDOWN,
-};
-
-/* ---------------------------------------------------------------------- */
-
-/* Cinergy 1400 DVB-T */
-static IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE] = {
- [0x01] = KEY_POWER,
- [0x02] = KEY_1,
- [0x03] = KEY_2,
- [0x04] = KEY_3,
- [0x05] = KEY_4,
- [0x06] = KEY_5,
- [0x07] = KEY_6,
- [0x08] = KEY_7,
- [0x09] = KEY_8,
- [0x0a] = KEY_9,
- [0x0c] = KEY_0,
-
- [0x0b] = KEY_VIDEO,
- [0x0d] = KEY_REFRESH,
- [0x0e] = KEY_SELECT,
- [0x0f] = KEY_EPG,
- [0x10] = KEY_UP,
- [0x11] = KEY_LEFT,
- [0x12] = KEY_OK,
- [0x13] = KEY_RIGHT,
- [0x14] = KEY_DOWN,
- [0x15] = KEY_TEXT,
- [0x16] = KEY_INFO,
-
- [0x17] = KEY_RED,
- [0x18] = KEY_GREEN,
- [0x19] = KEY_YELLOW,
- [0x1a] = KEY_BLUE,
-
- [0x1b] = KEY_CHANNELUP,
- [0x1c] = KEY_VOLUMEUP,
- [0x1d] = KEY_MUTE,
- [0x1e] = KEY_VOLUMEDOWN,
- [0x1f] = KEY_CHANNELDOWN,
-
- [0x40] = KEY_PAUSE,
- [0x4c] = KEY_PLAY,
- [0x58] = KEY_RECORD,
- [0x54] = KEY_PREVIOUS,
- [0x48] = KEY_STOP,
- [0x5c] = KEY_NEXT,
-};
-
-/* ---------------------------------------------------------------------- */
-
-/* AVERTV STUDIO 303 Remote */
-static IR_KEYTAB_TYPE ir_codes_avertv_303[IR_KEYTAB_SIZE] = {
- [ 0x2a ] = KEY_KP1,
- [ 0x32 ] = KEY_KP2,
- [ 0x3a ] = KEY_KP3,
- [ 0x4a ] = KEY_KP4,
- [ 0x52 ] = KEY_KP5,
- [ 0x5a ] = KEY_KP6,
- [ 0x6a ] = KEY_KP7,
- [ 0x72 ] = KEY_KP8,
- [ 0x7a ] = KEY_KP9,
- [ 0x0e ] = KEY_KP0,
-
- [ 0x02 ] = KEY_POWER,
- [ 0x22 ] = KEY_VIDEO,
- [ 0x42 ] = KEY_AUDIO,
- [ 0x62 ] = KEY_ZOOM,
- [ 0x0a ] = KEY_TV,
- [ 0x12 ] = KEY_CD,
- [ 0x1a ] = KEY_TEXT,
-
- [ 0x16 ] = KEY_SUBTITLE,
- [ 0x1e ] = KEY_REWIND,
- [ 0x06 ] = KEY_PRINT,
-
- [ 0x2e ] = KEY_SEARCH,
- [ 0x36 ] = KEY_SLEEP,
- [ 0x3e ] = KEY_SHUFFLE,
- [ 0x26 ] = KEY_MUTE,
-
- [ 0x4e ] = KEY_RECORD,
- [ 0x56 ] = KEY_PAUSE,
- [ 0x5e ] = KEY_STOP,
- [ 0x46 ] = KEY_PLAY,
-
- [ 0x6e ] = KEY_RED,
- [ 0x0b ] = KEY_GREEN,
- [ 0x66 ] = KEY_YELLOW,
- [ 0x03 ] = KEY_BLUE,
-
- [ 0x76 ] = KEY_LEFT,
- [ 0x7e ] = KEY_RIGHT,
- [ 0x13 ] = KEY_DOWN,
- [ 0x1b ] = KEY_UP,
-};
-
-/* ---------------------------------------------------------------------- */
-
-/* DigitalNow DNTV Live! DVB-T Pro Remote */
-static IR_KEYTAB_TYPE ir_codes_dntv_live_dvbt_pro[IR_KEYTAB_SIZE] = {
- [ 0x16 ] = KEY_POWER,
- [ 0x5b ] = KEY_HOME,
-
- [ 0x55 ] = KEY_TV, /* live tv */
- [ 0x58 ] = KEY_TUNER, /* digital Radio */
- [ 0x5a ] = KEY_RADIO, /* FM radio */
- [ 0x59 ] = KEY_DVD, /* dvd menu */
- [ 0x03 ] = KEY_1,
- [ 0x01 ] = KEY_2,
- [ 0x06 ] = KEY_3,
- [ 0x09 ] = KEY_4,
- [ 0x1d ] = KEY_5,
- [ 0x1f ] = KEY_6,
- [ 0x0d ] = KEY_7,
- [ 0x19 ] = KEY_8,
- [ 0x1b ] = KEY_9,
- [ 0x0c ] = KEY_CANCEL,
- [ 0x15 ] = KEY_0,
- [ 0x4a ] = KEY_CLEAR,
- [ 0x13 ] = KEY_BACK,
- [ 0x00 ] = KEY_TAB,
- [ 0x4b ] = KEY_UP,
- [ 0x4e ] = KEY_LEFT,
- [ 0x4f ] = KEY_OK,
- [ 0x52 ] = KEY_RIGHT,
- [ 0x51 ] = KEY_DOWN,
- [ 0x1e ] = KEY_VOLUMEUP,
- [ 0x0a ] = KEY_VOLUMEDOWN,
- [ 0x02 ] = KEY_CHANNELDOWN,
- [ 0x05 ] = KEY_CHANNELUP,
- [ 0x11 ] = KEY_RECORD,
- [ 0x14 ] = KEY_PLAY,
- [ 0x4c ] = KEY_PAUSE,
- [ 0x1a ] = KEY_STOP,
- [ 0x40 ] = KEY_REWIND,
- [ 0x12 ] = KEY_FASTFORWARD,
- [ 0x41 ] = KEY_PREVIOUSSONG, /* replay |< */
- [ 0x42 ] = KEY_NEXTSONG, /* skip >| */
- [ 0x54 ] = KEY_CAMERA, /* capture */
- [ 0x50 ] = KEY_LANGUAGE, /* sap */
- [ 0x47 ] = KEY_TV2, /* pip */
- [ 0x4d ] = KEY_SCREEN,
- [ 0x43 ] = KEY_SUBTITLE,
- [ 0x10 ] = KEY_MUTE,
- [ 0x49 ] = KEY_AUDIO, /* l/r */
- [ 0x07 ] = KEY_SLEEP,
- [ 0x08 ] = KEY_VIDEO, /* a/v */
- [ 0x0e ] = KEY_PREVIOUS, /* recall */
- [ 0x45 ] = KEY_ZOOM, /* zoom + */
- [ 0x46 ] = KEY_ANGLE, /* zoom - */
- [ 0x56 ] = KEY_RED,
- [ 0x57 ] = KEY_GREEN,
- [ 0x5c ] = KEY_YELLOW,
- [ 0x5d ] = KEY_BLUE,
-};
-
-/* ---------------------------------------------------------------------- */
-
struct cx88_IR {
struct cx88_core *core;
struct input_dev *input;
@@ -517,6 +186,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
ir->mask_keydown = 0x02;
ir->polling = 5; /* ms */
break;
+ case CX88_BOARD_PROLINK_PLAYTVPVR:
case CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO:
ir_codes = ir_codes_pixelview;
ir->gpio_addr = MO_GP1_IO;
@@ -524,6 +194,13 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
ir->mask_keyup = 0x80;
ir->polling = 1; /* ms */
break;
+ case CX88_BOARD_KWORLD_LTV883:
+ ir_codes = ir_codes_pixelview;
+ ir->gpio_addr = MO_GP1_IO;
+ ir->mask_keycode = 0x1f;
+ ir->mask_keyup = 0x60;
+ ir->polling = 1; /* ms */
+ break;
case CX88_BOARD_ADSTECH_DVB_T_PCI:
ir_codes = ir_codes_adstech_dvb_t_pci;
ir->gpio_addr = MO_GP1_IO;
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 073494ceab0..6c97aa740d2 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -227,7 +227,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
.minimum = 0x00,
.maximum = 0xff,
.step = 1,
- .default_value = 0,
+ .default_value = 0x7f,
.type = V4L2_CTRL_TYPE_INTEGER,
},
.off = 128,
@@ -255,7 +255,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
.minimum = 0,
.maximum = 0xff,
.step = 1,
- .default_value = 0,
+ .default_value = 0x7f,
.type = V4L2_CTRL_TYPE_INTEGER,
},
.off = 128,
@@ -300,7 +300,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
.minimum = 0,
.maximum = 0x3f,
.step = 1,
- .default_value = 0x1f,
+ .default_value = 0x3f,
.type = V4L2_CTRL_TYPE_INTEGER,
},
.reg = AUD_VOL_CTL,
@@ -336,17 +336,17 @@ static int res_get(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bi
return 1;
/* is it free? */
- down(&core->lock);
+ mutex_lock(&core->lock);
if (dev->resources & bit) {
/* no, someone else uses it */
- up(&core->lock);
+ mutex_unlock(&core->lock);
return 0;
}
/* it's free, grab it */
fh->resources |= bit;
dev->resources |= bit;
dprintk(1,"res: get %d\n",bit);
- up(&core->lock);
+ mutex_unlock(&core->lock);
return 1;
}
@@ -366,14 +366,13 @@ static
void res_free(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bits)
{
struct cx88_core *core = dev->core;
- if ((fh->resources & bits) != bits)
- BUG();
+ BUG_ON((fh->resources & bits) != bits);
- down(&core->lock);
+ mutex_lock(&core->lock);
fh->resources &= ~bits;
dev->resources &= ~bits;
dprintk(1,"res: put %d\n",bits);
- up(&core->lock);
+ mutex_unlock(&core->lock);
}
/* ------------------------------------------------------------------ */
@@ -909,7 +908,8 @@ static int get_control(struct cx88_core *core, struct v4l2_control *ctl)
value = c->sreg ? cx_sread(c->sreg) : cx_read(c->reg);
switch (ctl->id) {
case V4L2_CID_AUDIO_BALANCE:
- ctl->value = (value & 0x40) ? (value & 0x3f) : (0x40 - (value & 0x3f));
+ ctl->value = ((value & 0x7f) < 0x40) ? ((value & 0x7f) + 0x40)
+ : (0x7f - (value & 0x7f));
break;
case V4L2_CID_AUDIO_VOLUME:
ctl->value = 0x3f - (value & 0x3f);
@@ -918,9 +918,9 @@ static int get_control(struct cx88_core *core, struct v4l2_control *ctl)
ctl->value = ((value + (c->off << c->shift)) & c->mask) >> c->shift;
break;
}
- printk("get_control id=0x%X reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
- ctl->id, c->reg, ctl->value,
- c->mask, c->sreg ? " [shadowed]" : "");
+ dprintk(1,"get_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
+ ctl->id, c->v.name, ctl->value, c->reg,
+ value,c->mask, c->sreg ? " [shadowed]" : "");
return 0;
}
@@ -946,7 +946,7 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
mask=c->mask;
switch (ctl->id) {
case V4L2_CID_AUDIO_BALANCE:
- value = (ctl->value < 0x40) ? (0x40 - ctl->value) : ctl->value;
+ value = (ctl->value < 0x40) ? (0x7f - ctl->value) : (ctl->value - 0x40);
break;
case V4L2_CID_AUDIO_VOLUME:
value = 0x3f - (ctl->value & 0x3f);
@@ -969,9 +969,9 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
value = ((ctl->value - c->off) << c->shift) & c->mask;
break;
}
- printk("set_control id=0x%X reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
- ctl->id, c->reg, value,
- mask, c->sreg ? " [shadowed]" : "");
+ dprintk(1,"set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
+ ctl->id, c->v.name, ctl->value, c->reg, value,
+ mask, c->sreg ? " [shadowed]" : "");
if (c->sreg) {
cx_sandor(c->sreg, c->reg, mask, value);
} else {
@@ -987,8 +987,7 @@ static void init_controls(struct cx88_core *core)
for (i = 0; i < CX8800_CTLS; i++) {
ctrl.id=cx8800_ctls[i].v.id;
- ctrl.value=cx8800_ctls[i].v.default_value
- +cx8800_ctls[i].off;
+ ctrl.value=cx8800_ctls[i].v.default_value;
set_control(core, &ctrl);
}
}
@@ -1252,7 +1251,7 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
{
int err;
- dprintk( 1, "CORE IOCTL: 0x%x\n", cmd );
+ dprintk(2, "CORE IOCTL: 0x%x\n", cmd );
if (video_debug > 1)
v4l_print_ioctl(core->name,cmd);
@@ -1291,9 +1290,9 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
if (i == ARRAY_SIZE(tvnorms))
return -EINVAL;
- down(&core->lock);
+ mutex_lock(&core->lock);
cx88_set_tvnorm(core,&tvnorms[i]);
- up(&core->lock);
+ mutex_unlock(&core->lock);
return 0;
}
@@ -1343,10 +1342,10 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
if (*i >= 4)
return -EINVAL;
- down(&core->lock);
+ mutex_lock(&core->lock);
cx88_newstation(core);
video_mux(core,*i);
- up(&core->lock);
+ mutex_unlock(&core->lock);
return 0;
}
@@ -1438,7 +1437,7 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
return -EINVAL;
if (1 == radio && f->type != V4L2_TUNER_RADIO)
return -EINVAL;
- down(&core->lock);
+ mutex_lock(&core->lock);
core->freq = f->frequency;
cx88_newstation(core);
cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f);
@@ -1447,7 +1446,7 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
msleep (10);
cx88_set_tvaudio(core);
- up(&core->lock);
+ mutex_unlock(&core->lock);
return 0;
}
@@ -1921,11 +1920,11 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
pci_set_drvdata(pci_dev,dev);
/* initial device configuration */
- down(&core->lock);
+ mutex_lock(&core->lock);
cx88_set_tvnorm(core,tvnorms);
init_controls(core);
video_mux(core,0);
- up(&core->lock);
+ mutex_unlock(&core->lock);
/* start tvaudio thread */
if (core->tuner_type != TUNER_ABSENT)
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index e9fd55b57fa..cfa8668784b 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -35,6 +35,7 @@
#include "cx88-reg.h"
#include <linux/version.h>
+#include <linux/mutex.h>
#define CX88_VERSION_CODE KERNEL_VERSION(0,0,5)
#ifndef TRUE
@@ -62,7 +63,7 @@
/* need "shadow" registers for some write-only ones ... */
#define SHADOW_AUD_VOL_CTL 1
#define SHADOW_AUD_BAL_CTL 2
-#define SHADOW_MAX 2
+#define SHADOW_MAX 3
/* FM Radio deemphasis type */
enum cx88_deemph_type {
@@ -187,6 +188,8 @@ extern struct sram_channel cx88_sram_channels[];
#define CX88_BOARD_DNTV_LIVE_DVB_T_PRO 42
#define CX88_BOARD_KWORLD_DVB_T_CX22702 43
#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL 44
+#define CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT 45
+#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID 46
enum cx88_itype {
CX88_VMUX_COMPOSITE1 = 1,
@@ -308,8 +311,7 @@ struct cx88_core {
/* IR remote control state */
struct cx88_IR *ir;
- struct semaphore lock;
-
+ struct mutex lock;
/* various v4l controls */
u32 freq;
diff --git a/drivers/media/video/dpc7146.c b/drivers/media/video/dpc7146.c
index 2831bdd1205..0fcc935828f 100644
--- a/drivers/media/video/dpc7146.c
+++ b/drivers/media/video/dpc7146.c
@@ -1,6 +1,6 @@
/*
dpc7146.c - v4l2 driver for the dpc7146 demonstration board
-
+
Copyright (C) 2000-2003 Michael Hunold <michael@mihu.de>
This program is free software; you can redistribute it and/or modify
@@ -52,7 +52,7 @@
#define SAA711X_DECODED_BYTES_OF_TS_2 0x1C
#define SAA711X_STATUS_BYTE 0x1F
-#define DPC_BOARD_CAN_DO_VBI(dev) (dev->revision != 0)
+#define DPC_BOARD_CAN_DO_VBI(dev) (dev->revision != 0)
static int debug = 0;
module_param(debug, int, 0);
@@ -81,16 +81,16 @@ struct dpc
struct video_device *video_dev;
struct video_device *vbi_dev;
- struct i2c_adapter i2c_adapter;
+ struct i2c_adapter i2c_adapter;
struct i2c_client *saa7111a;
-
+
int cur_input; /* current input */
};
/* fixme: add vbi stuff here */
static int dpc_probe(struct saa7146_dev* dev)
{
- struct dpc* dpc = NULL;
+ struct dpc* dpc = NULL;
struct i2c_client *client;
struct list_head *item;
@@ -118,20 +118,20 @@ static int dpc_probe(struct saa7146_dev* dev)
/* loop through all i2c-devices on the bus and look who is there */
list_for_each(item,&dpc->i2c_adapter.clients) {
client = list_entry(item, struct i2c_client, list);
- if( I2C_SAA7111A == client->addr )
+ if( I2C_SAA7111A == client->addr )
dpc->saa7111a = client;
}
/* check if all devices are present */
if( 0 == dpc->saa7111a ) {
- DEB_D(("dpc_v4l2.o: dpc_attach failed for this device.\n"));
+ DEB_D(("dpc_v4l2.o: dpc_attach failed for this device.\n"));
i2c_del_adapter(&dpc->i2c_adapter);
kfree(dpc);
return -ENODEV;
}
-
- /* all devices are present, probe was successful */
- DEB_D(("dpc_v4l2.o: dpc_probe succeeded for this device.\n"));
+
+ /* all devices are present, probe was successful */
+ DEB_D(("dpc_v4l2.o: dpc_probe succeeded for this device.\n"));
/* we store the pointer in our private data field */
dev->ext_priv = dpc;
@@ -182,7 +182,7 @@ static struct saa7146_ext_vv vv_data;
static int dpc_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
{
struct dpc* dpc = (struct dpc*)dev->ext_priv;
-
+
DEB_D(("dpc_v4l2.o: dpc_attach called.\n"));
/* checking for i2c-devices can be omitted here, because we
@@ -193,7 +193,7 @@ static int dpc_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data
ERR(("cannot register capture v4l2 device. skipping.\n"));
return -1;
}
-
+
/* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
if( 0 != DPC_BOARD_CAN_DO_VBI(dev)) {
if( 0 != saa7146_register_device(&dpc->vbi_dev, dev, "dpc", VFL_TYPE_VBI)) {
@@ -205,18 +205,18 @@ static int dpc_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data
printk("dpc: found 'dpc7146 demonstration board'-%d.\n",dpc_num);
dpc_num++;
-
+
/* the rest */
dpc->cur_input = 0;
dpc_init_done(dev);
-
+
return 0;
}
static int dpc_detach(struct saa7146_dev* dev)
{
struct dpc* dpc = (struct dpc*)dev->ext_priv;
-
+
DEB_EE(("dev:%p\n",dev));
i2c_release_client(dpc->saa7111a);
@@ -238,25 +238,25 @@ static int dpc_detach(struct saa7146_dev* dev)
int dpc_vbi_bypass(struct saa7146_dev* dev)
{
struct dpc* dpc = (struct dpc*)dev->ext_priv;
-
+
int i = 1;
/* switch bypass in saa7111a */
if ( 0 != dpc->saa7111a->driver->command(dpc->saa7111a,SAA711X_VBI_BYPASS, &i)) {
printk("dpc_v4l2.o: VBI_BYPASS: could not address saa7111a.\n");
return -1;
- }
+ }
return 0;
}
#endif
-static int dpc_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
+static int dpc_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
{
struct saa7146_dev *dev = fh->dev;
struct dpc* dpc = (struct dpc*)dev->ext_priv;
/*
- struct saa7146_vv *vv = dev->vv_data;
+ struct saa7146_vv *vv = dev->vv_data;
*/
switch(cmd)
{
@@ -264,11 +264,11 @@ static int dpc_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
{
struct v4l2_input *i = arg;
DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
-
+
if( i->index < 0 || i->index >= DPC_INPUTS) {
return -EINVAL;
}
-
+
memcpy(i, &dpc_inputs[i->index], sizeof(struct v4l2_input));
DEB_D(("dpc_v4l2.o: v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n",i->index));
@@ -289,13 +289,13 @@ static int dpc_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
if (input < 0 || input >= DPC_INPUTS) {
return -EINVAL;
}
-
+
dpc->cur_input = input;
/* fixme: switch input here, switch audio, too! */
// saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, input_port_selection[input].hps_sync);
printk("dpc_v4l2.o: VIDIOC_S_INPUT: fixme switch input.\n");
-
+
return 0;
}
default:
@@ -334,8 +334,8 @@ static struct saa7146_standard standard[] = {
static struct saa7146_extension extension;
static struct saa7146_pci_extension_data dpc = {
- .ext_priv = "Multimedia eXtension Board",
- .ext = &extension,
+ .ext_priv = "Multimedia eXtension Board",
+ .ext = &extension,
};
static struct pci_device_id pci_tbl[] = {
@@ -357,7 +357,7 @@ static struct saa7146_ext_vv vv_data = {
.capabilities = V4L2_CAP_VBI_CAPTURE,
.stds = &standard[0],
.num_stds = sizeof(standard)/sizeof(struct saa7146_standard),
- .std_callback = &std_callback,
+ .std_callback = &std_callback,
.ioctls = &ioctls[0],
.ioctl = dpc_ioctl,
};
@@ -365,7 +365,7 @@ static struct saa7146_ext_vv vv_data = {
static struct saa7146_extension extension = {
.name = "dpc7146 demonstration board",
.flags = SAA7146_USE_I2C_IRQ,
-
+
.pci_tbl = &pci_tbl[0],
.module = THIS_MODULE,
@@ -375,7 +375,7 @@ static struct saa7146_extension extension = {
.irq_mask = 0,
.irq_func = NULL,
-};
+};
static int __init dpc_init_module(void)
{
@@ -383,7 +383,7 @@ static int __init dpc_init_module(void)
DEB_S(("failed to register extension.\n"));
return -ENODEV;
}
-
+
return 0;
}
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
index 885fd017008..5a793ae7cc2 100644
--- a/drivers/media/video/em28xx/Kconfig
+++ b/drivers/media/video/em28xx/Kconfig
@@ -5,6 +5,7 @@ config VIDEO_EM28XX
select VIDEO_TUNER
select VIDEO_TVEEPROM
select VIDEO_IR
+ select VIDEO_SAA711X
---help---
This is a video4linux driver for Empia 28xx based TV cards.
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 58f7b4194a0..4e22fc4889e 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -72,6 +72,24 @@ struct em28xx_board em28xx_boards[] = {
.amux = 1,
}},
},
+ [EM2820_BOARD_KWORLD_PVRTV2800RF] = {
+ .name = "Kworld PVR TV 2800 RF",
+ .is_em2800 = 0,
+ .vchannels = 2,
+ .norm = VIDEO_MODE_PAL,
+ .tda9887_conf = TDA9887_PRESENT,
+ .has_tuner = 1,
+ .decoder = EM28XX_SAA7113,
+ .input = {{
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
+ },{
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
[EM2820_BOARD_TERRATEC_CINERGY_250] = {
.name = "Terratec Cinergy 250 USB",
.vchannels = 3,
@@ -83,7 +101,7 @@ struct em28xx_board em28xx_boards[] = {
.input = {{
.type = EM28XX_VMUX_TELEVISION,
.vmux = 2,
- .amux = 0,
+ .amux = 1,
},{
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = 0,
@@ -257,27 +275,51 @@ struct usb_device_id em28xx_id_table [] = {
{ },
};
+void em28xx_pre_card_setup(struct em28xx *dev)
+{
+ /* request some modules */
+ switch(dev->model){
+ case EM2880_BOARD_TERRATEC_PRODIGY_XS:
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+ case EM2880_BOARD_TERRATEC_HYBRID_XS:
+ {
+ em28xx_write_regs_req(dev, 0x00, 0x08, "\x7d", 1); // reset through GPIO?
+ break;
+ }
+ }
+}
+
void em28xx_card_setup(struct em28xx *dev)
{
/* request some modules */
- if (dev->model == EM2820_BOARD_HAUPPAUGE_WINTV_USB_2) {
- struct tveeprom tv;
+ switch(dev->model){
+ case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
+ {
+ struct tveeprom tv;
#ifdef CONFIG_MODULES
- request_module("tveeprom");
- request_module("ir-kbd-i2c");
- request_module("msp3400");
+ request_module("tveeprom");
+ request_module("ir-kbd-i2c");
+ request_module("msp3400");
#endif
- /* Call first TVeeprom */
+ /* Call first TVeeprom */
+
+ dev->i2c_client.addr = 0xa0 >> 1;
+ tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata);
- dev->i2c_client.addr = 0xa0 >> 1;
- tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata);
+ dev->tuner_type= tv.tuner_type;
+ if (tv.audio_processor == AUDIO_CHIP_MSP34XX) {
+ dev->i2s_speed=2048000;
+ dev->has_msp34xx=1;
+ } else
+ dev->has_msp34xx=0;
+ break;
+ }
+ case EM2820_BOARD_KWORLD_PVRTV2800RF:
+ {
+ em28xx_write_regs_req(dev,0x00,0x08, "\xf9", 1); // GPIO enables sound on KWORLD PVR TV 2800RF
+ break;
+ }
- dev->tuner_type= tv.tuner_type;
- if (tv.audio_processor == AUDIO_CHIP_MSP34XX) {
- dev->i2s_speed=2048000;
- dev->has_msp34xx=1;
- } else
- dev->has_msp34xx=0;
}
}
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index 6ca8631bc36..5b6cece37ae 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -420,7 +420,6 @@ static int em28xx_set_tuner(int check_eeprom, struct i2c_client *client)
tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
tun_setup.type = dev->tuner_type;
tun_setup.addr = dev->tuner_addr;
-
em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
}
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 30dfa5370c7..31e89e4f18b 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -43,91 +43,6 @@ MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
#define dprintk(fmt, arg...) if (ir_debug) \
printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
-/* ---------------------------------------------------------------------- */
-
-static IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE] = {
- [ 0x01 ] = KEY_CHANNEL,
- [ 0x02 ] = KEY_SELECT,
- [ 0x03 ] = KEY_MUTE,
- [ 0x04 ] = KEY_POWER,
- [ 0x05 ] = KEY_KP1,
- [ 0x06 ] = KEY_KP2,
- [ 0x07 ] = KEY_KP3,
- [ 0x08 ] = KEY_CHANNELUP,
- [ 0x09 ] = KEY_KP4,
- [ 0x0a ] = KEY_KP5,
- [ 0x0b ] = KEY_KP6,
- [ 0x0c ] = KEY_CHANNELDOWN,
- [ 0x0d ] = KEY_KP7,
- [ 0x0e ] = KEY_KP8,
- [ 0x0f ] = KEY_KP9,
- [ 0x10 ] = KEY_VOLUMEUP,
- [ 0x11 ] = KEY_KP0,
- [ 0x12 ] = KEY_MENU,
- [ 0x13 ] = KEY_PRINT,
- [ 0x14 ] = KEY_VOLUMEDOWN,
- [ 0x16 ] = KEY_PAUSE,
- [ 0x18 ] = KEY_RECORD,
- [ 0x19 ] = KEY_REWIND,
- [ 0x1a ] = KEY_PLAY,
- [ 0x1b ] = KEY_FORWARD,
- [ 0x1c ] = KEY_BACKSPACE,
- [ 0x1e ] = KEY_STOP,
- [ 0x40 ] = KEY_ZOOM,
-};
-
-static IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE] = {
- [ 0x3a ] = KEY_KP0,
- [ 0x31 ] = KEY_KP1,
- [ 0x32 ] = KEY_KP2,
- [ 0x33 ] = KEY_KP3,
- [ 0x34 ] = KEY_KP4,
- [ 0x35 ] = KEY_KP5,
- [ 0x36 ] = KEY_KP6,
- [ 0x37 ] = KEY_KP7,
- [ 0x38 ] = KEY_KP8,
- [ 0x39 ] = KEY_KP9,
-
- [ 0x2f ] = KEY_POWER,
-
- [ 0x2e ] = KEY_P,
- [ 0x1f ] = KEY_L,
- [ 0x2b ] = KEY_I,
-
- [ 0x2d ] = KEY_ZOOM,
- [ 0x1e ] = KEY_ZOOM,
- [ 0x1b ] = KEY_VOLUMEUP,
- [ 0x0f ] = KEY_VOLUMEDOWN,
- [ 0x17 ] = KEY_CHANNELUP,
- [ 0x1c ] = KEY_CHANNELDOWN,
- [ 0x25 ] = KEY_INFO,
-
- [ 0x3c ] = KEY_MUTE,
-
- [ 0x3d ] = KEY_LEFT,
- [ 0x3b ] = KEY_RIGHT,
-
- [ 0x3f ] = KEY_UP,
- [ 0x3e ] = KEY_DOWN,
- [ 0x1a ] = KEY_PAUSE,
-
- [ 0x1d ] = KEY_MENU,
- [ 0x19 ] = KEY_PLAY,
- [ 0x16 ] = KEY_REWIND,
- [ 0x13 ] = KEY_FORWARD,
- [ 0x15 ] = KEY_PAUSE,
- [ 0x0e ] = KEY_REWIND,
- [ 0x0d ] = KEY_PLAY,
- [ 0x0b ] = KEY_STOP,
- [ 0x07 ] = KEY_FORWARD,
- [ 0x27 ] = KEY_RECORD,
- [ 0x26 ] = KEY_TUNER,
- [ 0x29 ] = KEY_TEXT,
- [ 0x2a ] = KEY_MEDIA,
- [ 0x18 ] = KEY_EPG,
- [ 0x27 ] = KEY_RECORD,
-};
-
/* ----------------------------------------------------------------------- */
static int get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 5b267808a9d..780342f7b23 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -28,6 +28,7 @@
#include <linux/list.h>
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/bitmap.h>
#include <linux/usb.h>
#include <linux/i2c.h>
#include <linux/version.h>
@@ -59,8 +60,14 @@ MODULE_LICENSE("GPL");
static LIST_HEAD(em28xx_devlist);
static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
module_param_array(card, int, NULL, 0444);
+module_param_array(video_nr, int, NULL, 0444);
+module_param_array(vbi_nr, int, NULL, 0444);
MODULE_PARM_DESC(card,"card type");
+MODULE_PARM_DESC(video_nr,"video device numbers");
+MODULE_PARM_DESC(vbi_nr,"vbi device numbers");
static int tuner = -1;
module_param(tuner, int, 0444);
@@ -70,6 +77,9 @@ static unsigned int video_debug = 0;
module_param(video_debug,int,0644);
MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
+/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */
+static unsigned long em28xx_devused;
+
/* supported tv norms */
static struct em28xx_tvnorm tvnorms[] = {
{
@@ -91,23 +101,6 @@ static struct em28xx_tvnorm tvnorms[] = {
}
};
-static const unsigned char saa7114_i2c_init[] = {
- 0x00,0x00,0x01,0x08,0x02,0xc4,0x03,0x30,0x04,0x90,0x05,0x90,0x06,0xeb,0x07,0xe0,
- 0x08,0x88,0x09,0x40,0x0a,0x80,0x0b,0x44,0x0c,0x40,0x0d,0x00,0x0e,0x81,0x0f,0x2a,
- 0x10,0x06,0x11,0x00,0x12,0xc8,0x13,0x80,0x14,0x00,0x15,0x11,0x16,0x01,0x17,0x42,
- 0x18,0x40,0x19,0x80,0x40,0x00,0x41,0xff,0x42,0xff,0x43,0xff,0x44,0xff,0x45,0xff,
- 0x46,0xff,0x47,0xff,0x48,0xff,0x49,0xff,0x4a,0xff,0x4b,0xff,0x4c,0xff,0x4d,0xff,
- 0x4e,0xff,0x4f,0xff,0x50,0xff,0x51,0xff,0x52,0xff,0x53,0xff,0x54,0x5f,0x55,0xff,
- 0x56,0xff,0x57,0xff,0x58,0x00,0x59,0x47,0x5a,0x03,0x5b,0x03,0x5d,0x3e,0x5e,0x00,
- 0x80,0x1c,0x83,0x01,0x84,0xa5,0x85,0x10,0x86,0x45,0x87,0x41,0x88,0xf0,0x88,0x00,
- 0x88,0xf0,0x90,0x00,0x91,0x08,0x92,0x00,0x93,0x80,0x94,0x08,0x95,0x00,0x96,0xc0,
- 0x97,0x02,0x98,0x13,0x99,0x00,0x9a,0x38,0x9b,0x01,0x9c,0x80,0x9d,0x02,0x9e,0x06,
- 0x9f,0x01,0xa0,0x01,0xa1,0x00,0xa2,0x00,0xa4,0x80,0xa5,0x36,0xa6,0x36,0xa8,0x67,
- 0xa9,0x04,0xaa,0x00,0xac,0x33,0xad,0x02,0xae,0x00,0xb0,0xcd,0xb1,0x04,0xb2,0xcd,
- 0xb3,0x04,0xb4,0x01,0xb8,0x00,0xb9,0x00,0xba,0x00,0xbb,0x00,0xbc,0x00,0xbd,0x00,
- 0xbe,0x00,0xbf,0x00
-};
-
#define TVNORMS ARRAY_SIZE(tvnorms)
/* supported controls */
@@ -134,65 +127,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
}
};
-/* FIXME: These are specific to saa711x - should be moved to its code */
-static struct v4l2_queryctrl saa711x_qctrl[] = {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = -128,
- .maximum = 127,
- .step = 1,
- .default_value = 0,
- .flags = 0,
- },{
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Contrast",
- .minimum = 0x0,
- .maximum = 0x1f,
- .step = 0x1,
- .default_value = 0x10,
- .flags = 0,
- },{
- .id = V4L2_CID_SATURATION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Saturation",
- .minimum = 0x0,
- .maximum = 0x1f,
- .step = 0x1,
- .default_value = 0x10,
- .flags = 0,
- },{
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Red chroma balance",
- .minimum = -128,
- .maximum = 127,
- .step = 1,
- .default_value = 0,
- .flags = 0,
- },{
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Blue chroma balance",
- .minimum = -128,
- .maximum = 127,
- .step = 1,
- .default_value = 0,
- .flags = 0,
- },{
- .id = V4L2_CID_GAMMA,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gamma",
- .minimum = 0x0,
- .maximum = 0x3f,
- .step = 0x1,
- .default_value = 0x20,
- .flags = 0,
- }
-};
-
static struct usb_driver em28xx_usb_driver;
static DEFINE_MUTEX(em28xx_sysfs_lock);
@@ -211,6 +145,11 @@ static int em28xx_config(struct em28xx *dev)
em28xx_write_regs_req(dev, 0x00, 0x06, "\x40", 1);
/* enable vbi capturing */
+
+/* em28xx_write_regs_req(dev,0x00,0x0e,"\xC0",1); audio register */
+/* em28xx_write_regs_req(dev,0x00,0x0f,"\x80",1); clk register */
+ em28xx_write_regs_req(dev,0x00,0x11,"\x51",1);
+
em28xx_audio_usb_mute(dev, 1);
dev->mute = 1; /* maybe not the right place... */
dev->volume = 0x1f;
@@ -230,22 +169,9 @@ static int em28xx_config(struct em28xx *dev)
static void em28xx_config_i2c(struct em28xx *dev)
{
struct v4l2_frequency f;
- struct video_decoder_init em28xx_vdi = {.data = NULL };
-
-
- /* configure decoder */
- if(dev->model == EM2820_BOARD_MSI_VOX_USB_2){
- em28xx_vdi.data=saa7114_i2c_init;
- em28xx_vdi.len=sizeof(saa7114_i2c_init);
- }
-
-
- em28xx_i2c_call_clients(dev, DECODER_INIT, &em28xx_vdi);
- em28xx_i2c_call_clients(dev, DECODER_SET_INPUT, &dev->ctl_input);
-/* em28xx_i2c_call_clients(dev,DECODER_SET_PICTURE, &dev->vpic); */
-/* em28xx_i2c_call_clients(dev,DECODER_SET_NORM,&dev->tvnorm->id); */
-/* em28xx_i2c_call_clients(dev,DECODER_ENABLE_OUTPUT,&output); */
-/* em28xx_i2c_call_clients(dev,DECODER_DUMP, NULL); */
+ em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL);
+ em28xx_i2c_call_clients(dev, VIDIOC_S_INPUT, &dev->ctl_input);
+ em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
/* configure tuner */
f.tuner = 0;
@@ -285,8 +211,7 @@ static void video_mux(struct em28xx *dev, int index)
dev->ctl_input = index;
dev->ctl_ainput = INPUT(index)->amux;
- em28xx_i2c_call_clients(dev, DECODER_SET_INPUT, &input);
-
+ em28xx_i2c_call_clients(dev, VIDIOC_S_INPUT, &input);
em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,input,dev->ctl_ainput);
@@ -298,11 +223,11 @@ static void video_mux(struct em28xx *dev, int index)
em28xx_audio_source(dev, ainput);
} else {
switch (dev->ctl_ainput) {
- case 0:
- ainput = EM28XX_AUDIO_SRC_TUNER;
- break;
- default:
- ainput = EM28XX_AUDIO_SRC_LINE;
+ case 0:
+ ainput = EM28XX_AUDIO_SRC_TUNER;
+ break;
+ default:
+ ainput = EM28XX_AUDIO_SRC_LINE;
}
em28xx_audio_source(dev, ainput);
}
@@ -323,13 +248,20 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
h = list_entry(list, struct em28xx, devlist);
if (h->vdev->minor == minor) {
dev = h;
+ dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ }
+ if (h->vbi_dev->minor == minor) {
+ dev = h;
+ dev->type = V4L2_BUF_TYPE_VBI_CAPTURE;
}
}
+ if (NULL == dev)
+ return -ENODEV;
filp->private_data=dev;
-
- em28xx_videodbg("users=%d\n", dev->users);
+ em28xx_videodbg("open minor=%d type=%s users=%d\n",
+ minor,v4l2_type_names[dev->type],dev->users);
if (!down_read_trylock(&em28xx_disconnect))
return -ERESTARTSYS;
@@ -340,40 +272,36 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
return -EBUSY;
}
-/* if(dev->vbi_dev->minor == minor){
- dev->type=V4L2_BUF_TYPE_VBI_CAPTURE;
- }*/
- if (dev->vdev->minor == minor) {
- dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- }
-
- init_MUTEX(&dev->fileop_lock); /* to 1 == available */
+ mutex_init(&dev->fileop_lock); /* to 1 == available */
spin_lock_init(&dev->queue_lock);
init_waitqueue_head(&dev->wait_frame);
init_waitqueue_head(&dev->wait_stream);
- down(&dev->lock);
+ mutex_lock(&dev->lock);
- em28xx_set_alternate(dev);
+ if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ em28xx_set_alternate(dev);
- dev->width = norm_maxw(dev);
- dev->height = norm_maxh(dev);
- dev->frame_size = dev->width * dev->height * 2;
- dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
- dev->bytesperline = dev->width * 2;
- dev->hscale = 0;
- dev->vscale = 0;
+ dev->width = norm_maxw(dev);
+ dev->height = norm_maxh(dev);
+ dev->frame_size = dev->width * dev->height * 2;
+ dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
+ dev->bytesperline = dev->width * 2;
+ dev->hscale = 0;
+ dev->vscale = 0;
- em28xx_capture_start(dev, 1);
- em28xx_resolution_set(dev);
+ em28xx_capture_start(dev, 1);
+ em28xx_resolution_set(dev);
- /* device needs to be initialized before isoc transfer */
- video_mux(dev, 0);
+ /* device needs to be initialized before isoc transfer */
+ video_mux(dev, 0);
- /* start the transfer */
- errCode = em28xx_init_isoc(dev);
- if (errCode)
- goto err;
+ /* start the transfer */
+ errCode = em28xx_init_isoc(dev);
+ if (errCode)
+ goto err;
+
+ }
dev->users++;
filp->private_data = dev;
@@ -386,10 +314,8 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
dev->state |= DEV_INITIALIZED;
- video_mux(dev, 0);
-
- err:
- up(&dev->lock);
+err:
+ mutex_unlock(&dev->lock);
up_read(&em28xx_disconnect);
return errCode;
}
@@ -403,14 +329,21 @@ static void em28xx_release_resources(struct em28xx *dev)
{
mutex_lock(&em28xx_sysfs_lock);
- em28xx_info("V4L2 device /dev/video%d deregistered\n",
- dev->vdev->minor);
+ /*FIXME: I2C IR should be disconnected */
+
+ em28xx_info("V4L2 devices /dev/video%d and /dev/vbi%d deregistered\n",
+ dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN,
+ dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
list_del(&dev->devlist);
video_unregister_device(dev->vdev);
-/* video_unregister_device(dev->vbi_dev); */
+ video_unregister_device(dev->vbi_dev);
em28xx_i2c_unregister(dev);
usb_put_dev(dev->udev);
mutex_unlock(&em28xx_sysfs_lock);
+
+
+ /* Mark device as unused */
+ em28xx_devused&=~(1<<dev->devno);
}
/*
@@ -424,7 +357,7 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
em28xx_videodbg("users=%d\n", dev->users);
- down(&dev->lock);
+ mutex_lock(&dev->lock);
em28xx_uninit_isoc(dev);
@@ -433,7 +366,7 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
/* the device is already disconnect, free the remaining resources */
if (dev->state & DEV_DISCONNECTED) {
em28xx_release_resources(dev);
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
kfree(dev);
return 0;
}
@@ -449,7 +382,7 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
dev->users--;
wake_up_interruptible_nr(&dev->open, 1);
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
return 0;
}
@@ -466,32 +399,54 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
int ret = 0;
struct em28xx *dev = filp->private_data;
- if (down_interruptible(&dev->fileop_lock))
+ if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ em28xx_videodbg("V4l2_Buf_type_videocapture is set\n");
+ }
+ if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n");
+ em28xx_videodbg("not supported yet! ...\n");
+ if (copy_to_user(buf, "", 1)) {
+ mutex_unlock(&dev->fileop_lock);
+ return -EFAULT;
+ }
+ return (1);
+ }
+ if (dev->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+ em28xx_videodbg("V4L2_BUF_TYPE_SLICED_VBI_CAPTURE is set\n");
+ em28xx_videodbg("not supported yet! ...\n");
+ if (copy_to_user(buf, "", 1)) {
+ mutex_unlock(&dev->fileop_lock);
+ return -EFAULT;
+ }
+ return (1);
+ }
+
+ if (mutex_lock_interruptible(&dev->fileop_lock))
return -ERESTARTSYS;
if (dev->state & DEV_DISCONNECTED) {
em28xx_videodbg("device not present\n");
- up(&dev->fileop_lock);
+ mutex_unlock(&dev->fileop_lock);
return -ENODEV;
}
if (dev->state & DEV_MISCONFIGURED) {
em28xx_videodbg("device misconfigured; close and open it again\n");
- up(&dev->fileop_lock);
+ mutex_unlock(&dev->fileop_lock);
return -EIO;
}
if (dev->io == IO_MMAP) {
em28xx_videodbg ("IO method is set to mmap; close and open"
" the device again to choose the read method\n");
- up(&dev->fileop_lock);
+ mutex_unlock(&dev->fileop_lock);
return -EINVAL;
}
if (dev->io == IO_NONE) {
if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) {
em28xx_errdev("read failed, not enough memory\n");
- up(&dev->fileop_lock);
+ mutex_unlock(&dev->fileop_lock);
return -ENOMEM;
}
dev->io = IO_READ;
@@ -500,13 +455,13 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
}
if (!count) {
- up(&dev->fileop_lock);
+ mutex_unlock(&dev->fileop_lock);
return 0;
}
if (list_empty(&dev->outqueue)) {
if (filp->f_flags & O_NONBLOCK) {
- up(&dev->fileop_lock);
+ mutex_unlock(&dev->fileop_lock);
return -EAGAIN;
}
ret = wait_event_interruptible
@@ -514,11 +469,11 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
(!list_empty(&dev->outqueue)) ||
(dev->state & DEV_DISCONNECTED));
if (ret) {
- up(&dev->fileop_lock);
+ mutex_unlock(&dev->fileop_lock);
return ret;
}
if (dev->state & DEV_DISCONNECTED) {
- up(&dev->fileop_lock);
+ mutex_unlock(&dev->fileop_lock);
return -ENODEV;
}
}
@@ -537,12 +492,12 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
count = f->buf.length;
if (copy_to_user(buf, f->bufmem, count)) {
- up(&dev->fileop_lock);
+ mutex_unlock(&dev->fileop_lock);
return -EFAULT;
}
*f_pos += count;
- up(&dev->fileop_lock);
+ mutex_unlock(&dev->fileop_lock);
return count;
}
@@ -556,7 +511,7 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
unsigned int mask = 0;
struct em28xx *dev = filp->private_data;
- if (down_interruptible(&dev->fileop_lock))
+ if (mutex_lock_interruptible(&dev->fileop_lock))
return POLLERR;
if (dev->state & DEV_DISCONNECTED) {
@@ -582,13 +537,13 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
if (!list_empty(&dev->outqueue))
mask |= POLLIN | POLLRDNORM;
- up(&dev->fileop_lock);
+ mutex_unlock(&dev->fileop_lock);
return mask;
}
}
- up(&dev->fileop_lock);
+ mutex_unlock(&dev->fileop_lock);
return POLLERR;
}
@@ -628,25 +583,25 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
struct em28xx *dev = filp->private_data;
- if (down_interruptible(&dev->fileop_lock))
+ if (mutex_lock_interruptible(&dev->fileop_lock))
return -ERESTARTSYS;
if (dev->state & DEV_DISCONNECTED) {
em28xx_videodbg("mmap: device not present\n");
- up(&dev->fileop_lock);
+ mutex_unlock(&dev->fileop_lock);
return -ENODEV;
}
if (dev->state & DEV_MISCONFIGURED) {
em28xx_videodbg ("mmap: Device is misconfigured; close and "
"open it again\n");
- up(&dev->fileop_lock);
+ mutex_unlock(&dev->fileop_lock);
return -EIO;
}
if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
size != PAGE_ALIGN(dev->frame[0].buf.length)) {
- up(&dev->fileop_lock);
+ mutex_unlock(&dev->fileop_lock);
return -EINVAL;
}
@@ -656,7 +611,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
}
if (i == dev->num_frames) {
em28xx_videodbg("mmap: user supplied mapping address is out of range\n");
- up(&dev->fileop_lock);
+ mutex_unlock(&dev->fileop_lock);
return -EINVAL;
}
@@ -668,7 +623,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
while (size > 0) { /* size is page-aligned */
if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
em28xx_videodbg("mmap: vm_insert_page failed\n");
- up(&dev->fileop_lock);
+ mutex_unlock(&dev->fileop_lock);
return -EAGAIN;
}
start += PAGE_SIZE;
@@ -680,7 +635,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
vma->vm_private_data = &dev->frame[i];
em28xx_vm_open(vma);
- up(&dev->fileop_lock);
+ mutex_unlock(&dev->fileop_lock);
return 0;
}
@@ -702,43 +657,6 @@ static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
}
}
-/*FIXME: should be moved to saa711x */
-static int saa711x_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
-{
- s32 tmp;
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- if ((tmp = em28xx_brightness_get(dev)) < 0)
- return -EIO;
- ctrl->value = (s32) ((s8) tmp); /* FIXME: clenaer way to extend sign? */
- return 0;
- case V4L2_CID_CONTRAST:
- if ((ctrl->value = em28xx_contrast_get(dev)) < 0)
- return -EIO;
- return 0;
- case V4L2_CID_SATURATION:
- if ((ctrl->value = em28xx_saturation_get(dev)) < 0)
- return -EIO;
- return 0;
- case V4L2_CID_RED_BALANCE:
- if ((tmp = em28xx_v_balance_get(dev)) < 0)
- return -EIO;
- ctrl->value = (s32) ((s8) tmp); /* FIXME: clenaer way to extend sign? */
- return 0;
- case V4L2_CID_BLUE_BALANCE:
- if ((tmp = em28xx_u_balance_get(dev)) < 0)
- return -EIO;
- ctrl->value = (s32) ((s8) tmp); /* FIXME: clenaer way to extend sign? */
- return 0;
- case V4L2_CID_GAMMA:
- if ((ctrl->value = em28xx_gamma_get(dev)) < 0)
- return -EIO;
- return 0;
- default:
- return -EINVAL;
- }
-}
-
/*
* em28xx_set_ctrl()
* mute or set new saturation, brightness or contrast
@@ -761,27 +679,6 @@ static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
}
}
-/*FIXME: should be moved to saa711x */
-static int saa711x_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
-{
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- return em28xx_brightness_set(dev, ctrl->value);
- case V4L2_CID_CONTRAST:
- return em28xx_contrast_set(dev, ctrl->value);
- case V4L2_CID_SATURATION:
- return em28xx_saturation_set(dev, ctrl->value);
- case V4L2_CID_RED_BALANCE:
- return em28xx_v_balance_set(dev, ctrl->value);
- case V4L2_CID_BLUE_BALANCE:
- return em28xx_u_balance_set(dev, ctrl->value);
- case V4L2_CID_GAMMA:
- return em28xx_gamma_set(dev, ctrl->value);
- default:
- return -EINVAL;
- }
-}
-
/*
* em28xx_stream_interrupt()
* stops streaming
@@ -802,7 +699,8 @@ static int em28xx_stream_interrupt(struct em28xx *dev)
else if (ret) {
dev->state |= DEV_MISCONFIGURED;
em28xx_videodbg("device is misconfigured; close and "
- "open /dev/video%d again\n", dev->vdev->minor);
+ "open /dev/video%d again\n",
+ dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN);
return ret;
}
@@ -853,6 +751,181 @@ static int em28xx_set_norm(struct em28xx *dev, int width, int height)
return 0;
}
+static int em28xx_get_fmt(struct em28xx *dev, struct v4l2_format *format)
+{
+ em28xx_videodbg("VIDIOC_G_FMT: type=%s\n",
+ (format->type ==V4L2_BUF_TYPE_VIDEO_CAPTURE) ?
+ "V4L2_BUF_TYPE_VIDEO_CAPTURE" :
+ (format->type ==V4L2_BUF_TYPE_VBI_CAPTURE) ?
+ "V4L2_BUF_TYPE_VBI_CAPTURE" :
+ (format->type ==V4L2_CAP_SLICED_VBI_CAPTURE) ?
+ "V4L2_BUF_TYPE_SLICED_VBI_CAPTURE " :
+ "not supported");
+
+ switch (format->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ {
+ format->fmt.pix.width = dev->width;
+ format->fmt.pix.height = dev->height;
+ format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+ format->fmt.pix.bytesperline = dev->bytesperline;
+ format->fmt.pix.sizeimage = dev->frame_size;
+ format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ format->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
+
+ em28xx_videodbg("VIDIOC_G_FMT: %dx%d\n", dev->width,
+ dev->height);
+ break;
+ }
+
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ {
+ format->fmt.sliced.service_set=0;
+
+ em28xx_i2c_call_clients(dev,VIDIOC_G_FMT,format);
+
+ if (format->fmt.sliced.service_set==0)
+ return -EINVAL;
+
+ break;
+ }
+
+ default:
+ return -EINVAL;
+ }
+ return (0);
+}
+
+static int em28xx_set_fmt(struct em28xx *dev, unsigned int cmd, struct v4l2_format *format)
+{
+ u32 i;
+ int ret = 0;
+ int width = format->fmt.pix.width;
+ int height = format->fmt.pix.height;
+ unsigned int hscale, vscale;
+ unsigned int maxh, maxw;
+
+ maxw = norm_maxw(dev);
+ maxh = norm_maxh(dev);
+
+ em28xx_videodbg("%s: type=%s\n",
+ cmd == VIDIOC_TRY_FMT ?
+ "VIDIOC_TRY_FMT" : "VIDIOC_S_FMT",
+ format->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
+ "V4L2_BUF_TYPE_VIDEO_CAPTURE" :
+ format->type == V4L2_BUF_TYPE_VBI_CAPTURE ?
+ "V4L2_BUF_TYPE_VBI_CAPTURE " :
+ "not supported");
+
+ if (format->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+ em28xx_i2c_call_clients(dev,VIDIOC_G_FMT,format);
+
+ if (format->fmt.sliced.service_set==0)
+ return -EINVAL;
+
+ return 0;
+ }
+
+
+ if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ em28xx_videodbg("%s: requested %dx%d\n",
+ cmd == VIDIOC_TRY_FMT ?
+ "VIDIOC_TRY_FMT" : "VIDIOC_S_FMT",
+ format->fmt.pix.width, format->fmt.pix.height);
+
+ /* FIXME: Move some code away from here */
+ /* width must even because of the YUYV format */
+ /* height must be even because of interlacing */
+ height &= 0xfffe;
+ width &= 0xfffe;
+
+ if (height < 32)
+ height = 32;
+ if (height > maxh)
+ height = maxh;
+ if (width < 48)
+ width = 48;
+ if (width > maxw)
+ width = maxw;
+
+ if(dev->is_em2800){
+ /* the em2800 can only scale down to 50% */
+ if(height % (maxh / 2))
+ height=maxh;
+ if(width % (maxw / 2))
+ width=maxw;
+ /* according to empiatech support */
+ /* the MaxPacketSize is to small to support */
+ /* framesizes larger than 640x480 @ 30 fps */
+ /* or 640x576 @ 25 fps. As this would cut */
+ /* of a part of the image we prefer */
+ /* 360x576 or 360x480 for now */
+ if(width == maxw && height == maxh)
+ width /= 2;
+ }
+
+ if ((hscale = (((unsigned long)maxw) << 12) / width - 4096L) >= 0x4000)
+ hscale = 0x3fff;
+
+ width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
+
+ if ((vscale = (((unsigned long)maxh) << 12) / height - 4096L) >= 0x4000)
+ vscale = 0x3fff;
+
+ height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
+
+ format->fmt.pix.width = width;
+ format->fmt.pix.height = height;
+ format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+ format->fmt.pix.bytesperline = width * 2;
+ format->fmt.pix.sizeimage = width * 2 * height;
+ format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ format->fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+ em28xx_videodbg("%s: returned %dx%d (%d, %d)\n",
+ cmd == VIDIOC_TRY_FMT ?
+ "VIDIOC_TRY_FMT" :"VIDIOC_S_FMT",
+ format->fmt.pix.width, format->fmt.pix.height, hscale, vscale);
+
+ if (cmd == VIDIOC_TRY_FMT)
+ return 0;
+
+ for (i = 0; i < dev->num_frames; i++)
+ if (dev->frame[i].vma_use_count) {
+ em28xx_videodbg("VIDIOC_S_FMT failed. "
+ "Unmap the buffers first.\n");
+ return -EINVAL;
+ }
+
+ /* stop io in case it is already in progress */
+ if (dev->stream == STREAM_ON) {
+ em28xx_videodbg("VIDIOC_SET_FMT: interupting stream\n");
+ if ((ret = em28xx_stream_interrupt(dev)))
+ return ret;
+ }
+
+ em28xx_release_buffers(dev);
+ dev->io = IO_NONE;
+
+ /* set new image size */
+ dev->width = width;
+ dev->height = height;
+ dev->frame_size = dev->width * dev->height * 2;
+ dev->field_size = dev->frame_size >> 1;
+ dev->bytesperline = dev->width * 2;
+ dev->hscale = hscale;
+ dev->vscale = vscale;
+ em28xx_uninit_isoc(dev);
+ em28xx_set_alternate(dev);
+ em28xx_capture_start(dev, 1);
+ em28xx_resolution_set(dev);
+ em28xx_init_isoc(dev);
+
+ return 0;
+}
+
/*
* em28xx_v4l2_do_ioctl()
* This function is _not_ called directly, but from
@@ -868,392 +941,325 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
switch (cmd) {
/* ---------- tv norms ---------- */
case VIDIOC_ENUMSTD:
- {
- struct v4l2_standard *e = arg;
- unsigned int i;
+ {
+ struct v4l2_standard *e = arg;
+ unsigned int i;
- i = e->index;
- if (i >= TVNORMS)
- return -EINVAL;
- ret = v4l2_video_std_construct(e, tvnorms[e->index].id,
- tvnorms[e->index].name);
- e->index = i;
- if (ret < 0)
- return ret;
- return 0;
- }
+ i = e->index;
+ if (i >= TVNORMS)
+ return -EINVAL;
+ ret = v4l2_video_std_construct(e, tvnorms[e->index].id,
+ tvnorms[e->index].name);
+ e->index = i;
+ if (ret < 0)
+ return ret;
+ return 0;
+ }
case VIDIOC_G_STD:
- {
- v4l2_std_id *id = arg;
+ {
+ v4l2_std_id *id = arg;
- *id = dev->tvnorm->id;
- return 0;
- }
+ *id = dev->tvnorm->id;
+ return 0;
+ }
case VIDIOC_S_STD:
- {
- v4l2_std_id *id = arg;
- unsigned int i;
+ {
+ v4l2_std_id *id = arg;
+ unsigned int i;
+ for (i = 0; i < TVNORMS; i++)
+ if (*id == tvnorms[i].id)
+ break;
+ if (i == TVNORMS)
for (i = 0; i < TVNORMS; i++)
- if (*id == tvnorms[i].id)
+ if (*id & tvnorms[i].id)
break;
- if (i == TVNORMS)
- for (i = 0; i < TVNORMS; i++)
- if (*id & tvnorms[i].id)
- break;
- if (i == TVNORMS)
- return -EINVAL;
-
- down(&dev->lock);
- dev->tvnorm = &tvnorms[i];
+ if (i == TVNORMS)
+ return -EINVAL;
- em28xx_set_norm(dev, dev->width, dev->height);
+ mutex_lock(&dev->lock);
+ dev->tvnorm = &tvnorms[i];
-/*
- dev->width=norm_maxw(dev);
- dev->height=norm_maxh(dev);
- dev->frame_size=dev->width*dev->height*2;
- dev->field_size=dev->frame_size>>1;
- dev->bytesperline=dev->width*2;
- dev->hscale=0;
- dev->vscale=0;
+ em28xx_set_norm(dev, dev->width, dev->height);
- em28xx_resolution_set(dev);
-*/
-/*
- em28xx_uninit_isoc(dev);
- em28xx_set_alternate(dev);
- em28xx_capture_start(dev, 1);
- em28xx_resolution_set(dev);
- em28xx_init_isoc(dev);
-*/
- em28xx_i2c_call_clients(dev, DECODER_SET_NORM,
- &tvnorms[i].mode);
- em28xx_i2c_call_clients(dev, VIDIOC_S_STD,
- &dev->tvnorm->id);
+ em28xx_i2c_call_clients(dev, VIDIOC_S_STD,
+ &dev->tvnorm->id);
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
- return 0;
- }
+ return 0;
+ }
- /* ------ input switching ---------- */
+ /* ------ input switching ---------- */
case VIDIOC_ENUMINPUT:
- {
- struct v4l2_input *i = arg;
- unsigned int n;
- static const char *iname[] = {
- [EM28XX_VMUX_COMPOSITE1] = "Composite1",
- [EM28XX_VMUX_COMPOSITE2] = "Composite2",
- [EM28XX_VMUX_COMPOSITE3] = "Composite3",
- [EM28XX_VMUX_COMPOSITE4] = "Composite4",
- [EM28XX_VMUX_SVIDEO] = "S-Video",
- [EM28XX_VMUX_TELEVISION] = "Television",
- [EM28XX_VMUX_CABLE] = "Cable TV",
- [EM28XX_VMUX_DVB] = "DVB",
- [EM28XX_VMUX_DEBUG] = "for debug only",
- };
-
- n = i->index;
- if (n >= MAX_EM28XX_INPUT)
- return -EINVAL;
- if (0 == INPUT(n)->type)
- return -EINVAL;
- memset(i, 0, sizeof(*i));
- i->index = n;
- i->type = V4L2_INPUT_TYPE_CAMERA;
- strcpy(i->name, iname[INPUT(n)->type]);
- if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) ||
- (EM28XX_VMUX_CABLE == INPUT(n)->type))
- i->type = V4L2_INPUT_TYPE_TUNER;
- for (n = 0; n < ARRAY_SIZE(tvnorms); n++)
- i->std |= tvnorms[n].id;
- return 0;
- }
-
+ {
+ struct v4l2_input *i = arg;
+ unsigned int n;
+ static const char *iname[] = {
+ [EM28XX_VMUX_COMPOSITE1] = "Composite1",
+ [EM28XX_VMUX_COMPOSITE2] = "Composite2",
+ [EM28XX_VMUX_COMPOSITE3] = "Composite3",
+ [EM28XX_VMUX_COMPOSITE4] = "Composite4",
+ [EM28XX_VMUX_SVIDEO] = "S-Video",
+ [EM28XX_VMUX_TELEVISION] = "Television",
+ [EM28XX_VMUX_CABLE] = "Cable TV",
+ [EM28XX_VMUX_DVB] = "DVB",
+ [EM28XX_VMUX_DEBUG] = "for debug only",
+ };
+
+ n = i->index;
+ if (n >= MAX_EM28XX_INPUT)
+ return -EINVAL;
+ if (0 == INPUT(n)->type)
+ return -EINVAL;
+ memset(i, 0, sizeof(*i));
+ i->index = n;
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+ strcpy(i->name, iname[INPUT(n)->type]);
+ if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) ||
+ (EM28XX_VMUX_CABLE == INPUT(n)->type))
+ i->type = V4L2_INPUT_TYPE_TUNER;
+ for (n = 0; n < ARRAY_SIZE(tvnorms); n++)
+ i->std |= tvnorms[n].id;
+ return 0;
+ }
case VIDIOC_G_INPUT:
- {
- int *i = arg;
- *i = dev->ctl_input;
-
- return 0;
- }
+ {
+ int *i = arg;
+ *i = dev->ctl_input;
+ return 0;
+ }
case VIDIOC_S_INPUT:
- {
- int *index = arg;
-
- if (*index >= MAX_EM28XX_INPUT)
- return -EINVAL;
- if (0 == INPUT(*index)->type)
- return -EINVAL;
+ {
+ int *index = arg;
- down(&dev->lock);
- video_mux(dev, *index);
- up(&dev->lock);
+ if (*index >= MAX_EM28XX_INPUT)
+ return -EINVAL;
+ if (0 == INPUT(*index)->type)
+ return -EINVAL;
- return 0;
- }
+ mutex_lock(&dev->lock);
+ video_mux(dev, *index);
+ mutex_unlock(&dev->lock);
+ return 0;
+ }
case VIDIOC_G_AUDIO:
- {
- struct v4l2_audio *a = arg;
- unsigned int index = a->index;
+ {
+ struct v4l2_audio *a = arg;
+ unsigned int index = a->index;
- if (a->index > 1)
- return -EINVAL;
- memset(a, 0, sizeof(*a));
- index = dev->ctl_ainput;
+ if (a->index > 1)
+ return -EINVAL;
+ memset(a, 0, sizeof(*a));
+ index = dev->ctl_ainput;
- if (index == 0) {
- strcpy(a->name, "Television");
- } else {
- strcpy(a->name, "Line In");
- }
- a->capability = V4L2_AUDCAP_STEREO;
- a->index = index;
- return 0;
+ if (index == 0) {
+ strcpy(a->name, "Television");
+ } else {
+ strcpy(a->name, "Line In");
}
-
+ a->capability = V4L2_AUDCAP_STEREO;
+ a->index = index;
+ return 0;
+ }
case VIDIOC_S_AUDIO:
- {
- struct v4l2_audio *a = arg;
- if (a->index != dev->ctl_ainput)
- return -EINVAL;
+ {
+ struct v4l2_audio *a = arg;
- return 0;
- }
+ if (a->index != dev->ctl_ainput)
+ return -EINVAL;
- /* --- controls ---------------------------------------------- */
+ return 0;
+ }
+
+ /* --- controls ---------------------------------------------- */
case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *qc = arg;
- int i, id=qc->id;
-
- memset(qc,0,sizeof(*qc));
- qc->id=id;
-
- if (!dev->has_msp34xx) {
- for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
- if (qc->id && qc->id == em28xx_qctrl[i].id) {
- memcpy(qc, &(em28xx_qctrl[i]),
- sizeof(*qc));
- return 0;
- }
- }
- }
- if (dev->decoder == EM28XX_TVP5150) {
- em28xx_i2c_call_clients(dev,cmd,qc);
- if (qc->type)
- return 0;
- else
- return -EINVAL;
- }
- for (i = 0; i < ARRAY_SIZE(saa711x_qctrl); i++) {
- if (qc->id && qc->id == saa711x_qctrl[i].id) {
- memcpy(qc, &(saa711x_qctrl[i]),
- sizeof(*qc));
- return 0;
- }
- }
+ {
+ struct v4l2_queryctrl *qc = arg;
+ int i, id=qc->id;
- return -EINVAL;
- }
+ memset(qc,0,sizeof(*qc));
+ qc->id=id;
- case VIDIOC_G_CTRL:
- {
- struct v4l2_control *ctrl = arg;
- int retval=-EINVAL;
-
- if (!dev->has_msp34xx)
- retval=em28xx_get_ctrl(dev, ctrl);
- if (retval==-EINVAL) {
- if (dev->decoder == EM28XX_TVP5150) {
- em28xx_i2c_call_clients(dev,cmd,arg);
+ if (!dev->has_msp34xx) {
+ for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
+ if (qc->id && qc->id == em28xx_qctrl[i].id) {
+ memcpy(qc, &(em28xx_qctrl[i]),
+ sizeof(*qc));
return 0;
}
-
- return saa711x_get_ctrl(dev, ctrl);
- } else return retval;
+ }
}
+ em28xx_i2c_call_clients(dev,cmd,qc);
+ if (qc->type)
+ return 0;
+ else
+ return -EINVAL;
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+ int retval=-EINVAL;
+ if (!dev->has_msp34xx)
+ retval=em28xx_get_ctrl(dev, ctrl);
+ if (retval==-EINVAL) {
+ em28xx_i2c_call_clients(dev,cmd,arg);
+ return 0;
+ } else return retval;
+ }
case VIDIOC_S_CTRL:
- {
- struct v4l2_control *ctrl = arg;
- u8 i;
-
- if (!dev->has_msp34xx){
- for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
- if (ctrl->id == em28xx_qctrl[i].id) {
- if (ctrl->value <
- em28xx_qctrl[i].minimum
- || ctrl->value >
- em28xx_qctrl[i].maximum)
- return -ERANGE;
- return em28xx_set_ctrl(dev, ctrl);
- }
- }
- }
-
- if (dev->decoder == EM28XX_TVP5150) {
- em28xx_i2c_call_clients(dev,cmd,arg);
- return 0;
- } else if (!dev->has_msp34xx) {
- for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
- if (ctrl->id == em28xx_qctrl[i].id) {
- if (ctrl->value <
- em28xx_qctrl[i].minimum
- || ctrl->value >
- em28xx_qctrl[i].maximum)
- return -ERANGE;
- return em28xx_set_ctrl(dev, ctrl);
- }
- }
- for (i = 0; i < ARRAY_SIZE(saa711x_qctrl); i++) {
- if (ctrl->id == saa711x_qctrl[i].id) {
- if (ctrl->value <
- saa711x_qctrl[i].minimum
- || ctrl->value >
- saa711x_qctrl[i].maximum)
- return -ERANGE;
- return saa711x_set_ctrl(dev, ctrl);
- }
+ {
+ struct v4l2_control *ctrl = arg;
+ u8 i;
+
+ if (!dev->has_msp34xx){
+ for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
+ if (ctrl->id == em28xx_qctrl[i].id) {
+ if (ctrl->value <
+ em28xx_qctrl[i].minimum
+ || ctrl->value >
+ em28xx_qctrl[i].maximum)
+ return -ERANGE;
+ return em28xx_set_ctrl(dev, ctrl);
}
}
-
- return -EINVAL;
}
- /* --- tuner ioctls ------------------------------------------ */
+ em28xx_i2c_call_clients(dev,cmd,arg);
+ return 0;
+ }
+ /* --- tuner ioctls ------------------------------------------ */
case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *t = arg;
- int status = 0;
+ {
+ struct v4l2_tuner *t = arg;
+ int status = 0;
- if (0 != t->index)
- return -EINVAL;
+ if (0 != t->index)
+ return -EINVAL;
- memset(t, 0, sizeof(*t));
- strcpy(t->name, "Tuner");
- t->type = V4L2_TUNER_ANALOG_TV;
- t->capability = V4L2_TUNER_CAP_NORM;
- t->rangehigh = 0xffffffffUL; /* FIXME: set correct range */
+ memset(t, 0, sizeof(*t));
+ strcpy(t->name, "Tuner");
+ t->type = V4L2_TUNER_ANALOG_TV;
+ t->capability = V4L2_TUNER_CAP_NORM;
+ t->rangehigh = 0xffffffffUL; /* FIXME: set correct range */
/* t->signal = 0xffff;*/
/* em28xx_i2c_call_clients(dev,VIDIOC_G_TUNER,t);*/
- /* No way to get signal strength? */
- down(&dev->lock);
- em28xx_i2c_call_clients(dev, DECODER_GET_STATUS,
- &status);
- up(&dev->lock);
- t->signal =
- (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0;
-
- em28xx_videodbg("VIDIO_G_TUNER: signal=%x, afc=%x\n", t->signal,
- t->afc);
- return 0;
- }
+ /* No way to get signal strength? */
+ mutex_lock(&dev->lock);
+ em28xx_i2c_call_clients(dev, DECODER_GET_STATUS,
+ &status);
+ mutex_unlock(&dev->lock);
+ t->signal =
+ (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0;
+
+ em28xx_videodbg("VIDIO_G_TUNER: signal=%x, afc=%x\n", t->signal,
+ t->afc);
+ return 0;
+ }
case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *t = arg;
- int status = 0;
+ {
+ struct v4l2_tuner *t = arg;
+ int status = 0;
- if (0 != t->index)
- return -EINVAL;
- memset(t, 0, sizeof(*t));
- strcpy(t->name, "Tuner");
- t->type = V4L2_TUNER_ANALOG_TV;
- t->capability = V4L2_TUNER_CAP_NORM;
- t->rangehigh = 0xffffffffUL; /* FIXME: set correct range */
+ if (0 != t->index)
+ return -EINVAL;
+ memset(t, 0, sizeof(*t));
+ strcpy(t->name, "Tuner");
+ t->type = V4L2_TUNER_ANALOG_TV;
+ t->capability = V4L2_TUNER_CAP_NORM;
+ t->rangehigh = 0xffffffffUL; /* FIXME: set correct range */
/* t->signal = 0xffff; */
- /* No way to get signal strength? */
- down(&dev->lock);
- em28xx_i2c_call_clients(dev, DECODER_GET_STATUS,
- &status);
- up(&dev->lock);
- t->signal =
- (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0;
-
- em28xx_videodbg("VIDIO_S_TUNER: signal=%x, afc=%x\n",
- t->signal, t->afc);
- return 0;
- }
+ /* No way to get signal strength? */
+ mutex_lock(&dev->lock);
+ em28xx_i2c_call_clients(dev, DECODER_GET_STATUS,
+ &status);
+ mutex_unlock(&dev->lock);
+ t->signal =
+ (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0;
+
+ em28xx_videodbg("VIDIO_S_TUNER: signal=%x, afc=%x\n",
+ t->signal, t->afc);
+ return 0;
+ }
case VIDIOC_G_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
+ {
+ struct v4l2_frequency *f = arg;
- memset(f, 0, sizeof(*f));
- f->type = V4L2_TUNER_ANALOG_TV;
- f->frequency = dev->ctl_freq;
+ memset(f, 0, sizeof(*f));
+ f->type = V4L2_TUNER_ANALOG_TV;
+ f->frequency = dev->ctl_freq;
- return 0;
- }
+ return 0;
+ }
case VIDIOC_S_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
-
- if (0 != f->tuner)
- return -EINVAL;
+ {
+ struct v4l2_frequency *f = arg;
- if (V4L2_TUNER_ANALOG_TV != f->type)
- return -EINVAL;
+ if (0 != f->tuner)
+ return -EINVAL;
- down(&dev->lock);
- dev->ctl_freq = f->frequency;
- em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
- up(&dev->lock);
- return 0;
- }
+ if (V4L2_TUNER_ANALOG_TV != f->type)
+ return -EINVAL;
+ mutex_lock(&dev->lock);
+ dev->ctl_freq = f->frequency;
+ em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
+ mutex_unlock(&dev->lock);
+ return 0;
+ }
case VIDIOC_CROPCAP:
- {
- struct v4l2_cropcap *cc = arg;
+ {
+ struct v4l2_cropcap *cc = arg;
- if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- cc->bounds.left = 0;
- cc->bounds.top = 0;
- cc->bounds.width = dev->width;
- cc->bounds.height = dev->height;
- cc->defrect = cc->bounds;
- cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */
- cc->pixelaspect.denominator = 59;
- return 0;
- }
+ if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ cc->bounds.left = 0;
+ cc->bounds.top = 0;
+ cc->bounds.width = dev->width;
+ cc->bounds.height = dev->height;
+ cc->defrect = cc->bounds;
+ cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */
+ cc->pixelaspect.denominator = 59;
+ return 0;
+ }
case VIDIOC_STREAMON:
- {
- int *type = arg;
+ {
+ int *type = arg;
- if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
- || dev->io != IO_MMAP)
- return -EINVAL;
+ if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+ || dev->io != IO_MMAP)
+ return -EINVAL;
- if (list_empty(&dev->inqueue))
- return -EINVAL;
+ if (list_empty(&dev->inqueue))
+ return -EINVAL;
- dev->stream = STREAM_ON; /* FIXME: Start video capture here? */
+ dev->stream = STREAM_ON; /* FIXME: Start video capture here? */
- em28xx_videodbg("VIDIOC_STREAMON: starting stream\n");
+ em28xx_videodbg("VIDIOC_STREAMON: starting stream\n");
- return 0;
- }
+ return 0;
+ }
case VIDIOC_STREAMOFF:
- {
- int *type = arg;
- int ret;
-
- if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
- || dev->io != IO_MMAP)
- return -EINVAL;
+ {
+ int *type = arg;
+ int ret;
- if (dev->stream == STREAM_ON) {
- em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream\n");
- if ((ret = em28xx_stream_interrupt(dev)))
- return ret;
- }
- em28xx_empty_framequeues(dev);
+ if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+ || dev->io != IO_MMAP)
+ return -EINVAL;
- return 0;
+ if (dev->stream == STREAM_ON) {
+ em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream\n");
+ if ((ret = em28xx_stream_interrupt(dev)))
+ return ret;
}
+ em28xx_empty_framequeues(dev);
+
+ return 0;
+ }
default:
return v4l_compat_translate_ioctl(inode, filp, cmd, arg,
driver_ioctl);
@@ -1283,327 +1289,170 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp,
/* --- capabilities ------------------------------------------ */
case VIDIOC_QUERYCAP:
{
- struct v4l2_capability *cap = arg;
-
- memset(cap, 0, sizeof(*cap));
- strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
- strlcpy(cap->card, em28xx_boards[dev->model].name,
- sizeof(cap->card));
- strlcpy(cap->bus_info, dev->udev->dev.bus_id,
- sizeof(cap->bus_info));
- cap->version = EM28XX_VERSION_CODE;
- cap->capabilities =
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_AUDIO |
- V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
- if (dev->has_tuner)
- cap->capabilities |= V4L2_CAP_TUNER;
- return 0;
- }
-
- /* --- capture ioctls ---------------------------------------- */
+ struct v4l2_capability *cap = arg;
+
+ memset(cap, 0, sizeof(*cap));
+ strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
+ strlcpy(cap->card, em28xx_boards[dev->model].name,
+ sizeof(cap->card));
+ strlcpy(cap->bus_info, dev->udev->dev.bus_id,
+ sizeof(cap->bus_info));
+ cap->version = EM28XX_VERSION_CODE;
+ cap->capabilities =
+ V4L2_CAP_SLICED_VBI_CAPTURE |
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_AUDIO |
+ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ if (dev->has_tuner)
+ cap->capabilities |= V4L2_CAP_TUNER;
+ return 0;
+ }
+ /* --- capture ioctls ---------------------------------------- */
case VIDIOC_ENUM_FMT:
- {
- struct v4l2_fmtdesc *fmtd = arg;
-
- if (fmtd->index != 0)
- return -EINVAL;
- memset(fmtd, 0, sizeof(*fmtd));
- fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- strcpy(fmtd->description, "Packed YUY2");
- fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
- memset(fmtd->reserved, 0, sizeof(fmtd->reserved));
- return 0;
- }
+ {
+ struct v4l2_fmtdesc *fmtd = arg;
+ if (fmtd->index != 0)
+ return -EINVAL;
+ memset(fmtd, 0, sizeof(*fmtd));
+ fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ strcpy(fmtd->description, "Packed YUY2");
+ fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
+ memset(fmtd->reserved, 0, sizeof(fmtd->reserved));
+ return 0;
+ }
case VIDIOC_G_FMT:
- {
- struct v4l2_format *format = arg;
-
- em28xx_videodbg("VIDIOC_G_FMT: type=%s\n",
- format->type ==
- V4L2_BUF_TYPE_VIDEO_CAPTURE ?
- "V4L2_BUF_TYPE_VIDEO_CAPTURE" : format->type ==
- V4L2_BUF_TYPE_VBI_CAPTURE ?
- "V4L2_BUF_TYPE_VBI_CAPTURE " :
- "not supported");
-
- if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- format->fmt.pix.width = dev->width;
- format->fmt.pix.height = dev->height;
- format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
- format->fmt.pix.bytesperline = dev->bytesperline;
- format->fmt.pix.sizeimage = dev->frame_size;
- format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- format->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
-
- em28xx_videodbg("VIDIOC_G_FMT: %dx%d\n", dev->width,
- dev->height);
- return 0;
- }
+ return em28xx_get_fmt(dev, (struct v4l2_format *) arg);
case VIDIOC_TRY_FMT:
case VIDIOC_S_FMT:
- {
- struct v4l2_format *format = arg;
- u32 i;
- int ret = 0;
- int width = format->fmt.pix.width;
- int height = format->fmt.pix.height;
- unsigned int hscale, vscale;
- unsigned int maxh, maxw;
-
- maxw = norm_maxw(dev);
- maxh = norm_maxh(dev);
-
-/* int both_fields; */
-
- em28xx_videodbg("%s: type=%s\n",
- cmd ==
- VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" :
- "VIDIOC_S_FMT",
- format->type ==
- V4L2_BUF_TYPE_VIDEO_CAPTURE ?
- "V4L2_BUF_TYPE_VIDEO_CAPTURE" : format->type ==
- V4L2_BUF_TYPE_VBI_CAPTURE ?
- "V4L2_BUF_TYPE_VBI_CAPTURE " :
- "not supported");
-
- if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- em28xx_videodbg("%s: requested %dx%d\n",
- cmd ==
- VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" :
- "VIDIOC_S_FMT", format->fmt.pix.width,
- format->fmt.pix.height);
-
- /* FIXME: Move some code away from here */
- /* width must even because of the YUYV format */
- /* height must be even because of interlacing */
- height &= 0xfffe;
- width &= 0xfffe;
-
- if (height < 32)
- height = 32;
- if (height > maxh)
- height = maxh;
- if (width < 48)
- width = 48;
- if (width > maxw)
- width = maxw;
-
- if(dev->is_em2800){
- /* the em2800 can only scale down to 50% */
- if(height % (maxh / 2))
- height=maxh;
- if(width % (maxw / 2))
- width=maxw;
- /* according to empiatech support */
- /* the MaxPacketSize is to small to support */
- /* framesizes larger than 640x480 @ 30 fps */
- /* or 640x576 @ 25 fps. As this would cut */
- /* of a part of the image we prefer */
- /* 360x576 or 360x480 for now */
- if(width == maxw && height == maxh)
- width /= 2;
- }
-
- if ((hscale =
- (((unsigned long)maxw) << 12) / width - 4096L) >=
- 0x4000)
- hscale = 0x3fff;
- width =
- (((unsigned long)maxw) << 12) / (hscale + 4096L);
-
- if ((vscale =
- (((unsigned long)maxh) << 12) / height - 4096L) >=
- 0x4000)
- vscale = 0x3fff;
- height =
- (((unsigned long)maxh) << 12) / (vscale + 4096L);
-
- format->fmt.pix.width = width;
- format->fmt.pix.height = height;
- format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
- format->fmt.pix.bytesperline = width * 2;
- format->fmt.pix.sizeimage = width * 2 * height;
- format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- format->fmt.pix.field = V4L2_FIELD_INTERLACED;
-
- em28xx_videodbg("%s: returned %dx%d (%d, %d)\n",
- cmd ==
- VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" :
- "VIDIOC_S_FMT", format->fmt.pix.width,
- format->fmt.pix.height, hscale, vscale);
-
- if (cmd == VIDIOC_TRY_FMT)
- return 0;
-
- for (i = 0; i < dev->num_frames; i++)
- if (dev->frame[i].vma_use_count) {
- em28xx_videodbg("VIDIOC_S_FMT failed. "
- "Unmap the buffers first.\n");
- return -EINVAL;
- }
+ return em28xx_set_fmt(dev, cmd, (struct v4l2_format *)arg);
- /* stop io in case it is already in progress */
- if (dev->stream == STREAM_ON) {
- em28xx_videodbg("VIDIOC_SET_FMT: interupting stream\n");
- if ((ret = em28xx_stream_interrupt(dev)))
- return ret;
- }
+ case VIDIOC_REQBUFS:
+ {
+ struct v4l2_requestbuffers *rb = arg;
+ u32 i;
+ int ret;
- em28xx_release_buffers(dev);
- dev->io = IO_NONE;
-
- /* set new image size */
- dev->width = width;
- dev->height = height;
- dev->frame_size = dev->width * dev->height * 2;
- dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
- dev->bytesperline = dev->width * 2;
- dev->hscale = hscale;
- dev->vscale = vscale;
-/* dev->both_fileds = both_fileds; */
- em28xx_uninit_isoc(dev);
- em28xx_set_alternate(dev);
- em28xx_capture_start(dev, 1);
- em28xx_resolution_set(dev);
- em28xx_init_isoc(dev);
+ if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ rb->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
- return 0;
+ if (dev->io == IO_READ) {
+ em28xx_videodbg ("method is set to read;"
+ " close and open the device again to"
+ " choose the mmap I/O method\n");
+ return -EINVAL;
}
- /* --- streaming capture ------------------------------------- */
- case VIDIOC_REQBUFS:
- {
- struct v4l2_requestbuffers *rb = arg;
- u32 i;
- int ret;
-
- if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- rb->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
-
- if (dev->io == IO_READ) {
- em28xx_videodbg ("method is set to read;"
- " close and open the device again to"
- " choose the mmap I/O method\n");
+ for (i = 0; i < dev->num_frames; i++)
+ if (dev->frame[i].vma_use_count) {
+ em28xx_videodbg ("VIDIOC_REQBUFS failed; previous buffers are still mapped\n");
return -EINVAL;
}
- for (i = 0; i < dev->num_frames; i++)
- if (dev->frame[i].vma_use_count) {
- em28xx_videodbg ("VIDIOC_REQBUFS failed; previous buffers are still mapped\n");
- return -EINVAL;
- }
-
- if (dev->stream == STREAM_ON) {
- em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n");
- if ((ret = em28xx_stream_interrupt(dev)))
- return ret;
- }
-
- em28xx_empty_framequeues(dev);
+ if (dev->stream == STREAM_ON) {
+ em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n");
+ if ((ret = em28xx_stream_interrupt(dev)))
+ return ret;
+ }
- em28xx_release_buffers(dev);
- if (rb->count)
- rb->count =
- em28xx_request_buffers(dev, rb->count);
+ em28xx_empty_framequeues(dev);
- dev->frame_current = NULL;
+ em28xx_release_buffers(dev);
+ if (rb->count)
+ rb->count =
+ em28xx_request_buffers(dev, rb->count);
- em28xx_videodbg ("VIDIOC_REQBUFS: setting io method to mmap: num bufs %i\n",
- rb->count);
- dev->io = rb->count ? IO_MMAP : IO_NONE;
- return 0;
- }
+ dev->frame_current = NULL;
+ em28xx_videodbg ("VIDIOC_REQBUFS: setting io method to mmap: num bufs %i\n",
+ rb->count);
+ dev->io = rb->count ? IO_MMAP : IO_NONE;
+ return 0;
+ }
case VIDIOC_QUERYBUF:
- {
- struct v4l2_buffer *b = arg;
+ {
+ struct v4l2_buffer *b = arg;
- if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- b->index >= dev->num_frames || dev->io != IO_MMAP)
- return -EINVAL;
+ if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ b->index >= dev->num_frames || dev->io != IO_MMAP)
+ return -EINVAL;
- memcpy(b, &dev->frame[b->index].buf, sizeof(*b));
+ memcpy(b, &dev->frame[b->index].buf, sizeof(*b));
- if (dev->frame[b->index].vma_use_count) {
- b->flags |= V4L2_BUF_FLAG_MAPPED;
- }
- if (dev->frame[b->index].state == F_DONE)
- b->flags |= V4L2_BUF_FLAG_DONE;
- else if (dev->frame[b->index].state != F_UNUSED)
- b->flags |= V4L2_BUF_FLAG_QUEUED;
- return 0;
+ if (dev->frame[b->index].vma_use_count) {
+ b->flags |= V4L2_BUF_FLAG_MAPPED;
}
+ if (dev->frame[b->index].state == F_DONE)
+ b->flags |= V4L2_BUF_FLAG_DONE;
+ else if (dev->frame[b->index].state != F_UNUSED)
+ b->flags |= V4L2_BUF_FLAG_QUEUED;
+ return 0;
+ }
case VIDIOC_QBUF:
- {
- struct v4l2_buffer *b = arg;
- unsigned long lock_flags;
+ {
+ struct v4l2_buffer *b = arg;
+ unsigned long lock_flags;
- if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- b->index >= dev->num_frames || dev->io != IO_MMAP) {
- return -EINVAL;
- }
+ if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ b->index >= dev->num_frames || dev->io != IO_MMAP) {
+ return -EINVAL;
+ }
- if (dev->frame[b->index].state != F_UNUSED) {
- return -EAGAIN;
- }
- dev->frame[b->index].state = F_QUEUED;
+ if (dev->frame[b->index].state != F_UNUSED) {
+ return -EAGAIN;
+ }
+ dev->frame[b->index].state = F_QUEUED;
- /* add frame to fifo */
- spin_lock_irqsave(&dev->queue_lock, lock_flags);
- list_add_tail(&dev->frame[b->index].frame,
- &dev->inqueue);
- spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+ /* add frame to fifo */
+ spin_lock_irqsave(&dev->queue_lock, lock_flags);
+ list_add_tail(&dev->frame[b->index].frame,
+ &dev->inqueue);
+ spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
- return 0;
- }
+ return 0;
+ }
case VIDIOC_DQBUF:
- {
- struct v4l2_buffer *b = arg;
- struct em28xx_frame_t *f;
- unsigned long lock_flags;
- int ret = 0;
+ {
+ struct v4l2_buffer *b = arg;
+ struct em28xx_frame_t *f;
+ unsigned long lock_flags;
+ int ret = 0;
- if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
- || dev->io != IO_MMAP)
- return -EINVAL;
+ if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+ || dev->io != IO_MMAP)
+ return -EINVAL;
- if (list_empty(&dev->outqueue)) {
- if (dev->stream == STREAM_OFF)
- return -EINVAL;
- if (filp->f_flags & O_NONBLOCK)
- return -EAGAIN;
- ret = wait_event_interruptible
- (dev->wait_frame,
- (!list_empty(&dev->outqueue)) ||
- (dev->state & DEV_DISCONNECTED));
- if (ret)
- return ret;
- if (dev->state & DEV_DISCONNECTED)
- return -ENODEV;
- }
+ if (list_empty(&dev->outqueue)) {
+ if (dev->stream == STREAM_OFF)
+ return -EINVAL;
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ ret = wait_event_interruptible
+ (dev->wait_frame,
+ (!list_empty(&dev->outqueue)) ||
+ (dev->state & DEV_DISCONNECTED));
+ if (ret)
+ return ret;
+ if (dev->state & DEV_DISCONNECTED)
+ return -ENODEV;
+ }
- spin_lock_irqsave(&dev->queue_lock, lock_flags);
- f = list_entry(dev->outqueue.next,
- struct em28xx_frame_t, frame);
- list_del(dev->outqueue.next);
- spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+ spin_lock_irqsave(&dev->queue_lock, lock_flags);
+ f = list_entry(dev->outqueue.next,
+ struct em28xx_frame_t, frame);
+ list_del(dev->outqueue.next);
+ spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
- f->state = F_UNUSED;
- memcpy(b, &f->buf, sizeof(*b));
+ f->state = F_UNUSED;
+ memcpy(b, &f->buf, sizeof(*b));
- if (f->vma_use_count)
- b->flags |= V4L2_BUF_FLAG_MAPPED;
+ if (f->vma_use_count)
+ b->flags |= V4L2_BUF_FLAG_MAPPED;
- return 0;
- }
+ return 0;
+ }
default:
return em28xx_do_ioctl(inode, filp, dev, cmd, arg,
em28xx_video_do_ioctl);
@@ -1621,25 +1470,25 @@ static int em28xx_v4l2_ioctl(struct inode *inode, struct file *filp,
int ret = 0;
struct em28xx *dev = filp->private_data;
- if (down_interruptible(&dev->fileop_lock))
+ if (mutex_lock_interruptible(&dev->fileop_lock))
return -ERESTARTSYS;
if (dev->state & DEV_DISCONNECTED) {
em28xx_errdev("v4l2 ioctl: device not present\n");
- up(&dev->fileop_lock);
+ mutex_unlock(&dev->fileop_lock);
return -ENODEV;
}
if (dev->state & DEV_MISCONFIGURED) {
em28xx_errdev
("v4l2 ioctl: device is misconfigured; close and open it again\n");
- up(&dev->fileop_lock);
+ mutex_unlock(&dev->fileop_lock);
return -EIO;
}
ret = video_usercopy(inode, filp, cmd, arg, em28xx_video_do_ioctl);
- up(&dev->fileop_lock);
+ mutex_unlock(&dev->fileop_lock);
return ret;
}
@@ -1673,7 +1522,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
dev->udev = udev;
dev->model = model;
- init_MUTEX(&dev->lock);
+ mutex_init(&dev->lock);
init_waitqueue_head(&dev->open);
dev->em28xx_write_regs = em28xx_write_regs;
@@ -1729,10 +1578,11 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
dev->vpic.depth = 16;
dev->vpic.palette = VIDEO_PALETTE_YUV422;
+ em28xx_pre_card_setup(dev);
#ifdef CONFIG_MODULES
/* request some modules */
if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114)
- request_module("saa711x");
+ request_module("saa7115");
if (dev->decoder == EM28XX_TVP5150)
request_module("tvp5150");
if (dev->has_tuner)
@@ -1744,10 +1594,11 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
if (errCode) {
em28xx_errdev("error configuring device\n");
kfree(dev);
+ em28xx_devused&=~(1<<dev->devno);
return -ENOMEM;
}
- down(&dev->lock);
+ mutex_lock(&dev->lock);
/* register i2c bus */
em28xx_i2c_register(dev);
@@ -1757,7 +1608,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
/* configure the device */
em28xx_config_i2c(dev);
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
errCode = em28xx_config(dev);
@@ -1770,9 +1621,30 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
if (NULL == dev->vdev) {
em28xx_errdev("cannot allocate video_device.\n");
kfree(dev);
+ em28xx_devused&=~(1<<dev->devno);
return -ENOMEM;
}
+ dev->vbi_dev = video_device_alloc();
+ if (NULL == dev->vbi_dev) {
+ em28xx_errdev("cannot allocate video_device.\n");
+ kfree(dev->vdev);
+ kfree(dev);
+ em28xx_devused&=~(1<<dev->devno);
+ return -ENOMEM;
+ }
+
+ /* Fills VBI device info */
+ dev->vbi_dev->type = VFL_TYPE_VBI;
+ dev->vbi_dev->hardware = 0;
+ dev->vbi_dev->fops = &em28xx_v4l_fops;
+ dev->vbi_dev->minor = -1;
+ dev->vbi_dev->dev = &dev->udev->dev;
+ dev->vbi_dev->release = video_device_release;
+ snprintf(dev->vbi_dev->name, sizeof(dev->vbi_dev->name), "%s#%d %s",
+ "em28xx",dev->devno,"vbi");
+
+ /* Fills CAPTURE device info */
dev->vdev->type = VID_TYPE_CAPTURE;
if (dev->has_tuner)
dev->vdev->type |= VID_TYPE_TUNER;
@@ -1781,21 +1653,39 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
dev->vdev->minor = -1;
dev->vdev->dev = &dev->udev->dev;
dev->vdev->release = video_device_release;
- snprintf(dev->vdev->name, sizeof(dev->vdev->name), "%s",
- "em28xx video");
+ snprintf(dev->vdev->name, sizeof(dev->vbi_dev->name), "%s#%d %s",
+ "em28xx",dev->devno,"video");
+
list_add_tail(&dev->devlist,&em28xx_devlist);
/* register v4l2 device */
- down(&dev->lock);
- if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1))) {
+ mutex_lock(&dev->lock);
+ if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
+ video_nr[dev->devno]))) {
em28xx_errdev("unable to register video device (error=%i).\n",
retval);
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
list_del(&dev->devlist);
video_device_release(dev->vdev);
kfree(dev);
+ em28xx_devused&=~(1<<dev->devno);
return -ENODEV;
}
+
+ if (video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
+ vbi_nr[dev->devno]) < 0) {
+ printk("unable to register vbi device\n");
+ mutex_unlock(&dev->lock);
+ list_del(&dev->devlist);
+ video_device_release(dev->vbi_dev);
+ video_device_release(dev->vdev);
+ kfree(dev);
+ em28xx_devused&=~(1<<dev->devno);
+ return -ENODEV;
+ } else {
+ printk("registered VBI\n");
+ }
+
if (dev->has_msp34xx) {
/* Send a reset to other chips via gpio */
em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1);
@@ -1806,10 +1696,11 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
}
video_mux(dev, 0);
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
- em28xx_info("V4L2 device registered as /dev/video%d\n",
- dev->vdev->minor);
+ em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n",
+ dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN,
+ dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
return 0;
}
@@ -1831,6 +1722,9 @@ static int em28xx_usb_probe(struct usb_interface *interface,
udev = usb_get_dev(interface_to_usbdev(interface));
ifnum = interface->altsetting[0].desc.bInterfaceNumber;
+ /* Check to see next free device and mark as used */
+ nr=find_first_zero_bit(&em28xx_devused,EM28XX_MAXBOARDS);
+ em28xx_devused|=1<<nr;
/* Don't register audio interfaces */
if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
@@ -1838,6 +1732,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
udev->descriptor.idVendor,udev->descriptor.idProduct,
ifnum,
interface->altsetting[0].desc.bInterfaceClass);
+
+ em28xx_devused&=~(1<<nr);
return -ENODEV;
}
@@ -1852,18 +1748,20 @@ static int em28xx_usb_probe(struct usb_interface *interface,
if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
USB_ENDPOINT_XFER_ISOC) {
em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n");
+ em28xx_devused&=~(1<<nr);
return -ENODEV;
}
if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
em28xx_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n");
+ em28xx_devused&=~(1<<nr);
return -ENODEV;
}
model=id->driver_info;
- nr=interface->minor;
- if (nr>EM28XX_MAXBOARDS) {
+ if (nr >= EM28XX_MAXBOARDS) {
printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS);
+ em28xx_devused&=~(1<<nr);
return -ENOMEM;
}
@@ -1871,19 +1769,24 @@ static int em28xx_usb_probe(struct usb_interface *interface,
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
em28xx_err(DRIVER_NAME ": out of memory!\n");
+ em28xx_devused&=~(1<<nr);
return -ENOMEM;
}
+ snprintf(dev->name, 29, "em28xx #%d", nr);
+ dev->devno=nr;
+
/* compute alternate max packet sizes */
uif = udev->actconfig->interface[0];
dev->num_alt=uif->num_altsetting;
- printk(DRIVER_NAME ": Alternate settings: %i\n",dev->num_alt);
+ em28xx_info("Alternate settings: %i\n",dev->num_alt);
// dev->alt_max_pkt_size = kmalloc(sizeof(*dev->alt_max_pkt_size)*
dev->alt_max_pkt_size = kmalloc(32*
dev->num_alt,GFP_KERNEL);
if (dev->alt_max_pkt_size == NULL) {
- em28xx_err(DRIVER_NAME ": out of memory!\n");
+ em28xx_errdev("out of memory!\n");
+ em28xx_devused&=~(1<<nr);
return -ENOMEM;
}
@@ -1892,27 +1795,26 @@ static int em28xx_usb_probe(struct usb_interface *interface,
wMaxPacketSize);
dev->alt_max_pkt_size[i] =
(tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
- printk(DRIVER_NAME ": Alternate setting %i, max size= %i\n",i,
+ em28xx_info("Alternate setting %i, max size= %i\n",i,
dev->alt_max_pkt_size[i]);
}
- snprintf(dev->name, 29, "em28xx #%d", nr);
-
if ((card[nr]>=0)&&(card[nr]<em28xx_bcount))
model=card[nr];
if ((model==EM2800_BOARD_UNKNOWN)||(model==EM2820_BOARD_UNKNOWN)) {
- printk( "%s: Your board has no eeprom inside it and thus can't\n"
+ em28xx_errdev( "Your board has no eeprom inside it and thus can't\n"
"%s: be autodetected. Please pass card=<n> insmod option to\n"
"%s: workaround that. Redirect complaints to the vendor of\n"
- "%s: the TV card. Best regards,\n"
+ "%s: the TV card. Generic type will be used."
+ "%s: Best regards,\n"
"%s: -- tux\n",
dev->name,dev->name,dev->name,dev->name,dev->name);
- printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
+ em28xx_errdev("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
dev->name);
for (i = 0; i < em28xx_bcount; i++) {
- printk("%s: card=%d -> %s\n",
- dev->name, i, em28xx_boards[i].name);
+ em28xx_errdev(" card=%d -> %s\n", i,
+ em28xx_boards[i].name);
}
}
@@ -1938,15 +1840,12 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
struct em28xx *dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
-/*FIXME: IR should be disconnected */
-
if (!dev)
return;
-
down_write(&em28xx_disconnect);
- down(&dev->lock);
+ mutex_lock(&dev->lock);
em28xx_info("disconnecting %s\n", dev->vdev->name);
@@ -1955,7 +1854,9 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
if (dev->users) {
em28xx_warn
("device /dev/video%d is open! Deregistration and memory "
- "deallocation are deferred on close.\n", dev->vdev->minor);
+ "deallocation are deferred on close.\n",
+ dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN);
+
dev->state |= DEV_MISCONFIGURED;
em28xx_uninit_isoc(dev);
dev->state |= DEV_DISCONNECTED;
@@ -1966,7 +1867,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
em28xx_release_resources(dev);
}
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
if (!dev->users) {
kfree(dev->alt_max_pkt_size);
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index 33de9d846af..e1ddc2f27a2 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -27,6 +27,7 @@
#include <linux/videodev.h>
#include <linux/i2c.h>
+#include <linux/mutex.h>
#include <media/ir-kbd-i2c.h>
/* Boards supported by driver */
@@ -41,6 +42,10 @@
#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7
#define EM2800_BOARD_KWORLD_USB2800 8
#define EM2820_BOARD_PINNACLE_DVC_90 9
+#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 10
+#define EM2880_BOARD_TERRATEC_HYBRID_XS 11
+#define EM2820_BOARD_KWORLD_PVRTV2800RF 12
+#define EM2880_BOARD_TERRATEC_PRODIGY_XS 13
#define UNSET -1
@@ -209,6 +214,7 @@ struct em28xx {
/* generic device properties */
char name[30]; /* name (including minor) of the device */
int model; /* index in the device_data struct */
+ int devno; /* marks the number of this device */
unsigned int is_em2800;
int video_inputs; /* number of video inputs */
struct list_head devlist;
@@ -256,7 +262,7 @@ struct em28xx {
enum em28xx_stream_state stream;
enum em28xx_io_method io;
/* locks */
- struct semaphore lock, fileop_lock;
+ struct mutex lock, fileop_lock;
spinlock_t queue_lock;
struct list_head inqueue, outqueue;
wait_queue_head_t open, wait_frame, wait_stream;
@@ -326,6 +332,7 @@ int em28xx_set_alternate(struct em28xx *dev);
/* Provided by em28xx-cards.c */
extern int em2800_variant_detect(struct usb_device* udev,int model);
+extern void em28xx_pre_card_setup(struct em28xx *dev);
extern void em28xx_card_setup(struct em28xx *dev);
extern struct em28xx_board em28xx_boards[];
extern struct usb_device_id em28xx_id_table[];
diff --git a/drivers/media/video/hexium_gemini.c b/drivers/media/video/hexium_gemini.c
index e7bbeb11553..c7fed340565 100644
--- a/drivers/media/video/hexium_gemini.c
+++ b/drivers/media/video/hexium_gemini.c
@@ -1,9 +1,9 @@
/*
hexium_gemini.c - v4l2 driver for Hexium Gemini frame grabber cards
-
+
Visit http://www.mihu.de/linux/saa7146/ and follow the link
to "hexium" for further details about this card.
-
+
Copyright (C) 2003 Michael Hunold <michael@mihu.de>
This program is free software; you can redistribute it and/or modify
@@ -81,7 +81,7 @@ struct hexium
struct video_device *video_dev;
struct i2c_adapter i2c_adapter;
-
+
int cur_input; /* current input */
v4l2_std_id cur_std; /* current standard */
int cur_bw; /* current black/white status */
@@ -174,7 +174,7 @@ static struct saa7146_standard hexium_standards[] = {
.h_offset = 1, .h_pixels = 720,
.v_max_out = 576, .h_max_out = 768,
}
-};
+};
/* bring hardware to a sane state. this has to be done, just in case someone
wants to capture from this device before it has been properly initialized.
@@ -311,7 +311,7 @@ static int hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
struct saa7146_dev *dev = fh->dev;
struct hexium *hexium = (struct hexium *) dev->ext_priv;
/*
- struct saa7146_vv *vv = dev->vv_data;
+ struct saa7146_vv *vv = dev->vv_data;
*/
switch (cmd) {
case VIDIOC_ENUMINPUT:
diff --git a/drivers/media/video/hexium_orion.c b/drivers/media/video/hexium_orion.c
index aad4a18aafd..137c4736da0 100644
--- a/drivers/media/video/hexium_orion.c
+++ b/drivers/media/video/hexium_orion.c
@@ -3,7 +3,7 @@
Visit http://www.mihu.de/linux/saa7146/ and follow the link
to "hexium" for further details about this card.
-
+
Copyright (C) 2003 Michael Hunold <michael@mihu.de>
This program is free software; you can redistribute it and/or modify
@@ -69,7 +69,7 @@ struct hexium
{
int type;
struct video_device *video_dev;
- struct i2c_adapter i2c_adapter;
+ struct i2c_adapter i2c_adapter;
int cur_input; /* current input */
};
@@ -86,7 +86,7 @@ static u8 hexium_saa7110[53]={
};
static struct {
- struct hexium_data data[8];
+ struct hexium_data data[8];
} hexium_input_select[] = {
{
{ /* cvbs 1 */
@@ -153,7 +153,7 @@ static struct {
{ 0x30, 0x60 },
{ 0x31, 0xB5 }, // ??
{ 0x21, 0x03 },
- }
+ }
}, {
{ /* y/c 1 */
{ 0x06, 0x80 },
@@ -187,7 +187,7 @@ static struct {
{ 0x31, 0x75 },
{ 0x21, 0x21 },
}
-}
+}
};
static struct saa7146_standard hexium_standards[] = {
@@ -207,7 +207,7 @@ static struct saa7146_standard hexium_standards[] = {
.h_offset = 1, .h_pixels = 720,
.v_max_out = 576, .h_max_out = 768,
}
-};
+};
/* this is only called for old HV-PCI6/Orion cards
without eeprom */
@@ -272,7 +272,7 @@ static int hexium_probe(struct saa7146_dev *dev)
return 0;
}
- /* check if this is an old hexium Orion card by looking at
+ /* check if this is an old hexium Orion card by looking at
a saa7110 at address 0x4e */
if (0 == (err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, &data))) {
printk("hexium_orion: device is a Hexium HV-PCI6/Orion (old).\n");
@@ -314,7 +314,7 @@ static int hexium_set_input(struct hexium *hexium, int input)
{
union i2c_smbus_data data;
int i = 0;
-
+
DEB_D((".\n"));
for (i = 0; i < 8; i++) {
@@ -375,7 +375,7 @@ static int hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
struct saa7146_dev *dev = fh->dev;
struct hexium *hexium = (struct hexium *) dev->ext_priv;
/*
- struct saa7146_vv *vv = dev->vv_data;
+ struct saa7146_vv *vv = dev->vv_data;
*/
switch (cmd) {
case VIDIOC_ENUMINPUT:
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 58b0e698282..95bacf43541 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -44,51 +44,17 @@
#include <media/ir-common.h>
#include <media/ir-kbd-i2c.h>
-/* Mark Phalan <phalanm@o2.ie> */
-static IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE] = {
- [ 0 ] = KEY_KP0,
- [ 1 ] = KEY_KP1,
- [ 2 ] = KEY_KP2,
- [ 3 ] = KEY_KP3,
- [ 4 ] = KEY_KP4,
- [ 5 ] = KEY_KP5,
- [ 6 ] = KEY_KP6,
- [ 7 ] = KEY_KP7,
- [ 8 ] = KEY_KP8,
- [ 9 ] = KEY_KP9,
-
- [ 18 ] = KEY_POWER,
- [ 16 ] = KEY_MUTE,
- [ 31 ] = KEY_VOLUMEDOWN,
- [ 27 ] = KEY_VOLUMEUP,
- [ 26 ] = KEY_CHANNELUP,
- [ 30 ] = KEY_CHANNELDOWN,
- [ 14 ] = KEY_PAGEUP,
- [ 29 ] = KEY_PAGEDOWN,
- [ 19 ] = KEY_SOUND,
-
- [ 24 ] = KEY_KPPLUSMINUS, /* CH +/- */
- [ 22 ] = KEY_SUBTITLE, /* CC */
- [ 13 ] = KEY_TEXT, /* TTX */
- [ 11 ] = KEY_TV, /* AIR/CBL */
- [ 17 ] = KEY_PC, /* PC/TV */
- [ 23 ] = KEY_OK, /* CH RTN */
- [ 25 ] = KEY_MODE, /* FUNC */
- [ 12 ] = KEY_SEARCH, /* AUTOSCAN */
-
- /* Not sure what to do with these ones! */
- [ 15 ] = KEY_SELECT, /* SOURCE */
- [ 10 ] = KEY_KPPLUS, /* +100 */
- [ 20 ] = KEY_KPEQUAL, /* SYNC */
- [ 28 ] = KEY_MEDIA, /* PC/TV */
-};
-
/* ----------------------------------------------------------------------- */
/* insmod parameters */
static int debug;
module_param(debug, int, 0644); /* debug level (0,1,2) */
+static int hauppauge = 0;
+module_param(hauppauge, int, 0644); /* Choose Hauppauge remote */
+MODULE_PARM_DESC(hauppauge, "Specify Hauppauge remote: 0=black, 1=grey (defaults to 0)");
+
+
#define DEVNAME "ir-kbd-i2c"
#define dprintk(level, fmt, arg...) if (debug >= level) \
printk(KERN_DEBUG DEVNAME ": " fmt , ## arg)
@@ -336,7 +302,11 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
name = "Hauppauge";
ir->get_key = get_key_haup;
ir_type = IR_TYPE_RC5;
- ir_codes = ir_codes_rc5_tv;
+ if (hauppauge == 1) {
+ ir_codes = ir_codes_hauppauge_new;
+ } else {
+ ir_codes = ir_codes_rc5_tv;
+ }
break;
case 0x30:
name = "KNC One";
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index 2869464aee0..850bee97090 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -925,7 +925,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
if (p->palette != VIDEO_PALETTE_YUV422)
return -EINVAL;
- down(&meye.lock);
+ mutex_lock(&meye.lock);
sonypi_camera_command(SONYPI_COMMAND_SETCAMERABRIGHTNESS,
p->brightness >> 10);
sonypi_camera_command(SONYPI_COMMAND_SETCAMERAHUE,
@@ -935,7 +935,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
sonypi_camera_command(SONYPI_COMMAND_SETCAMERACONTRAST,
p->contrast >> 10);
meye.picture = *p;
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
break;
}
@@ -946,21 +946,21 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
if (*i < 0 || *i >= gbuffers)
return -EINVAL;
- down(&meye.lock);
+ mutex_lock(&meye.lock);
switch (meye.grab_buffer[*i].state) {
case MEYE_BUF_UNUSED:
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
return -EINVAL;
case MEYE_BUF_USING:
if (file->f_flags & O_NONBLOCK) {
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
return -EAGAIN;
}
if (wait_event_interruptible(meye.proc_list,
(meye.grab_buffer[*i].state != MEYE_BUF_USING))) {
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
return -EINTR;
}
/* fall through */
@@ -968,7 +968,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
meye.grab_buffer[*i].state = MEYE_BUF_UNUSED;
kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int));
}
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
break;
}
@@ -987,7 +987,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
if (meye.grab_buffer[vm->frame].state != MEYE_BUF_UNUSED)
return -EBUSY;
- down(&meye.lock);
+ mutex_lock(&meye.lock);
if (vm->width == 640 && vm->height == 480) {
if (meye.params.subsample) {
meye.params.subsample = 0;
@@ -999,7 +999,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
restart = 1;
}
} else {
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
return -EINVAL;
}
@@ -1007,7 +1007,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
mchip_continuous_start();
meye.grab_buffer[vm->frame].state = MEYE_BUF_USING;
kfifo_put(meye.grabq, (unsigned char *)&vm->frame, sizeof(int));
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
break;
}
@@ -1039,7 +1039,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
if (jp->framerate > 31)
return -EINVAL;
- down(&meye.lock);
+ mutex_lock(&meye.lock);
if (meye.params.subsample != jp->subsample ||
meye.params.quality != jp->quality)
mchip_hic_stop(); /* need restart */
@@ -1050,7 +1050,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
meye.params.agc);
sonypi_camera_command(SONYPI_COMMAND_SETCAMERAPICTURE,
meye.params.picture);
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
break;
}
@@ -1068,12 +1068,12 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
}
if (meye.grab_buffer[*nb].state != MEYE_BUF_UNUSED)
return -EBUSY;
- down(&meye.lock);
+ mutex_lock(&meye.lock);
if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP)
mchip_cont_compression_start();
meye.grab_buffer[*nb].state = MEYE_BUF_USING;
kfifo_put(meye.grabq, (unsigned char *)nb, sizeof(int));
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
break;
}
@@ -1084,20 +1084,20 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
if (*i < 0 || *i >= gbuffers)
return -EINVAL;
- down(&meye.lock);
+ mutex_lock(&meye.lock);
switch (meye.grab_buffer[*i].state) {
case MEYE_BUF_UNUSED:
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
return -EINVAL;
case MEYE_BUF_USING:
if (file->f_flags & O_NONBLOCK) {
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
return -EAGAIN;
}
if (wait_event_interruptible(meye.proc_list,
(meye.grab_buffer[*i].state != MEYE_BUF_USING))) {
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
return -EINTR;
}
/* fall through */
@@ -1106,7 +1106,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int));
}
*i = meye.grab_buffer[*i].size;
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
break;
}
@@ -1116,14 +1116,14 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
return -EBUSY;
- down(&meye.lock);
+ mutex_lock(&meye.lock);
meye.grab_buffer[0].state = MEYE_BUF_USING;
mchip_take_picture();
mchip_get_picture(
meye.grab_fbuffer,
mchip_hsize() * mchip_vsize() * 2);
meye.grab_buffer[0].state = MEYE_BUF_DONE;
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
break;
}
@@ -1134,7 +1134,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
return -EBUSY;
- down(&meye.lock);
+ mutex_lock(&meye.lock);
meye.grab_buffer[0].state = MEYE_BUF_USING;
*len = -1;
while (*len == -1) {
@@ -1142,7 +1142,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
*len = mchip_compress_frame(meye.grab_fbuffer, gbufsize);
}
meye.grab_buffer[0].state = MEYE_BUF_DONE;
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
break;
}
@@ -1285,7 +1285,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_S_CTRL: {
struct v4l2_control *c = arg;
- down(&meye.lock);
+ mutex_lock(&meye.lock);
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
sonypi_camera_command(
@@ -1329,17 +1329,17 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
meye.params.framerate = c->value;
break;
default:
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
return -EINVAL;
}
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
break;
}
case VIDIOC_G_CTRL: {
struct v4l2_control *c = arg;
- down(&meye.lock);
+ mutex_lock(&meye.lock);
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
c->value = meye.picture.brightness >> 10;
@@ -1369,10 +1369,10 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
c->value = meye.params.framerate;
break;
default:
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
return -EINVAL;
}
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
break;
}
@@ -1469,7 +1469,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
f->fmt.pix.field != V4L2_FIELD_NONE)
return -EINVAL;
f->fmt.pix.field = V4L2_FIELD_NONE;
- down(&meye.lock);
+ mutex_lock(&meye.lock);
if (f->fmt.pix.width <= 320) {
f->fmt.pix.width = 320;
f->fmt.pix.height = 240;
@@ -1487,7 +1487,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP;
break;
}
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
f->fmt.pix.sizeimage = f->fmt.pix.height *
f->fmt.pix.bytesperline;
@@ -1509,11 +1509,11 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
/* already allocated, no modifications */
break;
}
- down(&meye.lock);
+ mutex_lock(&meye.lock);
if (meye.grab_fbuffer) {
for (i = 0; i < gbuffers; i++)
if (meye.vma_use_count[i]) {
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
return -EINVAL;
}
rvfree(meye.grab_fbuffer, gbuffers * gbufsize);
@@ -1525,12 +1525,12 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
if (!meye.grab_fbuffer) {
printk(KERN_ERR "meye: v4l framebuffer allocation"
" failed\n");
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
return -ENOMEM;
}
for (i = 0; i < gbuffers; i++)
meye.vma_use_count[i] = 0;
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
break;
}
@@ -1569,12 +1569,12 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
if (meye.grab_buffer[buf->index].state != MEYE_BUF_UNUSED)
return -EINVAL;
- down(&meye.lock);
+ mutex_lock(&meye.lock);
buf->flags |= V4L2_BUF_FLAG_QUEUED;
buf->flags &= ~V4L2_BUF_FLAG_DONE;
meye.grab_buffer[buf->index].state = MEYE_BUF_USING;
kfifo_put(meye.grabq, (unsigned char *)&buf->index, sizeof(int));
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
break;
}
@@ -1587,23 +1587,23 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
if (buf->memory != V4L2_MEMORY_MMAP)
return -EINVAL;
- down(&meye.lock);
+ mutex_lock(&meye.lock);
if (kfifo_len(meye.doneq) == 0 && file->f_flags & O_NONBLOCK) {
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
return -EAGAIN;
}
if (wait_event_interruptible(meye.proc_list,
kfifo_len(meye.doneq) != 0) < 0) {
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
return -EINTR;
}
if (!kfifo_get(meye.doneq, (unsigned char *)&reqnr,
sizeof(int))) {
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
return -EBUSY;
}
if (meye.grab_buffer[reqnr].state != MEYE_BUF_DONE) {
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
return -EINVAL;
}
buf->index = reqnr;
@@ -1616,12 +1616,12 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
buf->m.offset = reqnr * gbufsize;
buf->length = gbufsize;
meye.grab_buffer[reqnr].state = MEYE_BUF_UNUSED;
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
break;
}
case VIDIOC_STREAMON: {
- down(&meye.lock);
+ mutex_lock(&meye.lock);
switch (meye.mchip_mode) {
case MCHIP_HIC_MODE_CONT_OUT:
mchip_continuous_start();
@@ -1630,23 +1630,23 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
mchip_cont_compression_start();
break;
default:
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
return -EINVAL;
}
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
break;
}
case VIDIOC_STREAMOFF: {
int i;
- down(&meye.lock);
+ mutex_lock(&meye.lock);
mchip_hic_stop();
kfifo_reset(meye.grabq);
kfifo_reset(meye.doneq);
for (i = 0; i < MEYE_MAX_BUFNBRS; i++)
meye.grab_buffer[i].state = MEYE_BUF_UNUSED;
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
break;
}
@@ -1672,11 +1672,11 @@ static unsigned int meye_poll(struct file *file, poll_table *wait)
{
unsigned int res = 0;
- down(&meye.lock);
+ mutex_lock(&meye.lock);
poll_wait(file, &meye.proc_list, wait);
if (kfifo_len(meye.doneq))
res = POLLIN | POLLRDNORM;
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
return res;
}
@@ -1704,9 +1704,9 @@ static int meye_mmap(struct file *file, struct vm_area_struct *vma)
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
unsigned long page, pos;
- down(&meye.lock);
+ mutex_lock(&meye.lock);
if (size > gbuffers * gbufsize) {
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
return -EINVAL;
}
if (!meye.grab_fbuffer) {
@@ -1716,7 +1716,7 @@ static int meye_mmap(struct file *file, struct vm_area_struct *vma)
meye.grab_fbuffer = rvmalloc(gbuffers*gbufsize);
if (!meye.grab_fbuffer) {
printk(KERN_ERR "meye: v4l framebuffer allocation failed\n");
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
return -ENOMEM;
}
for (i = 0; i < gbuffers; i++)
@@ -1727,7 +1727,7 @@ static int meye_mmap(struct file *file, struct vm_area_struct *vma)
while (size > 0) {
page = vmalloc_to_pfn((void *)pos);
if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
return -EAGAIN;
}
start += PAGE_SIZE;
@@ -1744,7 +1744,7 @@ static int meye_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_private_data = (void *) (offset / gbufsize);
meye_vm_open(vma);
- up(&meye.lock);
+ mutex_unlock(&meye.lock);
return 0;
}
@@ -1913,7 +1913,7 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
goto outvideoreg;
}
- init_MUTEX(&meye.lock);
+ mutex_init(&meye.lock);
init_waitqueue_head(&meye.proc_list);
meye.picture.depth = 16;
meye.picture.palette = VIDEO_PALETTE_YUV422;
diff --git a/drivers/media/video/meye.h b/drivers/media/video/meye.h
index e8cd897b0d2..0d09a0e3803 100644
--- a/drivers/media/video/meye.h
+++ b/drivers/media/video/meye.h
@@ -260,6 +260,8 @@
/* private API definitions */
#include <linux/meye.h>
+#include <linux/mutex.h>
+
/* Enable jpg software correction */
#define MEYE_JPEG_CORRECTION 1
@@ -301,7 +303,7 @@ struct meye {
/* list of buffers */
struct meye_grab_buffer grab_buffer[MEYE_MAX_BUFNBRS];
int vma_use_count[MEYE_MAX_BUFNBRS]; /* mmap count */
- struct semaphore lock; /* semaphore for open/mmap... */
+ struct mutex lock; /* mutex for open/mmap... */
struct kfifo *grabq; /* queue for buffers to be grabbed */
spinlock_t grabq_lock; /* lock protecting the queue */
struct kfifo *doneq; /* queue for grabbed buffers */
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index 69ed369c2f4..11ea9765769 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -411,9 +411,9 @@ static int msp_mode_v4l2_to_v4l1(int rxsubchans)
if (rxsubchans & V4L2_TUNER_SUB_STEREO)
mode |= VIDEO_SOUND_STEREO;
if (rxsubchans & V4L2_TUNER_SUB_LANG2)
- mode |= VIDEO_SOUND_LANG2;
+ mode |= VIDEO_SOUND_LANG2 | VIDEO_SOUND_STEREO;
if (rxsubchans & V4L2_TUNER_SUB_LANG1)
- mode |= VIDEO_SOUND_LANG1;
+ mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_STEREO;
if (mode == 0)
mode |= VIDEO_SOUND_MONO;
return mode;
@@ -430,21 +430,6 @@ static int msp_mode_v4l1_to_v4l2(int mode)
return V4L2_TUNER_MODE_MONO;
}
-static void msp_any_detect_stereo(struct i2c_client *client)
-{
- struct msp_state *state = i2c_get_clientdata(client);
-
- switch (state->opmode) {
- case OPMODE_MANUAL:
- case OPMODE_AUTODETECT:
- autodetect_stereo(client);
- break;
- case OPMODE_AUTOSELECT:
- msp34xxg_detect_stereo(client);
- break;
- }
-}
-
static struct v4l2_queryctrl msp_qctrl_std[] = {
{
.id = V4L2_CID_AUDIO_VOLUME,
@@ -506,22 +491,6 @@ static struct v4l2_queryctrl msp_qctrl_sound_processing[] = {
};
-static void msp_any_set_audmode(struct i2c_client *client, int audmode)
-{
- struct msp_state *state = i2c_get_clientdata(client);
-
- switch (state->opmode) {
- case OPMODE_MANUAL:
- case OPMODE_AUTODETECT:
- state->watch_stereo = 0;
- msp3400c_setstereo(client, audmode);
- break;
- case OPMODE_AUTOSELECT:
- msp34xxg_set_audmode(client, audmode);
- break;
- }
-}
-
static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
{
struct msp_state *state = i2c_get_clientdata(client);
@@ -653,11 +622,10 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
}
if (scart) {
state->rxsubchans = V4L2_TUNER_SUB_STEREO;
- state->audmode = V4L2_TUNER_MODE_STEREO;
msp_set_scart(client, scart, 0);
msp_write_dsp(client, 0x000d, 0x1900);
if (state->opmode != OPMODE_AUTOSELECT)
- msp3400c_setstereo(client, state->audmode);
+ msp_set_audmode(client);
}
msp_wake_thread(client);
break;
@@ -671,8 +639,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
switch (state->opmode) {
case OPMODE_MANUAL:
/* set msp3400 to FM radio mode */
- msp3400c_setmode(client, MSP_MODE_FM_RADIO);
- msp3400c_setcarrier(client, MSP_CARRIER(10.7),
+ msp3400c_set_mode(client, MSP_MODE_FM_RADIO);
+ msp3400c_set_carrier(client, MSP_CARRIER(10.7),
MSP_CARRIER(10.7));
msp_set_audio(client);
break;
@@ -706,7 +674,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
if (state->radio)
break;
if (state->opmode == OPMODE_AUTOSELECT)
- msp_any_detect_stereo(client);
+ msp_detect_stereo(client);
va->mode = msp_mode_v4l2_to_v4l1(state->rxsubchans);
break;
}
@@ -722,8 +690,9 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
state->treble = va->treble;
msp_set_audio(client);
- if (va->mode != 0 && state->radio == 0)
- msp_any_set_audmode(client, msp_mode_v4l1_to_v4l2(va->mode));
+ if (va->mode != 0 && state->radio == 0) {
+ state->audmode = msp_mode_v4l1_to_v4l2(va->mode);
+ }
break;
}
@@ -831,11 +800,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
return -EINVAL;
}
- msp_any_detect_stereo(client);
- if (state->audmode == V4L2_TUNER_MODE_STEREO) {
- a->capability = V4L2_AUDCAP_STEREO;
- }
-
+ a->capability = V4L2_AUDCAP_STEREO;
+ a->mode = 0; /* TODO: add support for AVL */
break;
}
@@ -865,16 +831,10 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
}
if (scart) {
state->rxsubchans = V4L2_TUNER_SUB_STEREO;
- state->audmode = V4L2_TUNER_MODE_STEREO;
msp_set_scart(client, scart, 0);
msp_write_dsp(client, 0x000d, 0x1900);
}
- if (sarg->capability == V4L2_AUDCAP_STEREO) {
- state->audmode = V4L2_TUNER_MODE_STEREO;
- } else {
- state->audmode &= ~V4L2_TUNER_MODE_STEREO;
- }
- msp_any_set_audmode(client, state->audmode);
+ msp_set_audmode(client);
msp_wake_thread(client);
break;
}
@@ -886,7 +846,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
if (state->radio)
break;
if (state->opmode == OPMODE_AUTOSELECT)
- msp_any_detect_stereo(client);
+ msp_detect_stereo(client);
vt->audmode = state->audmode;
vt->rxsubchans = state->rxsubchans;
vt->capability = V4L2_TUNER_CAP_STEREO |
@@ -898,11 +858,11 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
- if (state->radio)
+ if (state->radio) /* TODO: add mono/stereo support for radio */
break;
+ state->audmode = vt->audmode;
/* only set audmode */
- if (vt->audmode != -1 && vt->audmode != 0)
- msp_any_set_audmode(client, vt->audmode);
+ msp_set_audmode(client);
break;
}
@@ -927,7 +887,6 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
return -EINVAL;
}
break;
-
}
case VIDIOC_S_AUDOUT:
@@ -993,7 +952,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
const char *p;
if (state->opmode == OPMODE_AUTOSELECT)
- msp_any_detect_stereo(client);
+ msp_detect_stereo(client);
v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n",
client->name, state->rev1, state->rev2);
v4l_info(client, "Audio: volume %d%s\n",
@@ -1094,6 +1053,7 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
memset(state, 0, sizeof(*state));
state->v4l2_std = V4L2_STD_NTSC;
+ state->audmode = V4L2_TUNER_MODE_LANG1;
state->volume = 58880; /* 0db gain */
state->balance = 32768; /* 0db gain */
state->bass = 32768;
diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c
index 2072c3efebb..852ab6a115f 100644
--- a/drivers/media/video/msp3400-kthreads.c
+++ b/drivers/media/video/msp3400-kthreads.c
@@ -109,7 +109,7 @@ static struct msp3400c_init_data_dem {
{-2, -8, -10, 10, 50, 86},
{-4, -12, -9, 23, 79, 126},
MSP_CARRIER(6.5), MSP_CARRIER(6.5),
- 0x00c6, 0x0140, 0x0120, 0x7c03
+ 0x00c6, 0x0140, 0x0120, 0x7c00
},
};
@@ -154,54 +154,60 @@ const char *msp_standard_std_name(int std)
return "unknown";
}
-void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2)
+static void msp_set_source(struct i2c_client *client, u16 src)
+{
+ struct msp_state *state = i2c_get_clientdata(client);
+
+ if (msp_dolby) {
+ msp_write_dsp(client, 0x0008, 0x0520); /* I2S1 */
+ msp_write_dsp(client, 0x0009, 0x0620); /* I2S2 */
+ } else {
+ msp_write_dsp(client, 0x0008, src);
+ msp_write_dsp(client, 0x0009, src);
+ }
+ msp_write_dsp(client, 0x000a, src);
+ msp_write_dsp(client, 0x000b, src);
+ msp_write_dsp(client, 0x000c, src);
+ if (state->has_scart23_in_scart2_out)
+ msp_write_dsp(client, 0x0041, src);
+}
+
+void msp3400c_set_carrier(struct i2c_client *client, int cdo1, int cdo2)
{
msp_write_dem(client, 0x0093, cdo1 & 0xfff);
msp_write_dem(client, 0x009b, cdo1 >> 12);
msp_write_dem(client, 0x00a3, cdo2 & 0xfff);
msp_write_dem(client, 0x00ab, cdo2 >> 12);
- msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/
+ msp_write_dem(client, 0x0056, 0); /* LOAD_REG_1/2 */
}
-void msp3400c_setmode(struct i2c_client *client, int type)
+void msp3400c_set_mode(struct i2c_client *client, int mode)
{
struct msp_state *state = i2c_get_clientdata(client);
+ struct msp3400c_init_data_dem *data = &msp3400c_init_data[mode];
int i;
- v4l_dbg(1, msp_debug, client, "setmode: %d\n", type);
- state->mode = type;
- state->audmode = V4L2_TUNER_MODE_MONO;
+ v4l_dbg(1, msp_debug, client, "set_mode: %d\n", mode);
+ state->mode = mode;
state->rxsubchans = V4L2_TUNER_SUB_MONO;
- msp_write_dem(client, 0x00bb, msp3400c_init_data[type].ad_cv);
+ msp_write_dem(client, 0x00bb, data->ad_cv);
for (i = 5; i >= 0; i--) /* fir 1 */
- msp_write_dem(client, 0x0001, msp3400c_init_data[type].fir1[i]);
+ msp_write_dem(client, 0x0001, data->fir1[i]);
msp_write_dem(client, 0x0005, 0x0004); /* fir 2 */
msp_write_dem(client, 0x0005, 0x0040);
msp_write_dem(client, 0x0005, 0x0000);
for (i = 5; i >= 0; i--)
- msp_write_dem(client, 0x0005, msp3400c_init_data[type].fir2[i]);
+ msp_write_dem(client, 0x0005, data->fir2[i]);
- msp_write_dem(client, 0x0083, msp3400c_init_data[type].mode_reg);
+ msp_write_dem(client, 0x0083, data->mode_reg);
- msp3400c_setcarrier(client, msp3400c_init_data[type].cdo1,
- msp3400c_init_data[type].cdo2);
+ msp3400c_set_carrier(client, data->cdo1, data->cdo2);
- msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/
-
- if (msp_dolby) {
- msp_write_dsp(client, 0x0008, 0x0520); /* I2S1 */
- msp_write_dsp(client, 0x0009, 0x0620); /* I2S2 */
- msp_write_dsp(client, 0x000b, msp3400c_init_data[type].dsp_src);
- } else {
- msp_write_dsp(client, 0x0008, msp3400c_init_data[type].dsp_src);
- msp_write_dsp(client, 0x0009, msp3400c_init_data[type].dsp_src);
- msp_write_dsp(client, 0x000b, msp3400c_init_data[type].dsp_src);
- }
- msp_write_dsp(client, 0x000a, msp3400c_init_data[type].dsp_src);
- msp_write_dsp(client, 0x000e, msp3400c_init_data[type].dsp_matrix);
+ msp_set_source(client, data->dsp_src);
+ msp_write_dsp(client, 0x000e, data->dsp_matrix);
if (state->has_nicam) {
/* nicam prescale */
@@ -209,29 +215,31 @@ void msp3400c_setmode(struct i2c_client *client, int type)
}
}
-/* turn on/off nicam + stereo */
-void msp3400c_setstereo(struct i2c_client *client, int mode)
+/* Set audio mode. Note that the pre-'G' models do not support BTSC+SAP,
+ nor do they support stereo BTSC. */
+static void msp3400c_set_audmode(struct i2c_client *client)
{
static char *strmode[] = { "mono", "stereo", "lang2", "lang1" };
struct msp_state *state = i2c_get_clientdata(client);
- int nicam = 0; /* channel source: FM/AM or nicam */
- int src = 0;
+ char *modestr = (state->audmode >= 0 && state->audmode < 4) ?
+ strmode[state->audmode] : "unknown";
+ int src = 0; /* channel source: FM/AM, nicam or SCART */
if (state->opmode == OPMODE_AUTOSELECT) {
/* this method would break everything, let's make sure
* it's never called
*/
- v4l_dbg(1, msp_debug, client, "setstereo called with mode=%d instead of set_source (ignored)\n",
- mode);
+ v4l_dbg(1, msp_debug, client,
+ "set_audmode called with mode=%d instead of set_source (ignored)\n",
+ state->audmode);
return;
}
/* switch demodulator */
switch (state->mode) {
case MSP_MODE_FM_TERRA:
- v4l_dbg(1, msp_debug, client, "FM setstereo: %s\n", strmode[mode]);
- msp3400c_setcarrier(client, state->second, state->main);
- switch (mode) {
+ v4l_dbg(1, msp_debug, client, "FM set_audmode: %s\n", modestr);
+ switch (state->audmode) {
case V4L2_TUNER_MODE_STEREO:
msp_write_dsp(client, 0x000e, 0x3001);
break;
@@ -243,50 +251,49 @@ void msp3400c_setstereo(struct i2c_client *client, int mode)
}
break;
case MSP_MODE_FM_SAT:
- v4l_dbg(1, msp_debug, client, "SAT setstereo: %s\n", strmode[mode]);
- switch (mode) {
+ v4l_dbg(1, msp_debug, client, "SAT set_audmode: %s\n", modestr);
+ switch (state->audmode) {
case V4L2_TUNER_MODE_MONO:
- msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
+ msp3400c_set_carrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
break;
case V4L2_TUNER_MODE_STEREO:
- msp3400c_setcarrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02));
+ msp3400c_set_carrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02));
break;
case V4L2_TUNER_MODE_LANG1:
- msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
+ msp3400c_set_carrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
break;
case V4L2_TUNER_MODE_LANG2:
- msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
+ msp3400c_set_carrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
break;
}
break;
case MSP_MODE_FM_NICAM1:
case MSP_MODE_FM_NICAM2:
case MSP_MODE_AM_NICAM:
- v4l_dbg(1, msp_debug, client, "NICAM setstereo: %s\n",strmode[mode]);
- msp3400c_setcarrier(client,state->second,state->main);
+ v4l_dbg(1, msp_debug, client, "NICAM set_audmode: %s\n",modestr);
+ msp3400c_set_carrier(client, state->second, state->main);
if (state->nicam_on)
- nicam=0x0100;
+ src = 0x0100; /* NICAM */
break;
case MSP_MODE_BTSC:
- v4l_dbg(1, msp_debug, client, "BTSC setstereo: %s\n",strmode[mode]);
- nicam=0x0300;
+ v4l_dbg(1, msp_debug, client, "BTSC set_audmode: %s\n",modestr);
break;
case MSP_MODE_EXTERN:
- v4l_dbg(1, msp_debug, client, "extern setstereo: %s\n",strmode[mode]);
- nicam = 0x0200;
+ v4l_dbg(1, msp_debug, client, "extern set_audmode: %s\n",modestr);
+ src = 0x0200; /* SCART */
break;
case MSP_MODE_FM_RADIO:
- v4l_dbg(1, msp_debug, client, "FM-Radio setstereo: %s\n",strmode[mode]);
+ v4l_dbg(1, msp_debug, client, "FM-Radio set_audmode: %s\n",modestr);
break;
default:
- v4l_dbg(1, msp_debug, client, "mono setstereo\n");
+ v4l_dbg(1, msp_debug, client, "mono set_audmode\n");
return;
}
/* switch audio */
- switch (mode) {
+ switch (state->audmode) {
case V4L2_TUNER_MODE_STEREO:
- src = 0x0020 | nicam;
+ src |= 0x0020;
break;
case V4L2_TUNER_MODE_MONO:
if (state->mode == MSP_MODE_AM_NICAM) {
@@ -297,29 +304,22 @@ void msp3400c_setstereo(struct i2c_client *client, int mode)
src = 0x0200;
break;
}
+ if (state->rxsubchans & V4L2_TUNER_SUB_STEREO)
+ src = 0x0030;
+ break;
case V4L2_TUNER_MODE_LANG1:
- src = 0x0000 | nicam;
+ /* switch to stereo for stereo transmission, otherwise
+ keep first language */
+ if (state->rxsubchans & V4L2_TUNER_SUB_STEREO)
+ src |= 0x0020;
break;
case V4L2_TUNER_MODE_LANG2:
- src = 0x0010 | nicam;
+ src |= 0x0010;
break;
}
- v4l_dbg(1, msp_debug, client, "setstereo final source/matrix = 0x%x\n", src);
+ v4l_dbg(1, msp_debug, client, "set_audmode final source/matrix = 0x%x\n", src);
- if (msp_dolby) {
- msp_write_dsp(client, 0x0008, 0x0520);
- msp_write_dsp(client, 0x0009, 0x0620);
- msp_write_dsp(client, 0x000a, src);
- msp_write_dsp(client, 0x000b, src);
- } else {
- msp_write_dsp(client, 0x0008, src);
- msp_write_dsp(client, 0x0009, src);
- msp_write_dsp(client, 0x000a, src);
- msp_write_dsp(client, 0x000b, src);
- msp_write_dsp(client, 0x000c, src);
- if (state->has_scart23_in_scart2_out)
- msp_write_dsp(client, 0x0041, src);
- }
+ msp_set_source(client, src);
}
static void msp3400c_print_mode(struct i2c_client *client)
@@ -347,12 +347,12 @@ static void msp3400c_print_mode(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
-int autodetect_stereo(struct i2c_client *client)
+static int msp3400c_detect_stereo(struct i2c_client *client)
{
struct msp_state *state = i2c_get_clientdata(client);
int val;
int rxsubchans = state->rxsubchans;
- int newnicam = state->nicam_on;
+ int newnicam = state->nicam_on;
int update = 0;
switch (state->mode) {
@@ -362,7 +362,7 @@ int autodetect_stereo(struct i2c_client *client)
val -= 65536;
v4l_dbg(2, msp_debug, client, "stereo detect register: %d\n", val);
if (val > 4096) {
- rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
+ rxsubchans = V4L2_TUNER_SUB_STEREO;
} else if (val < -4096) {
rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
} else {
@@ -386,14 +386,11 @@ int autodetect_stereo(struct i2c_client *client)
break;
case 1:
case 9:
- rxsubchans = V4L2_TUNER_SUB_MONO
- | V4L2_TUNER_SUB_LANG1;
+ rxsubchans = V4L2_TUNER_SUB_MONO;
break;
case 2:
case 10:
- rxsubchans = V4L2_TUNER_SUB_MONO
- | V4L2_TUNER_SUB_LANG1
- | V4L2_TUNER_SUB_LANG2;
+ rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
break;
default:
rxsubchans = V4L2_TUNER_SUB_MONO;
@@ -405,30 +402,17 @@ int autodetect_stereo(struct i2c_client *client)
rxsubchans = V4L2_TUNER_SUB_MONO;
}
break;
- case MSP_MODE_BTSC:
- val = msp_read_dem(client, 0x200);
- v4l_dbg(2, msp_debug, client, "status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
- val,
- (val & 0x0002) ? "no" : "yes",
- (val & 0x0004) ? "no" : "yes",
- (val & 0x0040) ? "stereo" : "mono",
- (val & 0x0080) ? ", nicam 2nd mono" : "",
- (val & 0x0100) ? ", bilingual/SAP" : "");
- rxsubchans = V4L2_TUNER_SUB_MONO;
- if (val & 0x0040) rxsubchans |= V4L2_TUNER_SUB_STEREO;
- if (val & 0x0100) rxsubchans |= V4L2_TUNER_SUB_LANG1;
- break;
}
if (rxsubchans != state->rxsubchans) {
update = 1;
- v4l_dbg(1, msp_debug, client, "watch: rxsubchans %d => %d\n",
- state->rxsubchans,rxsubchans);
+ v4l_dbg(1, msp_debug, client, "watch: rxsubchans %02x => %02x\n",
+ state->rxsubchans, rxsubchans);
state->rxsubchans = rxsubchans;
}
if (newnicam != state->nicam_on) {
update = 1;
v4l_dbg(1, msp_debug, client, "watch: nicam %d => %d\n",
- state->nicam_on,newnicam);
+ state->nicam_on, newnicam);
state->nicam_on = newnicam;
}
return update;
@@ -443,13 +427,8 @@ static void watch_stereo(struct i2c_client *client)
{
struct msp_state *state = i2c_get_clientdata(client);
- if (autodetect_stereo(client)) {
- if (state->rxsubchans & V4L2_TUNER_SUB_STEREO)
- msp3400c_setstereo(client, V4L2_TUNER_MODE_STEREO);
- else if (state->rxsubchans & V4L2_TUNER_SUB_LANG1)
- msp3400c_setstereo(client, V4L2_TUNER_MODE_LANG1);
- else
- msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+ if (msp3400c_detect_stereo(client)) {
+ msp3400c_set_audmode(client);
}
if (msp_once)
@@ -461,7 +440,7 @@ int msp3400c_thread(void *data)
struct i2c_client *client = data;
struct msp_state *state = i2c_get_clientdata(client);
struct msp3400c_carrier_detect *cd;
- int count, max1,max2,val1,val2, val,this;
+ int count, max1, max2, val1, val2, val, this;
v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n");
@@ -471,7 +450,7 @@ int msp3400c_thread(void *data)
v4l_dbg(2, msp_debug, client, "msp3400 thread: wakeup\n");
restart:
- v4l_dbg(1, msp_debug, client, "thread: restart scan\n");
+ v4l_dbg(2, msp_debug, client, "thread: restart scan\n");
state->restart = 0;
if (kthread_should_stop())
break;
@@ -485,13 +464,14 @@ int msp3400c_thread(void *data)
/* mute */
msp_set_mute(client);
- msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ );
+ msp3400c_set_mode(client, MSP_MODE_AM_DETECT /* +1 */ );
val1 = val2 = 0;
max1 = max2 = -1;
state->watch_stereo = 0;
+ state->nicam_on = 0;
/* some time for the tuner to sync */
- if (msp_sleep(state,200))
+ if (msp_sleep(state, 200))
goto restart;
/* carrier detect pass #1 -- main carrier */
@@ -506,7 +486,7 @@ int msp3400c_thread(void *data)
}
for (this = 0; this < count; this++) {
- msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
+ msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo);
if (msp_sleep(state,100))
goto restart;
val = msp_read_dsp(client, 0x1b);
@@ -542,7 +522,7 @@ int msp3400c_thread(void *data)
max2 = 0;
}
for (this = 0; this < count; this++) {
- msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
+ msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo);
if (msp_sleep(state,100))
goto restart;
val = msp_read_dsp(client, 0x1b);
@@ -554,22 +534,20 @@ int msp3400c_thread(void *data)
}
/* program the msp3400 according to the results */
- state->main = msp3400c_carrier_detect_main[max1].cdo;
+ state->main = msp3400c_carrier_detect_main[max1].cdo;
switch (max1) {
case 1: /* 5.5 */
if (max2 == 0) {
/* B/G FM-stereo */
state->second = msp3400c_carrier_detect_55[max2].cdo;
- msp3400c_setmode(client, MSP_MODE_FM_TERRA);
- state->nicam_on = 0;
- msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+ msp3400c_set_mode(client, MSP_MODE_FM_TERRA);
state->watch_stereo = 1;
} else if (max2 == 1 && state->has_nicam) {
/* B/G NICAM */
state->second = msp3400c_carrier_detect_55[max2].cdo;
- msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
+ msp3400c_set_mode(client, MSP_MODE_FM_NICAM1);
+ msp3400c_set_carrier(client, state->second, state->main);
state->nicam_on = 1;
- msp3400c_setcarrier(client, state->second, state->main);
state->watch_stereo = 1;
} else {
goto no_second;
@@ -578,35 +556,31 @@ int msp3400c_thread(void *data)
case 2: /* 6.0 */
/* PAL I NICAM */
state->second = MSP_CARRIER(6.552);
- msp3400c_setmode(client, MSP_MODE_FM_NICAM2);
+ msp3400c_set_mode(client, MSP_MODE_FM_NICAM2);
+ msp3400c_set_carrier(client, state->second, state->main);
state->nicam_on = 1;
- msp3400c_setcarrier(client, state->second, state->main);
state->watch_stereo = 1;
break;
case 3: /* 6.5 */
if (max2 == 1 || max2 == 2) {
/* D/K FM-stereo */
state->second = msp3400c_carrier_detect_65[max2].cdo;
- msp3400c_setmode(client, MSP_MODE_FM_TERRA);
- state->nicam_on = 0;
- msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+ msp3400c_set_mode(client, MSP_MODE_FM_TERRA);
state->watch_stereo = 1;
} else if (max2 == 0 && (state->v4l2_std & V4L2_STD_SECAM)) {
/* L NICAM or AM-mono */
state->second = msp3400c_carrier_detect_65[max2].cdo;
- msp3400c_setmode(client, MSP_MODE_AM_NICAM);
- state->nicam_on = 0;
- msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
- msp3400c_setcarrier(client, state->second, state->main);
+ msp3400c_set_mode(client, MSP_MODE_AM_NICAM);
+ msp3400c_set_carrier(client, state->second, state->main);
/* volume prescale for SCART (AM mono input) */
msp_write_dsp(client, 0x000d, 0x1900);
state->watch_stereo = 1;
} else if (max2 == 0 && state->has_nicam) {
/* D/K NICAM */
state->second = msp3400c_carrier_detect_65[max2].cdo;
- msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
+ msp3400c_set_mode(client, MSP_MODE_FM_NICAM1);
+ msp3400c_set_carrier(client, state->second, state->main);
state->nicam_on = 1;
- msp3400c_setcarrier(client, state->second, state->main);
state->watch_stereo = 1;
} else {
goto no_second;
@@ -616,23 +590,25 @@ int msp3400c_thread(void *data)
default:
no_second:
state->second = msp3400c_carrier_detect_main[max1].cdo;
- msp3400c_setmode(client, MSP_MODE_FM_TERRA);
- state->nicam_on = 0;
- msp3400c_setcarrier(client, state->second, state->main);
+ msp3400c_set_mode(client, MSP_MODE_FM_TERRA);
+ msp3400c_set_carrier(client, state->second, state->main);
state->rxsubchans = V4L2_TUNER_SUB_MONO;
- msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
break;
}
/* unmute */
msp_set_audio(client);
+ msp3400c_set_audmode(client);
if (msp_debug)
msp3400c_print_mode(client);
- /* monitor tv audio mode */
+ /* monitor tv audio mode, the first time don't wait
+ so long to get a quick stereo/bilingual result */
+ if (msp_sleep(state, 1000))
+ goto restart;
while (state->watch_stereo) {
- if (msp_sleep(state,5000))
+ if (msp_sleep(state, 5000))
goto restart;
watch_stereo(client);
}
@@ -656,7 +632,7 @@ int msp3410d_thread(void *data)
v4l_dbg(2, msp_debug, client, "msp3410 thread: wakeup\n");
restart:
- v4l_dbg(1, msp_debug, client, "thread: restart scan\n");
+ v4l_dbg(2, msp_debug, client, "thread: restart scan\n");
state->restart = 0;
if (kthread_should_stop())
break;
@@ -681,9 +657,10 @@ int msp3410d_thread(void *data)
else
std = (state->v4l2_std & V4L2_STD_NTSC) ? 0x20 : 1;
state->watch_stereo = 0;
+ state->nicam_on = 0;
if (msp_debug)
- v4l_dbg(1, msp_debug, client, "setting standard: %s (0x%04x)\n",
+ v4l_dbg(2, msp_debug, client, "setting standard: %s (0x%04x)\n",
msp_standard_std_name(std), std);
if (std != 1) {
@@ -700,7 +677,7 @@ int msp3410d_thread(void *data)
val = msp_read_dem(client, 0x7e);
if (val < 0x07ff)
break;
- v4l_dbg(1, msp_debug, client, "detection still in progress\n");
+ v4l_dbg(2, msp_debug, client, "detection still in progress\n");
}
}
for (i = 0; msp_stdlist[i].name != NULL; i++)
@@ -739,48 +716,34 @@ int msp3410d_thread(void *data)
state->rxsubchans = V4L2_TUNER_SUB_STEREO;
state->nicam_on = 1;
state->watch_stereo = 1;
- msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
break;
case 0x0009:
state->mode = MSP_MODE_AM_NICAM;
state->rxsubchans = V4L2_TUNER_SUB_MONO;
state->nicam_on = 1;
- msp3400c_setstereo(client,V4L2_TUNER_MODE_MONO);
state->watch_stereo = 1;
break;
case 0x0020: /* BTSC */
- /* just turn on stereo */
+ /* The pre-'G' models only have BTSC-mono */
state->mode = MSP_MODE_BTSC;
- state->rxsubchans = V4L2_TUNER_SUB_STEREO;
- state->nicam_on = 0;
- state->watch_stereo = 1;
- msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
+ state->rxsubchans = V4L2_TUNER_SUB_MONO;
break;
case 0x0040: /* FM radio */
state->mode = MSP_MODE_FM_RADIO;
state->rxsubchans = V4L2_TUNER_SUB_STEREO;
- state->audmode = V4L2_TUNER_MODE_STEREO;
- state->nicam_on = 0;
- state->watch_stereo = 0;
/* not needed in theory if we have radio, but
short programming enables carrier mute */
- msp3400c_setmode(client, MSP_MODE_FM_RADIO);
- msp3400c_setcarrier(client, MSP_CARRIER(10.7),
+ msp3400c_set_mode(client, MSP_MODE_FM_RADIO);
+ msp3400c_set_carrier(client, MSP_CARRIER(10.7),
MSP_CARRIER(10.7));
- /* scart routing */
+ /* scart routing (this doesn't belong here I think) */
msp_set_scart(client,SCART_IN2,0);
- /* msp34xx does radio decoding */
- msp_write_dsp(client, 0x08, 0x0020);
- msp_write_dsp(client, 0x09, 0x0020);
- msp_write_dsp(client, 0x0b, 0x0020);
break;
case 0x0003:
case 0x0004:
case 0x0005:
state->mode = MSP_MODE_FM_TERRA;
state->rxsubchans = V4L2_TUNER_SUB_MONO;
- state->audmode = V4L2_TUNER_MODE_MONO;
- state->nicam_on = 0;
state->watch_stereo = 1;
break;
}
@@ -791,11 +754,16 @@ int msp3410d_thread(void *data)
if (state->has_i2s_conf)
msp_write_dem(client, 0x40, state->i2s_mode);
- /* monitor tv audio mode */
+ msp3400c_set_audmode(client);
+
+ /* monitor tv audio mode, the first time don't wait
+ so long to get a quick stereo/bilingual result */
+ if (msp_sleep(state, 1000))
+ goto restart;
while (state->watch_stereo) {
- if (msp_sleep(state,5000))
- goto restart;
watch_stereo(client);
+ if (msp_sleep(state, 5000))
+ goto restart;
}
}
v4l_dbg(1, msp_debug, client, "thread: exit\n");
@@ -813,7 +781,7 @@ int msp3410d_thread(void *data)
* the value for source is the same as bit 15:8 of DSP registers 0x08,
* 0x0a and 0x0c: 0=mono, 1=stereo or A|B, 2=SCART, 3=stereo or A, 4=stereo or B
*
- * this function replaces msp3400c_setstereo
+ * this function replaces msp3400c_set_audmode
*/
static void msp34xxg_set_source(struct i2c_client *client, int source)
{
@@ -826,12 +794,7 @@ static void msp34xxg_set_source(struct i2c_client *client, int source)
int value = (source & 0x07) << 8 | (source == 0 ? 0x30 : 0x20);
v4l_dbg(1, msp_debug, client, "set source to %d (0x%x)\n", source, value);
- /* Loudspeaker Output */
- msp_write_dsp(client, 0x08, value);
- /* SCART1 DA Output */
- msp_write_dsp(client, 0x0a, value);
- /* Quasi-peak detector */
- msp_write_dsp(client, 0x0c, value);
+ msp_set_source(client, value);
/*
* set identification threshold. Personally, I
* I set it to a higher value that the default
@@ -948,13 +911,14 @@ int msp34xxg_thread(void *data)
if (msp_write_dsp(client, 0x13, state->acb))
return -1;
- msp_write_dem(client, 0x40, state->i2s_mode);
+ if (state->has_i2s_conf)
+ msp_write_dem(client, 0x40, state->i2s_mode);
}
v4l_dbg(1, msp_debug, client, "thread: exit\n");
return 0;
}
-void msp34xxg_detect_stereo(struct i2c_client *client)
+static void msp34xxg_detect_stereo(struct i2c_client *client)
{
struct msp_state *state = i2c_get_clientdata(client);
@@ -964,11 +928,11 @@ void msp34xxg_detect_stereo(struct i2c_client *client)
state->rxsubchans = 0;
if (is_stereo)
- state->rxsubchans |= V4L2_TUNER_SUB_STEREO;
+ state->rxsubchans = V4L2_TUNER_SUB_STEREO;
else
- state->rxsubchans |= V4L2_TUNER_SUB_MONO;
+ state->rxsubchans = V4L2_TUNER_SUB_MONO;
if (is_bilingual) {
- state->rxsubchans |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+ state->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
/* I'm supposed to check whether it's SAP or not
* and set only LANG2/SAP in this case. Yet, the MSP
* does a lot of work to hide this and handle everything
@@ -980,12 +944,12 @@ void msp34xxg_detect_stereo(struct i2c_client *client)
status, is_stereo, is_bilingual, state->rxsubchans);
}
-void msp34xxg_set_audmode(struct i2c_client *client, int audmode)
+static void msp34xxg_set_audmode(struct i2c_client *client)
{
struct msp_state *state = i2c_get_clientdata(client);
int source;
- switch (audmode) {
+ switch (state->audmode) {
case V4L2_TUNER_MODE_MONO:
source = 0; /* mono only */
break;
@@ -1000,11 +964,40 @@ void msp34xxg_set_audmode(struct i2c_client *client, int audmode)
source = 4; /* stereo or B */
break;
default:
- audmode = 0;
source = 1;
break;
}
- state->audmode = audmode;
msp34xxg_set_source(client, source);
}
+void msp_set_audmode(struct i2c_client *client)
+{
+ struct msp_state *state = i2c_get_clientdata(client);
+
+ switch (state->opmode) {
+ case OPMODE_MANUAL:
+ case OPMODE_AUTODETECT:
+ state->watch_stereo = 0;
+ msp3400c_set_audmode(client);
+ break;
+ case OPMODE_AUTOSELECT:
+ msp34xxg_set_audmode(client);
+ break;
+ }
+}
+
+void msp_detect_stereo(struct i2c_client *client)
+{
+ struct msp_state *state = i2c_get_clientdata(client);
+
+ switch (state->opmode) {
+ case OPMODE_MANUAL:
+ case OPMODE_AUTODETECT:
+ msp3400c_detect_stereo(client);
+ break;
+ case OPMODE_AUTOSELECT:
+ msp34xxg_detect_stereo(client);
+ break;
+ }
+}
+
diff --git a/drivers/media/video/msp3400.h b/drivers/media/video/msp3400.h
index a9ac57d0700..6fb5c8c994e 100644
--- a/drivers/media/video/msp3400.h
+++ b/drivers/media/video/msp3400.h
@@ -104,14 +104,12 @@ int msp_sleep(struct msp_state *state, int timeout);
/* msp3400-kthreads.c */
const char *msp_standard_std_name(int std);
-void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2);
-void msp3400c_setmode(struct i2c_client *client, int type);
-void msp3400c_setstereo(struct i2c_client *client, int mode);
-int autodetect_stereo(struct i2c_client *client);
+void msp_set_audmode(struct i2c_client *client);
+void msp_detect_stereo(struct i2c_client *client);
int msp3400c_thread(void *data);
int msp3410d_thread(void *data);
int msp34xxg_thread(void *data);
-void msp34xxg_detect_stereo(struct i2c_client *client);
-void msp34xxg_set_audmode(struct i2c_client *client, int audmode);
+void msp3400c_set_mode(struct i2c_client *client, int mode);
+void msp3400c_set_carrier(struct i2c_client *client, int cdo1, int cdo2);
#endif /* MSP3400_H */
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index 41715cacf92..eb3b3186749 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -1,11 +1,11 @@
/*
mxb - v4l2 driver for the Multimedia eXtension Board
-
+
Copyright (C) 1998-2006 Michael Hunold <michael@mihu.de>
Visit http://www.mihu.de/linux/saa7146/mxb/
for further details about this card.
-
+
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
@@ -35,12 +35,12 @@
#define I2C_SAA7111 0x24
-#define MXB_BOARD_CAN_DO_VBI(dev) (dev->revision != 0)
+#define MXB_BOARD_CAN_DO_VBI(dev) (dev->revision != 0)
/* global variable */
static int mxb_num = 0;
-/* initial frequence the tuner will be tuned to.
+/* initial frequence the tuner will be tuned to.
in verden (lower saxony, germany) 4148 is a
channel called "phoenix" */
static int freq = 4148;
@@ -55,7 +55,7 @@ MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
enum { TUNER, AUX1, AUX3, AUX3_YC };
static struct v4l2_input mxb_inputs[MXB_INPUTS] = {
- { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
+ { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
{ AUX1, "AUX1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
{ AUX3, "AUX3 Composite", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
{ AUX3_YC, "AUX3 S-Video", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
@@ -66,7 +66,7 @@ static struct v4l2_input mxb_inputs[MXB_INPUTS] = {
static struct {
int hps_source;
int hps_sync;
-} input_port_selection[MXB_INPUTS] = {
+} input_port_selection[MXB_INPUTS] = {
{ SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
{ SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
{ SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
@@ -81,7 +81,7 @@ static int video_audio_connect[MXB_INPUTS] =
/* these are the necessary input-output-pins for bringing one audio source
(see above) to the CD-output */
static struct tea6420_multiplex TEA6420_cd[MXB_AUDIOS+1][2] =
- {
+ {
{{1,1,0},{1,1,0}}, /* Tuner */
{{5,1,0},{6,1,0}}, /* AUX 1 */
{{4,1,0},{6,1,0}}, /* AUX 2 */
@@ -122,8 +122,8 @@ static struct saa7146_extension_ioctls ioctls[] = {
{ VIDIOC_S_FREQUENCY, SAA7146_EXCLUSIVE },
{ VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE },
{ VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE },
- { MXB_S_AUDIO_CD, SAA7146_EXCLUSIVE }, /* custom control */
- { MXB_S_AUDIO_LINE, SAA7146_EXCLUSIVE }, /* custom control */
+ { MXB_S_AUDIO_CD, SAA7146_EXCLUSIVE }, /* custom control */
+ { MXB_S_AUDIO_LINE, SAA7146_EXCLUSIVE }, /* custom control */
{ 0, 0 }
};
@@ -132,7 +132,7 @@ struct mxb
struct video_device *video_dev;
struct video_device *vbi_dev;
- struct i2c_adapter i2c_adapter;
+ struct i2c_adapter i2c_adapter;
struct i2c_client* saa7111a;
struct i2c_client* tda9840;
@@ -200,15 +200,15 @@ static int mxb_probe(struct saa7146_dev* dev)
client = list_entry(item, struct i2c_client, list);
if( I2C_TEA6420_1 == client->addr )
mxb->tea6420_1 = client;
- if( I2C_TEA6420_2 == client->addr )
+ if( I2C_TEA6420_2 == client->addr )
mxb->tea6420_2 = client;
- if( I2C_TEA6415C_2 == client->addr )
+ if( I2C_TEA6415C_2 == client->addr )
mxb->tea6415c = client;
- if( I2C_TDA9840 == client->addr )
+ if( I2C_TDA9840 == client->addr )
mxb->tda9840 = client;
if( I2C_SAA7111 == client->addr )
mxb->saa7111a = client;
- if( 0x60 == client->addr )
+ if( 0x60 == client->addr )
mxb->tuner = client;
}
@@ -222,7 +222,7 @@ static int mxb_probe(struct saa7146_dev* dev)
return -ENODEV;
}
- /* all devices are present, probe was successful */
+ /* all devices are present, probe was successful */
/* we store the pointer in our private data field */
dev->ext_priv = mxb;
@@ -230,7 +230,7 @@ static int mxb_probe(struct saa7146_dev* dev)
return 0;
}
-/* some init data for the saa7740, the so-called 'sound arena module'.
+/* some init data for the saa7740, the so-called 'sound arena module'.
there are no specs available, so we simply use some init values */
static struct {
int length;
@@ -330,7 +330,7 @@ static int mxb_init_done(struct saa7146_dev* dev)
v4l2_std_id std = V4L2_STD_PAL_BG;
int i = 0, err = 0;
- struct tea6415c_multiplex vm;
+ struct tea6415c_multiplex vm;
/* select video mode in saa7111a */
i = VIDEO_MODE_PAL;
@@ -380,16 +380,16 @@ static int mxb_init_done(struct saa7146_dev* dev)
vm.in = 3;
vm.out = 13;
mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm);
-
+
/* the rest for mxb */
mxb->cur_input = 0;
mxb->cur_mute = 1;
mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &mxb->cur_mode);
-
+
/* check if the saa7740 (aka 'sound arena module') is present
- on the mxb. if so, we must initialize it. due to lack of
+ on the mxb. if so, we must initialize it. due to lack of
informations about the saa7740, the values were reverse
engineered. */
msg.addr = 0x1b;
@@ -409,7 +409,7 @@ static int mxb_init_done(struct saa7146_dev* dev)
break;
}
- msg.len = mxb_saa7740_init[i].length;
+ msg.len = mxb_saa7740_init[i].length;
msg.buf = &mxb_saa7740_init[i].data[0];
if( 1 != (err = i2c_transfer(&mxb->i2c_adapter, &msg, 1))) {
DEB_D(("failed to initialize 'sound arena module'.\n"));
@@ -418,12 +418,12 @@ static int mxb_init_done(struct saa7146_dev* dev)
}
INFO(("'sound arena module' detected.\n"));
}
-err:
+err:
/* the rest for saa7146: you should definitely set some basic values
for the input-port handling of the saa7146. */
/* ext->saa has been filled by the core driver */
-
+
/* some stuff is done via variables */
saa7146_set_hps_source_and_sync(dev, input_port_selection[mxb->cur_input].hps_source, input_port_selection[mxb->cur_input].hps_sync);
@@ -431,7 +431,7 @@ err:
/* this is ugly, but because of the fact that this is completely
hardware dependend, it should be done directly... */
- saa7146_write(dev, DD1_STREAM_B, 0x00000000);
+ saa7146_write(dev, DD1_STREAM_B, 0x00000000);
saa7146_write(dev, DD1_INIT, 0x02000200);
saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
@@ -453,7 +453,7 @@ static struct saa7146_ext_vv vv_data;
static int mxb_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
{
struct mxb* mxb = (struct mxb*)dev->ext_priv;
-
+
DEB_EE(("dev:%p\n",dev));
/* checking for i2c-devices can be omitted here, because we
@@ -464,7 +464,7 @@ static int mxb_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data
ERR(("cannot register capture v4l2 device. skipping.\n"));
return -1;
}
-
+
/* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
if( 0 != MXB_BOARD_CAN_DO_VBI(dev)) {
if( 0 != saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
@@ -513,17 +513,17 @@ static int mxb_detach(struct saa7146_dev* dev)
return 0;
}
-static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
+static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
{
struct saa7146_dev *dev = fh->dev;
struct mxb* mxb = (struct mxb*)dev->ext_priv;
- struct saa7146_vv *vv = dev->vv_data;
-
+ struct saa7146_vv *vv = dev->vv_data;
+
switch(cmd) {
case VIDIOC_ENUMINPUT:
{
struct v4l2_input *i = arg;
-
+
DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
if( i->index < 0 || i->index >= MXB_INPUTS) {
return -EINVAL;
@@ -559,11 +559,11 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
break;
}
}
-
+
if( i < 0 ) {
return -EAGAIN;
}
-
+
switch (vc->id ) {
case V4L2_CID_AUDIO_MUTE: {
vc->value = mxb->cur_mute;
@@ -571,7 +571,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
return 0;
}
}
-
+
DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n",vc->value));
return 0;
}
@@ -580,17 +580,17 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
{
struct v4l2_control *vc = arg;
int i = 0;
-
+
for (i = MAXCONTROLS - 1; i >= 0; i--) {
if (mxb_controls[i].id == vc->id) {
break;
}
}
-
+
if( i < 0 ) {
return -EAGAIN;
}
-
+
switch (vc->id ) {
case V4L2_CID_AUDIO_MUTE: {
mxb->cur_mute = vc->value;
@@ -614,12 +614,12 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
*input = mxb->cur_input;
DEB_EE(("VIDIOC_G_INPUT %d.\n",*input));
- return 0;
- }
+ return 0;
+ }
case VIDIOC_S_INPUT:
{
int input = *(int *)arg;
- struct tea6415c_multiplex vm;
+ struct tea6415c_multiplex vm;
int i = 0;
DEB_EE(("VIDIOC_S_INPUT %d.\n",input));
@@ -627,34 +627,34 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
if (input < 0 || input >= MXB_INPUTS) {
return -EINVAL;
}
-
+
/* fixme: locke das setzen des inputs mit hilfe des mutexes
- down(&dev->lock);
+ mutex_lock(&dev->lock);
video_mux(dev,*i);
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
*/
-
+
/* fixme: check if streaming capture
if ( 0 != dev->streaming ) {
DEB_D(("VIDIOC_S_INPUT illegal while streaming.\n"));
return -EPERM;
}
*/
-
+
mxb->cur_input = input;
-
+
saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, input_port_selection[input].hps_sync);
-
+
/* prepare switching of tea6415c and saa7111a;
have a look at the 'background'-file for further informations */
switch( input ) {
-
+
case TUNER:
{
i = 0;
vm.in = 3;
vm.out = 17;
-
+
if ( 0 != mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm)) {
printk("VIDIOC_S_INPUT: could not address tea6415c #1\n");
return -EFAULT;
@@ -662,7 +662,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
/* connect tuner-output always to multicable */
vm.in = 3;
vm.out = 13;
- break;
+ break;
}
case AUX3_YC:
{
@@ -703,11 +703,11 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
break;
}
}
-
+
/* switch video in saa7111a */
if ( 0 != mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_INPUT, &i)) {
printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n");
- }
+ }
/* switch the audio-source only if necessary */
if( 0 == mxb->cur_mute ) {
@@ -738,11 +738,11 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */
/* FIXME: add the real signal strength here */
t->signal = 0xffff;
- t->afc = 0;
+ t->afc = 0;
mxb->tda9840->driver->command(mxb->tda9840,TDA9840_DETECT, &byte);
t->audmode = mxb->cur_mode;
-
+
if( byte < 0 ) {
t->rxsubchans = V4L2_TUNER_SUB_MONO;
} else {
@@ -777,12 +777,12 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
struct v4l2_tuner *t = arg;
int result = 0;
int byte = 0;
-
+
if( 0 != t->index ) {
DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index));
return -EINVAL;
}
-
+
switch(t->audmode) {
case V4L2_TUNER_MODE_STEREO: {
mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
@@ -813,7 +813,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
if( 0 != (result = mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &byte))) {
printk("VIDIOC_S_TUNER error. result:%d, byte:%d\n",result,byte);
}
-
+
return 0;
}
case VIDIOC_G_FREQUENCY:
@@ -839,7 +839,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
if (V4L2_TUNER_ANALOG_TV != f->type)
return -EINVAL;
-
+
if(0 != mxb->cur_input) {
DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n",mxb->cur_input));
return -EINVAL;
@@ -848,7 +848,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
mxb->cur_freq = *f;
DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency));
- /* tune in desired frequency */
+ /* tune in desired frequency */
mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq);
/* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
@@ -861,12 +861,12 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
case MXB_S_AUDIO_CD:
{
int i = *(int*)arg;
-
+
if( i < 0 || i >= MXB_AUDIOS ) {
DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n",i));
return -EINVAL;
}
-
+
DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n",i));
mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[i][0]);
@@ -877,12 +877,12 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
case MXB_S_AUDIO_LINE:
{
int i = *(int*)arg;
-
+
if( i < 0 || i >= MXB_AUDIOS ) {
DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n",i));
return -EINVAL;
}
-
+
DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n",i));
mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[i][0]);
mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[i][1]);
@@ -894,13 +894,13 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
struct v4l2_audio *a = arg;
if( a->index < 0 || a->index > MXB_INPUTS ) {
- DEB_D(("VIDIOC_G_AUDIO %d out of range.\n",a->index));
+ DEB_D(("VIDIOC_G_AUDIO %d out of range.\n",a->index));
return -EINVAL;
}
-
- DEB_EE(("VIDIOC_G_AUDIO %d.\n",a->index));
+
+ DEB_EE(("VIDIOC_G_AUDIO %d.\n",a->index));
memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
-
+
return 0;
}
case VIDIOC_S_AUDIO:
@@ -908,7 +908,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
struct v4l2_audio *a = arg;
DEB_D(("VIDIOC_S_AUDIO %d.\n",a->index));
return 0;
- }
+ }
default:
/*
DEB2(printk("does not handle this ioctl.\n"));
@@ -928,7 +928,7 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
v4l2_std_id std = V4L2_STD_PAL_I;
DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n"));
/* set the 7146 gpio register -- I don't know what this does exactly */
- saa7146_write(dev, GPIO_CTRL, 0x00404050);
+ saa7146_write(dev, GPIO_CTRL, 0x00404050);
/* unset the 7111 gpio register -- I don't know what this does exactly */
mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &zero);
mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
@@ -936,7 +936,7 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
v4l2_std_id std = V4L2_STD_PAL_BG;
DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n"));
/* set the 7146 gpio register -- I don't know what this does exactly */
- saa7146_write(dev, GPIO_CTRL, 0x00404050);
+ saa7146_write(dev, GPIO_CTRL, 0x00404050);
/* set the 7111 gpio register -- I don't know what this does exactly */
mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &one);
mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
@@ -969,8 +969,8 @@ static struct saa7146_standard standard[] = {
};
static struct saa7146_pci_extension_data mxb = {
- .ext_priv = "Multimedia eXtension Board",
- .ext = &extension,
+ .ext_priv = "Multimedia eXtension Board",
+ .ext = &extension,
};
static struct pci_device_id pci_tbl[] = {
@@ -992,7 +992,7 @@ static struct saa7146_ext_vv vv_data = {
.capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE,
.stds = &standard[0],
.num_stds = sizeof(standard)/sizeof(struct saa7146_standard),
- .std_callback = &std_callback,
+ .std_callback = &std_callback,
.ioctls = &ioctls[0],
.ioctl = mxb_ioctl,
};
@@ -1000,7 +1000,7 @@ static struct saa7146_ext_vv vv_data = {
static struct saa7146_extension extension = {
.name = MXB_IDENTIFIER,
.flags = SAA7146_USE_I2C_IRQ,
-
+
.pci_tbl = &pci_tbl[0],
.module = THIS_MODULE,
@@ -1010,7 +1010,7 @@ static struct saa7146_extension extension = {
.irq_mask = 0,
.irq_func = NULL,
-};
+};
static int __init mxb_init_module(void)
{
@@ -1018,7 +1018,7 @@ static int __init mxb_init_module(void)
DEB_S(("failed to register extension.\n"));
return -ENODEV;
}
-
+
return 0;
}
diff --git a/drivers/media/video/mxb.h b/drivers/media/video/mxb.h
index 2332ed5f7c6..400a57ba62e 100644
--- a/drivers/media/video/mxb.h
+++ b/drivers/media/video/mxb.h
@@ -38,5 +38,5 @@ static struct v4l2_audio mxb_audios[MXB_AUDIOS] = {
.name = "CD-ROM (X10)",
.capability = V4L2_AUDCAP_STEREO,
}
-};
+};
#endif
diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c
index f3fc361bec9..15fd85acabd 100644
--- a/drivers/media/video/planb.c
+++ b/drivers/media/video/planb.c
@@ -48,7 +48,7 @@
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/irq.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
#include "planb.h"
#include "saa7196.h"
@@ -329,12 +329,12 @@ static volatile struct dbdma_cmd *cmd_geo_setup(
static inline void planb_lock(struct planb *pb)
{
- down(&pb->lock);
+ mutex_lock(&pb->lock);
}
static inline void planb_unlock(struct planb *pb)
{
- up(&pb->lock);
+ mutex_unlock(&pb->lock);
}
/***************/
@@ -2067,7 +2067,7 @@ static int init_planb(struct planb *pb)
#endif
pb->tab_size = PLANB_MAXLINES + 40;
pb->suspend = 0;
- init_MUTEX(&pb->lock);
+ mutex_init(&pb->lock);
pb->ch1_cmd = 0;
pb->ch2_cmd = 0;
pb->mask = 0;
diff --git a/drivers/media/video/planb.h b/drivers/media/video/planb.h
index 8a0faad1611..79b6b561426 100644
--- a/drivers/media/video/planb.h
+++ b/drivers/media/video/planb.h
@@ -174,7 +174,7 @@ struct planb {
int user;
unsigned int tab_size;
int maxlines;
- struct semaphore lock;
+ struct mutex lock;
unsigned int irq; /* interrupt number */
volatile unsigned int intr_mask;
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c
index 9e644863948..05ca55939e7 100644
--- a/drivers/media/video/pms.c
+++ b/drivers/media/video/pms.c
@@ -30,6 +30,8 @@
#include <asm/io.h>
#include <linux/sched.h>
#include <linux/videodev.h>
+#include <linux/mutex.h>
+
#include <asm/uaccess.h>
@@ -44,7 +46,7 @@ struct pms_device
struct video_picture picture;
int height;
int width;
- struct semaphore lock;
+ struct mutex lock;
};
struct i2c_info
@@ -724,10 +726,10 @@ static int pms_do_ioctl(struct inode *inode, struct file *file,
struct video_channel *v = arg;
if(v->channel<0 || v->channel>3)
return -EINVAL;
- down(&pd->lock);
+ mutex_lock(&pd->lock);
pms_videosource(v->channel&1);
pms_vcrinput(v->channel>>1);
- up(&pd->lock);
+ mutex_unlock(&pd->lock);
return 0;
}
case VIDIOCGTUNER:
@@ -761,7 +763,7 @@ static int pms_do_ioctl(struct inode *inode, struct file *file,
struct video_tuner *v = arg;
if(v->tuner)
return -EINVAL;
- down(&pd->lock);
+ mutex_lock(&pd->lock);
switch(v->mode)
{
case VIDEO_MODE_AUTO:
@@ -785,10 +787,10 @@ static int pms_do_ioctl(struct inode *inode, struct file *file,
pms_format(2);
break;
default:
- up(&pd->lock);
+ mutex_unlock(&pd->lock);
return -EINVAL;
}
- up(&pd->lock);
+ mutex_unlock(&pd->lock);
return 0;
}
case VIDIOCGPICT:
@@ -809,12 +811,12 @@ static int pms_do_ioctl(struct inode *inode, struct file *file,
* Now load the card.
*/
- down(&pd->lock);
+ mutex_lock(&pd->lock);
pms_brightness(p->brightness>>8);
pms_hue(p->hue>>8);
pms_colour(p->colour>>8);
pms_contrast(p->contrast>>8);
- up(&pd->lock);
+ mutex_unlock(&pd->lock);
return 0;
}
case VIDIOCSWIN:
@@ -830,9 +832,9 @@ static int pms_do_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
pd->width=vw->width;
pd->height=vw->height;
- down(&pd->lock);
+ mutex_lock(&pd->lock);
pms_resolution(pd->width, pd->height);
- up(&pd->lock); /* Ok we figured out what to use from our wide choice */
+ mutex_unlock(&pd->lock); /* Ok we figured out what to use from our wide choice */
return 0;
}
case VIDIOCGWIN:
@@ -872,9 +874,9 @@ static ssize_t pms_read(struct file *file, char __user *buf,
struct pms_device *pd=(struct pms_device *)v;
int len;
- down(&pd->lock);
+ mutex_lock(&pd->lock);
len=pms_capture(pd, buf, (pd->picture.depth==16)?0:1,count);
- up(&pd->lock);
+ mutex_unlock(&pd->lock);
return len;
}
@@ -1029,7 +1031,7 @@ static int __init init_pms_cards(void)
return -ENODEV;
}
memcpy(&pms_device, &pms_template, sizeof(pms_template));
- init_MUTEX(&pms_device.lock);
+ mutex_init(&pms_device.lock);
pms_device.height=240;
pms_device.width=320;
pms_swsense(75);
diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c
index 2ce01020130..dd830e0e5e9 100644
--- a/drivers/media/video/saa5246a.c
+++ b/drivers/media/video/saa5246a.c
@@ -46,6 +46,8 @@
#include <linux/i2c.h>
#include <linux/videotext.h>
#include <linux/videodev.h>
+#include <linux/mutex.h>
+
#include "saa5246a.h"
MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>");
@@ -57,7 +59,7 @@ struct saa5246a_device
u8 pgbuf[NUM_DAUS][VTX_VIRTUALSIZE];
int is_searching[NUM_DAUS];
struct i2c_client *client;
- struct semaphore lock;
+ struct mutex lock;
};
static struct video_device saa_template; /* Declared near bottom */
@@ -90,7 +92,7 @@ static int saa5246a_attach(struct i2c_adapter *adap, int addr, int kind)
return -ENOMEM;
}
strlcpy(client->name, IF_NAME, I2C_NAME_SIZE);
- init_MUTEX(&t->lock);
+ mutex_init(&t->lock);
/*
* Now create a video4linux device
@@ -719,9 +721,9 @@ static int saa5246a_ioctl(struct inode *inode, struct file *file,
int err;
cmd = vtx_fix_command(cmd);
- down(&t->lock);
+ mutex_lock(&t->lock);
err = video_usercopy(inode, file, cmd, arg, do_saa5246a_ioctl);
- up(&t->lock);
+ mutex_unlock(&t->lock);
return err;
}
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
index 5694eb58c3a..a9f3cf0b1e3 100644
--- a/drivers/media/video/saa5249.c
+++ b/drivers/media/video/saa5249.c
@@ -56,6 +56,8 @@
#include <linux/i2c.h>
#include <linux/videotext.h>
#include <linux/videodev.h>
+#include <linux/mutex.h>
+
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -105,7 +107,7 @@ struct saa5249_device
int disp_mode;
int virtual_mode;
struct i2c_client *client;
- struct semaphore lock;
+ struct mutex lock;
};
@@ -158,7 +160,7 @@ static int saa5249_attach(struct i2c_adapter *adap, int addr, int kind)
return -ENOMEM;
}
strlcpy(client->name, IF_NAME, I2C_NAME_SIZE);
- init_MUTEX(&t->lock);
+ mutex_init(&t->lock);
/*
* Now create a video4linux device
@@ -619,9 +621,9 @@ static int saa5249_ioctl(struct inode *inode, struct file *file,
int err;
cmd = vtx_fix_command(cmd);
- down(&t->lock);
+ mutex_lock(&t->lock);
err = video_usercopy(inode,file,cmd,arg,do_saa5249_ioctl);
- up(&t->lock);
+ mutex_unlock(&t->lock);
return err;
}
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index ffd87ce5555..b184fd00b4e 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -1,4 +1,4 @@
-/* saa7115 - Philips SAA7114/SAA7115 video decoder driver
+/* saa7115 - Philips SAA7113/SAA7114/SAA7115 video decoder driver
*
* Based on saa7114 driver by Maxim Yevtyushkin, which is based on
* the saa7111 driver by Dave Perks.
@@ -16,6 +16,7 @@
* (2/17/2003)
*
* VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@xs4all.nl>
+ * SAA7113 support by Mauro Carvalho Chehab <mchehab@infradead.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -42,8 +43,9 @@
#include <media/audiochip.h>
#include <asm/div64.h>
-MODULE_DESCRIPTION("Philips SAA7114/SAA7115 video decoder driver");
-MODULE_AUTHOR("Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, Hans Verkuil");
+MODULE_DESCRIPTION("Philips SAA7113/SAA7114/SAA7115 video decoder driver");
+MODULE_AUTHOR( "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, "
+ "Hans Verkuil, Mauro Carvalho Chehab");
MODULE_LICENSE("GPL");
static int debug = 0;
@@ -51,7 +53,10 @@ module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
-static unsigned short normal_i2c[] = { 0x42 >> 1, 0x40 >> 1, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = {
+ 0x4a >>1, 0x48 >>1, /* SAA7113 */
+ 0x42 >> 1, 0x40 >> 1, /* SAA7114 and SAA7115 */
+ I2C_CLIENT_END };
I2C_CLIENT_INSMOD;
@@ -101,10 +106,12 @@ static inline int saa7115_read(struct i2c_client *client, u8 reg)
Hauppauge driver sets. */
static const unsigned char saa7115_init_auto_input[] = {
+ /* Front-End Part */
0x01, 0x48, /* white peak control disabled */
0x03, 0x20, /* was 0x30. 0x20: long vertical blanking */
0x04, 0x90, /* analog gain set to 0 */
0x05, 0x90, /* analog gain set to 0 */
+ /* Decoder Part */
0x06, 0xeb, /* horiz sync begin = -21 */
0x07, 0xe0, /* horiz sync stop = -17 */
0x0a, 0x80, /* was 0x88. decoder brightness, 0x80 is itu standard */
@@ -123,6 +130,8 @@ static const unsigned char saa7115_init_auto_input[] = {
0x1b, 0x42, /* misc chroma control 0x42 = recommended */
0x1c, 0xa9, /* combfilter control 0xA9 = recommended */
0x1d, 0x01, /* combfilter control 0x01 = recommended */
+
+ /* Power Device Control */
0x88, 0xd0, /* reset device */
0x88, 0xf0, /* set device programmed, all in operational mode */
0x00, 0x00
@@ -338,6 +347,33 @@ static const unsigned char saa7115_cfg_vbi_off[] = {
0x00, 0x00
};
+static const unsigned char saa7113_init_auto_input[] = {
+ 0x01, 0x08, /* PH7113_INCREMENT_DELAY - (1) (1) (1) (1) IDEL3 IDEL2 IDELL1 IDEL0 */
+ 0x02, 0xc2, /* PH7113_ANALOG_INPUT_CONTR_1 - FUSE1 FUSE0 GUDL1 GUDL0 MODE3 MODE2 MODE1 MODE0 */
+ 0x03, 0x30, /* PH7113_ANALOG_INPUT_CONTR_2 - (1) HLNRS VBSL WPOFF HOLDG GAFIX GAI28 GAI18 */
+ 0x04, 0x00, /* PH7113_ANALOG_INPUT_CONTR_3 - GAI17 GAI16 GAI15 GAI14 GAI13 GAI12 GAI11 GAI10 */
+ 0x05, 0x00, /* PH7113_ANALOG_INPUT_CONTR_4 - GAI27 GAI26 GAI25 GAI24 GAI23 GAI22 GAI21 GAI20 */
+ 0x06, 0x89, /* PH7113_HORIZONTAL_SYNC_START - HSB7 HSB6 HSB5 HSB4 HSB3 HSB2 HSB1 HSB0 */
+ 0x07, 0x0d, /* PH7113_HORIZONTAL_SYNC_STOP - HSS7 HSS6 HSS5 HSS4 HSS3 HSS2 HSS1 HSS0 */
+ 0x08, 0x88, /* PH7113_SYNC_CONTROL - AUFD FSEL FOET HTC1 HTC0 HPLL VNOI1 VNOI0 */
+ 0x09, 0x01, /* PH7113_LUMINANCE_CONTROL - BYPS PREF BPSS1 BPSS0 VBLB UPTCV APER1 APER0 */
+ 0x0a, 0x80, /* PH7113_LUMINANCE_BRIGHTNESS - BRIG7 BRIG6 BRIG5 BRIG4 BRIG3 BRIG2 BRIG1 BRIG0 */
+ 0x0b, 0x47, /* PH7113_LUMINANCE_CONTRAST - CONT7 CONT6 CONT5 CONT4 CONT3 CONT2 CONT1 CONT0 */
+ 0x0c, 0x40, /* PH7113_CHROMA_SATURATION - SATN7 SATN6 SATN5 SATN4 SATN3 SATN2 SATN1 SATN0 */
+ 0x0d, 0x00, /* PH7113_CHROMA_HUE_CONTROL - HUEC7 HUEC6 HUEC5 HUEC4 HUEC3 HUEC2 HUEC1 HUEC0 */
+ 0x0e, 0x01, /* PH7113_CHROMA_CONTROL - CDTO CSTD2 CSTD1 CSTD0 DCCF FCTC CHBW1 CHBW0 */
+ 0x0f, 0x2a, /* PH7113_CHROMA_GAIN_CONTROL - ACGC CGAIN6 CGAIN5 CGAIN4 CGAIN3 CGAIN2 CGAIN1 CGAIN0 */
+ 0x10, 0x08, /* PH7113_FORMAT_DELAY_CONTROL - OFTS1 OFTS0 HDEL1 HDEL0 VRLN YDEL2 YDEL1 YDEL0 */
+ 0x11, 0x0c, /* PH7113_OUTPUT_CONTROL_1 - GPSW1 CM99 GPSW0 HLSEL OEYC OERT VIPB COLO */
+ 0x12, 0x07, /* PH7113_OUTPUT_CONTROL_2 - RTSE13 RTSE12 RTSE11 RTSE10 RTSE03 RTSE02 RTSE01 RTSE00 */
+ 0x13, 0x00, /* PH7113_OUTPUT_CONTROL_3 - ADLSB (1) (1) OLDSB FIDP (1) AOSL1 AOSL0 */
+ 0x14, 0x00, /* RESERVED 14 - (1) (1) (1) (1) (1) (1) (1) (1) */
+ 0x15, 0x00, /* PH7113_V_GATE1_START - VSTA7 VSTA6 VSTA5 VSTA4 VSTA3 VSTA2 VSTA1 VSTA0 */
+ 0x16, 0x00, /* PH7113_V_GATE1_STOP - VSTO7 VSTO6 VSTO5 VSTO4 VSTO3 VSTO2 VSTO1 VSTO0 */
+ 0x17, 0x00, /* PH7113_V_GATE1_MSB - (1) (1) (1) (1) (1) (1) VSTO8 VSTA8 */
+ 0x00, 0x00
+};
+
static const unsigned char saa7115_init_misc[] = {
0x38, 0x03, /* audio stuff */
0x39, 0x10,
@@ -677,10 +713,35 @@ static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
saa7115_writeregs(client, saa7115_cfg_50hz_video);
}
+ /* Register 0E - Bits D6-D4 on NO-AUTO mode
+ (SAA7113 doesn't have auto mode)
+ 50 Hz / 625 lines 60 Hz / 525 lines
+ 000 PAL BGDHI (4.43Mhz) NTSC M (3.58MHz)
+ 001 NTSC 4.43 (50 Hz) PAL 4.43 (60 Hz)
+ 010 Combination-PAL N (3.58MHz) NTSC 4.43 (60 Hz)
+ 011 NTSC N (3.58MHz) PAL M (3.58MHz)
+ 100 reserved NTSC-Japan (3.58MHz)
+ */
+ if (state->ident == V4L2_IDENT_SAA7113) {
+ u8 reg = saa7115_read(client, 0x0e) & 0x8f;
+
+ if (std == V4L2_STD_PAL_M) {
+ reg|=0x30;
+ } else if (std == V4L2_STD_PAL_N) {
+ reg|=0x20;
+ } else if (std == V4L2_STD_PAL_60) {
+ reg|=0x10;
+ } else if (std == V4L2_STD_NTSC_M_JP) {
+ reg|=0x40;
+ }
+ saa7115_write(client, 0x0e, reg);
+ }
+
+
state->std = std;
/* restart task B if needed */
- if (taskb && state->ident == V4L2_IDENT_SAA7114) {
+ if (taskb && state->ident != V4L2_IDENT_SAA7115) {
saa7115_writeregs(client, saa7115_cfg_vbi_on);
}
@@ -703,7 +764,7 @@ static void saa7115_log_status(struct i2c_client *client)
int vcr;
v4l_info(client, "Audio frequency: %d Hz\n", state->audclk_freq);
- if (client->name[6] == '4') {
+ if (state->ident != V4L2_IDENT_SAA7115) {
/* status for the saa7114 */
reg1f = saa7115_read(client, 0x1f);
signalOk = (reg1f & 0xc1) == 0x81;
@@ -751,8 +812,8 @@ static void saa7115_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_fo
u8 lcr[24];
int i, x;
- /* saa7114 doesn't yet support VBI */
- if (state->ident == V4L2_IDENT_SAA7114)
+ /* saa7113/71144 doesn't yet support VBI */
+ if (state->ident != V4L2_IDENT_SAA7115)
return;
for (i = 0; i <= 23; i++)
@@ -791,7 +852,7 @@ static void saa7115_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_fo
case 0:
lcr[i] |= 0xf << (4 * x);
break;
- case V4L2_SLICED_TELETEXT_B:
+ case V4L2_SLICED_TELETEXT_PAL_B:
lcr[i] |= 1 << (4 * x);
break;
case V4L2_SLICED_CAPTION_525:
@@ -820,7 +881,7 @@ static void saa7115_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_fo
static int saa7115_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
{
static u16 lcr2vbi[] = {
- 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
+ 0, V4L2_SLICED_TELETEXT_PAL_B, 0, /* 1 */
0, V4L2_SLICED_CAPTION_525, /* 4 */
V4L2_SLICED_WSS_625, 0, /* 5 */
V4L2_SLICED_VPS, 0, 0, 0, 0, /* 7 */
@@ -985,7 +1046,7 @@ static void saa7115_decode_vbi_line(struct i2c_client *client,
/* decode payloads */
switch (id2) {
case 1:
- vbi->type = V4L2_SLICED_TELETEXT_B;
+ vbi->type = V4L2_SLICED_TELETEXT_PAL_B;
break;
case 4:
if (!saa7115_odd_parity(p[0]) || !saa7115_odd_parity(p[1]))
@@ -1261,14 +1322,12 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
saa7115_write(client, 0, 5);
chip_id = saa7115_read(client, 0) & 0x0f;
- if (chip_id != 4 && chip_id != 5) {
+ if (chip_id <3 && chip_id > 5) {
v4l_dbg(1, debug, client, "saa7115 not found\n");
kfree(client);
return 0;
}
- if (chip_id == 4) {
- snprintf(client->name, sizeof(client->name) - 1, "saa7114");
- }
+ snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id);
v4l_info(client, "saa711%d found @ 0x%x (%s)\n", chip_id, address << 1, adapter->name);
state = kzalloc(sizeof(struct saa7115_state), GFP_KERNEL);
@@ -1285,13 +1344,27 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
state->contrast = 64;
state->hue = 0;
state->sat = 64;
- state->ident = (chip_id == 4) ? V4L2_IDENT_SAA7114 : V4L2_IDENT_SAA7115;
+ switch (chip_id) {
+ case 3:
+ state->ident = V4L2_IDENT_SAA7113;
+ break;
+ case 4:
+ state->ident = V4L2_IDENT_SAA7114;
+ break;
+ default:
+ state->ident = V4L2_IDENT_SAA7115;
+ break;
+ }
+
state->audclk_freq = 48000;
v4l_dbg(1, debug, client, "writing init values\n");
/* init to 60hz/48khz */
- saa7115_writeregs(client, saa7115_init_auto_input);
+ if (state->ident==V4L2_IDENT_SAA7113)
+ saa7115_writeregs(client, saa7113_init_auto_input);
+ else
+ saa7115_writeregs(client, saa7115_init_auto_input);
saa7115_writeregs(client, saa7115_init_misc);
saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index 7df5e0826e1..64e2c108df3 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -308,8 +308,7 @@ static int dsp_buffer_init(struct saa7134_dev *dev)
static int dsp_buffer_free(struct saa7134_dev *dev)
{
- if (!dev->dmasound.blksize)
- BUG();
+ BUG_ON(!dev->dmasound.blksize);
videobuf_dma_free(&dev->dmasound.dma);
@@ -611,12 +610,12 @@ static int snd_card_saa7134_capture_open(snd_pcm_substream_t * substream)
struct saa7134_dev *dev = saa7134->dev;
int err;
- down(&dev->dmasound.lock);
+ mutex_lock(&dev->dmasound.lock);
dev->dmasound.read_count = 0;
dev->dmasound.read_offset = 0;
- up(&dev->dmasound.lock);
+ mutex_unlock(&dev->dmasound.lock);
pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
if (pcm == NULL)
@@ -934,7 +933,7 @@ static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum)
chip->irq = dev->pci->irq;
- init_MUTEX(&dev->dmasound.lock);
+ mutex_init(&dev->dmasound.lock);
if ((err = snd_card_saa7134_new_mixer(chip)) < 0)
goto __nodev;
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 6bc63a4086c..fdd7f48f3b7 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -536,7 +536,7 @@ struct saa7134_board saa7134_boards[] = {
.radio = {
.name = name_radio,
.amux = LINE2,
- },
+ },
},
[SAA7134_BOARD_MD7134] = {
.name = "Medion 7134",
@@ -640,6 +640,32 @@ struct saa7134_board saa7134_boards[] = {
.tv = 1,
}},
},
+ [SAA7134_BOARD_ELSA_700TV] = {
+ .name = "ELSA EX-VISION 700TV",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_HITACHI_NTSC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 4,
+ .amux = LINE2,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 6,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 7,
+ .amux = LINE1,
+ }},
+ .mute = {
+ .name = name_mute,
+ .amux = TV,
+ },
+ },
[SAA7134_BOARD_ASUSTeK_TVFM7134] = {
.name = "ASUS TV-FM 7134",
.audio_clock = 0x00187de7,
@@ -2002,7 +2028,7 @@ struct saa7134_board saa7134_boards[] = {
[SAA7134_BOARD_FLYTV_DIGIMATRIX] = {
.name = "FlyTV mini Asus Digimatrix",
.audio_clock = 0x00200000,
- .tuner_type = TUNER_LG_NTSC_TALN_MINI,
+ .tuner_type = TUNER_LG_TALN,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -2598,6 +2624,7 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.gpiomask = 0x00200000,
+ .mpeg = SAA7134_MPEG_DVB,
.inputs = {{
.name = name_tv, /* Analog broadcast/cable TV */
.vmux = 1,
@@ -2623,6 +2650,164 @@ struct saa7134_board saa7134_boards[] = {
.gpio = 0x000000, /* GPIO21=Low for FM radio antenna */
},
},
+ [SAA7134_BOARD_AVERMEDIA_777] = {
+ .name = "AverTV DVB-T 777",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_FLYDVBT_LR301] = {
+ /* LifeView FlyDVB-T */
+ /* Giampiero Giancipoli <gianci@libero.it> */
+ .name = "LifeView FlyDVB-T",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_comp1, /* Composite input */
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .name = name_svideo, /* S-Video signal on S-Video input */
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331] = {
+ .name = "ADS Instant TV Duo Cardbus PTV331",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .gpiomask = 0x00600000, /* Bit 21 0=Radio, Bit 22 0=TV */
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ .gpio = 0x00200000,
+ }},
+ },
+ [SAA7134_BOARD_TEVION_DVBT_220RF] = {
+ .name = "Tevion/KWorld DVB-T 220RF",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 0,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE1,
+ },
+ },
+ [SAA7134_BOARD_KWORLD_ATSC110] = {
+ .name = "Kworld ATSC110",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TUV1236D,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_AVERMEDIA_A169_B] = {
+ /* AVerMedia A169 */
+ /* Rickard Osser <ricky@osser.se> */
+ /* This card has two saa7134 chips on it,
+ but only one of them is currently working. */
+ .name = "AVerMedia A169 B",
+ .audio_clock = 0x02187de7,
+ .tuner_type = TUNER_LG_TALN,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x0a60000,
+ },
+ [SAA7134_BOARD_AVERMEDIA_A169_B1] = {
+ /* AVerMedia A169 */
+ /* Rickard Osser <ricky@osser.se> */
+ .name = "AVerMedia A169 B1",
+ .audio_clock = 0x02187de7,
+ .tuner_type = TUNER_LG_TALN,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0xca60000,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 4,
+ .amux = TV,
+ .tv = 1,
+ .gpio = 0x04a61000,
+ },{
+ .name = name_comp2, /* Composite SVIDEO (B/W if signal is carried with SVIDEO) */
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 9, /* 9 is correct as S-VIDEO1 according to a169.inf! */
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_MD7134_BRIDGE_2] = {
+ /* This card has two saa7134 chips on it,
+ but only one of them is currently working.
+ The programming for the primary decoder is
+ in SAA7134_BOARD_MD7134 */
+ .name = "Medion 7134 Bridge #2",
+ .audio_clock = 0x00187de7,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -2753,6 +2938,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
.driver_data = SAA7134_BOARD_ELSA_500TV,
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x1048,
+ .subdevice = 0x226c,
+ .driver_data = SAA7134_BOARD_ELSA_700TV,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
.subvendor = PCI_VENDOR_ID_ASUSTEK,
.subdevice = 0x4842,
@@ -3094,6 +3285,54 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0x0319,
.driver_data = SAA7134_BOARD_FLYDVB_TRIO,
},{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134, /* SAA 7131E */
+ .subvendor = 0x1461,
+ .subdevice = 0x2c05,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_777,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x5168,
+ .subdevice = 0x0301,
+ .driver_data = SAA7134_BOARD_FLYDVBT_LR301,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0331,
+ .subdevice = 0x1421,
+ .driver_data = SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x17de,
+ .subdevice = 0x7201,
+ .driver_data = SAA7134_BOARD_TEVION_DVBT_220RF,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */
+ .subvendor = 0x17de,
+ .subdevice = 0x7350,
+ .driver_data = SAA7134_BOARD_KWORLD_ATSC110,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1461,
+ .subdevice = 0x7360,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_A169_B,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1461,
+ .subdevice = 0x6360,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_A169_B1,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x16be,
+ .subdevice = 0x0005,
+ .driver_data = SAA7134_BOARD_MD7134_BRIDGE_2,
+ },{
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -3193,13 +3432,15 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_GOTVIEW_7135:
case SAA7134_BOARD_KWORLD_TERMINATOR:
case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
+ case SAA7134_BOARD_FLYDVBT_LR301:
+ case SAA7134_BOARD_FLYDVBTDUO:
dev->has_remote = SAA7134_REMOTE_GPIO;
break;
case SAA7134_BOARD_MD5044:
printk("%s: seems there are two different versions of the MD5044\n"
- "%s: (with the same ID) out there. If sound doesn't work for\n"
- "%s: you try the audio_clock_override=0x200000 insmod option.\n",
- dev->name,dev->name,dev->name);
+ "%s: (with the same ID) out there. If sound doesn't work for\n"
+ "%s: you try the audio_clock_override=0x200000 insmod option.\n",
+ dev->name,dev->name,dev->name);
break;
case SAA7134_BOARD_CINERGY400_CARDBUS:
/* power-up tuner chip */
@@ -3220,6 +3461,10 @@ int saa7134_board_init1(struct saa7134_dev *dev)
saa_writeb(SAA7134_GPIO_GPMODE3, 0x08);
saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x06);
break;
+ case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
+ saa_writeb(SAA7134_GPIO_GPMODE3, 0x08);
+ saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x00);
+ break;
case SAA7134_BOARD_AVERMEDIA_CARDBUS:
/* power-up tuner chip */
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0xffffffff, 0xffffffff);
@@ -3242,6 +3487,13 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_UPMOST_PURPLE_TV:
dev->has_remote = SAA7134_REMOTE_I2C;
break;
+ case SAA7134_BOARD_AVERMEDIA_A169_B:
+ case SAA7134_BOARD_MD7134_BRIDGE_2:
+ printk("%s: %s: dual saa713x broadcast decoders\n"
+ "%s: Sorry, none of the inputs to this chip are supported yet.\n"
+ "%s: Dual decoder functionality is disabled for now, use the other chip.\n",
+ dev->name,card(dev).name,dev->name,dev->name);
+ break;
}
return 0;
}
@@ -3362,14 +3614,44 @@ int saa7134_board_init2(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_PHILIPS_TIGER:
+ case SAA7134_BOARD_TEVION_DVBT_220RF:
case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
- /* this is a hybrid board, initialize to analog mode */
+ /* this is a hybrid board, initialize to analog mode
+ * and configure firmware eeprom address
+ */
{
u8 data[] = { 0x3c, 0x33, 0x68};
struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
i2c_transfer(&dev->i2c_adap, &msg, 1);
}
break;
+ case SAA7134_BOARD_FLYDVB_TRIO:
+ {
+ u8 data[] = { 0x3c, 0x33, 0x62};
+ struct i2c_msg msg = {.addr=0x09, .flags=0, .buf=data, .len = sizeof(data)};
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ }
+ break;
+ case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
+ /* make the tda10046 find its eeprom */
+ {
+ u8 data[] = { 0x3c, 0x33, 0x62};
+ struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ }
+ break;
+ case SAA7134_BOARD_KWORLD_ATSC110:
+ {
+ /* enable tuner */
+ int i;
+ static const u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 };
+ dev->i2c_client.addr = 0x0a;
+ for (i = 0; i < 5; i++)
+ if (2 != i2c_master_send(&dev->i2c_client,&buffer[i*2],2))
+ printk(KERN_WARNING "%s: Unable to enable tuner(%i).\n",
+ dev->name, i);
+ }
+ break;
}
return 0;
}
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 028904bd94a..58e568d7d2e 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -66,6 +66,11 @@ static unsigned int latency = UNSET;
module_param(latency, int, 0444);
MODULE_PARM_DESC(latency,"pci latency timer");
+int saa7134_no_overlay=-1;
+module_param_named(no_overlay, saa7134_no_overlay, int, 0444);
+MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)"
+ " [some VIA/SIS chipsets are known to have problem with overlay]");
+
static unsigned int video_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
static unsigned int vbi_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
static unsigned int radio_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
@@ -251,8 +256,7 @@ void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt)
void saa7134_dma_free(struct saa7134_dev *dev,struct saa7134_buf *buf)
{
- if (in_interrupt())
- BUG();
+ BUG_ON(in_interrupt());
videobuf_waiton(&buf->vb,0,0);
videobuf_dma_pci_unmap(dev->pci, &buf->vb.dma);
@@ -613,7 +617,7 @@ static int saa7134_hwinit1(struct saa7134_dev *dev)
saa_writel(SAA7134_IRQ1, 0);
saa_writel(SAA7134_IRQ2, 0);
- init_MUTEX(&dev->lock);
+ mutex_init(&dev->lock);
spin_lock_init(&dev->slock);
saa7134_track_gpio(dev,"pre-init");
@@ -835,6 +839,22 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
latency = 0x0A;
}
#endif
+ if (pci_pci_problems & PCIPCI_FAIL) {
+ printk(KERN_INFO "%s: quirk: this driver and your "
+ "chipset may not work together"
+ " in overlay mode.\n",dev->name);
+ if (!saa7134_no_overlay) {
+ printk(KERN_INFO "%s: quirk: overlay "
+ "mode will be disabled.\n",
+ dev->name);
+ saa7134_no_overlay = 1;
+ } else {
+ printk(KERN_INFO "%s: quirk: overlay "
+ "mode will be forced. Use this"
+ " option at your own risk.\n",
+ dev->name);
+ }
+ }
}
if (UNSET != latency) {
printk(KERN_INFO "%s: setting pci latency timer to %d\n",
@@ -937,6 +957,11 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
v4l2_prio_init(&dev->prio);
/* register v4l devices */
+ if (saa7134_no_overlay <= 0) {
+ saa7134_video_template.type |= VID_TYPE_OVERLAY;
+ } else {
+ printk("bttv: Overlay support disabled.\n");
+ }
dev->video_dev = vdev_init(dev,&saa7134_video_template,"video");
err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER,
video_nr[dev->nr]);
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 9db8e13f21c..86cfdb8514c 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -32,6 +32,7 @@
#include "saa7134-reg.h"
#include "saa7134.h"
#include <media/v4l2-common.h>
+#include "dvb-pll.h"
#ifdef HAVE_MT352
# include "mt352.h"
@@ -42,7 +43,6 @@
#endif
#ifdef HAVE_NXT200X
# include "nxt200x.h"
-# include "dvb-pll.h"
#endif
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
@@ -114,6 +114,24 @@ static int mt352_pinnacle_init(struct dvb_frontend* fe)
return 0;
}
+static int mt352_aver777_init(struct dvb_frontend* fe)
+{
+ static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x2d };
+ static u8 reset [] = { RESET, 0x80 };
+ static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
+ static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0xa0 };
+ static u8 capt_range_cfg[] = { CAPT_RANGE, 0x33 };
+
+ mt352_write(fe, clock_config, sizeof(clock_config));
+ udelay(200);
+ mt352_write(fe, reset, sizeof(reset));
+ mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
+ mt352_write(fe, agc_cfg, sizeof(agc_cfg));
+ mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+ return 0;
+}
+
static int mt352_pinnacle_pll_set(struct dvb_frontend* fe,
struct dvb_frontend_parameters* params,
u8* pllbuf)
@@ -146,6 +164,15 @@ static int mt352_pinnacle_pll_set(struct dvb_frontend* fe,
return 0;
}
+static int mt352_aver777_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8* pllbuf)
+{
+ pllbuf[0] = 0xc2;
+ dvb_pll_configure(&dvb_pll_philips_td1316, pllbuf+1,
+ params->frequency,
+ params->u.ofdm.bandwidth);
+ return 0;
+}
+
static struct mt352_config pinnacle_300i = {
.demod_address = 0x3c >> 1,
.adc_clock = 20333,
@@ -154,6 +181,12 @@ static struct mt352_config pinnacle_300i = {
.demod_init = mt352_pinnacle_init,
.pll_set = mt352_pinnacle_pll_set,
};
+
+static struct mt352_config avermedia_777 = {
+ .demod_address = 0xf,
+ .demod_init = mt352_aver777_init,
+ .pll_set = mt352_aver777_pll_set,
+};
#endif
/* ------------------------------------------------------------------ */
@@ -781,7 +814,7 @@ static int philips_tiger_pll_set(struct dvb_frontend *fe, struct dvb_frontend_pa
tda8290_msg.buf = tda8290_open;
i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1);
return ret;
-};
+}
static int philips_tiger_dvb_mode(struct dvb_frontend *fe)
{
@@ -817,6 +850,110 @@ static struct tda1004x_config philips_tiger_config = {
.request_firmware = NULL,
};
+/* ------------------------------------------------------------------ */
+
+static int lifeview_trio_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ int ret;
+
+ ret = philips_tda827xa_pll_set(0x60, fe, params);
+ return ret;
+}
+
+static int lifeview_trio_dvb_mode(struct dvb_frontend *fe)
+{
+ return 0;
+}
+
+static void lifeview_trio_analog_mode(struct dvb_frontend *fe)
+{
+ philips_tda827xa_pll_sleep(0x60, fe);
+}
+
+static struct tda1004x_config lifeview_trio_config = {
+ .demod_address = 0x09,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X_GPL,
+ .if_freq = TDA10046_FREQ_045,
+ .pll_init = lifeview_trio_dvb_mode,
+ .pll_set = lifeview_trio_pll_set,
+ .pll_sleep = lifeview_trio_analog_mode,
+ .request_firmware = NULL,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int ads_duo_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ int ret;
+
+ ret = philips_tda827xa_pll_set(0x61, fe, params);
+ return ret;
+}
+
+static int ads_duo_dvb_mode(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ /* route TDA8275a AGC input to the channel decoder */
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x60);
+ return 0;
+}
+
+static void ads_duo_analog_mode(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ /* route TDA8275a AGC input to the analog IF chip*/
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x20);
+ philips_tda827xa_pll_sleep( 0x61, fe);
+}
+
+static struct tda1004x_config ads_tech_duo_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X_GPL,
+ .if_freq = TDA10046_FREQ_045,
+ .pll_init = ads_duo_dvb_mode,
+ .pll_set = ads_duo_pll_set,
+ .pll_sleep = ads_duo_analog_mode,
+ .request_firmware = NULL,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int tevion_dvb220rf_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ int ret;
+ ret = philips_tda827xa_pll_set(0x60, fe, params);
+ return ret;
+}
+
+static int tevion_dvb220rf_pll_init(struct dvb_frontend *fe)
+{
+ return 0;
+}
+
+static void tevion_dvb220rf_pll_sleep(struct dvb_frontend *fe)
+{
+ philips_tda827xa_pll_sleep( 0x61, fe);
+}
+
+static struct tda1004x_config tevion_dvbt220rf_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .if_freq = TDA10046_FREQ_045,
+ .pll_init = tevion_dvb220rf_pll_init,
+ .pll_set = tevion_dvb220rf_pll_set,
+ .pll_sleep = tevion_dvb220rf_pll_sleep,
+ .request_firmware = NULL,
+};
+
#endif
/* ------------------------------------------------------------------ */
@@ -827,6 +964,22 @@ static struct nxt200x_config avertvhda180 = {
.pll_address = 0x61,
.pll_desc = &dvb_pll_tdhu2,
};
+
+static int nxt200x_set_pll_input(u8 *buf, int input)
+{
+ if (input)
+ buf[3] |= 0x08;
+ else
+ buf[3] &= ~0x08;
+ return 0;
+}
+
+static struct nxt200x_config kworldatsc110 = {
+ .demod_address = 0x0a,
+ .pll_address = 0x61,
+ .pll_desc = &dvb_pll_tuv1236d,
+ .set_pll_input = nxt200x_set_pll_input,
+};
#endif
/* ------------------------------------------------------------------ */
@@ -851,6 +1004,12 @@ static int dvb_init(struct saa7134_dev *dev)
dev->dvb.frontend = mt352_attach(&pinnacle_300i,
&dev->i2c_adap);
break;
+
+ case SAA7134_BOARD_AVERMEDIA_777:
+ printk("%s: avertv 777 dvb setup\n",dev->name);
+ dev->dvb.frontend = mt352_attach(&avermedia_777,
+ &dev->i2c_adap);
+ break;
#endif
#ifdef HAVE_TDA1004X
case SAA7134_BOARD_MD7134:
@@ -889,11 +1048,30 @@ static int dvb_init(struct saa7134_dev *dev)
dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
&dev->i2c_adap);
break;
+ case SAA7134_BOARD_FLYDVBT_LR301:
+ dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
+ &dev->i2c_adap);
+ break;
+ case SAA7134_BOARD_FLYDVB_TRIO:
+ dev->dvb.frontend = tda10046_attach(&lifeview_trio_config,
+ &dev->i2c_adap);
+ break;
+ case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
+ dev->dvb.frontend = tda10046_attach(&ads_tech_duo_config,
+ &dev->i2c_adap);
+ break;
+ case SAA7134_BOARD_TEVION_DVBT_220RF:
+ dev->dvb.frontend = tda10046_attach(&tevion_dvbt220rf_config,
+ &dev->i2c_adap);
+ break;
#endif
#ifdef HAVE_NXT200X
case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
dev->dvb.frontend = nxt200x_attach(&avertvhda180, &dev->i2c_adap);
break;
+ case SAA7134_BOARD_KWORLD_ATSC110:
+ dev->dvb.frontend = nxt200x_attach(&kworldatsc110, &dev->i2c_adap);
+ break;
#endif
default:
printk("%s: Huh? unknown DVB card?\n",dev->name);
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index bd4c389d4c3..1d972edb3be 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -89,7 +89,7 @@ static int ts_open(struct inode *inode, struct file *file)
dprintk("open minor=%d\n",minor);
err = -EBUSY;
- if (down_trylock(&dev->empress_tsq.lock))
+ if (!mutex_trylock(&dev->empress_tsq.lock))
goto done;
if (dev->empress_users)
goto done_up;
@@ -99,7 +99,7 @@ static int ts_open(struct inode *inode, struct file *file)
err = 0;
done_up:
- up(&dev->empress_tsq.lock);
+ mutex_unlock(&dev->empress_tsq.lock);
done:
return err;
}
@@ -110,7 +110,7 @@ static int ts_release(struct inode *inode, struct file *file)
if (dev->empress_tsq.streaming)
videobuf_streamoff(&dev->empress_tsq);
- down(&dev->empress_tsq.lock);
+ mutex_lock(&dev->empress_tsq.lock);
if (dev->empress_tsq.reading)
videobuf_read_stop(&dev->empress_tsq);
videobuf_mmap_free(&dev->empress_tsq);
@@ -119,7 +119,7 @@ static int ts_release(struct inode *inode, struct file *file)
/* stop the encoder */
ts_reset_encoder(dev);
- up(&dev->empress_tsq.lock);
+ mutex_unlock(&dev->empress_tsq.lock);
return 0;
}
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 82d28cbf289..1426e4c8602 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -42,485 +42,6 @@ MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
#define i2cdprintk(fmt, arg...) if (ir_debug) \
printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
-/* ---------------------------------------------------------------------- */
-
-static IR_KEYTAB_TYPE flyvideo_codes[IR_KEYTAB_SIZE] = {
- [ 15 ] = KEY_KP0,
- [ 3 ] = KEY_KP1,
- [ 4 ] = KEY_KP2,
- [ 5 ] = KEY_KP3,
- [ 7 ] = KEY_KP4,
- [ 8 ] = KEY_KP5,
- [ 9 ] = KEY_KP6,
- [ 11 ] = KEY_KP7,
- [ 12 ] = KEY_KP8,
- [ 13 ] = KEY_KP9,
-
- [ 14 ] = KEY_MODE, // Air/Cable
- [ 17 ] = KEY_VIDEO, // Video
- [ 21 ] = KEY_AUDIO, // Audio
- [ 0 ] = KEY_POWER, // Power
- [ 24 ] = KEY_TUNER, // AV Source
- [ 2 ] = KEY_ZOOM, // Fullscreen
- [ 26 ] = KEY_LANGUAGE, // Stereo
- [ 27 ] = KEY_MUTE, // Mute
- [ 20 ] = KEY_VOLUMEUP, // Volume +
- [ 23 ] = KEY_VOLUMEDOWN, // Volume -
- [ 18 ] = KEY_CHANNELUP, // Channel +
- [ 19 ] = KEY_CHANNELDOWN, // Channel -
- [ 6 ] = KEY_AGAIN, // Recall
- [ 16 ] = KEY_ENTER, // Enter
-};
-
-
-static IR_KEYTAB_TYPE cinergy_codes[IR_KEYTAB_SIZE] = {
- [ 0 ] = KEY_KP0,
- [ 1 ] = KEY_KP1,
- [ 2 ] = KEY_KP2,
- [ 3 ] = KEY_KP3,
- [ 4 ] = KEY_KP4,
- [ 5 ] = KEY_KP5,
- [ 6 ] = KEY_KP6,
- [ 7 ] = KEY_KP7,
- [ 8 ] = KEY_KP8,
- [ 9 ] = KEY_KP9,
-
- [ 0x0a ] = KEY_POWER,
- [ 0x0b ] = KEY_PROG1, // app
- [ 0x0c ] = KEY_ZOOM, // zoom/fullscreen
- [ 0x0d ] = KEY_CHANNELUP, // channel
- [ 0x0e ] = KEY_CHANNELDOWN, // channel-
- [ 0x0f ] = KEY_VOLUMEUP,
- [ 0x10 ] = KEY_VOLUMEDOWN,
- [ 0x11 ] = KEY_TUNER, // AV
- [ 0x12 ] = KEY_NUMLOCK, // -/--
- [ 0x13 ] = KEY_AUDIO, // audio
- [ 0x14 ] = KEY_MUTE,
- [ 0x15 ] = KEY_UP,
- [ 0x16 ] = KEY_DOWN,
- [ 0x17 ] = KEY_LEFT,
- [ 0x18 ] = KEY_RIGHT,
- [ 0x19 ] = BTN_LEFT,
- [ 0x1a ] = BTN_RIGHT,
- [ 0x1b ] = KEY_WWW, // text
- [ 0x1c ] = KEY_REWIND,
- [ 0x1d ] = KEY_FORWARD,
- [ 0x1e ] = KEY_RECORD,
- [ 0x1f ] = KEY_PLAY,
- [ 0x20 ] = KEY_PREVIOUSSONG,
- [ 0x21 ] = KEY_NEXTSONG,
- [ 0x22 ] = KEY_PAUSE,
- [ 0x23 ] = KEY_STOP,
-};
-
-/* Alfons Geser <a.geser@cox.net>
- * updates from Job D. R. Borges <jobdrb@ig.com.br> */
-static IR_KEYTAB_TYPE eztv_codes[IR_KEYTAB_SIZE] = {
- [ 18 ] = KEY_POWER,
- [ 1 ] = KEY_TV, // DVR
- [ 21 ] = KEY_DVD, // DVD
- [ 23 ] = KEY_AUDIO, // music
- // DVR mode / DVD mode / music mode
-
- [ 27 ] = KEY_MUTE, // mute
- [ 2 ] = KEY_LANGUAGE, // MTS/SAP / audio / autoseek
- [ 30 ] = KEY_SUBTITLE, // closed captioning / subtitle / seek
- [ 22 ] = KEY_ZOOM, // full screen
- [ 28 ] = KEY_VIDEO, // video source / eject / delall
- [ 29 ] = KEY_RESTART, // playback / angle / del
- [ 47 ] = KEY_SEARCH, // scan / menu / playlist
- [ 48 ] = KEY_CHANNEL, // CH surfing / bookmark / memo
-
- [ 49 ] = KEY_HELP, // help
- [ 50 ] = KEY_MODE, // num/memo
- [ 51 ] = KEY_ESC, // cancel
-
- [ 12 ] = KEY_UP, // up
- [ 16 ] = KEY_DOWN, // down
- [ 8 ] = KEY_LEFT, // left
- [ 4 ] = KEY_RIGHT, // right
- [ 3 ] = KEY_SELECT, // select
-
- [ 31 ] = KEY_REWIND, // rewind
- [ 32 ] = KEY_PLAYPAUSE, // play/pause
- [ 41 ] = KEY_FORWARD, // forward
- [ 20 ] = KEY_AGAIN, // repeat
- [ 43 ] = KEY_RECORD, // recording
- [ 44 ] = KEY_STOP, // stop
- [ 45 ] = KEY_PLAY, // play
- [ 46 ] = KEY_SHUFFLE, // snapshot / shuffle
-
- [ 0 ] = KEY_KP0,
- [ 5 ] = KEY_KP1,
- [ 6 ] = KEY_KP2,
- [ 7 ] = KEY_KP3,
- [ 9 ] = KEY_KP4,
- [ 10 ] = KEY_KP5,
- [ 11 ] = KEY_KP6,
- [ 13 ] = KEY_KP7,
- [ 14 ] = KEY_KP8,
- [ 15 ] = KEY_KP9,
-
- [ 42 ] = KEY_VOLUMEUP,
- [ 17 ] = KEY_VOLUMEDOWN,
- [ 24 ] = KEY_CHANNELUP, // CH.tracking up
- [ 25 ] = KEY_CHANNELDOWN, // CH.tracking down
-
- [ 19 ] = KEY_KPENTER, // enter
- [ 33 ] = KEY_KPDOT, // . (decimal dot)
-};
-
-static IR_KEYTAB_TYPE avacssmart_codes[IR_KEYTAB_SIZE] = {
- [ 30 ] = KEY_POWER, // power
- [ 28 ] = KEY_SEARCH, // scan
- [ 7 ] = KEY_SELECT, // source
-
- [ 22 ] = KEY_VOLUMEUP,
- [ 20 ] = KEY_VOLUMEDOWN,
- [ 31 ] = KEY_CHANNELUP,
- [ 23 ] = KEY_CHANNELDOWN,
- [ 24 ] = KEY_MUTE,
-
- [ 2 ] = KEY_KP0,
- [ 1 ] = KEY_KP1,
- [ 11 ] = KEY_KP2,
- [ 27 ] = KEY_KP3,
- [ 5 ] = KEY_KP4,
- [ 9 ] = KEY_KP5,
- [ 21 ] = KEY_KP6,
- [ 6 ] = KEY_KP7,
- [ 10 ] = KEY_KP8,
- [ 18 ] = KEY_KP9,
- [ 16 ] = KEY_KPDOT,
-
- [ 3 ] = KEY_TUNER, // tv/fm
- [ 4 ] = KEY_REWIND, // fm tuning left or function left
- [ 12 ] = KEY_FORWARD, // fm tuning right or function right
-
- [ 0 ] = KEY_RECORD,
- [ 8 ] = KEY_STOP,
- [ 17 ] = KEY_PLAY,
-
- [ 25 ] = KEY_ZOOM,
- [ 14 ] = KEY_MENU, // function
- [ 19 ] = KEY_AGAIN, // recall
- [ 29 ] = KEY_RESTART, // reset
- [ 26 ] = KEY_SHUFFLE, // snapshot/shuffle
-
-// FIXME
- [ 13 ] = KEY_F21, // mts
- [ 15 ] = KEY_F22, // min
-};
-
-/* Alex Hermann <gaaf@gmx.net> */
-static IR_KEYTAB_TYPE md2819_codes[IR_KEYTAB_SIZE] = {
- [ 40 ] = KEY_KP1,
- [ 24 ] = KEY_KP2,
- [ 56 ] = KEY_KP3,
- [ 36 ] = KEY_KP4,
- [ 20 ] = KEY_KP5,
- [ 52 ] = KEY_KP6,
- [ 44 ] = KEY_KP7,
- [ 28 ] = KEY_KP8,
- [ 60 ] = KEY_KP9,
- [ 34 ] = KEY_KP0,
-
- [ 32 ] = KEY_TV, // TV/FM
- [ 16 ] = KEY_CD, // CD
- [ 48 ] = KEY_TEXT, // TELETEXT
- [ 0 ] = KEY_POWER, // POWER
-
- [ 8 ] = KEY_VIDEO, // VIDEO
- [ 4 ] = KEY_AUDIO, // AUDIO
- [ 12 ] = KEY_ZOOM, // FULL SCREEN
-
- [ 18 ] = KEY_SUBTITLE, // DISPLAY - ???
- [ 50 ] = KEY_REWIND, // LOOP - ???
- [ 2 ] = KEY_PRINT, // PREVIEW - ???
-
- [ 42 ] = KEY_SEARCH, // AUTOSCAN
- [ 26 ] = KEY_SLEEP, // FREEZE - ???
- [ 58 ] = KEY_SHUFFLE, // SNAPSHOT - ???
- [ 10 ] = KEY_MUTE, // MUTE
-
- [ 38 ] = KEY_RECORD, // RECORD
- [ 22 ] = KEY_PAUSE, // PAUSE
- [ 54 ] = KEY_STOP, // STOP
- [ 6 ] = KEY_PLAY, // PLAY
-
- [ 46 ] = KEY_RED, // <RED>
- [ 33 ] = KEY_GREEN, // <GREEN>
- [ 14 ] = KEY_YELLOW, // <YELLOW>
- [ 1 ] = KEY_BLUE, // <BLUE>
-
- [ 30 ] = KEY_VOLUMEDOWN, // VOLUME-
- [ 62 ] = KEY_VOLUMEUP, // VOLUME+
- [ 17 ] = KEY_CHANNELDOWN, // CHANNEL/PAGE-
- [ 49 ] = KEY_CHANNELUP // CHANNEL/PAGE+
-};
-
-static IR_KEYTAB_TYPE videomate_tv_pvr_codes[IR_KEYTAB_SIZE] = {
- [ 20 ] = KEY_MUTE,
- [ 36 ] = KEY_ZOOM,
-
- [ 1 ] = KEY_DVD,
- [ 35 ] = KEY_RADIO,
- [ 0 ] = KEY_TV,
-
- [ 10 ] = KEY_REWIND,
- [ 8 ] = KEY_PLAYPAUSE,
- [ 15 ] = KEY_FORWARD,
-
- [ 2 ] = KEY_PREVIOUS,
- [ 7 ] = KEY_STOP,
- [ 6 ] = KEY_NEXT,
-
- [ 12 ] = KEY_UP,
- [ 14 ] = KEY_DOWN,
- [ 11 ] = KEY_LEFT,
- [ 13 ] = KEY_RIGHT,
- [ 17 ] = KEY_OK,
-
- [ 3 ] = KEY_MENU,
- [ 9 ] = KEY_SETUP,
- [ 5 ] = KEY_VIDEO,
- [ 34 ] = KEY_CHANNEL,
-
- [ 18 ] = KEY_VOLUMEUP,
- [ 21 ] = KEY_VOLUMEDOWN,
- [ 16 ] = KEY_CHANNELUP,
- [ 19 ] = KEY_CHANNELDOWN,
-
- [ 4 ] = KEY_RECORD,
-
- [ 22 ] = KEY_KP1,
- [ 23 ] = KEY_KP2,
- [ 24 ] = KEY_KP3,
- [ 25 ] = KEY_KP4,
- [ 26 ] = KEY_KP5,
- [ 27 ] = KEY_KP6,
- [ 28 ] = KEY_KP7,
- [ 29 ] = KEY_KP8,
- [ 30 ] = KEY_KP9,
- [ 31 ] = KEY_KP0,
-
- [ 32 ] = KEY_LANGUAGE,
- [ 33 ] = KEY_SLEEP,
-};
-
-/* Michael Tokarev <mjt@tls.msk.ru>
- http://www.corpit.ru/mjt/beholdTV/remote_control.jpg
- keytable is used by MANLI MTV00[12] and BeholdTV 40[13] at
- least, and probably other cards too.
- The "ascii-art picture" below (in comments, first row
- is the keycode in hex, and subsequent row(s) shows
- the button labels (several variants when appropriate)
- helps to descide which keycodes to assign to the buttons.
- */
-static IR_KEYTAB_TYPE manli_codes[IR_KEYTAB_SIZE] = {
-
- /* 0x1c 0x12 *
- * FUNCTION POWER *
- * FM (|) *
- * */
- [ 0x1c ] = KEY_RADIO, /*XXX*/
- [ 0x12 ] = KEY_POWER,
-
- /* 0x01 0x02 0x03 *
- * 1 2 3 *
- * *
- * 0x04 0x05 0x06 *
- * 4 5 6 *
- * *
- * 0x07 0x08 0x09 *
- * 7 8 9 *
- * */
- [ 0x01 ] = KEY_KP1,
- [ 0x02 ] = KEY_KP2,
- [ 0x03 ] = KEY_KP3,
- [ 0x04 ] = KEY_KP4,
- [ 0x05 ] = KEY_KP5,
- [ 0x06 ] = KEY_KP6,
- [ 0x07 ] = KEY_KP7,
- [ 0x08 ] = KEY_KP8,
- [ 0x09 ] = KEY_KP9,
-
- /* 0x0a 0x00 0x17 *
- * RECALL 0 +100 *
- * PLUS *
- * */
- [ 0x0a ] = KEY_AGAIN, /*XXX KEY_REWIND? */
- [ 0x00 ] = KEY_KP0,
- [ 0x17 ] = KEY_DIGITS, /*XXX*/
-
- /* 0x14 0x10 *
- * MENU INFO *
- * OSD */
- [ 0x14 ] = KEY_MENU,
- [ 0x10 ] = KEY_INFO,
-
- /* 0x0b *
- * Up *
- * *
- * 0x18 0x16 0x0c *
- * Left Ok Right *
- * *
- * 0x015 *
- * Down *
- * */
- [ 0x0b ] = KEY_UP, /*XXX KEY_SCROLLUP? */
- [ 0x18 ] = KEY_LEFT, /*XXX KEY_BACK? */
- [ 0x16 ] = KEY_OK, /*XXX KEY_SELECT? KEY_ENTER? */
- [ 0x0c ] = KEY_RIGHT, /*XXX KEY_FORWARD? */
- [ 0x15 ] = KEY_DOWN, /*XXX KEY_SCROLLDOWN? */
-
- /* 0x11 0x0d *
- * TV/AV MODE *
- * SOURCE STEREO *
- * */
- [ 0x11 ] = KEY_TV, /*XXX*/
- [ 0x0d ] = KEY_MODE, /*XXX there's no KEY_STEREO */
-
- /* 0x0f 0x1b 0x1a *
- * AUDIO Vol+ Chan+ *
- * TIMESHIFT??? *
- * *
- * 0x0e 0x1f 0x1e *
- * SLEEP Vol- Chan- *
- * */
- [ 0x0f ] = KEY_AUDIO,
- [ 0x1b ] = KEY_VOLUMEUP,
- [ 0x1a ] = KEY_CHANNELUP,
- [ 0x0e ] = KEY_SLEEP, /*XXX maybe KEY_PAUSE */
- [ 0x1f ] = KEY_VOLUMEDOWN,
- [ 0x1e ] = KEY_CHANNELDOWN,
-
- /* 0x13 0x19 *
- * MUTE SNAPSHOT*
- * */
- [ 0x13 ] = KEY_MUTE,
- [ 0x19 ] = KEY_RECORD, /*XXX*/
-
- // 0x1d unused ?
-};
-
-
-/* Mike Baikov <mike@baikov.com> */
-static IR_KEYTAB_TYPE gotview7135_codes[IR_KEYTAB_SIZE] = {
-
- [ 33 ] = KEY_POWER,
- [ 105] = KEY_TV,
- [ 51 ] = KEY_KP0,
- [ 81 ] = KEY_KP1,
- [ 49 ] = KEY_KP2,
- [ 113] = KEY_KP3,
- [ 59 ] = KEY_KP4,
- [ 88 ] = KEY_KP5,
- [ 65 ] = KEY_KP6,
- [ 72 ] = KEY_KP7,
- [ 48 ] = KEY_KP8,
- [ 83 ] = KEY_KP9,
- [ 115] = KEY_AGAIN, /* LOOP */
- [ 10 ] = KEY_AUDIO,
- [ 97 ] = KEY_PRINT, /* PREVIEW */
- [ 122] = KEY_VIDEO,
- [ 32 ] = KEY_CHANNELUP,
- [ 64 ] = KEY_CHANNELDOWN,
- [ 24 ] = KEY_VOLUMEDOWN,
- [ 80 ] = KEY_VOLUMEUP,
- [ 16 ] = KEY_MUTE,
- [ 74 ] = KEY_SEARCH,
- [ 123] = KEY_SHUFFLE, /* SNAPSHOT */
- [ 34 ] = KEY_RECORD,
- [ 98 ] = KEY_STOP,
- [ 120] = KEY_PLAY,
- [ 57 ] = KEY_REWIND,
- [ 89 ] = KEY_PAUSE,
- [ 25 ] = KEY_FORWARD,
- [ 9 ] = KEY_ZOOM,
-
- [ 82 ] = KEY_F21, /* LIVE TIMESHIFT */
- [ 26 ] = KEY_F22, /* MIN TIMESHIFT */
- [ 58 ] = KEY_F23, /* TIMESHIFT */
- [ 112] = KEY_F24, /* NORMAL TIMESHIFT */
-};
-
-static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = {
- [ 0x3 ] = KEY_POWER,
- [ 0x6f ] = KEY_MUTE,
- [ 0x10 ] = KEY_BACKSPACE, /* Recall */
-
- [ 0x11 ] = KEY_KP0,
- [ 0x4 ] = KEY_KP1,
- [ 0x5 ] = KEY_KP2,
- [ 0x6 ] = KEY_KP3,
- [ 0x8 ] = KEY_KP4,
- [ 0x9 ] = KEY_KP5,
- [ 0xa ] = KEY_KP6,
- [ 0xc ] = KEY_KP7,
- [ 0xd ] = KEY_KP8,
- [ 0xe ] = KEY_KP9,
- [ 0x12 ] = KEY_KPDOT, /* 100+ */
-
- [ 0x7 ] = KEY_VOLUMEUP,
- [ 0xb ] = KEY_VOLUMEDOWN,
- [ 0x1a ] = KEY_KPPLUS,
- [ 0x18 ] = KEY_KPMINUS,
- [ 0x15 ] = KEY_UP,
- [ 0x1d ] = KEY_DOWN,
- [ 0xf ] = KEY_CHANNELUP,
- [ 0x13 ] = KEY_CHANNELDOWN,
- [ 0x48 ] = KEY_ZOOM,
-
- [ 0x1b ] = KEY_VIDEO, /* Video source */
- [ 0x49 ] = KEY_LANGUAGE, /* MTS Select */
- [ 0x19 ] = KEY_SEARCH, /* Auto Scan */
-
- [ 0x4b ] = KEY_RECORD,
- [ 0x46 ] = KEY_PLAY,
- [ 0x45 ] = KEY_PAUSE, /* Pause */
- [ 0x44 ] = KEY_STOP,
- [ 0x40 ] = KEY_FORWARD, /* Forward ? */
- [ 0x42 ] = KEY_REWIND, /* Backward ? */
-
-};
-
-/* Mapping for the 28 key remote control as seen at
- http://www.sednacomputer.com/photo/cardbus-tv.jpg
- Pavel Mihaylov <bin@bash.info> */
-static IR_KEYTAB_TYPE pctv_sedna_codes[IR_KEYTAB_SIZE] = {
- [ 0 ] = KEY_KP0,
- [ 1 ] = KEY_KP1,
- [ 2 ] = KEY_KP2,
- [ 3 ] = KEY_KP3,
- [ 4 ] = KEY_KP4,
- [ 5 ] = KEY_KP5,
- [ 6 ] = KEY_KP6,
- [ 7 ] = KEY_KP7,
- [ 8 ] = KEY_KP8,
- [ 9 ] = KEY_KP9,
-
- [ 0x0a ] = KEY_AGAIN, /* Recall */
- [ 0x0b ] = KEY_CHANNELUP,
- [ 0x0c ] = KEY_VOLUMEUP,
- [ 0x0d ] = KEY_MODE, /* Stereo */
- [ 0x0e ] = KEY_STOP,
- [ 0x0f ] = KEY_PREVIOUSSONG,
- [ 0x10 ] = KEY_ZOOM,
- [ 0x11 ] = KEY_TUNER, /* Source */
- [ 0x12 ] = KEY_POWER,
- [ 0x13 ] = KEY_MUTE,
- [ 0x15 ] = KEY_CHANNELDOWN,
- [ 0x18 ] = KEY_VOLUMEDOWN,
- [ 0x19 ] = KEY_SHUFFLE, /* Snapshot */
- [ 0x1a ] = KEY_NEXTSONG,
- [ 0x1b ] = KEY_TEXT, /* Time Shift */
- [ 0x1c ] = KEY_RADIO, /* FM Radio */
- [ 0x1d ] = KEY_RECORD,
- [ 0x1e ] = KEY_PAUSE,
-};
-
-
/* -------------------- GPIO generic keycode builder -------------------- */
static int build_key(struct saa7134_dev *dev)
@@ -628,27 +149,27 @@ int saa7134_input_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_FLYVIDEO3000:
case SAA7134_BOARD_FLYTVPLATINUM_FM:
case SAA7134_BOARD_FLYTVPLATINUM_MINI2:
- ir_codes = flyvideo_codes;
+ ir_codes = ir_codes_flyvideo;
mask_keycode = 0xEC00000;
mask_keydown = 0x0040000;
break;
case SAA7134_BOARD_CINERGY400:
case SAA7134_BOARD_CINERGY600:
case SAA7134_BOARD_CINERGY600_MK3:
- ir_codes = cinergy_codes;
+ ir_codes = ir_codes_cinergy;
mask_keycode = 0x00003f;
mask_keyup = 0x040000;
break;
case SAA7134_BOARD_ECS_TVP3XP:
case SAA7134_BOARD_ECS_TVP3XP_4CB5:
- ir_codes = eztv_codes;
+ ir_codes = ir_codes_eztv;
mask_keycode = 0x00017c;
mask_keyup = 0x000002;
polling = 50; // ms
break;
case SAA7134_BOARD_KWORLD_XPERT:
case SAA7134_BOARD_AVACSSMARTTV:
- ir_codes = avacssmart_codes;
+ ir_codes = ir_codes_pixelview;
mask_keycode = 0x00001F;
mask_keyup = 0x000020;
polling = 50; // ms
@@ -660,7 +181,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
- ir_codes = md2819_codes;
+ ir_codes = ir_codes_avermedia;
mask_keycode = 0x0007C8;
mask_keydown = 0x000010;
polling = 50; // ms
@@ -669,7 +190,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
break;
case SAA7134_BOARD_KWORLD_TERMINATOR:
- ir_codes = avacssmart_codes;
+ ir_codes = ir_codes_pixelview;
mask_keycode = 0x00001f;
mask_keyup = 0x000060;
polling = 50; // ms
@@ -677,19 +198,19 @@ int saa7134_input_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_MANLI_MTV001:
case SAA7134_BOARD_MANLI_MTV002:
case SAA7134_BOARD_BEHOLD_409FM:
- ir_codes = manli_codes;
+ ir_codes = ir_codes_manli;
mask_keycode = 0x001f00;
mask_keyup = 0x004000;
polling = 50; // ms
break;
case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
- ir_codes = pctv_sedna_codes;
+ ir_codes = ir_codes_pctv_sedna;
mask_keycode = 0x001f00;
mask_keyup = 0x004000;
polling = 50; // ms
break;
case SAA7134_BOARD_GOTVIEW_7135:
- ir_codes = gotview7135_codes;
+ ir_codes = ir_codes_gotview7135;
mask_keycode = 0x0003EC;
mask_keyup = 0x008000;
mask_keydown = 0x000010;
@@ -698,17 +219,23 @@ int saa7134_input_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_VIDEOMATE_TV_PVR:
case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
- ir_codes = videomate_tv_pvr_codes;
+ ir_codes = ir_codes_videomate_tv_pvr;
mask_keycode = 0x00003F;
mask_keyup = 0x400000;
polling = 50; // ms
break;
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
case SAA7134_BOARD_VIDEOMATE_DVBT_200:
- ir_codes = videomate_tv_pvr_codes;
+ ir_codes = ir_codes_videomate_tv_pvr;
mask_keycode = 0x003F00;
mask_keyup = 0x040000;
break;
+ case SAA7134_BOARD_FLYDVBT_LR301:
+ case SAA7134_BOARD_FLYDVBTDUO:
+ ir_codes = ir_codes_flydvb;
+ mask_keycode = 0x0001F00;
+ mask_keydown = 0x0040000;
+ break;
}
if (NULL == ir_codes) {
printk("%s: Oops: IR config error [card=%d]\n",
diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c
index 7448e386a80..d79d05f8870 100644
--- a/drivers/media/video/saa7134/saa7134-oss.c
+++ b/drivers/media/video/saa7134/saa7134-oss.c
@@ -84,8 +84,7 @@ static int dsp_buffer_init(struct saa7134_dev *dev)
{
int err;
- if (!dev->dmasound.bufsize)
- BUG();
+ BUG_ON(!dev->dmasound.bufsize);
videobuf_dma_init(&dev->dmasound.dma);
err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE,
(dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
@@ -96,8 +95,7 @@ static int dsp_buffer_init(struct saa7134_dev *dev)
static int dsp_buffer_free(struct saa7134_dev *dev)
{
- if (!dev->dmasound.blksize)
- BUG();
+ BUG_ON(!dev->dmasound.blksize);
videobuf_dma_free(&dev->dmasound.dma);
dev->dmasound.blocks = 0;
dev->dmasound.blksize = 0;
@@ -254,7 +252,7 @@ static int dsp_open(struct inode *inode, struct file *file)
if (NULL == dev)
return -ENODEV;
- down(&dev->dmasound.lock);
+ mutex_lock(&dev->dmasound.lock);
err = -EBUSY;
if (dev->dmasound.users_dsp)
goto fail1;
@@ -270,13 +268,13 @@ static int dsp_open(struct inode *inode, struct file *file)
if (0 != err)
goto fail2;
- up(&dev->dmasound.lock);
+ mutex_unlock(&dev->dmasound.lock);
return 0;
fail2:
dev->dmasound.users_dsp--;
fail1:
- up(&dev->dmasound.lock);
+ mutex_unlock(&dev->dmasound.lock);
return err;
}
@@ -284,13 +282,13 @@ static int dsp_release(struct inode *inode, struct file *file)
{
struct saa7134_dev *dev = file->private_data;
- down(&dev->dmasound.lock);
+ mutex_lock(&dev->dmasound.lock);
if (dev->dmasound.recording_on)
dsp_rec_stop(dev);
dsp_buffer_free(dev);
dev->dmasound.users_dsp--;
file->private_data = NULL;
- up(&dev->dmasound.lock);
+ mutex_unlock(&dev->dmasound.lock);
return 0;
}
@@ -304,7 +302,7 @@ static ssize_t dsp_read(struct file *file, char __user *buffer,
int err,ret = 0;
add_wait_queue(&dev->dmasound.wq, &wait);
- down(&dev->dmasound.lock);
+ mutex_lock(&dev->dmasound.lock);
while (count > 0) {
/* wait for data if needed */
if (0 == dev->dmasound.read_count) {
@@ -328,12 +326,12 @@ static ssize_t dsp_read(struct file *file, char __user *buffer,
ret = -EAGAIN;
break;
}
- up(&dev->dmasound.lock);
+ mutex_unlock(&dev->dmasound.lock);
set_current_state(TASK_INTERRUPTIBLE);
if (0 == dev->dmasound.read_count)
schedule();
set_current_state(TASK_RUNNING);
- down(&dev->dmasound.lock);
+ mutex_lock(&dev->dmasound.lock);
if (signal_pending(current)) {
if (0 == ret)
ret = -EINTR;
@@ -362,7 +360,7 @@ static ssize_t dsp_read(struct file *file, char __user *buffer,
if (dev->dmasound.read_offset == dev->dmasound.bufsize)
dev->dmasound.read_offset = 0;
}
- up(&dev->dmasound.lock);
+ mutex_unlock(&dev->dmasound.lock);
remove_wait_queue(&dev->dmasound.wq, &wait);
return ret;
}
@@ -435,13 +433,13 @@ static int dsp_ioctl(struct inode *inode, struct file *file,
case SNDCTL_DSP_STEREO:
if (get_user(val, p))
return -EFAULT;
- down(&dev->dmasound.lock);
+ mutex_lock(&dev->dmasound.lock);
dev->dmasound.channels = val ? 2 : 1;
if (dev->dmasound.recording_on) {
dsp_rec_stop(dev);
dsp_rec_start(dev);
}
- up(&dev->dmasound.lock);
+ mutex_unlock(&dev->dmasound.lock);
return put_user(dev->dmasound.channels-1, p);
case SNDCTL_DSP_CHANNELS:
@@ -449,13 +447,13 @@ static int dsp_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
if (val != 1 && val != 2)
return -EINVAL;
- down(&dev->dmasound.lock);
+ mutex_lock(&dev->dmasound.lock);
dev->dmasound.channels = val;
if (dev->dmasound.recording_on) {
dsp_rec_stop(dev);
dsp_rec_start(dev);
}
- up(&dev->dmasound.lock);
+ mutex_unlock(&dev->dmasound.lock);
/* fall through */
case SOUND_PCM_READ_CHANNELS:
return put_user(dev->dmasound.channels, p);
@@ -478,13 +476,13 @@ static int dsp_ioctl(struct inode *inode, struct file *file,
case AFMT_U16_BE:
case AFMT_S16_LE:
case AFMT_S16_BE:
- down(&dev->dmasound.lock);
+ mutex_lock(&dev->dmasound.lock);
dev->dmasound.afmt = val;
if (dev->dmasound.recording_on) {
dsp_rec_stop(dev);
dsp_rec_start(dev);
}
- up(&dev->dmasound.lock);
+ mutex_unlock(&dev->dmasound.lock);
return put_user(dev->dmasound.afmt, p);
default:
return -EINVAL;
@@ -509,10 +507,10 @@ static int dsp_ioctl(struct inode *inode, struct file *file,
return 0;
case SNDCTL_DSP_RESET:
- down(&dev->dmasound.lock);
+ mutex_lock(&dev->dmasound.lock);
if (dev->dmasound.recording_on)
dsp_rec_stop(dev);
- up(&dev->dmasound.lock);
+ mutex_unlock(&dev->dmasound.lock);
return 0;
case SNDCTL_DSP_GETBLKSIZE:
return put_user(dev->dmasound.blksize, p);
@@ -556,10 +554,10 @@ static unsigned int dsp_poll(struct file *file, struct poll_table_struct *wait)
poll_wait(file, &dev->dmasound.wq, wait);
if (0 == dev->dmasound.read_count) {
- down(&dev->dmasound.lock);
+ mutex_lock(&dev->dmasound.lock);
if (!dev->dmasound.recording_on)
dsp_rec_start(dev);
- up(&dev->dmasound.lock);
+ mutex_unlock(&dev->dmasound.lock);
} else
mask |= (POLLIN | POLLRDNORM);
return mask;
@@ -852,7 +850,7 @@ int saa7134_oss_init1(struct saa7134_dev *dev)
return -1;
/* general */
- init_MUTEX(&dev->dmasound.lock);
+ mutex_init(&dev->dmasound.lock);
init_waitqueue_head(&dev->dmasound.wq);
switch (dev->pci->device) {
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
index afa4dcb3f96..3043233a8b6 100644
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -140,6 +140,12 @@ static struct saa7134_tvaudio tvaudio[] = {
.carr2 = 5850,
.mode = TVAUDIO_NICAM_AM,
},{
+ .name = "SECAM-L MONO",
+ .std = V4L2_STD_SECAM,
+ .carr1 = 6500,
+ .carr2 = -1,
+ .mode = TVAUDIO_AM_MONO,
+ },{
.name = "SECAM-D/K",
.std = V4L2_STD_SECAM,
.carr1 = 6500,
@@ -334,6 +340,12 @@ static void tvaudio_setmode(struct saa7134_dev *dev,
saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa1);
saa_writeb(SAA7134_NICAM_CONFIG, 0x00);
break;
+ case TVAUDIO_AM_MONO:
+ saa_writeb(SAA7134_DEMODULATOR, 0x12);
+ saa_writeb(SAA7134_DCXO_IDENT_CTRL, 0x00);
+ saa_writeb(SAA7134_FM_DEEMPHASIS, 0x44);
+ saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa0);
+ break;
case TVAUDIO_FM_SAT_STEREO:
/* not implemented (yet) */
break;
@@ -414,6 +426,7 @@ static int tvaudio_getstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au
switch (audio->mode) {
case TVAUDIO_FM_MONO:
+ case TVAUDIO_AM_MONO:
return V4L2_TUNER_SUB_MONO;
case TVAUDIO_FM_K_STEREO:
case TVAUDIO_FM_BG_STEREO:
@@ -480,6 +493,7 @@ static int tvaudio_setstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au
switch (audio->mode) {
case TVAUDIO_FM_MONO:
+ case TVAUDIO_AM_MONO:
/* nothing to do ... */
break;
case TVAUDIO_FM_K_STEREO:
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index e97426bc85d..57a11e71d99 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -460,17 +460,17 @@ static int res_get(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int
return 1;
/* is it free? */
- down(&dev->lock);
+ mutex_lock(&dev->lock);
if (dev->resources & bit) {
/* no, someone else uses it */
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
return 0;
}
/* it's free, grab it */
fh->resources |= bit;
dev->resources |= bit;
dprintk("res: get %d\n",bit);
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
return 1;
}
@@ -489,14 +489,13 @@ int res_locked(struct saa7134_dev *dev, unsigned int bit)
static
void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits)
{
- if ((fh->resources & bits) != bits)
- BUG();
+ BUG_ON((fh->resources & bits) != bits);
- down(&dev->lock);
+ mutex_lock(&dev->lock);
fh->resources &= ~bits;
dev->resources &= ~bits;
dprintk("res: put %d\n",bits);
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
}
/* ------------------------------------------------------------------ */
@@ -1340,21 +1339,21 @@ video_poll(struct file *file, struct poll_table_struct *wait)
if (!list_empty(&fh->cap.stream))
buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream);
} else {
- down(&fh->cap.lock);
+ mutex_lock(&fh->cap.lock);
if (UNSET == fh->cap.read_off) {
/* need to capture a new frame */
if (res_locked(fh->dev,RESOURCE_VIDEO)) {
- up(&fh->cap.lock);
+ mutex_unlock(&fh->cap.lock);
return POLLERR;
}
if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) {
- up(&fh->cap.lock);
+ mutex_unlock(&fh->cap.lock);
return POLLERR;
}
fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
fh->cap.read_off = 0;
}
- up(&fh->cap.lock);
+ mutex_unlock(&fh->cap.lock);
buf = fh->cap.read_buf;
}
@@ -1463,6 +1462,10 @@ static int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
f->fmt.pix.height * f->fmt.pix.bytesperline;
return 0;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ if (saa7134_no_overlay > 0) {
+ printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+ return -EINVAL;
+ }
f->fmt.win = fh->win;
return 0;
case V4L2_BUF_TYPE_VBI_CAPTURE:
@@ -1527,6 +1530,10 @@ static int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
return 0;
}
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ if (saa7134_no_overlay > 0) {
+ printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+ return -EINVAL;
+ }
err = verify_preview(dev,&f->fmt.win);
if (0 != err)
return err;
@@ -1557,18 +1564,22 @@ static int saa7134_s_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
fh->cap.field = f->fmt.pix.field;
return 0;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ if (saa7134_no_overlay > 0) {
+ printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+ return -EINVAL;
+ }
err = verify_preview(dev,&f->fmt.win);
if (0 != err)
return err;
- down(&dev->lock);
+ mutex_lock(&dev->lock);
fh->win = f->fmt.win;
fh->nclips = f->fmt.win.clipcount;
if (fh->nclips > 8)
fh->nclips = 8;
if (copy_from_user(fh->clips,f->fmt.win.clips,
sizeof(struct v4l2_clip)*fh->nclips)) {
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
return -EFAULT;
}
@@ -1578,7 +1589,7 @@ static int saa7134_s_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
start_preview(dev,fh);
spin_unlock_irqrestore(&dev->slock,flags);
}
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
return 0;
case V4L2_BUF_TYPE_VBI_CAPTURE:
saa7134_vbi_fmt(dev,f);
@@ -1612,9 +1623,9 @@ int saa7134_common_ioctl(struct saa7134_dev *dev,
return get_control(dev,arg);
case VIDIOC_S_CTRL:
{
- down(&dev->lock);
+ mutex_lock(&dev->lock);
err = set_control(dev,NULL,arg);
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
return err;
}
/* --- input switching --------------------------------------- */
@@ -1664,9 +1675,9 @@ int saa7134_common_ioctl(struct saa7134_dev *dev,
return -EINVAL;
if (NULL == card_in(dev,*i).name)
return -EINVAL;
- down(&dev->lock);
+ mutex_lock(&dev->lock);
video_mux(dev,*i);
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
return 0;
}
@@ -1716,11 +1727,13 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
cap->version = SAA7134_VERSION_CODE;
cap->capabilities =
V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_VIDEO_OVERLAY |
V4L2_CAP_VBI_CAPTURE |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING |
V4L2_CAP_TUNER;
+ if (saa7134_no_overlay <= 0) {
+ cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
+ }
if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET))
cap->capabilities &= ~V4L2_CAP_TUNER;
@@ -1766,7 +1779,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
if (i == TVNORMS)
return -EINVAL;
- down(&dev->lock);
+ mutex_lock(&dev->lock);
if (res_check(fh, RESOURCE_OVERLAY)) {
spin_lock_irqsave(&dev->slock,flags);
stop_preview(dev,fh);
@@ -1776,7 +1789,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
} else
set_tvnorm(dev,&tvnorms[i]);
saa7134_tvaudio_do_scan(dev);
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
return 0;
}
@@ -1909,13 +1922,13 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
return -EINVAL;
- down(&dev->lock);
+ mutex_lock(&dev->lock);
dev->ctl_freq = f->frequency;
saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,f);
saa7134_tvaudio_do_scan(dev);
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
return 0;
}
@@ -1971,6 +1984,10 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
switch (type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ if (saa7134_no_overlay > 0) {
+ printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+ return -EINVAL;
+ }
if (index >= FORMATS)
return -EINVAL;
if (f->type == V4L2_BUF_TYPE_VIDEO_OVERLAY &&
@@ -2031,6 +2048,11 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
int *on = arg;
if (*on) {
+ if (saa7134_no_overlay > 0) {
+ printk ("no_overlay\n");
+ return -EINVAL;
+ }
+
if (!res_get(dev,fh,RESOURCE_OVERLAY))
return -EBUSY;
spin_lock_irqsave(&dev->slock,flags);
@@ -2282,7 +2304,7 @@ static struct file_operations radio_fops =
struct video_device saa7134_video_template =
{
.name = "saa7134-video",
- .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_OVERLAY|
+ .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
VID_TYPE_CLIPPING|VID_TYPE_SCALES,
.hardware = 0,
.fops = &video_fops,
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 3261d8bebdd..17ba34f3076 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -29,6 +29,7 @@
#include <linux/input.h>
#include <linux/notifier.h>
#include <linux/delay.h>
+#include <linux/mutex.h>
#include <asm/io.h>
@@ -60,6 +61,7 @@ enum saa7134_tvaudio_mode {
TVAUDIO_FM_K_STEREO = 4,
TVAUDIO_NICAM_AM = 5,
TVAUDIO_NICAM_FM = 6,
+ TVAUDIO_AM_MONO = 7
};
enum saa7134_audio_in {
@@ -210,6 +212,15 @@ struct saa7134_format {
#define SAA7134_BOARD_MSI_TVATANYWHERE_PLUS 82
#define SAA7134_BOARD_CINERGY250PCI 83
#define SAA7134_BOARD_FLYDVB_TRIO 84
+#define SAA7134_BOARD_AVERMEDIA_777 85
+#define SAA7134_BOARD_FLYDVBT_LR301 86
+#define SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331 87
+#define SAA7134_BOARD_TEVION_DVBT_220RF 88
+#define SAA7134_BOARD_ELSA_700TV 89
+#define SAA7134_BOARD_KWORLD_ATSC110 90
+#define SAA7134_BOARD_AVERMEDIA_A169_B 91
+#define SAA7134_BOARD_AVERMEDIA_A169_B1 92
+#define SAA7134_BOARD_MD7134_BRIDGE_2 93
#define SAA7134_MAXBOARDS 8
#define SAA7134_INPUT_MAX 8
@@ -359,7 +370,7 @@ struct saa7134_fh {
/* dmasound dsp status */
struct saa7134_dmasound {
- struct semaphore lock;
+ struct mutex lock;
int minor_mixer;
int minor_dsp;
unsigned int users_dsp;
@@ -423,7 +434,7 @@ struct saa7134_mpeg_ops {
/* global device status */
struct saa7134_dev {
struct list_head devlist;
- struct semaphore lock;
+ struct mutex lock;
spinlock_t slock;
#ifdef VIDIOC_G_PRIORITY
struct v4l2_prio_state prio;
@@ -546,6 +557,7 @@ struct saa7134_dev {
/* saa7134-core.c */
extern struct list_head saa7134_devlist;
+extern int saa7134_no_overlay;
void saa7134_track_gpio(struct saa7134_dev *dev, char *msg);
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c
index a796a4e1917..027c8a074df 100644
--- a/drivers/media/video/tda8290.c
+++ b/drivers/media/video/tda8290.c
@@ -281,7 +281,7 @@ static void tda827xa_agcf(struct i2c_client *c)
static void tda8290_i2c_bridge(struct i2c_client *c, int close)
{
unsigned char enable[2] = { 0x21, 0xC0 };
- unsigned char disable[2] = { 0x21, 0x80 };
+ unsigned char disable[2] = { 0x21, 0x00 };
unsigned char *msg;
if(close) {
msg = enable;
@@ -302,6 +302,7 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
unsigned char soft_reset[] = { 0x00, 0x00 };
unsigned char easy_mode[] = { 0x01, t->tda8290_easy_mode };
unsigned char expert_mode[] = { 0x01, 0x80 };
+ unsigned char agc_out_on[] = { 0x02, 0x00 };
unsigned char gainset_off[] = { 0x28, 0x14 };
unsigned char if_agc_spd[] = { 0x0f, 0x88 };
unsigned char adc_head_6[] = { 0x05, 0x04 };
@@ -320,6 +321,7 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
pll_stat;
i2c_master_send(c, easy_mode, 2);
+ i2c_master_send(c, agc_out_on, 2);
i2c_master_send(c, soft_reset, 2);
msleep(1);
@@ -470,6 +472,7 @@ static void standby(struct i2c_client *c)
struct tuner *t = i2c_get_clientdata(c);
unsigned char cb1[] = { 0x30, 0xD0 };
unsigned char tda8290_standby[] = { 0x00, 0x02 };
+ unsigned char tda8290_agc_tri[] = { 0x02, 0x20 };
struct i2c_msg msg = {.addr = t->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
tda8290_i2c_bridge(c, 1);
@@ -477,6 +480,7 @@ static void standby(struct i2c_client *c)
cb1[1] = 0x90;
i2c_transfer(c->adapter, &msg, 1);
tda8290_i2c_bridge(c, 0);
+ i2c_master_send(c, tda8290_agc_tri, 2);
i2c_master_send(c, tda8290_standby, 2);
}
@@ -565,7 +569,7 @@ int tda8290_init(struct i2c_client *c)
strlcpy(c->name, "tda8290+75a", sizeof(c->name));
t->tda827x_ver = 2;
}
- tuner_info("tuner: type set to %s\n", c->name);
+ tuner_info("type set to %s\n", c->name);
t->set_tv_freq = set_tv_freq;
t->set_radio_freq = set_radio_freq;
diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c
index ed4c04119cc..0243700f58a 100644
--- a/drivers/media/video/tda9840.c
+++ b/drivers/media/video/tda9840.c
@@ -24,6 +24,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/i2c.h>
@@ -222,7 +223,7 @@ static int detach(struct i2c_client *client)
static struct i2c_driver driver = {
.driver = {
- .name = "tda9840",
+ .name = "tda9840",
},
.id = I2C_DRIVERID_TDA9840,
.attach_adapter = attach,
diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c
index bb35844e384..774ed0dbc56 100644
--- a/drivers/media/video/tea6415c.c
+++ b/drivers/media/video/tea6415c.c
@@ -26,6 +26,7 @@
Foundation, Inc., 675 Mvss Ave, Cambridge, MA 02139, USA.
*/
+
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/i2c.h>
@@ -107,7 +108,7 @@ static int switch_matrix(struct i2c_client *client, int i, int o)
{
u8 byte = 0;
int ret;
-
+
dprintk("adr:0x%02x, i:%d, o:%d\n", client->addr, i, o);
/* check if the pins are valid */
@@ -191,7 +192,7 @@ static int command(struct i2c_client *client, unsigned int cmd, void *arg)
static struct i2c_driver driver = {
.driver = {
- .name = "tea6415c",
+ .name = "tea6415c",
},
.id = I2C_DRIVERID_TEA6415C,
.attach_adapter = attach,
diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c
index 4dcba5a4fff..ad7d2872cfb 100644
--- a/drivers/media/video/tea6420.c
+++ b/drivers/media/video/tea6420.c
@@ -26,6 +26,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/i2c.h>
@@ -83,7 +84,7 @@ static int tea6420_switch(struct i2c_client *client, int i, int o, int g)
dprintk("i2c_smbus_write_byte() failed, ret:%d\n", ret);
return -EIO;
}
-
+
return 0;
}
@@ -167,7 +168,7 @@ static int command(struct i2c_client *client, unsigned int cmd, void *arg)
static struct i2c_driver driver = {
.driver = {
- .name = "tea6420",
+ .name = "tea6420",
},
.id = I2C_DRIVERID_TEA6420,
.attach_adapter = attach,
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index b6101bf446d..32e1849441f 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -173,7 +173,6 @@ static void set_type(struct i2c_client *c, unsigned int type,
}
t->type = type;
-
switch (t->type) {
case TUNER_MT2032:
microtune_init(c);
@@ -404,15 +403,16 @@ static void tuner_status(struct i2c_client *client)
tuner_info("Tuner mode: %s\n", p);
tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction);
tuner_info("Standard: 0x%08llx\n", t->std);
- if (t->mode == V4L2_TUNER_RADIO) {
- if (t->has_signal) {
- tuner_info("Signal strength: %d\n", t->has_signal(client));
- }
- if (t->is_stereo) {
- tuner_info("Stereo: %s\n", t->is_stereo(client) ? "yes" : "no");
- }
+ if (t->mode != V4L2_TUNER_RADIO)
+ return;
+ if (t->has_signal) {
+ tuner_info("Signal strength: %d\n", t->has_signal(client));
+ }
+ if (t->is_stereo) {
+ tuner_info("Stereo: %s\n", t->is_stereo(client) ? "yes" : "no");
}
}
+
/* ---------------------------------------------------------------------- */
/* static var Used only in tuner_attach and tuner_probe */
@@ -744,33 +744,29 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
return 0;
switch_v4l2();
- if (V4L2_TUNER_RADIO == t->mode) {
-
- if (t->has_signal)
- tuner->signal = t->has_signal(client);
-
- if (t->is_stereo) {
- if (t->is_stereo(client)) {
- tuner->rxsubchans =
- V4L2_TUNER_SUB_STEREO |
- V4L2_TUNER_SUB_MONO;
- } else {
- tuner->rxsubchans =
- V4L2_TUNER_SUB_MONO;
- }
- }
-
- tuner->capability |=
- V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
-
- tuner->audmode = t->audmode;
-
- tuner->rangelow = radio_range[0] * 16000;
- tuner->rangehigh = radio_range[1] * 16000;
- } else {
+ tuner->type = t->mode;
+ if (t->mode != V4L2_TUNER_RADIO) {
tuner->rangelow = tv_range[0] * 16;
tuner->rangehigh = tv_range[1] * 16;
+ break;
}
+
+ /* radio mode */
+ if (t->has_signal)
+ tuner->signal = t->has_signal(client);
+
+ tuner->rxsubchans =
+ V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+ if (t->is_stereo) {
+ tuner->rxsubchans = t->is_stereo(client) ?
+ V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+ }
+
+ tuner->capability |=
+ V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+ tuner->audmode = t->audmode;
+ tuner->rangelow = radio_range[0] * 16000;
+ tuner->rangehigh = radio_range[1] * 16000;
break;
}
case VIDIOC_S_TUNER:
@@ -782,10 +778,11 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
switch_v4l2();
- if (V4L2_TUNER_RADIO == t->mode) {
- t->audmode = tuner->audmode;
- set_radio_freq(client, t->radio_freq);
- }
+ /* do nothing unless we're a radio tuner */
+ if (t->mode != V4L2_TUNER_RADIO)
+ break;
+ t->audmode = tuner->audmode;
+ set_radio_freq(client, t->radio_freq);
break;
}
case VIDIOC_LOG_STATUS:
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index 37977ff4978..5d7abed7167 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -79,17 +79,6 @@ MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner");
#define TUNER_PLL_LOCKED 0x40
#define TUNER_STEREO_MK3 0x04
-#define TUNER_PARAM_ANALOG 0 /* to be removed */
-/* FIXME:
- * Right now, all tuners are using the first tuner_params[] array element
- * for analog mode. In the future, we will be merging similar tuner
- * definitions together, such that each tuner definition will have a
- * tuner_params struct for each available video standard. At that point,
- * TUNER_PARAM_ANALOG will be removed, and the tuner_params[] array
- * element will be chosen based on the video standard in use.
- *
- */
-
/* ---------------------------------------------------------------------- */
static int tuner_getstatus(struct i2c_client *c)
@@ -133,14 +122,53 @@ static int tuner_stereo(struct i2c_client *c)
static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
{
struct tuner *t = i2c_get_clientdata(c);
- u8 config, tuneraddr;
+ u8 config, cb, tuneraddr;
u16 div;
struct tunertype *tun;
u8 buffer[4];
int rc, IFPCoff, i, j;
+ enum param_type desired_type;
tun = &tuners[t->type];
- j = TUNER_PARAM_ANALOG;
+
+ /* IFPCoff = Video Intermediate Frequency - Vif:
+ 940 =16*58.75 NTSC/J (Japan)
+ 732 =16*45.75 M/N STD
+ 704 =16*44 ATSC (at DVB code)
+ 632 =16*39.50 I U.K.
+ 622.4=16*38.90 B/G D/K I, L STD
+ 592 =16*37.00 D China
+ 590 =16.36.875 B Australia
+ 543.2=16*33.95 L' STD
+ 171.2=16*10.70 FM Radio (at set_radio_freq)
+ */
+
+ if (t->std == V4L2_STD_NTSC_M_JP) {
+ IFPCoff = 940;
+ desired_type = TUNER_PARAM_TYPE_NTSC;
+ } else if ((t->std & V4L2_STD_MN) &&
+ !(t->std & ~V4L2_STD_MN)) {
+ IFPCoff = 732;
+ desired_type = TUNER_PARAM_TYPE_NTSC;
+ } else if (t->std == V4L2_STD_SECAM_LC) {
+ IFPCoff = 543;
+ desired_type = TUNER_PARAM_TYPE_SECAM;
+ } else {
+ IFPCoff = 623;
+ desired_type = TUNER_PARAM_TYPE_PAL;
+ }
+
+ for (j = 0; j < tun->count-1; j++) {
+ if (desired_type != tun->params[j].type)
+ continue;
+ break;
+ }
+ /* use default tuner_params if desired_type not available */
+ if (desired_type != tun->params[j].type) {
+ tuner_dbg("IFPCoff = %d: tuner_params undefined for tuner %d\n",
+ IFPCoff,t->type);
+ j = 0;
+ }
for (i = 0; i < tun->params[j].count; i++) {
if (freq > tun->params[j].ranges[i].limit)
@@ -152,11 +180,20 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
freq, tun->params[j].ranges[i - 1].limit);
freq = tun->params[j].ranges[--i].limit;
}
- config = tun->params[j].ranges[i].cb;
- /* i == 0 -> VHF_LO */
- /* i == 1 -> VHF_HI */
- /* i == 2 -> UHF */
- tuner_dbg("tv: range %d\n",i);
+ config = tun->params[j].ranges[i].config;
+ cb = tun->params[j].ranges[i].cb;
+ /* i == 0 -> VHF_LO
+ * i == 1 -> VHF_HI
+ * i == 2 -> UHF */
+ tuner_dbg("tv: param %d, range %d\n",j,i);
+
+ div=freq + IFPCoff + offset;
+
+ tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, Offset=%d.%02d MHz, div=%0d\n",
+ freq / 16, freq % 16 * 100 / 16,
+ IFPCoff / 16, IFPCoff % 16 * 100 / 16,
+ offset / 16, offset % 16 * 100 / 16,
+ div);
/* tv norm specific stuff for multi-norm tuners */
switch (t->type) {
@@ -164,40 +201,40 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
/* 0x01 -> ??? no change ??? */
/* 0x02 -> PAL BDGHI / SECAM L */
/* 0x04 -> ??? PAL others / SECAM others ??? */
- config &= ~0x02;
+ cb &= ~0x02;
if (t->std & V4L2_STD_SECAM)
- config |= 0x02;
+ cb |= 0x02;
break;
case TUNER_TEMIC_4046FM5:
- config &= ~0x0f;
+ cb &= ~0x0f;
if (t->std & V4L2_STD_PAL_BG) {
- config |= TEMIC_SET_PAL_BG;
+ cb |= TEMIC_SET_PAL_BG;
} else if (t->std & V4L2_STD_PAL_I) {
- config |= TEMIC_SET_PAL_I;
+ cb |= TEMIC_SET_PAL_I;
} else if (t->std & V4L2_STD_PAL_DK) {
- config |= TEMIC_SET_PAL_DK;
+ cb |= TEMIC_SET_PAL_DK;
} else if (t->std & V4L2_STD_SECAM_L) {
- config |= TEMIC_SET_PAL_L;
+ cb |= TEMIC_SET_PAL_L;
}
break;
case TUNER_PHILIPS_FQ1216ME:
- config &= ~0x0f;
+ cb &= ~0x0f;
if (t->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) {
- config |= PHILIPS_SET_PAL_BGDK;
+ cb |= PHILIPS_SET_PAL_BGDK;
} else if (t->std & V4L2_STD_PAL_I) {
- config |= PHILIPS_SET_PAL_I;
+ cb |= PHILIPS_SET_PAL_I;
} else if (t->std & V4L2_STD_SECAM_L) {
- config |= PHILIPS_SET_PAL_L;
+ cb |= PHILIPS_SET_PAL_L;
}
break;
@@ -207,15 +244,15 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
/* 0x01 -> ATSC antenna input 2 */
/* 0x02 -> NTSC antenna input 1 */
/* 0x03 -> NTSC antenna input 2 */
- config &= ~0x03;
+ cb &= ~0x03;
if (!(t->std & V4L2_STD_ATSC))
- config |= 2;
+ cb |= 2;
/* FIXME: input */
break;
case TUNER_MICROTUNE_4042FI5:
/* Set the charge pump for fast tuning */
- tun->params[j].config |= TUNER_CHARGE_PUMP;
+ config |= TUNER_CHARGE_PUMP;
break;
case TUNER_PHILIPS_TUV1236D:
@@ -227,9 +264,9 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
buffer[1] = 0x00;
buffer[2] = 0x17;
buffer[3] = 0x00;
- config &= ~0x40;
+ cb &= ~0x40;
if (t->std & V4L2_STD_ATSC) {
- config |= 0x40;
+ cb |= 0x40;
buffer[1] = 0x04;
}
/* set to the correct mode (analog or digital) */
@@ -244,47 +281,16 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
break;
}
- /* IFPCoff = Video Intermediate Frequency - Vif:
- 940 =16*58.75 NTSC/J (Japan)
- 732 =16*45.75 M/N STD
- 704 =16*44 ATSC (at DVB code)
- 632 =16*39.50 I U.K.
- 622.4=16*38.90 B/G D/K I, L STD
- 592 =16*37.00 D China
- 590 =16.36.875 B Australia
- 543.2=16*33.95 L' STD
- 171.2=16*10.70 FM Radio (at set_radio_freq)
- */
-
- if (t->std == V4L2_STD_NTSC_M_JP) {
- IFPCoff = 940;
- } else if ((t->std & V4L2_STD_MN) &&
- !(t->std & ~V4L2_STD_MN)) {
- IFPCoff = 732;
- } else if (t->std == V4L2_STD_SECAM_LC) {
- IFPCoff = 543;
- } else {
- IFPCoff = 623;
- }
-
- div=freq + IFPCoff + offset;
-
- tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, Offset=%d.%02d MHz, div=%0d\n",
- freq / 16, freq % 16 * 100 / 16,
- IFPCoff / 16, IFPCoff % 16 * 100 / 16,
- offset / 16, offset % 16 * 100 / 16,
- div);
-
if (tuners[t->type].params->cb_first_if_lower_freq && div < t->last_div) {
- buffer[0] = tun->params[j].config;
- buffer[1] = config;
+ buffer[0] = config;
+ buffer[1] = cb;
buffer[2] = (div>>8) & 0x7f;
buffer[3] = div & 0xff;
} else {
buffer[0] = (div>>8) & 0x7f;
buffer[1] = div & 0xff;
- buffer[2] = tun->params[j].config;
- buffer[3] = config;
+ buffer[2] = config;
+ buffer[3] = cb;
}
t->last_div = div;
tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
@@ -312,11 +318,11 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
}
/* Set the charge pump for optimized phase noise figure */
- tun->params[j].config &= ~TUNER_CHARGE_PUMP;
+ config &= ~TUNER_CHARGE_PUMP;
buffer[0] = (div>>8) & 0x7f;
buffer[1] = div & 0xff;
- buffer[2] = tun->params[j].config;
- buffer[3] = config;
+ buffer[2] = config;
+ buffer[3] = cb;
tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
buffer[0],buffer[1],buffer[2],buffer[3]);
@@ -332,12 +338,21 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
u8 buffer[4];
u16 div;
int rc, j;
+ enum param_type desired_type = TUNER_PARAM_TYPE_RADIO;
tun = &tuners[t->type];
- j = TUNER_PARAM_ANALOG;
+
+ for (j = 0; j < tun->count-1; j++) {
+ if (desired_type != tun->params[j].type)
+ continue;
+ break;
+ }
+ /* use default tuner_params if desired_type not available */
+ if (desired_type != tun->params[j].type)
+ j = 0;
div = (20 * freq / 16000) + (int)(20*10.7); /* IF 10.7 MHz */
- buffer[2] = (tun->params[j].config & ~TUNER_RATIO_MASK) | TUNER_RATIO_SELECT_50; /* 50 kHz step */
+ buffer[2] = (tun->params[j].ranges[0].config & ~TUNER_RATIO_MASK) | TUNER_RATIO_SELECT_50; /* 50 kHz step */
switch (t->type) {
case TUNER_TENA_9533_DI:
@@ -349,6 +364,9 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
case TUNER_PHILIPS_FMD1216ME_MK3:
buffer[3] = 0x19;
break;
+ case TUNER_TNF_5335MF:
+ buffer[3] = 0x11;
+ break;
case TUNER_PHILIPS_FM1256_IH3:
div = (20 * freq) / 16000 + (int)(33.3 * 20); /* IF 33.3 MHz */
buffer[3] = 0x19;
diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c
index 6fe781798d8..72e0f01db56 100644
--- a/drivers/media/video/tuner-types.c
+++ b/drivers/media/video/tuner-types.c
@@ -23,22 +23,25 @@
* Each tuner_params array may contain one or more elements, one
* for each video standard.
*
- * FIXME: Some tuner_range definitions are duplicated, and
- * should be eliminated.
+ * FIXME: tuner_params struct contains an element, tda988x. We must
+ * set this for all tuners that contain a tda988x chip, and then we
+ * can remove this setting from the various card structs.
*
- * FIXME: tunertype struct contains an element, has_tda988x.
- * We must set this for all tunertypes that contain a tda988x
- * chip, and then we can remove this setting from the various
- * card structs.
+ * FIXME: Right now, all tuners are using the first tuner_params[]
+ * array element for analog mode. In the future, we will be merging
+ * similar tuner definitions together, such that each tuner definition
+ * will have a tuner_params struct for each available video standard.
+ * At that point, the tuner_params[] array element will be chosen
+ * based on the video standard in use.
*/
/* 0-9 */
/* ------------ TUNER_TEMIC_PAL - TEMIC PAL ------------ */
static struct tuner_range tuner_temic_pal_ranges[] = {
- { 16 * 140.25 /*MHz*/, 0x02, },
- { 16 * 463.25 /*MHz*/, 0x04, },
- { 16 * 999.99 , 0x01, },
+ { 16 * 140.25 /*MHz*/, 0x8e, 0x02, },
+ { 16 * 463.25 /*MHz*/, 0x8e, 0x04, },
+ { 16 * 999.99 , 0x8e, 0x01, },
};
static struct tuner_params tuner_temic_pal_params[] = {
@@ -46,16 +49,15 @@ static struct tuner_params tuner_temic_pal_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_temic_pal_ranges,
.count = ARRAY_SIZE(tuner_temic_pal_ranges),
- .config = 0x8e,
},
};
/* ------------ TUNER_PHILIPS_PAL_I - Philips PAL_I ------------ */
static struct tuner_range tuner_philips_pal_i_ranges[] = {
- { 16 * 140.25 /*MHz*/, 0xa0, },
- { 16 * 463.25 /*MHz*/, 0x90, },
- { 16 * 999.99 , 0x30, },
+ { 16 * 140.25 /*MHz*/, 0x8e, 0xa0, },
+ { 16 * 463.25 /*MHz*/, 0x8e, 0x90, },
+ { 16 * 999.99 , 0x8e, 0x30, },
};
static struct tuner_params tuner_philips_pal_i_params[] = {
@@ -63,16 +65,15 @@ static struct tuner_params tuner_philips_pal_i_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_philips_pal_i_ranges,
.count = ARRAY_SIZE(tuner_philips_pal_i_ranges),
- .config = 0x8e,
},
};
/* ------------ TUNER_PHILIPS_NTSC - Philips NTSC ------------ */
static struct tuner_range tuner_philips_ntsc_ranges[] = {
- { 16 * 157.25 /*MHz*/, 0xa0, },
- { 16 * 451.25 /*MHz*/, 0x90, },
- { 16 * 999.99 , 0x30, },
+ { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, },
+ { 16 * 451.25 /*MHz*/, 0x8e, 0x90, },
+ { 16 * 999.99 , 0x8e, 0x30, },
};
static struct tuner_params tuner_philips_ntsc_params[] = {
@@ -80,7 +81,6 @@ static struct tuner_params tuner_philips_ntsc_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_philips_ntsc_ranges,
.count = ARRAY_SIZE(tuner_philips_ntsc_ranges),
- .config = 0x8e,
.cb_first_if_lower_freq = 1,
},
};
@@ -88,9 +88,9 @@ static struct tuner_params tuner_philips_ntsc_params[] = {
/* ------------ TUNER_PHILIPS_SECAM - Philips SECAM ------------ */
static struct tuner_range tuner_philips_secam_ranges[] = {
- { 16 * 168.25 /*MHz*/, 0xa7, },
- { 16 * 447.25 /*MHz*/, 0x97, },
- { 16 * 999.99 , 0x37, },
+ { 16 * 168.25 /*MHz*/, 0x8e, 0xa7, },
+ { 16 * 447.25 /*MHz*/, 0x8e, 0x97, },
+ { 16 * 999.99 , 0x8e, 0x37, },
};
static struct tuner_params tuner_philips_secam_params[] = {
@@ -98,7 +98,6 @@ static struct tuner_params tuner_philips_secam_params[] = {
.type = TUNER_PARAM_TYPE_SECAM,
.ranges = tuner_philips_secam_ranges,
.count = ARRAY_SIZE(tuner_philips_secam_ranges),
- .config = 0x8e,
.cb_first_if_lower_freq = 1,
},
};
@@ -106,9 +105,9 @@ static struct tuner_params tuner_philips_secam_params[] = {
/* ------------ TUNER_PHILIPS_PAL - Philips PAL ------------ */
static struct tuner_range tuner_philips_pal_ranges[] = {
- { 16 * 168.25 /*MHz*/, 0xa0, },
- { 16 * 447.25 /*MHz*/, 0x90, },
- { 16 * 999.99 , 0x30, },
+ { 16 * 168.25 /*MHz*/, 0x8e, 0xa0, },
+ { 16 * 447.25 /*MHz*/, 0x8e, 0x90, },
+ { 16 * 999.99 , 0x8e, 0x30, },
};
static struct tuner_params tuner_philips_pal_params[] = {
@@ -116,7 +115,6 @@ static struct tuner_params tuner_philips_pal_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_philips_pal_ranges,
.count = ARRAY_SIZE(tuner_philips_pal_ranges),
- .config = 0x8e,
.cb_first_if_lower_freq = 1,
},
};
@@ -124,9 +122,9 @@ static struct tuner_params tuner_philips_pal_params[] = {
/* ------------ TUNER_TEMIC_NTSC - TEMIC NTSC ------------ */
static struct tuner_range tuner_temic_ntsc_ranges[] = {
- { 16 * 157.25 /*MHz*/, 0x02, },
- { 16 * 463.25 /*MHz*/, 0x04, },
- { 16 * 999.99 , 0x01, },
+ { 16 * 157.25 /*MHz*/, 0x8e, 0x02, },
+ { 16 * 463.25 /*MHz*/, 0x8e, 0x04, },
+ { 16 * 999.99 , 0x8e, 0x01, },
};
static struct tuner_params tuner_temic_ntsc_params[] = {
@@ -134,16 +132,15 @@ static struct tuner_params tuner_temic_ntsc_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_temic_ntsc_ranges,
.count = ARRAY_SIZE(tuner_temic_ntsc_ranges),
- .config = 0x8e,
},
};
/* ------------ TUNER_TEMIC_PAL_I - TEMIC PAL_I ------------ */
static struct tuner_range tuner_temic_pal_i_ranges[] = {
- { 16 * 170.00 /*MHz*/, 0x02, },
- { 16 * 450.00 /*MHz*/, 0x04, },
- { 16 * 999.99 , 0x01, },
+ { 16 * 170.00 /*MHz*/, 0x8e, 0x02, },
+ { 16 * 450.00 /*MHz*/, 0x8e, 0x04, },
+ { 16 * 999.99 , 0x8e, 0x01, },
};
static struct tuner_params tuner_temic_pal_i_params[] = {
@@ -151,16 +148,15 @@ static struct tuner_params tuner_temic_pal_i_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_temic_pal_i_ranges,
.count = ARRAY_SIZE(tuner_temic_pal_i_ranges),
- .config = 0x8e,
},
};
/* ------------ TUNER_TEMIC_4036FY5_NTSC - TEMIC NTSC ------------ */
static struct tuner_range tuner_temic_4036fy5_ntsc_ranges[] = {
- { 16 * 157.25 /*MHz*/, 0xa0, },
- { 16 * 463.25 /*MHz*/, 0x90, },
- { 16 * 999.99 , 0x30, },
+ { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, },
+ { 16 * 463.25 /*MHz*/, 0x8e, 0x90, },
+ { 16 * 999.99 , 0x8e, 0x30, },
};
static struct tuner_params tuner_temic_4036fy5_ntsc_params[] = {
@@ -168,16 +164,15 @@ static struct tuner_params tuner_temic_4036fy5_ntsc_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_temic_4036fy5_ntsc_ranges,
.count = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_ranges),
- .config = 0x8e,
},
};
/* ------------ TUNER_ALPS_TSBH1_NTSC - TEMIC NTSC ------------ */
static struct tuner_range tuner_alps_tsb_1_ranges[] = {
- { 16 * 137.25 /*MHz*/, 0x01, },
- { 16 * 385.25 /*MHz*/, 0x02, },
- { 16 * 999.99 , 0x08, },
+ { 16 * 137.25 /*MHz*/, 0x8e, 0x01, },
+ { 16 * 385.25 /*MHz*/, 0x8e, 0x02, },
+ { 16 * 999.99 , 0x8e, 0x08, },
};
static struct tuner_params tuner_alps_tsbh1_ntsc_params[] = {
@@ -185,7 +180,6 @@ static struct tuner_params tuner_alps_tsbh1_ntsc_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_alps_tsb_1_ranges,
.count = ARRAY_SIZE(tuner_alps_tsb_1_ranges),
- .config = 0x8e,
},
};
@@ -197,16 +191,15 @@ static struct tuner_params tuner_alps_tsb_1_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_alps_tsb_1_ranges,
.count = ARRAY_SIZE(tuner_alps_tsb_1_ranges),
- .config = 0x8e,
},
};
/* ------------ TUNER_ALPS_TSBB5_PAL_I - Alps PAL_I ------------ */
static struct tuner_range tuner_alps_tsb_5_pal_ranges[] = {
- { 16 * 133.25 /*MHz*/, 0x01, },
- { 16 * 351.25 /*MHz*/, 0x02, },
- { 16 * 999.99 , 0x08, },
+ { 16 * 133.25 /*MHz*/, 0x8e, 0x01, },
+ { 16 * 351.25 /*MHz*/, 0x8e, 0x02, },
+ { 16 * 999.99 , 0x8e, 0x08, },
};
static struct tuner_params tuner_alps_tsbb5_params[] = {
@@ -214,7 +207,6 @@ static struct tuner_params tuner_alps_tsbb5_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_alps_tsb_5_pal_ranges,
.count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges),
- .config = 0x8e,
},
};
@@ -225,7 +217,6 @@ static struct tuner_params tuner_alps_tsbe5_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_alps_tsb_5_pal_ranges,
.count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges),
- .config = 0x8e,
},
};
@@ -236,33 +227,31 @@ static struct tuner_params tuner_alps_tsbc5_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_alps_tsb_5_pal_ranges,
.count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges),
- .config = 0x8e,
},
};
/* ------------ TUNER_TEMIC_4006FH5_PAL - TEMIC PAL ------------ */
-static struct tuner_range tuner_temic_4006fh5_pal_ranges[] = {
- { 16 * 170.00 /*MHz*/, 0xa0, },
- { 16 * 450.00 /*MHz*/, 0x90, },
- { 16 * 999.99 , 0x30, },
+static struct tuner_range tuner_lg_pal_ranges[] = {
+ { 16 * 170.00 /*MHz*/, 0x8e, 0xa0, },
+ { 16 * 450.00 /*MHz*/, 0x8e, 0x90, },
+ { 16 * 999.99 , 0x8e, 0x30, },
};
static struct tuner_params tuner_temic_4006fh5_params[] = {
{
.type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_temic_4006fh5_pal_ranges,
- .count = ARRAY_SIZE(tuner_temic_4006fh5_pal_ranges),
- .config = 0x8e,
+ .ranges = tuner_lg_pal_ranges,
+ .count = ARRAY_SIZE(tuner_lg_pal_ranges),
},
};
/* ------------ TUNER_ALPS_TSHC6_NTSC - Alps NTSC ------------ */
static struct tuner_range tuner_alps_tshc6_ntsc_ranges[] = {
- { 16 * 137.25 /*MHz*/, 0x14, },
- { 16 * 385.25 /*MHz*/, 0x12, },
- { 16 * 999.99 , 0x11, },
+ { 16 * 137.25 /*MHz*/, 0x8e, 0x14, },
+ { 16 * 385.25 /*MHz*/, 0x8e, 0x12, },
+ { 16 * 999.99 , 0x8e, 0x11, },
};
static struct tuner_params tuner_alps_tshc6_params[] = {
@@ -270,16 +259,15 @@ static struct tuner_params tuner_alps_tshc6_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_alps_tshc6_ntsc_ranges,
.count = ARRAY_SIZE(tuner_alps_tshc6_ntsc_ranges),
- .config = 0x8e,
},
};
/* ------------ TUNER_TEMIC_PAL_DK - TEMIC PAL ------------ */
static struct tuner_range tuner_temic_pal_dk_ranges[] = {
- { 16 * 168.25 /*MHz*/, 0xa0, },
- { 16 * 456.25 /*MHz*/, 0x90, },
- { 16 * 999.99 , 0x30, },
+ { 16 * 168.25 /*MHz*/, 0x8e, 0xa0, },
+ { 16 * 456.25 /*MHz*/, 0x8e, 0x90, },
+ { 16 * 999.99 , 0x8e, 0x30, },
};
static struct tuner_params tuner_temic_pal_dk_params[] = {
@@ -287,16 +275,15 @@ static struct tuner_params tuner_temic_pal_dk_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_temic_pal_dk_ranges,
.count = ARRAY_SIZE(tuner_temic_pal_dk_ranges),
- .config = 0x8e,
},
};
/* ------------ TUNER_PHILIPS_NTSC_M - Philips NTSC ------------ */
static struct tuner_range tuner_philips_ntsc_m_ranges[] = {
- { 16 * 160.00 /*MHz*/, 0xa0, },
- { 16 * 454.00 /*MHz*/, 0x90, },
- { 16 * 999.99 , 0x30, },
+ { 16 * 160.00 /*MHz*/, 0x8e, 0xa0, },
+ { 16 * 454.00 /*MHz*/, 0x8e, 0x90, },
+ { 16 * 999.99 , 0x8e, 0x30, },
};
static struct tuner_params tuner_philips_ntsc_m_params[] = {
@@ -304,16 +291,15 @@ static struct tuner_params tuner_philips_ntsc_m_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_philips_ntsc_m_ranges,
.count = ARRAY_SIZE(tuner_philips_ntsc_m_ranges),
- .config = 0x8e,
},
};
/* ------------ TUNER_TEMIC_4066FY5_PAL_I - TEMIC PAL_I ------------ */
static struct tuner_range tuner_temic_40x6f_5_pal_ranges[] = {
- { 16 * 169.00 /*MHz*/, 0xa0, },
- { 16 * 454.00 /*MHz*/, 0x90, },
- { 16 * 999.99 , 0x30, },
+ { 16 * 169.00 /*MHz*/, 0x8e, 0xa0, },
+ { 16 * 454.00 /*MHz*/, 0x8e, 0x90, },
+ { 16 * 999.99 , 0x8e, 0x30, },
};
static struct tuner_params tuner_temic_4066fy5_pal_i_params[] = {
@@ -321,7 +307,6 @@ static struct tuner_params tuner_temic_4066fy5_pal_i_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_temic_40x6f_5_pal_ranges,
.count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges),
- .config = 0x8e,
},
};
@@ -332,7 +317,6 @@ static struct tuner_params tuner_temic_4006fn5_multi_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_temic_40x6f_5_pal_ranges,
.count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges),
- .config = 0x8e,
},
};
@@ -340,9 +324,9 @@ static struct tuner_params tuner_temic_4006fn5_multi_params[] = {
/* ------------ TUNER_TEMIC_4009FR5_PAL - TEMIC PAL ------------ */
static struct tuner_range tuner_temic_4009f_5_pal_ranges[] = {
- { 16 * 141.00 /*MHz*/, 0xa0, },
- { 16 * 464.00 /*MHz*/, 0x90, },
- { 16 * 999.99 , 0x30, },
+ { 16 * 141.00 /*MHz*/, 0x8e, 0xa0, },
+ { 16 * 464.00 /*MHz*/, 0x8e, 0x90, },
+ { 16 * 999.99 , 0x8e, 0x30, },
};
static struct tuner_params tuner_temic_4009f_5_params[] = {
@@ -350,58 +334,42 @@ static struct tuner_params tuner_temic_4009f_5_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_temic_4009f_5_pal_ranges,
.count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
- .config = 0x8e,
},
};
/* ------------ TUNER_TEMIC_4039FR5_NTSC - TEMIC NTSC ------------ */
-static struct tuner_range tuner_temic_4039fr5_ntsc_ranges[] = {
- { 16 * 158.00 /*MHz*/, 0xa0, },
- { 16 * 453.00 /*MHz*/, 0x90, },
- { 16 * 999.99 , 0x30, },
+static struct tuner_range tuner_temic_4x3x_f_5_ntsc_ranges[] = {
+ { 16 * 158.00 /*MHz*/, 0x8e, 0xa0, },
+ { 16 * 453.00 /*MHz*/, 0x8e, 0x90, },
+ { 16 * 999.99 , 0x8e, 0x30, },
};
static struct tuner_params tuner_temic_4039fr5_params[] = {
{
.type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_temic_4039fr5_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_temic_4039fr5_ntsc_ranges),
- .config = 0x8e,
+ .ranges = tuner_temic_4x3x_f_5_ntsc_ranges,
+ .count = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges),
},
};
/* ------------ TUNER_TEMIC_4046FM5 - TEMIC PAL ------------ */
-static struct tuner_range tuner_temic_4046fm5_pal_ranges[] = {
- { 16 * 169.00 /*MHz*/, 0xa0, },
- { 16 * 454.00 /*MHz*/, 0x90, },
- { 16 * 999.99 , 0x30, },
-};
-
static struct tuner_params tuner_temic_4046fm5_params[] = {
{
.type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_temic_4046fm5_pal_ranges,
- .count = ARRAY_SIZE(tuner_temic_4046fm5_pal_ranges),
- .config = 0x8e,
+ .ranges = tuner_temic_40x6f_5_pal_ranges,
+ .count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges),
},
};
/* ------------ TUNER_PHILIPS_PAL_DK - Philips PAL ------------ */
-static struct tuner_range tuner_lg_pal_ranges[] = {
- { 16 * 170.00 /*MHz*/, 0xa0, },
- { 16 * 450.00 /*MHz*/, 0x90, },
- { 16 * 999.99 , 0x30, },
-};
-
static struct tuner_params tuner_philips_pal_dk_params[] = {
{
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_lg_pal_ranges,
.count = ARRAY_SIZE(tuner_lg_pal_ranges),
- .config = 0x8e,
},
};
@@ -412,7 +380,6 @@ static struct tuner_params tuner_philips_fq1216me_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_lg_pal_ranges,
.count = ARRAY_SIZE(tuner_lg_pal_ranges),
- .config = 0x8e,
},
};
@@ -423,7 +390,6 @@ static struct tuner_params tuner_lg_pal_i_fm_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_lg_pal_ranges,
.count = ARRAY_SIZE(tuner_lg_pal_ranges),
- .config = 0x8e,
},
};
@@ -434,16 +400,15 @@ static struct tuner_params tuner_lg_pal_i_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_lg_pal_ranges,
.count = ARRAY_SIZE(tuner_lg_pal_ranges),
- .config = 0x8e,
},
};
/* ------------ TUNER_LG_NTSC_FM - LGINNOTEK NTSC ------------ */
static struct tuner_range tuner_lg_ntsc_fm_ranges[] = {
- { 16 * 210.00 /*MHz*/, 0xa0, },
- { 16 * 497.00 /*MHz*/, 0x90, },
- { 16 * 999.99 , 0x30, },
+ { 16 * 210.00 /*MHz*/, 0x8e, 0xa0, },
+ { 16 * 497.00 /*MHz*/, 0x8e, 0x90, },
+ { 16 * 999.99 , 0x8e, 0x30, },
};
static struct tuner_params tuner_lg_ntsc_fm_params[] = {
@@ -451,7 +416,6 @@ static struct tuner_params tuner_lg_ntsc_fm_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_lg_ntsc_fm_ranges,
.count = ARRAY_SIZE(tuner_lg_ntsc_fm_ranges),
- .config = 0x8e,
},
};
@@ -462,7 +426,6 @@ static struct tuner_params tuner_lg_pal_fm_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_lg_pal_ranges,
.count = ARRAY_SIZE(tuner_lg_pal_ranges),
- .config = 0x8e,
},
};
@@ -473,7 +436,6 @@ static struct tuner_params tuner_lg_pal_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_lg_pal_ranges,
.count = ARRAY_SIZE(tuner_lg_pal_ranges),
- .config = 0x8e,
},
};
@@ -485,16 +447,15 @@ static struct tuner_params tuner_temic_4009_fn5_multi_pal_fm_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_temic_4009f_5_pal_ranges,
.count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
- .config = 0x8e,
},
};
/* ------------ TUNER_SHARP_2U5JF5540_NTSC - SHARP NTSC ------------ */
static struct tuner_range tuner_sharp_2u5jf5540_ntsc_ranges[] = {
- { 16 * 137.25 /*MHz*/, 0x01, },
- { 16 * 317.25 /*MHz*/, 0x02, },
- { 16 * 999.99 , 0x08, },
+ { 16 * 137.25 /*MHz*/, 0x8e, 0x01, },
+ { 16 * 317.25 /*MHz*/, 0x8e, 0x02, },
+ { 16 * 999.99 , 0x8e, 0x08, },
};
static struct tuner_params tuner_sharp_2u5jf5540_params[] = {
@@ -502,16 +463,15 @@ static struct tuner_params tuner_sharp_2u5jf5540_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_sharp_2u5jf5540_ntsc_ranges,
.count = ARRAY_SIZE(tuner_sharp_2u5jf5540_ntsc_ranges),
- .config = 0x8e,
},
};
/* ------------ TUNER_Samsung_PAL_TCPM9091PD27 - Samsung PAL ------------ */
static struct tuner_range tuner_samsung_pal_tcpm9091pd27_ranges[] = {
- { 16 * 169 /*MHz*/, 0xa0, },
- { 16 * 464 /*MHz*/, 0x90, },
- { 16 * 999.99 , 0x30, },
+ { 16 * 169 /*MHz*/, 0x8e, 0xa0, },
+ { 16 * 464 /*MHz*/, 0x8e, 0x90, },
+ { 16 * 999.99 , 0x8e, 0x30, },
};
static struct tuner_params tuner_samsung_pal_tcpm9091pd27_params[] = {
@@ -519,7 +479,6 @@ static struct tuner_params tuner_samsung_pal_tcpm9091pd27_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_samsung_pal_tcpm9091pd27_ranges,
.count = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_ranges),
- .config = 0x8e,
},
};
@@ -530,50 +489,35 @@ static struct tuner_params tuner_temic_4106fh5_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_temic_4009f_5_pal_ranges,
.count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
- .config = 0x8e,
},
};
/* ------------ TUNER_TEMIC_4012FY5 - TEMIC PAL ------------ */
-static struct tuner_range tuner_temic_4012fy5_pal_ranges[] = {
- { 16 * 140.25 /*MHz*/, 0x02, },
- { 16 * 463.25 /*MHz*/, 0x04, },
- { 16 * 999.99 , 0x01, },
-};
-
static struct tuner_params tuner_temic_4012fy5_params[] = {
{
.type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_temic_4012fy5_pal_ranges,
- .count = ARRAY_SIZE(tuner_temic_4012fy5_pal_ranges),
- .config = 0x8e,
+ .ranges = tuner_temic_pal_ranges,
+ .count = ARRAY_SIZE(tuner_temic_pal_ranges),
},
};
/* ------------ TUNER_TEMIC_4136FY5 - TEMIC NTSC ------------ */
-static struct tuner_range tuner_temic_4136_fy5_ntsc_ranges[] = {
- { 16 * 158.00 /*MHz*/, 0xa0, },
- { 16 * 453.00 /*MHz*/, 0x90, },
- { 16 * 999.99 , 0x30, },
-};
-
static struct tuner_params tuner_temic_4136_fy5_params[] = {
{
.type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_temic_4136_fy5_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_temic_4136_fy5_ntsc_ranges),
- .config = 0x8e,
+ .ranges = tuner_temic_4x3x_f_5_ntsc_ranges,
+ .count = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges),
},
};
/* ------------ TUNER_LG_PAL_NEW_TAPC - LGINNOTEK PAL ------------ */
static struct tuner_range tuner_lg_new_tapc_ranges[] = {
- { 16 * 170.00 /*MHz*/, 0x01, },
- { 16 * 450.00 /*MHz*/, 0x02, },
- { 16 * 999.99 , 0x08, },
+ { 16 * 170.00 /*MHz*/, 0x8e, 0x01, },
+ { 16 * 450.00 /*MHz*/, 0x8e, 0x02, },
+ { 16 * 999.99 , 0x8e, 0x08, },
};
static struct tuner_params tuner_lg_pal_new_tapc_params[] = {
@@ -581,16 +525,15 @@ static struct tuner_params tuner_lg_pal_new_tapc_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_lg_new_tapc_ranges,
.count = ARRAY_SIZE(tuner_lg_new_tapc_ranges),
- .config = 0x8e,
},
};
/* ------------ TUNER_PHILIPS_FM1216ME_MK3 - Philips PAL ------------ */
static struct tuner_range tuner_fm1216me_mk3_pal_ranges[] = {
- { 16 * 158.00 /*MHz*/, 0x01, },
- { 16 * 442.00 /*MHz*/, 0x02, },
- { 16 * 999.99 , 0x04, },
+ { 16 * 158.00 /*MHz*/, 0x8e, 0x01, },
+ { 16 * 442.00 /*MHz*/, 0x8e, 0x02, },
+ { 16 * 999.99 , 0x8e, 0x04, },
};
static struct tuner_params tuner_fm1216me_mk3_params[] = {
@@ -598,7 +541,6 @@ static struct tuner_params tuner_fm1216me_mk3_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_fm1216me_mk3_pal_ranges,
.count = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges),
- .config = 0x8e,
.cb_first_if_lower_freq = 1,
},
};
@@ -610,7 +552,6 @@ static struct tuner_params tuner_lg_ntsc_new_tapc_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_lg_new_tapc_ranges,
.count = ARRAY_SIZE(tuner_lg_new_tapc_ranges),
- .config = 0x8e,
},
};
@@ -622,16 +563,15 @@ static struct tuner_params tuner_hitachi_ntsc_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_lg_new_tapc_ranges,
.count = ARRAY_SIZE(tuner_lg_new_tapc_ranges),
- .config = 0x8e,
},
};
/* ------------ TUNER_PHILIPS_PAL_MK - Philips PAL ------------ */
static struct tuner_range tuner_philips_pal_mk_pal_ranges[] = {
- { 16 * 140.25 /*MHz*/, 0x01, },
- { 16 * 463.25 /*MHz*/, 0xc2, },
- { 16 * 999.99 , 0xcf, },
+ { 16 * 140.25 /*MHz*/, 0x8e, 0x01, },
+ { 16 * 463.25 /*MHz*/, 0x8e, 0xc2, },
+ { 16 * 999.99 , 0x8e, 0xcf, },
};
static struct tuner_params tuner_philips_pal_mk_params[] = {
@@ -639,16 +579,15 @@ static struct tuner_params tuner_philips_pal_mk_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_philips_pal_mk_pal_ranges,
.count = ARRAY_SIZE(tuner_philips_pal_mk_pal_ranges),
- .config = 0x8e,
},
};
/* ------------ TUNER_PHILIPS_ATSC - Philips ATSC ------------ */
static struct tuner_range tuner_philips_atsc_ranges[] = {
- { 16 * 157.25 /*MHz*/, 0xa0, },
- { 16 * 454.00 /*MHz*/, 0x90, },
- { 16 * 999.99 , 0x30, },
+ { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, },
+ { 16 * 454.00 /*MHz*/, 0x8e, 0x90, },
+ { 16 * 999.99 , 0x8e, 0x30, },
};
static struct tuner_params tuner_philips_atsc_params[] = {
@@ -656,16 +595,15 @@ static struct tuner_params tuner_philips_atsc_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_philips_atsc_ranges,
.count = ARRAY_SIZE(tuner_philips_atsc_ranges),
- .config = 0x8e,
},
};
/* ------------ TUNER_PHILIPS_FM1236_MK3 - Philips NTSC ------------ */
static struct tuner_range tuner_fm1236_mk3_ntsc_ranges[] = {
- { 16 * 160.00 /*MHz*/, 0x01, },
- { 16 * 442.00 /*MHz*/, 0x02, },
- { 16 * 999.99 , 0x04, },
+ { 16 * 160.00 /*MHz*/, 0x8e, 0x01, },
+ { 16 * 442.00 /*MHz*/, 0x8e, 0x02, },
+ { 16 * 999.99 , 0x8e, 0x04, },
};
static struct tuner_params tuner_fm1236_mk3_params[] = {
@@ -673,25 +611,17 @@ static struct tuner_params tuner_fm1236_mk3_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_fm1236_mk3_ntsc_ranges,
.count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
- .config = 0x8e,
.cb_first_if_lower_freq = 1,
},
};
/* ------------ TUNER_PHILIPS_4IN1 - Philips NTSC ------------ */
-static struct tuner_range tuner_philips_4in1_ntsc_ranges[] = {
- { 16 * 160.00 /*MHz*/, 0x01, },
- { 16 * 442.00 /*MHz*/, 0x02, },
- { 16 * 999.99 , 0x04, },
-};
-
static struct tuner_params tuner_philips_4in1_params[] = {
{
.type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_philips_4in1_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_philips_4in1_ntsc_ranges),
- .config = 0x8e,
+ .ranges = tuner_fm1236_mk3_ntsc_ranges,
+ .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
},
};
@@ -702,16 +632,15 @@ static struct tuner_params tuner_microtune_4049_fm5_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_temic_4009f_5_pal_ranges,
.count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
- .config = 0x8e,
},
};
/* ------------ TUNER_PANASONIC_VP27 - Panasonic NTSC ------------ */
static struct tuner_range tuner_panasonic_vp27_ntsc_ranges[] = {
- { 16 * 160.00 /*MHz*/, 0x01, },
- { 16 * 454.00 /*MHz*/, 0x02, },
- { 16 * 999.99 , 0x08, },
+ { 16 * 160.00 /*MHz*/, 0xce, 0x01, },
+ { 16 * 454.00 /*MHz*/, 0xce, 0x02, },
+ { 16 * 999.99 , 0xce, 0x08, },
};
static struct tuner_params tuner_panasonic_vp27_params[] = {
@@ -719,33 +648,25 @@ static struct tuner_params tuner_panasonic_vp27_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_panasonic_vp27_ntsc_ranges,
.count = ARRAY_SIZE(tuner_panasonic_vp27_ntsc_ranges),
- .config = 0xce,
},
};
/* ------------ TUNER_LG_NTSC_TAPE - LGINNOTEK NTSC ------------ */
-static struct tuner_range tuner_lg_ntsc_tape_ranges[] = {
- { 16 * 160.00 /*MHz*/, 0x01, },
- { 16 * 442.00 /*MHz*/, 0x02, },
- { 16 * 999.99 , 0x04, },
-};
-
static struct tuner_params tuner_lg_ntsc_tape_params[] = {
{
.type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_lg_ntsc_tape_ranges,
- .count = ARRAY_SIZE(tuner_lg_ntsc_tape_ranges),
- .config = 0x8e,
+ .ranges = tuner_fm1236_mk3_ntsc_ranges,
+ .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
},
};
/* ------------ TUNER_TNF_8831BGFF - Philips PAL ------------ */
static struct tuner_range tuner_tnf_8831bgff_pal_ranges[] = {
- { 16 * 161.25 /*MHz*/, 0xa0, },
- { 16 * 463.25 /*MHz*/, 0x90, },
- { 16 * 999.99 , 0x30, },
+ { 16 * 161.25 /*MHz*/, 0x8e, 0xa0, },
+ { 16 * 463.25 /*MHz*/, 0x8e, 0x90, },
+ { 16 * 999.99 , 0x8e, 0x30, },
};
static struct tuner_params tuner_tnf_8831bgff_params[] = {
@@ -753,16 +674,15 @@ static struct tuner_params tuner_tnf_8831bgff_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_tnf_8831bgff_pal_ranges,
.count = ARRAY_SIZE(tuner_tnf_8831bgff_pal_ranges),
- .config = 0x8e,
},
};
/* ------------ TUNER_MICROTUNE_4042FI5 - Microtune NTSC ------------ */
static struct tuner_range tuner_microtune_4042fi5_ntsc_ranges[] = {
- { 16 * 162.00 /*MHz*/, 0xa2, },
- { 16 * 457.00 /*MHz*/, 0x94, },
- { 16 * 999.99 , 0x31, },
+ { 16 * 162.00 /*MHz*/, 0x8e, 0xa2, },
+ { 16 * 457.00 /*MHz*/, 0x8e, 0x94, },
+ { 16 * 999.99 , 0x8e, 0x31, },
};
static struct tuner_params tuner_microtune_4042fi5_params[] = {
@@ -770,7 +690,6 @@ static struct tuner_params tuner_microtune_4042fi5_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_microtune_4042fi5_ntsc_ranges,
.count = ARRAY_SIZE(tuner_microtune_4042fi5_ntsc_ranges),
- .config = 0x8e,
},
};
@@ -778,9 +697,9 @@ static struct tuner_params tuner_microtune_4042fi5_params[] = {
/* ------------ TUNER_TCL_2002N - TCL NTSC ------------ */
static struct tuner_range tuner_tcl_2002n_ntsc_ranges[] = {
- { 16 * 172.00 /*MHz*/, 0x01, },
- { 16 * 448.00 /*MHz*/, 0x02, },
- { 16 * 999.99 , 0x08, },
+ { 16 * 172.00 /*MHz*/, 0x8e, 0x01, },
+ { 16 * 448.00 /*MHz*/, 0x8e, 0x02, },
+ { 16 * 999.99 , 0x8e, 0x08, },
};
static struct tuner_params tuner_tcl_2002n_params[] = {
@@ -788,34 +707,26 @@ static struct tuner_params tuner_tcl_2002n_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_tcl_2002n_ntsc_ranges,
.count = ARRAY_SIZE(tuner_tcl_2002n_ntsc_ranges),
- .config = 0x8e,
.cb_first_if_lower_freq = 1,
},
};
/* ------------ TUNER_PHILIPS_FM1256_IH3 - Philips PAL ------------ */
-static struct tuner_range tuner_philips_fm1256_ih3_pal_ranges[] = {
- { 16 * 160.00 /*MHz*/, 0x01, },
- { 16 * 442.00 /*MHz*/, 0x02, },
- { 16 * 999.99 , 0x04, },
-};
-
static struct tuner_params tuner_philips_fm1256_ih3_params[] = {
{
.type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_philips_fm1256_ih3_pal_ranges,
- .count = ARRAY_SIZE(tuner_philips_fm1256_ih3_pal_ranges),
- .config = 0x8e,
+ .ranges = tuner_fm1236_mk3_ntsc_ranges,
+ .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
},
};
/* ------------ TUNER_THOMSON_DTT7610 - THOMSON ATSC ------------ */
static struct tuner_range tuner_thomson_dtt7610_ntsc_ranges[] = {
- { 16 * 157.25 /*MHz*/, 0x39, },
- { 16 * 454.00 /*MHz*/, 0x3a, },
- { 16 * 999.99 , 0x3c, },
+ { 16 * 157.25 /*MHz*/, 0x8e, 0x39, },
+ { 16 * 454.00 /*MHz*/, 0x8e, 0x3a, },
+ { 16 * 999.99 , 0x8e, 0x3c, },
};
static struct tuner_params tuner_thomson_dtt7610_params[] = {
@@ -823,16 +734,15 @@ static struct tuner_params tuner_thomson_dtt7610_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_thomson_dtt7610_ntsc_ranges,
.count = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges),
- .config = 0x8e,
},
};
/* ------------ TUNER_PHILIPS_FQ1286 - Philips NTSC ------------ */
static struct tuner_range tuner_philips_fq1286_ntsc_ranges[] = {
- { 16 * 160.00 /*MHz*/, 0x41, },
- { 16 * 454.00 /*MHz*/, 0x42, },
- { 16 * 999.99 , 0x04, },
+ { 16 * 160.00 /*MHz*/, 0x8e, 0x41, },
+ { 16 * 454.00 /*MHz*/, 0x8e, 0x42, },
+ { 16 * 999.99 , 0x8e, 0x04, },
};
static struct tuner_params tuner_philips_fq1286_params[] = {
@@ -840,16 +750,15 @@ static struct tuner_params tuner_philips_fq1286_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_philips_fq1286_ntsc_ranges,
.count = ARRAY_SIZE(tuner_philips_fq1286_ntsc_ranges),
- .config = 0x8e,
},
};
/* ------------ TUNER_TCL_2002MB - TCL PAL ------------ */
static struct tuner_range tuner_tcl_2002mb_pal_ranges[] = {
- { 16 * 170.00 /*MHz*/, 0x01, },
- { 16 * 450.00 /*MHz*/, 0x02, },
- { 16 * 999.99 , 0x08, },
+ { 16 * 170.00 /*MHz*/, 0xce, 0x01, },
+ { 16 * 450.00 /*MHz*/, 0xce, 0x02, },
+ { 16 * 999.99 , 0xce, 0x08, },
};
static struct tuner_params tuner_tcl_2002mb_params[] = {
@@ -857,24 +766,22 @@ static struct tuner_params tuner_tcl_2002mb_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_tcl_2002mb_pal_ranges,
.count = ARRAY_SIZE(tuner_tcl_2002mb_pal_ranges),
- .config = 0xce,
},
};
/* ------------ TUNER_PHILIPS_FQ1216AME_MK4 - Philips PAL ------------ */
-static struct tuner_range tuner_philips_fq12_6a___mk4_ranges[] = {
- { 16 * 160.00 /*MHz*/, 0x01, },
- { 16 * 442.00 /*MHz*/, 0x02, },
- { 16 * 999.99 , 0x04, },
+static struct tuner_range tuner_philips_fq12_6a___mk4_pal_ranges[] = {
+ { 16 * 160.00 /*MHz*/, 0xce, 0x01, },
+ { 16 * 442.00 /*MHz*/, 0xce, 0x02, },
+ { 16 * 999.99 , 0xce, 0x04, },
};
static struct tuner_params tuner_philips_fq1216ame_mk4_params[] = {
{
.type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_philips_fq12_6a___mk4_ranges,
- .count = ARRAY_SIZE(tuner_philips_fq12_6a___mk4_ranges),
- .config = 0xce,
+ .ranges = tuner_philips_fq12_6a___mk4_pal_ranges,
+ .count = ARRAY_SIZE(tuner_philips_fq12_6a___mk4_pal_ranges),
},
};
@@ -883,35 +790,27 @@ static struct tuner_params tuner_philips_fq1216ame_mk4_params[] = {
static struct tuner_params tuner_philips_fq1236a_mk4_params[] = {
{
.type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_philips_fq12_6a___mk4_ranges,
- .count = ARRAY_SIZE(tuner_philips_fq12_6a___mk4_ranges),
- .config = 0x8e,
+ .ranges = tuner_fm1236_mk3_ntsc_ranges,
+ .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
},
};
/* ------------ TUNER_YMEC_TVF_8531MF - Philips NTSC ------------ */
-static struct tuner_range tuner_ymec_tvf_8531mf_ntsc_ranges[] = {
- { 16 * 160.00 /*MHz*/, 0xa0, },
- { 16 * 454.00 /*MHz*/, 0x90, },
- { 16 * 999.99 , 0x30, },
-};
-
static struct tuner_params tuner_ymec_tvf_8531mf_params[] = {
{
.type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_ymec_tvf_8531mf_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_ymec_tvf_8531mf_ntsc_ranges),
- .config = 0x8e,
+ .ranges = tuner_philips_ntsc_m_ranges,
+ .count = ARRAY_SIZE(tuner_philips_ntsc_m_ranges),
},
};
/* ------------ TUNER_YMEC_TVF_5533MF - Philips NTSC ------------ */
static struct tuner_range tuner_ymec_tvf_5533mf_ntsc_ranges[] = {
- { 16 * 160.00 /*MHz*/, 0x01, },
- { 16 * 454.00 /*MHz*/, 0x02, },
- { 16 * 999.99 , 0x04, },
+ { 16 * 160.00 /*MHz*/, 0x8e, 0x01, },
+ { 16 * 454.00 /*MHz*/, 0x8e, 0x02, },
+ { 16 * 999.99 , 0x8e, 0x04, },
};
static struct tuner_params tuner_ymec_tvf_5533mf_params[] = {
@@ -919,7 +818,6 @@ static struct tuner_params tuner_ymec_tvf_5533mf_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_ymec_tvf_5533mf_ntsc_ranges,
.count = ARRAY_SIZE(tuner_ymec_tvf_5533mf_ntsc_ranges),
- .config = 0x8e,
},
};
@@ -928,9 +826,9 @@ static struct tuner_params tuner_ymec_tvf_5533mf_params[] = {
/* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
static struct tuner_range tuner_thomson_dtt761x_ntsc_ranges[] = {
- { 16 * 145.25 /*MHz*/, 0x39, },
- { 16 * 415.25 /*MHz*/, 0x3a, },
- { 16 * 999.99 , 0x3c, },
+ { 16 * 145.25 /*MHz*/, 0x8e, 0x39, },
+ { 16 * 415.25 /*MHz*/, 0x8e, 0x3a, },
+ { 16 * 999.99 , 0x8e, 0x3c, },
};
@@ -939,42 +837,39 @@ static struct tuner_params tuner_thomson_dtt761x_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_thomson_dtt761x_ntsc_ranges,
.count = ARRAY_SIZE(tuner_thomson_dtt761x_ntsc_ranges),
- .config = 0x8e,
},
};
/* ------------ TUNER_TENA_9533_DI - Philips PAL ------------ */
-static struct tuner_range tuner_tuner_tena_9533_di_pal_ranges[] = {
- { 16 * 160.25 /*MHz*/, 0x01, },
- { 16 * 464.25 /*MHz*/, 0x02, },
- { 16 * 999.99 , 0x04, },
+static struct tuner_range tuner_tena_9533_di_pal_ranges[] = {
+ { 16 * 160.25 /*MHz*/, 0x8e, 0x01, },
+ { 16 * 464.25 /*MHz*/, 0x8e, 0x02, },
+ { 16 * 999.99 , 0x8e, 0x04, },
};
static struct tuner_params tuner_tena_9533_di_params[] = {
{
.type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_tuner_tena_9533_di_pal_ranges,
- .count = ARRAY_SIZE(tuner_tuner_tena_9533_di_pal_ranges),
- .config = 0x8e,
+ .ranges = tuner_tena_9533_di_pal_ranges,
+ .count = ARRAY_SIZE(tuner_tena_9533_di_pal_ranges),
},
};
/* ------------ TUNER_PHILIPS_FMD1216ME_MK3 - Philips PAL ------------ */
static struct tuner_range tuner_philips_fmd1216me_mk3_pal_ranges[] = {
- { 16 * 160.00 /*MHz*/, 0x51, },
- { 16 * 442.00 /*MHz*/, 0x52, },
- { 16 * 999.99 , 0x54, },
+ { 16 * 160.00 /*MHz*/, 0x86, 0x51, },
+ { 16 * 442.00 /*MHz*/, 0x86, 0x52, },
+ { 16 * 999.99 , 0x86, 0x54, },
};
-static struct tuner_params tuner_tuner_philips_fmd1216me_mk3_params[] = {
+static struct tuner_params tuner_philips_fmd1216me_mk3_params[] = {
{
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_philips_fmd1216me_mk3_pal_ranges,
.count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges),
- .config = 0x86,
},
};
@@ -982,9 +877,9 @@ static struct tuner_params tuner_tuner_philips_fmd1216me_mk3_params[] = {
/* ------------ TUNER_LG_TDVS_H062F - INFINEON ATSC ------------ */
static struct tuner_range tuner_tua6034_ntsc_ranges[] = {
- { 16 * 160.00 /*MHz*/, 0x01 },
- { 16 * 455.00 /*MHz*/, 0x02 },
- { 16 * 999.99 , 0x04 },
+ { 16 * 160.00 /*MHz*/, 0x8e, 0x01 },
+ { 16 * 455.00 /*MHz*/, 0x8e, 0x02 },
+ { 16 * 999.99 , 0x8e, 0x04 },
};
@@ -993,50 +888,51 @@ static struct tuner_params tuner_tua6034_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_tua6034_ntsc_ranges,
.count = ARRAY_SIZE(tuner_tua6034_ntsc_ranges),
- .config = 0x8e,
},
};
/* ------------ TUNER_YMEC_TVF66T5_B_DFF - Philips PAL ------------ */
-static struct tuner_range tuner_ymec_tvf66t5_b_dff_pal_ranges[] = {
- { 16 * 160.25 /*MHz*/, 0x01, },
- { 16 * 464.25 /*MHz*/, 0x02, },
- { 16 * 999.99 , 0x08, },
-};
-
static struct tuner_params tuner_ymec_tvf66t5_b_dff_params[] = {
{
.type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_ymec_tvf66t5_b_dff_pal_ranges,
- .count = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_pal_ranges),
- .config = 0x8e,
+ .ranges = tuner_tena_9533_di_pal_ranges,
+ .count = ARRAY_SIZE(tuner_tena_9533_di_pal_ranges),
},
};
/* ------------ TUNER_LG_NTSC_TALN_MINI - LGINNOTEK NTSC ------------ */
-static struct tuner_range tuner_lg_taln_mini_ntsc_ranges[] = {
- { 16 * 137.25 /*MHz*/, 0x01, },
- { 16 * 373.25 /*MHz*/, 0x02, },
- { 16 * 999.99 , 0x08, },
+static struct tuner_range tuner_lg_taln_ntsc_ranges[] = {
+ { 16 * 137.25 /*MHz*/, 0x8e, 0x01, },
+ { 16 * 373.25 /*MHz*/, 0x8e, 0x02, },
+ { 16 * 999.99 , 0x8e, 0x08, },
+};
+
+static struct tuner_range tuner_lg_taln_pal_secam_ranges[] = {
+ { 16 * 150.00 /*MHz*/, 0x8e, 0x01, },
+ { 16 * 425.00 /*MHz*/, 0x8e, 0x02, },
+ { 16 * 999.99 , 0x8e, 0x08, },
};
-static struct tuner_params tuner_lg_taln_mini_params[] = {
+static struct tuner_params tuner_lg_taln_params[] = {
{
.type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_lg_taln_mini_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_lg_taln_mini_ntsc_ranges),
- .config = 0x8e,
+ .ranges = tuner_lg_taln_ntsc_ranges,
+ .count = ARRAY_SIZE(tuner_lg_taln_ntsc_ranges),
+ },{
+ .type = TUNER_PARAM_TYPE_PAL,
+ .ranges = tuner_lg_taln_pal_secam_ranges,
+ .count = ARRAY_SIZE(tuner_lg_taln_pal_secam_ranges),
},
};
/* ------------ TUNER_PHILIPS_TD1316 - Philips PAL ------------ */
static struct tuner_range tuner_philips_td1316_pal_ranges[] = {
- { 16 * 160.00 /*MHz*/, 0xa1, },
- { 16 * 442.00 /*MHz*/, 0xa2, },
- { 16 * 999.99 , 0xa4, },
+ { 16 * 160.00 /*MHz*/, 0xc8, 0xa1, },
+ { 16 * 442.00 /*MHz*/, 0xc8, 0xa2, },
+ { 16 * 999.99 , 0xc8, 0xa4, },
};
static struct tuner_params tuner_philips_td1316_params[] = {
@@ -1044,34 +940,42 @@ static struct tuner_params tuner_philips_td1316_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_philips_td1316_pal_ranges,
.count = ARRAY_SIZE(tuner_philips_td1316_pal_ranges),
- .config = 0xc8,
},
};
/* ------------ TUNER_PHILIPS_TUV1236D - Philips ATSC ------------ */
static struct tuner_range tuner_tuv1236d_ntsc_ranges[] = {
- { 16 * 157.25 /*MHz*/, 0x01, },
- { 16 * 454.00 /*MHz*/, 0x02, },
- { 16 * 999.99 , 0x04, },
+ { 16 * 157.25 /*MHz*/, 0xce, 0x01, },
+ { 16 * 454.00 /*MHz*/, 0xce, 0x02, },
+ { 16 * 999.99 , 0xce, 0x04, },
};
-static struct tuner_params tuner_tuner_tuv1236d_params[] = {
+static struct tuner_params tuner_tuv1236d_params[] = {
{
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_tuv1236d_ntsc_ranges,
.count = ARRAY_SIZE(tuner_tuv1236d_ntsc_ranges),
- .config = 0xce,
},
};
-/* ------------ TUNER_TNF_5335MF - Philips NTSC ------------ */
+/* ------------ TUNER_TNF_xxx5 - Texas Instruments--------- */
+/* This is known to work with Tenna TVF58t5-MFF and TVF5835 MFF
+ * but it is expected to work also with other Tenna/Ymec
+ * models based on TI SN 761677 chip on both PAL and NTSC
+ */
+
+static struct tuner_range tuner_tnf_5335_d_if_pal_ranges[] = {
+ { 16 * 168.25 /*MHz*/, 0x8e, 0x01, },
+ { 16 * 471.25 /*MHz*/, 0x8e, 0x02, },
+ { 16 * 999.99 , 0x8e, 0x08, },
+};
static struct tuner_range tuner_tnf_5335mf_ntsc_ranges[] = {
- { 16 * 157.25 /*MHz*/, 0x01, },
- { 16 * 454.00 /*MHz*/, 0x02, },
- { 16 * 999.99 , 0x04, },
+ { 16 * 169.25 /*MHz*/, 0x8e, 0x01, },
+ { 16 * 469.25 /*MHz*/, 0x8e, 0x02, },
+ { 16 * 999.99 , 0x8e, 0x08, },
};
static struct tuner_params tuner_tnf_5335mf_params[] = {
@@ -1079,7 +983,11 @@ static struct tuner_params tuner_tnf_5335mf_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_tnf_5335mf_ntsc_ranges,
.count = ARRAY_SIZE(tuner_tnf_5335mf_ntsc_ranges),
- .config = 0x8e,
+ },
+ {
+ .type = TUNER_PARAM_TYPE_PAL,
+ .ranges = tuner_tnf_5335_d_if_pal_ranges,
+ .count = ARRAY_SIZE(tuner_tnf_5335_d_if_pal_ranges),
},
};
@@ -1087,9 +995,9 @@ static struct tuner_params tuner_tnf_5335mf_params[] = {
/* ------------ TUNER_SAMSUNG_TCPN_2121P30A - Samsung NTSC ------------ */
static struct tuner_range tuner_samsung_tcpn_2121p30a_ntsc_ranges[] = {
- { 16 * 175.75 /*MHz*/, 0x01, },
- { 16 * 410.25 /*MHz*/, 0x02, },
- { 16 * 999.99 , 0x08, },
+ { 16 * 130.00 /*MHz*/, 0xce, 0x01, },
+ { 16 * 364.50 /*MHz*/, 0xce, 0x02, },
+ { 16 * 999.99 , 0xce, 0x08, },
};
static struct tuner_params tuner_samsung_tcpn_2121p30a_params[] = {
@@ -1097,7 +1005,22 @@ static struct tuner_params tuner_samsung_tcpn_2121p30a_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_samsung_tcpn_2121p30a_ntsc_ranges,
.count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_ntsc_ranges),
- .config = 0xce,
+ },
+};
+
+/* ------------ TUNER_THOMSON_FE6600 - DViCO Hybrid PAL ------------ */
+
+static struct tuner_range tuner_thomson_fe6600_ranges[] = {
+ { 16 * 160.00 /*MHz*/, 0xfe, 0x11, },
+ { 16 * 442.00 /*MHz*/, 0xf6, 0x12, },
+ { 16 * 999.99 , 0xf6, 0x18, },
+};
+
+static struct tuner_params tuner_thomson_fe6600_params[] = {
+ {
+ .type = TUNER_PARAM_TYPE_PAL,
+ .ranges = tuner_thomson_fe6600_ranges,
+ .count = ARRAY_SIZE(tuner_thomson_fe6600_ranges),
},
};
@@ -1108,18 +1031,22 @@ struct tunertype tuners[] = {
[TUNER_TEMIC_PAL] = { /* TEMIC PAL */
.name = "Temic PAL (4002 FH5)",
.params = tuner_temic_pal_params,
+ .count = ARRAY_SIZE(tuner_temic_pal_params),
},
[TUNER_PHILIPS_PAL_I] = { /* Philips PAL_I */
.name = "Philips PAL_I (FI1246 and compatibles)",
.params = tuner_philips_pal_i_params,
+ .count = ARRAY_SIZE(tuner_philips_pal_i_params),
},
[TUNER_PHILIPS_NTSC] = { /* Philips NTSC */
.name = "Philips NTSC (FI1236,FM1236 and compatibles)",
.params = tuner_philips_ntsc_params,
+ .count = ARRAY_SIZE(tuner_philips_ntsc_params),
},
[TUNER_PHILIPS_SECAM] = { /* Philips SECAM */
.name = "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)",
.params = tuner_philips_secam_params,
+ .count = ARRAY_SIZE(tuner_philips_secam_params),
},
[TUNER_ABSENT] = { /* Tuner Absent */
.name = "NoTuner",
@@ -1127,120 +1054,148 @@ struct tunertype tuners[] = {
[TUNER_PHILIPS_PAL] = { /* Philips PAL */
.name = "Philips PAL_BG (FI1216 and compatibles)",
.params = tuner_philips_pal_params,
+ .count = ARRAY_SIZE(tuner_philips_pal_params),
},
[TUNER_TEMIC_NTSC] = { /* TEMIC NTSC */
.name = "Temic NTSC (4032 FY5)",
.params = tuner_temic_ntsc_params,
+ .count = ARRAY_SIZE(tuner_temic_ntsc_params),
},
[TUNER_TEMIC_PAL_I] = { /* TEMIC PAL_I */
.name = "Temic PAL_I (4062 FY5)",
.params = tuner_temic_pal_i_params,
+ .count = ARRAY_SIZE(tuner_temic_pal_i_params),
},
[TUNER_TEMIC_4036FY5_NTSC] = { /* TEMIC NTSC */
.name = "Temic NTSC (4036 FY5)",
.params = tuner_temic_4036fy5_ntsc_params,
+ .count = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_params),
},
[TUNER_ALPS_TSBH1_NTSC] = { /* TEMIC NTSC */
.name = "Alps HSBH1",
.params = tuner_alps_tsbh1_ntsc_params,
+ .count = ARRAY_SIZE(tuner_alps_tsbh1_ntsc_params),
},
/* 10-19 */
[TUNER_ALPS_TSBE1_PAL] = { /* TEMIC PAL */
.name = "Alps TSBE1",
.params = tuner_alps_tsb_1_params,
+ .count = ARRAY_SIZE(tuner_alps_tsb_1_params),
},
[TUNER_ALPS_TSBB5_PAL_I] = { /* Alps PAL_I */
.name = "Alps TSBB5",
.params = tuner_alps_tsbb5_params,
+ .count = ARRAY_SIZE(tuner_alps_tsbb5_params),
},
[TUNER_ALPS_TSBE5_PAL] = { /* Alps PAL */
.name = "Alps TSBE5",
.params = tuner_alps_tsbe5_params,
+ .count = ARRAY_SIZE(tuner_alps_tsbe5_params),
},
[TUNER_ALPS_TSBC5_PAL] = { /* Alps PAL */
.name = "Alps TSBC5",
.params = tuner_alps_tsbc5_params,
+ .count = ARRAY_SIZE(tuner_alps_tsbc5_params),
},
[TUNER_TEMIC_4006FH5_PAL] = { /* TEMIC PAL */
.name = "Temic PAL_BG (4006FH5)",
.params = tuner_temic_4006fh5_params,
+ .count = ARRAY_SIZE(tuner_temic_4006fh5_params),
},
[TUNER_ALPS_TSHC6_NTSC] = { /* Alps NTSC */
.name = "Alps TSCH6",
.params = tuner_alps_tshc6_params,
+ .count = ARRAY_SIZE(tuner_alps_tshc6_params),
},
[TUNER_TEMIC_PAL_DK] = { /* TEMIC PAL */
.name = "Temic PAL_DK (4016 FY5)",
.params = tuner_temic_pal_dk_params,
+ .count = ARRAY_SIZE(tuner_temic_pal_dk_params),
},
[TUNER_PHILIPS_NTSC_M] = { /* Philips NTSC */
.name = "Philips NTSC_M (MK2)",
.params = tuner_philips_ntsc_m_params,
+ .count = ARRAY_SIZE(tuner_philips_ntsc_m_params),
},
[TUNER_TEMIC_4066FY5_PAL_I] = { /* TEMIC PAL_I */
.name = "Temic PAL_I (4066 FY5)",
.params = tuner_temic_4066fy5_pal_i_params,
+ .count = ARRAY_SIZE(tuner_temic_4066fy5_pal_i_params),
},
[TUNER_TEMIC_4006FN5_MULTI_PAL] = { /* TEMIC PAL */
.name = "Temic PAL* auto (4006 FN5)",
.params = tuner_temic_4006fn5_multi_params,
+ .count = ARRAY_SIZE(tuner_temic_4006fn5_multi_params),
},
/* 20-29 */
[TUNER_TEMIC_4009FR5_PAL] = { /* TEMIC PAL */
.name = "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)",
.params = tuner_temic_4009f_5_params,
+ .count = ARRAY_SIZE(tuner_temic_4009f_5_params),
},
[TUNER_TEMIC_4039FR5_NTSC] = { /* TEMIC NTSC */
.name = "Temic NTSC (4039 FR5)",
.params = tuner_temic_4039fr5_params,
+ .count = ARRAY_SIZE(tuner_temic_4039fr5_params),
},
[TUNER_TEMIC_4046FM5] = { /* TEMIC PAL */
.name = "Temic PAL/SECAM multi (4046 FM5)",
.params = tuner_temic_4046fm5_params,
+ .count = ARRAY_SIZE(tuner_temic_4046fm5_params),
},
[TUNER_PHILIPS_PAL_DK] = { /* Philips PAL */
.name = "Philips PAL_DK (FI1256 and compatibles)",
.params = tuner_philips_pal_dk_params,
+ .count = ARRAY_SIZE(tuner_philips_pal_dk_params),
},
[TUNER_PHILIPS_FQ1216ME] = { /* Philips PAL */
.name = "Philips PAL/SECAM multi (FQ1216ME)",
.params = tuner_philips_fq1216me_params,
+ .count = ARRAY_SIZE(tuner_philips_fq1216me_params),
},
[TUNER_LG_PAL_I_FM] = { /* LGINNOTEK PAL_I */
.name = "LG PAL_I+FM (TAPC-I001D)",
.params = tuner_lg_pal_i_fm_params,
+ .count = ARRAY_SIZE(tuner_lg_pal_i_fm_params),
},
[TUNER_LG_PAL_I] = { /* LGINNOTEK PAL_I */
.name = "LG PAL_I (TAPC-I701D)",
.params = tuner_lg_pal_i_params,
+ .count = ARRAY_SIZE(tuner_lg_pal_i_params),
},
[TUNER_LG_NTSC_FM] = { /* LGINNOTEK NTSC */
.name = "LG NTSC+FM (TPI8NSR01F)",
.params = tuner_lg_ntsc_fm_params,
+ .count = ARRAY_SIZE(tuner_lg_ntsc_fm_params),
},
[TUNER_LG_PAL_FM] = { /* LGINNOTEK PAL */
.name = "LG PAL_BG+FM (TPI8PSB01D)",
.params = tuner_lg_pal_fm_params,
+ .count = ARRAY_SIZE(tuner_lg_pal_fm_params),
},
[TUNER_LG_PAL] = { /* LGINNOTEK PAL */
.name = "LG PAL_BG (TPI8PSB11D)",
.params = tuner_lg_pal_params,
+ .count = ARRAY_SIZE(tuner_lg_pal_params),
},
/* 30-39 */
[TUNER_TEMIC_4009FN5_MULTI_PAL_FM] = { /* TEMIC PAL */
.name = "Temic PAL* auto + FM (4009 FN5)",
.params = tuner_temic_4009_fn5_multi_pal_fm_params,
+ .count = ARRAY_SIZE(tuner_temic_4009_fn5_multi_pal_fm_params),
},
[TUNER_SHARP_2U5JF5540_NTSC] = { /* SHARP NTSC */
.name = "SHARP NTSC_JP (2U5JF5540)",
.params = tuner_sharp_2u5jf5540_params,
+ .count = ARRAY_SIZE(tuner_sharp_2u5jf5540_params),
},
[TUNER_Samsung_PAL_TCPM9091PD27] = { /* Samsung PAL */
.name = "Samsung PAL TCPM9091PD27",
.params = tuner_samsung_pal_tcpm9091pd27_params,
+ .count = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_params),
},
[TUNER_MT2032] = { /* Microtune PAL|NTSC */
.name = "MT20xx universal",
@@ -1248,86 +1203,106 @@ struct tunertype tuners[] = {
[TUNER_TEMIC_4106FH5] = { /* TEMIC PAL */
.name = "Temic PAL_BG (4106 FH5)",
.params = tuner_temic_4106fh5_params,
+ .count = ARRAY_SIZE(tuner_temic_4106fh5_params),
},
[TUNER_TEMIC_4012FY5] = { /* TEMIC PAL */
.name = "Temic PAL_DK/SECAM_L (4012 FY5)",
.params = tuner_temic_4012fy5_params,
+ .count = ARRAY_SIZE(tuner_temic_4012fy5_params),
},
[TUNER_TEMIC_4136FY5] = { /* TEMIC NTSC */
.name = "Temic NTSC (4136 FY5)",
.params = tuner_temic_4136_fy5_params,
+ .count = ARRAY_SIZE(tuner_temic_4136_fy5_params),
},
[TUNER_LG_PAL_NEW_TAPC] = { /* LGINNOTEK PAL */
.name = "LG PAL (newer TAPC series)",
.params = tuner_lg_pal_new_tapc_params,
+ .count = ARRAY_SIZE(tuner_lg_pal_new_tapc_params),
},
[TUNER_PHILIPS_FM1216ME_MK3] = { /* Philips PAL */
.name = "Philips PAL/SECAM multi (FM1216ME MK3)",
.params = tuner_fm1216me_mk3_params,
+ .count = ARRAY_SIZE(tuner_fm1216me_mk3_params),
},
[TUNER_LG_NTSC_NEW_TAPC] = { /* LGINNOTEK NTSC */
.name = "LG NTSC (newer TAPC series)",
.params = tuner_lg_ntsc_new_tapc_params,
+ .count = ARRAY_SIZE(tuner_lg_ntsc_new_tapc_params),
},
/* 40-49 */
[TUNER_HITACHI_NTSC] = { /* HITACHI NTSC */
.name = "HITACHI V7-J180AT",
.params = tuner_hitachi_ntsc_params,
+ .count = ARRAY_SIZE(tuner_hitachi_ntsc_params),
},
[TUNER_PHILIPS_PAL_MK] = { /* Philips PAL */
.name = "Philips PAL_MK (FI1216 MK)",
.params = tuner_philips_pal_mk_params,
+ .count = ARRAY_SIZE(tuner_philips_pal_mk_params),
},
[TUNER_PHILIPS_ATSC] = { /* Philips ATSC */
.name = "Philips 1236D ATSC/NTSC dual in",
.params = tuner_philips_atsc_params,
+ .count = ARRAY_SIZE(tuner_philips_atsc_params),
},
[TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */
.name = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)",
.params = tuner_fm1236_mk3_params,
+ .count = ARRAY_SIZE(tuner_fm1236_mk3_params),
},
[TUNER_PHILIPS_4IN1] = { /* Philips NTSC */
.name = "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)",
.params = tuner_philips_4in1_params,
+ .count = ARRAY_SIZE(tuner_philips_4in1_params),
},
[TUNER_MICROTUNE_4049FM5] = { /* Microtune PAL */
.name = "Microtune 4049 FM5",
.params = tuner_microtune_4049_fm5_params,
+ .count = ARRAY_SIZE(tuner_microtune_4049_fm5_params),
},
[TUNER_PANASONIC_VP27] = { /* Panasonic NTSC */
.name = "Panasonic VP27s/ENGE4324D",
.params = tuner_panasonic_vp27_params,
+ .count = ARRAY_SIZE(tuner_panasonic_vp27_params),
},
[TUNER_LG_NTSC_TAPE] = { /* LGINNOTEK NTSC */
.name = "LG NTSC (TAPE series)",
.params = tuner_lg_ntsc_tape_params,
+ .count = ARRAY_SIZE(tuner_lg_ntsc_tape_params),
},
[TUNER_TNF_8831BGFF] = { /* Philips PAL */
.name = "Tenna TNF 8831 BGFF)",
.params = tuner_tnf_8831bgff_params,
+ .count = ARRAY_SIZE(tuner_tnf_8831bgff_params),
},
[TUNER_MICROTUNE_4042FI5] = { /* Microtune NTSC */
.name = "Microtune 4042 FI5 ATSC/NTSC dual in",
.params = tuner_microtune_4042fi5_params,
+ .count = ARRAY_SIZE(tuner_microtune_4042fi5_params),
},
/* 50-59 */
[TUNER_TCL_2002N] = { /* TCL NTSC */
.name = "TCL 2002N",
.params = tuner_tcl_2002n_params,
+ .count = ARRAY_SIZE(tuner_tcl_2002n_params),
},
[TUNER_PHILIPS_FM1256_IH3] = { /* Philips PAL */
.name = "Philips PAL/SECAM_D (FM 1256 I-H3)",
.params = tuner_philips_fm1256_ih3_params,
+ .count = ARRAY_SIZE(tuner_philips_fm1256_ih3_params),
},
[TUNER_THOMSON_DTT7610] = { /* THOMSON ATSC */
.name = "Thomson DTT 7610 (ATSC/NTSC)",
.params = tuner_thomson_dtt7610_params,
+ .count = ARRAY_SIZE(tuner_thomson_dtt7610_params),
},
[TUNER_PHILIPS_FQ1286] = { /* Philips NTSC */
.name = "Philips FQ1286",
.params = tuner_philips_fq1286_params,
+ .count = ARRAY_SIZE(tuner_philips_fq1286_params),
},
[TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */
.name = "tda8290+75",
@@ -1335,22 +1310,27 @@ struct tunertype tuners[] = {
[TUNER_TCL_2002MB] = { /* TCL PAL */
.name = "TCL 2002MB",
.params = tuner_tcl_2002mb_params,
+ .count = ARRAY_SIZE(tuner_tcl_2002mb_params),
},
[TUNER_PHILIPS_FQ1216AME_MK4] = { /* Philips PAL */
.name = "Philips PAL/SECAM multi (FQ1216AME MK4)",
.params = tuner_philips_fq1216ame_mk4_params,
+ .count = ARRAY_SIZE(tuner_philips_fq1216ame_mk4_params),
},
[TUNER_PHILIPS_FQ1236A_MK4] = { /* Philips NTSC */
.name = "Philips FQ1236A MK4",
.params = tuner_philips_fq1236a_mk4_params,
+ .count = ARRAY_SIZE(tuner_philips_fq1236a_mk4_params),
},
[TUNER_YMEC_TVF_8531MF] = { /* Philips NTSC */
.name = "Ymec TVision TVF-8531MF/8831MF/8731MF",
.params = tuner_ymec_tvf_8531mf_params,
+ .count = ARRAY_SIZE(tuner_ymec_tvf_8531mf_params),
},
[TUNER_YMEC_TVF_5533MF] = { /* Philips NTSC */
.name = "Ymec TVision TVF-5533MF",
.params = tuner_ymec_tvf_5533mf_params,
+ .count = ARRAY_SIZE(tuner_ymec_tvf_5533mf_params),
},
/* 60-69 */
@@ -1358,10 +1338,12 @@ struct tunertype tuners[] = {
/* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
.name = "Thomson DTT 761X (ATSC/NTSC)",
.params = tuner_thomson_dtt761x_params,
+ .count = ARRAY_SIZE(tuner_thomson_dtt761x_params),
},
[TUNER_TENA_9533_DI] = { /* Philips PAL */
.name = "Tena TNF9533-D/IF/TNF9533-B/DF",
.params = tuner_tena_9533_di_params,
+ .count = ARRAY_SIZE(tuner_tena_9533_di_params),
},
[TUNER_TEA5767] = { /* Philips RADIO */
.name = "Philips TEA5767HN FM Radio",
@@ -1369,37 +1351,54 @@ struct tunertype tuners[] = {
},
[TUNER_PHILIPS_FMD1216ME_MK3] = { /* Philips PAL */
.name = "Philips FMD1216ME MK3 Hybrid Tuner",
- .params = tuner_tuner_philips_fmd1216me_mk3_params,
+ .params = tuner_philips_fmd1216me_mk3_params,
+ .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_params),
},
[TUNER_LG_TDVS_H062F] = { /* LGINNOTEK ATSC */
.name = "LG TDVS-H062F/TUA6034",
.params = tuner_tua6034_params,
+ .count = ARRAY_SIZE(tuner_tua6034_params),
},
[TUNER_YMEC_TVF66T5_B_DFF] = { /* Philips PAL */
.name = "Ymec TVF66T5-B/DFF",
.params = tuner_ymec_tvf66t5_b_dff_params,
+ .count = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_params),
},
- [TUNER_LG_NTSC_TALN_MINI] = { /* LGINNOTEK NTSC */
- .name = "LG NTSC (TALN mini series)",
- .params = tuner_lg_taln_mini_params,
+ [TUNER_LG_TALN] = { /* LGINNOTEK NTSC / PAL / SECAM */
+ .name = "LG TALN series",
+ .params = tuner_lg_taln_params,
+ .count = ARRAY_SIZE(tuner_lg_taln_params),
},
[TUNER_PHILIPS_TD1316] = { /* Philips PAL */
.name = "Philips TD1316 Hybrid Tuner",
.params = tuner_philips_td1316_params,
+ .count = ARRAY_SIZE(tuner_philips_td1316_params),
},
[TUNER_PHILIPS_TUV1236D] = { /* Philips ATSC */
.name = "Philips TUV1236D ATSC/NTSC dual in",
- .params = tuner_tuner_tuv1236d_params,
+ .params = tuner_tuv1236d_params,
+ .count = ARRAY_SIZE(tuner_tuv1236d_params),
},
- [TUNER_TNF_5335MF] = { /* Philips NTSC */
- .name = "Tena TNF 5335 MF",
+ [TUNER_TNF_5335MF] = { /* Tenna PAL/NTSC */
+ .name = "Tena TNF 5335 and similar models",
.params = tuner_tnf_5335mf_params,
+ .count = ARRAY_SIZE(tuner_tnf_5335mf_params),
},
/* 70-79 */
[TUNER_SAMSUNG_TCPN_2121P30A] = { /* Samsung NTSC */
.name = "Samsung TCPN 2121P30A",
.params = tuner_samsung_tcpn_2121p30a_params,
+ .count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_params),
+ },
+ [TUNER_XCEIVE_XC3028] = { /* Xceive 3028 */
+ .name = "Xceive xc3028",
+ /* see xc3028.c for details */
+ },
+ [TUNER_THOMSON_FE6600] = { /* Thomson PAL / DVB-T */
+ .name = "Thomson FE6600",
+ .params = tuner_thomson_fe6600_params,
+ .count = ARRAY_SIZE(tuner_thomson_fe6600_params),
},
};
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index c8e5ad0e818..4efb01bb44a 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -130,6 +130,7 @@ struct CHIPSTATE {
struct timer_list wt;
int done;
int watch_stereo;
+ int audmode;
};
/* ---------------------------------------------------------------------- */
@@ -1514,6 +1515,7 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind)
chip->type = desc-chiplist;
chip->shadow.count = desc->registers+1;
chip->prevmode = -1;
+ chip->audmode = V4L2_TUNER_MODE_LANG1;
/* register */
i2c_attach_client(&chip->c);
@@ -1671,6 +1673,8 @@ static int chip_command(struct i2c_client *client,
struct v4l2_tuner *vt = arg;
int mode = 0;
+ if (chip->radio)
+ break;
switch (vt->audmode) {
case V4L2_TUNER_MODE_MONO:
mode = VIDEO_SOUND_MONO;
@@ -1685,8 +1689,9 @@ static int chip_command(struct i2c_client *client,
mode = VIDEO_SOUND_LANG2;
break;
default:
- break;
+ return -EINVAL;
}
+ chip->audmode = vt->audmode;
if (desc->setmode && mode) {
chip->watch_stereo = 0;
@@ -1704,7 +1709,7 @@ static int chip_command(struct i2c_client *client,
if (chip->radio)
break;
- vt->audmode = 0;
+ vt->audmode = chip->audmode;
vt->rxsubchans = 0;
vt->capability = V4L2_TUNER_CAP_STEREO |
V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
@@ -1716,19 +1721,12 @@ static int chip_command(struct i2c_client *client,
vt->rxsubchans |= V4L2_TUNER_SUB_MONO;
if (mode & VIDEO_SOUND_STEREO)
vt->rxsubchans |= V4L2_TUNER_SUB_STEREO;
+ /* Note: for SAP it should be mono/lang2 or stereo/lang2.
+ When this module is converted fully to v4l2, then this
+ should change for those chips that can detect SAP. */
if (mode & VIDEO_SOUND_LANG1)
- vt->rxsubchans |= V4L2_TUNER_SUB_LANG1 |
- V4L2_TUNER_SUB_LANG2;
-
- mode = chip->mode;
- if (mode & VIDEO_SOUND_MONO)
- vt->audmode = V4L2_TUNER_MODE_MONO;
- if (mode & VIDEO_SOUND_STEREO)
- vt->audmode = V4L2_TUNER_MODE_STEREO;
- if (mode & VIDEO_SOUND_LANG1)
- vt->audmode = V4L2_TUNER_MODE_LANG1;
- if (mode & VIDEO_SOUND_LANG2)
- vt->audmode = V4L2_TUNER_MODE_LANG2;
+ vt->rxsubchans = V4L2_TUNER_SUB_LANG1 |
+ V4L2_TUNER_SUB_LANG2;
break;
}
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index 1864423b304..69d0fe159f4 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -1,8 +1,8 @@
/*
- * tvp5150 - Texas Instruments TVP5150A(M) video decoder driver
+ * tvp5150 - Texas Instruments TVP5150A/AM1 video decoder driver
*
- * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@brturbo.com.br)
- * This code is placed under the terms of the GNU General Public License
+ * Copyright (c) 2005,2006 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNU General Public License v2
*/
#include <linux/i2c.h>
@@ -13,10 +13,11 @@
#include "tvp5150_reg.h"
-MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver"); /* standard i2c insmod options */
+MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver");
MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_LICENSE("GPL");
+/* standard i2c insmod options */
static unsigned short normal_i2c[] = {
0xb8 >> 1,
0xba >> 1,
@@ -29,6 +30,9 @@ static int debug = 0;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
+#define tvp5150_err(fmt, arg...) do { \
+ printk(KERN_ERR "%s %d-%04x: " fmt, c->driver->driver.name, \
+ i2c_adapter_id(c->adapter), c->addr , ## arg); } while (0)
#define tvp5150_info(fmt, arg...) do { \
printk(KERN_INFO "%s %d-%04x: " fmt, c->driver->driver.name, \
i2c_adapter_id(c->adapter), c->addr , ## arg); } while (0)
@@ -84,7 +88,7 @@ static struct v4l2_queryctrl tvp5150_qctrl[] = {
struct tvp5150 {
struct i2c_client *client;
- int norm;
+ v4l2_std_id norm; /* Current set standard */
int input;
int enable;
int bright;
@@ -125,310 +129,155 @@ static inline void tvp5150_write(struct i2c_client *c, unsigned char addr,
tvp5150_dbg(0, "i2c i/o error: rc == %d (should be 2)\n", rc);
}
+static void dump_reg_range(struct i2c_client *c, char *s, u8 init, const u8 end,int max_line)
+{
+ int i=0;
+
+ while (init!=(u8)(end+1)) {
+ if ((i%max_line) == 0) {
+ if (i>0)
+ printk("\n");
+ printk("tvp5150: %s reg 0x%02x = ",s,init);
+ }
+ printk("%02x ",tvp5150_read(c, init));
+
+ init++;
+ i++;
+ }
+ printk("\n");
+}
+
static void dump_reg(struct i2c_client *c)
{
printk("tvp5150: Video input source selection #1 = 0x%02x\n",
- tvp5150_read(c, TVP5150_VD_IN_SRC_SEL_1));
+ tvp5150_read(c, TVP5150_VD_IN_SRC_SEL_1));
printk("tvp5150: Analog channel controls = 0x%02x\n",
- tvp5150_read(c, TVP5150_ANAL_CHL_CTL));
+ tvp5150_read(c, TVP5150_ANAL_CHL_CTL));
printk("tvp5150: Operation mode controls = 0x%02x\n",
- tvp5150_read(c, TVP5150_OP_MODE_CTL));
+ tvp5150_read(c, TVP5150_OP_MODE_CTL));
printk("tvp5150: Miscellaneous controls = 0x%02x\n",
- tvp5150_read(c, TVP5150_MISC_CTL));
- printk("tvp5150: Autoswitch mask: TVP5150A / TVP5150AM = 0x%02x\n",
- tvp5150_read(c, TVP5150_AUTOSW_MSK));
+ tvp5150_read(c, TVP5150_MISC_CTL));
+ printk("tvp5150: Autoswitch mask= 0x%02x\n",
+ tvp5150_read(c, TVP5150_AUTOSW_MSK));
printk("tvp5150: Color killer threshold control = 0x%02x\n",
- tvp5150_read(c, TVP5150_COLOR_KIL_THSH_CTL));
- printk("tvp5150: Luminance processing control #1 = 0x%02x\n",
- tvp5150_read(c, TVP5150_LUMA_PROC_CTL_1));
- printk("tvp5150: Luminance processing control #2 = 0x%02x\n",
- tvp5150_read(c, TVP5150_LUMA_PROC_CTL_2));
+ tvp5150_read(c, TVP5150_COLOR_KIL_THSH_CTL));
+ printk("tvp5150: Luminance processing controls #1 #2 and #3 = %02x %02x %02x\n",
+ tvp5150_read(c, TVP5150_LUMA_PROC_CTL_1),
+ tvp5150_read(c, TVP5150_LUMA_PROC_CTL_2),
+ tvp5150_read(c, TVP5150_LUMA_PROC_CTL_3));
printk("tvp5150: Brightness control = 0x%02x\n",
- tvp5150_read(c, TVP5150_BRIGHT_CTL));
+ tvp5150_read(c, TVP5150_BRIGHT_CTL));
printk("tvp5150: Color saturation control = 0x%02x\n",
- tvp5150_read(c, TVP5150_SATURATION_CTL));
+ tvp5150_read(c, TVP5150_SATURATION_CTL));
printk("tvp5150: Hue control = 0x%02x\n",
- tvp5150_read(c, TVP5150_HUE_CTL));
+ tvp5150_read(c, TVP5150_HUE_CTL));
printk("tvp5150: Contrast control = 0x%02x\n",
- tvp5150_read(c, TVP5150_CONTRAST_CTL));
+ tvp5150_read(c, TVP5150_CONTRAST_CTL));
printk("tvp5150: Outputs and data rates select = 0x%02x\n",
- tvp5150_read(c, TVP5150_DATA_RATE_SEL));
- printk("tvp5150: Luminance processing control #3 = 0x%02x\n",
- tvp5150_read(c, TVP5150_LUMA_PROC_CTL_3));
+ tvp5150_read(c, TVP5150_DATA_RATE_SEL));
printk("tvp5150: Configuration shared pins = 0x%02x\n",
- tvp5150_read(c, TVP5150_CONF_SHARED_PIN));
- printk("tvp5150: Active video cropping start MSB = 0x%02x\n",
- tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_MSB));
- printk("tvp5150: Active video cropping start LSB = 0x%02x\n",
- tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_LSB));
- printk("tvp5150: Active video cropping stop MSB = 0x%02x\n",
- tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_MSB));
- printk("tvp5150: Active video cropping stop LSB = 0x%02x\n",
- tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_LSB));
+ tvp5150_read(c, TVP5150_CONF_SHARED_PIN));
+ printk("tvp5150: Active video cropping start = 0x%02x%02x\n",
+ tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_MSB),
+ tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_LSB));
+ printk("tvp5150: Active video cropping stop = 0x%02x%02x\n",
+ tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_MSB),
+ tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_LSB));
printk("tvp5150: Genlock/RTC = 0x%02x\n",
- tvp5150_read(c, TVP5150_GENLOCK));
+ tvp5150_read(c, TVP5150_GENLOCK));
printk("tvp5150: Horizontal sync start = 0x%02x\n",
- tvp5150_read(c, TVP5150_HORIZ_SYNC_START));
+ tvp5150_read(c, TVP5150_HORIZ_SYNC_START));
printk("tvp5150: Vertical blanking start = 0x%02x\n",
- tvp5150_read(c, TVP5150_VERT_BLANKING_START));
+ tvp5150_read(c, TVP5150_VERT_BLANKING_START));
printk("tvp5150: Vertical blanking stop = 0x%02x\n",
- tvp5150_read(c, TVP5150_VERT_BLANKING_STOP));
- printk("tvp5150: Chrominance processing control #1 = 0x%02x\n",
- tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_1));
- printk("tvp5150: Chrominance processing control #2 = 0x%02x\n",
- tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_2));
+ tvp5150_read(c, TVP5150_VERT_BLANKING_STOP));
+ printk("tvp5150: Chrominance processing control #1 and #2 = %02x %02x\n",
+ tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_1),
+ tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_2));
printk("tvp5150: Interrupt reset register B = 0x%02x\n",
- tvp5150_read(c, TVP5150_INT_RESET_REG_B));
+ tvp5150_read(c, TVP5150_INT_RESET_REG_B));
printk("tvp5150: Interrupt enable register B = 0x%02x\n",
- tvp5150_read(c, TVP5150_INT_ENABLE_REG_B));
+ tvp5150_read(c, TVP5150_INT_ENABLE_REG_B));
printk("tvp5150: Interrupt configuration register B = 0x%02x\n",
- tvp5150_read(c, TVP5150_INTT_CONFIG_REG_B));
+ tvp5150_read(c, TVP5150_INTT_CONFIG_REG_B));
printk("tvp5150: Video standard = 0x%02x\n",
- tvp5150_read(c, TVP5150_VIDEO_STD));
- printk("tvp5150: Cb gain factor = 0x%02x\n",
- tvp5150_read(c, TVP5150_CB_GAIN_FACT));
- printk("tvp5150: Cr gain factor = 0x%02x\n",
- tvp5150_read(c, TVP5150_CR_GAIN_FACTOR));
+ tvp5150_read(c, TVP5150_VIDEO_STD));
+ printk("tvp5150: Chroma gain factor: Cb=0x%02x Cr=0x%02x\n",
+ tvp5150_read(c, TVP5150_CB_GAIN_FACT),
+ tvp5150_read(c, TVP5150_CR_GAIN_FACTOR));
printk("tvp5150: Macrovision on counter = 0x%02x\n",
- tvp5150_read(c, TVP5150_MACROVISION_ON_CTR));
+ tvp5150_read(c, TVP5150_MACROVISION_ON_CTR));
printk("tvp5150: Macrovision off counter = 0x%02x\n",
- tvp5150_read(c, TVP5150_MACROVISION_OFF_CTR));
- printk("tvp5150: revision select (TVP5150AM1 only) = 0x%02x\n",
- tvp5150_read(c, TVP5150_REV_SELECT));
- printk("tvp5150: MSB of device ID = 0x%02x\n",
- tvp5150_read(c, TVP5150_MSB_DEV_ID));
- printk("tvp5150: LSB of device ID = 0x%02x\n",
- tvp5150_read(c, TVP5150_LSB_DEV_ID));
- printk("tvp5150: ROM major version = 0x%02x\n",
- tvp5150_read(c, TVP5150_ROM_MAJOR_VER));
- printk("tvp5150: ROM minor version = 0x%02x\n",
- tvp5150_read(c, TVP5150_ROM_MINOR_VER));
- printk("tvp5150: Vertical line count MSB = 0x%02x\n",
- tvp5150_read(c, TVP5150_VERT_LN_COUNT_MSB));
- printk("tvp5150: Vertical line count LSB = 0x%02x\n",
- tvp5150_read(c, TVP5150_VERT_LN_COUNT_LSB));
+ tvp5150_read(c, TVP5150_MACROVISION_OFF_CTR));
+ printk("tvp5150: ITU-R BT.656.%d timing(TVP5150AM1 only)\n",
+ (tvp5150_read(c, TVP5150_REV_SELECT)&1)?3:4);
+ printk("tvp5150: Device ID = %02x%02x\n",
+ tvp5150_read(c, TVP5150_MSB_DEV_ID),
+ tvp5150_read(c, TVP5150_LSB_DEV_ID));
+ printk("tvp5150: ROM version = (hex) %02x.%02x\n",
+ tvp5150_read(c, TVP5150_ROM_MAJOR_VER),
+ tvp5150_read(c, TVP5150_ROM_MINOR_VER));
+ printk("tvp5150: Vertical line count = 0x%02x%02x\n",
+ tvp5150_read(c, TVP5150_VERT_LN_COUNT_MSB),
+ tvp5150_read(c, TVP5150_VERT_LN_COUNT_LSB));
printk("tvp5150: Interrupt status register B = 0x%02x\n",
- tvp5150_read(c, TVP5150_INT_STATUS_REG_B));
+ tvp5150_read(c, TVP5150_INT_STATUS_REG_B));
printk("tvp5150: Interrupt active register B = 0x%02x\n",
- tvp5150_read(c, TVP5150_INT_ACTIVE_REG_B));
- printk("tvp5150: Status register #1 = 0x%02x\n",
- tvp5150_read(c, TVP5150_STATUS_REG_1));
- printk("tvp5150: Status register #2 = 0x%02x\n",
- tvp5150_read(c, TVP5150_STATUS_REG_2));
- printk("tvp5150: Status register #3 = 0x%02x\n",
- tvp5150_read(c, TVP5150_STATUS_REG_3));
- printk("tvp5150: Status register #4 = 0x%02x\n",
- tvp5150_read(c, TVP5150_STATUS_REG_4));
- printk("tvp5150: Status register #5 = 0x%02x\n",
- tvp5150_read(c, TVP5150_STATUS_REG_5));
- printk("tvp5150: Closed caption data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_CC_DATA_REG1));
- printk("tvp5150: Closed caption data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_CC_DATA_REG2));
- printk("tvp5150: Closed caption data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_CC_DATA_REG3));
- printk("tvp5150: Closed caption data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_CC_DATA_REG4));
- printk("tvp5150: WSS data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_WSS_DATA_REG1));
- printk("tvp5150: WSS data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_WSS_DATA_REG2));
- printk("tvp5150: WSS data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_WSS_DATA_REG3));
- printk("tvp5150: WSS data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_WSS_DATA_REG4));
- printk("tvp5150: WSS data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_WSS_DATA_REG5));
- printk("tvp5150: WSS data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_WSS_DATA_REG6));
- printk("tvp5150: VPS data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_VPS_DATA_REG1));
- printk("tvp5150: VPS data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_VPS_DATA_REG2));
- printk("tvp5150: VPS data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_VPS_DATA_REG3));
- printk("tvp5150: VPS data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_VPS_DATA_REG4));
- printk("tvp5150: VPS data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_VPS_DATA_REG5));
- printk("tvp5150: VPS data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_VPS_DATA_REG6));
- printk("tvp5150: VPS data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_VPS_DATA_REG7));
- printk("tvp5150: VPS data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_VPS_DATA_REG8));
- printk("tvp5150: VPS data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_VPS_DATA_REG9));
- printk("tvp5150: VPS data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_VPS_DATA_REG10));
- printk("tvp5150: VPS data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_VPS_DATA_REG11));
- printk("tvp5150: VPS data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_VPS_DATA_REG12));
- printk("tvp5150: VPS data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_VPS_DATA_REG13));
- printk("tvp5150: VITC data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_VITC_DATA_REG1));
- printk("tvp5150: VITC data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_VITC_DATA_REG2));
- printk("tvp5150: VITC data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_VITC_DATA_REG3));
- printk("tvp5150: VITC data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_VITC_DATA_REG4));
- printk("tvp5150: VITC data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_VITC_DATA_REG5));
- printk("tvp5150: VITC data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_VITC_DATA_REG6));
- printk("tvp5150: VITC data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_VITC_DATA_REG7));
- printk("tvp5150: VITC data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_VITC_DATA_REG8));
- printk("tvp5150: VITC data registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_VITC_DATA_REG9));
- printk("tvp5150: VBI FIFO read data = 0x%02x\n",
- tvp5150_read(c, TVP5150_VBI_FIFO_READ_DATA));
- printk("tvp5150: Teletext filter 1 = 0x%02x\n",
- tvp5150_read(c, TVP5150_TELETEXT_FIL_1_1));
- printk("tvp5150: Teletext filter 1 = 0x%02x\n",
- tvp5150_read(c, TVP5150_TELETEXT_FIL_1_2));
- printk("tvp5150: Teletext filter 1 = 0x%02x\n",
- tvp5150_read(c, TVP5150_TELETEXT_FIL_1_3));
- printk("tvp5150: Teletext filter 1 = 0x%02x\n",
- tvp5150_read(c, TVP5150_TELETEXT_FIL_1_4));
- printk("tvp5150: Teletext filter 1 = 0x%02x\n",
- tvp5150_read(c, TVP5150_TELETEXT_FIL_1_5));
- printk("tvp5150: Teletext filter 2 = 0x%02x\n",
- tvp5150_read(c, TVP5150_TELETEXT_FIL_2_1));
- printk("tvp5150: Teletext filter 2 = 0x%02x\n",
- tvp5150_read(c, TVP5150_TELETEXT_FIL_2_2));
- printk("tvp5150: Teletext filter 2 = 0x%02x\n",
- tvp5150_read(c, TVP5150_TELETEXT_FIL_2_3));
- printk("tvp5150: Teletext filter 2 = 0x%02x\n",
- tvp5150_read(c, TVP5150_TELETEXT_FIL_2_4));
- printk("tvp5150: Teletext filter 2 = 0x%02x\n",
- tvp5150_read(c, TVP5150_TELETEXT_FIL_2_5));
+ tvp5150_read(c, TVP5150_INT_ACTIVE_REG_B));
+ printk("tvp5150: Status regs #1 to #5 = %02x %02x %02x %02x %02x\n",
+ tvp5150_read(c, TVP5150_STATUS_REG_1),
+ tvp5150_read(c, TVP5150_STATUS_REG_2),
+ tvp5150_read(c, TVP5150_STATUS_REG_3),
+ tvp5150_read(c, TVP5150_STATUS_REG_4),
+ tvp5150_read(c, TVP5150_STATUS_REG_5));
+
+ dump_reg_range(c,"Teletext filter 1", TVP5150_TELETEXT_FIL1_INI,
+ TVP5150_TELETEXT_FIL1_END,8);
+ dump_reg_range(c,"Teletext filter 2", TVP5150_TELETEXT_FIL2_INI,
+ TVP5150_TELETEXT_FIL2_END,8);
+
printk("tvp5150: Teletext filter enable = 0x%02x\n",
- tvp5150_read(c, TVP5150_TELETEXT_FIL_ENA));
+ tvp5150_read(c, TVP5150_TELETEXT_FIL_ENA));
printk("tvp5150: Interrupt status register A = 0x%02x\n",
- tvp5150_read(c, TVP5150_INT_STATUS_REG_A));
+ tvp5150_read(c, TVP5150_INT_STATUS_REG_A));
printk("tvp5150: Interrupt enable register A = 0x%02x\n",
- tvp5150_read(c, TVP5150_INT_ENABLE_REG_A));
+ tvp5150_read(c, TVP5150_INT_ENABLE_REG_A));
printk("tvp5150: Interrupt configuration = 0x%02x\n",
- tvp5150_read(c, TVP5150_INT_CONF));
- printk("tvp5150: VDP configuration RAM data = 0x%02x\n",
- tvp5150_read(c, TVP5150_VDP_CONF_RAM_DATA));
- printk("tvp5150: Configuration RAM address low byte = 0x%02x\n",
- tvp5150_read(c, TVP5150_CONF_RAM_ADDR_LOW));
- printk("tvp5150: Configuration RAM address high byte = 0x%02x\n",
- tvp5150_read(c, TVP5150_CONF_RAM_ADDR_HIGH));
+ tvp5150_read(c, TVP5150_INT_CONF));
printk("tvp5150: VDP status register = 0x%02x\n",
- tvp5150_read(c, TVP5150_VDP_STATUS_REG));
+ tvp5150_read(c, TVP5150_VDP_STATUS_REG));
printk("tvp5150: FIFO word count = 0x%02x\n",
- tvp5150_read(c, TVP5150_FIFO_WORD_COUNT));
+ tvp5150_read(c, TVP5150_FIFO_WORD_COUNT));
printk("tvp5150: FIFO interrupt threshold = 0x%02x\n",
- tvp5150_read(c, TVP5150_FIFO_INT_THRESHOLD));
+ tvp5150_read(c, TVP5150_FIFO_INT_THRESHOLD));
printk("tvp5150: FIFO reset = 0x%02x\n",
- tvp5150_read(c, TVP5150_FIFO_RESET));
+ tvp5150_read(c, TVP5150_FIFO_RESET));
printk("tvp5150: Line number interrupt = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_NUMBER_INT));
- printk("tvp5150: Pixel alignment register low byte = 0x%02x\n",
- tvp5150_read(c, TVP5150_PIX_ALIGN_REG_LOW));
- printk("tvp5150: Pixel alignment register high byte = 0x%02x\n",
- tvp5150_read(c, TVP5150_PIX_ALIGN_REG_HIGH));
+ tvp5150_read(c, TVP5150_LINE_NUMBER_INT));
+ printk("tvp5150: Pixel alignment register = 0x%02x%02x\n",
+ tvp5150_read(c, TVP5150_PIX_ALIGN_REG_HIGH),
+ tvp5150_read(c, TVP5150_PIX_ALIGN_REG_LOW));
printk("tvp5150: FIFO output control = 0x%02x\n",
- tvp5150_read(c, TVP5150_FIFO_OUT_CTRL));
- printk("tvp5150: Full field enable 1 = 0x%02x\n",
- tvp5150_read(c, TVP5150_FULL_FIELD_ENA_1));
- printk("tvp5150: Full field enable 2 = 0x%02x\n",
- tvp5150_read(c, TVP5150_FULL_FIELD_ENA_2));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_1));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_2));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_3));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_4));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_5));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_6));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_7));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_8));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_9));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_10));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_11));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_12));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_13));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_14));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_15));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_16));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_17));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_18));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_19));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_20));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_21));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_22));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_23));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_24));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_25));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_27));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_28));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_29));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_30));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_31));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_32));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_33));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_34));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_35));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_36));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_37));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_38));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_39));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_40));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_41));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_42));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_43));
- printk("tvp5150: Line mode registers = 0x%02x\n",
- tvp5150_read(c, TVP5150_LINE_MODE_REG_44));
+ tvp5150_read(c, TVP5150_FIFO_OUT_CTRL));
+ printk("tvp5150: Full field enable = 0x%02x\n",
+ tvp5150_read(c, TVP5150_FULL_FIELD_ENA));
printk("tvp5150: Full field mode register = 0x%02x\n",
- tvp5150_read(c, TVP5150_FULL_FIELD_MODE_REG));
+ tvp5150_read(c, TVP5150_FULL_FIELD_MODE_REG));
+
+ dump_reg_range(c,"CC data", TVP5150_CC_DATA_INI,
+ TVP5150_CC_DATA_END,8);
+
+ dump_reg_range(c,"WSS data", TVP5150_WSS_DATA_INI,
+ TVP5150_WSS_DATA_END,8);
+
+ dump_reg_range(c,"VPS data", TVP5150_VPS_DATA_INI,
+ TVP5150_VPS_DATA_END,8);
+
+ dump_reg_range(c,"VITC data", TVP5150_VITC_DATA_INI,
+ TVP5150_VITC_DATA_END,10);
+
+ dump_reg_range(c,"Line mode", TVP5150_LINE_MODE_INI,
+ TVP5150_LINE_MODE_END,8);
}
/****************************************************************************
@@ -593,10 +442,10 @@ static const struct i2c_reg_value tvp5150_init_default[] = {
TVP5150_FIFO_OUT_CTRL,0x01
},
{ /* 0xcf */
- TVP5150_FULL_FIELD_ENA_1,0x00
+ TVP5150_FULL_FIELD_ENA,0x00
},
{ /* 0xd0 */
- TVP5150_FULL_FIELD_ENA_2,0x00
+ TVP5150_LINE_MODE_INI,0x00
},
{ /* 0xfc */
TVP5150_FULL_FIELD_MODE_REG,0x7f
@@ -629,54 +478,101 @@ static const struct i2c_reg_value tvp5150_init_enable[] = {
}
};
+struct tvp5150_vbi_type {
+ unsigned int vbi_type;
+ unsigned int ini_line;
+ unsigned int end_line;
+ unsigned int by_field :1;
+};
+
struct i2c_vbi_ram_value {
u16 reg;
- unsigned char values[26];
+ struct tvp5150_vbi_type type;
+ unsigned char values[16];
};
+/* This struct have the values for each supported VBI Standard
+ * by
+ tvp5150_vbi_types should follow the same order as vbi_ram_default
+ * value 0 means rom position 0x10, value 1 means rom position 0x30
+ * and so on. There are 16 possible locations from 0 to 15.
+ */
+
static struct i2c_vbi_ram_value vbi_ram_default[] =
{
- {0x010, /* WST SECAM 6 */
- { 0xaa, 0xaa, 0xff, 0xff , 0xe7, 0x2e, 0x20, 0x26, 0xe6, 0xb4, 0x0e, 0x0, 0x0, 0x0, 0x10, 0x0 }
+ {0x010, /* Teletext, SECAM, WST System A */
+ {V4L2_SLICED_TELETEXT_SECAM,6,23,1},
+ { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x26,
+ 0xe6, 0xb4, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00 }
},
- {0x030, /* WST PAL B 6 */
- { 0xaa, 0xaa, 0xff, 0xff , 0x27, 0x2e, 0x20, 0x2b, 0xa6, 0x72, 0x10, 0x0, 0x0, 0x0, 0x10, 0x0 }
+ {0x030, /* Teletext, PAL, WST System B */
+ {V4L2_SLICED_TELETEXT_PAL_B,6,22,1},
+ { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x2b,
+ 0xa6, 0x72, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00 }
},
- {0x050, /* WST PAL C 6 */
- { 0xaa, 0xaa, 0xff, 0xff , 0xe7, 0x2e, 0x20, 0x22, 0xa6, 0x98, 0x0d, 0x0, 0x0, 0x0, 0x10, 0x0 }
+ {0x050, /* Teletext, PAL, WST System C */
+ {V4L2_SLICED_TELETEXT_PAL_C,6,22,1},
+ { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22,
+ 0xa6, 0x98, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
},
- {0x070, /* WST NTSC 6 */
- { 0xaa, 0xaa, 0xff, 0xff , 0x27, 0x2e, 0x20, 0x23, 0x69, 0x93, 0x0d, 0x0, 0x0, 0x0, 0x10, 0x0 }
+ {0x070, /* Teletext, NTSC, WST System B */
+ {V4L2_SLICED_TELETEXT_NTSC_B,10,21,1},
+ { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x23,
+ 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
},
- {0x090, /* NABTS, NTSC 6 */
- { 0xaa, 0xaa, 0xff, 0xff , 0xe7, 0x2e, 0x20, 0x22, 0x69, 0x93, 0x0d, 0x0, 0x0, 0x0, 0x15, 0x0 }
+ {0x090, /* Tetetext, NTSC NABTS System C */
+ {V4L2_SLICED_TELETEXT_NTSC_C,10,21,1},
+ { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22,
+ 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x15, 0x00 }
},
- {0x0b0, /* NABTS, NTSC-J 6 */
- { 0xaa, 0xaa, 0xff, 0xff , 0xa7, 0x2e, 0x20, 0x23, 0x69, 0x93, 0x0d, 0x0, 0x0, 0x0, 0x10, 0x0 }
+ {0x0b0, /* Teletext, NTSC-J, NABTS System D */
+ {V4L2_SLICED_TELETEXT_NTSC_D,10,21,1},
+ { 0xaa, 0xaa, 0xff, 0xff, 0xa7, 0x2e, 0x20, 0x23,
+ 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
},
- {0x0d0, /* CC, PAL/SECAM 6 */
- { 0xaa, 0x2a, 0xff, 0x3f , 0x04, 0x51, 0x6e, 0x02, 0xa6, 0x7b, 0x09, 0x0, 0x0, 0x0, 0x27, 0x0 }
+ {0x0d0, /* Closed Caption, PAL/SECAM */
+ {V4L2_SLICED_CAPTION_625,22,22,1},
+ { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02,
+ 0xa6, 0x7b, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 }
},
- {0x0f0, /* CC, NTSC 6 */
- { 0xaa, 0x2a, 0xff, 0x3f , 0x04, 0x51, 0x6e, 0x02, 0x69, 0x8c, 0x09, 0x0, 0x0, 0x0, 0x27, 0x0 }
+ {0x0f0, /* Closed Caption, NTSC */
+ {V4L2_SLICED_CAPTION_525,21,21,1},
+ { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02,
+ 0x69, 0x8c, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 }
},
- {0x110, /* WSS, PAL/SECAM 6 */
- { 0x5b, 0x55, 0xc5, 0xff , 0x0, 0x71, 0x6e, 0x42, 0xa6, 0xcd, 0x0f, 0x0, 0x0, 0x0, 0x3a, 0x0 }
+ {0x110, /* Wide Screen Signal, PAL/SECAM */
+ {V4L2_SLICED_WSS_625,23,23,1},
+ { 0x5b, 0x55, 0xc5, 0xff, 0x00, 0x71, 0x6e, 0x42,
+ 0xa6, 0xcd, 0x0f, 0x00, 0x00, 0x00, 0x3a, 0x00 }
},
- {0x130, /* WSS, NTSC C */
- { 0x38, 0x00, 0x3f, 0x00 , 0x0, 0x71, 0x6e, 0x43, 0x69, 0x7c, 0x08, 0x0, 0x0, 0x0, 0x39, 0x0 }
+ {0x130, /* Wide Screen Signal, NTSC C */
+ {V4L2_SLICED_WSS_525,20,20,1},
+ { 0x38, 0x00, 0x3f, 0x00, 0x00, 0x71, 0x6e, 0x43,
+ 0x69, 0x7c, 0x08, 0x00, 0x00, 0x00, 0x39, 0x00 }
},
- {0x150, /* VITC, PAL/SECAM 6 */
- { 0x0, 0x0, 0x0, 0x0 , 0x0, 0x8f, 0x6d, 0x49, 0xa6, 0x85, 0x08, 0x0, 0x0, 0x0, 0x4c, 0x0 }
+ {0x150, /* Vertical Interval Timecode (VITC), PAL/SECAM */
+ {V4l2_SLICED_VITC_625,6,22,0},
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49,
+ 0xa6, 0x85, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 }
},
- {0x170, /* VITC, NTSC 6 */
- { 0x0, 0x0, 0x0, 0x0 , 0x0, 0x8f, 0x6d, 0x49, 0x69, 0x94, 0x08, 0x0, 0x0, 0x0, 0x4c, 0x0 }
+ {0x170, /* Vertical Interval Timecode (VITC), NTSC */
+ {V4l2_SLICED_VITC_525,10,20,0},
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49,
+ 0x69, 0x94, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 }
},
+ {0x190, /* Video Program System (VPS), PAL */
+ {V4L2_SLICED_VPS,16,16,0},
+ { 0xaa, 0xaa, 0xff, 0xff, 0xba, 0xce, 0x2b, 0x0d,
+ 0xa6, 0xda, 0x0b, 0x00, 0x00, 0x00, 0x60, 0x00 }
+ },
+ /* 0x1d0 User programmable */
+
+ /* End of struct */
{ (u16)-1 }
};
static int tvp5150_write_inittab(struct i2c_client *c,
- const struct i2c_reg_value *regs)
+ const struct i2c_reg_value *regs)
{
while (regs->reg != 0xff) {
tvp5150_write(c, regs->reg, regs->value);
@@ -686,15 +582,15 @@ static int tvp5150_write_inittab(struct i2c_client *c,
}
static int tvp5150_vdp_init(struct i2c_client *c,
- const struct i2c_vbi_ram_value *regs)
+ const struct i2c_vbi_ram_value *regs)
{
unsigned int i;
/* Disable Full Field */
- tvp5150_write(c, TVP5150_FULL_FIELD_ENA_1, 0);
+ tvp5150_write(c, TVP5150_FULL_FIELD_ENA, 0);
/* Before programming, Line mode should be at 0xff */
- for (i=TVP5150_FULL_FIELD_ENA_2; i<=TVP5150_LINE_MODE_REG_44; i++)
+ for (i=TVP5150_LINE_MODE_INI; i<=TVP5150_LINE_MODE_END; i++)
tvp5150_write(c, i, 0xff);
/* Load Ram Table */
@@ -710,6 +606,117 @@ static int tvp5150_vdp_init(struct i2c_client *c,
return 0;
}
+/* Fills VBI capabilities based on i2c_vbi_ram_value struct */
+static void tvp5150_vbi_get_cap(const struct i2c_vbi_ram_value *regs,
+ struct v4l2_sliced_vbi_cap *cap)
+{
+ int line;
+
+ memset(cap, 0, sizeof *cap);
+
+ while (regs->reg != (u16)-1 ) {
+ for (line=regs->type.ini_line;line<=regs->type.end_line;line++) {
+ cap->service_lines[0][line] |= regs->type.vbi_type;
+ }
+ cap->service_set |= regs->type.vbi_type;
+
+ regs++;
+ }
+}
+
+/* Set vbi processing
+ * type - one of tvp5150_vbi_types
+ * line - line to gather data
+ * fields: bit 0 field1, bit 1, field2
+ * flags (default=0xf0) is a bitmask, were set means:
+ * bit 7: enable filtering null bytes on CC
+ * bit 6: send data also to FIFO
+ * bit 5: don't allow data with errors on FIFO
+ * bit 4: enable ECC when possible
+ * pix_align = pix alignment:
+ * LSB = field1
+ * MSB = field2
+ */
+static int tvp5150_set_vbi(struct i2c_client *c,
+ const struct i2c_vbi_ram_value *regs,
+ unsigned int type,u8 flags, int line,
+ const int fields)
+{
+ struct tvp5150 *decoder = i2c_get_clientdata(c);
+ v4l2_std_id std=decoder->norm;
+ u8 reg;
+ int pos=0;
+
+ if (std == V4L2_STD_ALL) {
+ tvp5150_err("VBI can't be configured without knowing number of lines\n");
+ return 0;
+ } else if (std && V4L2_STD_625_50) {
+ /* Don't follow NTSC Line number convension */
+ line += 3;
+ }
+
+ if (line<6||line>27)
+ return 0;
+
+ while (regs->reg != (u16)-1 ) {
+ if ((type & regs->type.vbi_type) &&
+ (line>=regs->type.ini_line) &&
+ (line<=regs->type.end_line)) {
+ type=regs->type.vbi_type;
+ break;
+ }
+
+ regs++;
+ pos++;
+ }
+ if (regs->reg == (u16)-1)
+ return 0;
+
+ type=pos | (flags & 0xf0);
+ reg=((line-6)<<1)+TVP5150_LINE_MODE_INI;
+
+ if (fields&1) {
+ tvp5150_write(c, reg, type);
+ }
+
+ if (fields&2) {
+ tvp5150_write(c, reg+1, type);
+ }
+
+ return type;
+}
+
+static int tvp5150_get_vbi(struct i2c_client *c,
+ const struct i2c_vbi_ram_value *regs, int line)
+{
+ struct tvp5150 *decoder = i2c_get_clientdata(c);
+ v4l2_std_id std=decoder->norm;
+ u8 reg;
+ int pos, type=0;
+
+ if (std == V4L2_STD_ALL) {
+ tvp5150_err("VBI can't be configured without knowing number of lines\n");
+ return 0;
+ } else if (std && V4L2_STD_625_50) {
+ /* Don't follow NTSC Line number convension */
+ line += 3;
+ }
+
+ if (line<6||line>27)
+ return 0;
+
+ reg=((line-6)<<1)+TVP5150_LINE_MODE_INI;
+
+ pos=tvp5150_read(c, reg)&0x0f;
+ if (pos<0x0f)
+ type=regs[pos].type.vbi_type;
+
+ pos=tvp5150_read(c, reg+1)&0x0f;
+ if (pos<0x0f)
+ type|=regs[pos].type.vbi_type;
+
+ return type;
+}
static int tvp5150_set_std(struct i2c_client *c, v4l2_std_id std)
{
struct tvp5150 *decoder = i2c_get_clientdata(c);
@@ -854,6 +861,69 @@ static int tvp5150_command(struct i2c_client *c,
*(v4l2_std_id *)arg = decoder->norm;
break;
+ case VIDIOC_G_SLICED_VBI_CAP:
+ {
+ struct v4l2_sliced_vbi_cap *cap = arg;
+ tvp5150_dbg(1, "VIDIOC_G_SLICED_VBI_CAP\n");
+
+ tvp5150_vbi_get_cap(vbi_ram_default, cap);
+ break;
+ }
+ case VIDIOC_S_FMT:
+ {
+ struct v4l2_format *fmt;
+ struct v4l2_sliced_vbi_format *svbi;
+ int i;
+
+ fmt = arg;
+ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+ return -EINVAL;
+ svbi = &fmt->fmt.sliced;
+ if (svbi->service_set != 0) {
+ for (i = 0; i <= 23; i++) {
+ svbi->service_lines[1][i] = 0;
+
+ svbi->service_lines[0][i]=tvp5150_set_vbi(c,
+ vbi_ram_default,
+ svbi->service_lines[0][i],0xf0,i,3);
+ }
+ /* Enables FIFO */
+ tvp5150_write(c, TVP5150_FIFO_OUT_CTRL,1);
+ } else {
+ /* Disables FIFO*/
+ tvp5150_write(c, TVP5150_FIFO_OUT_CTRL,0);
+
+ /* Disable Full Field */
+ tvp5150_write(c, TVP5150_FULL_FIELD_ENA, 0);
+
+ /* Disable Line modes */
+ for (i=TVP5150_LINE_MODE_INI; i<=TVP5150_LINE_MODE_END; i++)
+ tvp5150_write(c, i, 0xff);
+ }
+ break;
+ }
+ case VIDIOC_G_FMT:
+ {
+ struct v4l2_format *fmt;
+ struct v4l2_sliced_vbi_format *svbi;
+
+ int i, mask=0;
+
+ fmt = arg;
+ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+ return -EINVAL;
+ svbi = &fmt->fmt.sliced;
+ memset(svbi, 0, sizeof(*svbi));
+
+ for (i = 0; i <= 23; i++) {
+ svbi->service_lines[0][i]=tvp5150_get_vbi(c,
+ vbi_ram_default,i);
+ mask|=svbi->service_lines[0][i];
+ }
+ svbi->service_set=mask;
+ break;
+ }
+
#ifdef CONFIG_VIDEO_ADV_DEBUG
case VIDIOC_INT_G_REGISTER:
{
@@ -878,6 +948,7 @@ static int tvp5150_command(struct i2c_client *c,
}
#endif
+ case VIDIOC_LOG_STATUS:
case DECODER_DUMP:
dump_reg(c);
break;
@@ -1097,7 +1168,7 @@ static int tvp5150_detect_client(struct i2c_adapter *adapter,
rv = i2c_attach_client(c);
- core->norm = V4L2_STD_ALL;
+ core->norm = V4L2_STD_ALL; /* Default is autodetect */
core->input = 2;
core->enable = 1;
core->bright = 32768;
diff --git a/drivers/media/video/tvp5150_reg.h b/drivers/media/video/tvp5150_reg.h
index cd45c1ded78..4240043c0b2 100644
--- a/drivers/media/video/tvp5150_reg.h
+++ b/drivers/media/video/tvp5150_reg.h
@@ -1,3 +1,10 @@
+/*
+ * tvp5150 - Texas Instruments TVP5150A/AM1 video decoder registers
+ *
+ * Copyright (c) 2005,2006 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNU General Public License v2
+ */
+
#define TVP5150_VD_IN_SRC_SEL_1 0x00 /* Video input source selection #1 */
#define TVP5150_ANAL_CHL_CTL 0x01 /* Analog channel controls */
#define TVP5150_OP_MODE_CTL 0x02 /* Operation mode controls */
@@ -64,49 +71,32 @@
#define TVP5150_STATUS_REG_4 0x8b /* Status register #4 */
#define TVP5150_STATUS_REG_5 0x8c /* Status register #5 */
/* Reserved 8Dh-8Fh */
-#define TVP5150_CC_DATA_REG1 0x90 /* Closed caption data registers */
-#define TVP5150_CC_DATA_REG2 0x91 /* Closed caption data registers */
-#define TVP5150_CC_DATA_REG3 0x92 /* Closed caption data registers */
-#define TVP5150_CC_DATA_REG4 0x93 /* Closed caption data registers */
-#define TVP5150_WSS_DATA_REG1 0X94 /* WSS data registers */
-#define TVP5150_WSS_DATA_REG2 0X95 /* WSS data registers */
-#define TVP5150_WSS_DATA_REG3 0X96 /* WSS data registers */
-#define TVP5150_WSS_DATA_REG4 0X97 /* WSS data registers */
-#define TVP5150_WSS_DATA_REG5 0X98 /* WSS data registers */
-#define TVP5150_WSS_DATA_REG6 0X99 /* WSS data registers */
-#define TVP5150_VPS_DATA_REG1 0x9a /* VPS data registers */
-#define TVP5150_VPS_DATA_REG2 0x9b /* VPS data registers */
-#define TVP5150_VPS_DATA_REG3 0x9c /* VPS data registers */
-#define TVP5150_VPS_DATA_REG4 0x9d /* VPS data registers */
-#define TVP5150_VPS_DATA_REG5 0x9e /* VPS data registers */
-#define TVP5150_VPS_DATA_REG6 0x9f /* VPS data registers */
-#define TVP5150_VPS_DATA_REG7 0xa0 /* VPS data registers */
-#define TVP5150_VPS_DATA_REG8 0xa1 /* VPS data registers */
-#define TVP5150_VPS_DATA_REG9 0xa2 /* VPS data registers */
-#define TVP5150_VPS_DATA_REG10 0xa3 /* VPS data registers */
-#define TVP5150_VPS_DATA_REG11 0xa4 /* VPS data registers */
-#define TVP5150_VPS_DATA_REG12 0xa5 /* VPS data registers */
-#define TVP5150_VPS_DATA_REG13 0xa6 /* VPS data registers */
-#define TVP5150_VITC_DATA_REG1 0xa7 /* VITC data registers */
-#define TVP5150_VITC_DATA_REG2 0xa8 /* VITC data registers */
-#define TVP5150_VITC_DATA_REG3 0xa9 /* VITC data registers */
-#define TVP5150_VITC_DATA_REG4 0xaa /* VITC data registers */
-#define TVP5150_VITC_DATA_REG5 0xab /* VITC data registers */
-#define TVP5150_VITC_DATA_REG6 0xac /* VITC data registers */
-#define TVP5150_VITC_DATA_REG7 0xad /* VITC data registers */
-#define TVP5150_VITC_DATA_REG8 0xae /* VITC data registers */
-#define TVP5150_VITC_DATA_REG9 0xaf /* VITC data registers */
+ /* Closed caption data registers */
+#define TVP5150_CC_DATA_INI 0x90
+#define TVP5150_CC_DATA_END 0x93
+
+ /* WSS data registers */
+#define TVP5150_WSS_DATA_INI 0x94
+#define TVP5150_WSS_DATA_END 0x99
+
+/* VPS data registers */
+#define TVP5150_VPS_DATA_INI 0x9a
+#define TVP5150_VPS_DATA_END 0xa6
+
+/* VITC data registers */
+#define TVP5150_VITC_DATA_INI 0xa7
+#define TVP5150_VITC_DATA_END 0xaf
+
#define TVP5150_VBI_FIFO_READ_DATA 0xb0 /* VBI FIFO read data */
-#define TVP5150_TELETEXT_FIL_1_1 0xb1 /* Teletext filter 1 */
-#define TVP5150_TELETEXT_FIL_1_2 0xb2 /* Teletext filter 1 */
-#define TVP5150_TELETEXT_FIL_1_3 0xb3 /* Teletext filter 1 */
-#define TVP5150_TELETEXT_FIL_1_4 0xb4 /* Teletext filter 1 */
-#define TVP5150_TELETEXT_FIL_1_5 0xb5 /* Teletext filter 1 */
-#define TVP5150_TELETEXT_FIL_2_1 0xb6 /* Teletext filter 2 */
-#define TVP5150_TELETEXT_FIL_2_2 0xb7 /* Teletext filter 2 */
-#define TVP5150_TELETEXT_FIL_2_3 0xb8 /* Teletext filter 2 */
-#define TVP5150_TELETEXT_FIL_2_4 0xb9 /* Teletext filter 2 */
-#define TVP5150_TELETEXT_FIL_2_5 0xba /* Teletext filter 2 */
+
+/* Teletext filter 1 */
+#define TVP5150_TELETEXT_FIL1_INI 0xb1
+#define TVP5150_TELETEXT_FIL1_END 0xb5
+
+/* Teletext filter 2 */
+#define TVP5150_TELETEXT_FIL2_INI 0xb6
+#define TVP5150_TELETEXT_FIL2_END 0xba
+
#define TVP5150_TELETEXT_FIL_ENA 0xbb /* Teletext filter enable */
/* Reserved BCh-BFh */
#define TVP5150_INT_STATUS_REG_A 0xc0 /* Interrupt status register A */
@@ -124,50 +114,11 @@
#define TVP5150_PIX_ALIGN_REG_HIGH 0xcc /* Pixel alignment register high byte */
#define TVP5150_FIFO_OUT_CTRL 0xcd /* FIFO output control */
/* Reserved CEh */
-#define TVP5150_FULL_FIELD_ENA_1 0xcf /* Full field enable 1 */
-#define TVP5150_FULL_FIELD_ENA_2 0xd0 /* Full field enable 2 */
-#define TVP5150_LINE_MODE_REG_1 0xd1 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_2 0xd2 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_3 0xd3 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_4 0xd4 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_5 0xd5 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_6 0xd6 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_7 0xd7 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_8 0xd8 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_9 0xd9 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_10 0xda /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_11 0xdb /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_12 0xdc /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_13 0xdd /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_14 0xde /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_15 0xdf /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_16 0xe0 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_17 0xe1 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_18 0xe2 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_19 0xe3 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_20 0xe4 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_21 0xe5 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_22 0xe6 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_23 0xe7 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_24 0xe8 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_25 0xe9 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_27 0xea /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_28 0xeb /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_29 0xec /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_30 0xed /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_31 0xee /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_32 0xef /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_33 0xf0 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_34 0xf1 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_35 0xf2 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_36 0xf3 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_37 0xf4 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_38 0xf5 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_39 0xf6 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_40 0xf7 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_41 0xf8 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_42 0xf9 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_43 0xfa /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_44 0xfb /* Line mode registers */
+#define TVP5150_FULL_FIELD_ENA 0xcf /* Full field enable 1 */
+
+/* Line mode registers */
+#define TVP5150_LINE_MODE_INI 0xd0
+#define TVP5150_LINE_MODE_END 0xfb
+
#define TVP5150_FULL_FIELD_MODE_REG 0xfc /* Full field mode register */
/* Reserved FDh-FFh */
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index cd2c4475525..95a6e47c99f 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -97,7 +97,7 @@ int v4l2_video_std_construct(struct v4l2_standard *vs,
memset(vs, 0, sizeof(struct v4l2_standard));
vs->index = index;
vs->id = id;
- if (id & (V4L2_STD_NTSC | V4L2_STD_PAL_M)) {
+ if (id & V4L2_STD_525_60) {
vs->frameperiod.numerator = 1001;
vs->frameperiod.denominator = 30000;
vs->framelines = 525;
@@ -110,7 +110,6 @@ int v4l2_video_std_construct(struct v4l2_standard *vs,
return 0;
}
-
/* ----------------------------------------------------------------- */
/* priority handling */
@@ -171,7 +170,7 @@ int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local)
/* ----------------------------------------------------------------- */
-/* some arrays for pretty-printing debug messages */
+/* some arrays for pretty-printing debug messages of enum types */
char *v4l2_field_names[] = {
[V4L2_FIELD_ANY] = "any",
@@ -192,6 +191,14 @@ char *v4l2_type_names[] = {
[V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out",
};
+static char *v4l2_memory_names[] = {
+ [V4L2_MEMORY_MMAP] = "mmap",
+ [V4L2_MEMORY_USERPTR] = "userptr",
+ [V4L2_MEMORY_OVERLAY] = "overlay",
+};
+
+#define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown"
+
/* ------------------------------------------------------------------ */
/* debug help functions */
@@ -324,6 +331,15 @@ static const char *v4l2_int_ioctls[] = {
};
#define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls)
+static void v4l_print_pix_fmt (char *s, struct v4l2_pix_format *fmt)
+{
+ printk ("%s: width=%d, height=%d, format=%d, field=%s, "
+ "bytesperline=%d sizeimage=%d, colorspace=%d\n", s,
+ fmt->width,fmt->height,fmt->pixelformat,
+ prt_names(fmt->field,v4l2_field_names),
+ fmt->bytesperline,fmt->sizeimage,fmt->colorspace);
+};
+
/* Common ioctl debug function. This function can be used by
external ioctl messages as well as internal V4L ioctl */
void v4l_printk_ioctl(unsigned int cmd)
@@ -362,6 +378,541 @@ void v4l_printk_ioctl(unsigned int cmd)
}
}
+/* Common ioctl debug function. This function can be used by
+ external ioctl messages as well as internal V4L ioctl and its
+ arguments */
+void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
+{
+ printk(s);
+ printk(": ");
+ v4l_printk_ioctl(cmd);
+ switch (cmd) {
+ case VIDIOC_INT_G_CHIP_IDENT:
+ {
+ enum v4l2_chip_ident *p=arg;
+ printk ("%s: chip ident=%d\n", s, *p);
+ break;
+ }
+ case VIDIOC_G_PRIORITY:
+ case VIDIOC_S_PRIORITY:
+ {
+ enum v4l2_priority *p=arg;
+ printk ("%s: priority=%d\n", s, *p);
+ break;
+ }
+ case VIDIOC_INT_S_TUNER_MODE:
+ {
+ enum v4l2_tuner_type *p=arg;
+ printk ("%s: tuner type=%d\n", s, *p);
+ break;
+ }
+ case DECODER_SET_VBI_BYPASS:
+ case DECODER_ENABLE_OUTPUT:
+ case DECODER_GET_STATUS:
+ case DECODER_SET_OUTPUT:
+ case DECODER_SET_INPUT:
+ case DECODER_SET_GPIO:
+ case DECODER_SET_NORM:
+ case VIDIOCCAPTURE:
+ case VIDIOCSYNC:
+ case VIDIOCSWRITEMODE:
+ case TUNER_SET_TYPE_ADDR:
+ case TUNER_SET_STANDBY:
+ case TDA9887_SET_CONFIG:
+ case AUDC_SET_INPUT:
+ case VIDIOC_OVERLAY_OLD:
+ case VIDIOC_STREAMOFF:
+ case VIDIOC_G_OUTPUT:
+ case VIDIOC_S_OUTPUT:
+ case VIDIOC_STREAMON:
+ case VIDIOC_G_INPUT:
+ case VIDIOC_OVERLAY:
+ case VIDIOC_S_INPUT:
+ {
+ int *p=arg;
+ printk ("%s: value=%d\n", s, *p);
+ break;
+ }
+ case MSP_SET_MATRIX:
+ {
+ struct msp_matrix *p=arg;
+ printk ("%s: input=%d, output=%d\n", s, p->input, p->output);
+ break;
+ }
+ case VIDIOC_G_AUDIO:
+ case VIDIOC_S_AUDIO:
+ case VIDIOC_ENUMAUDIO:
+ case VIDIOC_G_AUDIO_OLD:
+ {
+ struct v4l2_audio *p=arg;
+
+ printk ("%s: index=%d, name=%s, capability=%d, mode=%d\n",
+ s,p->index, p->name,p->capability, p->mode);
+ break;
+ }
+ case VIDIOC_G_AUDOUT:
+ case VIDIOC_S_AUDOUT:
+ case VIDIOC_ENUMAUDOUT:
+ case VIDIOC_G_AUDOUT_OLD:
+ {
+ struct v4l2_audioout *p=arg;
+ printk ("%s: index=%d, name=%s, capability=%d, mode=%d\n", s,
+ p->index, p->name, p->capability,p->mode);
+ break;
+ }
+ case VIDIOC_QBUF:
+ case VIDIOC_DQBUF:
+ case VIDIOC_QUERYBUF:
+ {
+ struct v4l2_buffer *p=arg;
+ struct v4l2_timecode *tc=&p->timecode;
+ printk ("%s: %02ld:%02d:%02d.%08ld index=%d, type=%s, "
+ "bytesused=%d, flags=0x%08d, "
+ "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx\n",
+ s,
+ (p->timestamp.tv_sec/3600),
+ (int)(p->timestamp.tv_sec/60)%60,
+ (int)(p->timestamp.tv_sec%60),
+ p->timestamp.tv_usec,
+ p->index,
+ prt_names(p->type,v4l2_type_names),
+ p->bytesused,p->flags,
+ p->field,p->sequence,
+ prt_names(p->memory,v4l2_memory_names),
+ p->m.userptr);
+ printk ("%s: timecode= %02d:%02d:%02d type=%d, "
+ "flags=0x%08d, frames=%d, userbits=0x%08x",
+ s,tc->hours,tc->minutes,tc->seconds,
+ tc->type, tc->flags, tc->frames, (__u32) tc->userbits);
+ break;
+ }
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *p=arg;
+ printk ("%s: driver=%s, card=%s, bus=%s, version=%d, "
+ "capabilities=%d\n", s,
+ p->driver,p->card,p->bus_info,
+ p->version,
+ p->capabilities);
+ break;
+ }
+ case VIDIOC_G_CTRL:
+ case VIDIOC_S_CTRL:
+ case VIDIOC_S_CTRL_OLD:
+ {
+ struct v4l2_control *p=arg;
+ printk ("%s: id=%d, value=%d\n", s, p->id, p->value);
+ break;
+ }
+ case VIDIOC_G_CROP:
+ case VIDIOC_S_CROP:
+ {
+ struct v4l2_crop *p=arg;
+ /*FIXME: Should also show rect structs */
+ printk ("%s: type=%d\n", s, p->type);
+ break;
+ }
+ case VIDIOC_CROPCAP:
+ case VIDIOC_CROPCAP_OLD:
+ {
+ struct v4l2_cropcap *p=arg;
+ /*FIXME: Should also show rect structs */
+ printk ("%s: type=%d\n", s, p->type);
+ break;
+ }
+ case VIDIOC_INT_DECODE_VBI_LINE:
+ {
+ struct v4l2_decode_vbi_line *p=arg;
+ printk ("%s: is_second_field=%d, ptr=0x%08lx, line=%d, "
+ "type=%d\n", s,
+ p->is_second_field,(unsigned long)p->p,p->line,p->type);
+ break;
+ }
+ case VIDIOC_ENUM_FMT:
+ {
+ struct v4l2_fmtdesc *p=arg;
+ printk ("%s: index=%d, type=%d, flags=%d, description=%s,"
+ " pixelformat=%d\n", s,
+ p->index, p->type, p->flags,p->description,
+ p->pixelformat);
+
+ break;
+ }
+ case VIDIOC_G_FMT:
+ case VIDIOC_S_FMT:
+ case VIDIOC_TRY_FMT:
+ {
+ struct v4l2_format *p=arg;
+ printk ("%s: type=%s\n", s,
+ prt_names(p->type,v4l2_type_names));
+ switch (p->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ v4l_print_pix_fmt (s, &p->fmt.pix);
+ break;
+ default:
+ break;
+ }
+ }
+ case VIDIOC_G_FBUF:
+ case VIDIOC_S_FBUF:
+ {
+ struct v4l2_framebuffer *p=arg;
+ printk ("%s: capability=%d, flags=%d, base=0x%08lx\n", s,
+ p->capability,p->flags, (unsigned long)p->base);
+ v4l_print_pix_fmt (s, &p->fmt);
+ break;
+ }
+ case VIDIOC_G_FREQUENCY:
+ case VIDIOC_S_FREQUENCY:
+ {
+ struct v4l2_frequency *p=arg;
+ printk ("%s: tuner=%d, type=%d, frequency=%d\n", s,
+ p->tuner,p->type,p->frequency);
+ break;
+ }
+ case VIDIOC_ENUMINPUT:
+ {
+ struct v4l2_input *p=arg;
+ printk ("%s: index=%d, name=%s, type=%d, audioset=%d, "
+ "tuner=%d, std=%lld, status=%d\n", s,
+ p->index,p->name,p->type,p->audioset,
+ p->tuner,p->std,
+ p->status);
+ break;
+ }
+ case VIDIOC_G_JPEGCOMP:
+ case VIDIOC_S_JPEGCOMP:
+ {
+ struct v4l2_jpegcompression *p=arg;
+ printk ("%s: quality=%d, APPn=%d, APP_len=%d, COM_len=%d,"
+ " jpeg_markers=%d\n", s,
+ p->quality,p->APPn,p->APP_len,
+ p->COM_len,p->jpeg_markers);
+ break;
+ }
+ case VIDIOC_G_MODULATOR:
+ case VIDIOC_S_MODULATOR:
+ {
+ struct v4l2_modulator *p=arg;
+ printk ("%s: index=%d, name=%s, capability=%d, rangelow=%d,"
+ " rangehigh=%d, txsubchans=%d\n", s,
+ p->index, p->name,p->capability,p->rangelow,
+ p->rangehigh,p->txsubchans);
+ break;
+ }
+ case VIDIOC_G_MPEGCOMP:
+ case VIDIOC_S_MPEGCOMP:
+ {
+ struct v4l2_mpeg_compression *p=arg;
+ /*FIXME: Several fields not shown */
+ printk ("%s: ts_pid_pmt=%d, ts_pid_audio=%d, ts_pid_video=%d, "
+ "ts_pid_pcr=%d, ps_size=%d, au_sample_rate=%d, "
+ "au_pesid=%c, vi_frame_rate=%d, vi_frames_per_gop=%d, "
+ "vi_bframes_count=%d, vi_pesid=%c\n", s,
+ p->ts_pid_pmt,p->ts_pid_audio, p->ts_pid_video,
+ p->ts_pid_pcr, p->ps_size, p->au_sample_rate,
+ p->au_pesid, p->vi_frame_rate,
+ p->vi_frames_per_gop, p->vi_bframes_count,
+ p->vi_pesid);
+ break;
+ }
+ case VIDIOC_ENUMOUTPUT:
+ {
+ struct v4l2_output *p=arg;
+ printk ("%s: index=%d, name=%s,type=%d, audioset=%d, "
+ "modulator=%d, std=%lld\n",
+ s,p->index,p->name,p->type,p->audioset,
+ p->modulator,p->std);
+ break;
+ }
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *p=arg;
+ printk ("%s: id=%d, type=%d, name=%s, min/max=%d/%d,"
+ " step=%d, default=%d, flags=0x%08x\n", s,
+ p->id,p->type,p->name,p->minimum,p->maximum,
+ p->step,p->default_value,p->flags);
+ break;
+ }
+ case VIDIOC_QUERYMENU:
+ {
+ struct v4l2_querymenu *p=arg;
+ printk ("%s: id=%d, index=%d, name=%s\n", s,
+ p->id,p->index,p->name);
+ break;
+ }
+ case VIDIOC_INT_G_REGISTER:
+ case VIDIOC_INT_S_REGISTER:
+ {
+ struct v4l2_register *p=arg;
+ printk ("%s: i2c_id=%d, reg=%lu, val=%d\n", s,
+ p->i2c_id,p->reg,p->val);
+
+ break;
+ }
+ case VIDIOC_REQBUFS:
+ {
+ struct v4l2_requestbuffers *p=arg;
+ printk ("%s: count=%d, type=%s, memory=%s\n", s,
+ p->count,
+ prt_names(p->type,v4l2_type_names),
+ prt_names(p->memory,v4l2_memory_names));
+ break;
+ }
+ case VIDIOC_INT_S_AUDIO_ROUTING:
+ case VIDIOC_INT_S_VIDEO_ROUTING:
+ case VIDIOC_INT_G_AUDIO_ROUTING:
+ case VIDIOC_INT_G_VIDEO_ROUTING:
+ {
+ struct v4l2_routing *p=arg;
+ printk ("%s: input=%d, output=%d\n", s, p->input, p->output);
+ break;
+ }
+ case VIDIOC_G_SLICED_VBI_CAP:
+ {
+ struct v4l2_sliced_vbi_cap *p=arg;
+ printk ("%s: service_set=%d\n", s,
+ p->service_set);
+ break;
+ }
+ case VIDIOC_INT_S_VBI_DATA:
+ case VIDIOC_INT_G_VBI_DATA:
+ {
+ struct v4l2_sliced_vbi_data *p=arg;
+ printk ("%s: id=%d, field=%d, line=%d\n", s,
+ p->id, p->field, p->line);
+ break;
+ }
+ case VIDIOC_ENUMSTD:
+ {
+ struct v4l2_standard *p=arg;
+ printk ("%s: index=%d, id=%lld, name=%s, fps=%d/%d, framelines=%d\n", s,
+ p->index, p->id, p->name,
+ p->frameperiod.numerator,
+ p->frameperiod.denominator,
+ p->framelines);
+
+ break;
+ }
+ case VIDIOC_G_PARM:
+ case VIDIOC_S_PARM:
+ case VIDIOC_S_PARM_OLD:
+ {
+ struct v4l2_streamparm *p=arg;
+ printk ("%s: type=%d\n", s, p->type);
+
+ break;
+ }
+ case VIDIOC_G_TUNER:
+ case VIDIOC_S_TUNER:
+ {
+ struct v4l2_tuner *p=arg;
+ printk ("%s: index=%d, name=%s, type=%d, capability=%d, "
+ "rangelow=%d, rangehigh=%d, signal=%d, afc=%d, "
+ "rxsubchans=%d, audmode=%d\n", s,
+ p->index, p->name, p->type,
+ p->capability, p->rangelow,p->rangehigh,
+ p->rxsubchans, p->audmode, p->signal,
+ p->afc);
+ break;
+ }
+ case VIDIOCGVBIFMT:
+ case VIDIOCSVBIFMT:
+ {
+ struct vbi_format *p=arg;
+ printk ("%s: sampling_rate=%d, samples_per_line=%d, "
+ "sample_format=%d, start=%d/%d, count=%d/%d, flags=%d\n", s,
+ p->sampling_rate,p->samples_per_line,
+ p->sample_format,p->start[0],p->start[1],
+ p->count[0],p->count[1],p->flags);
+ break;
+ }
+ case VIDIOCGAUDIO:
+ case VIDIOCSAUDIO:
+ {
+ struct video_audio *p=arg;
+ printk ("%s: audio=%d, volume=%d, bass=%d, treble=%d, "
+ "flags=%d, name=%s, mode=%d, balance=%d, step=%d\n",
+ s,p->audio,p->volume,p->bass, p->treble,
+ p->flags,p->name,p->mode,p->balance,p->step);
+ break;
+ }
+ case VIDIOCGFBUF:
+ case VIDIOCSFBUF:
+ {
+ struct video_buffer *p=arg;
+ printk ("%s: base=%08lx, height=%d, width=%d, depth=%d, "
+ "bytesperline=%d\n", s,
+ (unsigned long) p->base, p->height, p->width,
+ p->depth,p->bytesperline);
+ break;
+ }
+ case VIDIOCGCAP:
+ {
+ struct video_capability *p=arg;
+ printk ("%s: name=%s, type=%d, channels=%d, audios=%d, "
+ "maxwidth=%d, maxheight=%d, minwidth=%d, minheight=%d\n",
+ s,p->name,p->type,p->channels,p->audios,
+ p->maxwidth,p->maxheight,p->minwidth,
+ p->minheight);
+
+ break;
+ }
+ case VIDIOCGCAPTURE:
+ case VIDIOCSCAPTURE:
+ {
+ struct video_capture *p=arg;
+ printk ("%s: x=%d, y=%d, width=%d, height=%d, decimation=%d,"
+ " flags=%d\n", s,
+ p->x, p->y,p->width, p->height,
+ p->decimation,p->flags);
+ break;
+ }
+ case VIDIOCGCHAN:
+ case VIDIOCSCHAN:
+ {
+ struct video_channel *p=arg;
+ printk ("%s: channel=%d, name=%s, tuners=%d, flags=%d, "
+ "type=%d, norm=%d\n", s,
+ p->channel,p->name,p->tuners,
+ p->flags,p->type,p->norm);
+
+ break;
+ }
+ case VIDIOCSMICROCODE:
+ {
+ struct video_code *p=arg;
+ printk ("%s: loadwhat=%s, datasize=%d\n", s,
+ p->loadwhat,p->datasize);
+ break;
+ }
+ case DECODER_GET_CAPABILITIES:
+ {
+ struct video_decoder_capability *p=arg;
+ printk ("%s: flags=%d, inputs=%d, outputs=%d\n", s,
+ p->flags,p->inputs,p->outputs);
+ break;
+ }
+ case DECODER_INIT:
+ {
+ struct video_decoder_init *p=arg;
+ printk ("%s: len=%c\n", s, p->len);
+ break;
+ }
+ case VIDIOCGPLAYINFO:
+ {
+ struct video_info *p=arg;
+ printk ("%s: frame_count=%d, h_size=%d, v_size=%d, "
+ "smpte_timecode=%d, picture_type=%d, "
+ "temporal_reference=%d, user_data=%s\n", s,
+ p->frame_count, p->h_size,
+ p->v_size, p->smpte_timecode,
+ p->picture_type, p->temporal_reference,
+ p->user_data);
+ break;
+ }
+ case VIDIOCKEY:
+ {
+ struct video_key *p=arg;
+ printk ("%s: key=%s, flags=%d\n", s,
+ p->key, p->flags);
+ break;
+ }
+ case VIDIOCGMBUF:
+ {
+ struct video_mbuf *p=arg;
+ printk ("%s: size=%d, frames=%d, offsets=0x%08lx\n", s,
+ p->size,
+ p->frames,
+ (unsigned long)p->offsets);
+ break;
+ }
+ case VIDIOCMCAPTURE:
+ {
+ struct video_mmap *p=arg;
+ printk ("%s: frame=%d, height=%d, width=%d, format=%d\n", s,
+ p->frame,
+ p->height, p->width,
+ p->format);
+ break;
+ }
+ case VIDIOCGPICT:
+ case VIDIOCSPICT:
+ case DECODER_SET_PICTURE:
+ {
+ struct video_picture *p=arg;
+
+ printk ("%s: brightness=%d, hue=%d, colour=%d, contrast=%d,"
+ " whiteness=%d, depth=%d, palette=%d\n", s,
+ p->brightness, p->hue, p->colour,
+ p->contrast, p->whiteness, p->depth,
+ p->palette);
+ break;
+ }
+ case VIDIOCSPLAYMODE:
+ {
+ struct video_play_mode *p=arg;
+ printk ("%s: mode=%d, p1=%d, p2=%d\n", s,
+ p->mode,p->p1,p->p2);
+ break;
+ }
+ case VIDIOCGTUNER:
+ case VIDIOCSTUNER:
+ {
+ struct video_tuner *p=arg;
+ printk ("%s: tuner=%d, name=%s, rangelow=%ld, rangehigh=%ld, "
+ "flags=%d, mode=%d, signal=%d\n", s,
+ p->tuner, p->name,p->rangelow, p->rangehigh,
+ p->flags,p->mode, p->signal);
+ break;
+ }
+ case VIDIOCGUNIT:
+ {
+ struct video_unit *p=arg;
+ printk ("%s: video=%d, vbi=%d, radio=%d, audio=%d, "
+ "teletext=%d\n", s,
+ p->video,p->vbi,p->radio,p->audio,p->teletext);
+ break;
+ }
+ case VIDIOCGWIN:
+ case VIDIOCSWIN:
+ {
+ struct video_window *p=arg;
+ printk ("%s: x=%d, y=%d, width=%d, height=%d, chromakey=%d,"
+ " flags=%d, clipcount=%d\n", s,
+ p->x, p->y,p->width, p->height,
+ p->chromakey,p->flags,
+ p->clipcount);
+ break;
+ }
+ case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+ case VIDIOC_INT_I2S_CLOCK_FREQ:
+ case VIDIOC_INT_S_STANDBY:
+ {
+ u32 *p=arg;
+
+ printk ("%s: value=%d\n", s, *p);
+ break;
+ }
+ case VIDIOCGFREQ:
+ case VIDIOCSFREQ:
+ {
+ unsigned long *p=arg;
+ printk ("%s: value=%lu\n", s, *p);
+ break;
+ }
+ case VIDIOC_G_STD:
+ case VIDIOC_S_STD:
+ case VIDIOC_QUERYSTD:
+ {
+ v4l2_std_id *p=arg;
+
+ printk ("%s: value=%llu\n", s, *p);
+ break;
+ }
+ }
+}
+
/* ----------------------------------------------------------------- */
EXPORT_SYMBOL(v4l2_video_std_construct);
@@ -376,6 +927,7 @@ EXPORT_SYMBOL(v4l2_prio_check);
EXPORT_SYMBOL(v4l2_field_names);
EXPORT_SYMBOL(v4l2_type_names);
EXPORT_SYMBOL(v4l_printk_ioctl);
+EXPORT_SYMBOL(v4l_printk_ioctl_arg);
/*
* Local variables:
diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c
index 0a4004a4393..caf3e7e2f21 100644
--- a/drivers/media/video/video-buf-dvb.c
+++ b/drivers/media/video/video-buf-dvb.c
@@ -96,7 +96,7 @@ static int videobuf_dvb_start_feed(struct dvb_demux_feed *feed)
if (!demux->dmx.frontend)
return -EINVAL;
- down(&dvb->lock);
+ mutex_lock(&dvb->lock);
dvb->nfeeds++;
rc = dvb->nfeeds;
@@ -110,7 +110,7 @@ static int videobuf_dvb_start_feed(struct dvb_demux_feed *feed)
}
out:
- up(&dvb->lock);
+ mutex_unlock(&dvb->lock);
return rc;
}
@@ -120,14 +120,14 @@ static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed)
struct videobuf_dvb *dvb = demux->priv;
int err = 0;
- down(&dvb->lock);
+ mutex_lock(&dvb->lock);
dvb->nfeeds--;
if (0 == dvb->nfeeds && NULL != dvb->thread) {
// FIXME: cx8802_cancel_buffers(dev);
err = kthread_stop(dvb->thread);
dvb->thread = NULL;
}
- up(&dvb->lock);
+ mutex_unlock(&dvb->lock);
return err;
}
@@ -139,7 +139,7 @@ int videobuf_dvb_register(struct videobuf_dvb *dvb,
{
int result;
- init_MUTEX(&dvb->lock);
+ mutex_init(&dvb->lock);
/* register adapter */
result = dvb_register_adapter(&dvb->adapter, dvb->name, module);
diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c
index 9ef477523d2..87e937581d5 100644
--- a/drivers/media/video/video-buf.c
+++ b/drivers/media/video/video-buf.c
@@ -59,8 +59,7 @@ videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages)
pg = vmalloc_to_page(virt);
if (NULL == pg)
goto err;
- if (PageHighMem(pg))
- BUG();
+ BUG_ON(PageHighMem(pg));
sglist[i].page = pg;
sglist[i].length = PAGE_SIZE;
}
@@ -385,7 +384,7 @@ void videobuf_queue_init(struct videobuf_queue* q,
q->ops = ops;
q->priv_data = priv;
- init_MUTEX(&q->lock);
+ mutex_init(&q->lock);
INIT_LIST_HEAD(&q->stream);
}
@@ -428,7 +427,7 @@ videobuf_queue_is_busy(struct videobuf_queue *q)
void
videobuf_queue_cancel(struct videobuf_queue *q)
{
- unsigned long flags;
+ unsigned long flags=0;
int i;
/* remove queued buffers from list */
@@ -549,7 +548,7 @@ videobuf_reqbufs(struct videobuf_queue *q,
if (!list_empty(&q->stream))
return -EBUSY;
- down(&q->lock);
+ mutex_lock(&q->lock);
count = req->count;
if (count > VIDEO_MAX_FRAME)
count = VIDEO_MAX_FRAME;
@@ -566,7 +565,7 @@ videobuf_reqbufs(struct videobuf_queue *q,
req->count = count;
done:
- up(&q->lock);
+ mutex_unlock(&q->lock);
return retval;
}
@@ -589,10 +588,10 @@ videobuf_qbuf(struct videobuf_queue *q,
{
struct videobuf_buffer *buf;
enum v4l2_field field;
- unsigned long flags;
+ unsigned long flags=0;
int retval;
- down(&q->lock);
+ mutex_lock(&q->lock);
retval = -EBUSY;
if (q->reading)
goto done;
@@ -652,7 +651,7 @@ videobuf_qbuf(struct videobuf_queue *q,
retval = 0;
done:
- up(&q->lock);
+ mutex_unlock(&q->lock);
return retval;
}
@@ -663,7 +662,7 @@ videobuf_dqbuf(struct videobuf_queue *q,
struct videobuf_buffer *buf;
int retval;
- down(&q->lock);
+ mutex_lock(&q->lock);
retval = -EBUSY;
if (q->reading)
goto done;
@@ -693,7 +692,7 @@ videobuf_dqbuf(struct videobuf_queue *q,
videobuf_status(b,buf,q->type);
done:
- up(&q->lock);
+ mutex_unlock(&q->lock);
return retval;
}
@@ -701,10 +700,10 @@ int videobuf_streamon(struct videobuf_queue *q)
{
struct videobuf_buffer *buf;
struct list_head *list;
- unsigned long flags;
+ unsigned long flags=0;
int retval;
- down(&q->lock);
+ mutex_lock(&q->lock);
retval = -EBUSY;
if (q->reading)
goto done;
@@ -721,7 +720,7 @@ int videobuf_streamon(struct videobuf_queue *q)
spin_unlock_irqrestore(q->irqlock,flags);
done:
- up(&q->lock);
+ mutex_unlock(&q->lock);
return retval;
}
@@ -729,7 +728,7 @@ int videobuf_streamoff(struct videobuf_queue *q)
{
int retval = -EINVAL;
- down(&q->lock);
+ mutex_lock(&q->lock);
if (!q->streaming)
goto done;
videobuf_queue_cancel(q);
@@ -737,7 +736,7 @@ int videobuf_streamoff(struct videobuf_queue *q)
retval = 0;
done:
- up(&q->lock);
+ mutex_unlock(&q->lock);
return retval;
}
@@ -746,7 +745,7 @@ videobuf_read_zerocopy(struct videobuf_queue *q, char __user *data,
size_t count, loff_t *ppos)
{
enum v4l2_field field;
- unsigned long flags;
+ unsigned long flags=0;
int retval;
/* setup stuff */
@@ -788,11 +787,11 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
int nonblocking)
{
enum v4l2_field field;
- unsigned long flags;
+ unsigned long flags=0;
unsigned size, nbufs, bytes;
int retval;
- down(&q->lock);
+ mutex_lock(&q->lock);
nbufs = 1; size = 0;
q->ops->buf_setup(q,&nbufs,&size);
@@ -860,14 +859,14 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
}
done:
- up(&q->lock);
+ mutex_unlock(&q->lock);
return retval;
}
int videobuf_read_start(struct videobuf_queue *q)
{
enum v4l2_field field;
- unsigned long flags;
+ unsigned long flags=0;
int count = 0, size = 0;
int err, i;
@@ -919,10 +918,10 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
{
unsigned int *fc, bytes;
int err, retval;
- unsigned long flags;
+ unsigned long flags=0;
dprintk(2,"%s\n",__FUNCTION__);
- down(&q->lock);
+ mutex_lock(&q->lock);
retval = -EBUSY;
if (q->streaming)
goto done;
@@ -996,7 +995,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
}
done:
- up(&q->lock);
+ mutex_unlock(&q->lock);
return retval;
}
@@ -1007,7 +1006,7 @@ unsigned int videobuf_poll_stream(struct file *file,
struct videobuf_buffer *buf = NULL;
unsigned int rc = 0;
- down(&q->lock);
+ mutex_lock(&q->lock);
if (q->streaming) {
if (!list_empty(&q->stream))
buf = list_entry(q->stream.next,
@@ -1035,7 +1034,7 @@ unsigned int videobuf_poll_stream(struct file *file,
buf->state == STATE_ERROR)
rc = POLLIN|POLLRDNORM;
}
- up(&q->lock);
+ mutex_unlock(&q->lock);
return rc;
}
@@ -1064,7 +1063,7 @@ videobuf_vm_close(struct vm_area_struct *vma)
map->count--;
if (0 == map->count) {
dprintk(1,"munmap %p q=%p\n",map,q);
- down(&q->lock);
+ mutex_lock(&q->lock);
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
if (NULL == q->bufs[i])
continue;
@@ -1076,7 +1075,7 @@ videobuf_vm_close(struct vm_area_struct *vma)
q->bufs[i]->baddr = 0;
q->ops->buf_release(q,q->bufs[i]);
}
- up(&q->lock);
+ mutex_unlock(&q->lock);
kfree(map);
}
return;
@@ -1170,7 +1169,7 @@ int videobuf_mmap_mapper(struct videobuf_queue *q,
unsigned int first,last,size,i;
int retval;
- down(&q->lock);
+ mutex_lock(&q->lock);
retval = -EINVAL;
if (!(vma->vm_flags & VM_WRITE)) {
dprintk(1,"mmap app bug: PROT_WRITE please\n");
@@ -1238,7 +1237,7 @@ int videobuf_mmap_mapper(struct videobuf_queue *q,
retval = 0;
done:
- up(&q->lock);
+ mutex_unlock(&q->lock);
return retval;
}
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index 078880e4c8c..75e3d41382f 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -224,13 +224,13 @@ int video_exclusive_open(struct inode *inode, struct file *file)
struct video_device *vfl = video_devdata(file);
int retval = 0;
- down(&vfl->lock);
+ mutex_lock(&vfl->lock);
if (vfl->users) {
retval = -EBUSY;
} else {
vfl->users++;
}
- up(&vfl->lock);
+ mutex_unlock(&vfl->lock);
return retval;
}
@@ -279,23 +279,23 @@ int video_register_device(struct video_device *vfd, int type, int nr)
switch(type)
{
case VFL_TYPE_GRABBER:
- base=0;
- end=64;
+ base=MINOR_VFL_TYPE_GRABBER_MIN;
+ end=MINOR_VFL_TYPE_GRABBER_MAX+1;
name_base = "video";
break;
case VFL_TYPE_VTX:
- base=192;
- end=224;
+ base=MINOR_VFL_TYPE_VTX_MIN;
+ end=MINOR_VFL_TYPE_VTX_MAX+1;
name_base = "vtx";
break;
case VFL_TYPE_VBI:
- base=224;
- end=256;
+ base=MINOR_VFL_TYPE_VBI_MIN;
+ end=MINOR_VFL_TYPE_VBI_MAX+1;
name_base = "vbi";
break;
case VFL_TYPE_RADIO:
- base=64;
- end=128;
+ base=MINOR_VFL_TYPE_RADIO_MIN;
+ end=MINOR_VFL_TYPE_RADIO_MAX+1;
name_base = "radio";
break;
default:
@@ -328,7 +328,7 @@ int video_register_device(struct video_device *vfd, int type, int nr)
sprintf(vfd->devfs_name, "v4l/%s%d", name_base, i - base);
devfs_mk_cdev(MKDEV(VIDEO_MAJOR, vfd->minor),
S_IFCHR | S_IRUSR | S_IWUSR, vfd->devfs_name);
- init_MUTEX(&vfd->lock);
+ mutex_init(&vfd->lock);
/* sysfs class */
memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev));
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index c8fd8238904..0229819d0aa 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -42,6 +42,7 @@
#include <linux/videodev.h>
#include <linux/videodev2.h>
#include <linux/video_decoder.h>
+#include <linux/mutex.h>
#include <asm/paccess.h>
#include <asm/io.h>
@@ -245,7 +246,7 @@ struct vino_framebuffer_queue {
struct vino_framebuffer *buffer[VINO_FRAMEBUFFER_COUNT_MAX];
spinlock_t queue_lock;
- struct semaphore queue_sem;
+ struct mutex queue_mutex;
wait_queue_head_t frame_wait_queue;
};
@@ -283,7 +284,7 @@ struct vino_channel_settings {
/* the driver is currently processing the queue */
int capturing;
- struct semaphore sem;
+ struct mutex mutex;
spinlock_t capture_lock;
unsigned int users;
@@ -1131,11 +1132,11 @@ static void vino_queue_free(struct vino_framebuffer_queue *q)
if (q->type != VINO_MEMORY_MMAP)
return;
- down(&q->queue_sem);
+ mutex_lock(&q->queue_mutex);
vino_queue_free_with_count(q, q->length);
- up(&q->queue_sem);
+ mutex_unlock(&q->queue_mutex);
}
static int vino_queue_init(struct vino_framebuffer_queue *q,
@@ -1159,7 +1160,7 @@ static int vino_queue_init(struct vino_framebuffer_queue *q,
if (*length < 1)
return -EINVAL;
- down(&q->queue_sem);
+ mutex_lock(&q->queue_mutex);
if (*length > VINO_FRAMEBUFFER_COUNT_MAX)
*length = VINO_FRAMEBUFFER_COUNT_MAX;
@@ -1211,7 +1212,7 @@ static int vino_queue_init(struct vino_framebuffer_queue *q,
q->magic = VINO_QUEUE_MAGIC;
}
- up(&q->queue_sem);
+ mutex_unlock(&q->queue_mutex);
return ret;
}
@@ -4045,7 +4046,7 @@ static int vino_open(struct inode *inode, struct file *file)
dprintk("open(): channel = %c\n",
(vcs->channel == VINO_CHANNEL_A) ? 'A' : 'B');
- down(&vcs->sem);
+ mutex_lock(&vcs->mutex);
if (vcs->users) {
dprintk("open(): driver busy\n");
@@ -4062,7 +4063,7 @@ static int vino_open(struct inode *inode, struct file *file)
vcs->users++;
out:
- up(&vcs->sem);
+ mutex_unlock(&vcs->mutex);
dprintk("open(): %s!\n", ret ? "failed" : "complete");
@@ -4075,7 +4076,7 @@ static int vino_close(struct inode *inode, struct file *file)
struct vino_channel_settings *vcs = video_get_drvdata(dev);
dprintk("close():\n");
- down(&vcs->sem);
+ mutex_lock(&vcs->mutex);
vcs->users--;
@@ -4087,7 +4088,7 @@ static int vino_close(struct inode *inode, struct file *file)
vino_queue_free(&vcs->fb_queue);
}
- up(&vcs->sem);
+ mutex_unlock(&vcs->mutex);
return 0;
}
@@ -4130,7 +4131,7 @@ static int vino_mmap(struct file *file, struct vm_area_struct *vma)
// TODO: reject mmap if already mapped
- if (down_interruptible(&vcs->sem))
+ if (mutex_lock_interruptible(&vcs->mutex))
return -EINTR;
if (vcs->reading) {
@@ -4214,7 +4215,7 @@ found:
vma->vm_ops = &vino_vm_ops;
out:
- up(&vcs->sem);
+ mutex_unlock(&vcs->mutex);
return ret;
}
@@ -4374,12 +4375,12 @@ static int vino_ioctl(struct inode *inode, struct file *file,
struct vino_channel_settings *vcs = video_get_drvdata(dev);
int ret;
- if (down_interruptible(&vcs->sem))
+ if (mutex_lock_interruptible(&vcs->mutex))
return -EINTR;
ret = video_usercopy(inode, file, cmd, arg, vino_do_ioctl);
- up(&vcs->sem);
+ mutex_unlock(&vcs->mutex);
return ret;
}
@@ -4564,10 +4565,10 @@ static int vino_init_channel_settings(struct vino_channel_settings *vcs,
vcs->capturing = 0;
- init_MUTEX(&vcs->sem);
+ mutex_init(&vcs->mutex);
spin_lock_init(&vcs->capture_lock);
- init_MUTEX(&vcs->fb_queue.queue_sem);
+ mutex_init(&vcs->fb_queue.queue_mutex);
spin_lock_init(&vcs->fb_queue.queue_lock);
init_waitqueue_head(&vcs->fb_queue.frame_wait_queue);
diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c
index 285d7d06809..c32fad1ce51 100644
--- a/drivers/mmc/pxamci.c
+++ b/drivers/mmc/pxamci.c
@@ -438,7 +438,7 @@ static int pxamci_probe(struct platform_device *pdev)
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
- if (!r || irq == NO_IRQ)
+ if (!r || irq < 0)
return -ENXIO;
r = request_mem_region(r->start, SZ_4K, DRIVER_NAME);
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c
index 53e3afc1b7b..09d5c3f2698 100644
--- a/drivers/net/arm/am79c961a.c
+++ b/drivers/net/arm/am79c961a.c
@@ -696,7 +696,9 @@ static int __init am79c961_probe(struct platform_device *pdev)
dev->base_addr = res->start;
dev->irq = platform_get_irq(pdev, 0);
- ret = -ENODEV;
+ ret = -ENODEV;
+ if (dev->irq < 0)
+ goto nodev;
if (!request_region(dev->base_addr, 0x18, dev->name))
goto nodev;
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c
index e67b1d06611..95e2bb8dd7b 100644
--- a/drivers/net/fs_enet/mac-fcc.c
+++ b/drivers/net/fs_enet/mac-fcc.c
@@ -118,6 +118,8 @@ static int do_pd_setup(struct fs_enet_private *fep)
/* Fill out IRQ field */
fep->interrupt = platform_get_irq(pdev, 0);
+ if (fep->interrupt < 0)
+ return -EINVAL;
/* Attach the memory for the FCC Parameter RAM */
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram");
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c
index 2e8f4446969..3dad69dfdb2 100644
--- a/drivers/net/fs_enet/mac-fec.c
+++ b/drivers/net/fs_enet/mac-fec.c
@@ -144,6 +144,8 @@ static int do_pd_setup(struct fs_enet_private *fep)
/* Fill out IRQ field */
fep->interrupt = platform_get_irq_byname(pdev,"interrupt");
+ if (fep->interrupt < 0)
+ return -EINVAL;
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
fep->fec.fecp =(void*)r->start;
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c
index a3897fda71f..a772b286f96 100644
--- a/drivers/net/fs_enet/mac-scc.c
+++ b/drivers/net/fs_enet/mac-scc.c
@@ -118,6 +118,8 @@ static int do_pd_setup(struct fs_enet_private *fep)
/* Fill out IRQ field */
fep->interrupt = platform_get_irq_byname(pdev, "interrupt");
+ if (fep->interrupt < 0)
+ return -EINVAL;
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
fep->scc.sccp = (void *)r->start;
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 0e8e3fcde9f..771e25d8c41 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -193,8 +193,12 @@ static int gfar_probe(struct platform_device *pdev)
priv->interruptTransmit = platform_get_irq_byname(pdev, "tx");
priv->interruptReceive = platform_get_irq_byname(pdev, "rx");
priv->interruptError = platform_get_irq_byname(pdev, "error");
+ if (priv->interruptTransmit < 0 || priv->interruptReceive < 0 || priv->interruptError < 0)
+ goto regs_fail;
} else {
priv->interruptTransmit = platform_get_irq(pdev, 0);
+ if (priv->interruptTransmit < 0)
+ goto regs_fail;
}
/* get a pointer to the register memory */
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index 7ec08127c9d..75e9b3b910c 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -2221,6 +2221,10 @@ static int smc_drv_probe(struct platform_device *pdev)
ndev->dma = (unsigned char)-1;
ndev->irq = platform_get_irq(pdev, 0);
+ if (ndev->irq < 0) {
+ ret = -ENODEV;
+ goto out_free_netdev;
+ }
ret = smc_request_attrib(pdev);
if (ret)
diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c
index 47b5ade95bd..2c23d758439 100644
--- a/drivers/pcmcia/omap_cf.c
+++ b/drivers/pcmcia/omap_cf.c
@@ -218,7 +218,7 @@ static int __init omap_cf_probe(struct device *dev)
/* either CFLASH.IREQ (INT_1610_CF) or some GPIO */
irq = platform_get_irq(pdev, 0);
- if (!irq)
+ if (irq < 0)
return -EINVAL;
cf = kcalloc(1, sizeof *cf, GFP_KERNEL);
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 3c606cf8c8c..5c94a5d4efc 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -379,6 +379,14 @@ config SCSI_AHA1740
config SCSI_AACRAID
tristate "Adaptec AACRAID support"
depends on SCSI && PCI
+ help
+ This driver supports a variety of Dell, HP, Adaptec, IBM and
+ ICP storage products. For a list of supported products, refer
+ to <file:Documentation/scsi/aacraid.txt>.
+
+ To compile this driver as a module, choose M here: the module
+ will be called aacraid.
+
source "drivers/scsi/aic7xxx/Kconfig.aic7xxx"
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 320e765fa0c..15dc2e00e1b 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -163,7 +163,7 @@ ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \
CFLAGS_ncr53c8xx.o := $(ncr53c8xx-flags-y) $(ncr53c8xx-flags-m)
zalon7xx-objs := zalon.o ncr53c8xx.o
NCR_Q720_mod-objs := NCR_Q720.o ncr53c8xx.o
-libata-objs := libata-core.o libata-scsi.o
+libata-objs := libata-core.o libata-scsi.o libata-bmdma.o
oktagon_esp_mod-objs := oktagon_esp.o oktagon_io.o
# Files generated that shall be removed upon make clean
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 559ff7aae3f..e97ab3e6de4 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -66,6 +66,9 @@ enum {
AHCI_IRQ_ON_SG = (1 << 31),
AHCI_CMD_ATAPI = (1 << 5),
AHCI_CMD_WRITE = (1 << 6),
+ AHCI_CMD_PREFETCH = (1 << 7),
+ AHCI_CMD_RESET = (1 << 8),
+ AHCI_CMD_CLR_BUSY = (1 << 10),
RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */
@@ -85,6 +88,7 @@ enum {
/* HOST_CAP bits */
HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */
+ HOST_CAP_CLO = (1 << 24), /* Command List Override support */
/* registers for each SATA port */
PORT_LST_ADDR = 0x00, /* command list DMA addr */
@@ -138,6 +142,7 @@ enum {
PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */
PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */
PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */
+ PORT_CMD_CLO = (1 << 3), /* Command list override */
PORT_CMD_POWER_ON = (1 << 2), /* Power up device */
PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */
PORT_CMD_START = (1 << 0), /* Enable port DMA engine */
@@ -184,9 +189,9 @@ struct ahci_port_priv {
static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static int ahci_qc_issue(struct ata_queued_cmd *qc);
+static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
-static void ahci_phy_reset(struct ata_port *ap);
+static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes);
static void ahci_irq_clear(struct ata_port *ap);
static void ahci_eng_timeout(struct ata_port *ap);
static int ahci_port_start(struct ata_port *ap);
@@ -202,11 +207,11 @@ static struct scsi_host_template ahci_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
+ .eh_timed_out = ata_scsi_timed_out,
.eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = AHCI_MAX_SG,
- .max_sectors = ATA_MAX_SECTORS,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.emulated = ATA_SHT_EMULATED,
.use_clustering = AHCI_USE_CLUSTERING,
@@ -225,7 +230,7 @@ static const struct ata_port_operations ahci_ops = {
.tf_read = ahci_tf_read,
- .phy_reset = ahci_phy_reset,
+ .probe_reset = ahci_probe_reset,
.qc_prep = ahci_qc_prep,
.qc_issue = ahci_qc_issue,
@@ -247,8 +252,7 @@ static const struct ata_port_info ahci_port_info[] = {
{
.sht = &ahci_sht,
.host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
- ATA_FLAG_PIO_DMA,
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
.port_ops = &ahci_ops,
@@ -450,17 +454,48 @@ static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
}
-static void ahci_phy_reset(struct ata_port *ap)
+static int ahci_stop_engine(struct ata_port *ap)
{
- void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
- struct ata_taskfile tf;
- struct ata_device *dev = &ap->device[0];
- u32 new_tmp, tmp;
+ void __iomem *mmio = ap->host_set->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+ int work;
+ u32 tmp;
- __sata_phy_reset(ap);
+ tmp = readl(port_mmio + PORT_CMD);
+ tmp &= ~PORT_CMD_START;
+ writel(tmp, port_mmio + PORT_CMD);
- if (ap->flags & ATA_FLAG_PORT_DISABLED)
- return;
+ /* wait for engine to stop. TODO: this could be
+ * as long as 500 msec
+ */
+ work = 1000;
+ while (work-- > 0) {
+ tmp = readl(port_mmio + PORT_CMD);
+ if ((tmp & PORT_CMD_LIST_ON) == 0)
+ return 0;
+ udelay(10);
+ }
+
+ return -EIO;
+}
+
+static void ahci_start_engine(struct ata_port *ap)
+{
+ void __iomem *mmio = ap->host_set->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+ u32 tmp;
+
+ tmp = readl(port_mmio + PORT_CMD);
+ tmp |= PORT_CMD_START;
+ writel(tmp, port_mmio + PORT_CMD);
+ readl(port_mmio + PORT_CMD); /* flush */
+}
+
+static unsigned int ahci_dev_classify(struct ata_port *ap)
+{
+ void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+ struct ata_taskfile tf;
+ u32 tmp;
tmp = readl(port_mmio + PORT_SIG);
tf.lbah = (tmp >> 24) & 0xff;
@@ -468,15 +503,46 @@ static void ahci_phy_reset(struct ata_port *ap)
tf.lbal = (tmp >> 8) & 0xff;
tf.nsect = (tmp) & 0xff;
- dev->class = ata_dev_classify(&tf);
- if (!ata_dev_present(dev)) {
- ata_port_disable(ap);
- return;
- }
+ return ata_dev_classify(&tf);
+}
+
+static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, u32 opts)
+{
+ pp->cmd_slot[0].opts = cpu_to_le32(opts);
+ pp->cmd_slot[0].status = 0;
+ pp->cmd_slot[0].tbl_addr = cpu_to_le32(pp->cmd_tbl_dma & 0xffffffff);
+ pp->cmd_slot[0].tbl_addr_hi = cpu_to_le32((pp->cmd_tbl_dma >> 16) >> 16);
+}
+
+static int ahci_hardreset(struct ata_port *ap, int verbose, unsigned int *class)
+{
+ int rc;
+
+ DPRINTK("ENTER\n");
+
+ ahci_stop_engine(ap);
+ rc = sata_std_hardreset(ap, verbose, class);
+ ahci_start_engine(ap);
+
+ if (rc == 0)
+ *class = ahci_dev_classify(ap);
+ if (*class == ATA_DEV_UNKNOWN)
+ *class = ATA_DEV_NONE;
+
+ DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
+ return rc;
+}
+
+static void ahci_postreset(struct ata_port *ap, unsigned int *class)
+{
+ void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+ u32 new_tmp, tmp;
+
+ ata_std_postreset(ap, class);
/* Make sure port's ATAPI bit is set appropriately */
new_tmp = tmp = readl(port_mmio + PORT_CMD);
- if (dev->class == ATA_DEV_ATAPI)
+ if (*class == ATA_DEV_ATAPI)
new_tmp |= PORT_CMD_ATAPI;
else
new_tmp &= ~PORT_CMD_ATAPI;
@@ -486,6 +552,12 @@ static void ahci_phy_reset(struct ata_port *ap)
}
}
+static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes)
+{
+ return ata_drive_probe_reset(ap, NULL, NULL, ahci_hardreset,
+ ahci_postreset, classes);
+}
+
static u8 ahci_check_status(struct ata_port *ap)
{
void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr;
@@ -533,42 +605,36 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct ahci_port_priv *pp = ap->private_data;
+ int is_atapi = is_atapi_taskfile(&qc->tf);
u32 opts;
const u32 cmd_fis_len = 5; /* five dwords */
unsigned int n_elem;
/*
- * Fill in command slot information (currently only one slot,
- * slot 0, is currently since we don't do queueing)
- */
-
- opts = cmd_fis_len;
- if (qc->tf.flags & ATA_TFLAG_WRITE)
- opts |= AHCI_CMD_WRITE;
- if (is_atapi_taskfile(&qc->tf))
- opts |= AHCI_CMD_ATAPI;
-
- pp->cmd_slot[0].opts = cpu_to_le32(opts);
- pp->cmd_slot[0].status = 0;
- pp->cmd_slot[0].tbl_addr = cpu_to_le32(pp->cmd_tbl_dma & 0xffffffff);
- pp->cmd_slot[0].tbl_addr_hi = cpu_to_le32((pp->cmd_tbl_dma >> 16) >> 16);
-
- /*
* Fill in command table information. First, the header,
* a SATA Register - Host to Device command FIS.
*/
ata_tf_to_fis(&qc->tf, pp->cmd_tbl, 0);
- if (opts & AHCI_CMD_ATAPI) {
+ if (is_atapi) {
memset(pp->cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
- memcpy(pp->cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, ap->cdb_len);
+ memcpy(pp->cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb,
+ qc->dev->cdb_len);
}
- if (!(qc->flags & ATA_QCFLAG_DMAMAP))
- return;
+ n_elem = 0;
+ if (qc->flags & ATA_QCFLAG_DMAMAP)
+ n_elem = ahci_fill_sg(qc);
- n_elem = ahci_fill_sg(qc);
+ /*
+ * Fill in command slot information.
+ */
+ opts = cmd_fis_len | n_elem << 16;
+ if (qc->tf.flags & ATA_TFLAG_WRITE)
+ opts |= AHCI_CMD_WRITE;
+ if (is_atapi)
+ opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
- pp->cmd_slot[0].opts |= cpu_to_le32(n_elem << 16);
+ ahci_fill_cmd_slot(pp, opts);
}
static void ahci_restart_port(struct ata_port *ap, u32 irq_stat)
@@ -576,7 +642,6 @@ static void ahci_restart_port(struct ata_port *ap, u32 irq_stat)
void __iomem *mmio = ap->host_set->mmio_base;
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
u32 tmp;
- int work;
if ((ap->device[0].class != ATA_DEV_ATAPI) ||
((irq_stat & PORT_IRQ_TF_ERR) == 0))
@@ -592,20 +657,7 @@ static void ahci_restart_port(struct ata_port *ap, u32 irq_stat)
readl(port_mmio + PORT_SCR_ERR));
/* stop DMA */
- tmp = readl(port_mmio + PORT_CMD);
- tmp &= ~PORT_CMD_START;
- writel(tmp, port_mmio + PORT_CMD);
-
- /* wait for engine to stop. TODO: this could be
- * as long as 500 msec
- */
- work = 1000;
- while (work-- > 0) {
- tmp = readl(port_mmio + PORT_CMD);
- if ((tmp & PORT_CMD_LIST_ON) == 0)
- break;
- udelay(10);
- }
+ ahci_stop_engine(ap);
/* clear SATA phy error, if any */
tmp = readl(port_mmio + PORT_SCR_ERR);
@@ -624,10 +676,7 @@ static void ahci_restart_port(struct ata_port *ap, u32 irq_stat)
}
/* re-start DMA */
- tmp = readl(port_mmio + PORT_CMD);
- tmp |= PORT_CMD_START;
- writel(tmp, port_mmio + PORT_CMD);
- readl(port_mmio + PORT_CMD); /* flush */
+ ahci_start_engine(ap);
}
static void ahci_eng_timeout(struct ata_port *ap)
@@ -642,25 +691,13 @@ static void ahci_eng_timeout(struct ata_port *ap)
spin_lock_irqsave(&host_set->lock, flags);
+ ahci_restart_port(ap, readl(port_mmio + PORT_IRQ_STAT));
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (!qc) {
- printk(KERN_ERR "ata%u: BUG: timeout without command\n",
- ap->id);
- } else {
- ahci_restart_port(ap, readl(port_mmio + PORT_IRQ_STAT));
-
- /* hack alert! We cannot use the supplied completion
- * function from inside the ->eh_strategy_handler() thread.
- * libata is the only user of ->eh_strategy_handler() in
- * any kernel, so the default scsi_done() assumes it is
- * not being called from the SCSI EH.
- */
- qc->scsidone = scsi_finish_command;
- qc->err_mask |= AC_ERR_OTHER;
- ata_qc_complete(qc);
- }
+ qc->err_mask |= AC_ERR_TIMEOUT;
spin_unlock_irqrestore(&host_set->lock, flags);
+
+ ata_eh_qc_complete(qc);
}
static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
@@ -678,7 +715,7 @@ static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
ci = readl(port_mmio + PORT_CMD_ISSUE);
if (likely((ci & 0x1) == 0)) {
if (qc) {
- assert(qc->err_mask == 0);
+ WARN_ON(qc->err_mask);
ata_qc_complete(qc);
qc = NULL;
}
@@ -697,7 +734,7 @@ static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
ahci_restart_port(ap, status);
if (qc) {
- qc->err_mask |= AC_ERR_OTHER;
+ qc->err_mask |= err_mask;
ata_qc_complete(qc);
}
}
@@ -770,7 +807,7 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *
return IRQ_RETVAL(handled);
}
-static int ahci_qc_issue(struct ata_queued_cmd *qc)
+static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
index fc3ca051cee..9327b62f97d 100644
--- a/drivers/scsi/ata_piix.c
+++ b/drivers/scsi/ata_piix.c
@@ -101,36 +101,54 @@ enum {
ICH5_PCS = 0x92, /* port control and status */
PIIX_SCC = 0x0A, /* sub-class code register */
- PIIX_FLAG_AHCI = (1 << 28), /* AHCI possible */
- PIIX_FLAG_CHECKINTR = (1 << 29), /* make sure PCI INTx enabled */
- PIIX_FLAG_COMBINED = (1 << 30), /* combined mode possible */
+ PIIX_FLAG_IGNORE_PCS = (1 << 25), /* ignore PCS present bits */
+ PIIX_FLAG_SCR = (1 << 26), /* SCR available */
+ PIIX_FLAG_AHCI = (1 << 27), /* AHCI possible */
+ PIIX_FLAG_CHECKINTR = (1 << 28), /* make sure PCI INTx enabled */
+ PIIX_FLAG_COMBINED = (1 << 29), /* combined mode possible */
+ /* ICH6/7 use different scheme for map value */
+ PIIX_FLAG_COMBINED_ICH6 = PIIX_FLAG_COMBINED | (1 << 30),
/* combined mode. if set, PATA is channel 0.
* if clear, PATA is channel 1.
*/
- PIIX_COMB_PATA_P0 = (1 << 1),
- PIIX_COMB = (1 << 2), /* combined mode enabled? */
-
PIIX_PORT_ENABLED = (1 << 0),
PIIX_PORT_PRESENT = (1 << 4),
PIIX_80C_PRI = (1 << 5) | (1 << 4),
PIIX_80C_SEC = (1 << 7) | (1 << 6),
- ich5_pata = 0,
- ich5_sata = 1,
- piix4_pata = 2,
- ich6_sata = 3,
- ich6_sata_ahci = 4,
+ /* controller IDs */
+ piix4_pata = 0,
+ ich5_pata = 1,
+ ich5_sata = 2,
+ esb_sata = 3,
+ ich6_sata = 4,
+ ich6_sata_ahci = 5,
+ ich6m_sata_ahci = 6,
+
+ /* constants for mapping table */
+ P0 = 0, /* port 0 */
+ P1 = 1, /* port 1 */
+ P2 = 2, /* port 2 */
+ P3 = 3, /* port 3 */
+ IDE = -1, /* IDE */
+ NA = -2, /* not avaliable */
+ RV = -3, /* reserved */
PIIX_AHCI_DEVICE = 6,
};
+struct piix_map_db {
+ const u32 mask;
+ const int map[][4];
+};
+
static int piix_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent);
-static void piix_pata_phy_reset(struct ata_port *ap);
-static void piix_sata_phy_reset(struct ata_port *ap);
+static int piix_pata_probe_reset(struct ata_port *ap, unsigned int *classes);
+static int piix_sata_probe_reset(struct ata_port *ap, unsigned int *classes);
static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev);
static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev);
@@ -147,19 +165,32 @@ static const struct pci_device_id piix_pci_tbl[] = {
* list in drivers/pci/quirks.c.
*/
+ /* 82801EB (ICH5) */
{ 0x8086, 0x24d1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
+ /* 82801EB (ICH5) */
{ 0x8086, 0x24df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
- { 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
- { 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
+ /* 6300ESB (ICH5 variant with broken PCS present bits) */
+ { 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb_sata },
+ /* 6300ESB pretending RAID */
+ { 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb_sata },
+ /* 82801FB/FW (ICH6/ICH6W) */
{ 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata },
+ /* 82801FR/FRW (ICH6R/ICH6RW) */
{ 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
- { 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+ /* 82801FBM ICH6M (ICH6R with only port 0 and 2 implemented) */
+ { 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata_ahci },
+ /* 82801GB/GR/GH (ICH7, identical to ICH6) */
{ 0x8086, 0x27c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
- { 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+ /* 2801GBM/GHM (ICH7M, identical to ICH6M) */
+ { 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata_ahci },
+ /* Enterprise Southbridge 2 (where's the datasheet?) */
{ 0x8086, 0x2680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+ /* SATA Controller 1 IDE (ICH8, no datasheet yet) */
{ 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+ /* SATA Controller 2 IDE (ICH8, ditto) */
{ 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
- { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+ /* Mobile SATA Controller IDE (ICH8M, ditto) */
+ { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata_ahci },
{ } /* terminate list */
};
@@ -178,11 +209,11 @@ static struct scsi_host_template piix_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
+ .eh_timed_out = ata_scsi_timed_out,
.eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = LIBATA_MAX_PRD,
- .max_sectors = ATA_MAX_SECTORS,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.emulated = ATA_SHT_EMULATED,
.use_clustering = ATA_SHT_USE_CLUSTERING,
@@ -205,7 +236,7 @@ static const struct ata_port_operations piix_pata_ops = {
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
- .phy_reset = piix_pata_phy_reset,
+ .probe_reset = piix_pata_probe_reset,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -233,7 +264,7 @@ static const struct ata_port_operations piix_sata_ops = {
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
- .phy_reset = piix_sata_phy_reset,
+ .probe_reset = piix_sata_probe_reset,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -252,12 +283,62 @@ static const struct ata_port_operations piix_sata_ops = {
.host_stop = ata_host_stop,
};
+static struct piix_map_db ich5_map_db = {
+ .mask = 0x7,
+ .map = {
+ /* PM PS SM SS MAP */
+ { P0, NA, P1, NA }, /* 000b */
+ { P1, NA, P0, NA }, /* 001b */
+ { RV, RV, RV, RV },
+ { RV, RV, RV, RV },
+ { P0, P1, IDE, IDE }, /* 100b */
+ { P1, P0, IDE, IDE }, /* 101b */
+ { IDE, IDE, P0, P1 }, /* 110b */
+ { IDE, IDE, P1, P0 }, /* 111b */
+ },
+};
+
+static struct piix_map_db ich6_map_db = {
+ .mask = 0x3,
+ .map = {
+ /* PM PS SM SS MAP */
+ { P0, P1, P2, P3 }, /* 00b */
+ { IDE, IDE, P1, P3 }, /* 01b */
+ { P0, P2, IDE, IDE }, /* 10b */
+ { RV, RV, RV, RV },
+ },
+};
+
+static struct piix_map_db ich6m_map_db = {
+ .mask = 0x3,
+ .map = {
+ /* PM PS SM SS MAP */
+ { P0, P1, P2, P3 }, /* 00b */
+ { RV, RV, RV, RV },
+ { P0, P2, IDE, IDE }, /* 10b */
+ { RV, RV, RV, RV },
+ },
+};
+
static struct ata_port_info piix_port_info[] = {
+ /* piix4_pata */
+ {
+ .sht = &piix_sht,
+ .host_flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = 0x1f, /* pio0-4 */
+#if 0
+ .mwdma_mask = 0x06, /* mwdma1-2 */
+#else
+ .mwdma_mask = 0x00, /* mwdma broken */
+#endif
+ .udma_mask = ATA_UDMA_MASK_40C,
+ .port_ops = &piix_pata_ops,
+ },
+
/* ich5_pata */
{
.sht = &piix_sht,
- .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
- PIIX_FLAG_CHECKINTR,
+ .host_flags = ATA_FLAG_SLAVE_POSS | PIIX_FLAG_CHECKINTR,
.pio_mask = 0x1f, /* pio0-4 */
#if 0
.mwdma_mask = 0x06, /* mwdma1-2 */
@@ -271,50 +352,63 @@ static struct ata_port_info piix_port_info[] = {
/* ich5_sata */
{
.sht = &piix_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST |
- PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR,
+ .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED |
+ PIIX_FLAG_CHECKINTR,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &piix_sata_ops,
+ .private_data = &ich5_map_db,
},
- /* piix4_pata */
+ /* i6300esb_sata */
{
.sht = &piix_sht,
- .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED |
+ PIIX_FLAG_CHECKINTR | PIIX_FLAG_IGNORE_PCS,
.pio_mask = 0x1f, /* pio0-4 */
-#if 0
- .mwdma_mask = 0x06, /* mwdma1-2 */
-#else
- .mwdma_mask = 0x00, /* mwdma broken */
-#endif
- .udma_mask = ATA_UDMA_MASK_40C,
- .port_ops = &piix_pata_ops,
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &piix_sata_ops,
+ .private_data = &ich5_map_db,
},
/* ich6_sata */
{
.sht = &piix_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST |
- PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR |
- ATA_FLAG_SLAVE_POSS,
+ .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED_ICH6 |
+ PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &piix_sata_ops,
+ .private_data = &ich6_map_db,
},
/* ich6_sata_ahci */
{
.sht = &piix_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST |
- PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR |
- ATA_FLAG_SLAVE_POSS | PIIX_FLAG_AHCI,
+ .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED_ICH6 |
+ PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
+ PIIX_FLAG_AHCI,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &piix_sata_ops,
+ .private_data = &ich6_map_db,
+ },
+
+ /* ich6m_sata_ahci */
+ {
+ .sht = &piix_sht,
+ .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED_ICH6 |
+ PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
+ PIIX_FLAG_AHCI,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &piix_sata_ops,
+ .private_data = &ich6m_map_db,
},
};
@@ -363,102 +457,123 @@ cbl40:
}
/**
- * piix_pata_phy_reset - Probe specified port on PATA host controller
- * @ap: Port to probe
+ * piix_pata_probeinit - probeinit for PATA host controller
+ * @ap: Target port
*
- * Probe PATA phy.
+ * Probeinit including cable detection.
*
* LOCKING:
* None (inherited from caller).
*/
+static void piix_pata_probeinit(struct ata_port *ap)
+{
+ piix_pata_cbl_detect(ap);
+ ata_std_probeinit(ap);
+}
-static void piix_pata_phy_reset(struct ata_port *ap)
+/**
+ * piix_pata_probe_reset - Perform reset on PATA port and classify
+ * @ap: Port to reset
+ * @classes: Resulting classes of attached devices
+ *
+ * Reset PATA phy and classify attached devices.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+static int piix_pata_probe_reset(struct ata_port *ap, unsigned int *classes)
{
struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->hard_port_no])) {
- ata_port_disable(ap);
printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
- return;
+ return 0;
}
- piix_pata_cbl_detect(ap);
-
- ata_port_probe(ap);
-
- ata_bus_reset(ap);
+ return ata_drive_probe_reset(ap, piix_pata_probeinit,
+ ata_std_softreset, NULL,
+ ata_std_postreset, classes);
}
/**
* piix_sata_probe - Probe PCI device for present SATA devices
* @ap: Port associated with the PCI device we wish to probe
*
- * Reads SATA PCI device's PCI config register Port Configuration
- * and Status (PCS) to determine port and device availability.
+ * Reads and configures SATA PCI device's PCI config register
+ * Port Configuration and Status (PCS) to determine port and
+ * device availability.
*
* LOCKING:
* None (inherited from caller).
*
* RETURNS:
- * Non-zero if port is enabled, it may or may not have a device
- * attached in that case (PRESENT bit would only be set if BIOS probe
- * was done). Zero is returned if port is disabled.
+ * Mask of avaliable devices on the port.
*/
-static int piix_sata_probe (struct ata_port *ap)
+static unsigned int piix_sata_probe (struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
- int combined = (ap->flags & ATA_FLAG_SLAVE_POSS);
- int orig_mask, mask, i;
+ const unsigned int *map = ap->host_set->private_data;
+ int base = 2 * ap->hard_port_no;
+ unsigned int present_mask = 0;
+ int port, i;
u8 pcs;
- mask = (PIIX_PORT_PRESENT << ap->hard_port_no) |
- (PIIX_PORT_ENABLED << ap->hard_port_no);
-
pci_read_config_byte(pdev, ICH5_PCS, &pcs);
- orig_mask = (int) pcs & 0xff;
-
- /* TODO: this is vaguely wrong for ICH6 combined mode,
- * where only two of the four SATA ports are mapped
- * onto a single ATA channel. It is also vaguely inaccurate
- * for ICH5, which has only two ports. However, this is ok,
- * as further device presence detection code will handle
- * any false positives produced here.
- */
+ DPRINTK("ata%u: ENTER, pcs=0x%x base=%d\n", ap->id, pcs, base);
- for (i = 0; i < 4; i++) {
- mask = (PIIX_PORT_ENABLED << i);
+ /* enable all ports on this ap and wait for them to settle */
+ for (i = 0; i < 2; i++) {
+ port = map[base + i];
+ if (port >= 0)
+ pcs |= 1 << port;
+ }
+
+ pci_write_config_byte(pdev, ICH5_PCS, pcs);
+ msleep(100);
- if ((orig_mask & mask) == mask)
- if (combined || (i == ap->hard_port_no))
- return 1;
+ /* let's see which devices are present */
+ pci_read_config_byte(pdev, ICH5_PCS, &pcs);
+
+ for (i = 0; i < 2; i++) {
+ port = map[base + i];
+ if (port < 0)
+ continue;
+ if (ap->flags & PIIX_FLAG_IGNORE_PCS || pcs & 1 << (4 + port))
+ present_mask |= 1 << i;
+ else
+ pcs &= ~(1 << port);
}
- return 0;
+ /* disable offline ports on non-AHCI controllers */
+ if (!(ap->flags & PIIX_FLAG_AHCI))
+ pci_write_config_byte(pdev, ICH5_PCS, pcs);
+
+ DPRINTK("ata%u: LEAVE, pcs=0x%x present_mask=0x%x\n",
+ ap->id, pcs, present_mask);
+
+ return present_mask;
}
/**
- * piix_sata_phy_reset - Probe specified port on SATA host controller
- * @ap: Port to probe
+ * piix_sata_probe_reset - Perform reset on SATA port and classify
+ * @ap: Port to reset
+ * @classes: Resulting classes of attached devices
*
- * Probe SATA phy.
+ * Reset SATA phy and classify attached devices.
*
* LOCKING:
* None (inherited from caller).
*/
-
-static void piix_sata_phy_reset(struct ata_port *ap)
+static int piix_sata_probe_reset(struct ata_port *ap, unsigned int *classes)
{
if (!piix_sata_probe(ap)) {
- ata_port_disable(ap);
printk(KERN_INFO "ata%u: SATA port has no device.\n", ap->id);
- return;
+ return 0;
}
- ap->cbl = ATA_CBL_SATA;
-
- ata_port_probe(ap);
-
- ata_bus_reset(ap);
+ return ata_drive_probe_reset(ap, ata_std_probeinit,
+ ata_std_softreset, NULL,
+ ata_std_postreset, classes);
}
/**
@@ -627,6 +742,7 @@ static int piix_disable_ahci(struct pci_dev *pdev)
/**
* piix_check_450nx_errata - Check for problem 450NX setup
+ * @ata_dev: the PCI device to check
*
* Check for the present of 450NX errata #19 and errata #25. If
* they are found return an error code so we can turn off DMA
@@ -659,6 +775,54 @@ static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev)
return no_piix_dma;
}
+static void __devinit piix_init_sata_map(struct pci_dev *pdev,
+ struct ata_port_info *pinfo)
+{
+ struct piix_map_db *map_db = pinfo[0].private_data;
+ const unsigned int *map;
+ int i, invalid_map = 0;
+ u8 map_value;
+
+ pci_read_config_byte(pdev, ICH5_PMR, &map_value);
+
+ map = map_db->map[map_value & map_db->mask];
+
+ dev_printk(KERN_INFO, &pdev->dev, "MAP [");
+ for (i = 0; i < 4; i++) {
+ switch (map[i]) {
+ case RV:
+ invalid_map = 1;
+ printk(" XX");
+ break;
+
+ case NA:
+ printk(" --");
+ break;
+
+ case IDE:
+ WARN_ON((i & 1) || map[i + 1] != IDE);
+ pinfo[i / 2] = piix_port_info[ich5_pata];
+ i++;
+ printk(" IDE IDE");
+ break;
+
+ default:
+ printk(" P%d", map[i]);
+ if (i & 1)
+ pinfo[i / 2].host_flags |= ATA_FLAG_SLAVE_POSS;
+ break;
+ }
+ }
+ printk(" ]\n");
+
+ if (invalid_map)
+ dev_printk(KERN_ERR, &pdev->dev,
+ "invalid MAP value %u\n", map_value);
+
+ pinfo[0].private_data = (void *)map;
+ pinfo[1].private_data = (void *)map;
+}
+
/**
* piix_init_one - Register PIIX ATA PCI device with kernel services
* @pdev: PCI device to register
@@ -677,9 +841,9 @@ static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev)
static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_port_info *port_info[2];
- unsigned int combined = 0;
- unsigned int pata_chan = 0, sata_chan = 0;
+ struct ata_port_info port_info[2];
+ struct ata_port_info *ppinfo[2] = { &port_info[0], &port_info[1] };
+ unsigned long host_flags;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev,
@@ -689,10 +853,12 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (!in_module_init)
return -ENODEV;
- port_info[0] = &piix_port_info[ent->driver_data];
- port_info[1] = &piix_port_info[ent->driver_data];
+ port_info[0] = piix_port_info[ent->driver_data];
+ port_info[1] = piix_port_info[ent->driver_data];
+
+ host_flags = port_info[0].host_flags;
- if (port_info[0]->host_flags & PIIX_FLAG_AHCI) {
+ if (host_flags & PIIX_FLAG_AHCI) {
u8 tmp;
pci_read_config_byte(pdev, PIIX_SCC, &tmp);
if (tmp == PIIX_AHCI_DEVICE) {
@@ -702,18 +868,9 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
}
}
- if (port_info[0]->host_flags & PIIX_FLAG_COMBINED) {
- u8 tmp;
- pci_read_config_byte(pdev, ICH5_PMR, &tmp);
-
- if (tmp & PIIX_COMB) {
- combined = 1;
- if (tmp & PIIX_COMB_PATA_P0)
- sata_chan = 1;
- else
- pata_chan = 1;
- }
- }
+ /* Initialize SATA map */
+ if (host_flags & ATA_FLAG_SATA)
+ piix_init_sata_map(pdev, port_info);
/* On ICH5, some BIOSen disable the interrupt using the
* PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3.
@@ -721,28 +878,19 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
* MSI is disabled (and it is disabled, as we don't use
* message-signalled interrupts currently).
*/
- if (port_info[0]->host_flags & PIIX_FLAG_CHECKINTR)
+ if (host_flags & PIIX_FLAG_CHECKINTR)
pci_intx(pdev, 1);
- if (combined) {
- port_info[sata_chan] = &piix_port_info[ent->driver_data];
- port_info[sata_chan]->host_flags |= ATA_FLAG_SLAVE_POSS;
- port_info[pata_chan] = &piix_port_info[ich5_pata];
-
- dev_printk(KERN_WARNING, &pdev->dev,
- "combined mode detected (p=%u, s=%u)\n",
- pata_chan, sata_chan);
- }
if (piix_check_450nx_errata(pdev)) {
/* This writes into the master table but it does not
really matter for this errata as we will apply it to
all the PIIX devices on the board */
- port_info[0]->mwdma_mask = 0;
- port_info[0]->udma_mask = 0;
- port_info[1]->mwdma_mask = 0;
- port_info[1]->udma_mask = 0;
+ port_info[0].mwdma_mask = 0;
+ port_info[0].udma_mask = 0;
+ port_info[1].mwdma_mask = 0;
+ port_info[1].udma_mask = 0;
}
- return ata_pci_init_one(pdev, port_info, 2);
+ return ata_pci_init_one(pdev, ppinfo, 2);
}
static int __init piix_init(void)
diff --git a/drivers/scsi/libata-bmdma.c b/drivers/scsi/libata-bmdma.c
new file mode 100644
index 00000000000..a93336adcd2
--- /dev/null
+++ b/drivers/scsi/libata-bmdma.c
@@ -0,0 +1,703 @@
+/*
+ * libata-bmdma.c - helper library for PCI IDE BMDMA
+ *
+ * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Please ALWAYS copy linux-ide@vger.kernel.org
+ * on emails.
+ *
+ * Copyright 2003-2006 Red Hat, Inc. All rights reserved.
+ * Copyright 2003-2006 Jeff Garzik
+ *
+ *
+ * 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, 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * Hardware documentation available from http://www.t13.org/ and
+ * http://www.sata-io.org/
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/libata.h>
+
+#include "libata.h"
+
+/**
+ * ata_tf_load_pio - send taskfile registers to host controller
+ * @ap: Port to which output is sent
+ * @tf: ATA taskfile register set
+ *
+ * Outputs ATA taskfile to standard ATA host controller.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+static void ata_tf_load_pio(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+ if (tf->ctl != ap->last_ctl) {
+ outb(tf->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = tf->ctl;
+ ata_wait_idle(ap);
+ }
+
+ if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+ outb(tf->hob_feature, ioaddr->feature_addr);
+ outb(tf->hob_nsect, ioaddr->nsect_addr);
+ outb(tf->hob_lbal, ioaddr->lbal_addr);
+ outb(tf->hob_lbam, ioaddr->lbam_addr);
+ outb(tf->hob_lbah, ioaddr->lbah_addr);
+ VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
+ tf->hob_feature,
+ tf->hob_nsect,
+ tf->hob_lbal,
+ tf->hob_lbam,
+ tf->hob_lbah);
+ }
+
+ if (is_addr) {
+ outb(tf->feature, ioaddr->feature_addr);
+ outb(tf->nsect, ioaddr->nsect_addr);
+ outb(tf->lbal, ioaddr->lbal_addr);
+ outb(tf->lbam, ioaddr->lbam_addr);
+ outb(tf->lbah, ioaddr->lbah_addr);
+ VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
+ tf->feature,
+ tf->nsect,
+ tf->lbal,
+ tf->lbam,
+ tf->lbah);
+ }
+
+ if (tf->flags & ATA_TFLAG_DEVICE) {
+ outb(tf->device, ioaddr->device_addr);
+ VPRINTK("device 0x%X\n", tf->device);
+ }
+
+ ata_wait_idle(ap);
+}
+
+/**
+ * ata_tf_load_mmio - send taskfile registers to host controller
+ * @ap: Port to which output is sent
+ * @tf: ATA taskfile register set
+ *
+ * Outputs ATA taskfile to standard ATA host controller using MMIO.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+static void ata_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+ if (tf->ctl != ap->last_ctl) {
+ writeb(tf->ctl, (void __iomem *) ap->ioaddr.ctl_addr);
+ ap->last_ctl = tf->ctl;
+ ata_wait_idle(ap);
+ }
+
+ if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+ writeb(tf->hob_feature, (void __iomem *) ioaddr->feature_addr);
+ writeb(tf->hob_nsect, (void __iomem *) ioaddr->nsect_addr);
+ writeb(tf->hob_lbal, (void __iomem *) ioaddr->lbal_addr);
+ writeb(tf->hob_lbam, (void __iomem *) ioaddr->lbam_addr);
+ writeb(tf->hob_lbah, (void __iomem *) ioaddr->lbah_addr);
+ VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
+ tf->hob_feature,
+ tf->hob_nsect,
+ tf->hob_lbal,
+ tf->hob_lbam,
+ tf->hob_lbah);
+ }
+
+ if (is_addr) {
+ writeb(tf->feature, (void __iomem *) ioaddr->feature_addr);
+ writeb(tf->nsect, (void __iomem *) ioaddr->nsect_addr);
+ writeb(tf->lbal, (void __iomem *) ioaddr->lbal_addr);
+ writeb(tf->lbam, (void __iomem *) ioaddr->lbam_addr);
+ writeb(tf->lbah, (void __iomem *) ioaddr->lbah_addr);
+ VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
+ tf->feature,
+ tf->nsect,
+ tf->lbal,
+ tf->lbam,
+ tf->lbah);
+ }
+
+ if (tf->flags & ATA_TFLAG_DEVICE) {
+ writeb(tf->device, (void __iomem *) ioaddr->device_addr);
+ VPRINTK("device 0x%X\n", tf->device);
+ }
+
+ ata_wait_idle(ap);
+}
+
+
+/**
+ * ata_tf_load - send taskfile registers to host controller
+ * @ap: Port to which output is sent
+ * @tf: ATA taskfile register set
+ *
+ * Outputs ATA taskfile to standard ATA host controller using MMIO
+ * or PIO as indicated by the ATA_FLAG_MMIO flag.
+ * Writes the control, feature, nsect, lbal, lbam, and lbah registers.
+ * Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect,
+ * hob_lbal, hob_lbam, and hob_lbah.
+ *
+ * This function waits for idle (!BUSY and !DRQ) after writing
+ * registers. If the control register has a new value, this
+ * function also waits for idle after writing control and before
+ * writing the remaining registers.
+ *
+ * May be used as the tf_load() entry in ata_port_operations.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+ if (ap->flags & ATA_FLAG_MMIO)
+ ata_tf_load_mmio(ap, tf);
+ else
+ ata_tf_load_pio(ap, tf);
+}
+
+/**
+ * ata_exec_command_pio - issue ATA command to host controller
+ * @ap: port to which command is being issued
+ * @tf: ATA taskfile register set
+ *
+ * Issues PIO write to ATA command register, with proper
+ * synchronization with interrupt handler / other threads.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host_set lock)
+ */
+
+static void ata_exec_command_pio(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+ DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
+
+ outb(tf->command, ap->ioaddr.command_addr);
+ ata_pause(ap);
+}
+
+
+/**
+ * ata_exec_command_mmio - issue ATA command to host controller
+ * @ap: port to which command is being issued
+ * @tf: ATA taskfile register set
+ *
+ * Issues MMIO write to ATA command register, with proper
+ * synchronization with interrupt handler / other threads.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host_set lock)
+ */
+
+static void ata_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+ DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
+
+ writeb(tf->command, (void __iomem *) ap->ioaddr.command_addr);
+ ata_pause(ap);
+}
+
+
+/**
+ * ata_exec_command - issue ATA command to host controller
+ * @ap: port to which command is being issued
+ * @tf: ATA taskfile register set
+ *
+ * Issues PIO/MMIO write to ATA command register, with proper
+ * synchronization with interrupt handler / other threads.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host_set lock)
+ */
+void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+ if (ap->flags & ATA_FLAG_MMIO)
+ ata_exec_command_mmio(ap, tf);
+ else
+ ata_exec_command_pio(ap, tf);
+}
+
+/**
+ * ata_tf_read_pio - input device's ATA taskfile shadow registers
+ * @ap: Port from which input is read
+ * @tf: ATA taskfile register set for storing input
+ *
+ * Reads ATA taskfile registers for currently-selected device
+ * into @tf.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+static void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ tf->command = ata_check_status(ap);
+ tf->feature = inb(ioaddr->error_addr);
+ tf->nsect = inb(ioaddr->nsect_addr);
+ tf->lbal = inb(ioaddr->lbal_addr);
+ tf->lbam = inb(ioaddr->lbam_addr);
+ tf->lbah = inb(ioaddr->lbah_addr);
+ tf->device = inb(ioaddr->device_addr);
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ outb(tf->ctl | ATA_HOB, ioaddr->ctl_addr);
+ tf->hob_feature = inb(ioaddr->error_addr);
+ tf->hob_nsect = inb(ioaddr->nsect_addr);
+ tf->hob_lbal = inb(ioaddr->lbal_addr);
+ tf->hob_lbam = inb(ioaddr->lbam_addr);
+ tf->hob_lbah = inb(ioaddr->lbah_addr);
+ }
+}
+
+/**
+ * ata_tf_read_mmio - input device's ATA taskfile shadow registers
+ * @ap: Port from which input is read
+ * @tf: ATA taskfile register set for storing input
+ *
+ * Reads ATA taskfile registers for currently-selected device
+ * into @tf via MMIO.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+static void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ tf->command = ata_check_status(ap);
+ tf->feature = readb((void __iomem *)ioaddr->error_addr);
+ tf->nsect = readb((void __iomem *)ioaddr->nsect_addr);
+ tf->lbal = readb((void __iomem *)ioaddr->lbal_addr);
+ tf->lbam = readb((void __iomem *)ioaddr->lbam_addr);
+ tf->lbah = readb((void __iomem *)ioaddr->lbah_addr);
+ tf->device = readb((void __iomem *)ioaddr->device_addr);
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ writeb(tf->ctl | ATA_HOB, (void __iomem *) ap->ioaddr.ctl_addr);
+ tf->hob_feature = readb((void __iomem *)ioaddr->error_addr);
+ tf->hob_nsect = readb((void __iomem *)ioaddr->nsect_addr);
+ tf->hob_lbal = readb((void __iomem *)ioaddr->lbal_addr);
+ tf->hob_lbam = readb((void __iomem *)ioaddr->lbam_addr);
+ tf->hob_lbah = readb((void __iomem *)ioaddr->lbah_addr);
+ }
+}
+
+
+/**
+ * ata_tf_read - input device's ATA taskfile shadow registers
+ * @ap: Port from which input is read
+ * @tf: ATA taskfile register set for storing input
+ *
+ * Reads ATA taskfile registers for currently-selected device
+ * into @tf.
+ *
+ * Reads nsect, lbal, lbam, lbah, and device. If ATA_TFLAG_LBA48
+ * is set, also reads the hob registers.
+ *
+ * May be used as the tf_read() entry in ata_port_operations.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ if (ap->flags & ATA_FLAG_MMIO)
+ ata_tf_read_mmio(ap, tf);
+ else
+ ata_tf_read_pio(ap, tf);
+}
+
+/**
+ * ata_check_status_pio - Read device status reg & clear interrupt
+ * @ap: port where the device is
+ *
+ * Reads ATA taskfile status register for currently-selected device
+ * and return its value. This also clears pending interrupts
+ * from this device
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static u8 ata_check_status_pio(struct ata_port *ap)
+{
+ return inb(ap->ioaddr.status_addr);
+}
+
+/**
+ * ata_check_status_mmio - Read device status reg & clear interrupt
+ * @ap: port where the device is
+ *
+ * Reads ATA taskfile status register for currently-selected device
+ * via MMIO and return its value. This also clears pending interrupts
+ * from this device
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static u8 ata_check_status_mmio(struct ata_port *ap)
+{
+ return readb((void __iomem *) ap->ioaddr.status_addr);
+}
+
+
+/**
+ * ata_check_status - Read device status reg & clear interrupt
+ * @ap: port where the device is
+ *
+ * Reads ATA taskfile status register for currently-selected device
+ * and return its value. This also clears pending interrupts
+ * from this device
+ *
+ * May be used as the check_status() entry in ata_port_operations.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+u8 ata_check_status(struct ata_port *ap)
+{
+ if (ap->flags & ATA_FLAG_MMIO)
+ return ata_check_status_mmio(ap);
+ return ata_check_status_pio(ap);
+}
+
+
+/**
+ * ata_altstatus - Read device alternate status reg
+ * @ap: port where the device is
+ *
+ * Reads ATA taskfile alternate status register for
+ * currently-selected device and return its value.
+ *
+ * Note: may NOT be used as the check_altstatus() entry in
+ * ata_port_operations.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+u8 ata_altstatus(struct ata_port *ap)
+{
+ if (ap->ops->check_altstatus)
+ return ap->ops->check_altstatus(ap);
+
+ if (ap->flags & ATA_FLAG_MMIO)
+ return readb((void __iomem *)ap->ioaddr.altstatus_addr);
+ return inb(ap->ioaddr.altstatus_addr);
+}
+
+#ifdef CONFIG_PCI
+static struct ata_probe_ent *
+ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
+{
+ struct ata_probe_ent *probe_ent;
+
+ probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
+ if (!probe_ent) {
+ printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
+ kobject_name(&(dev->kobj)));
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&probe_ent->node);
+ probe_ent->dev = dev;
+
+ probe_ent->sht = port->sht;
+ probe_ent->host_flags = port->host_flags;
+ probe_ent->pio_mask = port->pio_mask;
+ probe_ent->mwdma_mask = port->mwdma_mask;
+ probe_ent->udma_mask = port->udma_mask;
+ probe_ent->port_ops = port->port_ops;
+
+ return probe_ent;
+}
+
+
+/**
+ * ata_pci_init_native_mode - Initialize native-mode driver
+ * @pdev: pci device to be initialized
+ * @port: array[2] of pointers to port info structures.
+ * @ports: bitmap of ports present
+ *
+ * Utility function which allocates and initializes an
+ * ata_probe_ent structure for a standard dual-port
+ * PIO-based IDE controller. The returned ata_probe_ent
+ * structure can be passed to ata_device_add(). The returned
+ * ata_probe_ent structure should then be freed with kfree().
+ *
+ * The caller need only pass the address of the primary port, the
+ * secondary will be deduced automatically. If the device has non
+ * standard secondary port mappings this function can be called twice,
+ * once for each interface.
+ */
+
+struct ata_probe_ent *
+ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int ports)
+{
+ struct ata_probe_ent *probe_ent =
+ ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
+ int p = 0;
+
+ if (!probe_ent)
+ return NULL;
+
+ probe_ent->irq = pdev->irq;
+ probe_ent->irq_flags = SA_SHIRQ;
+ probe_ent->private_data = port[0]->private_data;
+
+ if (ports & ATA_PORT_PRIMARY) {
+ probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 0);
+ probe_ent->port[p].altstatus_addr =
+ probe_ent->port[p].ctl_addr =
+ pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS;
+ probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4);
+ ata_std_ports(&probe_ent->port[p]);
+ p++;
+ }
+
+ if (ports & ATA_PORT_SECONDARY) {
+ probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 2);
+ probe_ent->port[p].altstatus_addr =
+ probe_ent->port[p].ctl_addr =
+ pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS;
+ probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4) + 8;
+ ata_std_ports(&probe_ent->port[p]);
+ p++;
+ }
+
+ probe_ent->n_ports = p;
+ return probe_ent;
+}
+
+
+static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
+ struct ata_port_info *port, int port_num)
+{
+ struct ata_probe_ent *probe_ent;
+
+ probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port);
+ if (!probe_ent)
+ return NULL;
+
+ probe_ent->legacy_mode = 1;
+ probe_ent->n_ports = 1;
+ probe_ent->hard_port_no = port_num;
+ probe_ent->private_data = port->private_data;
+
+ switch(port_num)
+ {
+ case 0:
+ probe_ent->irq = 14;
+ probe_ent->port[0].cmd_addr = 0x1f0;
+ probe_ent->port[0].altstatus_addr =
+ probe_ent->port[0].ctl_addr = 0x3f6;
+ break;
+ case 1:
+ probe_ent->irq = 15;
+ probe_ent->port[0].cmd_addr = 0x170;
+ probe_ent->port[0].altstatus_addr =
+ probe_ent->port[0].ctl_addr = 0x376;
+ break;
+ }
+
+ probe_ent->port[0].bmdma_addr =
+ pci_resource_start(pdev, 4) + 8 * port_num;
+ ata_std_ports(&probe_ent->port[0]);
+
+ return probe_ent;
+}
+
+
+/**
+ * ata_pci_init_one - Initialize/register PCI IDE host controller
+ * @pdev: Controller to be initialized
+ * @port_info: Information from low-level host driver
+ * @n_ports: Number of ports attached to host controller
+ *
+ * This is a helper function which can be called from a driver's
+ * xxx_init_one() probe function if the hardware uses traditional
+ * IDE taskfile registers.
+ *
+ * This function calls pci_enable_device(), reserves its register
+ * regions, sets the dma mask, enables bus master mode, and calls
+ * ata_device_add()
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, negative on errno-based value on error.
+ */
+
+int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
+ unsigned int n_ports)
+{
+ struct ata_probe_ent *probe_ent = NULL, *probe_ent2 = NULL;
+ struct ata_port_info *port[2];
+ u8 tmp8, mask;
+ unsigned int legacy_mode = 0;
+ int disable_dev_on_err = 1;
+ int rc;
+
+ DPRINTK("ENTER\n");
+
+ port[0] = port_info[0];
+ if (n_ports > 1)
+ port[1] = port_info[1];
+ else
+ port[1] = port[0];
+
+ if ((port[0]->host_flags & ATA_FLAG_NO_LEGACY) == 0
+ && (pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+ /* TODO: What if one channel is in native mode ... */
+ pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
+ mask = (1 << 2) | (1 << 0);
+ if ((tmp8 & mask) != mask)
+ legacy_mode = (1 << 3);
+ }
+
+ /* FIXME... */
+ if ((!legacy_mode) && (n_ports > 2)) {
+ printk(KERN_ERR "ata: BUG: native mode, n_ports > 2\n");
+ n_ports = 2;
+ /* For now */
+ }
+
+ /* FIXME: Really for ATA it isn't safe because the device may be
+ multi-purpose and we want to leave it alone if it was already
+ enabled. Secondly for shared use as Arjan says we want refcounting
+
+ Checking dev->is_enabled is insufficient as this is not set at
+ boot for the primary video which is BIOS enabled
+ */
+
+ rc = pci_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc) {
+ disable_dev_on_err = 0;
+ goto err_out;
+ }
+
+ /* FIXME: Should use platform specific mappers for legacy port ranges */
+ if (legacy_mode) {
+ if (!request_region(0x1f0, 8, "libata")) {
+ struct resource *conflict, res;
+ res.start = 0x1f0;
+ res.end = 0x1f0 + 8 - 1;
+ conflict = ____request_resource(&ioport_resource, &res);
+ if (!strcmp(conflict->name, "libata"))
+ legacy_mode |= (1 << 0);
+ else {
+ disable_dev_on_err = 0;
+ printk(KERN_WARNING "ata: 0x1f0 IDE port busy\n");
+ }
+ } else
+ legacy_mode |= (1 << 0);
+
+ if (!request_region(0x170, 8, "libata")) {
+ struct resource *conflict, res;
+ res.start = 0x170;
+ res.end = 0x170 + 8 - 1;
+ conflict = ____request_resource(&ioport_resource, &res);
+ if (!strcmp(conflict->name, "libata"))
+ legacy_mode |= (1 << 1);
+ else {
+ disable_dev_on_err = 0;
+ printk(KERN_WARNING "ata: 0x170 IDE port busy\n");
+ }
+ } else
+ legacy_mode |= (1 << 1);
+ }
+
+ /* we have legacy mode, but all ports are unavailable */
+ if (legacy_mode == (1 << 3)) {
+ rc = -EBUSY;
+ goto err_out_regions;
+ }
+
+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+
+ if (legacy_mode) {
+ if (legacy_mode & (1 << 0))
+ probe_ent = ata_pci_init_legacy_port(pdev, port[0], 0);
+ if (legacy_mode & (1 << 1))
+ probe_ent2 = ata_pci_init_legacy_port(pdev, port[1], 1);
+ } else {
+ if (n_ports == 2)
+ probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
+ else
+ probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY);
+ }
+ if (!probe_ent && !probe_ent2) {
+ rc = -ENOMEM;
+ goto err_out_regions;
+ }
+
+ pci_set_master(pdev);
+
+ /* FIXME: check ata_device_add return */
+ if (legacy_mode) {
+ if (legacy_mode & (1 << 0))
+ ata_device_add(probe_ent);
+ if (legacy_mode & (1 << 1))
+ ata_device_add(probe_ent2);
+ } else
+ ata_device_add(probe_ent);
+
+ kfree(probe_ent);
+ kfree(probe_ent2);
+
+ return 0;
+
+err_out_regions:
+ if (legacy_mode & (1 << 0))
+ release_region(0x1f0, 8);
+ if (legacy_mode & (1 << 1))
+ release_region(0x170, 8);
+ pci_release_regions(pdev);
+err_out:
+ if (disable_dev_on_err)
+ pci_disable_device(pdev);
+ return rc;
+}
+
+#endif /* CONFIG_PCI */
+
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 4f91b0dc572..714b42bad93 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -61,24 +61,17 @@
#include "libata.h"
-static unsigned int ata_busy_sleep (struct ata_port *ap,
- unsigned long tmout_pat,
- unsigned long tmout);
-static void ata_dev_reread_id(struct ata_port *ap, struct ata_device *dev);
-static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev);
+static unsigned int ata_dev_init_params(struct ata_port *ap,
+ struct ata_device *dev);
static void ata_set_mode(struct ata_port *ap);
static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev);
-static unsigned int ata_get_mode_mask(const struct ata_port *ap, int shift);
-static int fgb(u32 bitmap);
-static int ata_choose_xfer_mode(const struct ata_port *ap,
- u8 *xfer_mode_out,
- unsigned int *xfer_shift_out);
-static void __ata_qc_complete(struct ata_queued_cmd *qc);
+static unsigned int ata_dev_xfermask(struct ata_port *ap,
+ struct ata_device *dev);
static unsigned int ata_unique_id = 1;
static struct workqueue_struct *ata_wq;
-int atapi_enabled = 0;
+int atapi_enabled = 1;
module_param(atapi_enabled, int, 0444);
MODULE_PARM_DESC(atapi_enabled, "Enable discovery of ATAPI devices (0=off, 1=on)");
@@ -91,403 +84,6 @@ MODULE_DESCRIPTION("Library module for ATA devices");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
-/**
- * ata_tf_load_pio - send taskfile registers to host controller
- * @ap: Port to which output is sent
- * @tf: ATA taskfile register set
- *
- * Outputs ATA taskfile to standard ATA host controller.
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-static void ata_tf_load_pio(struct ata_port *ap, const struct ata_taskfile *tf)
-{
- struct ata_ioports *ioaddr = &ap->ioaddr;
- unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
-
- if (tf->ctl != ap->last_ctl) {
- outb(tf->ctl, ioaddr->ctl_addr);
- ap->last_ctl = tf->ctl;
- ata_wait_idle(ap);
- }
-
- if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
- outb(tf->hob_feature, ioaddr->feature_addr);
- outb(tf->hob_nsect, ioaddr->nsect_addr);
- outb(tf->hob_lbal, ioaddr->lbal_addr);
- outb(tf->hob_lbam, ioaddr->lbam_addr);
- outb(tf->hob_lbah, ioaddr->lbah_addr);
- VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
- tf->hob_feature,
- tf->hob_nsect,
- tf->hob_lbal,
- tf->hob_lbam,
- tf->hob_lbah);
- }
-
- if (is_addr) {
- outb(tf->feature, ioaddr->feature_addr);
- outb(tf->nsect, ioaddr->nsect_addr);
- outb(tf->lbal, ioaddr->lbal_addr);
- outb(tf->lbam, ioaddr->lbam_addr);
- outb(tf->lbah, ioaddr->lbah_addr);
- VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
- tf->feature,
- tf->nsect,
- tf->lbal,
- tf->lbam,
- tf->lbah);
- }
-
- if (tf->flags & ATA_TFLAG_DEVICE) {
- outb(tf->device, ioaddr->device_addr);
- VPRINTK("device 0x%X\n", tf->device);
- }
-
- ata_wait_idle(ap);
-}
-
-/**
- * ata_tf_load_mmio - send taskfile registers to host controller
- * @ap: Port to which output is sent
- * @tf: ATA taskfile register set
- *
- * Outputs ATA taskfile to standard ATA host controller using MMIO.
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-static void ata_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
-{
- struct ata_ioports *ioaddr = &ap->ioaddr;
- unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
-
- if (tf->ctl != ap->last_ctl) {
- writeb(tf->ctl, (void __iomem *) ap->ioaddr.ctl_addr);
- ap->last_ctl = tf->ctl;
- ata_wait_idle(ap);
- }
-
- if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
- writeb(tf->hob_feature, (void __iomem *) ioaddr->feature_addr);
- writeb(tf->hob_nsect, (void __iomem *) ioaddr->nsect_addr);
- writeb(tf->hob_lbal, (void __iomem *) ioaddr->lbal_addr);
- writeb(tf->hob_lbam, (void __iomem *) ioaddr->lbam_addr);
- writeb(tf->hob_lbah, (void __iomem *) ioaddr->lbah_addr);
- VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
- tf->hob_feature,
- tf->hob_nsect,
- tf->hob_lbal,
- tf->hob_lbam,
- tf->hob_lbah);
- }
-
- if (is_addr) {
- writeb(tf->feature, (void __iomem *) ioaddr->feature_addr);
- writeb(tf->nsect, (void __iomem *) ioaddr->nsect_addr);
- writeb(tf->lbal, (void __iomem *) ioaddr->lbal_addr);
- writeb(tf->lbam, (void __iomem *) ioaddr->lbam_addr);
- writeb(tf->lbah, (void __iomem *) ioaddr->lbah_addr);
- VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
- tf->feature,
- tf->nsect,
- tf->lbal,
- tf->lbam,
- tf->lbah);
- }
-
- if (tf->flags & ATA_TFLAG_DEVICE) {
- writeb(tf->device, (void __iomem *) ioaddr->device_addr);
- VPRINTK("device 0x%X\n", tf->device);
- }
-
- ata_wait_idle(ap);
-}
-
-
-/**
- * ata_tf_load - send taskfile registers to host controller
- * @ap: Port to which output is sent
- * @tf: ATA taskfile register set
- *
- * Outputs ATA taskfile to standard ATA host controller using MMIO
- * or PIO as indicated by the ATA_FLAG_MMIO flag.
- * Writes the control, feature, nsect, lbal, lbam, and lbah registers.
- * Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect,
- * hob_lbal, hob_lbam, and hob_lbah.
- *
- * This function waits for idle (!BUSY and !DRQ) after writing
- * registers. If the control register has a new value, this
- * function also waits for idle after writing control and before
- * writing the remaining registers.
- *
- * May be used as the tf_load() entry in ata_port_operations.
- *
- * LOCKING:
- * Inherited from caller.
- */
-void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
-{
- if (ap->flags & ATA_FLAG_MMIO)
- ata_tf_load_mmio(ap, tf);
- else
- ata_tf_load_pio(ap, tf);
-}
-
-/**
- * ata_exec_command_pio - issue ATA command to host controller
- * @ap: port to which command is being issued
- * @tf: ATA taskfile register set
- *
- * Issues PIO write to ATA command register, with proper
- * synchronization with interrupt handler / other threads.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-static void ata_exec_command_pio(struct ata_port *ap, const struct ata_taskfile *tf)
-{
- DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
-
- outb(tf->command, ap->ioaddr.command_addr);
- ata_pause(ap);
-}
-
-
-/**
- * ata_exec_command_mmio - issue ATA command to host controller
- * @ap: port to which command is being issued
- * @tf: ATA taskfile register set
- *
- * Issues MMIO write to ATA command register, with proper
- * synchronization with interrupt handler / other threads.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-static void ata_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
-{
- DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
-
- writeb(tf->command, (void __iomem *) ap->ioaddr.command_addr);
- ata_pause(ap);
-}
-
-
-/**
- * ata_exec_command - issue ATA command to host controller
- * @ap: port to which command is being issued
- * @tf: ATA taskfile register set
- *
- * Issues PIO/MMIO write to ATA command register, with proper
- * synchronization with interrupt handler / other threads.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
-{
- if (ap->flags & ATA_FLAG_MMIO)
- ata_exec_command_mmio(ap, tf);
- else
- ata_exec_command_pio(ap, tf);
-}
-
-/**
- * ata_tf_to_host - issue ATA taskfile to host controller
- * @ap: port to which command is being issued
- * @tf: ATA taskfile register set
- *
- * Issues ATA taskfile register set to ATA host controller,
- * with proper synchronization with interrupt handler and
- * other threads.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-static inline void ata_tf_to_host(struct ata_port *ap,
- const struct ata_taskfile *tf)
-{
- ap->ops->tf_load(ap, tf);
- ap->ops->exec_command(ap, tf);
-}
-
-/**
- * ata_tf_read_pio - input device's ATA taskfile shadow registers
- * @ap: Port from which input is read
- * @tf: ATA taskfile register set for storing input
- *
- * Reads ATA taskfile registers for currently-selected device
- * into @tf.
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-static void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf)
-{
- struct ata_ioports *ioaddr = &ap->ioaddr;
-
- tf->command = ata_check_status(ap);
- tf->feature = inb(ioaddr->error_addr);
- tf->nsect = inb(ioaddr->nsect_addr);
- tf->lbal = inb(ioaddr->lbal_addr);
- tf->lbam = inb(ioaddr->lbam_addr);
- tf->lbah = inb(ioaddr->lbah_addr);
- tf->device = inb(ioaddr->device_addr);
-
- if (tf->flags & ATA_TFLAG_LBA48) {
- outb(tf->ctl | ATA_HOB, ioaddr->ctl_addr);
- tf->hob_feature = inb(ioaddr->error_addr);
- tf->hob_nsect = inb(ioaddr->nsect_addr);
- tf->hob_lbal = inb(ioaddr->lbal_addr);
- tf->hob_lbam = inb(ioaddr->lbam_addr);
- tf->hob_lbah = inb(ioaddr->lbah_addr);
- }
-}
-
-/**
- * ata_tf_read_mmio - input device's ATA taskfile shadow registers
- * @ap: Port from which input is read
- * @tf: ATA taskfile register set for storing input
- *
- * Reads ATA taskfile registers for currently-selected device
- * into @tf via MMIO.
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-static void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf)
-{
- struct ata_ioports *ioaddr = &ap->ioaddr;
-
- tf->command = ata_check_status(ap);
- tf->feature = readb((void __iomem *)ioaddr->error_addr);
- tf->nsect = readb((void __iomem *)ioaddr->nsect_addr);
- tf->lbal = readb((void __iomem *)ioaddr->lbal_addr);
- tf->lbam = readb((void __iomem *)ioaddr->lbam_addr);
- tf->lbah = readb((void __iomem *)ioaddr->lbah_addr);
- tf->device = readb((void __iomem *)ioaddr->device_addr);
-
- if (tf->flags & ATA_TFLAG_LBA48) {
- writeb(tf->ctl | ATA_HOB, (void __iomem *) ap->ioaddr.ctl_addr);
- tf->hob_feature = readb((void __iomem *)ioaddr->error_addr);
- tf->hob_nsect = readb((void __iomem *)ioaddr->nsect_addr);
- tf->hob_lbal = readb((void __iomem *)ioaddr->lbal_addr);
- tf->hob_lbam = readb((void __iomem *)ioaddr->lbam_addr);
- tf->hob_lbah = readb((void __iomem *)ioaddr->lbah_addr);
- }
-}
-
-
-/**
- * ata_tf_read - input device's ATA taskfile shadow registers
- * @ap: Port from which input is read
- * @tf: ATA taskfile register set for storing input
- *
- * Reads ATA taskfile registers for currently-selected device
- * into @tf.
- *
- * Reads nsect, lbal, lbam, lbah, and device. If ATA_TFLAG_LBA48
- * is set, also reads the hob registers.
- *
- * May be used as the tf_read() entry in ata_port_operations.
- *
- * LOCKING:
- * Inherited from caller.
- */
-void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
-{
- if (ap->flags & ATA_FLAG_MMIO)
- ata_tf_read_mmio(ap, tf);
- else
- ata_tf_read_pio(ap, tf);
-}
-
-/**
- * ata_check_status_pio - Read device status reg & clear interrupt
- * @ap: port where the device is
- *
- * Reads ATA taskfile status register for currently-selected device
- * and return its value. This also clears pending interrupts
- * from this device
- *
- * LOCKING:
- * Inherited from caller.
- */
-static u8 ata_check_status_pio(struct ata_port *ap)
-{
- return inb(ap->ioaddr.status_addr);
-}
-
-/**
- * ata_check_status_mmio - Read device status reg & clear interrupt
- * @ap: port where the device is
- *
- * Reads ATA taskfile status register for currently-selected device
- * via MMIO and return its value. This also clears pending interrupts
- * from this device
- *
- * LOCKING:
- * Inherited from caller.
- */
-static u8 ata_check_status_mmio(struct ata_port *ap)
-{
- return readb((void __iomem *) ap->ioaddr.status_addr);
-}
-
-
-/**
- * ata_check_status - Read device status reg & clear interrupt
- * @ap: port where the device is
- *
- * Reads ATA taskfile status register for currently-selected device
- * and return its value. This also clears pending interrupts
- * from this device
- *
- * May be used as the check_status() entry in ata_port_operations.
- *
- * LOCKING:
- * Inherited from caller.
- */
-u8 ata_check_status(struct ata_port *ap)
-{
- if (ap->flags & ATA_FLAG_MMIO)
- return ata_check_status_mmio(ap);
- return ata_check_status_pio(ap);
-}
-
-
-/**
- * ata_altstatus - Read device alternate status reg
- * @ap: port where the device is
- *
- * Reads ATA taskfile alternate status register for
- * currently-selected device and return its value.
- *
- * Note: may NOT be used as the check_altstatus() entry in
- * ata_port_operations.
- *
- * LOCKING:
- * Inherited from caller.
- */
-u8 ata_altstatus(struct ata_port *ap)
-{
- if (ap->ops->check_altstatus)
- return ap->ops->check_altstatus(ap);
-
- if (ap->flags & ATA_FLAG_MMIO)
- return readb((void __iomem *)ap->ioaddr.altstatus_addr);
- return inb(ap->ioaddr.altstatus_addr);
-}
-
/**
* ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
@@ -632,58 +228,148 @@ int ata_rwcmd_protocol(struct ata_queued_cmd *qc)
return -1;
}
-static const char * const xfer_mode_str[] = {
- "UDMA/16",
- "UDMA/25",
- "UDMA/33",
- "UDMA/44",
- "UDMA/66",
- "UDMA/100",
- "UDMA/133",
- "UDMA7",
- "MWDMA0",
- "MWDMA1",
- "MWDMA2",
- "PIO0",
- "PIO1",
- "PIO2",
- "PIO3",
- "PIO4",
+/**
+ * ata_pack_xfermask - Pack pio, mwdma and udma masks into xfer_mask
+ * @pio_mask: pio_mask
+ * @mwdma_mask: mwdma_mask
+ * @udma_mask: udma_mask
+ *
+ * Pack @pio_mask, @mwdma_mask and @udma_mask into a single
+ * unsigned int xfer_mask.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * Packed xfer_mask.
+ */
+static unsigned int ata_pack_xfermask(unsigned int pio_mask,
+ unsigned int mwdma_mask,
+ unsigned int udma_mask)
+{
+ return ((pio_mask << ATA_SHIFT_PIO) & ATA_MASK_PIO) |
+ ((mwdma_mask << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA) |
+ ((udma_mask << ATA_SHIFT_UDMA) & ATA_MASK_UDMA);
+}
+
+static const struct ata_xfer_ent {
+ unsigned int shift, bits;
+ u8 base;
+} ata_xfer_tbl[] = {
+ { ATA_SHIFT_PIO, ATA_BITS_PIO, XFER_PIO_0 },
+ { ATA_SHIFT_MWDMA, ATA_BITS_MWDMA, XFER_MW_DMA_0 },
+ { ATA_SHIFT_UDMA, ATA_BITS_UDMA, XFER_UDMA_0 },
+ { -1, },
};
/**
- * ata_udma_string - convert UDMA bit offset to string
- * @mask: mask of bits supported; only highest bit counts.
+ * ata_xfer_mask2mode - Find matching XFER_* for the given xfer_mask
+ * @xfer_mask: xfer_mask of interest
*
- * Determine string which represents the highest speed
- * (highest bit in @udma_mask).
+ * Return matching XFER_* value for @xfer_mask. Only the highest
+ * bit of @xfer_mask is considered.
*
* LOCKING:
* None.
*
* RETURNS:
- * Constant C string representing highest speed listed in
- * @udma_mask, or the constant C string "<n/a>".
+ * Matching XFER_* value, 0 if no match found.
*/
+static u8 ata_xfer_mask2mode(unsigned int xfer_mask)
+{
+ int highbit = fls(xfer_mask) - 1;
+ const struct ata_xfer_ent *ent;
-static const char *ata_mode_string(unsigned int mask)
+ for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
+ if (highbit >= ent->shift && highbit < ent->shift + ent->bits)
+ return ent->base + highbit - ent->shift;
+ return 0;
+}
+
+/**
+ * ata_xfer_mode2mask - Find matching xfer_mask for XFER_*
+ * @xfer_mode: XFER_* of interest
+ *
+ * Return matching xfer_mask for @xfer_mode.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * Matching xfer_mask, 0 if no match found.
+ */
+static unsigned int ata_xfer_mode2mask(u8 xfer_mode)
{
- int i;
+ const struct ata_xfer_ent *ent;
- for (i = 7; i >= 0; i--)
- if (mask & (1 << i))
- goto out;
- for (i = ATA_SHIFT_MWDMA + 2; i >= ATA_SHIFT_MWDMA; i--)
- if (mask & (1 << i))
- goto out;
- for (i = ATA_SHIFT_PIO + 4; i >= ATA_SHIFT_PIO; i--)
- if (mask & (1 << i))
- goto out;
+ for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
+ if (xfer_mode >= ent->base && xfer_mode < ent->base + ent->bits)
+ return 1 << (ent->shift + xfer_mode - ent->base);
+ return 0;
+}
- return "<n/a>";
+/**
+ * ata_xfer_mode2shift - Find matching xfer_shift for XFER_*
+ * @xfer_mode: XFER_* of interest
+ *
+ * Return matching xfer_shift for @xfer_mode.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * Matching xfer_shift, -1 if no match found.
+ */
+static int ata_xfer_mode2shift(unsigned int xfer_mode)
+{
+ const struct ata_xfer_ent *ent;
-out:
- return xfer_mode_str[i];
+ for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
+ if (xfer_mode >= ent->base && xfer_mode < ent->base + ent->bits)
+ return ent->shift;
+ return -1;
+}
+
+/**
+ * ata_mode_string - convert xfer_mask to string
+ * @xfer_mask: mask of bits supported; only highest bit counts.
+ *
+ * Determine string which represents the highest speed
+ * (highest bit in @modemask).
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * Constant C string representing highest speed listed in
+ * @mode_mask, or the constant C string "<n/a>".
+ */
+static const char *ata_mode_string(unsigned int xfer_mask)
+{
+ static const char * const xfer_mode_str[] = {
+ "PIO0",
+ "PIO1",
+ "PIO2",
+ "PIO3",
+ "PIO4",
+ "MWDMA0",
+ "MWDMA1",
+ "MWDMA2",
+ "UDMA/16",
+ "UDMA/25",
+ "UDMA/33",
+ "UDMA/44",
+ "UDMA/66",
+ "UDMA/100",
+ "UDMA/133",
+ "UDMA7",
+ };
+ int highbit;
+
+ highbit = fls(xfer_mask) - 1;
+ if (highbit >= 0 && highbit < ARRAY_SIZE(xfer_mode_str))
+ return xfer_mode_str[highbit];
+ return "<n/a>";
}
/**
@@ -838,6 +524,7 @@ unsigned int ata_dev_classify(const struct ata_taskfile *tf)
* ata_dev_try_classify - Parse returned ATA device signature
* @ap: ATA channel to examine
* @device: Device to examine (starting at zero)
+ * @r_err: Value of error register on completion
*
* After an event -- SRST, E.D.D., or SATA COMRESET -- occurs,
* an ATA/ATAPI-defined set of values is placed in the ATA
@@ -850,11 +537,14 @@ unsigned int ata_dev_classify(const struct ata_taskfile *tf)
*
* LOCKING:
* caller.
+ *
+ * RETURNS:
+ * Device type - %ATA_DEV_ATA, %ATA_DEV_ATAPI or %ATA_DEV_NONE.
*/
-static u8 ata_dev_try_classify(struct ata_port *ap, unsigned int device)
+static unsigned int
+ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err)
{
- struct ata_device *dev = &ap->device[device];
struct ata_taskfile tf;
unsigned int class;
u8 err;
@@ -865,8 +555,8 @@ static u8 ata_dev_try_classify(struct ata_port *ap, unsigned int device)
ap->ops->tf_read(ap, &tf);
err = tf.feature;
-
- dev->class = ATA_DEV_NONE;
+ if (r_err)
+ *r_err = err;
/* see if device passed diags */
if (err == 1)
@@ -874,22 +564,20 @@ static u8 ata_dev_try_classify(struct ata_port *ap, unsigned int device)
else if ((device == 0) && (err == 0x81))
/* do nothing */ ;
else
- return err;
+ return ATA_DEV_NONE;
- /* determine if device if ATA or ATAPI */
+ /* determine if device is ATA or ATAPI */
class = ata_dev_classify(&tf);
+
if (class == ATA_DEV_UNKNOWN)
- return err;
+ return ATA_DEV_NONE;
if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0))
- return err;
-
- dev->class = class;
-
- return err;
+ return ATA_DEV_NONE;
+ return class;
}
/**
- * ata_dev_id_string - Convert IDENTIFY DEVICE page into string
+ * ata_id_string - Convert IDENTIFY DEVICE page into string
* @id: IDENTIFY DEVICE results we will examine
* @s: string into which data is output
* @ofs: offset into identify device page
@@ -903,8 +591,8 @@ static u8 ata_dev_try_classify(struct ata_port *ap, unsigned int device)
* caller.
*/
-void ata_dev_id_string(const u16 *id, unsigned char *s,
- unsigned int ofs, unsigned int len)
+void ata_id_string(const u16 *id, unsigned char *s,
+ unsigned int ofs, unsigned int len)
{
unsigned int c;
@@ -922,6 +610,49 @@ void ata_dev_id_string(const u16 *id, unsigned char *s,
}
}
+/**
+ * ata_id_c_string - Convert IDENTIFY DEVICE page into C string
+ * @id: IDENTIFY DEVICE results we will examine
+ * @s: string into which data is output
+ * @ofs: offset into identify device page
+ * @len: length of string to return. must be an odd number.
+ *
+ * This function is identical to ata_id_string except that it
+ * trims trailing spaces and terminates the resulting string with
+ * null. @len must be actual maximum length (even number) + 1.
+ *
+ * LOCKING:
+ * caller.
+ */
+void ata_id_c_string(const u16 *id, unsigned char *s,
+ unsigned int ofs, unsigned int len)
+{
+ unsigned char *p;
+
+ WARN_ON(!(len & 1));
+
+ ata_id_string(id, s, ofs, len - 1);
+
+ p = s + strnlen(s, len - 1);
+ while (p > s && p[-1] == ' ')
+ p--;
+ *p = '\0';
+}
+
+static u64 ata_id_n_sectors(const u16 *id)
+{
+ if (ata_id_has_lba(id)) {
+ if (ata_id_has_lba48(id))
+ return ata_id_u64(id, 100);
+ else
+ return ata_id_u32(id, 60);
+ } else {
+ if (ata_id_current_chs_valid(id))
+ return ata_id_u32(id, 57);
+ else
+ return id[1] * id[3] * id[6];
+ }
+}
/**
* ata_noop_dev_select - Select device 0/1 on ATA bus
@@ -1011,90 +742,172 @@ void ata_dev_select(struct ata_port *ap, unsigned int device,
/**
* ata_dump_id - IDENTIFY DEVICE info debugging output
- * @dev: Device whose IDENTIFY DEVICE page we will dump
+ * @id: IDENTIFY DEVICE page to dump
*
- * Dump selected 16-bit words from a detected device's
- * IDENTIFY PAGE page.
+ * Dump selected 16-bit words from the given IDENTIFY DEVICE
+ * page.
*
* LOCKING:
* caller.
*/
-static inline void ata_dump_id(const struct ata_device *dev)
+static inline void ata_dump_id(const u16 *id)
{
DPRINTK("49==0x%04x "
"53==0x%04x "
"63==0x%04x "
"64==0x%04x "
"75==0x%04x \n",
- dev->id[49],
- dev->id[53],
- dev->id[63],
- dev->id[64],
- dev->id[75]);
+ id[49],
+ id[53],
+ id[63],
+ id[64],
+ id[75]);
DPRINTK("80==0x%04x "
"81==0x%04x "
"82==0x%04x "
"83==0x%04x "
"84==0x%04x \n",
- dev->id[80],
- dev->id[81],
- dev->id[82],
- dev->id[83],
- dev->id[84]);
+ id[80],
+ id[81],
+ id[82],
+ id[83],
+ id[84]);
DPRINTK("88==0x%04x "
"93==0x%04x\n",
- dev->id[88],
- dev->id[93]);
+ id[88],
+ id[93]);
}
-/*
- * Compute the PIO modes available for this device. This is not as
- * trivial as it seems if we must consider early devices correctly.
+/**
+ * ata_id_xfermask - Compute xfermask from the given IDENTIFY data
+ * @id: IDENTIFY data to compute xfer mask from
+ *
+ * Compute the xfermask for this device. This is not as trivial
+ * as it seems if we must consider early devices correctly.
+ *
+ * FIXME: pre IDE drive timing (do we care ?).
+ *
+ * LOCKING:
+ * None.
*
- * FIXME: pre IDE drive timing (do we care ?).
+ * RETURNS:
+ * Computed xfermask
*/
-
-static unsigned int ata_pio_modes(const struct ata_device *adev)
+static unsigned int ata_id_xfermask(const u16 *id)
{
- u16 modes;
+ unsigned int pio_mask, mwdma_mask, udma_mask;
/* Usual case. Word 53 indicates word 64 is valid */
- if (adev->id[ATA_ID_FIELD_VALID] & (1 << 1)) {
- modes = adev->id[ATA_ID_PIO_MODES] & 0x03;
- modes <<= 3;
- modes |= 0x7;
- return modes;
+ if (id[ATA_ID_FIELD_VALID] & (1 << 1)) {
+ pio_mask = id[ATA_ID_PIO_MODES] & 0x03;
+ pio_mask <<= 3;
+ pio_mask |= 0x7;
+ } else {
+ /* If word 64 isn't valid then Word 51 high byte holds
+ * the PIO timing number for the maximum. Turn it into
+ * a mask.
+ */
+ pio_mask = (2 << (id[ATA_ID_OLD_PIO_MODES] & 0xFF)) - 1 ;
+
+ /* But wait.. there's more. Design your standards by
+ * committee and you too can get a free iordy field to
+ * process. However its the speeds not the modes that
+ * are supported... Note drivers using the timing API
+ * will get this right anyway
+ */
}
- /* If word 64 isn't valid then Word 51 high byte holds the PIO timing
- number for the maximum. Turn it into a mask and return it */
- modes = (2 << ((adev->id[ATA_ID_OLD_PIO_MODES] >> 8) & 0xFF)) - 1 ;
- return modes;
- /* But wait.. there's more. Design your standards by committee and
- you too can get a free iordy field to process. However its the
- speeds not the modes that are supported... Note drivers using the
- timing API will get this right anyway */
+ mwdma_mask = id[ATA_ID_MWDMA_MODES] & 0x07;
+
+ udma_mask = 0;
+ if (id[ATA_ID_FIELD_VALID] & (1 << 2))
+ udma_mask = id[ATA_ID_UDMA_MODES] & 0xff;
+
+ return ata_pack_xfermask(pio_mask, mwdma_mask, udma_mask);
}
-struct ata_exec_internal_arg {
- unsigned int err_mask;
- struct ata_taskfile *tf;
- struct completion *waiting;
-};
+/**
+ * ata_port_queue_task - Queue port_task
+ * @ap: The ata_port to queue port_task for
+ *
+ * Schedule @fn(@data) for execution after @delay jiffies using
+ * port_task. There is one port_task per port and it's the
+ * user(low level driver)'s responsibility to make sure that only
+ * one task is active at any given time.
+ *
+ * libata core layer takes care of synchronization between
+ * port_task and EH. ata_port_queue_task() may be ignored for EH
+ * synchronization.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data,
+ unsigned long delay)
+{
+ int rc;
+
+ if (ap->flags & ATA_FLAG_FLUSH_PORT_TASK)
+ return;
+
+ PREPARE_WORK(&ap->port_task, fn, data);
+
+ if (!delay)
+ rc = queue_work(ata_wq, &ap->port_task);
+ else
+ rc = queue_delayed_work(ata_wq, &ap->port_task, delay);
+
+ /* rc == 0 means that another user is using port task */
+ WARN_ON(rc == 0);
+}
-int ata_qc_complete_internal(struct ata_queued_cmd *qc)
+/**
+ * ata_port_flush_task - Flush port_task
+ * @ap: The ata_port to flush port_task for
+ *
+ * After this function completes, port_task is guranteed not to
+ * be running or scheduled.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ */
+void ata_port_flush_task(struct ata_port *ap)
{
- struct ata_exec_internal_arg *arg = qc->private_data;
- struct completion *waiting = arg->waiting;
+ unsigned long flags;
- if (!(qc->err_mask & ~AC_ERR_DEV))
- qc->ap->ops->tf_read(qc->ap, arg->tf);
- arg->err_mask = qc->err_mask;
- arg->waiting = NULL;
- complete(waiting);
+ DPRINTK("ENTER\n");
- return 0;
+ spin_lock_irqsave(&ap->host_set->lock, flags);
+ ap->flags |= ATA_FLAG_FLUSH_PORT_TASK;
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+ DPRINTK("flush #1\n");
+ flush_workqueue(ata_wq);
+
+ /*
+ * At this point, if a task is running, it's guaranteed to see
+ * the FLUSH flag; thus, it will never queue pio tasks again.
+ * Cancel and flush.
+ */
+ if (!cancel_delayed_work(&ap->port_task)) {
+ DPRINTK("flush #2\n");
+ flush_workqueue(ata_wq);
+ }
+
+ spin_lock_irqsave(&ap->host_set->lock, flags);
+ ap->flags &= ~ATA_FLAG_FLUSH_PORT_TASK;
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+ DPRINTK("EXIT\n");
+}
+
+void ata_qc_complete_internal(struct ata_queued_cmd *qc)
+{
+ struct completion *waiting = qc->private_data;
+
+ qc->ap->ops->tf_read(qc->ap, &qc->tf);
+ complete(waiting);
}
/**
@@ -1125,7 +938,7 @@ ata_exec_internal(struct ata_port *ap, struct ata_device *dev,
struct ata_queued_cmd *qc;
DECLARE_COMPLETION(wait);
unsigned long flags;
- struct ata_exec_internal_arg arg;
+ unsigned int err_mask;
spin_lock_irqsave(&ap->host_set->lock, flags);
@@ -1139,13 +952,12 @@ ata_exec_internal(struct ata_port *ap, struct ata_device *dev,
qc->nsect = buflen / ATA_SECT_SIZE;
}
- arg.waiting = &wait;
- arg.tf = tf;
- qc->private_data = &arg;
+ qc->private_data = &wait;
qc->complete_fn = ata_qc_complete_internal;
- if (ata_qc_issue(qc))
- goto issue_fail;
+ qc->err_mask = ata_qc_issue(qc);
+ if (qc->err_mask)
+ ata_qc_complete(qc);
spin_unlock_irqrestore(&ap->host_set->lock, flags);
@@ -1158,8 +970,8 @@ ata_exec_internal(struct ata_port *ap, struct ata_device *dev,
* before the caller cleans up, it will result in a
* spurious interrupt. We can live with that.
*/
- if (arg.waiting) {
- qc->err_mask = AC_ERR_OTHER;
+ if (qc->flags & ATA_QCFLAG_ACTIVE) {
+ qc->err_mask = AC_ERR_TIMEOUT;
ata_qc_complete(qc);
printk(KERN_WARNING "ata%u: qc timeout (cmd 0x%x)\n",
ap->id, command);
@@ -1168,12 +980,12 @@ ata_exec_internal(struct ata_port *ap, struct ata_device *dev,
spin_unlock_irqrestore(&ap->host_set->lock, flags);
}
- return arg.err_mask;
+ *tf = qc->tf;
+ err_mask = qc->err_mask;
- issue_fail:
ata_qc_free(qc);
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
- return AC_ERR_OTHER;
+
+ return err_mask;
}
/**
@@ -1210,73 +1022,78 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev)
}
/**
- * ata_dev_identify - obtain IDENTIFY x DEVICE page
- * @ap: port on which device we wish to probe resides
- * @device: device bus address, starting at zero
- *
- * Following bus reset, we issue the IDENTIFY [PACKET] DEVICE
- * command, and read back the 512-byte device information page.
- * The device information page is fed to us via the standard
- * PIO-IN protocol, but we hand-code it here. (TODO: investigate
- * using standard PIO-IN paths)
- *
- * After reading the device information page, we use several
- * bits of information from it to initialize data structures
- * that will be used during the lifetime of the ata_device.
- * Other data from the info page is used to disqualify certain
- * older ATA devices we do not wish to support.
+ * ata_dev_read_id - Read ID data from the specified device
+ * @ap: port on which target device resides
+ * @dev: target device
+ * @p_class: pointer to class of the target device (may be changed)
+ * @post_reset: is this read ID post-reset?
+ * @p_id: read IDENTIFY page (newly allocated)
+ *
+ * Read ID data from the specified device. ATA_CMD_ID_ATA is
+ * performed on ATA devices and ATA_CMD_ID_ATAPI on ATAPI
+ * devices. This function also takes care of EDD signature
+ * misreporting (to be removed once EDD support is gone) and
+ * issues ATA_CMD_INIT_DEV_PARAMS for pre-ATA4 drives.
*
* LOCKING:
- * Inherited from caller. Some functions called by this function
- * obtain the host_set lock.
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
*/
-
-static void ata_dev_identify(struct ata_port *ap, unsigned int device)
+static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev,
+ unsigned int *p_class, int post_reset, u16 **p_id)
{
- struct ata_device *dev = &ap->device[device];
- unsigned int major_version;
- u16 tmp;
- unsigned long xfer_modes;
+ unsigned int class = *p_class;
unsigned int using_edd;
struct ata_taskfile tf;
- unsigned int err_mask;
+ unsigned int err_mask = 0;
+ u16 *id;
+ const char *reason;
int rc;
- if (!ata_dev_present(dev)) {
- DPRINTK("ENTER/EXIT (host %u, dev %u) -- nodev\n",
- ap->id, device);
- return;
- }
+ DPRINTK("ENTER, host %u, dev %u\n", ap->id, dev->devno);
- if (ap->flags & (ATA_FLAG_SRST | ATA_FLAG_SATA_RESET))
+ if (ap->ops->probe_reset ||
+ ap->flags & (ATA_FLAG_SRST | ATA_FLAG_SATA_RESET))
using_edd = 0;
else
using_edd = 1;
- DPRINTK("ENTER, host %u, dev %u\n", ap->id, device);
-
- assert (dev->class == ATA_DEV_ATA || dev->class == ATA_DEV_ATAPI ||
- dev->class == ATA_DEV_NONE);
+ ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */
- ata_dev_select(ap, device, 1, 1); /* select device 0/1 */
+ id = kmalloc(sizeof(id[0]) * ATA_ID_WORDS, GFP_KERNEL);
+ if (id == NULL) {
+ rc = -ENOMEM;
+ reason = "out of memory";
+ goto err_out;
+ }
-retry:
- ata_tf_init(ap, &tf, device);
+ retry:
+ ata_tf_init(ap, &tf, dev->devno);
- if (dev->class == ATA_DEV_ATA) {
+ switch (class) {
+ case ATA_DEV_ATA:
tf.command = ATA_CMD_ID_ATA;
- DPRINTK("do ATA identify\n");
- } else {
+ break;
+ case ATA_DEV_ATAPI:
tf.command = ATA_CMD_ID_ATAPI;
- DPRINTK("do ATAPI identify\n");
+ break;
+ default:
+ rc = -ENODEV;
+ reason = "unsupported class";
+ goto err_out;
}
tf.protocol = ATA_PROT_PIO;
err_mask = ata_exec_internal(ap, dev, &tf, DMA_FROM_DEVICE,
- dev->id, sizeof(dev->id));
+ id, sizeof(id[0]) * ATA_ID_WORDS);
if (err_mask) {
+ rc = -EIO;
+ reason = "I/O error";
+
if (err_mask & ~AC_ERR_DEV)
goto err_out;
@@ -1291,180 +1108,223 @@ retry:
* ATA software reset (SRST, the default) does not appear
* to have this problem.
*/
- if ((using_edd) && (dev->class == ATA_DEV_ATA)) {
+ if ((using_edd) && (class == ATA_DEV_ATA)) {
u8 err = tf.feature;
if (err & ATA_ABORTED) {
- dev->class = ATA_DEV_ATAPI;
+ class = ATA_DEV_ATAPI;
goto retry;
}
}
goto err_out;
}
- swap_buf_le16(dev->id, ATA_ID_WORDS);
+ swap_buf_le16(id, ATA_ID_WORDS);
+
+ /* sanity check */
+ if ((class == ATA_DEV_ATA) != ata_id_is_ata(id)) {
+ rc = -EINVAL;
+ reason = "device reports illegal type";
+ goto err_out;
+ }
+
+ if (post_reset && class == ATA_DEV_ATA) {
+ /*
+ * The exact sequence expected by certain pre-ATA4 drives is:
+ * SRST RESET
+ * IDENTIFY
+ * INITIALIZE DEVICE PARAMETERS
+ * anything else..
+ * Some drives were very specific about that exact sequence.
+ */
+ if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) {
+ err_mask = ata_dev_init_params(ap, dev);
+ if (err_mask) {
+ rc = -EIO;
+ reason = "INIT_DEV_PARAMS failed";
+ goto err_out;
+ }
+
+ /* current CHS translation info (id[53-58]) might be
+ * changed. reread the identify device info.
+ */
+ post_reset = 0;
+ goto retry;
+ }
+ }
+
+ *p_class = class;
+ *p_id = id;
+ return 0;
+
+ err_out:
+ printk(KERN_WARNING "ata%u: dev %u failed to IDENTIFY (%s)\n",
+ ap->id, dev->devno, reason);
+ kfree(id);
+ return rc;
+}
+
+static inline u8 ata_dev_knobble(const struct ata_port *ap,
+ struct ata_device *dev)
+{
+ return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
+}
+
+/**
+ * ata_dev_configure - Configure the specified ATA/ATAPI device
+ * @ap: Port on which target device resides
+ * @dev: Target device to configure
+ * @print_info: Enable device info printout
+ *
+ * Configure @dev according to @dev->id. Generic and low-level
+ * driver specific fixups are also applied.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise
+ */
+static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev,
+ int print_info)
+{
+ const u16 *id = dev->id;
+ unsigned int xfer_mask;
+ int i, rc;
+
+ if (!ata_dev_present(dev)) {
+ DPRINTK("ENTER/EXIT (host %u, dev %u) -- nodev\n",
+ ap->id, dev->devno);
+ return 0;
+ }
+
+ DPRINTK("ENTER, host %u, dev %u\n", ap->id, dev->devno);
/* print device capabilities */
- printk(KERN_DEBUG "ata%u: dev %u cfg "
- "49:%04x 82:%04x 83:%04x 84:%04x 85:%04x 86:%04x 87:%04x 88:%04x\n",
- ap->id, device, dev->id[49],
- dev->id[82], dev->id[83], dev->id[84],
- dev->id[85], dev->id[86], dev->id[87],
- dev->id[88]);
+ if (print_info)
+ printk(KERN_DEBUG "ata%u: dev %u cfg 49:%04x 82:%04x 83:%04x "
+ "84:%04x 85:%04x 86:%04x 87:%04x 88:%04x\n",
+ ap->id, dev->devno, id[49], id[82], id[83],
+ id[84], id[85], id[86], id[87], id[88]);
+
+ /* initialize to-be-configured parameters */
+ dev->flags = 0;
+ dev->max_sectors = 0;
+ dev->cdb_len = 0;
+ dev->n_sectors = 0;
+ dev->cylinders = 0;
+ dev->heads = 0;
+ dev->sectors = 0;
/*
* common ATA, ATAPI feature tests
*/
/* we require DMA support (bits 8 of word 49) */
- if (!ata_id_has_dma(dev->id)) {
+ if (!ata_id_has_dma(id)) {
printk(KERN_DEBUG "ata%u: no dma\n", ap->id);
+ rc = -EINVAL;
goto err_out_nosup;
}
- /* quick-n-dirty find max transfer mode; for printk only */
- xfer_modes = dev->id[ATA_ID_UDMA_MODES];
- if (!xfer_modes)
- xfer_modes = (dev->id[ATA_ID_MWDMA_MODES]) << ATA_SHIFT_MWDMA;
- if (!xfer_modes)
- xfer_modes = ata_pio_modes(dev);
+ /* find max transfer mode; for printk only */
+ xfer_mask = ata_id_xfermask(id);
- ata_dump_id(dev);
+ ata_dump_id(id);
/* ATA-specific feature tests */
if (dev->class == ATA_DEV_ATA) {
- if (!ata_id_is_ata(dev->id)) /* sanity check */
- goto err_out_nosup;
+ dev->n_sectors = ata_id_n_sectors(id);
- /* get major version */
- tmp = dev->id[ATA_ID_MAJOR_VER];
- for (major_version = 14; major_version >= 1; major_version--)
- if (tmp & (1 << major_version))
- break;
+ if (ata_id_has_lba(id)) {
+ const char *lba_desc;
- /*
- * The exact sequence expected by certain pre-ATA4 drives is:
- * SRST RESET
- * IDENTIFY
- * INITIALIZE DEVICE PARAMETERS
- * anything else..
- * Some drives were very specific about that exact sequence.
- */
- if (major_version < 4 || (!ata_id_has_lba(dev->id))) {
- ata_dev_init_params(ap, dev);
-
- /* current CHS translation info (id[53-58]) might be
- * changed. reread the identify device info.
- */
- ata_dev_reread_id(ap, dev);
- }
-
- if (ata_id_has_lba(dev->id)) {
+ lba_desc = "LBA";
dev->flags |= ATA_DFLAG_LBA;
-
- if (ata_id_has_lba48(dev->id)) {
+ if (ata_id_has_lba48(id)) {
dev->flags |= ATA_DFLAG_LBA48;
- dev->n_sectors = ata_id_u64(dev->id, 100);
- } else {
- dev->n_sectors = ata_id_u32(dev->id, 60);
+ lba_desc = "LBA48";
}
/* print device info to dmesg */
- printk(KERN_INFO "ata%u: dev %u ATA-%d, max %s, %Lu sectors:%s\n",
- ap->id, device,
- major_version,
- ata_mode_string(xfer_modes),
- (unsigned long long)dev->n_sectors,
- dev->flags & ATA_DFLAG_LBA48 ? " LBA48" : " LBA");
- } else {
+ if (print_info)
+ printk(KERN_INFO "ata%u: dev %u ATA-%d, "
+ "max %s, %Lu sectors: %s\n",
+ ap->id, dev->devno,
+ ata_id_major_version(id),
+ ata_mode_string(xfer_mask),
+ (unsigned long long)dev->n_sectors,
+ lba_desc);
+ } else {
/* CHS */
/* Default translation */
- dev->cylinders = dev->id[1];
- dev->heads = dev->id[3];
- dev->sectors = dev->id[6];
- dev->n_sectors = dev->cylinders * dev->heads * dev->sectors;
+ dev->cylinders = id[1];
+ dev->heads = id[3];
+ dev->sectors = id[6];
- if (ata_id_current_chs_valid(dev->id)) {
+ if (ata_id_current_chs_valid(id)) {
/* Current CHS translation is valid. */
- dev->cylinders = dev->id[54];
- dev->heads = dev->id[55];
- dev->sectors = dev->id[56];
-
- dev->n_sectors = ata_id_u32(dev->id, 57);
+ dev->cylinders = id[54];
+ dev->heads = id[55];
+ dev->sectors = id[56];
}
/* print device info to dmesg */
- printk(KERN_INFO "ata%u: dev %u ATA-%d, max %s, %Lu sectors: CHS %d/%d/%d\n",
- ap->id, device,
- major_version,
- ata_mode_string(xfer_modes),
- (unsigned long long)dev->n_sectors,
- (int)dev->cylinders, (int)dev->heads, (int)dev->sectors);
-
+ if (print_info)
+ printk(KERN_INFO "ata%u: dev %u ATA-%d, "
+ "max %s, %Lu sectors: CHS %u/%u/%u\n",
+ ap->id, dev->devno,
+ ata_id_major_version(id),
+ ata_mode_string(xfer_mask),
+ (unsigned long long)dev->n_sectors,
+ dev->cylinders, dev->heads, dev->sectors);
}
- ap->host->max_cmd_len = 16;
+ dev->cdb_len = 16;
}
/* ATAPI-specific feature tests */
else if (dev->class == ATA_DEV_ATAPI) {
- if (ata_id_is_ata(dev->id)) /* sanity check */
- goto err_out_nosup;
-
- rc = atapi_cdb_len(dev->id);
+ rc = atapi_cdb_len(id);
if ((rc < 12) || (rc > ATAPI_CDB_LEN)) {
printk(KERN_WARNING "ata%u: unsupported CDB len\n", ap->id);
+ rc = -EINVAL;
goto err_out_nosup;
}
- ap->cdb_len = (unsigned int) rc;
- ap->host->max_cmd_len = (unsigned char) ap->cdb_len;
+ dev->cdb_len = (unsigned int) rc;
/* print device info to dmesg */
- printk(KERN_INFO "ata%u: dev %u ATAPI, max %s\n",
- ap->id, device,
- ata_mode_string(xfer_modes));
+ if (print_info)
+ printk(KERN_INFO "ata%u: dev %u ATAPI, max %s\n",
+ ap->id, dev->devno, ata_mode_string(xfer_mask));
}
- DPRINTK("EXIT, drv_stat = 0x%x\n", ata_chk_status(ap));
- return;
-
-err_out_nosup:
- printk(KERN_WARNING "ata%u: dev %u not supported, ignoring\n",
- ap->id, device);
-err_out:
- dev->class++; /* converts ATA_DEV_xxx into ATA_DEV_xxx_UNSUP */
- DPRINTK("EXIT, err\n");
-}
-
-
-static inline u8 ata_dev_knobble(const struct ata_port *ap)
-{
- return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(ap->device->id)));
-}
-
-/**
- * ata_dev_config - Run device specific handlers and check for
- * SATA->PATA bridges
- * @ap: Bus
- * @i: Device
- *
- * LOCKING:
- */
+ ap->host->max_cmd_len = 0;
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ ap->host->max_cmd_len = max_t(unsigned int,
+ ap->host->max_cmd_len,
+ ap->device[i].cdb_len);
-void ata_dev_config(struct ata_port *ap, unsigned int i)
-{
/* limit bridge transfers to udma5, 200 sectors */
- if (ata_dev_knobble(ap)) {
- printk(KERN_INFO "ata%u(%u): applying bridge limits\n",
- ap->id, ap->device->devno);
+ if (ata_dev_knobble(ap, dev)) {
+ if (print_info)
+ printk(KERN_INFO "ata%u(%u): applying bridge limits\n",
+ ap->id, dev->devno);
ap->udma_mask &= ATA_UDMA5;
- ap->host->max_sectors = ATA_MAX_SECTORS;
- ap->host->hostt->max_sectors = ATA_MAX_SECTORS;
- ap->device[i].flags |= ATA_DFLAG_LOCK_SECTORS;
+ dev->max_sectors = ATA_MAX_SECTORS;
}
if (ap->ops->dev_config)
- ap->ops->dev_config(ap, &ap->device[i]);
+ ap->ops->dev_config(ap, dev);
+
+ DPRINTK("EXIT, drv_stat = 0x%x\n", ata_chk_status(ap));
+ return 0;
+
+err_out_nosup:
+ printk(KERN_WARNING "ata%u: dev %u not supported, ignoring\n",
+ ap->id, dev->devno);
+ DPRINTK("EXIT, err\n");
+ return rc;
}
/**
@@ -1484,21 +1344,59 @@ void ata_dev_config(struct ata_port *ap, unsigned int i)
static int ata_bus_probe(struct ata_port *ap)
{
- unsigned int i, found = 0;
+ unsigned int classes[ATA_MAX_DEVICES];
+ unsigned int i, rc, found = 0;
- ap->ops->phy_reset(ap);
- if (ap->flags & ATA_FLAG_PORT_DISABLED)
- goto err_out;
+ ata_port_probe(ap);
+
+ /* reset and determine device classes */
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ classes[i] = ATA_DEV_UNKNOWN;
+
+ if (ap->ops->probe_reset) {
+ rc = ap->ops->probe_reset(ap, classes);
+ if (rc) {
+ printk("ata%u: reset failed (errno=%d)\n", ap->id, rc);
+ return rc;
+ }
+ } else {
+ ap->ops->phy_reset(ap);
+
+ if (!(ap->flags & ATA_FLAG_PORT_DISABLED))
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ classes[i] = ap->device[i].class;
+
+ ata_port_probe(ap);
+ }
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ if (classes[i] == ATA_DEV_UNKNOWN)
+ classes[i] = ATA_DEV_NONE;
+
+ /* read IDENTIFY page and configure devices */
for (i = 0; i < ATA_MAX_DEVICES; i++) {
- ata_dev_identify(ap, i);
- if (ata_dev_present(&ap->device[i])) {
- found = 1;
- ata_dev_config(ap,i);
+ struct ata_device *dev = &ap->device[i];
+
+ dev->class = classes[i];
+
+ if (!ata_dev_present(dev))
+ continue;
+
+ WARN_ON(dev->id != NULL);
+ if (ata_dev_read_id(ap, dev, &dev->class, 1, &dev->id)) {
+ dev->class = ATA_DEV_NONE;
+ continue;
+ }
+
+ if (ata_dev_configure(ap, dev, 1)) {
+ dev->class++; /* disable device */
+ continue;
}
+
+ found = 1;
}
- if ((!found) || (ap->flags & ATA_FLAG_PORT_DISABLED))
+ if (!found)
goto err_out_disable;
ata_set_mode(ap);
@@ -1509,7 +1407,6 @@ static int ata_bus_probe(struct ata_port *ap)
err_out_disable:
ap->ops->port_disable(ap);
-err_out:
return -1;
}
@@ -1530,6 +1427,41 @@ void ata_port_probe(struct ata_port *ap)
}
/**
+ * sata_print_link_status - Print SATA link status
+ * @ap: SATA port to printk link status about
+ *
+ * This function prints link speed and status of a SATA link.
+ *
+ * LOCKING:
+ * None.
+ */
+static void sata_print_link_status(struct ata_port *ap)
+{
+ u32 sstatus, tmp;
+ const char *speed;
+
+ if (!ap->ops->scr_read)
+ return;
+
+ sstatus = scr_read(ap, SCR_STATUS);
+
+ if (sata_dev_present(ap)) {
+ tmp = (sstatus >> 4) & 0xf;
+ if (tmp & (1 << 0))
+ speed = "1.5";
+ else if (tmp & (1 << 1))
+ speed = "3.0";
+ else
+ speed = "<unknown>";
+ printk(KERN_INFO "ata%u: SATA link up %s Gbps (SStatus %X)\n",
+ ap->id, speed, sstatus);
+ } else {
+ printk(KERN_INFO "ata%u: SATA link down (SStatus %X)\n",
+ ap->id, sstatus);
+ }
+}
+
+/**
* __sata_phy_reset - Wake/reset a low-level SATA PHY
* @ap: SATA port associated with target SATA PHY.
*
@@ -1563,27 +1495,14 @@ void __sata_phy_reset(struct ata_port *ap)
break;
} while (time_before(jiffies, timeout));
- /* TODO: phy layer with polling, timeouts, etc. */
- sstatus = scr_read(ap, SCR_STATUS);
- if (sata_dev_present(ap)) {
- const char *speed;
- u32 tmp;
+ /* print link status */
+ sata_print_link_status(ap);
- tmp = (sstatus >> 4) & 0xf;
- if (tmp & (1 << 0))
- speed = "1.5";
- else if (tmp & (1 << 1))
- speed = "3.0";
- else
- speed = "<unknown>";
- printk(KERN_INFO "ata%u: SATA link up %s Gbps (SStatus %X)\n",
- ap->id, speed, sstatus);
+ /* TODO: phy layer with polling, timeouts, etc. */
+ if (sata_dev_present(ap))
ata_port_probe(ap);
- } else {
- printk(KERN_INFO "ata%u: SATA link down (SStatus %X)\n",
- ap->id, sstatus);
+ else
ata_port_disable(ap);
- }
if (ap->flags & ATA_FLAG_PORT_DISABLED)
return;
@@ -1756,9 +1675,9 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed,
ata_timing_quantize(t, t, T, UT);
/*
- * Even in DMA/UDMA modes we still use PIO access for IDENTIFY, S.M.A.R.T
- * and some other commands. We have to ensure that the DMA cycle timing is
- * slower/equal than the fastest PIO timing.
+ * Even in DMA/UDMA modes we still use PIO access for IDENTIFY,
+ * S.M.A.R.T * and some other commands. We have to ensure that the
+ * DMA cycle timing is slower/equal than the fastest PIO timing.
*/
if (speed > XFER_PIO_4) {
@@ -1767,7 +1686,7 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed,
}
/*
- * Lenghten active & recovery time so that cycle time is correct.
+ * Lengthen active & recovery time so that cycle time is correct.
*/
if (t->act8b + t->rec8b < t->cyc8b) {
@@ -1783,31 +1702,8 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed,
return 0;
}
-static const struct {
- unsigned int shift;
- u8 base;
-} xfer_mode_classes[] = {
- { ATA_SHIFT_UDMA, XFER_UDMA_0 },
- { ATA_SHIFT_MWDMA, XFER_MW_DMA_0 },
- { ATA_SHIFT_PIO, XFER_PIO_0 },
-};
-
-static u8 base_from_shift(unsigned int shift)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(xfer_mode_classes); i++)
- if (xfer_mode_classes[i].shift == shift)
- return xfer_mode_classes[i].base;
-
- return 0xff;
-}
-
static void ata_dev_set_mode(struct ata_port *ap, struct ata_device *dev)
{
- int ofs, idx;
- u8 base;
-
if (!ata_dev_present(dev) || (ap->flags & ATA_FLAG_PORT_DISABLED))
return;
@@ -1816,65 +1712,58 @@ static void ata_dev_set_mode(struct ata_port *ap, struct ata_device *dev)
ata_dev_set_xfermode(ap, dev);
- base = base_from_shift(dev->xfer_shift);
- ofs = dev->xfer_mode - base;
- idx = ofs + dev->xfer_shift;
- WARN_ON(idx >= ARRAY_SIZE(xfer_mode_str));
+ if (ata_dev_revalidate(ap, dev, 0)) {
+ printk(KERN_ERR "ata%u: failed to revalidate after set "
+ "xfermode, disabled\n", ap->id);
+ ata_port_disable(ap);
+ }
- DPRINTK("idx=%d xfer_shift=%u, xfer_mode=0x%x, base=0x%x, offset=%d\n",
- idx, dev->xfer_shift, (int)dev->xfer_mode, (int)base, ofs);
+ DPRINTK("xfer_shift=%u, xfer_mode=0x%x\n",
+ dev->xfer_shift, (int)dev->xfer_mode);
printk(KERN_INFO "ata%u: dev %u configured for %s\n",
- ap->id, dev->devno, xfer_mode_str[idx]);
+ ap->id, dev->devno,
+ ata_mode_string(ata_xfer_mode2mask(dev->xfer_mode)));
}
static int ata_host_set_pio(struct ata_port *ap)
{
- unsigned int mask;
- int x, i;
- u8 base, xfer_mode;
-
- mask = ata_get_mode_mask(ap, ATA_SHIFT_PIO);
- x = fgb(mask);
- if (x < 0) {
- printk(KERN_WARNING "ata%u: no PIO support\n", ap->id);
- return -1;
- }
-
- base = base_from_shift(ATA_SHIFT_PIO);
- xfer_mode = base + x;
-
- DPRINTK("base 0x%x xfer_mode 0x%x mask 0x%x x %d\n",
- (int)base, (int)xfer_mode, mask, x);
+ int i;
for (i = 0; i < ATA_MAX_DEVICES; i++) {
struct ata_device *dev = &ap->device[i];
- if (ata_dev_present(dev)) {
- dev->pio_mode = xfer_mode;
- dev->xfer_mode = xfer_mode;
- dev->xfer_shift = ATA_SHIFT_PIO;
- if (ap->ops->set_piomode)
- ap->ops->set_piomode(ap, dev);
+
+ if (!ata_dev_present(dev))
+ continue;
+
+ if (!dev->pio_mode) {
+ printk(KERN_WARNING "ata%u: no PIO support\n", ap->id);
+ return -1;
}
+
+ dev->xfer_mode = dev->pio_mode;
+ dev->xfer_shift = ATA_SHIFT_PIO;
+ if (ap->ops->set_piomode)
+ ap->ops->set_piomode(ap, dev);
}
return 0;
}
-static void ata_host_set_dma(struct ata_port *ap, u8 xfer_mode,
- unsigned int xfer_shift)
+static void ata_host_set_dma(struct ata_port *ap)
{
int i;
for (i = 0; i < ATA_MAX_DEVICES; i++) {
struct ata_device *dev = &ap->device[i];
- if (ata_dev_present(dev)) {
- dev->dma_mode = xfer_mode;
- dev->xfer_mode = xfer_mode;
- dev->xfer_shift = xfer_shift;
- if (ap->ops->set_dmamode)
- ap->ops->set_dmamode(ap, dev);
- }
+
+ if (!ata_dev_present(dev) || !dev->dma_mode)
+ continue;
+
+ dev->xfer_mode = dev->dma_mode;
+ dev->xfer_shift = ata_xfer_mode2shift(dev->dma_mode);
+ if (ap->ops->set_dmamode)
+ ap->ops->set_dmamode(ap, dev);
}
}
@@ -1886,32 +1775,37 @@ static void ata_host_set_dma(struct ata_port *ap, u8 xfer_mode,
*
* LOCKING:
* PCI/etc. bus probe sem.
- *
*/
static void ata_set_mode(struct ata_port *ap)
{
- unsigned int xfer_shift;
- u8 xfer_mode;
- int rc;
+ int i, rc;
- /* step 1: always set host PIO timings */
- rc = ata_host_set_pio(ap);
- if (rc)
- goto err_out;
+ /* step 1: calculate xfer_mask */
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+ unsigned int xfer_mask;
- /* step 2: choose the best data xfer mode */
- xfer_mode = xfer_shift = 0;
- rc = ata_choose_xfer_mode(ap, &xfer_mode, &xfer_shift);
+ if (!ata_dev_present(dev))
+ continue;
+
+ xfer_mask = ata_dev_xfermask(ap, dev);
+
+ dev->pio_mode = ata_xfer_mask2mode(xfer_mask & ATA_MASK_PIO);
+ dev->dma_mode = ata_xfer_mask2mode(xfer_mask & (ATA_MASK_MWDMA |
+ ATA_MASK_UDMA));
+ }
+
+ /* step 2: always set host PIO timings */
+ rc = ata_host_set_pio(ap);
if (rc)
goto err_out;
- /* step 3: if that xfer mode isn't PIO, set host DMA timings */
- if (xfer_shift != ATA_SHIFT_PIO)
- ata_host_set_dma(ap, xfer_mode, xfer_shift);
+ /* step 3: set host DMA timings */
+ ata_host_set_dma(ap);
/* step 4: update devices' xfer mode */
- ata_dev_set_mode(ap, &ap->device[0]);
- ata_dev_set_mode(ap, &ap->device[1]);
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ ata_dev_set_mode(ap, &ap->device[i]);
if (ap->flags & ATA_FLAG_PORT_DISABLED)
return;
@@ -1926,6 +1820,26 @@ err_out:
}
/**
+ * ata_tf_to_host - issue ATA taskfile to host controller
+ * @ap: port to which command is being issued
+ * @tf: ATA taskfile register set
+ *
+ * Issues ATA taskfile register set to ATA host controller,
+ * with proper synchronization with interrupt handler and
+ * other threads.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host_set lock)
+ */
+
+static inline void ata_tf_to_host(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ ap->ops->tf_load(ap, tf);
+ ap->ops->exec_command(ap, tf);
+}
+
+/**
* ata_busy_sleep - sleep until BSY clears, or timeout
* @ap: port containing status register to be polled
* @tmout_pat: impatience timeout
@@ -1935,12 +1849,10 @@ err_out:
* or a timeout occurs.
*
* LOCKING: None.
- *
*/
-static unsigned int ata_busy_sleep (struct ata_port *ap,
- unsigned long tmout_pat,
- unsigned long tmout)
+unsigned int ata_busy_sleep (struct ata_port *ap,
+ unsigned long tmout_pat, unsigned long tmout)
{
unsigned long timer_start, timeout;
u8 status;
@@ -2159,9 +2071,9 @@ void ata_bus_reset(struct ata_port *ap)
/*
* determine by signature whether we have ATA or ATAPI devices
*/
- err = ata_dev_try_classify(ap, 0);
+ ap->device[0].class = ata_dev_try_classify(ap, 0, &err);
if ((slave_possible) && (err != 0x81))
- ata_dev_try_classify(ap, 1);
+ ap->device[1].class = ata_dev_try_classify(ap, 1, &err);
/* re-enable interrupts */
if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */
@@ -2196,11 +2108,446 @@ err_out:
DPRINTK("EXIT\n");
}
-static void ata_pr_blacklisted(const struct ata_port *ap,
- const struct ata_device *dev)
+static int sata_phy_resume(struct ata_port *ap)
{
- printk(KERN_WARNING "ata%u: dev %u is on DMA blacklist, disabling DMA\n",
- ap->id, dev->devno);
+ unsigned long timeout = jiffies + (HZ * 5);
+ u32 sstatus;
+
+ scr_write_flush(ap, SCR_CONTROL, 0x300);
+
+ /* Wait for phy to become ready, if necessary. */
+ do {
+ msleep(200);
+ sstatus = scr_read(ap, SCR_STATUS);
+ if ((sstatus & 0xf) != 1)
+ return 0;
+ } while (time_before(jiffies, timeout));
+
+ return -1;
+}
+
+/**
+ * ata_std_probeinit - initialize probing
+ * @ap: port to be probed
+ *
+ * @ap is about to be probed. Initialize it. This function is
+ * to be used as standard callback for ata_drive_probe_reset().
+ *
+ * NOTE!!! Do not use this function as probeinit if a low level
+ * driver implements only hardreset. Just pass NULL as probeinit
+ * in that case. Using this function is probably okay but doing
+ * so makes reset sequence different from the original
+ * ->phy_reset implementation and Jeff nervous. :-P
+ */
+extern void ata_std_probeinit(struct ata_port *ap)
+{
+ if (ap->flags & ATA_FLAG_SATA && ap->ops->scr_read) {
+ sata_phy_resume(ap);
+ if (sata_dev_present(ap))
+ ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+ }
+}
+
+/**
+ * ata_std_softreset - reset host port via ATA SRST
+ * @ap: port to reset
+ * @verbose: fail verbosely
+ * @classes: resulting classes of attached devices
+ *
+ * Reset host port using ATA SRST. This function is to be used
+ * as standard callback for ata_drive_*_reset() functions.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ata_std_softreset(struct ata_port *ap, int verbose, unsigned int *classes)
+{
+ unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
+ unsigned int devmask = 0, err_mask;
+ u8 err;
+
+ DPRINTK("ENTER\n");
+
+ if (ap->ops->scr_read && !sata_dev_present(ap)) {
+ classes[0] = ATA_DEV_NONE;
+ goto out;
+ }
+
+ /* determine if device 0/1 are present */
+ if (ata_devchk(ap, 0))
+ devmask |= (1 << 0);
+ if (slave_possible && ata_devchk(ap, 1))
+ devmask |= (1 << 1);
+
+ /* select device 0 again */
+ ap->ops->dev_select(ap, 0);
+
+ /* issue bus reset */
+ DPRINTK("about to softreset, devmask=%x\n", devmask);
+ err_mask = ata_bus_softreset(ap, devmask);
+ if (err_mask) {
+ if (verbose)
+ printk(KERN_ERR "ata%u: SRST failed (err_mask=0x%x)\n",
+ ap->id, err_mask);
+ else
+ DPRINTK("EXIT, softreset failed (err_mask=0x%x)\n",
+ err_mask);
+ return -EIO;
+ }
+
+ /* determine by signature whether we have ATA or ATAPI devices */
+ classes[0] = ata_dev_try_classify(ap, 0, &err);
+ if (slave_possible && err != 0x81)
+ classes[1] = ata_dev_try_classify(ap, 1, &err);
+
+ out:
+ DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
+ return 0;
+}
+
+/**
+ * sata_std_hardreset - reset host port via SATA phy reset
+ * @ap: port to reset
+ * @verbose: fail verbosely
+ * @class: resulting class of attached device
+ *
+ * SATA phy-reset host port using DET bits of SControl register.
+ * This function is to be used as standard callback for
+ * ata_drive_*_reset().
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int sata_std_hardreset(struct ata_port *ap, int verbose, unsigned int *class)
+{
+ DPRINTK("ENTER\n");
+
+ /* Issue phy wake/reset */
+ scr_write_flush(ap, SCR_CONTROL, 0x301);
+
+ /*
+ * Couldn't find anything in SATA I/II specs, but AHCI-1.1
+ * 10.4.2 says at least 1 ms.
+ */
+ msleep(1);
+
+ /* Bring phy back */
+ sata_phy_resume(ap);
+
+ /* TODO: phy layer with polling, timeouts, etc. */
+ if (!sata_dev_present(ap)) {
+ *class = ATA_DEV_NONE;
+ DPRINTK("EXIT, link offline\n");
+ return 0;
+ }
+
+ if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
+ if (verbose)
+ printk(KERN_ERR "ata%u: COMRESET failed "
+ "(device not ready)\n", ap->id);
+ else
+ DPRINTK("EXIT, device not ready\n");
+ return -EIO;
+ }
+
+ ap->ops->dev_select(ap, 0); /* probably unnecessary */
+
+ *class = ata_dev_try_classify(ap, 0, NULL);
+
+ DPRINTK("EXIT, class=%u\n", *class);
+ return 0;
+}
+
+/**
+ * ata_std_postreset - standard postreset callback
+ * @ap: the target ata_port
+ * @classes: classes of attached devices
+ *
+ * This function is invoked after a successful reset. Note that
+ * the device might have been reset more than once using
+ * different reset methods before postreset is invoked.
+ *
+ * This function is to be used as standard callback for
+ * ata_drive_*_reset().
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ */
+void ata_std_postreset(struct ata_port *ap, unsigned int *classes)
+{
+ DPRINTK("ENTER\n");
+
+ /* set cable type if it isn't already set */
+ if (ap->cbl == ATA_CBL_NONE && ap->flags & ATA_FLAG_SATA)
+ ap->cbl = ATA_CBL_SATA;
+
+ /* print link status */
+ if (ap->cbl == ATA_CBL_SATA)
+ sata_print_link_status(ap);
+
+ /* re-enable interrupts */
+ if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */
+ ata_irq_on(ap);
+
+ /* is double-select really necessary? */
+ if (classes[0] != ATA_DEV_NONE)
+ ap->ops->dev_select(ap, 1);
+ if (classes[1] != ATA_DEV_NONE)
+ ap->ops->dev_select(ap, 0);
+
+ /* bail out if no device is present */
+ if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
+ DPRINTK("EXIT, no device\n");
+ return;
+ }
+
+ /* set up device control */
+ if (ap->ioaddr.ctl_addr) {
+ if (ap->flags & ATA_FLAG_MMIO)
+ writeb(ap->ctl, (void __iomem *) ap->ioaddr.ctl_addr);
+ else
+ outb(ap->ctl, ap->ioaddr.ctl_addr);
+ }
+
+ DPRINTK("EXIT\n");
+}
+
+/**
+ * ata_std_probe_reset - standard probe reset method
+ * @ap: prot to perform probe-reset
+ * @classes: resulting classes of attached devices
+ *
+ * The stock off-the-shelf ->probe_reset method.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ata_std_probe_reset(struct ata_port *ap, unsigned int *classes)
+{
+ ata_reset_fn_t hardreset;
+
+ hardreset = NULL;
+ if (ap->flags & ATA_FLAG_SATA && ap->ops->scr_read)
+ hardreset = sata_std_hardreset;
+
+ return ata_drive_probe_reset(ap, ata_std_probeinit,
+ ata_std_softreset, hardreset,
+ ata_std_postreset, classes);
+}
+
+static int do_probe_reset(struct ata_port *ap, ata_reset_fn_t reset,
+ ata_postreset_fn_t postreset,
+ unsigned int *classes)
+{
+ int i, rc;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ classes[i] = ATA_DEV_UNKNOWN;
+
+ rc = reset(ap, 0, classes);
+ if (rc)
+ return rc;
+
+ /* If any class isn't ATA_DEV_UNKNOWN, consider classification
+ * is complete and convert all ATA_DEV_UNKNOWN to
+ * ATA_DEV_NONE.
+ */
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ if (classes[i] != ATA_DEV_UNKNOWN)
+ break;
+
+ if (i < ATA_MAX_DEVICES)
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ if (classes[i] == ATA_DEV_UNKNOWN)
+ classes[i] = ATA_DEV_NONE;
+
+ if (postreset)
+ postreset(ap, classes);
+
+ return classes[0] != ATA_DEV_UNKNOWN ? 0 : -ENODEV;
+}
+
+/**
+ * ata_drive_probe_reset - Perform probe reset with given methods
+ * @ap: port to reset
+ * @probeinit: probeinit method (can be NULL)
+ * @softreset: softreset method (can be NULL)
+ * @hardreset: hardreset method (can be NULL)
+ * @postreset: postreset method (can be NULL)
+ * @classes: resulting classes of attached devices
+ *
+ * Reset the specified port and classify attached devices using
+ * given methods. This function prefers softreset but tries all
+ * possible reset sequences to reset and classify devices. This
+ * function is intended to be used for constructing ->probe_reset
+ * callback by low level drivers.
+ *
+ * Reset methods should follow the following rules.
+ *
+ * - Return 0 on sucess, -errno on failure.
+ * - If classification is supported, fill classes[] with
+ * recognized class codes.
+ * - If classification is not supported, leave classes[] alone.
+ * - If verbose is non-zero, print error message on failure;
+ * otherwise, shut up.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -EINVAL if no reset method is avaliable, -ENODEV
+ * if classification fails, and any error code from reset
+ * methods.
+ */
+int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit,
+ ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+ ata_postreset_fn_t postreset, unsigned int *classes)
+{
+ int rc = -EINVAL;
+
+ if (probeinit)
+ probeinit(ap);
+
+ if (softreset) {
+ rc = do_probe_reset(ap, softreset, postreset, classes);
+ if (rc == 0)
+ return 0;
+ }
+
+ if (!hardreset)
+ return rc;
+
+ rc = do_probe_reset(ap, hardreset, postreset, classes);
+ if (rc == 0 || rc != -ENODEV)
+ return rc;
+
+ if (softreset)
+ rc = do_probe_reset(ap, softreset, postreset, classes);
+
+ return rc;
+}
+
+/**
+ * ata_dev_same_device - Determine whether new ID matches configured device
+ * @ap: port on which the device to compare against resides
+ * @dev: device to compare against
+ * @new_class: class of the new device
+ * @new_id: IDENTIFY page of the new device
+ *
+ * Compare @new_class and @new_id against @dev and determine
+ * whether @dev is the device indicated by @new_class and
+ * @new_id.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * 1 if @dev matches @new_class and @new_id, 0 otherwise.
+ */
+static int ata_dev_same_device(struct ata_port *ap, struct ata_device *dev,
+ unsigned int new_class, const u16 *new_id)
+{
+ const u16 *old_id = dev->id;
+ unsigned char model[2][41], serial[2][21];
+ u64 new_n_sectors;
+
+ if (dev->class != new_class) {
+ printk(KERN_INFO
+ "ata%u: dev %u class mismatch %d != %d\n",
+ ap->id, dev->devno, dev->class, new_class);
+ return 0;
+ }
+
+ ata_id_c_string(old_id, model[0], ATA_ID_PROD_OFS, sizeof(model[0]));
+ ata_id_c_string(new_id, model[1], ATA_ID_PROD_OFS, sizeof(model[1]));
+ ata_id_c_string(old_id, serial[0], ATA_ID_SERNO_OFS, sizeof(serial[0]));
+ ata_id_c_string(new_id, serial[1], ATA_ID_SERNO_OFS, sizeof(serial[1]));
+ new_n_sectors = ata_id_n_sectors(new_id);
+
+ if (strcmp(model[0], model[1])) {
+ printk(KERN_INFO
+ "ata%u: dev %u model number mismatch '%s' != '%s'\n",
+ ap->id, dev->devno, model[0], model[1]);
+ return 0;
+ }
+
+ if (strcmp(serial[0], serial[1])) {
+ printk(KERN_INFO
+ "ata%u: dev %u serial number mismatch '%s' != '%s'\n",
+ ap->id, dev->devno, serial[0], serial[1]);
+ return 0;
+ }
+
+ if (dev->class == ATA_DEV_ATA && dev->n_sectors != new_n_sectors) {
+ printk(KERN_INFO
+ "ata%u: dev %u n_sectors mismatch %llu != %llu\n",
+ ap->id, dev->devno, (unsigned long long)dev->n_sectors,
+ (unsigned long long)new_n_sectors);
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * ata_dev_revalidate - Revalidate ATA device
+ * @ap: port on which the device to revalidate resides
+ * @dev: device to revalidate
+ * @post_reset: is this revalidation after reset?
+ *
+ * Re-read IDENTIFY page and make sure @dev is still attached to
+ * the port.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, negative errno otherwise
+ */
+int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev,
+ int post_reset)
+{
+ unsigned int class;
+ u16 *id;
+ int rc;
+
+ if (!ata_dev_present(dev))
+ return -ENODEV;
+
+ class = dev->class;
+ id = NULL;
+
+ /* allocate & read ID data */
+ rc = ata_dev_read_id(ap, dev, &class, post_reset, &id);
+ if (rc)
+ goto fail;
+
+ /* is the device still there? */
+ if (!ata_dev_same_device(ap, dev, class, id)) {
+ rc = -ENODEV;
+ goto fail;
+ }
+
+ kfree(dev->id);
+ dev->id = id;
+
+ /* configure device according to the new ID */
+ return ata_dev_configure(ap, dev, 0);
+
+ fail:
+ printk(KERN_ERR "ata%u: dev %u revalidation failed (errno=%d)\n",
+ ap->id, dev->devno, rc);
+ kfree(id);
+ return rc;
}
static const char * const ata_dma_blacklist [] = {
@@ -2237,151 +2584,57 @@ static const char * const ata_dma_blacklist [] = {
static int ata_dma_blacklisted(const struct ata_device *dev)
{
- unsigned char model_num[40];
- char *s;
- unsigned int len;
+ unsigned char model_num[41];
int i;
- ata_dev_id_string(dev->id, model_num, ATA_ID_PROD_OFS,
- sizeof(model_num));
- s = &model_num[0];
- len = strnlen(s, sizeof(model_num));
-
- /* ATAPI specifies that empty space is blank-filled; remove blanks */
- while ((len > 0) && (s[len - 1] == ' ')) {
- len--;
- s[len] = 0;
- }
+ ata_id_c_string(dev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
for (i = 0; i < ARRAY_SIZE(ata_dma_blacklist); i++)
- if (!strncmp(ata_dma_blacklist[i], s, len))
+ if (!strcmp(ata_dma_blacklist[i], model_num))
return 1;
return 0;
}
-static unsigned int ata_get_mode_mask(const struct ata_port *ap, int shift)
-{
- const struct ata_device *master, *slave;
- unsigned int mask;
-
- master = &ap->device[0];
- slave = &ap->device[1];
-
- assert (ata_dev_present(master) || ata_dev_present(slave));
-
- if (shift == ATA_SHIFT_UDMA) {
- mask = ap->udma_mask;
- if (ata_dev_present(master)) {
- mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff);
- if (ata_dma_blacklisted(master)) {
- mask = 0;
- ata_pr_blacklisted(ap, master);
- }
- }
- if (ata_dev_present(slave)) {
- mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff);
- if (ata_dma_blacklisted(slave)) {
- mask = 0;
- ata_pr_blacklisted(ap, slave);
- }
- }
- }
- else if (shift == ATA_SHIFT_MWDMA) {
- mask = ap->mwdma_mask;
- if (ata_dev_present(master)) {
- mask &= (master->id[ATA_ID_MWDMA_MODES] & 0x07);
- if (ata_dma_blacklisted(master)) {
- mask = 0;
- ata_pr_blacklisted(ap, master);
- }
- }
- if (ata_dev_present(slave)) {
- mask &= (slave->id[ATA_ID_MWDMA_MODES] & 0x07);
- if (ata_dma_blacklisted(slave)) {
- mask = 0;
- ata_pr_blacklisted(ap, slave);
- }
- }
- }
- else if (shift == ATA_SHIFT_PIO) {
- mask = ap->pio_mask;
- if (ata_dev_present(master)) {
- /* spec doesn't return explicit support for
- * PIO0-2, so we fake it
- */
- u16 tmp_mode = master->id[ATA_ID_PIO_MODES] & 0x03;
- tmp_mode <<= 3;
- tmp_mode |= 0x7;
- mask &= tmp_mode;
- }
- if (ata_dev_present(slave)) {
- /* spec doesn't return explicit support for
- * PIO0-2, so we fake it
- */
- u16 tmp_mode = slave->id[ATA_ID_PIO_MODES] & 0x03;
- tmp_mode <<= 3;
- tmp_mode |= 0x7;
- mask &= tmp_mode;
- }
- }
- else {
- mask = 0xffffffff; /* shut up compiler warning */
- BUG();
- }
-
- return mask;
-}
-
-/* find greatest bit */
-static int fgb(u32 bitmap)
-{
- unsigned int i;
- int x = -1;
-
- for (i = 0; i < 32; i++)
- if (bitmap & (1 << i))
- x = i;
-
- return x;
-}
-
/**
- * ata_choose_xfer_mode - attempt to find best transfer mode
- * @ap: Port for which an xfer mode will be selected
- * @xfer_mode_out: (output) SET FEATURES - XFER MODE code
- * @xfer_shift_out: (output) bit shift that selects this mode
+ * ata_dev_xfermask - Compute supported xfermask of the given device
+ * @ap: Port on which the device to compute xfermask for resides
+ * @dev: Device to compute xfermask for
*
- * Based on host and device capabilities, determine the
- * maximum transfer mode that is amenable to all.
+ * Compute supported xfermask of @dev. This function is
+ * responsible for applying all known limits including host
+ * controller limits, device blacklist, etc...
*
* LOCKING:
- * PCI/etc. bus probe sem.
+ * None.
*
* RETURNS:
- * Zero on success, negative on error.
+ * Computed xfermask.
*/
-
-static int ata_choose_xfer_mode(const struct ata_port *ap,
- u8 *xfer_mode_out,
- unsigned int *xfer_shift_out)
+static unsigned int ata_dev_xfermask(struct ata_port *ap,
+ struct ata_device *dev)
{
- unsigned int mask, shift;
- int x, i;
+ unsigned long xfer_mask;
+ int i;
- for (i = 0; i < ARRAY_SIZE(xfer_mode_classes); i++) {
- shift = xfer_mode_classes[i].shift;
- mask = ata_get_mode_mask(ap, shift);
+ xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask,
+ ap->udma_mask);
- x = fgb(mask);
- if (x >= 0) {
- *xfer_mode_out = xfer_mode_classes[i].base + x;
- *xfer_shift_out = shift;
- return 0;
- }
+ /* use port-wide xfermask for now */
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *d = &ap->device[i];
+ if (!ata_dev_present(d))
+ continue;
+ xfer_mask &= ata_id_xfermask(d->id);
+ if (ata_dma_blacklisted(d))
+ xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
}
- return -1;
+ if (ata_dma_blacklisted(dev))
+ printk(KERN_WARNING "ata%u: dev %u is on DMA blacklist, "
+ "disabling DMA\n", ap->id, dev->devno);
+
+ return xfer_mask;
}
/**
@@ -2420,63 +2673,28 @@ static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev)
}
/**
- * ata_dev_reread_id - Reread the device identify device info
- * @ap: port where the device is
- * @dev: device to reread the identify device info
- *
- * LOCKING:
- */
-
-static void ata_dev_reread_id(struct ata_port *ap, struct ata_device *dev)
-{
- struct ata_taskfile tf;
-
- ata_tf_init(ap, &tf, dev->devno);
-
- if (dev->class == ATA_DEV_ATA) {
- tf.command = ATA_CMD_ID_ATA;
- DPRINTK("do ATA identify\n");
- } else {
- tf.command = ATA_CMD_ID_ATAPI;
- DPRINTK("do ATAPI identify\n");
- }
-
- tf.flags |= ATA_TFLAG_DEVICE;
- tf.protocol = ATA_PROT_PIO;
-
- if (ata_exec_internal(ap, dev, &tf, DMA_FROM_DEVICE,
- dev->id, sizeof(dev->id)))
- goto err_out;
-
- swap_buf_le16(dev->id, ATA_ID_WORDS);
-
- ata_dump_id(dev);
-
- DPRINTK("EXIT\n");
-
- return;
-err_out:
- printk(KERN_ERR "ata%u: failed to reread ID, disabled\n", ap->id);
- ata_port_disable(ap);
-}
-
-/**
* ata_dev_init_params - Issue INIT DEV PARAMS command
* @ap: Port associated with device @dev
* @dev: Device to which command will be sent
*
* LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, AC_ERR_* mask otherwise.
*/
-static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev)
+static unsigned int ata_dev_init_params(struct ata_port *ap,
+ struct ata_device *dev)
{
struct ata_taskfile tf;
+ unsigned int err_mask;
u16 sectors = dev->id[6];
u16 heads = dev->id[3];
/* Number of sectors per track 1-255. Number of heads 1-16 */
if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16)
- return;
+ return 0;
/* set up init dev params taskfile */
DPRINTK("init dev params \n");
@@ -2488,13 +2706,10 @@ static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev)
tf.nsect = sectors;
tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */
- if (ata_exec_internal(ap, dev, &tf, DMA_NONE, NULL, 0)) {
- printk(KERN_ERR "ata%u: failed to init parameters, disabled\n",
- ap->id);
- ata_port_disable(ap);
- }
+ err_mask = ata_exec_internal(ap, dev, &tf, DMA_NONE, NULL, 0);
- DPRINTK("EXIT\n");
+ DPRINTK("EXIT, err_mask=%x\n", err_mask);
+ return err_mask;
}
/**
@@ -2514,11 +2729,11 @@ static void ata_sg_clean(struct ata_queued_cmd *qc)
int dir = qc->dma_dir;
void *pad_buf = NULL;
- assert(qc->flags & ATA_QCFLAG_DMAMAP);
- assert(sg != NULL);
+ WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP));
+ WARN_ON(sg == NULL);
if (qc->flags & ATA_QCFLAG_SINGLE)
- assert(qc->n_elem <= 1);
+ WARN_ON(qc->n_elem > 1);
VPRINTK("unmapping %u sg elements\n", qc->n_elem);
@@ -2573,8 +2788,8 @@ static void ata_fill_sg(struct ata_queued_cmd *qc)
struct scatterlist *sg;
unsigned int idx;
- assert(qc->__sg != NULL);
- assert(qc->n_elem > 0 || qc->pad_len > 0);
+ WARN_ON(qc->__sg == NULL);
+ WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
idx = 0;
ata_for_each_sg(sg, qc) {
@@ -2727,7 +2942,7 @@ static int ata_sg_setup_one(struct ata_queued_cmd *qc)
void *pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
struct scatterlist *psg = &qc->pad_sgent;
- assert(qc->dev->class == ATA_DEV_ATAPI);
+ WARN_ON(qc->dev->class != ATA_DEV_ATAPI);
memset(pad_buf, 0, ATA_DMA_PAD_SZ);
@@ -2791,7 +3006,7 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
int n_elem, pre_n_elem, dir, trim_sg = 0;
VPRINTK("ENTER, ata%u\n", ap->id);
- assert(qc->flags & ATA_QCFLAG_SG);
+ WARN_ON(!(qc->flags & ATA_QCFLAG_SG));
/* we must lengthen transfers to end on a 32-bit boundary */
qc->pad_len = lsg->length & 3;
@@ -2800,7 +3015,7 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
struct scatterlist *psg = &qc->pad_sgent;
unsigned int offset;
- assert(qc->dev->class == ATA_DEV_ATAPI);
+ WARN_ON(qc->dev->class != ATA_DEV_ATAPI);
memset(pad_buf, 0, ATA_DMA_PAD_SZ);
@@ -2876,7 +3091,7 @@ void ata_poll_qc_complete(struct ata_queued_cmd *qc)
}
/**
- * ata_pio_poll -
+ * ata_pio_poll - poll using PIO, depending on current state
* @ap: the target ata_port
*
* LOCKING:
@@ -2894,7 +3109,7 @@ static unsigned long ata_pio_poll(struct ata_port *ap)
unsigned int reg_state = HSM_ST_UNKNOWN;
qc = ata_qc_from_tag(ap, ap->active_tag);
- assert(qc != NULL);
+ WARN_ON(qc == NULL);
switch (ap->hsm_task_state) {
case HSM_ST:
@@ -2915,7 +3130,7 @@ static unsigned long ata_pio_poll(struct ata_port *ap)
status = ata_chk_status(ap);
if (status & ATA_BUSY) {
if (time_after(jiffies, ap->pio_task_timeout)) {
- qc->err_mask |= AC_ERR_ATA_BUS;
+ qc->err_mask |= AC_ERR_TIMEOUT;
ap->hsm_task_state = HSM_ST_TMOUT;
return 0;
}
@@ -2962,7 +3177,7 @@ static int ata_pio_complete (struct ata_port *ap)
}
qc = ata_qc_from_tag(ap, ap->active_tag);
- assert(qc != NULL);
+ WARN_ON(qc == NULL);
drv_stat = ata_wait_idle(ap);
if (!ata_ok(drv_stat)) {
@@ -2973,7 +3188,7 @@ static int ata_pio_complete (struct ata_port *ap)
ap->hsm_task_state = HSM_ST_IDLE;
- assert(qc->err_mask == 0);
+ WARN_ON(qc->err_mask);
ata_poll_qc_complete(qc);
/* another command may start at this point */
@@ -2983,7 +3198,7 @@ static int ata_pio_complete (struct ata_port *ap)
/**
- * swap_buf_le16 - swap halves of 16-words in place
+ * swap_buf_le16 - swap halves of 16-bit words in place
* @buf: Buffer to swap
* @buf_words: Number of 16-bit words in buffer.
*
@@ -3293,7 +3508,7 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc)
err_out:
printk(KERN_INFO "ata%u: dev %u: ATAPI check failed\n",
ap->id, dev->devno);
- qc->err_mask |= AC_ERR_ATA_BUS;
+ qc->err_mask |= AC_ERR_HSM;
ap->hsm_task_state = HSM_ST_ERR;
}
@@ -3330,7 +3545,7 @@ static void ata_pio_block(struct ata_port *ap)
}
qc = ata_qc_from_tag(ap, ap->active_tag);
- assert(qc != NULL);
+ WARN_ON(qc == NULL);
/* check error */
if (status & (ATA_ERR | ATA_DF)) {
@@ -3351,7 +3566,7 @@ static void ata_pio_block(struct ata_port *ap)
} else {
/* handle BSY=0, DRQ=0 as error */
if ((status & ATA_DRQ) == 0) {
- qc->err_mask |= AC_ERR_ATA_BUS;
+ qc->err_mask |= AC_ERR_HSM;
ap->hsm_task_state = HSM_ST_ERR;
return;
}
@@ -3365,7 +3580,7 @@ static void ata_pio_error(struct ata_port *ap)
struct ata_queued_cmd *qc;
qc = ata_qc_from_tag(ap, ap->active_tag);
- assert(qc != NULL);
+ WARN_ON(qc == NULL);
if (qc->tf.command != ATA_CMD_PACKET)
printk(KERN_WARNING "ata%u: PIO error\n", ap->id);
@@ -3373,7 +3588,7 @@ static void ata_pio_error(struct ata_port *ap)
/* make sure qc->err_mask is available to
* know what's wrong and recover
*/
- assert(qc->err_mask);
+ WARN_ON(qc->err_mask == 0);
ap->hsm_task_state = HSM_ST_IDLE;
@@ -3414,12 +3629,84 @@ fsm_start:
}
if (timeout)
- queue_delayed_work(ata_wq, &ap->pio_task, timeout);
+ ata_port_queue_task(ap, ata_pio_task, ap, timeout);
else if (!qc_completed)
goto fsm_start;
}
/**
+ * atapi_packet_task - Write CDB bytes to hardware
+ * @_data: Port to which ATAPI device is attached.
+ *
+ * When device has indicated its readiness to accept
+ * a CDB, this function is called. Send the CDB.
+ * If DMA is to be performed, exit immediately.
+ * Otherwise, we are in polling mode, so poll
+ * status under operation succeeds or fails.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ */
+
+static void atapi_packet_task(void *_data)
+{
+ struct ata_port *ap = _data;
+ struct ata_queued_cmd *qc;
+ u8 status;
+
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ WARN_ON(qc == NULL);
+ WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
+
+ /* sleep-wait for BSY to clear */
+ DPRINTK("busy wait\n");
+ if (ata_busy_sleep(ap, ATA_TMOUT_CDB_QUICK, ATA_TMOUT_CDB)) {
+ qc->err_mask |= AC_ERR_TIMEOUT;
+ goto err_out;
+ }
+
+ /* make sure DRQ is set */
+ status = ata_chk_status(ap);
+ if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ) {
+ qc->err_mask |= AC_ERR_HSM;
+ goto err_out;
+ }
+
+ /* send SCSI cdb */
+ DPRINTK("send cdb\n");
+ WARN_ON(qc->dev->cdb_len < 12);
+
+ if (qc->tf.protocol == ATA_PROT_ATAPI_DMA ||
+ qc->tf.protocol == ATA_PROT_ATAPI_NODATA) {
+ unsigned long flags;
+
+ /* Once we're done issuing command and kicking bmdma,
+ * irq handler takes over. To not lose irq, we need
+ * to clear NOINTR flag before sending cdb, but
+ * interrupt handler shouldn't be invoked before we're
+ * finished. Hence, the following locking.
+ */
+ spin_lock_irqsave(&ap->host_set->lock, flags);
+ ap->flags &= ~ATA_FLAG_NOINTR;
+ ata_data_xfer(ap, qc->cdb, qc->dev->cdb_len, 1);
+ if (qc->tf.protocol == ATA_PROT_ATAPI_DMA)
+ ap->ops->bmdma_start(qc); /* initiate bmdma */
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ } else {
+ ata_data_xfer(ap, qc->cdb, qc->dev->cdb_len, 1);
+
+ /* PIO commands are handled by polling */
+ ap->hsm_task_state = HSM_ST;
+ ata_port_queue_task(ap, ata_pio_task, ap, 0);
+ }
+
+ return;
+
+err_out:
+ ata_poll_qc_complete(qc);
+}
+
+/**
* ata_qc_timeout - Handle timeout of queued command
* @qc: Command that timed out
*
@@ -3447,15 +3734,9 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc)
DPRINTK("ENTER\n");
- spin_lock_irqsave(&host_set->lock, flags);
+ ap->hsm_task_state = HSM_ST_IDLE;
- /* hack alert! We cannot use the supplied completion
- * function from inside the ->eh_strategy_handler() thread.
- * libata is the only user of ->eh_strategy_handler() in
- * any kernel, so the default scsi_done() assumes it is
- * not being called from the SCSI EH.
- */
- qc->scsidone = scsi_finish_command;
+ spin_lock_irqsave(&host_set->lock, flags);
switch (qc->tf.protocol) {
@@ -3480,12 +3761,13 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc)
/* complete taskfile transaction */
qc->err_mask |= ac_err_mask(drv_stat);
- ata_qc_complete(qc);
break;
}
spin_unlock_irqrestore(&host_set->lock, flags);
+ ata_eh_qc_complete(qc);
+
DPRINTK("EXIT\n");
}
@@ -3510,20 +3792,10 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc)
void ata_eng_timeout(struct ata_port *ap)
{
- struct ata_queued_cmd *qc;
-
DPRINTK("ENTER\n");
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc)
- ata_qc_timeout(qc);
- else {
- printk(KERN_ERR "ata%u: BUG: timeout without command\n",
- ap->id);
- goto out;
- }
+ ata_qc_timeout(ata_qc_from_tag(ap, ap->active_tag));
-out:
DPRINTK("EXIT\n");
}
@@ -3579,21 +3851,6 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
return qc;
}
-static void __ata_qc_complete(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- unsigned int tag;
-
- qc->flags = 0;
- tag = qc->tag;
- if (likely(ata_tag_valid(tag))) {
- if (tag == ap->active_tag)
- ap->active_tag = ATA_TAG_POISON;
- qc->tag = ATA_TAG_POISON;
- clear_bit(tag, &ap->qactive);
- }
-}
-
/**
* ata_qc_free - free unused ata_queued_cmd
* @qc: Command to complete
@@ -3606,29 +3863,25 @@ static void __ata_qc_complete(struct ata_queued_cmd *qc)
*/
void ata_qc_free(struct ata_queued_cmd *qc)
{
- assert(qc != NULL); /* ata_qc_from_tag _might_ return NULL */
+ struct ata_port *ap = qc->ap;
+ unsigned int tag;
- __ata_qc_complete(qc);
-}
+ WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
-/**
- * ata_qc_complete - Complete an active ATA command
- * @qc: Command to complete
- * @err_mask: ATA Status register contents
- *
- * Indicate to the mid and upper layers that an ATA
- * command has completed, with either an ok or not-ok status.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
+ qc->flags = 0;
+ tag = qc->tag;
+ if (likely(ata_tag_valid(tag))) {
+ if (tag == ap->active_tag)
+ ap->active_tag = ATA_TAG_POISON;
+ qc->tag = ATA_TAG_POISON;
+ clear_bit(tag, &ap->qactive);
+ }
+}
-void ata_qc_complete(struct ata_queued_cmd *qc)
+void __ata_qc_complete(struct ata_queued_cmd *qc)
{
- int rc;
-
- assert(qc != NULL); /* ata_qc_from_tag _might_ return NULL */
- assert(qc->flags & ATA_QCFLAG_ACTIVE);
+ WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
+ WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
if (likely(qc->flags & ATA_QCFLAG_DMAMAP))
ata_sg_clean(qc);
@@ -3640,17 +3893,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
qc->flags &= ~ATA_QCFLAG_ACTIVE;
/* call completion callback */
- rc = qc->complete_fn(qc);
-
- /* if callback indicates not to complete command (non-zero),
- * return immediately
- */
- if (rc != 0)
- return;
-
- __ata_qc_complete(qc);
-
- VPRINTK("EXIT\n");
+ qc->complete_fn(qc);
}
static inline int ata_should_dma_map(struct ata_queued_cmd *qc)
@@ -3690,20 +3933,20 @@ static inline int ata_should_dma_map(struct ata_queued_cmd *qc)
* spin_lock_irqsave(host_set lock)
*
* RETURNS:
- * Zero on success, negative on error.
+ * Zero on success, AC_ERR_* mask on failure
*/
-int ata_qc_issue(struct ata_queued_cmd *qc)
+unsigned int ata_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
if (ata_should_dma_map(qc)) {
if (qc->flags & ATA_QCFLAG_SG) {
if (ata_sg_setup(qc))
- goto err_out;
+ goto sg_err;
} else if (qc->flags & ATA_QCFLAG_SINGLE) {
if (ata_sg_setup_one(qc))
- goto err_out;
+ goto sg_err;
}
} else {
qc->flags &= ~ATA_QCFLAG_DMAMAP;
@@ -3716,8 +3959,9 @@ int ata_qc_issue(struct ata_queued_cmd *qc)
return ap->ops->qc_issue(qc);
-err_out:
- return -1;
+sg_err:
+ qc->flags &= ~ATA_QCFLAG_DMAMAP;
+ return AC_ERR_SYSTEM;
}
@@ -3736,10 +3980,10 @@ err_out:
* spin_lock_irqsave(host_set lock)
*
* RETURNS:
- * Zero on success, negative on error.
+ * Zero on success, AC_ERR_* mask on failure
*/
-int ata_qc_issue_prot(struct ata_queued_cmd *qc)
+unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
@@ -3760,31 +4004,31 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc)
ata_qc_set_polling(qc);
ata_tf_to_host(ap, &qc->tf);
ap->hsm_task_state = HSM_ST;
- queue_work(ata_wq, &ap->pio_task);
+ ata_port_queue_task(ap, ata_pio_task, ap, 0);
break;
case ATA_PROT_ATAPI:
ata_qc_set_polling(qc);
ata_tf_to_host(ap, &qc->tf);
- queue_work(ata_wq, &ap->packet_task);
+ ata_port_queue_task(ap, atapi_packet_task, ap, 0);
break;
case ATA_PROT_ATAPI_NODATA:
ap->flags |= ATA_FLAG_NOINTR;
ata_tf_to_host(ap, &qc->tf);
- queue_work(ata_wq, &ap->packet_task);
+ ata_port_queue_task(ap, atapi_packet_task, ap, 0);
break;
case ATA_PROT_ATAPI_DMA:
ap->flags |= ATA_FLAG_NOINTR;
ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
ap->ops->bmdma_setup(qc); /* set up bmdma */
- queue_work(ata_wq, &ap->packet_task);
+ ata_port_queue_task(ap, atapi_packet_task, ap, 0);
break;
default:
WARN_ON(1);
- return -1;
+ return AC_ERR_SYSTEM;
}
return 0;
@@ -4147,91 +4391,6 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
return IRQ_RETVAL(handled);
}
-/**
- * atapi_packet_task - Write CDB bytes to hardware
- * @_data: Port to which ATAPI device is attached.
- *
- * When device has indicated its readiness to accept
- * a CDB, this function is called. Send the CDB.
- * If DMA is to be performed, exit immediately.
- * Otherwise, we are in polling mode, so poll
- * status under operation succeeds or fails.
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- */
-
-static void atapi_packet_task(void *_data)
-{
- struct ata_port *ap = _data;
- struct ata_queued_cmd *qc;
- u8 status;
-
- qc = ata_qc_from_tag(ap, ap->active_tag);
- assert(qc != NULL);
- assert(qc->flags & ATA_QCFLAG_ACTIVE);
-
- /* sleep-wait for BSY to clear */
- DPRINTK("busy wait\n");
- if (ata_busy_sleep(ap, ATA_TMOUT_CDB_QUICK, ATA_TMOUT_CDB)) {
- qc->err_mask |= AC_ERR_ATA_BUS;
- goto err_out;
- }
-
- /* make sure DRQ is set */
- status = ata_chk_status(ap);
- if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ) {
- qc->err_mask |= AC_ERR_ATA_BUS;
- goto err_out;
- }
-
- /* send SCSI cdb */
- DPRINTK("send cdb\n");
- assert(ap->cdb_len >= 12);
-
- if (qc->tf.protocol == ATA_PROT_ATAPI_DMA ||
- qc->tf.protocol == ATA_PROT_ATAPI_NODATA) {
- unsigned long flags;
-
- /* Once we're done issuing command and kicking bmdma,
- * irq handler takes over. To not lose irq, we need
- * to clear NOINTR flag before sending cdb, but
- * interrupt handler shouldn't be invoked before we're
- * finished. Hence, the following locking.
- */
- spin_lock_irqsave(&ap->host_set->lock, flags);
- ap->flags &= ~ATA_FLAG_NOINTR;
- ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
- if (qc->tf.protocol == ATA_PROT_ATAPI_DMA)
- ap->ops->bmdma_start(qc); /* initiate bmdma */
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
- } else {
- ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
-
- /* PIO commands are handled by polling */
- ap->hsm_task_state = HSM_ST;
- queue_work(ata_wq, &ap->pio_task);
- }
-
- return;
-
-err_out:
- ata_poll_qc_complete(qc);
-}
-
-
-/**
- * ata_port_start - Set port up for dma.
- * @ap: Port to initialize
- *
- * Called just after data structures for each port are
- * initialized. Allocates space for PRD table.
- *
- * May be used as the port_start() entry in ata_port_operations.
- *
- * LOCKING:
- * Inherited from caller.
- */
/*
* Execute a 'simple' command, that only consists of the opcode 'cmd' itself,
@@ -4284,6 +4443,8 @@ static int ata_start_drive(struct ata_port *ap, struct ata_device *dev)
/**
* ata_device_resume - wakeup a previously suspended devices
+ * @ap: port the device is connected to
+ * @dev: the device to resume
*
* Kick the drive back into action, by sending it an idle immediate
* command and making sure its transfer mode matches between drive
@@ -4306,10 +4467,11 @@ int ata_device_resume(struct ata_port *ap, struct ata_device *dev)
/**
* ata_device_suspend - prepare a device for suspend
+ * @ap: port the device is connected to
+ * @dev: the device to suspend
*
* Flush the cache on the drive, if appropriate, then issue a
* standbynow command.
- *
*/
int ata_device_suspend(struct ata_port *ap, struct ata_device *dev)
{
@@ -4323,6 +4485,19 @@ int ata_device_suspend(struct ata_port *ap, struct ata_device *dev)
return 0;
}
+/**
+ * ata_port_start - Set port up for dma.
+ * @ap: Port to initialize
+ *
+ * Called just after data structures for each port are
+ * initialized. Allocates space for PRD table.
+ *
+ * May be used as the port_start() entry in ata_port_operations.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
int ata_port_start (struct ata_port *ap)
{
struct device *dev = ap->host_set->dev;
@@ -4436,8 +4611,8 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
ap->active_tag = ATA_TAG_POISON;
ap->last_ctl = 0xFF;
- INIT_WORK(&ap->packet_task, atapi_packet_task, ap);
- INIT_WORK(&ap->pio_task, ata_pio_task, ap);
+ INIT_WORK(&ap->port_task, NULL, NULL);
+ INIT_LIST_HEAD(&ap->eh_done_q);
for (i = 0; i < ATA_MAX_DEVICES; i++)
ap->device[i].devno = i;
@@ -4579,9 +4754,9 @@ int ata_device_add(const struct ata_probe_ent *ent)
ap = host_set->ports[i];
- DPRINTK("ata%u: probe begin\n", ap->id);
+ DPRINTK("ata%u: bus probe begin\n", ap->id);
rc = ata_bus_probe(ap);
- DPRINTK("ata%u: probe end\n", ap->id);
+ DPRINTK("ata%u: bus probe end\n", ap->id);
if (rc) {
/* FIXME: do something useful here?
@@ -4605,7 +4780,7 @@ int ata_device_add(const struct ata_probe_ent *ent)
}
/* probes are done, now scan each port's disk(s) */
- DPRINTK("probe begin\n");
+ DPRINTK("host probe begin\n");
for (i = 0; i < count; i++) {
struct ata_port *ap = host_set->ports[i];
@@ -4691,11 +4866,14 @@ void ata_host_set_remove(struct ata_host_set *host_set)
int ata_scsi_release(struct Scsi_Host *host)
{
struct ata_port *ap = (struct ata_port *) &host->hostdata[0];
+ int i;
DPRINTK("ENTER\n");
ap->ops->port_disable(ap);
ata_host_remove(ap, 0);
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ kfree(ap->device[i].id);
DPRINTK("EXIT\n");
return 1;
@@ -4727,32 +4905,6 @@ void ata_std_ports(struct ata_ioports *ioaddr)
ioaddr->command_addr = ioaddr->cmd_addr + ATA_REG_CMD;
}
-static struct ata_probe_ent *
-ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
-{
- struct ata_probe_ent *probe_ent;
-
- probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (!probe_ent) {
- printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
- kobject_name(&(dev->kobj)));
- return NULL;
- }
-
- INIT_LIST_HEAD(&probe_ent->node);
- probe_ent->dev = dev;
-
- probe_ent->sht = port->sht;
- probe_ent->host_flags = port->host_flags;
- probe_ent->pio_mask = port->pio_mask;
- probe_ent->mwdma_mask = port->mwdma_mask;
- probe_ent->udma_mask = port->udma_mask;
- probe_ent->port_ops = port->port_ops;
-
- return probe_ent;
-}
-
-
#ifdef CONFIG_PCI
@@ -4764,256 +4916,6 @@ void ata_pci_host_stop (struct ata_host_set *host_set)
}
/**
- * ata_pci_init_native_mode - Initialize native-mode driver
- * @pdev: pci device to be initialized
- * @port: array[2] of pointers to port info structures.
- * @ports: bitmap of ports present
- *
- * Utility function which allocates and initializes an
- * ata_probe_ent structure for a standard dual-port
- * PIO-based IDE controller. The returned ata_probe_ent
- * structure can be passed to ata_device_add(). The returned
- * ata_probe_ent structure should then be freed with kfree().
- *
- * The caller need only pass the address of the primary port, the
- * secondary will be deduced automatically. If the device has non
- * standard secondary port mappings this function can be called twice,
- * once for each interface.
- */
-
-struct ata_probe_ent *
-ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int ports)
-{
- struct ata_probe_ent *probe_ent =
- ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
- int p = 0;
-
- if (!probe_ent)
- return NULL;
-
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
- probe_ent->private_data = port[0]->private_data;
-
- if (ports & ATA_PORT_PRIMARY) {
- probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 0);
- probe_ent->port[p].altstatus_addr =
- probe_ent->port[p].ctl_addr =
- pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS;
- probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4);
- ata_std_ports(&probe_ent->port[p]);
- p++;
- }
-
- if (ports & ATA_PORT_SECONDARY) {
- probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 2);
- probe_ent->port[p].altstatus_addr =
- probe_ent->port[p].ctl_addr =
- pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS;
- probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4) + 8;
- ata_std_ports(&probe_ent->port[p]);
- p++;
- }
-
- probe_ent->n_ports = p;
- return probe_ent;
-}
-
-static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, struct ata_port_info *port, int port_num)
-{
- struct ata_probe_ent *probe_ent;
-
- probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port);
- if (!probe_ent)
- return NULL;
-
- probe_ent->legacy_mode = 1;
- probe_ent->n_ports = 1;
- probe_ent->hard_port_no = port_num;
- probe_ent->private_data = port->private_data;
-
- switch(port_num)
- {
- case 0:
- probe_ent->irq = 14;
- probe_ent->port[0].cmd_addr = 0x1f0;
- probe_ent->port[0].altstatus_addr =
- probe_ent->port[0].ctl_addr = 0x3f6;
- break;
- case 1:
- probe_ent->irq = 15;
- probe_ent->port[0].cmd_addr = 0x170;
- probe_ent->port[0].altstatus_addr =
- probe_ent->port[0].ctl_addr = 0x376;
- break;
- }
- probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4) + 8 * port_num;
- ata_std_ports(&probe_ent->port[0]);
- return probe_ent;
-}
-
-/**
- * ata_pci_init_one - Initialize/register PCI IDE host controller
- * @pdev: Controller to be initialized
- * @port_info: Information from low-level host driver
- * @n_ports: Number of ports attached to host controller
- *
- * This is a helper function which can be called from a driver's
- * xxx_init_one() probe function if the hardware uses traditional
- * IDE taskfile registers.
- *
- * This function calls pci_enable_device(), reserves its register
- * regions, sets the dma mask, enables bus master mode, and calls
- * ata_device_add()
- *
- * LOCKING:
- * Inherited from PCI layer (may sleep).
- *
- * RETURNS:
- * Zero on success, negative on errno-based value on error.
- */
-
-int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
- unsigned int n_ports)
-{
- struct ata_probe_ent *probe_ent = NULL, *probe_ent2 = NULL;
- struct ata_port_info *port[2];
- u8 tmp8, mask;
- unsigned int legacy_mode = 0;
- int disable_dev_on_err = 1;
- int rc;
-
- DPRINTK("ENTER\n");
-
- port[0] = port_info[0];
- if (n_ports > 1)
- port[1] = port_info[1];
- else
- port[1] = port[0];
-
- if ((port[0]->host_flags & ATA_FLAG_NO_LEGACY) == 0
- && (pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
- /* TODO: What if one channel is in native mode ... */
- pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
- mask = (1 << 2) | (1 << 0);
- if ((tmp8 & mask) != mask)
- legacy_mode = (1 << 3);
- }
-
- /* FIXME... */
- if ((!legacy_mode) && (n_ports > 2)) {
- printk(KERN_ERR "ata: BUG: native mode, n_ports > 2\n");
- n_ports = 2;
- /* For now */
- }
-
- /* FIXME: Really for ATA it isn't safe because the device may be
- multi-purpose and we want to leave it alone if it was already
- enabled. Secondly for shared use as Arjan says we want refcounting
-
- Checking dev->is_enabled is insufficient as this is not set at
- boot for the primary video which is BIOS enabled
- */
-
- rc = pci_enable_device(pdev);
- if (rc)
- return rc;
-
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- disable_dev_on_err = 0;
- goto err_out;
- }
-
- /* FIXME: Should use platform specific mappers for legacy port ranges */
- if (legacy_mode) {
- if (!request_region(0x1f0, 8, "libata")) {
- struct resource *conflict, res;
- res.start = 0x1f0;
- res.end = 0x1f0 + 8 - 1;
- conflict = ____request_resource(&ioport_resource, &res);
- if (!strcmp(conflict->name, "libata"))
- legacy_mode |= (1 << 0);
- else {
- disable_dev_on_err = 0;
- printk(KERN_WARNING "ata: 0x1f0 IDE port busy\n");
- }
- } else
- legacy_mode |= (1 << 0);
-
- if (!request_region(0x170, 8, "libata")) {
- struct resource *conflict, res;
- res.start = 0x170;
- res.end = 0x170 + 8 - 1;
- conflict = ____request_resource(&ioport_resource, &res);
- if (!strcmp(conflict->name, "libata"))
- legacy_mode |= (1 << 1);
- else {
- disable_dev_on_err = 0;
- printk(KERN_WARNING "ata: 0x170 IDE port busy\n");
- }
- } else
- legacy_mode |= (1 << 1);
- }
-
- /* we have legacy mode, but all ports are unavailable */
- if (legacy_mode == (1 << 3)) {
- rc = -EBUSY;
- goto err_out_regions;
- }
-
- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- goto err_out_regions;
- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- goto err_out_regions;
-
- if (legacy_mode) {
- if (legacy_mode & (1 << 0))
- probe_ent = ata_pci_init_legacy_port(pdev, port[0], 0);
- if (legacy_mode & (1 << 1))
- probe_ent2 = ata_pci_init_legacy_port(pdev, port[1], 1);
- } else {
- if (n_ports == 2)
- probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
- else
- probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY);
- }
- if (!probe_ent && !probe_ent2) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
-
- pci_set_master(pdev);
-
- /* FIXME: check ata_device_add return */
- if (legacy_mode) {
- if (legacy_mode & (1 << 0))
- ata_device_add(probe_ent);
- if (legacy_mode & (1 << 1))
- ata_device_add(probe_ent2);
- } else
- ata_device_add(probe_ent);
-
- kfree(probe_ent);
- kfree(probe_ent2);
-
- return 0;
-
-err_out_regions:
- if (legacy_mode & (1 << 0))
- release_region(0x1f0, 8);
- if (legacy_mode & (1 << 1))
- release_region(0x170, 8);
- pci_release_regions(pdev);
-err_out:
- if (disable_dev_on_err)
- pci_disable_device(pdev);
- return rc;
-}
-
-/**
* ata_pci_remove_one - PCI layer callback for device removal
* @pdev: PCI device that was removed
*
@@ -5143,7 +5045,7 @@ EXPORT_SYMBOL_GPL(ata_device_add);
EXPORT_SYMBOL_GPL(ata_host_set_remove);
EXPORT_SYMBOL_GPL(ata_sg_init);
EXPORT_SYMBOL_GPL(ata_sg_init_one);
-EXPORT_SYMBOL_GPL(ata_qc_complete);
+EXPORT_SYMBOL_GPL(__ata_qc_complete);
EXPORT_SYMBOL_GPL(ata_qc_issue_prot);
EXPORT_SYMBOL_GPL(ata_eng_timeout);
EXPORT_SYMBOL_GPL(ata_tf_load);
@@ -5169,18 +5071,30 @@ EXPORT_SYMBOL_GPL(ata_port_probe);
EXPORT_SYMBOL_GPL(sata_phy_reset);
EXPORT_SYMBOL_GPL(__sata_phy_reset);
EXPORT_SYMBOL_GPL(ata_bus_reset);
+EXPORT_SYMBOL_GPL(ata_std_probeinit);
+EXPORT_SYMBOL_GPL(ata_std_softreset);
+EXPORT_SYMBOL_GPL(sata_std_hardreset);
+EXPORT_SYMBOL_GPL(ata_std_postreset);
+EXPORT_SYMBOL_GPL(ata_std_probe_reset);
+EXPORT_SYMBOL_GPL(ata_drive_probe_reset);
+EXPORT_SYMBOL_GPL(ata_dev_revalidate);
EXPORT_SYMBOL_GPL(ata_port_disable);
EXPORT_SYMBOL_GPL(ata_ratelimit);
+EXPORT_SYMBOL_GPL(ata_busy_sleep);
+EXPORT_SYMBOL_GPL(ata_port_queue_task);
EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
+EXPORT_SYMBOL_GPL(ata_scsi_timed_out);
EXPORT_SYMBOL_GPL(ata_scsi_error);
EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
EXPORT_SYMBOL_GPL(ata_scsi_release);
EXPORT_SYMBOL_GPL(ata_host_intr);
EXPORT_SYMBOL_GPL(ata_dev_classify);
-EXPORT_SYMBOL_GPL(ata_dev_id_string);
-EXPORT_SYMBOL_GPL(ata_dev_config);
+EXPORT_SYMBOL_GPL(ata_id_string);
+EXPORT_SYMBOL_GPL(ata_id_c_string);
EXPORT_SYMBOL_GPL(ata_scsi_simulate);
+EXPORT_SYMBOL_GPL(ata_eh_qc_complete);
+EXPORT_SYMBOL_GPL(ata_eh_qc_retry);
EXPORT_SYMBOL_GPL(ata_pio_need_iordy);
EXPORT_SYMBOL_GPL(ata_timing_compute);
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 59503c9ccac..ccedb453697 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -151,7 +151,7 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
struct scsi_sense_hdr sshdr;
enum dma_data_direction data_dir;
- if (NULL == (void *)arg)
+ if (arg == NULL)
return -EINVAL;
if (copy_from_user(args, arg, sizeof(args)))
@@ -201,7 +201,7 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
/* Need code to retrieve data from check condition? */
if ((argbuf)
- && copy_to_user((void *)(arg + sizeof(args)), argbuf, argsize))
+ && copy_to_user(arg + sizeof(args), argbuf, argsize))
rc = -EFAULT;
error:
if (argbuf)
@@ -228,7 +228,7 @@ int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg)
u8 args[7];
struct scsi_sense_hdr sshdr;
- if (NULL == (void *)arg)
+ if (arg == NULL)
return -EINVAL;
if (copy_from_user(args, arg, sizeof(args)))
@@ -553,7 +553,7 @@ void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc)
/*
* Read the controller registers.
*/
- assert(NULL != qc->ap->ops->tf_read);
+ WARN_ON(qc->ap->ops->tf_read == NULL);
qc->ap->ops->tf_read(qc->ap, tf);
/*
@@ -628,7 +628,7 @@ void ata_gen_fixed_sense(struct ata_queued_cmd *qc)
/*
* Read the controller registers.
*/
- assert(NULL != qc->ap->ops->tf_read);
+ WARN_ON(qc->ap->ops->tf_read == NULL);
qc->ap->ops->tf_read(qc->ap, tf);
/*
@@ -684,23 +684,23 @@ int ata_scsi_slave_config(struct scsi_device *sdev)
if (sdev->id < ATA_MAX_DEVICES) {
struct ata_port *ap;
struct ata_device *dev;
+ unsigned int max_sectors;
ap = (struct ata_port *) &sdev->host->hostdata[0];
dev = &ap->device[sdev->id];
- /* TODO: 1024 is an arbitrary number, not the
+ /* TODO: 2048 is an arbitrary number, not the
* hardware maximum. This should be increased to
* 65534 when Jens Axboe's patch for dynamically
* determining max_sectors is merged.
*/
- if ((dev->flags & ATA_DFLAG_LBA48) &&
- ((dev->flags & ATA_DFLAG_LOCK_SECTORS) == 0)) {
- /*
- * do not overwrite sdev->host->max_sectors, since
- * other drives on this host may not support LBA48
- */
- blk_queue_max_sectors(sdev->request_queue, 2048);
- }
+ max_sectors = ATA_MAX_SECTORS;
+ if (dev->flags & ATA_DFLAG_LBA48)
+ max_sectors = 2048;
+ if (dev->max_sectors)
+ max_sectors = dev->max_sectors;
+
+ blk_queue_max_sectors(sdev->request_queue, max_sectors);
/*
* SATA DMA transfers must be multiples of 4 byte, so
@@ -717,6 +717,47 @@ int ata_scsi_slave_config(struct scsi_device *sdev)
}
/**
+ * ata_scsi_timed_out - SCSI layer time out callback
+ * @cmd: timed out SCSI command
+ *
+ * Handles SCSI layer timeout. We race with normal completion of
+ * the qc for @cmd. If the qc is already gone, we lose and let
+ * the scsi command finish (EH_HANDLED). Otherwise, the qc has
+ * timed out and EH should be invoked. Prevent ata_qc_complete()
+ * from finishing it by setting EH_SCHEDULED and return
+ * EH_NOT_HANDLED.
+ *
+ * LOCKING:
+ * Called from timer context
+ *
+ * RETURNS:
+ * EH_HANDLED or EH_NOT_HANDLED
+ */
+enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
+{
+ struct Scsi_Host *host = cmd->device->host;
+ struct ata_port *ap = (struct ata_port *) &host->hostdata[0];
+ unsigned long flags;
+ struct ata_queued_cmd *qc;
+ enum scsi_eh_timer_return ret = EH_HANDLED;
+
+ DPRINTK("ENTER\n");
+
+ spin_lock_irqsave(&ap->host_set->lock, flags);
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (qc) {
+ WARN_ON(qc->scsicmd != cmd);
+ qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
+ qc->err_mask |= AC_ERR_TIMEOUT;
+ ret = EH_NOT_HANDLED;
+ }
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+ DPRINTK("EXIT, ret=%d\n", ret);
+ return ret;
+}
+
+/**
* ata_scsi_error - SCSI layer error handler callback
* @host: SCSI host on which error occurred
*
@@ -732,23 +773,84 @@ int ata_scsi_slave_config(struct scsi_device *sdev)
int ata_scsi_error(struct Scsi_Host *host)
{
struct ata_port *ap;
+ unsigned long flags;
DPRINTK("ENTER\n");
ap = (struct ata_port *) &host->hostdata[0];
+
+ spin_lock_irqsave(&ap->host_set->lock, flags);
+ WARN_ON(ap->flags & ATA_FLAG_IN_EH);
+ ap->flags |= ATA_FLAG_IN_EH;
+ WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL);
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+ ata_port_flush_task(ap);
+
ap->ops->eng_timeout(ap);
- /* TODO: this is per-command; when queueing is supported
- * this code will either change or move to a more
- * appropriate place
- */
- host->host_failed--;
- INIT_LIST_HEAD(&host->eh_cmd_q);
+ WARN_ON(host->host_failed || !list_empty(&host->eh_cmd_q));
+
+ scsi_eh_flush_done_q(&ap->eh_done_q);
+
+ spin_lock_irqsave(&ap->host_set->lock, flags);
+ ap->flags &= ~ATA_FLAG_IN_EH;
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
DPRINTK("EXIT\n");
return 0;
}
+static void ata_eh_scsidone(struct scsi_cmnd *scmd)
+{
+ /* nada */
+}
+
+static void __ata_eh_qc_complete(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct scsi_cmnd *scmd = qc->scsicmd;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ap->host_set->lock, flags);
+ qc->scsidone = ata_eh_scsidone;
+ __ata_qc_complete(qc);
+ WARN_ON(ata_tag_valid(qc->tag));
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+ scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
+}
+
+/**
+ * ata_eh_qc_complete - Complete an active ATA command from EH
+ * @qc: Command to complete
+ *
+ * Indicate to the mid and upper layers that an ATA command has
+ * completed. To be used from EH.
+ */
+void ata_eh_qc_complete(struct ata_queued_cmd *qc)
+{
+ struct scsi_cmnd *scmd = qc->scsicmd;
+ scmd->retries = scmd->allowed;
+ __ata_eh_qc_complete(qc);
+}
+
+/**
+ * ata_eh_qc_retry - Tell midlayer to retry an ATA command after EH
+ * @qc: Command to retry
+ *
+ * Indicate to the mid and upper layers that an ATA command
+ * should be retried. To be used from EH.
+ *
+ * SCSI midlayer limits the number of retries to scmd->allowed.
+ * This function might need to adjust scmd->retries for commands
+ * which get retried due to unrelated NCQ failures.
+ */
+void ata_eh_qc_retry(struct ata_queued_cmd *qc)
+{
+ __ata_eh_qc_complete(qc);
+}
+
/**
* ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command
* @qc: Storage for translated ATA taskfile
@@ -985,9 +1087,13 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, const u8 *sc
if (dev->flags & ATA_DFLAG_LBA) {
tf->flags |= ATA_TFLAG_LBA;
- if (dev->flags & ATA_DFLAG_LBA48) {
- if (n_block > (64 * 1024))
- goto invalid_fld;
+ if (lba_28_ok(block, n_block)) {
+ /* use LBA28 */
+ tf->command = ATA_CMD_VERIFY;
+ tf->device |= (block >> 24) & 0xf;
+ } else if (lba_48_ok(block, n_block)) {
+ if (!(dev->flags & ATA_DFLAG_LBA48))
+ goto out_of_range;
/* use LBA48 */
tf->flags |= ATA_TFLAG_LBA48;
@@ -998,15 +1104,9 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, const u8 *sc
tf->hob_lbah = (block >> 40) & 0xff;
tf->hob_lbam = (block >> 32) & 0xff;
tf->hob_lbal = (block >> 24) & 0xff;
- } else {
- if (n_block > 256)
- goto invalid_fld;
-
- /* use LBA28 */
- tf->command = ATA_CMD_VERIFY;
-
- tf->device |= (block >> 24) & 0xf;
- }
+ } else
+ /* request too large even for LBA48 */
+ goto out_of_range;
tf->nsect = n_block & 0xff;
@@ -1019,8 +1119,8 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, const u8 *sc
/* CHS */
u32 sect, head, cyl, track;
- if (n_block > 256)
- goto invalid_fld;
+ if (!lba_28_ok(block, n_block))
+ goto out_of_range;
/* Convert LBA to CHS */
track = (u32)block / dev->sectors;
@@ -1139,9 +1239,11 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
if (dev->flags & ATA_DFLAG_LBA) {
tf->flags |= ATA_TFLAG_LBA;
- if (dev->flags & ATA_DFLAG_LBA48) {
- /* The request -may- be too large for LBA48. */
- if ((block >> 48) || (n_block > 65536))
+ if (lba_28_ok(block, n_block)) {
+ /* use LBA28 */
+ tf->device |= (block >> 24) & 0xf;
+ } else if (lba_48_ok(block, n_block)) {
+ if (!(dev->flags & ATA_DFLAG_LBA48))
goto out_of_range;
/* use LBA48 */
@@ -1152,15 +1254,9 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
tf->hob_lbah = (block >> 40) & 0xff;
tf->hob_lbam = (block >> 32) & 0xff;
tf->hob_lbal = (block >> 24) & 0xff;
- } else {
- /* use LBA28 */
-
- /* The request -may- be too large for LBA28. */
- if ((block >> 28) || (n_block > 256))
- goto out_of_range;
-
- tf->device |= (block >> 24) & 0xf;
- }
+ } else
+ /* request too large even for LBA48 */
+ goto out_of_range;
if (unlikely(ata_rwcmd_protocol(qc) < 0))
goto invalid_fld;
@@ -1178,7 +1274,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
u32 sect, head, cyl, track;
/* The request -may- be too large for CHS addressing. */
- if ((block >> 28) || (n_block > 256))
+ if (!lba_28_ok(block, n_block))
goto out_of_range;
if (unlikely(ata_rwcmd_protocol(qc) < 0))
@@ -1225,7 +1321,7 @@ nothing_to_do:
return 1;
}
-static int ata_scsi_qc_complete(struct ata_queued_cmd *qc)
+static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
{
struct scsi_cmnd *cmd = qc->scsicmd;
u8 *cdb = cmd->cmnd;
@@ -1262,7 +1358,7 @@ static int ata_scsi_qc_complete(struct ata_queued_cmd *qc)
qc->scsidone(cmd);
- return 0;
+ ata_qc_free(qc);
}
/**
@@ -1328,8 +1424,9 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev,
goto early_finish;
/* select device, send command to hardware */
- if (ata_qc_issue(qc))
- goto err_did;
+ qc->err_mask = ata_qc_issue(qc);
+ if (qc->err_mask)
+ ata_qc_complete(qc);
VPRINTK("EXIT\n");
return;
@@ -1472,8 +1569,8 @@ unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
if (buflen > 35) {
memcpy(&rbuf[8], "ATA ", 8);
- ata_dev_id_string(args->id, &rbuf[16], ATA_ID_PROD_OFS, 16);
- ata_dev_id_string(args->id, &rbuf[32], ATA_ID_FW_REV_OFS, 4);
+ ata_id_string(args->id, &rbuf[16], ATA_ID_PROD_OFS, 16);
+ ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV_OFS, 4);
if (rbuf[32] == 0 || rbuf[32] == ' ')
memcpy(&rbuf[32], "n/a ", 4);
}
@@ -1547,8 +1644,8 @@ unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
memcpy(rbuf, hdr, sizeof(hdr));
if (buflen > (ATA_SERNO_LEN + 4 - 1))
- ata_dev_id_string(args->id, (unsigned char *) &rbuf[4],
- ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
+ ata_id_string(args->id, (unsigned char *) &rbuf[4],
+ ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
return 0;
}
@@ -1713,15 +1810,12 @@ static int ata_dev_supports_fua(u16 *id)
if (!ata_id_has_fua(id))
return 0;
- model[40] = '\0';
- fw[8] = '\0';
-
- ata_dev_id_string(id, model, ATA_ID_PROD_OFS, sizeof(model) - 1);
- ata_dev_id_string(id, fw, ATA_ID_FW_REV_OFS, sizeof(fw) - 1);
+ ata_id_c_string(id, model, ATA_ID_PROD_OFS, sizeof(model));
+ ata_id_c_string(id, fw, ATA_ID_FW_REV_OFS, sizeof(fw));
- if (strncmp(model, "Maxtor", 6))
+ if (strcmp(model, "Maxtor"))
return 1;
- if (strncmp(fw, "BANC1G10", 8))
+ if (strcmp(fw, "BANC1G10"))
return 1;
return 0; /* blacklisted */
@@ -2015,7 +2109,7 @@ void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8
done(cmd);
}
-static int atapi_sense_complete(struct ata_queued_cmd *qc)
+static void atapi_sense_complete(struct ata_queued_cmd *qc)
{
if (qc->err_mask && ((qc->err_mask & AC_ERR_DEV) == 0))
/* FIXME: not quite right; we don't want the
@@ -2026,7 +2120,7 @@ static int atapi_sense_complete(struct ata_queued_cmd *qc)
ata_gen_ata_desc_sense(qc);
qc->scsidone(qc->scsicmd);
- return 0;
+ ata_qc_free(qc);
}
/* is it pointless to prefer PIO for "safety reasons"? */
@@ -2056,7 +2150,7 @@ static void atapi_request_sense(struct ata_queued_cmd *qc)
ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer));
qc->dma_dir = DMA_FROM_DEVICE;
- memset(&qc->cdb, 0, ap->cdb_len);
+ memset(&qc->cdb, 0, qc->dev->cdb_len);
qc->cdb[0] = REQUEST_SENSE;
qc->cdb[4] = SCSI_SENSE_BUFFERSIZE;
@@ -2075,15 +2169,14 @@ static void atapi_request_sense(struct ata_queued_cmd *qc)
qc->complete_fn = atapi_sense_complete;
- if (ata_qc_issue(qc)) {
- qc->err_mask |= AC_ERR_OTHER;
+ qc->err_mask = ata_qc_issue(qc);
+ if (qc->err_mask)
ata_qc_complete(qc);
- }
DPRINTK("EXIT\n");
}
-static int atapi_qc_complete(struct ata_queued_cmd *qc)
+static void atapi_qc_complete(struct ata_queued_cmd *qc)
{
struct scsi_cmnd *cmd = qc->scsicmd;
unsigned int err_mask = qc->err_mask;
@@ -2093,7 +2186,7 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc)
if (unlikely(err_mask & AC_ERR_DEV)) {
cmd->result = SAM_STAT_CHECK_CONDITION;
atapi_request_sense(qc);
- return 1;
+ return;
}
else if (unlikely(err_mask))
@@ -2133,7 +2226,7 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc)
}
qc->scsidone(cmd);
- return 0;
+ ata_qc_free(qc);
}
/**
* atapi_xlat - Initialize PACKET taskfile
@@ -2159,7 +2252,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
if (ata_check_atapi_dma(qc))
using_pio = 1;
- memcpy(&qc->cdb, scsicmd, qc->ap->cdb_len);
+ memcpy(&qc->cdb, scsicmd, dev->cdb_len);
qc->complete_fn = atapi_qc_complete;
@@ -2519,7 +2612,8 @@ out_unlock:
/**
* ata_scsi_simulate - simulate SCSI command on ATA device
- * @id: current IDENTIFY data for target device.
+ * @ap: port the device is connected to
+ * @dev: the target device
* @cmd: SCSI command being sent to device.
* @done: SCSI command completion function.
*
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
index fddaf479a54..f4c48c91b63 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -45,8 +45,9 @@ extern int libata_fua;
extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
struct ata_device *dev);
extern int ata_rwcmd_protocol(struct ata_queued_cmd *qc);
+extern void ata_port_flush_task(struct ata_port *ap);
extern void ata_qc_free(struct ata_queued_cmd *qc);
-extern int ata_qc_issue(struct ata_queued_cmd *qc);
+extern unsigned int ata_qc_issue(struct ata_queued_cmd *qc);
extern int ata_check_atapi_dma(struct ata_queued_cmd *qc);
extern void ata_dev_select(struct ata_port *ap, unsigned int device,
unsigned int wait, unsigned int can_sleep);
diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c
index e8df0c9ec1e..5f33cc932e7 100644
--- a/drivers/scsi/pdc_adma.c
+++ b/drivers/scsi/pdc_adma.c
@@ -131,7 +131,7 @@ static void adma_host_stop(struct ata_host_set *host_set);
static void adma_port_stop(struct ata_port *ap);
static void adma_phy_reset(struct ata_port *ap);
static void adma_qc_prep(struct ata_queued_cmd *qc);
-static int adma_qc_issue(struct ata_queued_cmd *qc);
+static unsigned int adma_qc_issue(struct ata_queued_cmd *qc);
static int adma_check_atapi_dma(struct ata_queued_cmd *qc);
static void adma_bmdma_stop(struct ata_queued_cmd *qc);
static u8 adma_bmdma_status(struct ata_port *ap);
@@ -143,11 +143,11 @@ static struct scsi_host_template adma_ata_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
+ .eh_timed_out = ata_scsi_timed_out,
.eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = LIBATA_MAX_PRD,
- .max_sectors = ATA_MAX_SECTORS,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.emulated = ATA_SHT_EMULATED,
.use_clustering = ENABLE_CLUSTERING,
@@ -419,7 +419,7 @@ static inline void adma_packet_start(struct ata_queued_cmd *qc)
writew(aPIOMD4 | aGO, chan + ADMA_CONTROL);
}
-static int adma_qc_issue(struct ata_queued_cmd *qc)
+static unsigned int adma_qc_issue(struct ata_queued_cmd *qc)
{
struct adma_port_priv *pp = qc->ap->private_data;
diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c
index 2770005324b..e561281967d 100644
--- a/drivers/scsi/sata_mv.c
+++ b/drivers/scsi/sata_mv.c
@@ -37,7 +37,7 @@
#include <asm/io.h>
#define DRV_NAME "sata_mv"
-#define DRV_VERSION "0.5"
+#define DRV_VERSION "0.6"
enum {
/* BAR's are enumerated in terms of pci_resource_start() terms */
@@ -228,7 +228,9 @@ enum {
MV_HP_ERRATA_50XXB2 = (1 << 2),
MV_HP_ERRATA_60X1B2 = (1 << 3),
MV_HP_ERRATA_60X1C0 = (1 << 4),
- MV_HP_50XX = (1 << 5),
+ MV_HP_ERRATA_XX42A0 = (1 << 5),
+ MV_HP_50XX = (1 << 6),
+ MV_HP_GEN_IIE = (1 << 7),
/* Port private flags (pp_flags) */
MV_PP_FLAG_EDMA_EN = (1 << 0),
@@ -237,6 +239,9 @@ enum {
#define IS_50XX(hpriv) ((hpriv)->hp_flags & MV_HP_50XX)
#define IS_60XX(hpriv) (((hpriv)->hp_flags & MV_HP_50XX) == 0)
+#define IS_GEN_I(hpriv) IS_50XX(hpriv)
+#define IS_GEN_II(hpriv) IS_60XX(hpriv)
+#define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
enum {
/* Our DMA boundary is determined by an ePRD being unable to handle
@@ -255,6 +260,8 @@ enum chip_type {
chip_5080,
chip_604x,
chip_608x,
+ chip_6042,
+ chip_7042,
};
/* Command ReQuest Block: 32B */
@@ -265,6 +272,14 @@ struct mv_crqb {
u16 ata_cmd[11];
};
+struct mv_crqb_iie {
+ u32 addr;
+ u32 addr_hi;
+ u32 flags;
+ u32 len;
+ u32 ata_cmd[4];
+};
+
/* Command ResPonse Block: 8B */
struct mv_crpb {
u16 id;
@@ -328,7 +343,8 @@ static void mv_host_stop(struct ata_host_set *host_set);
static int mv_port_start(struct ata_port *ap);
static void mv_port_stop(struct ata_port *ap);
static void mv_qc_prep(struct ata_queued_cmd *qc);
-static int mv_qc_issue(struct ata_queued_cmd *qc);
+static void mv_qc_prep_iie(struct ata_queued_cmd *qc);
+static unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
static irqreturn_t mv_interrupt(int irq, void *dev_instance,
struct pt_regs *regs);
static void mv_eng_timeout(struct ata_port *ap);
@@ -362,11 +378,11 @@ static struct scsi_host_template mv_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
+ .eh_timed_out = ata_scsi_timed_out,
.eh_strategy_handler = ata_scsi_error,
.can_queue = MV_USE_Q_DEPTH,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = MV_MAX_SG_CT / 2,
- .max_sectors = ATA_MAX_SECTORS,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.emulated = ATA_SHT_EMULATED,
.use_clustering = ATA_SHT_USE_CLUSTERING,
@@ -430,6 +446,33 @@ static const struct ata_port_operations mv6_ops = {
.host_stop = mv_host_stop,
};
+static const struct ata_port_operations mv_iie_ops = {
+ .port_disable = ata_port_disable,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .phy_reset = mv_phy_reset,
+
+ .qc_prep = mv_qc_prep_iie,
+ .qc_issue = mv_qc_issue,
+
+ .eng_timeout = mv_eng_timeout,
+
+ .irq_handler = mv_interrupt,
+ .irq_clear = mv_irq_clear,
+
+ .scr_read = mv_scr_read,
+ .scr_write = mv_scr_write,
+
+ .port_start = mv_port_start,
+ .port_stop = mv_port_stop,
+ .host_stop = mv_host_stop,
+};
+
static const struct ata_port_info mv_port_info[] = {
{ /* chip_504x */
.sht = &mv_sht,
@@ -467,6 +510,21 @@ static const struct ata_port_info mv_port_info[] = {
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &mv6_ops,
},
+ { /* chip_6042 */
+ .sht = &mv_sht,
+ .host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &mv_iie_ops,
+ },
+ { /* chip_7042 */
+ .sht = &mv_sht,
+ .host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS |
+ MV_FLAG_DUAL_HC),
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &mv_iie_ops,
+ },
};
static const struct pci_device_id mv_pci_tbl[] = {
@@ -477,6 +535,7 @@ static const struct pci_device_id mv_pci_tbl[] = {
{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6040), 0, 0, chip_604x},
{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6041), 0, 0, chip_604x},
+ {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6042), 0, 0, chip_6042},
{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6080), 0, 0, chip_608x},
{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6081), 0, 0, chip_608x},
@@ -572,8 +631,8 @@ static void mv_irq_clear(struct ata_port *ap)
* @base: port base address
* @pp: port private data
*
- * Verify the local cache of the eDMA state is accurate with an
- * assert.
+ * Verify the local cache of the eDMA state is accurate with a
+ * WARN_ON.
*
* LOCKING:
* Inherited from caller.
@@ -584,15 +643,15 @@ static void mv_start_dma(void __iomem *base, struct mv_port_priv *pp)
writelfl(EDMA_EN, base + EDMA_CMD_OFS);
pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
}
- assert(EDMA_EN & readl(base + EDMA_CMD_OFS));
+ WARN_ON(!(EDMA_EN & readl(base + EDMA_CMD_OFS)));
}
/**
* mv_stop_dma - Disable eDMA engine
* @ap: ATA channel to manipulate
*
- * Verify the local cache of the eDMA state is accurate with an
- * assert.
+ * Verify the local cache of the eDMA state is accurate with a
+ * WARN_ON.
*
* LOCKING:
* Inherited from caller.
@@ -610,7 +669,7 @@ static void mv_stop_dma(struct ata_port *ap)
writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
} else {
- assert(!(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS)));
+ WARN_ON(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS));
}
/* now properly wait for the eDMA to stop */
@@ -773,6 +832,33 @@ static inline void mv_priv_free(struct mv_port_priv *pp, struct device *dev)
dma_free_coherent(dev, MV_PORT_PRIV_DMA_SZ, pp->crpb, pp->crpb_dma);
}
+static void mv_edma_cfg(struct mv_host_priv *hpriv, void __iomem *port_mmio)
+{
+ u32 cfg = readl(port_mmio + EDMA_CFG_OFS);
+
+ /* set up non-NCQ EDMA configuration */
+ cfg &= ~0x1f; /* clear queue depth */
+ cfg &= ~EDMA_CFG_NCQ; /* clear NCQ mode */
+ cfg &= ~(1 << 9); /* disable equeue */
+
+ if (IS_GEN_I(hpriv))
+ cfg |= (1 << 8); /* enab config burst size mask */
+
+ else if (IS_GEN_II(hpriv))
+ cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN;
+
+ else if (IS_GEN_IIE(hpriv)) {
+ cfg |= (1 << 23); /* dis RX PM port mask */
+ cfg &= ~(1 << 16); /* dis FIS-based switching (for now) */
+ cfg &= ~(1 << 19); /* dis 128-entry queue (for now?) */
+ cfg |= (1 << 18); /* enab early completion */
+ cfg |= (1 << 17); /* enab host q cache */
+ cfg |= (1 << 22); /* enab cutthrough */
+ }
+
+ writelfl(cfg, port_mmio + EDMA_CFG_OFS);
+}
+
/**
* mv_port_start - Port specific init/start routine.
* @ap: ATA channel to manipulate
@@ -786,6 +872,7 @@ static inline void mv_priv_free(struct mv_port_priv *pp, struct device *dev)
static int mv_port_start(struct ata_port *ap)
{
struct device *dev = ap->host_set->dev;
+ struct mv_host_priv *hpriv = ap->host_set->private_data;
struct mv_port_priv *pp;
void __iomem *port_mmio = mv_ap_base(ap);
void *mem;
@@ -829,17 +916,26 @@ static int mv_port_start(struct ata_port *ap)
pp->sg_tbl = mem;
pp->sg_tbl_dma = mem_dma;
- writelfl(EDMA_CFG_Q_DEPTH | EDMA_CFG_RD_BRST_EXT |
- EDMA_CFG_WR_BUFF_LEN, port_mmio + EDMA_CFG_OFS);
+ mv_edma_cfg(hpriv, port_mmio);
writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS);
writelfl(pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK,
port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
- writelfl(0, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
- writelfl(0, port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
+ if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
+ writelfl(pp->crqb_dma & 0xffffffff,
+ port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
+ else
+ writelfl(0, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS);
+
+ if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
+ writelfl(pp->crpb_dma & 0xffffffff,
+ port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
+ else
+ writelfl(0, port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
+
writelfl(pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK,
port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
@@ -960,21 +1056,19 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
struct ata_taskfile *tf;
u16 flags = 0;
- if (ATA_PROT_DMA != qc->tf.protocol) {
+ if (ATA_PROT_DMA != qc->tf.protocol)
return;
- }
/* the req producer index should be the same as we remember it */
- assert(((readl(mv_ap_base(qc->ap) + EDMA_REQ_Q_IN_PTR_OFS) >>
- EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) ==
- pp->req_producer);
+ WARN_ON(((readl(mv_ap_base(qc->ap) + EDMA_REQ_Q_IN_PTR_OFS) >>
+ EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
+ pp->req_producer);
/* Fill in command request block
*/
- if (!(qc->tf.flags & ATA_TFLAG_WRITE)) {
+ if (!(qc->tf.flags & ATA_TFLAG_WRITE))
flags |= CRQB_FLAG_READ;
- }
- assert(MV_MAX_Q_DEPTH > qc->tag);
+ WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
flags |= qc->tag << CRQB_TAG_SHIFT;
pp->crqb[pp->req_producer].sg_addr =
@@ -1029,9 +1123,76 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
mv_crqb_pack_cmd(cw++, tf->device, ATA_REG_DEVICE, 0);
mv_crqb_pack_cmd(cw++, tf->command, ATA_REG_CMD, 1); /* last */
- if (!(qc->flags & ATA_QCFLAG_DMAMAP)) {
+ if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+ return;
+ mv_fill_sg(qc);
+}
+
+/**
+ * mv_qc_prep_iie - Host specific command preparation.
+ * @qc: queued command to prepare
+ *
+ * This routine simply redirects to the general purpose routine
+ * if command is not DMA. Else, it handles prep of the CRQB
+ * (command request block), does some sanity checking, and calls
+ * the SG load routine.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct mv_port_priv *pp = ap->private_data;
+ struct mv_crqb_iie *crqb;
+ struct ata_taskfile *tf;
+ u32 flags = 0;
+
+ if (ATA_PROT_DMA != qc->tf.protocol)
+ return;
+
+ /* the req producer index should be the same as we remember it */
+ WARN_ON(((readl(mv_ap_base(qc->ap) + EDMA_REQ_Q_IN_PTR_OFS) >>
+ EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
+ pp->req_producer);
+
+ /* Fill in Gen IIE command request block
+ */
+ if (!(qc->tf.flags & ATA_TFLAG_WRITE))
+ flags |= CRQB_FLAG_READ;
+
+ WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
+ flags |= qc->tag << CRQB_TAG_SHIFT;
+
+ crqb = (struct mv_crqb_iie *) &pp->crqb[pp->req_producer];
+ crqb->addr = cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
+ crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
+ crqb->flags = cpu_to_le32(flags);
+
+ tf = &qc->tf;
+ crqb->ata_cmd[0] = cpu_to_le32(
+ (tf->command << 16) |
+ (tf->feature << 24)
+ );
+ crqb->ata_cmd[1] = cpu_to_le32(
+ (tf->lbal << 0) |
+ (tf->lbam << 8) |
+ (tf->lbah << 16) |
+ (tf->device << 24)
+ );
+ crqb->ata_cmd[2] = cpu_to_le32(
+ (tf->hob_lbal << 0) |
+ (tf->hob_lbam << 8) |
+ (tf->hob_lbah << 16) |
+ (tf->hob_feature << 24)
+ );
+ crqb->ata_cmd[3] = cpu_to_le32(
+ (tf->nsect << 0) |
+ (tf->hob_nsect << 8)
+ );
+
+ if (!(qc->flags & ATA_QCFLAG_DMAMAP))
return;
- }
mv_fill_sg(qc);
}
@@ -1047,7 +1208,7 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
* LOCKING:
* Inherited from caller.
*/
-static int mv_qc_issue(struct ata_queued_cmd *qc)
+static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
{
void __iomem *port_mmio = mv_ap_base(qc->ap);
struct mv_port_priv *pp = qc->ap->private_data;
@@ -1065,12 +1226,12 @@ static int mv_qc_issue(struct ata_queued_cmd *qc)
in_ptr = readl(port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
/* the req producer index should be the same as we remember it */
- assert(((in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) ==
- pp->req_producer);
+ WARN_ON(((in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
+ pp->req_producer);
/* until we do queuing, the queue should be empty at this point */
- assert(((in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) ==
- ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS) >>
- EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
+ WARN_ON(((in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
+ ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS) >>
+ EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
mv_inc_q_index(&pp->req_producer); /* now incr producer index */
@@ -1090,7 +1251,7 @@ static int mv_qc_issue(struct ata_queued_cmd *qc)
*
* This routine is for use when the port is in DMA mode, when it
* will be using the CRPB (command response block) method of
- * returning command completion information. We assert indices
+ * returning command completion information. We check indices
* are good, grab status, and bump the response consumer index to
* prove that we're up to date.
*
@@ -1106,16 +1267,16 @@ static u8 mv_get_crpb_status(struct ata_port *ap)
out_ptr = readl(port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
/* the response consumer index should be the same as we remember it */
- assert(((out_ptr >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) ==
- pp->rsp_consumer);
+ WARN_ON(((out_ptr >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
+ pp->rsp_consumer);
/* increment our consumer index... */
pp->rsp_consumer = mv_inc_q_index(&pp->rsp_consumer);
/* and, until we do NCQ, there should only be 1 CRPB waiting */
- assert(((readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS) >>
- EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) ==
- pp->rsp_consumer);
+ WARN_ON(((readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS) >>
+ EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
+ pp->rsp_consumer);
/* write out our inc'd consumer index so EDMA knows we're caught up */
out_ptr &= EDMA_RSP_Q_BASE_LO_MASK;
@@ -1192,7 +1353,6 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant,
u32 hc_irq_cause;
int shift, port, port0, hard_port, handled;
unsigned int err_mask;
- u8 ata_status = 0;
if (hc == 0) {
port0 = 0;
@@ -1210,6 +1370,7 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant,
hc,relevant,hc_irq_cause);
for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) {
+ u8 ata_status = 0;
ap = host_set->ports[port];
hard_port = port & MV_PORT_MASK; /* range 0-3 */
handled = 0; /* ensure ata_status is set if handled++ */
@@ -1681,6 +1842,12 @@ static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
m2 |= hpriv->signal[port].pre;
m2 &= ~(1 << 16);
+ /* according to mvSata 3.6.1, some IIE values are fixed */
+ if (IS_GEN_IIE(hpriv)) {
+ m2 &= ~0xC30FF01F;
+ m2 |= 0x0000900F;
+ }
+
writel(m2, port_mmio + PHY_MODE2);
}
@@ -1846,7 +2013,6 @@ static void mv_phy_reset(struct ata_port *ap)
static void mv_eng_timeout(struct ata_port *ap)
{
struct ata_queued_cmd *qc;
- unsigned long flags;
printk(KERN_ERR "ata%u: Entering mv_eng_timeout\n",ap->id);
DPRINTK("All regs @ start of eng_timeout\n");
@@ -1861,22 +2027,8 @@ static void mv_eng_timeout(struct ata_port *ap)
mv_err_intr(ap);
mv_stop_and_reset(ap);
- if (!qc) {
- printk(KERN_ERR "ata%u: BUG: timeout without command\n",
- ap->id);
- } else {
- /* hack alert! We cannot use the supplied completion
- * function from inside the ->eh_strategy_handler() thread.
- * libata is the only user of ->eh_strategy_handler() in
- * any kernel, so the default scsi_done() assumes it is
- * not being called from the SCSI EH.
- */
- spin_lock_irqsave(&ap->host_set->lock, flags);
- qc->scsidone = scsi_finish_command;
- qc->err_mask |= AC_ERR_OTHER;
- ata_qc_complete(qc);
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
- }
+ qc->err_mask |= AC_ERR_TIMEOUT;
+ ata_eh_qc_complete(qc);
}
/**
@@ -1995,6 +2147,27 @@ static int mv_chip_id(struct pci_dev *pdev, struct mv_host_priv *hpriv,
}
break;
+ case chip_7042:
+ case chip_6042:
+ hpriv->ops = &mv6xxx_ops;
+
+ hp_flags |= MV_HP_GEN_IIE;
+
+ switch (rev_id) {
+ case 0x0:
+ hp_flags |= MV_HP_ERRATA_XX42A0;
+ break;
+ case 0x1:
+ hp_flags |= MV_HP_ERRATA_60X1C0;
+ break;
+ default:
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "Applying 60X1C0 workarounds to unknown rev\n");
+ hp_flags |= MV_HP_ERRATA_60X1C0;
+ break;
+ }
+ break;
+
default:
printk(KERN_ERR DRV_NAME ": BUG: invalid board index %u\n", board_idx);
return 1;
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c
index bbbb55eeb73..caffadc2e0a 100644
--- a/drivers/scsi/sata_nv.c
+++ b/drivers/scsi/sata_nv.c
@@ -229,11 +229,11 @@ static struct scsi_host_template nv_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
+ .eh_timed_out = ata_scsi_timed_out,
.eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = LIBATA_MAX_PRD,
- .max_sectors = ATA_MAX_SECTORS,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.emulated = ATA_SHT_EMULATED,
.use_clustering = ATA_SHT_USE_CLUSTERING,
diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c
index b0b0a69b356..84cb3940ad8 100644
--- a/drivers/scsi/sata_promise.c
+++ b/drivers/scsi/sata_promise.c
@@ -46,7 +46,7 @@
#include "sata_promise.h"
#define DRV_NAME "sata_promise"
-#define DRV_VERSION "1.03"
+#define DRV_VERSION "1.04"
enum {
@@ -58,6 +58,7 @@ enum {
PDC_GLOBAL_CTL = 0x48, /* Global control/status (per port) */
PDC_CTLSTAT = 0x60, /* IDE control and status (per port) */
PDC_SATA_PLUG_CSR = 0x6C, /* SATA Plug control/status reg */
+ PDC2_SATA_PLUG_CSR = 0x60, /* SATAII Plug control/status reg */
PDC_SLEW_CTL = 0x470, /* slew rate control reg */
PDC_ERR_MASK = (1<<19) | (1<<20) | (1<<21) | (1<<22) |
@@ -67,8 +68,10 @@ enum {
board_20319 = 1, /* FastTrak S150 TX4 */
board_20619 = 2, /* FastTrak TX4000 */
board_20771 = 3, /* FastTrak TX2300 */
+ board_2057x = 4, /* SATAII150 Tx2plus */
+ board_40518 = 5, /* SATAII150 Tx4 */
- PDC_HAS_PATA = (1 << 1), /* PDC20375 has PATA */
+ PDC_HAS_PATA = (1 << 1), /* PDC20375/20575 has PATA */
PDC_RESET = (1 << 11), /* HDMA reset */
@@ -82,6 +85,10 @@ struct pdc_port_priv {
dma_addr_t pkt_dma;
};
+struct pdc_host_priv {
+ int hotplug_offset;
+};
+
static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
@@ -95,7 +102,8 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc);
static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
static void pdc_irq_clear(struct ata_port *ap);
-static int pdc_qc_issue_prot(struct ata_queued_cmd *qc);
+static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc);
+static void pdc_host_stop(struct ata_host_set *host_set);
static struct scsi_host_template pdc_ata_sht = {
@@ -103,11 +111,11 @@ static struct scsi_host_template pdc_ata_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
+ .eh_timed_out = ata_scsi_timed_out,
.eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = LIBATA_MAX_PRD,
- .max_sectors = ATA_MAX_SECTORS,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.emulated = ATA_SHT_EMULATED,
.use_clustering = ATA_SHT_USE_CLUSTERING,
@@ -137,7 +145,7 @@ static const struct ata_port_operations pdc_sata_ops = {
.scr_write = pdc_sata_scr_write,
.port_start = pdc_port_start,
.port_stop = pdc_port_stop,
- .host_stop = ata_pci_host_stop,
+ .host_stop = pdc_host_stop,
};
static const struct ata_port_operations pdc_pata_ops = {
@@ -158,7 +166,7 @@ static const struct ata_port_operations pdc_pata_ops = {
.port_start = pdc_port_start,
.port_stop = pdc_port_stop,
- .host_stop = ata_pci_host_stop,
+ .host_stop = pdc_host_stop,
};
static const struct ata_port_info pdc_port_info[] = {
@@ -201,6 +209,26 @@ static const struct ata_port_info pdc_port_info[] = {
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
.port_ops = &pdc_sata_ops,
},
+
+ /* board_2057x */
+ {
+ .sht = &pdc_ata_sht,
+ .host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .port_ops = &pdc_sata_ops,
+ },
+
+ /* board_40518 */
+ {
+ .sht = &pdc_ata_sht,
+ .host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .port_ops = &pdc_sata_ops,
+ },
};
static const struct pci_device_id pdc_ata_pci_tbl[] = {
@@ -217,9 +245,9 @@ static const struct pci_device_id pdc_ata_pci_tbl[] = {
{ PCI_VENDOR_ID_PROMISE, 0x3376, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
board_2037x },
{ PCI_VENDOR_ID_PROMISE, 0x3574, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2037x },
+ board_2057x },
{ PCI_VENDOR_ID_PROMISE, 0x3d75, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2037x },
+ board_2057x },
{ PCI_VENDOR_ID_PROMISE, 0x3d73, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
board_2037x },
@@ -227,12 +255,14 @@ static const struct pci_device_id pdc_ata_pci_tbl[] = {
board_20319 },
{ PCI_VENDOR_ID_PROMISE, 0x3319, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
board_20319 },
+ { PCI_VENDOR_ID_PROMISE, 0x3515, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_20319 },
{ PCI_VENDOR_ID_PROMISE, 0x3519, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
board_20319 },
{ PCI_VENDOR_ID_PROMISE, 0x3d17, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
board_20319 },
{ PCI_VENDOR_ID_PROMISE, 0x3d18, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20319 },
+ board_40518 },
{ PCI_VENDOR_ID_PROMISE, 0x6629, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
board_20619 },
@@ -261,12 +291,11 @@ static int pdc_port_start(struct ata_port *ap)
if (rc)
return rc;
- pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+ pp = kzalloc(sizeof(*pp), GFP_KERNEL);
if (!pp) {
rc = -ENOMEM;
goto err_out;
}
- memset(pp, 0, sizeof(*pp));
pp->pkt = dma_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL);
if (!pp->pkt) {
@@ -298,6 +327,16 @@ static void pdc_port_stop(struct ata_port *ap)
}
+static void pdc_host_stop(struct ata_host_set *host_set)
+{
+ struct pdc_host_priv *hp = host_set->private_data;
+
+ ata_pci_host_stop(host_set);
+
+ kfree(hp);
+}
+
+
static void pdc_reset_port(struct ata_port *ap)
{
void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_CTLSTAT;
@@ -394,19 +433,6 @@ static void pdc_eng_timeout(struct ata_port *ap)
spin_lock_irqsave(&host_set->lock, flags);
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (!qc) {
- printk(KERN_ERR "ata%u: BUG: timeout without command\n",
- ap->id);
- goto out;
- }
-
- /* hack alert! We cannot use the supplied completion
- * function from inside the ->eh_strategy_handler() thread.
- * libata is the only user of ->eh_strategy_handler() in
- * any kernel, so the default scsi_done() assumes it is
- * not being called from the SCSI EH.
- */
- qc->scsidone = scsi_finish_command;
switch (qc->tf.protocol) {
case ATA_PROT_DMA:
@@ -414,7 +440,6 @@ static void pdc_eng_timeout(struct ata_port *ap)
printk(KERN_ERR "ata%u: command timeout\n", ap->id);
drv_stat = ata_wait_idle(ap);
qc->err_mask |= __ac_err_mask(drv_stat);
- ata_qc_complete(qc);
break;
default:
@@ -424,12 +449,11 @@ static void pdc_eng_timeout(struct ata_port *ap)
ap->id, qc->tf.command, drv_stat);
qc->err_mask |= ac_err_mask(drv_stat);
- ata_qc_complete(qc);
break;
}
-out:
spin_unlock_irqrestore(&host_set->lock, flags);
+ ata_eh_qc_complete(qc);
DPRINTK("EXIT\n");
}
@@ -495,14 +519,15 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *r
VPRINTK("QUICK EXIT 2\n");
return IRQ_NONE;
}
+
+ spin_lock(&host_set->lock);
+
mask &= 0xffff; /* only 16 tags possible */
if (!mask) {
VPRINTK("QUICK EXIT 3\n");
- return IRQ_NONE;
+ goto done_irq;
}
- spin_lock(&host_set->lock);
-
writel(mask, mmio_base + PDC_INT_SEQMASK);
for (i = 0; i < host_set->n_ports; i++) {
@@ -519,10 +544,10 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *r
}
}
- spin_unlock(&host_set->lock);
-
VPRINTK("EXIT\n");
+done_irq:
+ spin_unlock(&host_set->lock);
return IRQ_RETVAL(handled);
}
@@ -544,7 +569,7 @@ static inline void pdc_packet_start(struct ata_queued_cmd *qc)
readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */
}
-static int pdc_qc_issue_prot(struct ata_queued_cmd *qc)
+static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc)
{
switch (qc->tf.protocol) {
case ATA_PROT_DMA:
@@ -600,6 +625,8 @@ static void pdc_ata_setup_port(struct ata_ioports *port, unsigned long base)
static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
{
void __iomem *mmio = pe->mmio_base;
+ struct pdc_host_priv *hp = pe->private_data;
+ int hotplug_offset = hp->hotplug_offset;
u32 tmp;
/*
@@ -614,12 +641,12 @@ static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
writel(tmp, mmio + PDC_FLASH_CTL);
/* clear plug/unplug flags for all ports */
- tmp = readl(mmio + PDC_SATA_PLUG_CSR);
- writel(tmp | 0xff, mmio + PDC_SATA_PLUG_CSR);
+ tmp = readl(mmio + hotplug_offset);
+ writel(tmp | 0xff, mmio + hotplug_offset);
/* mask plug/unplug ints */
- tmp = readl(mmio + PDC_SATA_PLUG_CSR);
- writel(tmp | 0xff0000, mmio + PDC_SATA_PLUG_CSR);
+ tmp = readl(mmio + hotplug_offset);
+ writel(tmp | 0xff0000, mmio + hotplug_offset);
/* reduce TBG clock to 133 Mhz. */
tmp = readl(mmio + PDC_TBG_MODE);
@@ -641,6 +668,7 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
{
static int printed_version;
struct ata_probe_ent *probe_ent = NULL;
+ struct pdc_host_priv *hp;
unsigned long base;
void __iomem *mmio_base;
unsigned int board_idx = (unsigned int) ent->driver_data;
@@ -671,13 +699,12 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
if (rc)
goto err_out_regions;
- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+ probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
if (probe_ent == NULL) {
rc = -ENOMEM;
goto err_out_regions;
}
- memset(probe_ent, 0, sizeof(*probe_ent));
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
@@ -688,6 +715,16 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
}
base = (unsigned long) mmio_base;
+ hp = kzalloc(sizeof(*hp), GFP_KERNEL);
+ if (hp == NULL) {
+ rc = -ENOMEM;
+ goto err_out_free_ent;
+ }
+
+ /* Set default hotplug offset */
+ hp->hotplug_offset = PDC_SATA_PLUG_CSR;
+ probe_ent->private_data = hp;
+
probe_ent->sht = pdc_port_info[board_idx].sht;
probe_ent->host_flags = pdc_port_info[board_idx].host_flags;
probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask;
@@ -707,6 +744,10 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
/* notice 4-port boards */
switch (board_idx) {
+ case board_40518:
+ /* Override hotplug offset for SATAII150 */
+ hp->hotplug_offset = PDC2_SATA_PLUG_CSR;
+ /* Fall through */
case board_20319:
probe_ent->n_ports = 4;
@@ -716,6 +757,10 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
probe_ent->port[2].scr_addr = base + 0x600;
probe_ent->port[3].scr_addr = base + 0x700;
break;
+ case board_2057x:
+ /* Override hotplug offset for SATAII150 */
+ hp->hotplug_offset = PDC2_SATA_PLUG_CSR;
+ /* Fall through */
case board_2037x:
probe_ent->n_ports = 2;
break;
@@ -741,8 +786,10 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
/* initialize adapter */
pdc_host_init(board_idx, probe_ent);
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
+ /* FIXME: Need any other frees than hp? */
+ if (!ata_device_add(probe_ent))
+ kfree(hp);
+
kfree(probe_ent);
return 0;
diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c
index 80480f0fb2b..9602f43a298 100644
--- a/drivers/scsi/sata_qstor.c
+++ b/drivers/scsi/sata_qstor.c
@@ -120,7 +120,7 @@ static void qs_host_stop(struct ata_host_set *host_set);
static void qs_port_stop(struct ata_port *ap);
static void qs_phy_reset(struct ata_port *ap);
static void qs_qc_prep(struct ata_queued_cmd *qc);
-static int qs_qc_issue(struct ata_queued_cmd *qc);
+static unsigned int qs_qc_issue(struct ata_queued_cmd *qc);
static int qs_check_atapi_dma(struct ata_queued_cmd *qc);
static void qs_bmdma_stop(struct ata_queued_cmd *qc);
static u8 qs_bmdma_status(struct ata_port *ap);
@@ -132,11 +132,11 @@ static struct scsi_host_template qs_ata_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
+ .eh_timed_out = ata_scsi_timed_out,
.eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = QS_MAX_PRD,
- .max_sectors = ATA_MAX_SECTORS,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.emulated = ATA_SHT_EMULATED,
//FIXME .use_clustering = ATA_SHT_USE_CLUSTERING,
@@ -276,8 +276,8 @@ static unsigned int qs_fill_sg(struct ata_queued_cmd *qc)
unsigned int nelem;
u8 *prd = pp->pkt + QS_CPB_BYTES;
- assert(qc->__sg != NULL);
- assert(qc->n_elem > 0 || qc->pad_len > 0);
+ WARN_ON(qc->__sg == NULL);
+ WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
nelem = 0;
ata_for_each_sg(sg, qc) {
@@ -352,7 +352,7 @@ static inline void qs_packet_start(struct ata_queued_cmd *qc)
readl(chan + QS_CCT_CFF); /* flush */
}
-static int qs_qc_issue(struct ata_queued_cmd *qc)
+static unsigned int qs_qc_issue(struct ata_queued_cmd *qc)
{
struct qs_port_priv *pp = qc->ap->private_data;
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
index 9face3c6aa2..4f2a67ed39d 100644
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -49,24 +49,30 @@
#define DRV_VERSION "0.9"
enum {
+ /*
+ * host flags
+ */
SIL_FLAG_RERR_ON_DMA_ACT = (1 << 29),
SIL_FLAG_MOD15WRITE = (1 << 30),
+ SIL_DFL_HOST_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO,
+ /*
+ * Controller IDs
+ */
sil_3112 = 0,
- sil_3112_m15w = 1,
- sil_3512 = 2,
- sil_3114 = 3,
-
- SIL_FIFO_R0 = 0x40,
- SIL_FIFO_W0 = 0x41,
- SIL_FIFO_R1 = 0x44,
- SIL_FIFO_W1 = 0x45,
- SIL_FIFO_R2 = 0x240,
- SIL_FIFO_W2 = 0x241,
- SIL_FIFO_R3 = 0x244,
- SIL_FIFO_W3 = 0x245,
+ sil_3512 = 1,
+ sil_3114 = 2,
+ /*
+ * Register offsets
+ */
SIL_SYSCFG = 0x48,
+
+ /*
+ * Register bits
+ */
+ /* SYSCFG */
SIL_MASK_IDE0_INT = (1 << 22),
SIL_MASK_IDE1_INT = (1 << 23),
SIL_MASK_IDE2_INT = (1 << 24),
@@ -75,9 +81,12 @@ enum {
SIL_MASK_4PORT = SIL_MASK_2PORT |
SIL_MASK_IDE2_INT | SIL_MASK_IDE3_INT,
- SIL_IDE2_BMDMA = 0x200,
-
+ /* BMDMA/BMDMA2 */
SIL_INTR_STEERING = (1 << 1),
+
+ /*
+ * Others
+ */
SIL_QUIRK_MOD15WRITE = (1 << 0),
SIL_QUIRK_UDMA5MAX = (1 << 1),
};
@@ -90,13 +99,13 @@ static void sil_post_set_mode (struct ata_port *ap);
static const struct pci_device_id sil_pci_tbl[] = {
- { 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w },
- { 0x1095, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w },
+ { 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+ { 0x1095, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
{ 0x1095, 0x3512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3512 },
{ 0x1095, 0x3114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3114 },
- { 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w },
- { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w },
- { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w },
+ { 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+ { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+ { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
{ } /* terminate list */
};
@@ -137,11 +146,11 @@ static struct scsi_host_template sil_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
+ .eh_timed_out = ata_scsi_timed_out,
.eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = LIBATA_MAX_PRD,
- .max_sectors = ATA_MAX_SECTORS,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.emulated = ATA_SHT_EMULATED,
.use_clustering = ATA_SHT_USE_CLUSTERING,
@@ -159,7 +168,7 @@ static const struct ata_port_operations sil_ops = {
.check_status = ata_check_status,
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
- .phy_reset = sata_phy_reset,
+ .probe_reset = ata_std_probe_reset,
.post_set_mode = sil_post_set_mode,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -181,19 +190,7 @@ static const struct ata_port_info sil_port_info[] = {
/* sil_3112 */
{
.sht = &sil_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_SRST | ATA_FLAG_MMIO,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = 0x3f, /* udma0-5 */
- .port_ops = &sil_ops,
- },
- /* sil_3112_15w - keep it sync'd w/ sil_3112 */
- {
- .sht = &sil_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_SRST | ATA_FLAG_MMIO |
- SIL_FLAG_MOD15WRITE,
+ .host_flags = SIL_DFL_HOST_FLAGS | SIL_FLAG_MOD15WRITE,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x3f, /* udma0-5 */
@@ -202,9 +199,7 @@ static const struct ata_port_info sil_port_info[] = {
/* sil_3512 */
{
.sht = &sil_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_SRST | ATA_FLAG_MMIO |
- SIL_FLAG_RERR_ON_DMA_ACT,
+ .host_flags = SIL_DFL_HOST_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x3f, /* udma0-5 */
@@ -213,9 +208,7 @@ static const struct ata_port_info sil_port_info[] = {
/* sil_3114 */
{
.sht = &sil_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_SRST | ATA_FLAG_MMIO |
- SIL_FLAG_RERR_ON_DMA_ACT,
+ .host_flags = SIL_DFL_HOST_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x3f, /* udma0-5 */
@@ -229,16 +222,17 @@ static const struct {
unsigned long tf; /* ATA taskfile register block */
unsigned long ctl; /* ATA control/altstatus register block */
unsigned long bmdma; /* DMA register block */
+ unsigned long fifo_cfg; /* FIFO Valid Byte Count and Control */
unsigned long scr; /* SATA control register block */
unsigned long sien; /* SATA Interrupt Enable register */
unsigned long xfer_mode;/* data transfer mode register */
unsigned long sfis_cfg; /* SATA FIS reception config register */
} sil_port[] = {
/* port 0 ... */
- { 0x80, 0x8A, 0x00, 0x100, 0x148, 0xb4, 0x14c },
- { 0xC0, 0xCA, 0x08, 0x180, 0x1c8, 0xf4, 0x1cc },
- { 0x280, 0x28A, 0x200, 0x300, 0x348, 0x2b4, 0x34c },
- { 0x2C0, 0x2CA, 0x208, 0x380, 0x3c8, 0x2f4, 0x3cc },
+ { 0x80, 0x8A, 0x00, 0x40, 0x100, 0x148, 0xb4, 0x14c },
+ { 0xC0, 0xCA, 0x08, 0x44, 0x180, 0x1c8, 0xf4, 0x1cc },
+ { 0x280, 0x28A, 0x200, 0x240, 0x300, 0x348, 0x2b4, 0x34c },
+ { 0x2C0, 0x2CA, 0x208, 0x244, 0x380, 0x3c8, 0x2f4, 0x3cc },
/* ... port 3 */
};
@@ -354,22 +348,12 @@ static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
{
unsigned int n, quirks = 0;
- unsigned char model_num[40];
- const char *s;
- unsigned int len;
+ unsigned char model_num[41];
- ata_dev_id_string(dev->id, model_num, ATA_ID_PROD_OFS,
- sizeof(model_num));
- s = &model_num[0];
- len = strnlen(s, sizeof(model_num));
-
- /* ATAPI specifies that empty space is blank-filled; remove blanks */
- while ((len > 0) && (s[len - 1] == ' '))
- len--;
+ ata_id_c_string(dev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
for (n = 0; sil_blacklist[n].product; n++)
- if (!memcmp(sil_blacklist[n].product, s,
- strlen(sil_blacklist[n].product))) {
+ if (!strcmp(sil_blacklist[n].product, model_num)) {
quirks = sil_blacklist[n].quirk;
break;
}
@@ -380,16 +364,14 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
(quirks & SIL_QUIRK_MOD15WRITE))) {
printk(KERN_INFO "ata%u(%u): applying Seagate errata fix (mod15write workaround)\n",
ap->id, dev->devno);
- ap->host->max_sectors = 15;
- ap->host->hostt->max_sectors = 15;
- dev->flags |= ATA_DFLAG_LOCK_SECTORS;
+ dev->max_sectors = 15;
return;
}
/* limit to udma5 */
if (quirks & SIL_QUIRK_UDMA5MAX) {
printk(KERN_INFO "ata%u(%u): applying Maxtor errata fix %s\n",
- ap->id, dev->devno, s);
+ ap->id, dev->devno, model_num);
ap->udma_mask &= ATA_UDMA5;
return;
}
@@ -431,13 +413,12 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
goto err_out_regions;
- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+ probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
if (probe_ent == NULL) {
rc = -ENOMEM;
goto err_out_regions;
}
- memset(probe_ent, 0, sizeof(*probe_ent));
INIT_LIST_HEAD(&probe_ent->node);
probe_ent->dev = pci_dev_to_dev(pdev);
probe_ent->port_ops = sil_port_info[ent->driver_data].port_ops;
@@ -474,19 +455,12 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (cls) {
cls >>= 3;
cls++; /* cls = (line_size/8)+1 */
- writeb(cls, mmio_base + SIL_FIFO_R0);
- writeb(cls, mmio_base + SIL_FIFO_W0);
- writeb(cls, mmio_base + SIL_FIFO_R1);
- writeb(cls, mmio_base + SIL_FIFO_W1);
- if (ent->driver_data == sil_3114) {
- writeb(cls, mmio_base + SIL_FIFO_R2);
- writeb(cls, mmio_base + SIL_FIFO_W2);
- writeb(cls, mmio_base + SIL_FIFO_R3);
- writeb(cls, mmio_base + SIL_FIFO_W3);
- }
+ for (i = 0; i < probe_ent->n_ports; i++)
+ writew(cls << 8 | cls,
+ mmio_base + sil_port[i].fifo_cfg);
} else
dev_printk(KERN_WARNING, &pdev->dev,
- "cache line size not set. Driver may not function\n");
+ "cache line size not set. Driver may not function\n");
/* Apply R_ERR on DMA activate FIS errata workaround */
if (probe_ent->host_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
@@ -509,10 +483,10 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
irq_mask = SIL_MASK_4PORT;
/* flip the magic "make 4 ports work" bit */
- tmp = readl(mmio_base + SIL_IDE2_BMDMA);
+ tmp = readl(mmio_base + sil_port[2].bmdma);
if ((tmp & SIL_INTR_STEERING) == 0)
writel(tmp | SIL_INTR_STEERING,
- mmio_base + SIL_IDE2_BMDMA);
+ mmio_base + sil_port[2].bmdma);
} else {
irq_mask = SIL_MASK_2PORT;
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index 923130185a9..9a53a5ed38c 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -249,9 +249,9 @@ static u8 sil24_check_status(struct ata_port *ap);
static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg);
static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
-static void sil24_phy_reset(struct ata_port *ap);
+static int sil24_probe_reset(struct ata_port *ap, unsigned int *classes);
static void sil24_qc_prep(struct ata_queued_cmd *qc);
-static int sil24_qc_issue(struct ata_queued_cmd *qc);
+static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
static void sil24_irq_clear(struct ata_port *ap);
static void sil24_eng_timeout(struct ata_port *ap);
static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
@@ -262,6 +262,7 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
static const struct pci_device_id sil24_pci_tbl[] = {
{ 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
+ { 0x8086, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
{ 0x1095, 0x3132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3132 },
{ 0x1095, 0x3131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 },
{ 0x1095, 0x3531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 },
@@ -280,11 +281,11 @@ static struct scsi_host_template sil24_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
+ .eh_timed_out = ata_scsi_timed_out,
.eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = LIBATA_MAX_PRD,
- .max_sectors = ATA_MAX_SECTORS,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.emulated = ATA_SHT_EMULATED,
.use_clustering = ATA_SHT_USE_CLUSTERING,
@@ -305,7 +306,7 @@ static const struct ata_port_operations sil24_ops = {
.tf_read = sil24_tf_read,
- .phy_reset = sil24_phy_reset,
+ .probe_reset = sil24_probe_reset,
.qc_prep = sil24_qc_prep,
.qc_issue = sil24_qc_issue,
@@ -335,8 +336,8 @@ static struct ata_port_info sil24_port_info[] = {
{
.sht = &sil24_sht,
.host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_SRST | ATA_FLAG_MMIO |
- ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(4),
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+ SIL24_NPORTS2FLAG(4),
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x3f, /* udma0-5 */
@@ -346,8 +347,8 @@ static struct ata_port_info sil24_port_info[] = {
{
.sht = &sil24_sht,
.host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_SRST | ATA_FLAG_MMIO |
- ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(2),
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+ SIL24_NPORTS2FLAG(2),
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x3f, /* udma0-5 */
@@ -357,8 +358,8 @@ static struct ata_port_info sil24_port_info[] = {
{
.sht = &sil24_sht,
.host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_SRST | ATA_FLAG_MMIO |
- ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(1),
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+ SIL24_NPORTS2FLAG(1),
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x3f, /* udma0-5 */
@@ -370,7 +371,7 @@ static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev)
{
void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
- if (ap->cdb_len == 16)
+ if (dev->cdb_len == 16)
writel(PORT_CS_CDB16, port + PORT_CTRL_STAT);
else
writel(PORT_CS_CDB16, port + PORT_CTRL_CLR);
@@ -427,14 +428,23 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
*tf = pp->tf;
}
-static int sil24_issue_SRST(struct ata_port *ap)
+static int sil24_softreset(struct ata_port *ap, int verbose,
+ unsigned int *class)
{
void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
struct sil24_port_priv *pp = ap->private_data;
struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
dma_addr_t paddr = pp->cmd_block_dma;
+ unsigned long timeout = jiffies + ATA_TMOUT_BOOT * HZ;
u32 irq_enable, irq_stat;
- int cnt;
+
+ DPRINTK("ENTER\n");
+
+ if (!sata_dev_present(ap)) {
+ DPRINTK("PHY reports no device\n");
+ *class = ATA_DEV_NONE;
+ goto out;
+ }
/* temporarily turn off IRQs during SRST */
irq_enable = readl(port + PORT_IRQ_ENABLE_SET);
@@ -451,7 +461,7 @@ static int sil24_issue_SRST(struct ata_port *ap)
writel((u32)paddr, port + PORT_CMD_ACTIVATE);
- for (cnt = 0; cnt < 100; cnt++) {
+ do {
irq_stat = readl(port + PORT_IRQ_STAT);
writel(irq_stat, port + PORT_IRQ_STAT); /* clear irq */
@@ -459,36 +469,42 @@ static int sil24_issue_SRST(struct ata_port *ap)
if (irq_stat & (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR))
break;
- msleep(1);
- }
+ msleep(100);
+ } while (time_before(jiffies, timeout));
/* restore IRQs */
writel(irq_enable, port + PORT_IRQ_ENABLE_SET);
- if (!(irq_stat & PORT_IRQ_COMPLETE))
- return -1;
+ if (!(irq_stat & PORT_IRQ_COMPLETE)) {
+ DPRINTK("EXIT, srst failed\n");
+ return -EIO;
+ }
- /* update TF */
sil24_update_tf(ap);
+ *class = ata_dev_classify(&pp->tf);
+
+ if (*class == ATA_DEV_UNKNOWN)
+ *class = ATA_DEV_NONE;
+
+ out:
+ DPRINTK("EXIT, class=%u\n", *class);
return 0;
}
-static void sil24_phy_reset(struct ata_port *ap)
+static int sil24_hardreset(struct ata_port *ap, int verbose,
+ unsigned int *class)
{
- struct sil24_port_priv *pp = ap->private_data;
+ unsigned int dummy_class;
- __sata_phy_reset(ap);
- if (ap->flags & ATA_FLAG_PORT_DISABLED)
- return;
-
- if (sil24_issue_SRST(ap) < 0) {
- printk(KERN_ERR DRV_NAME
- " ata%u: SRST failed, disabling port\n", ap->id);
- ap->ops->port_disable(ap);
- return;
- }
+ /* sil24 doesn't report device signature after hard reset */
+ return sata_std_hardreset(ap, verbose, &dummy_class);
+}
- ap->device->class = ata_dev_classify(&pp->tf);
+static int sil24_probe_reset(struct ata_port *ap, unsigned int *classes)
+{
+ return ata_drive_probe_reset(ap, ata_std_probeinit,
+ sil24_softreset, sil24_hardreset,
+ ata_std_postreset, classes);
}
static inline void sil24_fill_sg(struct ata_queued_cmd *qc,
@@ -533,7 +549,7 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
prb = &cb->atapi.prb;
sge = cb->atapi.sge;
memset(cb->atapi.cdb, 0, 32);
- memcpy(cb->atapi.cdb, qc->cdb, ap->cdb_len);
+ memcpy(cb->atapi.cdb, qc->cdb, qc->dev->cdb_len);
if (qc->tf.protocol != ATA_PROT_ATAPI_NODATA) {
if (qc->tf.flags & ATA_TFLAG_WRITE)
@@ -557,7 +573,7 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
sil24_fill_sg(qc, sge);
}
-static int sil24_qc_issue(struct ata_queued_cmd *qc)
+static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
@@ -638,23 +654,10 @@ static void sil24_eng_timeout(struct ata_port *ap)
struct ata_queued_cmd *qc;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (!qc) {
- printk(KERN_ERR "ata%u: BUG: timeout without command\n",
- ap->id);
- return;
- }
- /*
- * hack alert! We cannot use the supplied completion
- * function from inside the ->eh_strategy_handler() thread.
- * libata is the only user of ->eh_strategy_handler() in
- * any kernel, so the default scsi_done() assumes it is
- * not being called from the SCSI EH.
- */
printk(KERN_ERR "ata%u: command timeout\n", ap->id);
- qc->scsidone = scsi_finish_command;
- qc->err_mask |= AC_ERR_OTHER;
- ata_qc_complete(qc);
+ qc->err_mask |= AC_ERR_TIMEOUT;
+ ata_eh_qc_complete(qc);
sil24_reset_controller(ap);
}
@@ -895,6 +898,7 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
probe_ent->sht = pinfo->sht;
probe_ent->host_flags = pinfo->host_flags;
probe_ent->pio_mask = pinfo->pio_mask;
+ probe_ent->mwdma_mask = pinfo->mwdma_mask;
probe_ent->udma_mask = pinfo->udma_mask;
probe_ent->port_ops = pinfo->port_ops;
probe_ent->n_ports = SIL24_FLAG2NPORTS(pinfo->host_flags);
diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c
index 2df8c5632ac..7fd45f86de9 100644
--- a/drivers/scsi/sata_sis.c
+++ b/drivers/scsi/sata_sis.c
@@ -87,11 +87,11 @@ static struct scsi_host_template sis_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
+ .eh_timed_out = ata_scsi_timed_out,
.eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = ATA_MAX_PRD,
- .max_sectors = ATA_MAX_SECTORS,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.emulated = ATA_SHT_EMULATED,
.use_clustering = ATA_SHT_USE_CLUSTERING,
diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c
index d8472563fde..4aaccd53e73 100644
--- a/drivers/scsi/sata_svw.c
+++ b/drivers/scsi/sata_svw.c
@@ -288,11 +288,11 @@ static struct scsi_host_template k2_sata_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
+ .eh_timed_out = ata_scsi_timed_out,
.eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = LIBATA_MAX_PRD,
- .max_sectors = ATA_MAX_SECTORS,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.emulated = ATA_SHT_EMULATED,
.use_clustering = ATA_SHT_USE_CLUSTERING,
diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c
index bc87c16c80d..9f8a7681540 100644
--- a/drivers/scsi/sata_sx4.c
+++ b/drivers/scsi/sata_sx4.c
@@ -174,7 +174,7 @@ static void pdc20621_get_from_dimm(struct ata_probe_ent *pe,
static void pdc20621_put_to_dimm(struct ata_probe_ent *pe,
void *psource, u32 offset, u32 size);
static void pdc20621_irq_clear(struct ata_port *ap);
-static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc);
+static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc);
static struct scsi_host_template pdc_sata_sht = {
@@ -182,11 +182,11 @@ static struct scsi_host_template pdc_sata_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
+ .eh_timed_out = ata_scsi_timed_out,
.eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = LIBATA_MAX_PRD,
- .max_sectors = ATA_MAX_SECTORS,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.emulated = ATA_SHT_EMULATED,
.use_clustering = ATA_SHT_USE_CLUSTERING,
@@ -460,7 +460,7 @@ static void pdc20621_dma_prep(struct ata_queued_cmd *qc)
unsigned int i, idx, total_len = 0, sgt_len;
u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ];
- assert(qc->flags & ATA_QCFLAG_DMAMAP);
+ WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP));
VPRINTK("ata%u: ENTER\n", ap->id);
@@ -678,7 +678,7 @@ static void pdc20621_packet_start(struct ata_queued_cmd *qc)
}
}
-static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc)
+static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc)
{
switch (qc->tf.protocol) {
case ATA_PROT_DMA:
@@ -866,26 +866,12 @@ static void pdc_eng_timeout(struct ata_port *ap)
spin_lock_irqsave(&host_set->lock, flags);
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (!qc) {
- printk(KERN_ERR "ata%u: BUG: timeout without command\n",
- ap->id);
- goto out;
- }
-
- /* hack alert! We cannot use the supplied completion
- * function from inside the ->eh_strategy_handler() thread.
- * libata is the only user of ->eh_strategy_handler() in
- * any kernel, so the default scsi_done() assumes it is
- * not being called from the SCSI EH.
- */
- qc->scsidone = scsi_finish_command;
switch (qc->tf.protocol) {
case ATA_PROT_DMA:
case ATA_PROT_NODATA:
printk(KERN_ERR "ata%u: command timeout\n", ap->id);
qc->err_mask |= __ac_err_mask(ata_wait_idle(ap));
- ata_qc_complete(qc);
break;
default:
@@ -895,12 +881,11 @@ static void pdc_eng_timeout(struct ata_port *ap)
ap->id, qc->tf.command, drv_stat);
qc->err_mask |= ac_err_mask(drv_stat);
- ata_qc_complete(qc);
break;
}
-out:
spin_unlock_irqrestore(&host_set->lock, flags);
+ ata_eh_qc_complete(qc);
DPRINTK("EXIT\n");
}
diff --git a/drivers/scsi/sata_uli.c b/drivers/scsi/sata_uli.c
index 9635ca70097..37a487b7d65 100644
--- a/drivers/scsi/sata_uli.c
+++ b/drivers/scsi/sata_uli.c
@@ -75,11 +75,11 @@ static struct scsi_host_template uli_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
+ .eh_timed_out = ata_scsi_timed_out,
.eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = LIBATA_MAX_PRD,
- .max_sectors = ATA_MAX_SECTORS,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.emulated = ATA_SHT_EMULATED,
.use_clustering = ATA_SHT_USE_CLUSTERING,
diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c
index 6d5b0a794cf..ff65a0b0457 100644
--- a/drivers/scsi/sata_via.c
+++ b/drivers/scsi/sata_via.c
@@ -94,11 +94,11 @@ static struct scsi_host_template svia_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
+ .eh_timed_out = ata_scsi_timed_out,
.eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = LIBATA_MAX_PRD,
- .max_sectors = ATA_MAX_SECTORS,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.emulated = ATA_SHT_EMULATED,
.use_clustering = ATA_SHT_USE_CLUSTERING,
diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c
index e484e8db681..b574379a7a8 100644
--- a/drivers/scsi/sata_vsc.c
+++ b/drivers/scsi/sata_vsc.c
@@ -251,11 +251,11 @@ static struct scsi_host_template vsc_sata_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
+ .eh_timed_out = ata_scsi_timed_out,
.eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = LIBATA_MAX_PRD,
- .max_sectors = ATA_MAX_SECTORS,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.emulated = ATA_SHT_EMULATED,
.use_clustering = ATA_SHT_USE_CLUSTERING,
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index ff82ccfbb10..5d169a2881b 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -584,8 +584,7 @@ static int scsi_request_sense(struct scsi_cmnd *scmd)
* keep a list of pending commands for final completion, and once we
* are ready to leave error handling we handle completion for real.
**/
-static void scsi_eh_finish_cmd(struct scsi_cmnd *scmd,
- struct list_head *done_q)
+void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, struct list_head *done_q)
{
scmd->device->host->host_failed--;
scmd->eh_eflags = 0;
@@ -597,6 +596,7 @@ static void scsi_eh_finish_cmd(struct scsi_cmnd *scmd,
scsi_setup_cmd_retry(scmd);
list_move_tail(&scmd->eh_entry, done_q);
}
+EXPORT_SYMBOL(scsi_eh_finish_cmd);
/**
* scsi_eh_get_sense - Get device sense data.
@@ -1425,7 +1425,7 @@ static void scsi_eh_ready_devs(struct Scsi_Host *shost,
* @done_q: list_head of processed commands.
*
**/
-static void scsi_eh_flush_done_q(struct list_head *done_q)
+void scsi_eh_flush_done_q(struct list_head *done_q)
{
struct scsi_cmnd *scmd, *next;
@@ -1454,6 +1454,7 @@ static void scsi_eh_flush_done_q(struct list_head *done_q)
}
}
}
+EXPORT_SYMBOL(scsi_eh_flush_done_q);
/**
* scsi_unjam_host - Attempt to fix a host which has a cmd that failed.
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index 7410e093a6b..00d7c0ad8cb 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -1066,6 +1066,8 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
port->mapbase = res->start;
port->membase = S3C24XX_VA_UART + (res->start - S3C24XX_PA_UART);
port->irq = platform_get_irq(platdev, 0);
+ if (port->irq < 0)
+ port->irq = 0;
ourport->clk = clk_get(&platdev->dev, "uart");
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index dce9d987f0f..c196f384530 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -378,7 +378,7 @@ const struct usb_device_id *usb_match_id(struct usb_interface *interface,
return NULL;
}
-EXPORT_SYMBOL(usb_match_id);
+EXPORT_SYMBOL_GPL_FUTURE(usb_match_id);
int usb_device_match(struct device *dev, struct device_driver *drv)
{
@@ -446,7 +446,7 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner)
return retval;
}
-EXPORT_SYMBOL(usb_register_driver);
+EXPORT_SYMBOL_GPL_FUTURE(usb_register_driver);
/**
* usb_deregister - unregister a USB driver
@@ -469,4 +469,4 @@ void usb_deregister(struct usb_driver *driver)
usbfs_update_special();
}
-EXPORT_SYMBOL(usb_deregister);
+EXPORT_SYMBOL_GPL_FUTURE(usb_deregister);
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 3785b3f7df1..ca19abe01c5 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -286,7 +286,7 @@ void usb_hcd_omap_remove (struct usb_hcd *, struct platform_device *);
int usb_hcd_omap_probe (const struct hc_driver *driver,
struct platform_device *pdev)
{
- int retval;
+ int retval, irq;
struct usb_hcd *hcd = 0;
struct ohci_hcd *ohci;
@@ -329,7 +329,12 @@ int usb_hcd_omap_probe (const struct hc_driver *driver,
if (retval < 0)
goto err2;
- retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), SA_INTERRUPT);
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ retval = -ENXIO;
+ goto err2;
+ }
+ retval = usb_add_hcd(hcd, irq, SA_INTERRUPT);
if (retval == 0)
return retval;
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index f5079c78ba4..fdebd60a325 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -899,8 +899,6 @@ config FB_RADEON_OLD
Choose this option if you want to use an ATI Radeon graphics card as
a framebuffer device. There are both PCI and AGP versions. You
don't need to choose this to run the Radeon in plain VGA mode.
- There is a product page at
- <http://www.ati.com/na/pages/products/pc/radeon32/index.html>.
config FB_RADEON
tristate "ATI Radeon display support"
diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c
index 3b0e7138344..082759447bf 100644
--- a/drivers/video/epson1355fb.c
+++ b/drivers/video/epson1355fb.c
@@ -607,6 +607,7 @@ static void clearfb16(struct fb_info *info)
static void epson1355fb_platform_release(struct device *device)
{
+ dev_err(device, "This driver is broken, please bug the authors so they will fix it.\n");
}
static int epson1355fb_remove(struct platform_device *dev)
diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index 8a893ce7040..d9831fd4234 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -1457,7 +1457,7 @@ static int __init sa1100fb_probe(struct platform_device *pdev)
int ret, irq;
irq = platform_get_irq(pdev, 0);
- if (irq <= 0)
+ if (irq < 0)
return -EINVAL;
if (!request_mem_region(0xb0100000, 0x10000, "LCD"))
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c
index 53208cb5839..77eed1fd994 100644
--- a/drivers/video/vfb.c
+++ b/drivers/video/vfb.c
@@ -401,6 +401,7 @@ static int __init vfb_setup(char *options)
static void vfb_platform_release(struct device *device)
{
// This is called when the reference count goes to zero.
+ dev_err(device, "This driver is broken, please bug the authors so they will fix it.\n");
}
static int __init vfb_probe(struct platform_device *dev)