diff options
Diffstat (limited to 'drivers')
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], - ¶->filter.mask[1], DMX_FILTER_SIZE-1); + ¶->filter.mask[1], DMX_FILTER_SIZE - 1); memcpy(&(*secfilter)->filter_mode[3], - ¶->filter.mode[1], DMX_FILTER_SIZE-1); + ¶->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) |