diff options
Diffstat (limited to 'drivers')
235 files changed, 18306 insertions, 6315 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index 503d82569449..6d9d7fab77f5 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -15,6 +15,8 @@ obj-$(CONFIG_ACPI) += acpi/ obj-$(CONFIG_PNP) += pnp/ obj-$(CONFIG_ARM_AMBA) += amba/ +obj-$(CONFIG_XEN) += xen/ + # char/ comes before serial/ etc so that the VT console is the boot-time # default. obj-y += char/ diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 88a6fc7fd271..58f1338981bc 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -40,6 +40,7 @@ #include <linux/jiffies.h> #include <linux/kmod.h> #include <linux/seq_file.h> +#include <linux/reboot.h> #include <asm/uaccess.h> #include <acpi/acpi_bus.h> @@ -59,7 +60,6 @@ #define ACPI_THERMAL_NOTIFY_CRITICAL 0xF0 #define ACPI_THERMAL_NOTIFY_HOT 0xF1 #define ACPI_THERMAL_MODE_ACTIVE 0x00 -#define ACPI_THERMAL_PATH_POWEROFF "/sbin/poweroff" #define ACPI_THERMAL_MAX_ACTIVE 10 #define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65 @@ -419,26 +419,6 @@ static int acpi_thermal_get_devices(struct acpi_thermal *tz) return 0; } -static int acpi_thermal_call_usermode(char *path) -{ - char *argv[2] = { NULL, NULL }; - char *envp[3] = { NULL, NULL, NULL }; - - - if (!path) - return -EINVAL; - - argv[0] = path; - - /* minimal command environment */ - envp[0] = "HOME=/"; - envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; - - call_usermodehelper(argv[0], argv, envp, 0); - - return 0; -} - static int acpi_thermal_critical(struct acpi_thermal *tz) { if (!tz || !tz->trips.critical.flags.valid) @@ -456,7 +436,7 @@ static int acpi_thermal_critical(struct acpi_thermal *tz) acpi_bus_generate_event(tz->device, ACPI_THERMAL_NOTIFY_CRITICAL, tz->trips.critical.flags.enabled); - acpi_thermal_call_usermode(ACPI_THERMAL_PATH_POWEROFF); + orderly_poweroff(true); return 0; } diff --git a/drivers/atm/Kconfig b/drivers/atm/Kconfig index bb4ae6281491..bed9f58c2d5a 100644 --- a/drivers/atm/Kconfig +++ b/drivers/atm/Kconfig @@ -172,7 +172,7 @@ config ATM_ZATM_DEBUG config ATM_NICSTAR tristate "IDT 77201 (NICStAR) (ForeRunnerLE)" - depends on PCI && !64BIT + depends on PCI && !64BIT && VIRT_TO_BUS help The NICStAR chipset family is used in a large number of ATM NICs for 25 and for 155 Mbps, including IDT cards and the Fore ForeRunnerLE diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index 77637e780d41..41b2204ebc6e 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -1738,7 +1738,8 @@ static int __devinit eni_do_init(struct atm_dev *dev) printk(KERN_ERR KERN_ERR DEV_LABEL "(itf %d): bad " "magic - expected 0x%x, got 0x%x\n",dev->number, ENI155_MAGIC,(unsigned) readl(&eprom->magic)); - return -EINVAL; + error = -EINVAL; + goto unmap; } } eni_dev->phy = base+PHY_BASE; @@ -1765,17 +1766,27 @@ static int __devinit eni_do_init(struct atm_dev *dev) printk(")\n"); printk(KERN_ERR DEV_LABEL "(itf %d): ERROR - wrong id 0x%x\n", dev->number,(unsigned) eni_in(MID_RES_ID_MCON)); - return -EINVAL; + error = -EINVAL; + goto unmap; } error = eni_dev->asic ? get_esi_asic(dev) : get_esi_fpga(dev,base); - if (error) return error; + if (error) + goto unmap; for (i = 0; i < ESI_LEN; i++) printk("%s%02X",i ? "-" : "",dev->esi[i]); printk(")\n"); printk(KERN_NOTICE DEV_LABEL "(itf %d): %s,%s\n",dev->number, eni_in(MID_RES_ID_MCON) & 0x200 ? "ASIC" : "FPGA", media_name[eni_in(MID_RES_ID_MCON) & DAUGTHER_ID]); - return suni_init(dev); + + error = suni_init(dev); + if (error) + goto unmap; +out: + return error; +unmap: + iounmap(base); + goto out; } diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c index 38b688f9f6a9..737cea49f872 100644 --- a/drivers/atm/firestream.c +++ b/drivers/atm/firestream.c @@ -1710,7 +1710,7 @@ static int __devinit fs_init (struct fs_dev *dev) /* This bit is documented as "RESERVED" */ if (isr & ISR_INIT_ERR) { printk (KERN_ERR "Error initializing the FS... \n"); - return 1; + goto unmap; } if (isr & ISR_INIT) { fs_dprintk (FS_DEBUG_INIT, "Ha! Initialized OK!\n"); @@ -1723,7 +1723,7 @@ static int __devinit fs_init (struct fs_dev *dev) if (!to) { printk (KERN_ERR "timeout initializing the FS... \n"); - return 1; + goto unmap; } /* XXX fix for fs155 */ @@ -1803,7 +1803,7 @@ static int __devinit fs_init (struct fs_dev *dev) if (!dev->atm_vccs) { printk (KERN_WARNING "Couldn't allocate memory for VCC buffers. Woops!\n"); /* XXX Clean up..... */ - return 1; + goto unmap; } dev->tx_inuse = kzalloc (dev->nchannels / 8 /* bits/byte */ , GFP_KERNEL); @@ -1813,7 +1813,7 @@ static int __devinit fs_init (struct fs_dev *dev) if (!dev->tx_inuse) { printk (KERN_WARNING "Couldn't allocate memory for tx_inuse bits!\n"); /* XXX Clean up..... */ - return 1; + goto unmap; } /* -- RAS1 : FS155 and 50 differ. Default (0) should be OK for both */ /* -- RAS2 : FS50 only: Default is OK. */ @@ -1840,7 +1840,7 @@ static int __devinit fs_init (struct fs_dev *dev) if (request_irq (dev->irq, fs_irq, IRQF_SHARED, "firestream", dev)) { printk (KERN_WARNING "couldn't get irq %d for firestream.\n", pci_dev->irq); /* XXX undo all previous stuff... */ - return 1; + goto unmap; } fs_dprintk (FS_DEBUG_INIT, "Grabbed irq %d for dev at %p.\n", dev->irq, dev); @@ -1890,6 +1890,9 @@ static int __devinit fs_init (struct fs_dev *dev) func_exit (); return 0; +unmap: + iounmap(dev->base); + return 1; } static int __devinit firestream_init_one (struct pci_dev *pci_dev, @@ -2012,6 +2015,7 @@ static void __devexit firestream_remove_one (struct pci_dev *pdev) for (i=0;i < FS_NR_RX_QUEUES;i++) free_queue (dev, &dev->rx_rq[i]); + iounmap(dev->base); fs_dprintk (FS_DEBUG_ALLOC, "Free fs-dev: %p\n", dev); nxtdev = dev->next; kfree (dev); diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c index 8f995ce8d73b..f8b1700f4c16 100644 --- a/drivers/atm/idt77252.c +++ b/drivers/atm/idt77252.c @@ -65,7 +65,7 @@ static char const rcsid[] = static unsigned int vpibits = 1; -#define CONFIG_ATM_IDT77252_SEND_IDLE 1 +#define ATM_IDT77252_SEND_IDLE 1 /* @@ -3404,7 +3404,7 @@ init_card(struct atm_dev *dev) conf = SAR_CFG_TX_FIFO_SIZE_9 | /* Use maximum fifo size */ SAR_CFG_RXSTQ_SIZE_8k | /* Receive Status Queue is 8k */ SAR_CFG_IDLE_CLP | /* Set CLP on idle cells */ -#ifndef CONFIG_ATM_IDT77252_SEND_IDLE +#ifndef ATM_IDT77252_SEND_IDLE SAR_CFG_NO_IDLE | /* Do not send idle cells */ #endif 0; @@ -3541,7 +3541,7 @@ init_card(struct atm_dev *dev) printk("%s: Linkrate on ATM line : %u bit/s, %u cell/s.\n", card->name, linkrate, card->link_pcr); -#ifdef CONFIG_ATM_IDT77252_SEND_IDLE +#ifdef ATM_IDT77252_SEND_IDLE card->utopia_pcr = card->link_pcr; #else card->utopia_pcr = (160000000 / 8 / 54); diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c index 0e2c1ae650e7..55fd1b4543fd 100644 --- a/drivers/atm/lanai.c +++ b/drivers/atm/lanai.c @@ -552,8 +552,8 @@ static inline void sram_write(const struct lanai_dev *lanai, writel(val, sram_addr(lanai, offset)); } -static int __init sram_test_word( - const struct lanai_dev *lanai, int offset, u32 pattern) +static int __devinit sram_test_word(const struct lanai_dev *lanai, + int offset, u32 pattern) { u32 readback; sram_write(lanai, pattern, offset); diff --git a/drivers/atm/nicstarmac.c b/drivers/atm/nicstarmac.c index 480947f4e01e..842e26c45557 100644 --- a/drivers/atm/nicstarmac.c +++ b/drivers/atm/nicstarmac.c @@ -134,7 +134,7 @@ nicstar_read_eprom_status( virt_addr_t base ) /* Send read instruction */ val = NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE ) & 0xFFFFFFF0; - for (i=0; i<sizeof rdsrtab/sizeof rdsrtab[0]; i++) + for (i=0; i<ARRAY_SIZE(rdsrtab); i++) { NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE, (val | rdsrtab[i]) ); diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 8f65b88cf711..a4a311992408 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -427,4 +427,13 @@ config XILINX_SYSACE help Include support for the Xilinx SystemACE CompactFlash interface +config XEN_BLKDEV_FRONTEND + tristate "Xen virtual block device support" + depends on XEN + default y + help + This driver implements the front-end of the Xen virtual + block device driver. It communicates with a back-end driver + in another domain which drives the actual block device. + endif # BLK_DEV diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 9ee08ab4ffa8..3e31532df0ed 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -29,3 +29,4 @@ obj-$(CONFIG_VIODASD) += viodasd.o obj-$(CONFIG_BLK_DEV_SX8) += sx8.o obj-$(CONFIG_BLK_DEV_UB) += ub.o +obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c index 0f5e3caf85d7..2288b55d916f 100644 --- a/drivers/block/sunvdc.c +++ b/drivers/block/sunvdc.c @@ -45,8 +45,6 @@ struct vdc_req_entry { struct vdc_port { struct vio_driver_state vio; - struct vdc *vp; - struct gendisk *disk; struct vdc_completion *cmp; @@ -72,8 +70,6 @@ struct vdc_port { struct vio_disk_geom geom; struct vio_disk_vtoc label; - - struct list_head list; }; static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio) @@ -81,15 +77,6 @@ static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio) return container_of(vio, struct vdc_port, vio); } -struct vdc { - /* Protects prot_list. */ - spinlock_t lock; - - struct vio_dev *dev; - - struct list_head port_list; -}; - /* Ordered from largest major to lowest */ static struct vio_version vdc_versions[] = { { .major = 1, .minor = 0 }, @@ -747,21 +734,23 @@ static struct vio_driver_ops vdc_vio_ops = { .handshake_complete = vdc_handshake_complete, }; +static void print_version(void) +{ + static int version_printed; + + if (version_printed++ == 0) + printk(KERN_INFO "%s", version); +} + static int __devinit vdc_port_probe(struct vio_dev *vdev, const struct vio_device_id *id) { struct mdesc_handle *hp; struct vdc_port *port; - unsigned long flags; - struct vdc *vp; const u64 *port_id; int err; - vp = dev_get_drvdata(vdev->dev.parent); - if (!vp) { - printk(KERN_ERR PFX "Cannot find port parent vdc.\n"); - return -ENODEV; - } + print_version(); hp = mdesc_grab(); @@ -783,7 +772,6 @@ static int __devinit vdc_port_probe(struct vio_dev *vdev, goto err_out_release_mdesc; } - port->vp = vp; port->dev_no = *port_id; if (port->dev_no >= 26) @@ -818,12 +806,6 @@ static int __devinit vdc_port_probe(struct vio_dev *vdev, if (err) goto err_out_free_tx_ring; - INIT_LIST_HEAD(&port->list); - - spin_lock_irqsave(&vp->lock, flags); - list_add(&port->list, &vp->port_list); - spin_unlock_irqrestore(&vp->lock, flags); - dev_set_drvdata(&vdev->dev, port); mdesc_release(hp); @@ -879,58 +861,6 @@ static struct vio_driver vdc_port_driver = { } }; -static int __devinit vdc_probe(struct vio_dev *vdev, - const struct vio_device_id *id) -{ - static int vdc_version_printed; - struct vdc *vp; - - if (vdc_version_printed++ == 0) - printk(KERN_INFO "%s", version); - - vp = kzalloc(sizeof(struct vdc), GFP_KERNEL); - if (!vp) - return -ENOMEM; - - spin_lock_init(&vp->lock); - vp->dev = vdev; - INIT_LIST_HEAD(&vp->port_list); - - dev_set_drvdata(&vdev->dev, vp); - - return 0; -} - -static int vdc_remove(struct vio_dev *vdev) -{ - - struct vdc *vp = dev_get_drvdata(&vdev->dev); - - if (vp) { - kfree(vp); - dev_set_drvdata(&vdev->dev, NULL); - } - return 0; -} - -static struct vio_device_id vdc_match[] = { - { - .type = "block", - }, - {}, -}; -MODULE_DEVICE_TABLE(vio, vdc_match); - -static struct vio_driver vdc_driver = { - .id_table = vdc_match, - .probe = vdc_probe, - .remove = vdc_remove, - .driver = { - .name = "vdc", - .owner = THIS_MODULE, - } -}; - static int __init vdc_init(void) { int err; @@ -940,19 +870,13 @@ static int __init vdc_init(void) goto out_err; vdc_major = err; - err = vio_register_driver(&vdc_driver); - if (err) - goto out_unregister_blkdev; err = vio_register_driver(&vdc_port_driver); if (err) - goto out_unregister_vdc; + goto out_unregister_blkdev; return 0; -out_unregister_vdc: - vio_unregister_driver(&vdc_driver); - out_unregister_blkdev: unregister_blkdev(vdc_major, VDCBLK_NAME); vdc_major = 0; @@ -964,7 +888,6 @@ out_err: static void __exit vdc_exit(void) { vio_unregister_driver(&vdc_port_driver); - vio_unregister_driver(&vdc_driver); unregister_blkdev(vdc_major, VDCBLK_NAME); } diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c new file mode 100644 index 000000000000..6746c29181f8 --- /dev/null +++ b/drivers/block/xen-blkfront.c @@ -0,0 +1,988 @@ +/* + * blkfront.c + * + * XenLinux virtual block device driver. + * + * Copyright (c) 2003-2004, Keir Fraser & Steve Hand + * Modifications by Mark A. Williamson are (c) Intel Research Cambridge + * Copyright (c) 2004, Christian Limpach + * Copyright (c) 2004, Andrew Warfield + * Copyright (c) 2005, Christopher Clark + * Copyright (c) 2005, XenSource Ltd + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include <linux/interrupt.h> +#include <linux/blkdev.h> +#include <linux/module.h> + +#include <xen/xenbus.h> +#include <xen/grant_table.h> +#include <xen/events.h> +#include <xen/page.h> + +#include <xen/interface/grant_table.h> +#include <xen/interface/io/blkif.h> + +#include <asm/xen/hypervisor.h> + +enum blkif_state { + BLKIF_STATE_DISCONNECTED, + BLKIF_STATE_CONNECTED, + BLKIF_STATE_SUSPENDED, +}; + +struct blk_shadow { + struct blkif_request req; + unsigned long request; + unsigned long frame[BLKIF_MAX_SEGMENTS_PER_REQUEST]; +}; + +static struct block_device_operations xlvbd_block_fops; + +#define BLK_RING_SIZE __RING_SIZE((struct blkif_sring *)0, PAGE_SIZE) + +/* + * We have one of these per vbd, whether ide, scsi or 'other'. They + * hang in private_data off the gendisk structure. We may end up + * putting all kinds of interesting stuff here :-) + */ +struct blkfront_info +{ + struct xenbus_device *xbdev; + dev_t dev; + struct gendisk *gd; + int vdevice; + blkif_vdev_t handle; + enum blkif_state connected; + int ring_ref; + struct blkif_front_ring ring; + unsigned int evtchn, irq; + struct request_queue *rq; + struct work_struct work; + struct gnttab_free_callback callback; + struct blk_shadow shadow[BLK_RING_SIZE]; + unsigned long shadow_free; + int feature_barrier; + + /** + * The number of people holding this device open. We won't allow a + * hot-unplug unless this is 0. + */ + int users; +}; + +static DEFINE_SPINLOCK(blkif_io_lock); + +#define MAXIMUM_OUTSTANDING_BLOCK_REQS \ + (BLKIF_MAX_SEGMENTS_PER_REQUEST * BLK_RING_SIZE) +#define GRANT_INVALID_REF 0 + +#define PARTS_PER_DISK 16 + +#define BLKIF_MAJOR(dev) ((dev)>>8) +#define BLKIF_MINOR(dev) ((dev) & 0xff) + +#define DEV_NAME "xvd" /* name in /dev */ + +/* Information about our VBDs. */ +#define MAX_VBDS 64 +static LIST_HEAD(vbds_list); + +static int get_id_from_freelist(struct blkfront_info *info) +{ + unsigned long free = info->shadow_free; + BUG_ON(free > BLK_RING_SIZE); + info->shadow_free = info->shadow[free].req.id; + info->shadow[free].req.id = 0x0fffffee; /* debug */ + return free; +} + +static void add_id_to_freelist(struct blkfront_info *info, + unsigned long id) +{ + info->shadow[id].req.id = info->shadow_free; + info->shadow[id].request = 0; + info->shadow_free = id; +} + +static void blkif_restart_queue_callback(void *arg) +{ + struct blkfront_info *info = (struct blkfront_info *)arg; + schedule_work(&info->work); +} + +/* + * blkif_queue_request + * + * request block io + * + * id: for guest use only. + * operation: BLKIF_OP_{READ,WRITE,PROBE} + * buffer: buffer to read/write into. this should be a + * virtual address in the guest os. + */ +static int blkif_queue_request(struct request *req) +{ + struct blkfront_info *info = req->rq_disk->private_data; + unsigned long buffer_mfn; + struct blkif_request *ring_req; + struct bio *bio; + struct bio_vec *bvec; + int idx; + unsigned long id; + unsigned int fsect, lsect; + int ref; + grant_ref_t gref_head; + + if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) + return 1; + + if (gnttab_alloc_grant_references( + BLKIF_MAX_SEGMENTS_PER_REQUEST, &gref_head) < 0) { + gnttab_request_free_callback( + &info->callback, + blkif_restart_queue_callback, + info, + BLKIF_MAX_SEGMENTS_PER_REQUEST); + return 1; + } + + /* Fill out a communications ring structure. */ + ring_req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt); + id = get_id_from_freelist(info); + info->shadow[id].request = (unsigned long)req; + + ring_req->id = id; + ring_req->sector_number = (blkif_sector_t)req->sector; + ring_req->handle = info->handle; + + ring_req->operation = rq_data_dir(req) ? + BLKIF_OP_WRITE : BLKIF_OP_READ; + if (blk_barrier_rq(req)) + ring_req->operation = BLKIF_OP_WRITE_BARRIER; + + ring_req->nr_segments = 0; + rq_for_each_bio (bio, req) { + bio_for_each_segment (bvec, bio, idx) { + BUG_ON(ring_req->nr_segments + == BLKIF_MAX_SEGMENTS_PER_REQUEST); + buffer_mfn = pfn_to_mfn(page_to_pfn(bvec->bv_page)); + fsect = bvec->bv_offset >> 9; + lsect = fsect + (bvec->bv_len >> 9) - 1; + /* install a grant reference. */ + ref = gnttab_claim_grant_reference(&gref_head); + BUG_ON(ref == -ENOSPC); + + gnttab_grant_foreign_access_ref( + ref, + info->xbdev->otherend_id, + buffer_mfn, + rq_data_dir(req) ); + + info->shadow[id].frame[ring_req->nr_segments] = + mfn_to_pfn(buffer_mfn); + + ring_req->seg[ring_req->nr_segments] = + (struct blkif_request_segment) { + .gref = ref, + .first_sect = fsect, + .last_sect = lsect }; + + ring_req->nr_segments++; + } + } + + info->ring.req_prod_pvt++; + + /* Keep a private copy so we can reissue requests when recovering. */ + info->shadow[id].req = *ring_req; + + gnttab_free_grant_references(gref_head); + + return 0; +} + + +static inline void flush_requests(struct blkfront_info *info) +{ + int notify; + + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->ring, notify); + + if (notify) + notify_remote_via_irq(info->irq); +} + +/* + * do_blkif_request + * read a block; request is in a request queue + */ +static void do_blkif_request(request_queue_t *rq) +{ + struct blkfront_info *info = NULL; + struct request *req; + int queued; + + pr_debug("Entered do_blkif_request\n"); + + queued = 0; + + while ((req = elv_next_request(rq)) != NULL) { + info = req->rq_disk->private_data; + if (!blk_fs_request(req)) { + end_request(req, 0); + continue; + } + + if (RING_FULL(&info->ring)) + goto wait; + + pr_debug("do_blk_req %p: cmd %p, sec %lx, " + "(%u/%li) buffer:%p [%s]\n", + req, req->cmd, (unsigned long)req->sector, + req->current_nr_sectors, + req->nr_sectors, req->buffer, + rq_data_dir(req) ? "write" : "read"); + + + blkdev_dequeue_request(req); + if (blkif_queue_request(req)) { + blk_requeue_request(rq, req); +wait: + /* Avoid pointless unplugs. */ + blk_stop_queue(rq); + break; + } + + queued++; + } + + if (queued != 0) + flush_requests(info); +} + +static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size) +{ + request_queue_t *rq; + + rq = blk_init_queue(do_blkif_request, &blkif_io_lock); + if (rq == NULL) + return -1; + + elevator_init(rq, "noop"); + + /* Hard sector size and max sectors impersonate the equiv. hardware. */ + blk_queue_hardsect_size(rq, sector_size); + blk_queue_max_sectors(rq, 512); + + /* Each segment in a request is up to an aligned page in size. */ + blk_queue_segment_boundary(rq, PAGE_SIZE - 1); + blk_queue_max_segment_size(rq, PAGE_SIZE); + + /* Ensure a merged request will fit in a single I/O ring slot. */ + blk_queue_max_phys_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST); + blk_queue_max_hw_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST); + + /* Make sure buffer addresses are sector-aligned. */ + blk_queue_dma_alignment(rq, 511); + + gd->queue = rq; + + return 0; +} + + +static int xlvbd_barrier(struct blkfront_info *info) +{ + int err; + + err = blk_queue_ordered(info->rq, + info->feature_barrier ? QUEUE_ORDERED_DRAIN : QUEUE_ORDERED_NONE, + NULL); + + if (err) + return err; + + printk(KERN_INFO "blkfront: %s: barriers %s\n", + info->gd->disk_name, + info->feature_barrier ? "enabled" : "disabled"); + return 0; +} + + +static int xlvbd_alloc_gendisk(int minor, blkif_sector_t capacity, + int vdevice, u16 vdisk_info, u16 sector_size, + struct blkfront_info *info) +{ + struct gendisk *gd; + int nr_minors = 1; + int err = -ENODEV; + + BUG_ON(info->gd != NULL); + BUG_ON(info->rq != NULL); + + if ((minor % PARTS_PER_DISK) == 0) + nr_minors = PARTS_PER_DISK; + + gd = alloc_disk(nr_minors); + if (gd == NULL) + goto out; + + if (nr_minors > 1) + sprintf(gd->disk_name, "%s%c", DEV_NAME, + 'a' + minor / PARTS_PER_DISK); + else + sprintf(gd->disk_name, "%s%c%d", DEV_NAME, + 'a' + minor / PARTS_PER_DISK, + minor % PARTS_PER_DISK); + + gd->major = XENVBD_MAJOR; + gd->first_minor = minor; + gd->fops = &xlvbd_block_fops; + gd->private_data = info; + gd->driverfs_dev = &(info->xbdev->dev); + set_capacity(gd, capacity); + + if (xlvbd_init_blk_queue(gd, sector_size)) { + del_gendisk(gd); + goto out; + } + + info->rq = gd->queue; + info->gd = gd; + + if (info->feature_barrier) + xlvbd_barrier(info); + + if (vdisk_info & VDISK_READONLY) + set_disk_ro(gd, 1); + + if (vdisk_info & VDISK_REMOVABLE) + gd->flags |= GENHD_FL_REMOVABLE; + + if (vdisk_info & VDISK_CDROM) + gd->flags |= GENHD_FL_CD; + + return 0; + + out: + return err; +} + +static void kick_pending_request_queues(struct blkfront_info *info) +{ + if (!RING_FULL(&info->ring)) { + /* Re-enable calldowns. */ + blk_start_queue(info->rq); + /* Kick things off immediately. */ + do_blkif_request(info->rq); + } +} + +static void blkif_restart_queue(struct work_struct *work) +{ + struct blkfront_info *info = container_of(work, struct blkfront_info, work); + + spin_lock_irq(&blkif_io_lock); + if (info->connected == BLKIF_STATE_CONNECTED) + kick_pending_request_queues(info); + spin_unlock_irq(&blkif_io_lock); +} + +static void blkif_free(struct blkfront_info *info, int suspend) +{ + /* Prevent new requests being issued until we fix things up. */ + spin_lock_irq(&blkif_io_lock); + info->connected = suspend ? + BLKIF_STATE_SUSPENDED : BLKIF_STATE_DISCONNECTED; + /* No more blkif_request(). */ + if (info->rq) + blk_stop_queue(info->rq); + /* No more gnttab callback work. */ + gnttab_cancel_free_callback(&info->callback); + spin_unlock_irq(&blkif_io_lock); + + /* Flush gnttab callback work. Must be done with no locks held. */ + flush_scheduled_work(); + + /* Free resources associated with old device channel. */ + if (info->ring_ref != GRANT_INVALID_REF) { + gnttab_end_foreign_access(info->ring_ref, 0, + (unsigned long)info->ring.sring); + info->ring_ref = GRANT_INVALID_REF; + info->ring.sring = NULL; + } + if (info->irq) + unbind_from_irqhandler(info->irq, info); + info->evtchn = info->irq = 0; + +} + +static void blkif_completion(struct blk_shadow *s) +{ + int i; + for (i = 0; i < s->req.nr_segments; i++) + gnttab_end_foreign_access(s->req.seg[i].gref, 0, 0UL); +} + +static irqreturn_t blkif_interrupt(int irq, void *dev_id) +{ + struct request *req; + struct blkif_response *bret; + RING_IDX i, rp; + unsigned long flags; + struct blkfront_info *info = (struct blkfront_info *)dev_id; + int uptodate; + + spin_lock_irqsave(&blkif_io_lock, flags); + + if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) { + spin_unlock_irqrestore(&blkif_io_lock, flags); + return IRQ_HANDLED; + } + + again: + rp = info->ring.sring->rsp_prod; + rmb(); /* Ensure we see queued responses up to 'rp'. */ + + for (i = info->ring.rsp_cons; i != rp; i++) { + unsigned long id; + int ret; + + bret = RING_GET_RESPONSE(&info->ring, i); + id = bret->id; + req = (struct request *)info->shadow[id].request; + + blkif_completion(&info->shadow[id]); + + add_id_to_freelist(info, id); + + uptodate = (bret->status == BLKIF_RSP_OKAY); + switch (bret->operation) { + case BLKIF_OP_WRITE_BARRIER: + if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) { + printk(KERN_WARNING "blkfront: %s: write barrier op failed\n", + info->gd->disk_name); + uptodate = -EOPNOTSUPP; + info->feature_barrier = 0; + xlvbd_barrier(info); + } + /* fall through */ + case BLKIF_OP_READ: + case BLKIF_OP_WRITE: + if (unlikely(bret->status != BLKIF_RSP_OKAY)) + dev_dbg(&info->xbdev->dev, "Bad return from blkdev data " + "request: %x\n", bret->status); + + ret = end_that_request_first(req, uptodate, + req->hard_nr_sectors); + BUG_ON(ret); + end_that_request_last(req, uptodate); + break; + default: + BUG(); + } + } + + info->ring.rsp_cons = i; + + if (i != info->ring.req_prod_pvt) { + int more_to_do; + RING_FINAL_CHECK_FOR_RESPONSES(&info->ring, more_to_do); + if (more_to_do) + goto again; + } else + info->ring.sring->rsp_event = i + 1; + + kick_pending_request_queues(info); + + spin_unlock_irqrestore(&blkif_io_lock, flags); + + return IRQ_HANDLED; +} + + +static int setup_blkring(struct xenbus_device *dev, + struct blkfront_info *info) +{ + struct blkif_sring *sring; + int err; + + info->ring_ref = GRANT_INVALID_REF; + + sring = (struct blkif_sring *)__get_free_page(GFP_KERNEL); + if (!sring) { + xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring"); + return -ENOMEM; + } + SHARED_RING_INIT(sring); + FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE); + + err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring)); + if (err < 0) { + free_page((unsigned long)sring); + info->ring.sring = NULL; + goto fail; + } + info->ring_ref = err; + + err = xenbus_alloc_evtchn(dev, &info->evtchn); + if (err) + goto fail; + + err = bind_evtchn_to_irqhandler(info->evtchn, + blkif_interrupt, + IRQF_SAMPLE_RANDOM, "blkif", info); + if (err <= 0) { + xenbus_dev_fatal(dev, err, + "bind_evtchn_to_irqhandler failed"); + goto fail; + } + info->irq = err; + + return 0; +fail: + blkif_free(info, 0); + return err; +} + + +/* Common code used when first setting up, and when resuming. */ +static int talk_to_backend(struct xenbus_device *dev, + struct blkfront_info *info) +{ + const char *message = NULL; + struct xenbus_transaction xbt; + int err; + + /* Create shared ring, alloc event channel. */ + err = setup_blkring(dev, info); + if (err) + goto out; + +again: + err = xenbus_transaction_start(&xbt); + if (err) { + xenbus_dev_fatal(dev, err, "starting transaction"); + goto destroy_blkring; + } + + err = xenbus_printf(xbt, dev->nodename, + "ring-ref", "%u", info->ring_ref); + if (err) { + message = "writing ring-ref"; + goto abort_transaction; + } + err = xenbus_printf(xbt, dev->nodename, + "event-channel", "%u", info->evtchn); + if (err) { + message = "writing event-channel"; + goto abort_transaction; + } + + err = xenbus_transaction_end(xbt, 0); + if (err) { + if (err == -EAGAIN) + goto again; + xenbus_dev_fatal(dev, err, "completing transaction"); + goto destroy_blkring; + } + + xenbus_switch_state(dev, XenbusStateInitialised); + + return 0; + + abort_transaction: + xenbus_transaction_end(xbt, 1); + if (message) + xenbus_dev_fatal(dev, err, "%s", message); + destroy_blkring: + blkif_free(info, 0); + out: + return err; +} + + +/** + * Entry point to this code when a new device is created. Allocate the basic + * structures and the ring buffer for communication with the backend, and + * inform the backend of the appropriate details for those. Switch to + * Initialised state. + */ +static int blkfront_probe(struct xenbus_device *dev, + const struct xenbus_device_id *id) +{ + int err, vdevice, i; + struct blkfront_info *info; + + /* FIXME: Use dynamic device id if this is not set. */ + err = xenbus_scanf(XBT_NIL, dev->nodename, + "virtual-device", "%i", &vdevice); + if (err != 1) { + xenbus_dev_fatal(dev, err, "reading virtual-device"); + return err; + } + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); + return -ENOMEM; + } + + info->xbdev = dev; + info->vdevice = vdevice; + info->connected = BLKIF_STATE_DISCONNECTED; + INIT_WORK(&info->work, blkif_restart_queue); + + for (i = 0; i < BLK_RING_SIZE; i++) + info->shadow[i].req.id = i+1; + info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff; + + /* Front end dir is a number, which is used as the id. */ + info->handle = simple_strtoul(strrchr(dev->nodename, '/')+1, NULL, 0); + dev->dev.driver_data = info; + + err = talk_to_backend(dev, info); + if (err) { + kfree(info); + dev->dev.driver_data = NULL; + return err; + } + + return 0; +} + + +static int blkif_recover(struct blkfront_info *info) +{ + int i; + struct blkif_request *req; + struct blk_shadow *copy; + int j; + + /* Stage 1: Make a safe copy of the shadow state. */ + copy = kmalloc(sizeof(info->shadow), GFP_KERNEL); + if (!copy) + return -ENOMEM; + memcpy(copy, info->shadow, sizeof(info->shadow)); + + /* Stage 2: Set up free list. */ + memset(&info->shadow, 0, sizeof(info->shadow)); + for (i = 0; i < BLK_RING_SIZE; i++) + info->shadow[i].req.id = i+1; + info->shadow_free = info->ring.req_prod_pvt; + info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff; + + /* Stage 3: Find pending requests and requeue them. */ + for (i = 0; i < BLK_RING_SIZE; i++) { + /* Not in use? */ + if (copy[i].request == 0) + continue; + + /* Grab a request slot and copy shadow state into it. */ + req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt); + *req = copy[i].req; + + /* We get a new request id, and must reset the shadow state. */ + req->id = get_id_from_freelist(info); + memcpy(&info->shadow[req->id], ©[i], sizeof(copy[i])); + + /* Rewrite any grant references invalidated by susp/resume. */ + for (j = 0; j < req->nr_segments; j++) + gnttab_grant_foreign_access_ref( + req->seg[j].gref, + info->xbdev->otherend_id, + pfn_to_mfn(info->shadow[req->id].frame[j]), + rq_data_dir( + (struct request *) + info->shadow[req->id].request)); + info->shadow[req->id].req = *req; + + info->ring.req_prod_pvt++; + } + + kfree(copy); + + xenbus_switch_state(info->xbdev, XenbusStateConnected); + + spin_lock_irq(&blkif_io_lock); + + /* Now safe for us to use the shared ring */ + info->connected = BLKIF_STATE_CONNECTED; + + /* Send off requeued requests */ + flush_requests(info); + + /* Kick any other new requests queued since we resumed */ + kick_pending_request_queues(info); + + spin_unlock_irq(&blkif_io_lock); + + return 0; +} + +/** + * We are reconnecting to the backend, due to a suspend/resume, or a backend + * driver restart. We tear down our blkif structure and recreate it, but + * leave the device-layer structures intact so that this is transparent to the + * rest of the kernel. + */ +static int blkfront_resume(struct xenbus_device *dev) +{ + struct blkfront_info *info = dev->dev.driver_data; + int err; + + dev_dbg(&dev->dev, "blkfront_resume: %s\n", dev->nodename); + + blkif_free(info, info->connected == BLKIF_STATE_CONNECTED); + + err = talk_to_backend(dev, info); + if (info->connected == BLKIF_STATE_SUSPENDED && !err) + err = blkif_recover(info); + + return err; +} + + +/* + * Invoked when the backend is finally 'ready' (and has told produced + * the details about the physical device - #sectors, size, etc). + */ +static void blkfront_connect(struct blkfront_info *info) +{ + unsigned long long sectors; + unsigned long sector_size; + unsigned int binfo; + int err; + + if ((info->connected == BLKIF_STATE_CONNECTED) || + (info->connected == BLKIF_STATE_SUSPENDED) ) + return; + + dev_dbg(&info->xbdev->dev, "%s:%s.\n", + __func__, info->xbdev->otherend); + + err = xenbus_gather(XBT_NIL, info->xbdev->otherend, + "sectors", "%llu", §ors, + "info", "%u", &binfo, + "sector-size", "%lu", §or_size, + NULL); + if (err) { + xenbus_dev_fatal(info->xbdev, err, + "reading backend fields at %s", + info->xbdev->otherend); + return; + } + + err = xenbus_gather(XBT_NIL, info->xbdev->otherend, + "feature-barrier", "%lu", &info->feature_barrier, + NULL); + if (err) + info->feature_barrier = 0; + + err = xlvbd_alloc_gendisk(BLKIF_MINOR(info->vdevice), + sectors, info->vdevice, + binfo, sector_size, info); + if (err) { + xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s", + info->xbdev->otherend); + return; + } + + xenbus_switch_state(info->xbdev, XenbusStateConnected); + + /* Kick pending requests. */ + spin_lock_irq(&blkif_io_lock); + info->connected = BLKIF_STATE_CONNECTED; + kick_pending_request_queues(info); + spin_unlock_irq(&blkif_io_lock); + + add_disk(info->gd); +} + +/** + * Handle the change of state of the backend to Closing. We must delete our + * device-layer structures now, to ensure that writes are flushed through to + * the backend. Once is this done, we can switch to Closed in + * acknowledgement. + */ +static void blkfront_closing(struct xenbus_device *dev) +{ + struct blkfront_info *info = dev->dev.driver_data; + unsigned long flags; + + dev_dbg(&dev->dev, "blkfront_closing: %s removed\n", dev->nodename); + + if (info->rq == NULL) + goto out; + + spin_lock_irqsave(&blkif_io_lock, flags); + + del_gendisk(info->gd); + + /* No more blkif_request(). */ + blk_stop_queue(info->rq); + + /* No more gnttab callback work. */ + gnttab_cancel_free_callback(&info->callback); + spin_unlock_irqrestore(&blkif_io_lock, flags); + + /* Flush gnttab callback work. Must be done with no locks held. */ + flush_scheduled_work(); + + blk_cleanup_queue(info->rq); + info->rq = NULL; + + out: + xenbus_frontend_closed(dev); +} + +/** + * Callback received when the backend's state changes. + */ +static void backend_changed(struct xenbus_device *dev, + enum xenbus_state backend_state) +{ + struct blkfront_info *info = dev->dev.driver_data; + struct block_device *bd; + + dev_dbg(&dev->dev, "blkfront:backend_changed.\n"); + + switch (backend_state) { + case XenbusStateInitialising: + case XenbusStateInitWait: + case XenbusStateInitialised: + case XenbusStateUnknown: + case XenbusStateClosed: + break; + + case XenbusStateConnected: + blkfront_connect(info); + break; + + case XenbusStateClosing: + bd = bdget(info->dev); + if (bd == NULL) + xenbus_dev_fatal(dev, -ENODEV, "bdget failed"); + + mutex_lock(&bd->bd_mutex); + if (info->users > 0) + xenbus_dev_error(dev, -EBUSY, + "Device in use; refusing to close"); + else + blkfront_closing(dev); + mutex_unlock(&bd->bd_mutex); + bdput(bd); + break; + } +} + +static int blkfront_remove(struct xenbus_device *dev) +{ + struct blkfront_info *info = dev->dev.driver_data; + + dev_dbg(&dev->dev, "blkfront_remove: %s removed\n", dev->nodename); + + blkif_free(info, 0); + + kfree(info); + + return 0; +} + +static int blkif_open(struct inode *inode, struct file *filep) +{ + struct blkfront_info *info = inode->i_bdev->bd_disk->private_data; + info->users++; + return 0; +} + +static int blkif_release(struct inode *inode, struct file *filep) +{ + struct blkfront_info *info = inode->i_bdev->bd_disk->private_data; + info->users--; + if (info->users == 0) { + /* Check whether we have been instructed to close. We will + have ignored this request initially, as the device was + still mounted. */ + struct xenbus_device *dev = info->xbdev; + enum xenbus_state state = xenbus_read_driver_state(dev->otherend); + + if (state == XenbusStateClosing) + blkfront_closing(dev); + } + return 0; +} + +static struct block_device_operations xlvbd_block_fops = +{ + .owner = THIS_MODULE, + .open = blkif_open, + .release = blkif_release, +}; + + +static struct xenbus_device_id blkfront_ids[] = { + { "vbd" }, + { "" } +}; + +static struct xenbus_driver blkfront = { + .name = "vbd", + .owner = THIS_MODULE, + .ids = blkfront_ids, + .probe = blkfront_probe, + .remove = blkfront_remove, + .resume = blkfront_resume, + .otherend_changed = backend_changed, +}; + +static int __init xlblk_init(void) +{ + if (!is_running_on_xen()) + return -ENODEV; + + if (register_blkdev(XENVBD_MAJOR, DEV_NAME)) { + printk(KERN_WARNING "xen_blk: can't get major %d with name %s\n", + XENVBD_MAJOR, DEV_NAME); + return -ENODEV; + } + + return xenbus_register_frontend(&blkfront); +} +module_init(xlblk_init); + + +static void xlblk_exit(void) +{ + return xenbus_unregister_driver(&blkfront); +} +module_exit(xlblk_exit); + +MODULE_DESCRIPTION("Xen virtual block device frontend"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_BLOCKDEV_MAJOR(XENVBD_MAJOR); diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index d8d7125529c4..9e8f21410d2d 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -372,39 +372,6 @@ config ISTALLION To compile this driver as a module, choose M here: the module will be called istallion. -config SERIAL_DEC - bool "DECstation serial support" - depends on MACH_DECSTATION - default y - help - This selects whether you want to be asked about drivers for - DECstation serial ports. - - Note that the answer to this question won't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about DECstation serial ports. - -config SERIAL_DEC_CONSOLE - bool "Support for console on a DECstation serial port" - depends on SERIAL_DEC - default y - help - If you say Y here, it will be possible to use a serial port as the - system console (the system console is the device which receives all - kernel messages and warnings and which allows logins in single user - mode). Note that the firmware uses ttyS0 as the serial console on - the Maxine and ttyS2 on the others. - - If unsure, say Y. - -config ZS - bool "Z85C30 Serial Support" - depends on SERIAL_DEC - default y - help - Documentation on the Zilog 85C350 serial communications controller - is downloadable at <http://www.zilog.com/pdfs/serial/z85c30.pdf> - config A2232 tristate "Commodore A2232 serial support (EXPERIMENTAL)" depends on EXPERIMENTAL && ZORRO && BROKEN_ON_SMP @@ -637,6 +604,14 @@ config HVC_BEAT help Toshiba's Cell Reference Set Beat Console device driver +config HVC_XEN + bool "Xen Hypervisor Console support" + depends on XEN + select HVC_DRIVER + default y + help + Xen virtual console device driver + config HVCS tristate "IBM Hypervisor Virtual Console Server support" depends on PPC_PSERIES diff --git a/drivers/char/Makefile b/drivers/char/Makefile index f2996a95eb07..8852b8d643cf 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o obj-$(CONFIG_HVC_BEAT) += hvc_beat.o obj-$(CONFIG_HVC_DRIVER) += hvc_console.o +obj-$(CONFIG_HVC_XEN) += hvc_xen.o obj-$(CONFIG_RAW_DRIVER) += raw.o obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o obj-$(CONFIG_MSPEC) += mspec.o diff --git a/drivers/char/decserial.c b/drivers/char/decserial.c deleted file mode 100644 index 8ea2bea2b183..000000000000 --- a/drivers/char/decserial.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * sercons.c - * choose the right serial device at boot time - * - * triemer 6-SEP-1998 - * sercons.c is designed to allow the three different kinds - * of serial devices under the decstation world to co-exist - * in the same kernel. The idea here is to abstract - * the pieces of the drivers that are common to this file - * so that they do not clash at compile time and runtime. - * - * HK 16-SEP-1998 v0.002 - * removed the PROM console as this is not a real serial - * device. Added support for PROM console in drivers/char/tty_io.c - * instead. Although it may work to enable more than one - * console device I strongly recommend to use only one. - */ - -#include <linux/init.h> -#include <asm/dec/machtype.h> - -#ifdef CONFIG_ZS -extern int zs_init(void); -#endif - -#ifdef CONFIG_SERIAL_CONSOLE - -#ifdef CONFIG_ZS -extern void zs_serial_console_init(void); -#endif - -#endif - -/* rs_init - starts up the serial interface - - handle normal case of starting up the serial interface */ - -#ifdef CONFIG_SERIAL - -int __init rs_init(void) -{ -#ifdef CONFIG_ZS - if (IOASIC) - return zs_init(); -#endif - return -ENXIO; -} - -__initcall(rs_init); - -#endif - -#ifdef CONFIG_SERIAL_CONSOLE - -/* serial_console_init handles the special case of starting - * up the console on the serial port - */ -static int __init decserial_console_init(void) -{ -#ifdef CONFIG_ZS - if (IOASIC) - zs_serial_console_init(); -#endif - return 0; -} -console_initcall(decserial_console_init); - -#endif diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c new file mode 100644 index 000000000000..dd68f8541c2d --- /dev/null +++ b/drivers/char/hvc_xen.c @@ -0,0 +1,159 @@ +/* + * xen console driver interface to hvc_console.c + * + * (c) 2007 Gerd Hoffmann <kraxel@suse.de> + * + * 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/console.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/types.h> + +#include <asm/xen/hypervisor.h> +#include <xen/page.h> +#include <xen/events.h> +#include <xen/interface/io/console.h> +#include <xen/hvc-console.h> + +#include "hvc_console.h" + +#define HVC_COOKIE 0x58656e /* "Xen" in hex */ + +static struct hvc_struct *hvc; +static int xencons_irq; + +/* ------------------------------------------------------------------ */ + +static inline struct xencons_interface *xencons_interface(void) +{ + return mfn_to_virt(xen_start_info->console.domU.mfn); +} + +static inline void notify_daemon(void) +{ + /* Use evtchn: this is called early, before irq is set up. */ + notify_remote_via_evtchn(xen_start_info->console.domU.evtchn); +} + +static int write_console(uint32_t vtermno, const char *data, int len) +{ + struct xencons_interface *intf = xencons_interface(); + XENCONS_RING_IDX cons, prod; + int sent = 0; + + cons = intf->out_cons; + prod = intf->out_prod; + mb(); /* update queue values before going on */ + BUG_ON((prod - cons) > sizeof(intf->out)); + + while ((sent < len) && ((prod - cons) < sizeof(intf->out))) + intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++]; + + wmb(); /* write ring before updating pointer */ + intf->out_prod = prod; + + notify_daemon(); + return sent; +} + +static int read_console(uint32_t vtermno, char *buf, int len) +{ + struct xencons_interface *intf = xencons_interface(); + XENCONS_RING_IDX cons, prod; + int recv = 0; + + cons = intf->in_cons; + prod = intf->in_prod; + mb(); /* get pointers before reading ring */ + BUG_ON((prod - cons) > sizeof(intf->in)); + + while (cons != prod && recv < len) + buf[recv++] = intf->in[MASK_XENCONS_IDX(cons++, intf->in)]; + + mb(); /* read ring before consuming */ + intf->in_cons = cons; + + notify_daemon(); + return recv; +} + +static struct hv_ops hvc_ops = { + .get_chars = read_console, + .put_chars = write_console, +}; + +static int __init xen_init(void) +{ + struct hvc_struct *hp; + + if (!is_running_on_xen()) + return 0; + + xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn); + if (xencons_irq < 0) + xencons_irq = 0 /* NO_IRQ */; + hp = hvc_alloc(HVC_COOKIE, xencons_irq, &hvc_ops, 256); + if (IS_ERR(hp)) + return PTR_ERR(hp); + + hvc = hp; + return 0; +} + +static void __exit xen_fini(void) +{ + if (hvc) + hvc_remove(hvc); +} + +static int xen_cons_init(void) +{ + if (!is_running_on_xen()) + return 0; + + hvc_instantiate(HVC_COOKIE, 0, &hvc_ops); + return 0; +} + +module_init(xen_init); +module_exit(xen_fini); +console_initcall(xen_cons_init); + +static void xenboot_write_console(struct console *console, const char *string, + unsigned len) +{ + unsigned int linelen, off = 0; + const char *pos; + + while (off < len && NULL != (pos = strchr(string+off, '\n'))) { + linelen = pos-string+off; + if (off + linelen > len) + break; + write_console(0, string+off, linelen); + write_console(0, "\r\n", 2); + off += linelen + 1; + } + if (off < len) + write_console(0, string+off, len-off); +} + +struct console xenboot_console = { + .name = "xenboot", + .write = xenboot_write_console, + .flags = CON_PRINTBUFFER | CON_BOOT, +}; diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 41476abc0693..db703758db98 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -224,6 +224,7 @@ ohci_update_phy_reg(struct fw_card *card, int addr, u32 val, old; reg_write(ohci, OHCI1394_PhyControl, OHCI1394_PhyControl_Read(addr)); + flush_writes(ohci); msleep(2); val = reg_read(ohci, OHCI1394_PhyControl); if ((val & OHCI1394_PhyControl_ReadDone) == 0) { @@ -586,7 +587,7 @@ static void context_stop(struct context *ctx) break; fw_notify("context_stop: still active (0x%08x)\n", reg); - msleep(1); + mdelay(1); } } diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index 7c53be0387fb..fc984474162c 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c @@ -840,7 +840,6 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status) container_of(base_orb, struct sbp2_command_orb, base); struct fw_unit *unit = orb->unit; struct fw_device *device = fw_device(unit->device.parent); - struct scatterlist *sg; int result; if (status != NULL) { @@ -876,11 +875,10 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status) dma_unmap_single(device->card->device, orb->base.request_bus, sizeof(orb->request), DMA_TO_DEVICE); - if (orb->cmd->use_sg > 0) { - sg = (struct scatterlist *)orb->cmd->request_buffer; - dma_unmap_sg(device->card->device, sg, orb->cmd->use_sg, + if (scsi_sg_count(orb->cmd) > 0) + dma_unmap_sg(device->card->device, scsi_sglist(orb->cmd), + scsi_sg_count(orb->cmd), orb->cmd->sc_data_direction); - } if (orb->page_table_bus != 0) dma_unmap_single(device->card->device, orb->page_table_bus, @@ -901,8 +899,8 @@ static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb) int sg_len, l, i, j, count; dma_addr_t sg_addr; - sg = (struct scatterlist *)orb->cmd->request_buffer; - count = dma_map_sg(device->card->device, sg, orb->cmd->use_sg, + sg = scsi_sglist(orb->cmd); + count = dma_map_sg(device->card->device, sg, scsi_sg_count(orb->cmd), orb->cmd->sc_data_direction); if (count == 0) goto fail; @@ -971,7 +969,7 @@ static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb) return 0; fail_page_table: - dma_unmap_sg(device->card->device, sg, orb->cmd->use_sg, + dma_unmap_sg(device->card->device, sg, scsi_sg_count(orb->cmd), orb->cmd->sc_data_direction); fail: return -ENOMEM; @@ -1031,7 +1029,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) orb->request.misc |= COMMAND_ORB_DIRECTION(SBP2_DIRECTION_TO_MEDIA); - if (cmd->use_sg && sbp2_command_orb_map_scatterlist(orb) < 0) + if (scsi_sg_count(cmd) && sbp2_command_orb_map_scatterlist(orb) < 0) goto fail_mapping; fw_memcpy_to_be32(&orb->request, &orb->request, sizeof(orb->request)); diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c index 80d0121463d0..3ce8e2fbe15f 100644 --- a/drivers/firewire/fw-transaction.c +++ b/drivers/firewire/fw-transaction.c @@ -605,8 +605,10 @@ fw_send_response(struct fw_card *card, struct fw_request *request, int rcode) * check is sufficient to ensure we don't send response to * broadcast packets or posted writes. */ - if (request->ack != ACK_PENDING) + if (request->ack != ACK_PENDING) { + kfree(request); return; + } if (rcode == RCODE_COMPLETE) fw_fill_response(&request->response, request->request_header, @@ -628,11 +630,6 @@ fw_core_handle_request(struct fw_card *card, struct fw_packet *p) unsigned long flags; int tcode, destination, source; - if (p->payload_length > 2048) { - /* FIXME: send error response. */ - return; - } - if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE) return; diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h index 5abed193f4a6..5ceaccd10564 100644 --- a/drivers/firewire/fw-transaction.h +++ b/drivers/firewire/fw-transaction.h @@ -123,6 +123,10 @@ typedef void (*fw_transaction_callback_t)(struct fw_card *card, int rcode, size_t length, void *callback_data); +/* + * Important note: The callback must guarantee that either fw_send_response() + * or kfree() is called on the @request. + */ typedef void (*fw_address_callback_t)(struct fw_card *card, struct fw_request *request, int tcode, int destination, int source, diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c index dbb22403979f..3d90fc002097 100644 --- a/drivers/macintosh/therm_pm72.c +++ b/drivers/macintosh/therm_pm72.c @@ -1770,7 +1770,8 @@ static int call_critical_overtemp(void) "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; - return call_usermodehelper(critical_overtemp_path, argv, envp, 0); + return call_usermodehelper(critical_overtemp_path, + argv, envp, UMH_WAIT_EXEC); } diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c index e18d265d5d33..516d943227e2 100644 --- a/drivers/macintosh/windfarm_core.c +++ b/drivers/macintosh/windfarm_core.c @@ -80,7 +80,8 @@ int wf_critical_overtemp(void) "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; - return call_usermodehelper(critical_overtemp_path, argv, envp, 0); + return call_usermodehelper(critical_overtemp_path, + argv, envp, UMH_WAIT_EXEC); } EXPORT_SYMBOL_GPL(wf_critical_overtemp); diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c index 3d65917a1bbb..8fe81e1807e0 100644 --- a/drivers/md/dm-exception-store.c +++ b/drivers/md/dm-exception-store.c @@ -623,6 +623,7 @@ int dm_create_persistent(struct exception_store *store) ps->metadata_wq = create_singlethread_workqueue("ksnaphd"); if (!ps->metadata_wq) { + kfree(ps); DMERR("couldn't start header metadata update thread"); return -ENOMEM; } diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 624b21cef5b3..d9d033e07e19 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -80,8 +80,12 @@ config VIDEO_BUF_DVB config VIDEO_BTCX tristate +config VIDEO_IR_I2C + tristate + config VIDEO_IR tristate + select VIDEO_IR_I2C if I2C config VIDEO_TVEEPROM tristate diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c index fcb194135627..fe447a06e24e 100644 --- a/drivers/media/common/ir-functions.c +++ b/drivers/media/common/ir-functions.c @@ -107,21 +107,20 @@ void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir, } /* -------------------------------------------------------------------------- */ - +/* extract mask bits out of data and pack them into the result */ u32 ir_extract_bits(u32 data, u32 mask) { - int mbit, vbit; - u32 value; + u32 vbit = 1, value = 0; + + do { + if (mask&1) { + if (data&1) + value |= vbit; + vbit<<=1; + } + data>>=1; + } while (mask>>=1); - 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; } diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c index ef3e54cd9407..ba6701e97671 100644 --- a/drivers/media/common/saa7146_core.c +++ b/drivers/media/common/saa7146_core.c @@ -27,7 +27,7 @@ static int saa7146_num; unsigned int saa7146_debug; -module_param(saa7146_debug, int, 0644); +module_param(saa7146_debug, uint, 0644); MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)"); #if 0 @@ -130,10 +130,10 @@ static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages) /********************************************************************************/ /* common page table functions */ -char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt) +void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt) { int pages = (length+PAGE_SIZE-1)/PAGE_SIZE; - char *mem = vmalloc_32(length); + void *mem = vmalloc_32(length); int slen = 0; if (NULL == mem) @@ -168,7 +168,7 @@ err_null: return NULL; } -void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, char *mem, struct saa7146_pgtable *pt) +void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt) { pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE); saa7146_pgtable_free(pci, pt); diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index e3d04a4cef4d..664280c78ff2 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c @@ -889,9 +889,9 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int DEB_EE(("VIDIOC_QUERYCAP\n")); - strcpy(cap->driver, "saa7146 v4l2"); - strlcpy(cap->card, dev->ext->name, sizeof(cap->card)); - sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci)); + strcpy((char *)cap->driver, "saa7146 v4l2"); + strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card)); + sprintf((char *)cap->bus_info,"PCI:%s", pci_name(dev->pci)); cap->version = SAA7146_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | @@ -968,7 +968,7 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int } memset(f,0,sizeof(*f)); f->index = index; - strlcpy(f->description,formats[index].name,sizeof(f->description)); + strlcpy((char *)f->description,formats[index].name,sizeof(f->description)); f->pixelformat = formats[index].pixelformat; break; } diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig index a0dcd59da76e..3197aeb61d1f 100644 --- a/drivers/media/dvb/b2c2/Kconfig +++ b/drivers/media/dvb/b2c2/Kconfig @@ -1,7 +1,7 @@ config DVB_B2C2_FLEXCOP tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters" depends on DVB_CORE && I2C - select DVB_PLL + select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_MT352 if !DVB_FE_CUSTOMISE select DVB_MT312 if !DVB_FE_CUSTOMISE diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile index bff00b58bf65..e97ff60a1eff 100644 --- a/drivers/media/dvb/b2c2/Makefile +++ b/drivers/media/dvb/b2c2/Makefile @@ -12,4 +12,4 @@ obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o b2c2-flexcop-usb-objs = flexcop-usb.o obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o -EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c index b02c2fd65baa..0378fd646591 100644 --- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c +++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c @@ -500,13 +500,13 @@ int flexcop_frontend_init(struct flexcop_device *fc) /* try the air atsc 2nd generation (nxt2002) */ if ((fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, &fc->i2c_adap)) != NULL) { fc->dev_type = FC_AIR_ATSC2; - dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, &dvb_pll_samsung_tbmv); + dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, DVB_PLL_SAMSUNG_TBMV); info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address); } else /* try the air atsc 3nd generation (lgdt3303) */ if ((fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) { fc->dev_type = FC_AIR_ATSC3; - dvb_attach(dvb_pll_attach, fc->fe, 0x61, &fc->i2c_adap, &dvb_pll_lg_tdvs_h06xf); + dvb_attach(dvb_pll_attach, fc->fe, 0x61, &fc->i2c_adap, DVB_PLL_LG_TDVS_H06XF); info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address); } else /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */ diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig index cfd6fb729a61..ea666174e988 100644 --- a/drivers/media/dvb/bt8xx/Kconfig +++ b/drivers/media/dvb/bt8xx/Kconfig @@ -7,7 +7,7 @@ config DVB_BT8XX select DVB_CX24110 if !DVB_FE_CUSTOMISE select DVB_OR51211 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select DVB_PLL + select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_ZL10353 if !DVB_FE_CUSTOMISE select FW_LOADER help diff --git a/drivers/media/dvb/bt8xx/Makefile b/drivers/media/dvb/bt8xx/Makefile index 9d197efb481d..84cf70504d17 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/bt8xx -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/dst.c b/drivers/media/dvb/bt8xx/dst.c index e908e3cf1e50..b7a17e69ca4d 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -1652,7 +1652,7 @@ static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_paramet static int dst_tune_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* p, unsigned int mode_flags, - int *delay, + unsigned int *delay, fe_status_t *status) { struct dst_state *state = fe->demodulator_priv; diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index 4f1c09bee538..67613eb6fa3d 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -611,7 +611,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter); if (card->fe != NULL) { dvb_attach(dvb_pll_attach, card->fe, 0x61, - card->i2c_adapter, &dvb_pll_lg_tdvs_h06xf); + card->i2c_adapter, DVB_PLL_LG_TDVS_H06XF); dprintk ("dvb_bt8xx: lgdt330x detected\n"); } break; @@ -692,6 +692,9 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) case BTTV_BOARD_PC_HDTV: card->fe = dvb_attach(or51211_attach, &or51211_config, card->i2c_adapter); + if (card->fe != NULL) + dvb_attach(dvb_pll_attach, card->fe, 0x61, + card->i2c_adapter, DVB_PLL_FCV1236D); break; } diff --git a/drivers/media/dvb/cinergyT2/Makefile b/drivers/media/dvb/cinergyT2/Makefile index c51aece20f9f..d762d8cb0cf1 100644 --- a/drivers/media/dvb/cinergyT2/Makefile +++ b/drivers/media/dvb/cinergyT2/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_DVB_CINERGYT2) += cinergyT2.o -EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index b40af48a2edb..5a1449f485cf 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -829,7 +829,7 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2) input_dev->id.vendor = cinergyt2->udev->descriptor.idVendor; input_dev->id.product = cinergyt2->udev->descriptor.idProduct; input_dev->id.version = 1; - input_dev->cdev.dev = &cinergyt2->udev->dev; + input_dev->dev.parent = &cinergyt2->udev->dev; err = input_register_device(input_dev); if (err) { @@ -1000,18 +1000,15 @@ static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state) if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->wq_sem)) return -ERESTARTSYS; - if (1) { - cinergyt2_suspend_rc(cinergyt2); - cancel_rearming_delayed_work(&cinergyt2->query_work); + cinergyt2_suspend_rc(cinergyt2); + cancel_rearming_delayed_work(&cinergyt2->query_work); - mutex_lock(&cinergyt2->sem); - if (cinergyt2->streaming) - cinergyt2_stop_stream_xfer(cinergyt2); - cinergyt2_sleep(cinergyt2, 1); - mutex_unlock(&cinergyt2->sem); - } + mutex_lock(&cinergyt2->sem); + if (cinergyt2->streaming) + cinergyt2_stop_stream_xfer(cinergyt2); + cinergyt2_sleep(cinergyt2, 1); + mutex_unlock(&cinergyt2->sem); - mutex_unlock(&cinergyt2->wq_sem); return 0; } diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index 275df65fde99..5394de2e4ce0 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -97,7 +97,7 @@ static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src, if (avail > todo) avail = todo; - ret = dvb_ringbuffer_read(src, buf, avail, 1); + ret = dvb_ringbuffer_read(src, (u8 *)buf, avail, 1); if (ret < 0) break; diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 2a03bf53cb29..4fadddb264d6 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -175,7 +175,7 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * e * @param nlen Number of bytes in needle. * @return Pointer into haystack needle was found at, or NULL if not found. */ -static u8 *findstr(u8 * haystack, int hlen, u8 * needle, int nlen) +static char *findstr(char * haystack, int hlen, char * needle, int nlen) { int i; @@ -482,7 +482,7 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot) } /* check it contains the correct DVB string */ - dvb_str = findstr(tuple, tupleLength, "DVB_CI_V", 8); + dvb_str = findstr((char *)tuple, tupleLength, "DVB_CI_V", 8); if (dvb_str == NULL) return -EINVAL; if (tupleLength < ((dvb_str - (char *) tuple) + 12)) @@ -513,8 +513,8 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot) ca->slot_info[slot].config_option = tuple[0] & 0x3f; /* OK, check it contains the correct strings */ - if ((findstr(tuple, tupleLength, "DVB_HOST", 8) == NULL) || - (findstr(tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL)) + if ((findstr((char *)tuple, tupleLength, "DVB_HOST", 8) == NULL) || + (findstr((char *)tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL)) break; got_cftableentry = 1; @@ -1300,7 +1300,7 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file, struct dvb_ca_private *ca = dvbdev->priv; u8 slot, connection_id; int status; - char fragbuf[HOST_LINK_BUF_SIZE]; + u8 fragbuf[HOST_LINK_BUF_SIZE]; int fragpos = 0; int fraglen; unsigned long timeout; @@ -1486,7 +1486,7 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf, } if ((status = dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 2, - buf + pktlen, fraglen, 1)) < 0) { + (u8 *)buf + pktlen, fraglen, 1)) < 0) { goto exit; } pktlen += fraglen; diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c index 6d8d1c3df863..cb6987fce26c 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/drivers/media/dvb/dvb-core/dvb_demux.c @@ -1068,7 +1068,7 @@ static int dvbdmx_write(struct dmx_demux *demux, const char *buf, size_t count) if (mutex_lock_interruptible(&dvbdemux->mutex)) return -ERESTARTSYS; - dvb_dmx_swfilter(dvbdemux, buf, count); + dvb_dmx_swfilter(dvbdemux, (u8 *)buf, count); mutex_unlock(&dvbdemux->mutex); if (signal_pending(current)) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index f233d78bc364..a770a87b9a93 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -103,7 +103,7 @@ struct dvb_frontend_ops { int (*tune)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, unsigned int mode_flags, - int *delay, + unsigned int *delay, fe_status_t *status); /* get frontend tuning algorithm from the module */ int (*get_frontend_algo)(struct dvb_frontend *fe); diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 4ebf33a5ffa2..acf026342ec5 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -347,7 +347,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) { struct dvb_net_priv *priv = dev->priv; unsigned long skipped = 0L; - u8 *ts, *ts_end, *from_where = NULL, ts_remain = 0, how_much = 0, new_ts = 1; + const u8 *ts, *ts_end, *from_where = NULL; + u8 ts_remain = 0, how_much = 0, new_ts = 1; struct ethhdr *ethh = NULL; #ifdef ULE_DEBUG @@ -364,7 +365,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) /* For all TS cells in current buffer. * Appearently, we are called for every single TS cell. */ - for (ts = (char *)buf, ts_end = (char *)buf + buf_len; ts < ts_end; /* no default incr. */ ) { + for (ts = buf, ts_end = buf + buf_len; ts < ts_end; /* no default incr. */ ) { if (new_ts) { /* We are about to process a new TS cell. */ diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index a9fa3337dd81..9ef0c00605ee 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -208,7 +208,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, if ((id = dvbdev_get_free_id (adap, type)) < 0){ mutex_unlock(&dvbdev_register_lock); *pdvbdev = NULL; - printk ("%s: could get find free device id...\n", __FUNCTION__); + printk(KERN_ERR "%s: couldn't find free device id\n", __FUNCTION__); return -ENFILE; } @@ -252,7 +252,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, return PTR_ERR(clsdev); } - dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", + dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", adap->num, dnames[type], id, nums2minor(adap->num, type, id), nums2minor(adap->num, type, id)); @@ -311,7 +311,7 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct modu memset (adap, 0, sizeof(struct dvb_adapter)); INIT_LIST_HEAD (&adap->device_list); - printk ("DVB: registering new adapter (%s).\n", name); + printk(KERN_INFO "DVB: registering new adapter (%s)\n", name); adap->num = num; adap->name = name; @@ -407,13 +407,13 @@ static int __init init_dvbdev(void) dev_t dev = MKDEV(DVB_MAJOR, 0); if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) { - printk("dvb-core: unable to get major %d\n", DVB_MAJOR); + printk(KERN_ERR "dvb-core: unable to get major %d\n", DVB_MAJOR); return retval; } cdev_init(&dvb_device_cdev, &dvb_device_fops); if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) { - printk("dvb-core: unable to get major %d\n", DVB_MAJOR); + printk(KERN_ERR "dvb-core: unable register character device\n"); goto error; } diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 54488737a08f..40e41f2f5afe 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -2,7 +2,6 @@ config DVB_USB tristate "Support for various USB DVB devices" depends on DVB_CORE && USB && I2C select FW_LOADER - select DVB_PLL help By enabling this you will be able to choose the various supported USB1.1 and USB2.0 DVB devices. @@ -27,13 +26,14 @@ config DVB_USB_A800 depends on DVB_USB select DVB_DIB3000MC select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select DVB_PLL if !DVB_FE_CUSTOMISE help Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver. config DVB_USB_DIBUSB_MB tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)" depends on DVB_USB - select DVB_PLL + select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_DIB3000MB select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE help @@ -89,7 +89,7 @@ config DVB_USB_DIB0700 config DVB_USB_UMT_010 tristate "HanfTek UMT-010 DVB-T USB2.0 support" depends on DVB_USB - select DVB_PLL + select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_DIB3000MC select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE help @@ -98,7 +98,7 @@ config DVB_USB_UMT_010 config DVB_USB_CXUSB tristate "Conexant USB2.0 hybrid reference design support" depends on DVB_USB - select DVB_PLL + select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_CX22702 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE select DVB_MT352 if !DVB_FE_CUSTOMISE @@ -142,7 +142,7 @@ config DVB_USB_AU6610 config DVB_USB_DIGITV tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support" depends on DVB_USB - select DVB_PLL + select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_NXT6000 if !DVB_FE_CUSTOMISE select DVB_MT352 if !DVB_FE_CUSTOMISE help @@ -188,6 +188,7 @@ config DVB_USB_NOVA_T_USB2 depends on DVB_USB select DVB_DIB3000MC select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select DVB_PLL if !DVB_FE_CUSTOMISE help Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver. @@ -216,5 +217,23 @@ config DVB_USB_OPERA1 tristate "Opera1 DVB-S USB2.0 receiver" depends on DVB_USB select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_PLL if !DVB_FE_CUSTOMISE help Say Y here to support the Opera DVB-S USB2.0 receiver. + +config DVB_USB_AF9005 + tristate "Afatech AF9005 DVB-T USB1.1 support" + depends on DVB_USB && EXPERIMENTAL + select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE + help + Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver + and the TerraTec Cinergy T USB XE (Rev.1) + +config DVB_USB_AF9005_REMOTE + tristate "Afatech AF9005 default remote control support" + depends on DVB_USB_AF9005 + help + Say Y here to support the default remote control decoding for the + Afatech AF9005 based receiver. + diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 976f840cc904..73ac0a93fdeb 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -55,4 +55,10 @@ dvb-usb-opera-objs = opera1.o obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o -EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ +dvb-usb-af9005-objs = af9005.o af9005-fe.o +obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o + +dvb-usb-af9005-remote-objs = af9005-remote.o +obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff --git a/drivers/media/dvb/dvb-usb/af9005-fe.c b/drivers/media/dvb/dvb-usb/af9005-fe.c new file mode 100644 index 000000000000..7195c9461524 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/af9005-fe.c @@ -0,0 +1,1503 @@ +/* Frontend part of the Linux driver for the Afatech 9005 + * USB1.1 DVB-T receiver. + * + * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org) + * + * Thanks to Afatech who kindly provided information. + * + * 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. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "af9005.h" +#include "af9005-script.h" +#include "mt2060.h" +#include "qt1010.h" +#include <asm/div64.h> + +struct af9005_fe_state { + struct dvb_usb_device *d; + struct dvb_frontend *tuner; + + fe_status_t stat; + + /* retraining parameters */ + u32 original_fcw; + u16 original_rf_top; + u16 original_if_top; + u16 original_if_min; + u16 original_aci0_if_top; + u16 original_aci1_if_top; + u16 original_aci0_if_min; + u8 original_if_unplug_th; + u8 original_rf_unplug_th; + u8 original_dtop_if_unplug_th; + u8 original_dtop_rf_unplug_th; + + /* statistics */ + u32 pre_vit_error_count; + u32 pre_vit_bit_count; + u32 ber; + u32 post_vit_error_count; + u32 post_vit_bit_count; + u32 unc; + u16 abort_count; + + int opened; + int strong; + unsigned long next_status_check; + struct dvb_frontend frontend; +}; + +static int af9005_write_word_agc(struct dvb_usb_device *d, u16 reghi, + u16 reglo, u8 pos, u8 len, u16 value) +{ + int ret; + u8 temp; + + if ((ret = af9005_write_ofdm_register(d, reglo, (u8) (value & 0xff)))) + return ret; + temp = (u8) ((value & 0x0300) >> 8); + return af9005_write_register_bits(d, reghi, pos, len, + (u8) ((value & 0x300) >> 8)); +} + +static int af9005_read_word_agc(struct dvb_usb_device *d, u16 reghi, + u16 reglo, u8 pos, u8 len, u16 * value) +{ + int ret; + u8 temp0, temp1; + + if ((ret = af9005_read_ofdm_register(d, reglo, &temp0))) + return ret; + if ((ret = af9005_read_ofdm_register(d, reghi, &temp1))) + return ret; + switch (pos) { + case 0: + *value = ((u16) (temp1 & 0x03) << 8) + (u16) temp0; + break; + case 2: + *value = ((u16) (temp1 & 0x0C) << 6) + (u16) temp0; + break; + case 4: + *value = ((u16) (temp1 & 0x30) << 4) + (u16) temp0; + break; + case 6: + *value = ((u16) (temp1 & 0xC0) << 2) + (u16) temp0; + break; + default: + err("invalid pos in read word agc"); + return -EINVAL; + } + return 0; + +} + +static int af9005_is_fecmon_available(struct dvb_frontend *fe, int *available) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + int ret; + u8 temp; + + *available = false; + + ret = af9005_read_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en, + fec_vtb_rsd_mon_en_pos, + fec_vtb_rsd_mon_en_len, &temp); + if (ret) + return ret; + if (temp & 1) { + ret = + af9005_read_register_bits(state->d, + xd_p_reg_ofsm_read_rbc_en, + reg_ofsm_read_rbc_en_pos, + reg_ofsm_read_rbc_en_len, &temp); + if (ret) + return ret; + if ((temp & 1) == 0) + *available = true; + + } + return 0; +} + +static int af9005_get_post_vit_err_cw_count(struct dvb_frontend *fe, + u32 * post_err_count, + u32 * post_cw_count, + u16 * abort_count) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + int ret; + u32 err_count; + u32 cw_count; + u8 temp, temp0, temp1, temp2; + u16 loc_abort_count; + + *post_err_count = 0; + *post_cw_count = 0; + + /* check if error bit count is ready */ + ret = + af9005_read_register_bits(state->d, xd_r_fec_rsd_ber_rdy, + fec_rsd_ber_rdy_pos, fec_rsd_ber_rdy_len, + &temp); + if (ret) + return ret; + if (!temp) { + deb_info("rsd counter not ready\n"); + return 100; + } + /* get abort count */ + ret = + af9005_read_ofdm_register(state->d, + xd_r_fec_rsd_abort_packet_cnt_7_0, + &temp0); + if (ret) + return ret; + ret = + af9005_read_ofdm_register(state->d, + xd_r_fec_rsd_abort_packet_cnt_15_8, + &temp1); + if (ret) + return ret; + loc_abort_count = ((u16) temp1 << 8) + temp0; + + /* get error count */ + ret = + af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_7_0, + &temp0); + if (ret) + return ret; + ret = + af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_15_8, + &temp1); + if (ret) + return ret; + ret = + af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_23_16, + &temp2); + if (ret) + return ret; + err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0; + *post_err_count = err_count - (u32) loc_abort_count *8 * 8; + + /* get RSD packet number */ + ret = + af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0, + &temp0); + if (ret) + return ret; + ret = + af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8, + &temp1); + if (ret) + return ret; + cw_count = ((u32) temp1 << 8) + temp0; + if (cw_count == 0) { + err("wrong RSD packet count"); + return -EIO; + } + deb_info("POST abort count %d err count %d rsd packets %d\n", + loc_abort_count, err_count, cw_count); + *post_cw_count = cw_count - (u32) loc_abort_count; + *abort_count = loc_abort_count; + return 0; + +} + +static int af9005_get_post_vit_ber(struct dvb_frontend *fe, + u32 * post_err_count, u32 * post_cw_count, + u16 * abort_count) +{ + u32 loc_cw_count = 0, loc_err_count; + u16 loc_abort_count; + int ret; + + ret = + af9005_get_post_vit_err_cw_count(fe, &loc_err_count, &loc_cw_count, + &loc_abort_count); + if (ret) + return ret; + *post_err_count = loc_err_count; + *post_cw_count = loc_cw_count * 204 * 8; + *abort_count = loc_abort_count; + + return 0; +} + +static int af9005_get_pre_vit_err_bit_count(struct dvb_frontend *fe, + u32 * pre_err_count, + u32 * pre_bit_count) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + u8 temp, temp0, temp1, temp2; + u32 super_frame_count, x, bits; + int ret; + + ret = + af9005_read_register_bits(state->d, xd_r_fec_vtb_ber_rdy, + fec_vtb_ber_rdy_pos, fec_vtb_ber_rdy_len, + &temp); + if (ret) + return ret; + if (!temp) { + deb_info("viterbi counter not ready\n"); + return 101; /* ERR_APO_VTB_COUNTER_NOT_READY; */ + } + ret = + af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_7_0, + &temp0); + if (ret) + return ret; + ret = + af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_15_8, + &temp1); + if (ret) + return ret; + ret = + af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_23_16, + &temp2); + if (ret) + return ret; + *pre_err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0; + + ret = + af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0, + &temp0); + if (ret) + return ret; + ret = + af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8, + &temp1); + if (ret) + return ret; + super_frame_count = ((u32) temp1 << 8) + temp0; + if (super_frame_count == 0) { + deb_info("super frame count 0\n"); + return 102; + } + + /* read fft mode */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod, + reg_tpsd_txmod_pos, reg_tpsd_txmod_len, + &temp); + if (ret) + return ret; + if (temp == 0) { + /* 2K */ + x = 1512; + } else if (temp == 1) { + /* 8k */ + x = 6048; + } else { + err("Invalid fft mode"); + return -EINVAL; + } + + /* read constellation mode */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_tpsd_const, + reg_tpsd_const_pos, reg_tpsd_const_len, + &temp); + if (ret) + return ret; + switch (temp) { + case 0: /* QPSK */ + bits = 2; + break; + case 1: /* QAM_16 */ + bits = 4; + break; + case 2: /* QAM_64 */ + bits = 6; + break; + default: + err("invalid constellation mode"); + return -EINVAL; + } + *pre_bit_count = super_frame_count * 68 * 4 * x * bits; + deb_info("PRE err count %d frame count %d bit count %d\n", + *pre_err_count, super_frame_count, *pre_bit_count); + return 0; +} + +static int af9005_reset_pre_viterbi(struct dvb_frontend *fe) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + int ret; + + /* set super frame count to 1 */ + ret = + af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0, + 1 & 0xff); + if (ret) + return ret; + af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8, + 1 >> 8); + if (ret) + return ret; + /* reset pre viterbi error count */ + ret = + af9005_write_register_bits(state->d, xd_p_fec_vtb_ber_rst, + fec_vtb_ber_rst_pos, fec_vtb_ber_rst_len, + 1); + + return ret; +} + +static int af9005_reset_post_viterbi(struct dvb_frontend *fe) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + int ret; + + /* set packet unit */ + ret = + af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0, + 10000 & 0xff); + if (ret) + return ret; + ret = + af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8, + 10000 >> 8); + if (ret) + return ret; + /* reset post viterbi error count */ + ret = + af9005_write_register_bits(state->d, xd_p_fec_rsd_ber_rst, + fec_rsd_ber_rst_pos, fec_rsd_ber_rst_len, + 1); + + return ret; +} + +static int af9005_get_statistic(struct dvb_frontend *fe) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + int ret, fecavailable; + u64 numerator, denominator; + + deb_info("GET STATISTIC\n"); + ret = af9005_is_fecmon_available(fe, &fecavailable); + if (ret) + return ret; + if (!fecavailable) { + deb_info("fecmon not available\n"); + return 0; + } + + ret = af9005_get_pre_vit_err_bit_count(fe, &state->pre_vit_error_count, + &state->pre_vit_bit_count); + if (ret == 0) { + af9005_reset_pre_viterbi(fe); + if (state->pre_vit_bit_count > 0) { + /* according to v 0.0.4 of the dvb api ber should be a multiple + of 10E-9 so we have to multiply the error count by + 10E9=1000000000 */ + numerator = + (u64) state->pre_vit_error_count * (u64) 1000000000; + denominator = (u64) state->pre_vit_bit_count; + state->ber = do_div(numerator, denominator); + } else { + state->ber = 0xffffffff; + } + } + + ret = af9005_get_post_vit_ber(fe, &state->post_vit_error_count, + &state->post_vit_bit_count, + &state->abort_count); + if (ret == 0) { + ret = af9005_reset_post_viterbi(fe); + state->unc += state->abort_count; + if (ret) + return ret; + } + return 0; +} + +static int af9005_fe_refresh_state(struct dvb_frontend *fe) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + if (time_after(jiffies, state->next_status_check)) { + deb_info("REFRESH STATE\n"); + + /* statistics */ + if (af9005_get_statistic(fe)) + err("get_statistic_failed"); + state->next_status_check = jiffies + 250 * HZ / 1000; + } + return 0; +} + +static int af9005_fe_read_status(struct dvb_frontend *fe, fe_status_t * stat) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + u8 temp; + int ret; + + if (state->tuner == NULL) + return -ENODEV; + + *stat = 0; + ret = af9005_read_register_bits(state->d, xd_p_agc_lock, + agc_lock_pos, agc_lock_len, &temp); + if (ret) + return ret; + if (temp) + *stat |= FE_HAS_SIGNAL; + + ret = af9005_read_register_bits(state->d, xd_p_fd_tpsd_lock, + fd_tpsd_lock_pos, fd_tpsd_lock_len, + &temp); + if (ret) + return ret; + if (temp) + *stat |= FE_HAS_CARRIER; + + ret = af9005_read_register_bits(state->d, + xd_r_mp2if_sync_byte_locked, + mp2if_sync_byte_locked_pos, + mp2if_sync_byte_locked_pos, &temp); + if (ret) + return ret; + if (temp) + *stat |= FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_LOCK; + if (state->opened) + af9005_led_control(state->d, *stat & FE_HAS_LOCK); + + ret = + af9005_read_register_bits(state->d, xd_p_reg_strong_sginal_detected, + reg_strong_sginal_detected_pos, + reg_strong_sginal_detected_len, &temp); + if (ret) + return ret; + if (temp != state->strong) { + deb_info("adjust for strong signal %d\n", temp); + state->strong = temp; + } + return 0; +} + +static int af9005_fe_read_ber(struct dvb_frontend *fe, u32 * ber) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + if (state->tuner == NULL) + return -ENODEV; + af9005_fe_refresh_state(fe); + *ber = state->ber; + return 0; +} + +static int af9005_fe_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + if (state->tuner == NULL) + return -ENODEV; + af9005_fe_refresh_state(fe); + *unc = state->unc; + return 0; +} + +static int af9005_fe_read_signal_strength(struct dvb_frontend *fe, + u16 * strength) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + int ret; + u8 if_gain, rf_gain; + + if (state->tuner == NULL) + return -ENODEV; + ret = + af9005_read_ofdm_register(state->d, xd_r_reg_aagc_rf_gain, + &rf_gain); + if (ret) + return ret; + ret = + af9005_read_ofdm_register(state->d, xd_r_reg_aagc_if_gain, + &if_gain); + if (ret) + return ret; + /* this value has no real meaning, but i don't have the tables that relate + the rf and if gain with the dbm, so I just scale the value */ + *strength = (512 - rf_gain - if_gain) << 7; + return 0; +} + +static int af9005_fe_read_snr(struct dvb_frontend *fe, u16 * snr) +{ + /* the snr can be derived from the ber and the constellation + but I don't think this kind of complex calculations belong + in the driver. I may be wrong.... */ + return -ENOSYS; +} + +static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw) +{ + u8 temp0, temp1, temp2, temp3, buf[4]; + int ret; + u32 NS_coeff1_2048Nu; + u32 NS_coeff1_8191Nu; + u32 NS_coeff1_8192Nu; + u32 NS_coeff1_8193Nu; + u32 NS_coeff2_2k; + u32 NS_coeff2_8k; + + switch (bw) { + case BANDWIDTH_6_MHZ: + NS_coeff1_2048Nu = 0x2ADB6DC; + NS_coeff1_8191Nu = 0xAB7313; + NS_coeff1_8192Nu = 0xAB6DB7; + NS_coeff1_8193Nu = 0xAB685C; + NS_coeff2_2k = 0x156DB6E; + NS_coeff2_8k = 0x55B6DC; + break; + + case BANDWIDTH_7_MHZ: + NS_coeff1_2048Nu = 0x3200001; + NS_coeff1_8191Nu = 0xC80640; + NS_coeff1_8192Nu = 0xC80000; + NS_coeff1_8193Nu = 0xC7F9C0; + NS_coeff2_2k = 0x1900000; + NS_coeff2_8k = 0x640000; + break; + + case BANDWIDTH_8_MHZ: + NS_coeff1_2048Nu = 0x3924926; + NS_coeff1_8191Nu = 0xE4996E; + NS_coeff1_8192Nu = 0xE49249; + NS_coeff1_8193Nu = 0xE48B25; + NS_coeff2_2k = 0x1C92493; + NS_coeff2_8k = 0x724925; + break; + default: + err("Invalid bandwith %d.", bw); + return -EINVAL; + } + + /* + * write NS_coeff1_2048Nu + */ + + temp0 = (u8) (NS_coeff1_2048Nu & 0x000000FF); + temp1 = (u8) ((NS_coeff1_2048Nu & 0x0000FF00) >> 8); + temp2 = (u8) ((NS_coeff1_2048Nu & 0x00FF0000) >> 16); + temp3 = (u8) ((NS_coeff1_2048Nu & 0x03000000) >> 24); + + /* big endian to make 8051 happy */ + buf[0] = temp3; + buf[1] = temp2; + buf[2] = temp1; + buf[3] = temp0; + + /* cfoe_NS_2k_coeff1_25_24 */ + ret = af9005_write_ofdm_register(d, 0xAE00, buf[0]); + if (ret) + return ret; + + /* cfoe_NS_2k_coeff1_23_16 */ + ret = af9005_write_ofdm_register(d, 0xAE01, buf[1]); + if (ret) + return ret; + + /* cfoe_NS_2k_coeff1_15_8 */ + ret = af9005_write_ofdm_register(d, 0xAE02, buf[2]); + if (ret) + return ret; + + /* cfoe_NS_2k_coeff1_7_0 */ + ret = af9005_write_ofdm_register(d, 0xAE03, buf[3]); + if (ret) + return ret; + + /* + * write NS_coeff2_2k + */ + + temp0 = (u8) ((NS_coeff2_2k & 0x0000003F)); + temp1 = (u8) ((NS_coeff2_2k & 0x00003FC0) >> 6); + temp2 = (u8) ((NS_coeff2_2k & 0x003FC000) >> 14); + temp3 = (u8) ((NS_coeff2_2k & 0x01C00000) >> 22); + + /* big endian to make 8051 happy */ + buf[0] = temp3; + buf[1] = temp2; + buf[2] = temp1; + buf[3] = temp0; + + ret = af9005_write_ofdm_register(d, 0xAE04, buf[0]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE05, buf[1]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE06, buf[2]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE07, buf[3]); + if (ret) + return ret; + + /* + * write NS_coeff1_8191Nu + */ + + temp0 = (u8) ((NS_coeff1_8191Nu & 0x000000FF)); + temp1 = (u8) ((NS_coeff1_8191Nu & 0x0000FF00) >> 8); + temp2 = (u8) ((NS_coeff1_8191Nu & 0x00FFC000) >> 16); + temp3 = (u8) ((NS_coeff1_8191Nu & 0x03000000) >> 24); + + /* big endian to make 8051 happy */ + buf[0] = temp3; + buf[1] = temp2; + buf[2] = temp1; + buf[3] = temp0; + + ret = af9005_write_ofdm_register(d, 0xAE08, buf[0]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE09, buf[1]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE0A, buf[2]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE0B, buf[3]); + if (ret) + return ret; + + /* + * write NS_coeff1_8192Nu + */ + + temp0 = (u8) (NS_coeff1_8192Nu & 0x000000FF); + temp1 = (u8) ((NS_coeff1_8192Nu & 0x0000FF00) >> 8); + temp2 = (u8) ((NS_coeff1_8192Nu & 0x00FFC000) >> 16); + temp3 = (u8) ((NS_coeff1_8192Nu & 0x03000000) >> 24); + + /* big endian to make 8051 happy */ + buf[0] = temp3; + buf[1] = temp2; + buf[2] = temp1; + buf[3] = temp0; + + ret = af9005_write_ofdm_register(d, 0xAE0C, buf[0]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE0D, buf[1]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE0E, buf[2]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE0F, buf[3]); + if (ret) + return ret; + + /* + * write NS_coeff1_8193Nu + */ + + temp0 = (u8) ((NS_coeff1_8193Nu & 0x000000FF)); + temp1 = (u8) ((NS_coeff1_8193Nu & 0x0000FF00) >> 8); + temp2 = (u8) ((NS_coeff1_8193Nu & 0x00FFC000) >> 16); + temp3 = (u8) ((NS_coeff1_8193Nu & 0x03000000) >> 24); + + /* big endian to make 8051 happy */ + buf[0] = temp3; + buf[1] = temp2; + buf[2] = temp1; + buf[3] = temp0; + + ret = af9005_write_ofdm_register(d, 0xAE10, buf[0]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE11, buf[1]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE12, buf[2]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE13, buf[3]); + if (ret) + return ret; + + /* + * write NS_coeff2_8k + */ + + temp0 = (u8) ((NS_coeff2_8k & 0x0000003F)); + temp1 = (u8) ((NS_coeff2_8k & 0x00003FC0) >> 6); + temp2 = (u8) ((NS_coeff2_8k & 0x003FC000) >> 14); + temp3 = (u8) ((NS_coeff2_8k & 0x01C00000) >> 22); + + /* big endian to make 8051 happy */ + buf[0] = temp3; + buf[1] = temp2; + buf[2] = temp1; + buf[3] = temp0; + + ret = af9005_write_ofdm_register(d, 0xAE14, buf[0]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE15, buf[1]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE16, buf[2]); + if (ret) + return ret; + + ret = af9005_write_ofdm_register(d, 0xAE17, buf[3]); + return ret; + +} + +static int af9005_fe_select_bw(struct dvb_usb_device *d, fe_bandwidth_t bw) +{ + u8 temp; + switch (bw) { + case BANDWIDTH_6_MHZ: + temp = 0; + break; + case BANDWIDTH_7_MHZ: + temp = 1; + break; + case BANDWIDTH_8_MHZ: + temp = 2; + break; + default: + err("Invalid bandwith %d.", bw); + return -EINVAL; + } + return af9005_write_register_bits(d, xd_g_reg_bw, reg_bw_pos, + reg_bw_len, temp); +} + +static int af9005_fe_power(struct dvb_frontend *fe, int on) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + u8 temp = on; + int ret; + deb_info("power %s tuner\n", on ? "on" : "off"); + ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0); + return ret; +} + +static struct mt2060_config af9005_mt2060_config = { + 0xC0 +}; + +static struct qt1010_config af9005_qt1010_config = { + 0xC4 +}; + +static int af9005_fe_init(struct dvb_frontend *fe) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + struct dvb_usb_adapter *adap = fe->dvb->priv; + int ret, i, scriptlen; + u8 temp, temp0 = 0, temp1 = 0, temp2 = 0; + u8 buf[2]; + u16 if1; + + deb_info("in af9005_fe_init\n"); + + /* reset */ + deb_info("reset\n"); + if ((ret = + af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst_en, + 4, 1, 0x01))) + return ret; + if ((ret = af9005_write_ofdm_register(state->d, APO_REG_RESET, 0))) + return ret; + /* clear ofdm reset */ + deb_info("clear ofdm reset\n"); + for (i = 0; i < 150; i++) { + if ((ret = + af9005_read_ofdm_register(state->d, + xd_I2C_reg_ofdm_rst, &temp))) + return ret; + if (temp & (regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos)) + break; + msleep(10); + } + if (i == 150) + return -ETIMEDOUT; + + /*FIXME in the dump + write B200 A9 + write xd_g_reg_ofsm_clk 7 + read eepr c6 (2) + read eepr c7 (2) + misc ctrl 3 -> 1 + read eepr ca (6) + write xd_g_reg_ofsm_clk 0 + write B200 a1 + */ + ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa9); + if (ret) + return ret; + ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x07); + if (ret) + return ret; + temp = 0x01; + ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0); + if (ret) + return ret; + ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x00); + if (ret) + return ret; + ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa1); + if (ret) + return ret; + + temp = regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos; + if ((ret = + af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst, + reg_ofdm_rst_pos, reg_ofdm_rst_len, 1))) + return ret; + if ((ret = + af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst, + reg_ofdm_rst_pos, reg_ofdm_rst_len, 0))) + return ret; + + if (ret) + return ret; + /* don't know what register aefc is, but this is what the windows driver does */ + ret = af9005_write_ofdm_register(state->d, 0xaefc, 0); + if (ret) + return ret; + + /* set stand alone chip */ + deb_info("set stand alone chip\n"); + if ((ret = + af9005_write_register_bits(state->d, xd_p_reg_dca_stand_alone, + reg_dca_stand_alone_pos, + reg_dca_stand_alone_len, 1))) + return ret; + + /* set dca upper & lower chip */ + deb_info("set dca upper & lower chip\n"); + if ((ret = + af9005_write_register_bits(state->d, xd_p_reg_dca_upper_chip, + reg_dca_upper_chip_pos, + reg_dca_upper_chip_len, 0))) + return ret; + if ((ret = + af9005_write_register_bits(state->d, xd_p_reg_dca_lower_chip, + reg_dca_lower_chip_pos, + reg_dca_lower_chip_len, 0))) + return ret; + + /* set 2wire master clock to 0x14 (for 60KHz) */ + deb_info("set 2wire master clock to 0x14 (for 60KHz)\n"); + if ((ret = + af9005_write_ofdm_register(state->d, xd_I2C_i2c_m_period, 0x14))) + return ret; + + /* clear dca enable chip */ + deb_info("clear dca enable chip\n"); + if ((ret = + af9005_write_register_bits(state->d, xd_p_reg_dca_en, + reg_dca_en_pos, reg_dca_en_len, 0))) + return ret; + /* FIXME these are register bits, but I don't know which ones */ + ret = af9005_write_ofdm_register(state->d, 0xa16c, 1); + if (ret) + return ret; + ret = af9005_write_ofdm_register(state->d, 0xa3c1, 0); + if (ret) + return ret; + + /* init other parameters: program cfoe and select bandwith */ + deb_info("program cfoe\n"); + if ((ret = af9005_fe_program_cfoe(state->d, BANDWIDTH_6_MHZ))) + return ret; + /* set read-update bit for constellation */ + deb_info("set read-update bit for constellation\n"); + if ((ret = + af9005_write_register_bits(state->d, xd_p_reg_feq_read_update, + reg_feq_read_update_pos, + reg_feq_read_update_len, 1))) + return ret; + + /* sample code has a set MPEG TS code here + but sniffing reveals that it doesn't do it */ + + /* set read-update bit to 1 for DCA constellation */ + deb_info("set read-update bit 1 for DCA constellation\n"); + if ((ret = + af9005_write_register_bits(state->d, xd_p_reg_dca_read_update, + reg_dca_read_update_pos, + reg_dca_read_update_len, 1))) + return ret; + + /* enable fec monitor */ + deb_info("enable fec monitor\n"); + if ((ret = + af9005_write_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en, + fec_vtb_rsd_mon_en_pos, + fec_vtb_rsd_mon_en_len, 1))) + return ret; + + /* FIXME should be register bits, I don't know which ones */ + ret = af9005_write_ofdm_register(state->d, 0xa601, 0); + + /* set api_retrain_never_freeze */ + deb_info("set api_retrain_never_freeze\n"); + if ((ret = af9005_write_ofdm_register(state->d, 0xaefb, 0x01))) + return ret; + + /* load init script */ + deb_info("load init script\n"); + scriptlen = sizeof(script) / sizeof(RegDesc); + for (i = 0; i < scriptlen; i++) { + if ((ret = + af9005_write_register_bits(state->d, script[i].reg, + script[i].pos, + script[i].len, script[i].val))) + return ret; + /* save 3 bytes of original fcw */ + if (script[i].reg == 0xae18) + temp2 = script[i].val; + if (script[i].reg == 0xae19) + temp1 = script[i].val; + if (script[i].reg == 0xae1a) + temp0 = script[i].val; + + /* save original unplug threshold */ + if (script[i].reg == xd_p_reg_unplug_th) + state->original_if_unplug_th = script[i].val; + if (script[i].reg == xd_p_reg_unplug_rf_gain_th) + state->original_rf_unplug_th = script[i].val; + if (script[i].reg == xd_p_reg_unplug_dtop_if_gain_th) + state->original_dtop_if_unplug_th = script[i].val; + if (script[i].reg == xd_p_reg_unplug_dtop_rf_gain_th) + state->original_dtop_rf_unplug_th = script[i].val; + + } + state->original_fcw = + ((u32) temp2 << 16) + ((u32) temp1 << 8) + (u32) temp0; + + + /* save original TOPs */ + deb_info("save original TOPs\n"); + + /* RF TOP */ + ret = + af9005_read_word_agc(state->d, + xd_p_reg_aagc_rf_top_numerator_9_8, + xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2, + &state->original_rf_top); + if (ret) + return ret; + + /* IF TOP */ + ret = + af9005_read_word_agc(state->d, + xd_p_reg_aagc_if_top_numerator_9_8, + xd_p_reg_aagc_if_top_numerator_7_0, 0, 2, + &state->original_if_top); + if (ret) + return ret; + + /* ACI 0 IF TOP */ + ret = + af9005_read_word_agc(state->d, 0xA60E, 0xA60A, 4, 2, + &state->original_aci0_if_top); + if (ret) + return ret; + + /* ACI 1 IF TOP */ + ret = + af9005_read_word_agc(state->d, 0xA60E, 0xA60B, 6, 2, + &state->original_aci1_if_top); + if (ret) + return ret; + + /* attach tuner and init */ + if (state->tuner == NULL) { + /* read tuner and board id from eeprom */ + ret = af9005_read_eeprom(adap->dev, 0xc6, buf, 2); + if (ret) { + err("Impossible to read EEPROM\n"); + return ret; + } + deb_info("Tuner id %d, board id %d\n", buf[0], buf[1]); + switch (buf[0]) { + case 2: /* MT2060 */ + /* read if1 from eeprom */ + ret = af9005_read_eeprom(adap->dev, 0xc8, buf, 2); + if (ret) { + err("Impossible to read EEPROM\n"); + return ret; + } + if1 = (u16) (buf[0] << 8) + buf[1]; + state->tuner = + dvb_attach(mt2060_attach, fe, &adap->dev->i2c_adap, + &af9005_mt2060_config, if1); + if (state->tuner == NULL) { + deb_info("MT2060 attach failed\n"); + return -ENODEV; + } + break; + case 3: /* QT1010 */ + case 9: /* QT1010B */ + state->tuner = + dvb_attach(qt1010_attach, fe, &adap->dev->i2c_adap, + &af9005_qt1010_config); + if (state->tuner == NULL) { + deb_info("QT1010 attach failed\n"); + return -ENODEV; + } + break; + default: + err("Unsupported tuner type %d", buf[0]); + return -ENODEV; + } + ret = state->tuner->ops.tuner_ops.init(state->tuner); + if (ret) + return ret; + } + + deb_info("profit!\n"); + return 0; +} + +static int af9005_fe_sleep(struct dvb_frontend *fe) +{ + return af9005_fe_power(fe, 0); +} + +static int af9005_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + + if (acquire) { + state->opened++; + } else { + + state->opened--; + if (!state->opened) + af9005_led_control(state->d, 0); + } + return 0; +} + +static int af9005_fe_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fep) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + int ret; + u8 temp, temp0, temp1, temp2; + + deb_info("af9005_fe_set_frontend freq %d bw %d\n", fep->frequency, + fep->u.ofdm.bandwidth); + if (state->tuner == NULL) { + err("Tuner not attached"); + return -ENODEV; + } + + deb_info("turn off led\n"); + /* not in the log */ + ret = af9005_led_control(state->d, 0); + if (ret) + return ret; + /* not sure about the bits */ + ret = af9005_write_register_bits(state->d, XD_MP2IF_MISC, 2, 1, 0); + if (ret) + return ret; + + /* set FCW to default value */ + deb_info("set FCW to default value\n"); + temp0 = (u8) (state->original_fcw & 0x000000ff); + temp1 = (u8) ((state->original_fcw & 0x0000ff00) >> 8); + temp2 = (u8) ((state->original_fcw & 0x00ff0000) >> 16); + ret = af9005_write_ofdm_register(state->d, 0xae1a, temp0); + if (ret) + return ret; + ret = af9005_write_ofdm_register(state->d, 0xae19, temp1); + if (ret) + return ret; + ret = af9005_write_ofdm_register(state->d, 0xae18, temp2); + if (ret) + return ret; + + /* restore original TOPs */ + deb_info("restore original TOPs\n"); + ret = + af9005_write_word_agc(state->d, + xd_p_reg_aagc_rf_top_numerator_9_8, + xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2, + state->original_rf_top); + if (ret) + return ret; + ret = + af9005_write_word_agc(state->d, + xd_p_reg_aagc_if_top_numerator_9_8, + xd_p_reg_aagc_if_top_numerator_7_0, 0, 2, + state->original_if_top); + if (ret) + return ret; + ret = + af9005_write_word_agc(state->d, 0xA60E, 0xA60A, 4, 2, + state->original_aci0_if_top); + if (ret) + return ret; + ret = + af9005_write_word_agc(state->d, 0xA60E, 0xA60B, 6, 2, + state->original_aci1_if_top); + if (ret) + return ret; + + /* select bandwith */ + deb_info("select bandwidth"); + ret = af9005_fe_select_bw(state->d, fep->u.ofdm.bandwidth); + if (ret) + return ret; + ret = af9005_fe_program_cfoe(state->d, fep->u.ofdm.bandwidth); + if (ret) + return ret; + + /* clear easy mode flag */ + deb_info("clear easy mode flag\n"); + ret = af9005_write_ofdm_register(state->d, 0xaefd, 0); + if (ret) + return ret; + + /* set unplug threshold to original value */ + deb_info("set unplug threshold to original value\n"); + ret = + af9005_write_ofdm_register(state->d, xd_p_reg_unplug_th, + state->original_if_unplug_th); + if (ret) + return ret; + /* set tuner */ + deb_info("set tuner\n"); + ret = state->tuner->ops.tuner_ops.set_params(state->tuner, fep); + if (ret) + return ret; + + /* trigger ofsm */ + deb_info("trigger ofsm\n"); + temp = 0; + ret = af9005_write_tuner_registers(state->d, 0xffff, &temp, 1); + if (ret) + return ret; + + /* clear retrain and freeze flag */ + deb_info("clear retrain and freeze flag\n"); + ret = + af9005_write_register_bits(state->d, + xd_p_reg_api_retrain_request, + reg_api_retrain_request_pos, 2, 0); + if (ret) + return ret; + + /* reset pre viterbi and post viterbi registers and statistics */ + af9005_reset_pre_viterbi(fe); + af9005_reset_post_viterbi(fe); + state->pre_vit_error_count = 0; + state->pre_vit_bit_count = 0; + state->ber = 0; + state->post_vit_error_count = 0; + /* state->unc = 0; commented out since it should be ever increasing */ + state->abort_count = 0; + + state->next_status_check = jiffies; + state->strong = -1; + + return 0; +} + +static int af9005_fe_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fep) +{ + struct af9005_fe_state *state = fe->demodulator_priv; + int ret; + u8 temp; + + /* mode */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_tpsd_const, + reg_tpsd_const_pos, reg_tpsd_const_len, + &temp); + if (ret) + return ret; + deb_info("===== fe_get_frontend ==============\n"); + deb_info("CONSTELLATION "); + switch (temp) { + case 0: + fep->u.ofdm.constellation = QPSK; + deb_info("QPSK\n"); + break; + case 1: + fep->u.ofdm.constellation = QAM_16; + deb_info("QAM_16\n"); + break; + case 2: + fep->u.ofdm.constellation = QAM_64; + deb_info("QAM_64\n"); + break; + } + + /* tps hierarchy and alpha value */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_tpsd_hier, + reg_tpsd_hier_pos, reg_tpsd_hier_len, + &temp); + if (ret) + return ret; + deb_info("HIERARCHY "); + switch (temp) { + case 0: + fep->u.ofdm.hierarchy_information = HIERARCHY_NONE; + deb_info("NONE\n"); + break; + case 1: + fep->u.ofdm.hierarchy_information = HIERARCHY_1; + deb_info("1\n"); + break; + case 2: + fep->u.ofdm.hierarchy_information = HIERARCHY_2; + deb_info("2\n"); + break; + case 3: + fep->u.ofdm.hierarchy_information = HIERARCHY_4; + deb_info("4\n"); + break; + } + + /* high/low priority */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_dec_pri, + reg_dec_pri_pos, reg_dec_pri_len, &temp); + if (ret) + return ret; + /* if temp is set = high priority */ + deb_info("PRIORITY %s\n", temp ? "high" : "low"); + + /* high coderate */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_tpsd_hpcr, + reg_tpsd_hpcr_pos, reg_tpsd_hpcr_len, + &temp); + if (ret) + return ret; + deb_info("CODERATE HP "); + switch (temp) { + case 0: + fep->u.ofdm.code_rate_HP = FEC_1_2; + deb_info("FEC_1_2\n"); + break; + case 1: + fep->u.ofdm.code_rate_HP = FEC_2_3; + deb_info("FEC_2_3\n"); + break; + case 2: + fep->u.ofdm.code_rate_HP = FEC_3_4; + deb_info("FEC_3_4\n"); + break; + case 3: + fep->u.ofdm.code_rate_HP = FEC_5_6; + deb_info("FEC_5_6\n"); + break; + case 4: + fep->u.ofdm.code_rate_HP = FEC_7_8; + deb_info("FEC_7_8\n"); + break; + } + + /* low coderate */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_tpsd_lpcr, + reg_tpsd_lpcr_pos, reg_tpsd_lpcr_len, + &temp); + if (ret) + return ret; + deb_info("CODERATE LP "); + switch (temp) { + case 0: + fep->u.ofdm.code_rate_LP = FEC_1_2; + deb_info("FEC_1_2\n"); + break; + case 1: + fep->u.ofdm.code_rate_LP = FEC_2_3; + deb_info("FEC_2_3\n"); + break; + case 2: + fep->u.ofdm.code_rate_LP = FEC_3_4; + deb_info("FEC_3_4\n"); + break; + case 3: + fep->u.ofdm.code_rate_LP = FEC_5_6; + deb_info("FEC_5_6\n"); + break; + case 4: + fep->u.ofdm.code_rate_LP = FEC_7_8; + deb_info("FEC_7_8\n"); + break; + } + + /* guard interval */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_tpsd_gi, + reg_tpsd_gi_pos, reg_tpsd_gi_len, &temp); + if (ret) + return ret; + deb_info("GUARD INTERVAL "); + switch (temp) { + case 0: + fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + deb_info("1_32\n"); + break; + case 1: + fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; + deb_info("1_16\n"); + break; + case 2: + fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; + deb_info("1_8\n"); + break; + case 3: + fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; + deb_info("1_4\n"); + break; + } + + /* fft */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod, + reg_tpsd_txmod_pos, reg_tpsd_txmod_len, + &temp); + if (ret) + return ret; + deb_info("TRANSMISSION MODE "); + switch (temp) { + case 0: + fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; + deb_info("2K\n"); + break; + case 1: + fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + deb_info("8K\n"); + break; + } + + /* bandwidth */ + ret = + af9005_read_register_bits(state->d, xd_g_reg_bw, reg_bw_pos, + reg_bw_len, &temp); + deb_info("BANDWIDTH "); + switch (temp) { + case 0: + fep->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; + deb_info("6\n"); + break; + case 1: + fep->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; + deb_info("7\n"); + break; + case 2: + fep->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; + deb_info("8\n"); + break; + } + return 0; +} + +static void af9005_fe_release(struct dvb_frontend *fe) +{ + struct af9005_fe_state *state = + (struct af9005_fe_state *)fe->demodulator_priv; + if (state->tuner != NULL && state->tuner->ops.tuner_ops.release != NULL) { + state->tuner->ops.tuner_ops.release(state->tuner); +#ifdef CONFIG_DVB_CORE_ATTACH + symbol_put_addr(state->tuner->ops.tuner_ops.release); +#endif + } + kfree(state); +} + +static struct dvb_frontend_ops af9005_fe_ops; + +struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d) +{ + struct af9005_fe_state *state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct af9005_fe_state), GFP_KERNEL); + if (state == NULL) + goto error; + + deb_info("attaching frontend af9005\n"); + + state->d = d; + state->tuner = NULL; + state->opened = 0; + + memcpy(&state->frontend.ops, &af9005_fe_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + return &state->frontend; + error: + return NULL; +} + +static struct dvb_frontend_ops af9005_fe_ops = { + .info = { + .name = "AF9005 USB DVB-T", + .type = FE_OFDM, + .frequency_min = 44250000, + .frequency_max = 867250000, + .frequency_stepsize = 250000, + .caps = FE_CAN_INVERSION_AUTO | + 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_RECOVER | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = af9005_fe_release, + + .init = af9005_fe_init, + .sleep = af9005_fe_sleep, + .ts_bus_ctrl = af9005_ts_bus_ctrl, + + .set_frontend = af9005_fe_set_frontend, + .get_frontend = af9005_fe_get_frontend, + + .read_status = af9005_fe_read_status, + .read_ber = af9005_fe_read_ber, + .read_signal_strength = af9005_fe_read_signal_strength, + .read_snr = af9005_fe_read_snr, + .read_ucblocks = af9005_fe_read_unc_blocks, +}; diff --git a/drivers/media/dvb/dvb-usb/af9005-remote.c b/drivers/media/dvb/dvb-usb/af9005-remote.c new file mode 100644 index 000000000000..ff00c0e8f4a1 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/af9005-remote.c @@ -0,0 +1,157 @@ +/* DVB USB compliant Linux driver for the Afatech 9005 + * USB1.1 DVB-T receiver. + * + * Standard remote decode function + * + * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org) + * + * Thanks to Afatech who kindly provided information. + * + * 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. + * + * see Documentation/dvb/REDME.dvb-usb for more information + */ +#include "af9005.h" +/* debug */ +int dvb_usb_af9005_remote_debug; +module_param_named(debug, dvb_usb_af9005_remote_debug, int, 0644); +MODULE_PARM_DESC(debug, + "enable (1) or disable (0) debug messages." + DVB_USB_DEBUG_STATUS); + +#define deb_decode(args...) dprintk(dvb_usb_af9005_remote_debug,0x01,args) + +struct dvb_usb_rc_key af9005_rc_keys[] = { + + {0x01, 0xb7, KEY_POWER}, + {0x01, 0xa7, KEY_VOLUMEUP}, + {0x01, 0x87, KEY_CHANNELUP}, + {0x01, 0x7f, KEY_MUTE}, + {0x01, 0xbf, KEY_VOLUMEDOWN}, + {0x01, 0x3f, KEY_CHANNELDOWN}, + {0x01, 0xdf, KEY_1}, + {0x01, 0x5f, KEY_2}, + {0x01, 0x9f, KEY_3}, + {0x01, 0x1f, KEY_4}, + {0x01, 0xef, KEY_5}, + {0x01, 0x6f, KEY_6}, + {0x01, 0xaf, KEY_7}, + {0x01, 0x27, KEY_8}, + {0x01, 0x07, KEY_9}, + {0x01, 0xcf, KEY_ZOOM}, + {0x01, 0x4f, KEY_0}, + {0x01, 0x8f, KEY_GOTO}, /* marked jump on the remote */ + + {0x00, 0xbd, KEY_POWER}, + {0x00, 0x7d, KEY_VOLUMEUP}, + {0x00, 0xfd, KEY_CHANNELUP}, + {0x00, 0x9d, KEY_MUTE}, + {0x00, 0x5d, KEY_VOLUMEDOWN}, + {0x00, 0xdd, KEY_CHANNELDOWN}, + {0x00, 0xad, KEY_1}, + {0x00, 0x6d, KEY_2}, + {0x00, 0xed, KEY_3}, + {0x00, 0x8d, KEY_4}, + {0x00, 0x4d, KEY_5}, + {0x00, 0xcd, KEY_6}, + {0x00, 0xb5, KEY_7}, + {0x00, 0x75, KEY_8}, + {0x00, 0xf5, KEY_9}, + {0x00, 0x95, KEY_ZOOM}, + {0x00, 0x55, KEY_0}, + {0x00, 0xd5, KEY_GOTO}, /* marked jump on the remote */ +}; + +int af9005_rc_keys_size = ARRAY_SIZE(af9005_rc_keys); + +static int repeatable_keys[] = { + KEY_VOLUMEUP, + KEY_VOLUMEDOWN, + KEY_CHANNELUP, + KEY_CHANNELDOWN +}; + +int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, u32 * event, + int *state) +{ + u16 mark, space; + u32 result; + u8 cust, dat, invdat; + int i; + + if (len >= 6) { + mark = (u16) (data[0] << 8) + data[1]; + space = (u16) (data[2] << 8) + data[3]; + if (space * 3 < mark) { + for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) { + if (d->last_event == repeatable_keys[i]) { + *state = REMOTE_KEY_REPEAT; + *event = d->last_event; + deb_decode("repeat key, event %x\n", + *event); + return 0; + } + } + deb_decode("repeated key ignored (non repeatable)\n"); + return 0; + } else if (len >= 33 * 4) { /*32 bits + start code */ + result = 0; + for (i = 4; i < 4 + 32 * 4; i += 4) { + result <<= 1; + mark = (u16) (data[i] << 8) + data[i + 1]; + mark >>= 1; + space = (u16) (data[i + 2] << 8) + data[i + 3]; + space >>= 1; + if (mark * 2 > space) + result += 1; + } + deb_decode("key pressed, raw value %x\n", result); + if ((result & 0xff000000) != 0xfe000000) { + deb_decode + ("doesn't start with 0xfe, ignored\n"); + return 0; + } + cust = (result >> 16) & 0xff; + dat = (result >> 8) & 0xff; + invdat = (~result) & 0xff; + if (dat != invdat) { + deb_decode("code != inverted code\n"); + return 0; + } + for (i = 0; i < af9005_rc_keys_size; i++) { + if (af9005_rc_keys[i].custom == cust + && af9005_rc_keys[i].data == dat) { + *event = af9005_rc_keys[i].event; + *state = REMOTE_KEY_PRESSED; + deb_decode + ("key pressed, event %x\n", *event); + return 0; + } + } + deb_decode("not found in table\n"); + } + } + return 0; +} + +EXPORT_SYMBOL(af9005_rc_keys); +EXPORT_SYMBOL(af9005_rc_keys_size); +EXPORT_SYMBOL(af9005_rc_decode); + +MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>"); +MODULE_DESCRIPTION + ("Standard remote control decoder for Afatech 9005 DVB-T USB1.1 stick"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/af9005-script.h b/drivers/media/dvb/dvb-usb/af9005-script.h new file mode 100644 index 000000000000..6eeaae51b1ca --- /dev/null +++ b/drivers/media/dvb/dvb-usb/af9005-script.h @@ -0,0 +1,203 @@ +/* +File automatically generated by createinit.py using data +extracted from AF05BDA.sys (windows driver): + +dd if=AF05BDA.sys of=initsequence bs=1 skip=88316 count=1110 +python createinit.py > af9005-script.h + +*/ + +typedef struct { + u16 reg; + u8 pos; + u8 len; + u8 val; +} RegDesc; + +RegDesc script[] = { + {0xa180, 0x0, 0x8, 0xa}, + {0xa181, 0x0, 0x8, 0xd7}, + {0xa182, 0x0, 0x8, 0xa3}, + {0xa0a0, 0x0, 0x8, 0x0}, + {0xa0a1, 0x0, 0x5, 0x0}, + {0xa0a1, 0x5, 0x1, 0x1}, + {0xa0c0, 0x0, 0x4, 0x1}, + {0xa20e, 0x4, 0x4, 0xa}, + {0xa20f, 0x0, 0x8, 0x40}, + {0xa210, 0x0, 0x8, 0x8}, + {0xa32a, 0x0, 0x4, 0xa}, + {0xa32c, 0x0, 0x8, 0x20}, + {0xa32b, 0x0, 0x8, 0x15}, + {0xa1a0, 0x1, 0x1, 0x1}, + {0xa000, 0x0, 0x1, 0x1}, + {0xa000, 0x1, 0x1, 0x0}, + {0xa001, 0x1, 0x1, 0x1}, + {0xa001, 0x0, 0x1, 0x0}, + {0xa001, 0x5, 0x1, 0x0}, + {0xa00e, 0x0, 0x5, 0x10}, + {0xa00f, 0x0, 0x3, 0x4}, + {0xa00f, 0x3, 0x3, 0x5}, + {0xa010, 0x0, 0x3, 0x4}, + {0xa010, 0x3, 0x3, 0x5}, + {0xa016, 0x4, 0x4, 0x3}, + {0xa01f, 0x0, 0x6, 0xa}, + {0xa020, 0x0, 0x6, 0xa}, + {0xa2bc, 0x0, 0x1, 0x1}, + {0xa2bc, 0x5, 0x1, 0x1}, + {0xa015, 0x0, 0x8, 0x50}, + {0xa016, 0x0, 0x1, 0x0}, + {0xa02a, 0x0, 0x8, 0x50}, + {0xa029, 0x0, 0x8, 0x4b}, + {0xa614, 0x0, 0x8, 0x46}, + {0xa002, 0x0, 0x5, 0x19}, + {0xa003, 0x0, 0x5, 0x1a}, + {0xa004, 0x0, 0x5, 0x19}, + {0xa005, 0x0, 0x5, 0x1a}, + {0xa008, 0x0, 0x8, 0x69}, + {0xa009, 0x0, 0x2, 0x2}, + {0xae1b, 0x0, 0x8, 0x69}, + {0xae1c, 0x0, 0x8, 0x2}, + {0xae1d, 0x0, 0x8, 0x2a}, + {0xa022, 0x0, 0x8, 0xaa}, + {0xa006, 0x0, 0x8, 0xc8}, + {0xa007, 0x0, 0x2, 0x0}, + {0xa00c, 0x0, 0x8, 0xba}, + {0xa00d, 0x0, 0x2, 0x2}, + {0xa608, 0x0, 0x8, 0xba}, + {0xa60e, 0x0, 0x2, 0x2}, + {0xa609, 0x0, 0x8, 0x80}, + {0xa60e, 0x2, 0x2, 0x3}, + {0xa00a, 0x0, 0x8, 0xb6}, + {0xa00b, 0x0, 0x2, 0x0}, + {0xa011, 0x0, 0x8, 0xb9}, + {0xa012, 0x0, 0x2, 0x0}, + {0xa013, 0x0, 0x8, 0xbd}, + {0xa014, 0x0, 0x2, 0x2}, + {0xa366, 0x0, 0x1, 0x1}, + {0xa2bc, 0x3, 0x1, 0x0}, + {0xa2bd, 0x0, 0x8, 0xa}, + {0xa2be, 0x0, 0x8, 0x14}, + {0xa2bf, 0x0, 0x8, 0x8}, + {0xa60a, 0x0, 0x8, 0xbd}, + {0xa60e, 0x4, 0x2, 0x2}, + {0xa60b, 0x0, 0x8, 0x86}, + {0xa60e, 0x6, 0x2, 0x3}, + {0xa001, 0x2, 0x2, 0x1}, + {0xa1c7, 0x0, 0x8, 0xf5}, + {0xa03d, 0x0, 0x8, 0xb1}, + {0xa616, 0x0, 0x8, 0xff}, + {0xa617, 0x0, 0x8, 0xad}, + {0xa618, 0x0, 0x8, 0xad}, + {0xa61e, 0x3, 0x1, 0x1}, + {0xae1a, 0x0, 0x8, 0x0}, + {0xae19, 0x0, 0x8, 0xc8}, + {0xae18, 0x0, 0x8, 0x61}, + {0xa140, 0x0, 0x8, 0x0}, + {0xa141, 0x0, 0x8, 0xc8}, + {0xa142, 0x0, 0x7, 0x61}, + {0xa023, 0x0, 0x8, 0xff}, + {0xa021, 0x0, 0x8, 0xad}, + {0xa026, 0x0, 0x1, 0x0}, + {0xa024, 0x0, 0x8, 0xff}, + {0xa025, 0x0, 0x8, 0xff}, + {0xa1c8, 0x0, 0x8, 0xf}, + {0xa2bc, 0x1, 0x1, 0x0}, + {0xa60c, 0x0, 0x4, 0x5}, + {0xa60c, 0x4, 0x4, 0x6}, + {0xa60d, 0x0, 0x8, 0xa}, + {0xa371, 0x0, 0x1, 0x1}, + {0xa366, 0x1, 0x3, 0x7}, + {0xa338, 0x0, 0x8, 0x10}, + {0xa339, 0x0, 0x6, 0x7}, + {0xa33a, 0x0, 0x6, 0x1f}, + {0xa33b, 0x0, 0x8, 0xf6}, + {0xa33c, 0x3, 0x5, 0x4}, + {0xa33d, 0x4, 0x4, 0x0}, + {0xa33d, 0x1, 0x1, 0x1}, + {0xa33d, 0x2, 0x1, 0x1}, + {0xa33d, 0x3, 0x1, 0x1}, + {0xa16d, 0x0, 0x4, 0xf}, + {0xa161, 0x0, 0x5, 0x5}, + {0xa162, 0x0, 0x4, 0x5}, + {0xa165, 0x0, 0x8, 0xff}, + {0xa166, 0x0, 0x8, 0x9c}, + {0xa2c3, 0x0, 0x4, 0x5}, + {0xa61a, 0x0, 0x6, 0xf}, + {0xb200, 0x0, 0x8, 0xa1}, + {0xb201, 0x0, 0x8, 0x7}, + {0xa093, 0x0, 0x1, 0x0}, + {0xa093, 0x1, 0x5, 0xf}, + {0xa094, 0x0, 0x8, 0xff}, + {0xa095, 0x0, 0x8, 0xf}, + {0xa080, 0x2, 0x5, 0x3}, + {0xa081, 0x0, 0x4, 0x0}, + {0xa081, 0x4, 0x4, 0x9}, + {0xa082, 0x0, 0x5, 0x1f}, + {0xa08d, 0x0, 0x8, 0x1}, + {0xa083, 0x0, 0x8, 0x32}, + {0xa084, 0x0, 0x1, 0x0}, + {0xa08e, 0x0, 0x8, 0x3}, + {0xa085, 0x0, 0x8, 0x32}, + {0xa086, 0x0, 0x3, 0x0}, + {0xa087, 0x0, 0x8, 0x6e}, + {0xa088, 0x0, 0x5, 0x15}, + {0xa089, 0x0, 0x8, 0x0}, + {0xa08a, 0x0, 0x5, 0x19}, + {0xa08b, 0x0, 0x8, 0x92}, + {0xa08c, 0x0, 0x5, 0x1c}, + {0xa120, 0x0, 0x8, 0x0}, + {0xa121, 0x0, 0x5, 0x10}, + {0xa122, 0x0, 0x8, 0x0}, + {0xa123, 0x0, 0x7, 0x40}, + {0xa123, 0x7, 0x1, 0x0}, + {0xa124, 0x0, 0x8, 0x13}, + {0xa125, 0x0, 0x7, 0x10}, + {0xa1c0, 0x0, 0x8, 0x0}, + {0xa1c1, 0x0, 0x5, 0x4}, + {0xa1c2, 0x0, 0x8, 0x0}, + {0xa1c3, 0x0, 0x5, 0x10}, + {0xa1c3, 0x5, 0x3, 0x0}, + {0xa1c4, 0x0, 0x6, 0x0}, + {0xa1c5, 0x0, 0x7, 0x10}, + {0xa100, 0x0, 0x8, 0x0}, + {0xa101, 0x0, 0x5, 0x10}, + {0xa102, 0x0, 0x8, 0x0}, + {0xa103, 0x0, 0x7, 0x40}, + {0xa103, 0x7, 0x1, 0x0}, + {0xa104, 0x0, 0x8, 0x18}, + {0xa105, 0x0, 0x7, 0xa}, + {0xa106, 0x0, 0x8, 0x20}, + {0xa107, 0x0, 0x8, 0x40}, + {0xa108, 0x0, 0x4, 0x0}, + {0xa38c, 0x0, 0x8, 0xfc}, + {0xa38d, 0x0, 0x8, 0x0}, + {0xa38e, 0x0, 0x8, 0x7e}, + {0xa38f, 0x0, 0x8, 0x0}, + {0xa390, 0x0, 0x8, 0x2f}, + {0xa60f, 0x5, 0x1, 0x1}, + {0xa170, 0x0, 0x8, 0xdc}, + {0xa171, 0x0, 0x2, 0x0}, + {0xa2ae, 0x0, 0x1, 0x1}, + {0xa2ae, 0x1, 0x1, 0x1}, + {0xa392, 0x0, 0x1, 0x1}, + {0xa391, 0x2, 0x1, 0x0}, + {0xabc1, 0x0, 0x8, 0xff}, + {0xabc2, 0x0, 0x8, 0x0}, + {0xabc8, 0x0, 0x8, 0x8}, + {0xabca, 0x0, 0x8, 0x10}, + {0xabcb, 0x0, 0x1, 0x0}, + {0xabc3, 0x5, 0x3, 0x7}, + {0xabc0, 0x6, 0x1, 0x0}, + {0xabc0, 0x4, 0x2, 0x0}, + {0xa344, 0x4, 0x4, 0x1}, + {0xabc0, 0x7, 0x1, 0x1}, + {0xabc0, 0x2, 0x1, 0x1}, + {0xa345, 0x0, 0x8, 0x66}, + {0xa346, 0x0, 0x8, 0x66}, + {0xa347, 0x0, 0x4, 0x0}, + {0xa343, 0x0, 0x4, 0xa}, + {0xa347, 0x4, 0x4, 0x2}, + {0xa348, 0x0, 0x4, 0xc}, + {0xa348, 0x4, 0x4, 0x7}, + {0xa349, 0x0, 0x6, 0x2}, +}; diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c new file mode 100644 index 000000000000..7db6eee50e39 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/af9005.c @@ -0,0 +1,1141 @@ +/* DVB USB compliant Linux driver for the Afatech 9005 + * USB1.1 DVB-T receiver. + * + * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org) + * + * Thanks to Afatech who kindly provided information. + * + * 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. + * + * see Documentation/dvb/REDME.dvb-usb for more information + */ +#include "af9005.h" + +/* debug */ +int dvb_usb_af9005_debug; +module_param_named(debug, dvb_usb_af9005_debug, int, 0644); +MODULE_PARM_DESC(debug, + "set debugging level (1=info,xfer=2,rc=4,reg=8,i2c=16,fw=32 (or-able))." + DVB_USB_DEBUG_STATUS); +/* enable obnoxious led */ +int dvb_usb_af9005_led = 1; +module_param_named(led, dvb_usb_af9005_led, bool, 0644); +MODULE_PARM_DESC(led, "enable led (default: 1)."); + +/* eeprom dump */ +int dvb_usb_af9005_dump_eeprom = 0; +module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0); +MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom."); + +/* remote control decoder */ +int (*rc_decode) (struct dvb_usb_device * d, u8 * data, int len, u32 * event, + int *state); +void *rc_keys; +int *rc_keys_size; + +u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; + +struct af9005_device_state { + u8 sequence; + int led_state; +}; + +int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 * wbuf, u16 wlen, + u8 * rbuf, u16 rlen, int delay_ms) +{ + int actlen, ret = -ENOMEM; + + if (wbuf == NULL || wlen == 0) + return -EINVAL; + + if ((ret = mutex_lock_interruptible(&d->usb_mutex))) + return ret; + + deb_xfer(">>> "); + debug_dump(wbuf, wlen, deb_xfer); + + ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev, + 2), wbuf, wlen, + &actlen, 2000); + + if (ret) + err("bulk message failed: %d (%d/%d)", ret, wlen, actlen); + else + ret = actlen != wlen ? -1 : 0; + + /* an answer is expected, and no error before */ + if (!ret && rbuf && rlen) { + if (delay_ms) + msleep(delay_ms); + + ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, + 0x01), rbuf, + rlen, &actlen, 2000); + + if (ret) + err("recv bulk message failed: %d", ret); + else { + deb_xfer("<<< "); + debug_dump(rbuf, actlen, deb_xfer); + } + } + + mutex_unlock(&d->usb_mutex); + return ret; +} + +int af9005_usb_generic_write(struct dvb_usb_device *d, u8 * buf, u16 len) +{ + return af9005_usb_generic_rw(d, buf, len, NULL, 0, 0); +} + +int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg, + int readwrite, int type, u8 * values, int len) +{ + struct af9005_device_state *st = d->priv; + u8 obuf[16] = { 0 }; + u8 ibuf[17] = { 0 }; + u8 command; + int i; + int ret; + + if (len < 1) { + err("generic read/write, less than 1 byte. Makes no sense."); + return -EINVAL; + } + if (len > 8) { + err("generic read/write, more than 8 bytes. Not supported."); + return -EINVAL; + } + + obuf[0] = 14; /* rest of buffer length low */ + obuf[1] = 0; /* rest of buffer length high */ + + obuf[2] = AF9005_REGISTER_RW; /* register operation */ + obuf[3] = 12; /* rest of buffer length */ + + obuf[4] = st->sequence++; /* sequence number */ + + obuf[5] = (u8) (reg >> 8); /* register address */ + obuf[6] = (u8) (reg & 0xff); + + if (type == AF9005_OFDM_REG) { + command = AF9005_CMD_OFDM_REG; + } else { + command = AF9005_CMD_TUNER; + } + + if (len > 1) + command |= + AF9005_CMD_BURST | AF9005_CMD_AUTOINC | (len - 1) << 3; + command |= readwrite; + if (readwrite == AF9005_CMD_WRITE) + for (i = 0; i < len; i++) + obuf[8 + i] = values[i]; + else if (type == AF9005_TUNER_REG) + /* read command for tuner, the first byte contains the i2c address */ + obuf[8] = values[0]; + obuf[7] = command; + + ret = af9005_usb_generic_rw(d, obuf, 16, ibuf, 17, 0); + if (ret) + return ret; + + /* sanity check */ + if (ibuf[2] != AF9005_REGISTER_RW_ACK) { + err("generic read/write, wrong reply code."); + return -EIO; + } + if (ibuf[3] != 0x0d) { + err("generic read/write, wrong length in reply."); + return -EIO; + } + if (ibuf[4] != obuf[4]) { + err("generic read/write, wrong sequence in reply."); + return -EIO; + } + /* + Windows driver doesn't check these fields, in fact sometimes + the register in the reply is different that what has been sent + + if (ibuf[5] != obuf[5] || ibuf[6] != obuf[6]) { + err("generic read/write, wrong register in reply."); + return -EIO; + } + if (ibuf[7] != command) { + err("generic read/write wrong command in reply."); + return -EIO; + } + */ + if (ibuf[16] != 0x01) { + err("generic read/write wrong status code in reply."); + return -EIO; + } + if (readwrite == AF9005_CMD_READ) + for (i = 0; i < len; i++) + values[i] = ibuf[8 + i]; + + return 0; + +} + +int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 * value) +{ + int ret; + deb_reg("read register %x ", reg); + ret = af9005_generic_read_write(d, reg, + AF9005_CMD_READ, AF9005_OFDM_REG, + value, 1); + if (ret) + deb_reg("failed\n"); + else + deb_reg("value %x\n", *value); + return ret; +} + +int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg, + u8 * values, int len) +{ + int ret; + deb_reg("read %d registers %x ", len, reg); + ret = af9005_generic_read_write(d, reg, + AF9005_CMD_READ, AF9005_OFDM_REG, + values, len); + if (ret) + deb_reg("failed\n"); + else + debug_dump(values, len, deb_reg); + return ret; +} + +int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 value) +{ + int ret; + u8 temp = value; + deb_reg("write register %x value %x ", reg, value); + ret = af9005_generic_read_write(d, reg, + AF9005_CMD_WRITE, AF9005_OFDM_REG, + &temp, 1); + if (ret) + deb_reg("failed\n"); + else + deb_reg("ok\n"); + return ret; +} + +int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg, + u8 * values, int len) +{ + int ret; + deb_reg("write %d registers %x values ", len, reg); + debug_dump(values, len, deb_reg); + + ret = af9005_generic_read_write(d, reg, + AF9005_CMD_WRITE, AF9005_OFDM_REG, + values, len); + if (ret) + deb_reg("failed\n"); + else + deb_reg("ok\n"); + return ret; +} + +int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos, + u8 len, u8 * value) +{ + u8 temp; + int ret; + deb_reg("read bits %x %x %x", reg, pos, len); + ret = af9005_read_ofdm_register(d, reg, &temp); + if (ret) { + deb_reg(" failed\n"); + return ret; + } + *value = (temp >> pos) & regmask[len - 1]; + deb_reg(" value %x\n", *value); + return 0; + +} + +int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos, + u8 len, u8 value) +{ + u8 temp, mask; + int ret; + deb_reg("write bits %x %x %x value %x\n", reg, pos, len, value); + if (pos == 0 && len == 8) + return af9005_write_ofdm_register(d, reg, value); + ret = af9005_read_ofdm_register(d, reg, &temp); + if (ret) + return ret; + mask = regmask[len - 1] << pos; + temp = (temp & ~mask) | ((value << pos) & mask); + return af9005_write_ofdm_register(d, reg, temp); + +} + +static int af9005_usb_read_tuner_registers(struct dvb_usb_device *d, + u16 reg, u8 * values, int len) +{ + return af9005_generic_read_write(d, reg, + AF9005_CMD_READ, AF9005_TUNER_REG, + values, len); +} + +static int af9005_usb_write_tuner_registers(struct dvb_usb_device *d, + u16 reg, u8 * values, int len) +{ + return af9005_generic_read_write(d, reg, + AF9005_CMD_WRITE, + AF9005_TUNER_REG, values, len); +} + +int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg, + u8 * values, int len) +{ + /* don't let the name of this function mislead you: it's just used + as an interface from the firmware to the i2c bus. The actual + i2c addresses are contained in the data */ + int ret, i, done = 0, fail = 0; + u8 temp; + ret = af9005_usb_write_tuner_registers(d, reg, values, len); + if (ret) + return ret; + if (reg != 0xffff) { + /* check if write done (0xa40d bit 1) or fail (0xa40d bit 2) */ + for (i = 0; i < 200; i++) { + ret = + af9005_read_ofdm_register(d, + xd_I2C_i2c_m_status_wdat_done, + &temp); + if (ret) + return ret; + done = temp & (regmask[i2c_m_status_wdat_done_len - 1] + << i2c_m_status_wdat_done_pos); + if (done) + break; + fail = temp & (regmask[i2c_m_status_wdat_fail_len - 1] + << i2c_m_status_wdat_fail_pos); + if (fail) + break; + msleep(50); + } + if (i == 200) + return -ETIMEDOUT; + if (fail) { + /* clear write fail bit */ + af9005_write_register_bits(d, + xd_I2C_i2c_m_status_wdat_fail, + i2c_m_status_wdat_fail_pos, + i2c_m_status_wdat_fail_len, + 1); + return -EIO; + } + /* clear write done bit */ + ret = + af9005_write_register_bits(d, + xd_I2C_i2c_m_status_wdat_fail, + i2c_m_status_wdat_done_pos, + i2c_m_status_wdat_done_len, 1); + if (ret) + return ret; + } + return 0; +} + +int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg, u8 addr, + u8 * values, int len) +{ + /* don't let the name of this function mislead you: it's just used + as an interface from the firmware to the i2c bus. The actual + i2c addresses are contained in the data */ + int ret, i; + u8 temp, buf[2]; + + buf[0] = addr; /* tuner i2c address */ + buf[1] = values[0]; /* tuner register */ + + values[0] = addr + 0x01; /* i2c read address */ + + if (reg == APO_REG_I2C_RW_SILICON_TUNER) { + /* write tuner i2c address to tuner, 0c00c0 undocumented, found by sniffing */ + ret = af9005_write_tuner_registers(d, 0x00c0, buf, 2); + if (ret) + return ret; + } + + /* send read command to ofsm */ + ret = af9005_usb_read_tuner_registers(d, reg, values, 1); + if (ret) + return ret; + + /* check if read done */ + for (i = 0; i < 200; i++) { + ret = af9005_read_ofdm_register(d, 0xa408, &temp); + if (ret) + return ret; + if (temp & 0x01) + break; + msleep(50); + } + if (i == 200) + return -ETIMEDOUT; + + /* clear read done bit (by writing 1) */ + ret = af9005_write_ofdm_register(d, xd_I2C_i2c_m_data8, 1); + if (ret) + return ret; + + /* get read data (available from 0xa400) */ + for (i = 0; i < len; i++) { + ret = af9005_read_ofdm_register(d, 0xa400 + i, &temp); + if (ret) + return ret; + values[i] = temp; + } + return 0; +} + +static int af9005_i2c_write(struct dvb_usb_device *d, u8 i2caddr, u8 reg, + u8 * data, int len) +{ + int ret, i; + u8 buf[3]; + deb_i2c("i2c_write i2caddr %x, reg %x, len %d data ", i2caddr, + reg, len); + debug_dump(data, len, deb_i2c); + + for (i = 0; i < len; i++) { + buf[0] = i2caddr; + buf[1] = reg + (u8) i; + buf[2] = data[i]; + ret = + af9005_write_tuner_registers(d, + APO_REG_I2C_RW_SILICON_TUNER, + buf, 3); + if (ret) { + deb_i2c("i2c_write failed\n"); + return ret; + } + } + deb_i2c("i2c_write ok\n"); + return 0; +} + +static int af9005_i2c_read(struct dvb_usb_device *d, u8 i2caddr, u8 reg, + u8 * data, int len) +{ + int ret, i; + u8 temp; + deb_i2c("i2c_read i2caddr %x, reg %x, len %d\n ", i2caddr, reg, len); + for (i = 0; i < len; i++) { + temp = reg + i; + ret = + af9005_read_tuner_registers(d, + APO_REG_I2C_RW_SILICON_TUNER, + i2caddr, &temp, 1); + if (ret) { + deb_i2c("i2c_read failed\n"); + return ret; + } + data[i] = temp; + } + deb_i2c("i2c data read: "); + debug_dump(data, len, deb_i2c); + return 0; +} + +static int af9005_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + /* only implements what the mt2060 module does, don't know how + to make it really generic */ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret; + u8 reg, addr; + u8 *value; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + if (num > 2) + warn("more than 2 i2c messages at a time is not handled yet. TODO."); + + if (num == 2) { + /* reads a single register */ + reg = *msg[0].buf; + addr = msg[0].addr; + value = msg[1].buf; + ret = af9005_i2c_read(d, addr, reg, value, 1); + if (ret == 0) + ret = 2; + } else { + /* write one or more registers */ + reg = msg[0].buf[0]; + addr = msg[0].addr; + value = &msg[0].buf[1]; + ret = af9005_i2c_write(d, addr, reg, value, msg[0].len - 1); + if (ret == 0) + ret = 1; + } + + mutex_unlock(&d->i2c_mutex); + return ret; +} + +static u32 af9005_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm af9005_i2c_algo = { + .master_xfer = af9005_i2c_xfer, + .functionality = af9005_i2c_func, +}; + +int af9005_send_command(struct dvb_usb_device *d, u8 command, u8 * wbuf, + int wlen, u8 * rbuf, int rlen) +{ + struct af9005_device_state *st = d->priv; + + int ret, i, packet_len; + u8 buf[64]; + u8 ibuf[64]; + + if (wlen < 0) { + err("send command, wlen less than 0 bytes. Makes no sense."); + return -EINVAL; + } + if (wlen > 54) { + err("send command, wlen more than 54 bytes. Not supported."); + return -EINVAL; + } + if (rlen > 54) { + err("send command, rlen more than 54 bytes. Not supported."); + return -EINVAL; + } + packet_len = wlen + 5; + buf[0] = (u8) (packet_len & 0xff); + buf[1] = (u8) ((packet_len & 0xff00) >> 8); + + buf[2] = 0x26; /* packet type */ + buf[3] = wlen + 3; + buf[4] = st->sequence++; + buf[5] = command; + buf[6] = wlen; + for (i = 0; i < wlen; i++) + buf[7 + i] = wbuf[i]; + ret = af9005_usb_generic_rw(d, buf, wlen + 7, ibuf, rlen + 7, 0); + if (ret) + return ret; + if (ibuf[2] != 0x27) { + err("send command, wrong reply code."); + return -EIO; + } + if (ibuf[4] != buf[4]) { + err("send command, wrong sequence in reply."); + return -EIO; + } + if (ibuf[5] != 0x01) { + err("send command, wrong status code in reply."); + return -EIO; + } + if (ibuf[6] != rlen) { + err("send command, invalid data length in reply."); + return -EIO; + } + for (i = 0; i < rlen; i++) + rbuf[i] = ibuf[i + 7]; + return 0; +} + +int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, u8 * values, + int len) +{ + struct af9005_device_state *st = d->priv; + u8 obuf[16], ibuf[14]; + int ret, i; + + memset(obuf, 0, sizeof(obuf)); + memset(ibuf, 0, sizeof(ibuf)); + + obuf[0] = 14; /* length of rest of packet low */ + obuf[1] = 0; /* length of rest of packer high */ + + obuf[2] = 0x2a; /* read/write eeprom */ + + obuf[3] = 12; /* size */ + + obuf[4] = st->sequence++; + + obuf[5] = 0; /* read */ + + obuf[6] = len; + obuf[7] = address; + ret = af9005_usb_generic_rw(d, obuf, 16, ibuf, 14, 0); + if (ret) + return ret; + if (ibuf[2] != 0x2b) { + err("Read eeprom, invalid reply code"); + return -EIO; + } + if (ibuf[3] != 10) { + err("Read eeprom, invalid reply length"); + return -EIO; + } + if (ibuf[4] != obuf[4]) { + err("Read eeprom, wrong sequence in reply "); + return -EIO; + } + if (ibuf[5] != 1) { + err("Read eeprom, wrong status in reply "); + return -EIO; + } + for (i = 0; i < len; i++) { + values[i] = ibuf[6 + i]; + } + return 0; +} + +static int af9005_boot_packet(struct usb_device *udev, int type, u8 * reply) +{ + u8 buf[FW_BULKOUT_SIZE + 2]; + u16 checksum; + int act_len, i, ret; + memset(buf, 0, sizeof(buf)); + buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff); + buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff); + switch (type) { + case FW_CONFIG: + buf[2] = 0x11; + buf[3] = 0x04; + buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */ + buf[5] = 0x03; + checksum = buf[4] + buf[5]; + buf[6] = (u8) ((checksum >> 8) & 0xff); + buf[7] = (u8) (checksum & 0xff); + break; + case FW_CONFIRM: + buf[2] = 0x11; + buf[3] = 0x04; + buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */ + buf[5] = 0x01; + checksum = buf[4] + buf[5]; + buf[6] = (u8) ((checksum >> 8) & 0xff); + buf[7] = (u8) (checksum & 0xff); + break; + case FW_BOOT: + buf[2] = 0x10; + buf[3] = 0x08; + buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */ + buf[5] = 0x97; + buf[6] = 0xaa; + buf[7] = 0x55; + buf[8] = 0xa5; + buf[9] = 0x5a; + checksum = 0; + for (i = 4; i <= 9; i++) + checksum += buf[i]; + buf[10] = (u8) ((checksum >> 8) & 0xff); + buf[11] = (u8) (checksum & 0xff); + break; + default: + err("boot packet invalid boot packet type"); + return -EINVAL; + } + deb_fw(">>> "); + debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw); + + ret = usb_bulk_msg(udev, + usb_sndbulkpipe(udev, 0x02), + buf, FW_BULKOUT_SIZE + 2, &act_len, 2000); + if (ret) + err("boot packet bulk message failed: %d (%d/%d)", ret, + FW_BULKOUT_SIZE + 2, act_len); + else + ret = act_len != FW_BULKOUT_SIZE + 2 ? -1 : 0; + if (ret) + return ret; + memset(buf, 0, 9); + ret = usb_bulk_msg(udev, + usb_rcvbulkpipe(udev, 0x01), buf, 9, &act_len, 2000); + if (ret) { + err("boot packet recv bulk message failed: %d", ret); + return ret; + } + deb_fw("<<< "); + debug_dump(buf, act_len, deb_fw); + checksum = 0; + switch (type) { + case FW_CONFIG: + if (buf[2] != 0x11) { + err("boot bad config header."); + return -EIO; + } + if (buf[3] != 0x05) { + err("boot bad config size."); + return -EIO; + } + if (buf[4] != 0x00) { + err("boot bad config sequence."); + return -EIO; + } + if (buf[5] != 0x04) { + err("boot bad config subtype."); + return -EIO; + } + for (i = 4; i <= 6; i++) + checksum += buf[i]; + if (buf[7] * 256 + buf[8] != checksum) { + err("boot bad config checksum."); + return -EIO; + } + *reply = buf[6]; + break; + case FW_CONFIRM: + if (buf[2] != 0x11) { + err("boot bad confirm header."); + return -EIO; + } + if (buf[3] != 0x05) { + err("boot bad confirm size."); + return -EIO; + } + if (buf[4] != 0x00) { + err("boot bad confirm sequence."); + return -EIO; + } + if (buf[5] != 0x02) { + err("boot bad confirm subtype."); + return -EIO; + } + for (i = 4; i <= 6; i++) + checksum += buf[i]; + if (buf[7] * 256 + buf[8] != checksum) { + err("boot bad confirm checksum."); + return -EIO; + } + *reply = buf[6]; + break; + case FW_BOOT: + if (buf[2] != 0x10) { + err("boot bad boot header."); + return -EIO; + } + if (buf[3] != 0x05) { + err("boot bad boot size."); + return -EIO; + } + if (buf[4] != 0x00) { + err("boot bad boot sequence."); + return -EIO; + } + if (buf[5] != 0x01) { + err("boot bad boot pattern 01."); + return -EIO; + } + if (buf[6] != 0x10) { + err("boot bad boot pattern 10."); + return -EIO; + } + for (i = 4; i <= 6; i++) + checksum += buf[i]; + if (buf[7] * 256 + buf[8] != checksum) { + err("boot bad boot checksum."); + return -EIO; + } + break; + + } + + return 0; +} + +int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw) +{ + int i, packets, ret, act_len; + + u8 buf[FW_BULKOUT_SIZE + 2]; + u8 reply; + + ret = af9005_boot_packet(udev, FW_CONFIG, &reply); + if (ret) + return ret; + if (reply != 0x01) { + err("before downloading firmware, FW_CONFIG expected 0x01, received 0x%x", reply); + return -EIO; + } + packets = fw->size / FW_BULKOUT_SIZE; + buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff); + buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff); + for (i = 0; i < packets; i++) { + memcpy(&buf[2], fw->data + i * FW_BULKOUT_SIZE, + FW_BULKOUT_SIZE); + deb_fw(">>> "); + debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw); + ret = usb_bulk_msg(udev, + usb_sndbulkpipe(udev, 0x02), + buf, FW_BULKOUT_SIZE + 2, &act_len, 1000); + if (ret) { + err("firmware download failed at packet %d with code %d", i, ret); + return ret; + } + } + ret = af9005_boot_packet(udev, FW_CONFIRM, &reply); + if (ret) + return ret; + if (reply != (u8) (packets & 0xff)) { + err("after downloading firmware, FW_CONFIRM expected 0x%x, received 0x%x", packets & 0xff, reply); + return -EIO; + } + ret = af9005_boot_packet(udev, FW_BOOT, &reply); + if (ret) + return ret; + ret = af9005_boot_packet(udev, FW_CONFIG, &reply); + if (ret) + return ret; + if (reply != 0x02) { + err("after downloading firmware, FW_CONFIG expected 0x02, received 0x%x", reply); + return -EIO; + } + + return 0; + +} + +int af9005_led_control(struct dvb_usb_device *d, int onoff) +{ + struct af9005_device_state *st = d->priv; + int temp, ret; + + if (onoff && dvb_usb_af9005_led) + temp = 1; + else + temp = 0; + if (st->led_state != temp) { + ret = + af9005_write_register_bits(d, xd_p_reg_top_locken1, + reg_top_locken1_pos, + reg_top_locken1_len, temp); + if (ret) + return ret; + ret = + af9005_write_register_bits(d, xd_p_reg_top_lock1, + reg_top_lock1_pos, + reg_top_lock1_len, temp); + if (ret) + return ret; + st->led_state = temp; + } + return 0; +} + +static int af9005_frontend_attach(struct dvb_usb_adapter *adap) +{ + u8 buf[8]; + int i; + + /* without these calls the first commands after downloading + the firmware fail. I put these calls here to simulate + what it is done in dvb-usb-init.c. + */ + struct usb_device *udev = adap->dev->udev; + usb_clear_halt(udev, usb_sndbulkpipe(udev, 2)); + usb_clear_halt(udev, usb_rcvbulkpipe(udev, 1)); + if (dvb_usb_af9005_dump_eeprom) { + printk("EEPROM DUMP\n"); + for (i = 0; i < 255; i += 8) { + af9005_read_eeprom(adap->dev, i, buf, 8); + printk("ADDR %x ", i); + debug_dump(buf, 8, printk); + } + } + adap->fe = af9005_fe_attach(adap->dev); + return 0; +} + +static int af9005_rc_query(struct dvb_usb_device *d, u32 * event, int *state) +{ + struct af9005_device_state *st = d->priv; + int ret, len; + + u8 obuf[5]; + u8 ibuf[256]; + + *state = REMOTE_NO_KEY_PRESSED; + if (rc_decode == NULL) { + /* it shouldn't never come here */ + return 0; + } + /* deb_info("rc_query\n"); */ + obuf[0] = 3; /* rest of packet length low */ + obuf[1] = 0; /* rest of packet lentgh high */ + obuf[2] = 0x40; /* read remote */ + obuf[3] = 1; /* rest of packet length */ + obuf[4] = st->sequence++; /* sequence number */ + ret = af9005_usb_generic_rw(d, obuf, 5, ibuf, 256, 0); + if (ret) { + err("rc query failed"); + return ret; + } + if (ibuf[2] != 0x41) { + err("rc query bad header."); + return -EIO; + } + if (ibuf[4] != obuf[4]) { + err("rc query bad sequence."); + return -EIO; + } + len = ibuf[5]; + if (len > 246) { + err("rc query invalid length"); + return -EIO; + } + if (len > 0) { + deb_rc("rc data (%d) ", len); + debug_dump((ibuf + 6), len, deb_rc); + ret = rc_decode(d, &ibuf[6], len, event, state); + if (ret) { + err("rc_decode failed"); + return ret; + } else { + deb_rc("rc_decode state %x event %x\n", *state, *event); + if (*state == REMOTE_KEY_REPEAT) + *event = d->last_event; + } + } + return 0; +} + +static int af9005_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + + return 0; +} + +static int af9005_pid_filter_control(struct dvb_usb_adapter *adap, int onoff) +{ + int ret; + deb_info("pid filter control onoff %d\n", onoff); + if (onoff) { + ret = + af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1); + if (ret) + return ret; + ret = + af9005_write_register_bits(adap->dev, + XD_MP2IF_DMX_CTRL, 1, 1, 1); + if (ret) + return ret; + ret = + af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1); + } else + ret = + af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 0); + if (ret) + return ret; + deb_info("pid filter control ok\n"); + return 0; +} + +static int af9005_pid_filter(struct dvb_usb_adapter *adap, int index, + u16 pid, int onoff) +{ + u8 cmd = index & 0x1f; + int ret; + deb_info("set pid filter, index %d, pid %x, onoff %d\n", index, + pid, onoff); + if (onoff) { + /* cannot use it as pid_filter_ctrl since it has to be done + before setting the first pid */ + if (adap->feedcount == 1) { + deb_info("first pid set, enable pid table\n"); + ret = af9005_pid_filter_control(adap, onoff); + if (ret) + return ret; + } + ret = + af9005_write_ofdm_register(adap->dev, + XD_MP2IF_PID_DATA_L, + (u8) (pid & 0xff)); + if (ret) + return ret; + ret = + af9005_write_ofdm_register(adap->dev, + XD_MP2IF_PID_DATA_H, + (u8) (pid >> 8)); + if (ret) + return ret; + cmd |= 0x20 | 0x40; + } else { + if (adap->feedcount == 0) { + deb_info("last pid unset, disable pid table\n"); + ret = af9005_pid_filter_control(adap, onoff); + if (ret) + return ret; + } + } + ret = af9005_write_ofdm_register(adap->dev, XD_MP2IF_PID_IDX, cmd); + if (ret) + return ret; + deb_info("set pid ok\n"); + return 0; +} + +static int af9005_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, + int *cold) +{ + int ret; + u8 reply; + ret = af9005_boot_packet(udev, FW_CONFIG, &reply); + if (ret) + return ret; + deb_info("result of FW_CONFIG in identify state %d\n", reply); + if (reply == 0x01) + *cold = 1; + else if (reply == 0x02) + *cold = 0; + else + return -EIO; + deb_info("Identify state cold = %d\n", *cold); + return 0; +} + +static struct dvb_usb_device_properties af9005_properties; + +static int af9005_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return dvb_usb_device_init(intf, &af9005_properties, THIS_MODULE, NULL); +} + +static struct usb_device_id af9005_usb_table[] = { + {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9005)}, + {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE)}, + {0}, +}; + +MODULE_DEVICE_TABLE(usb, af9005_usb_table); + +static struct dvb_usb_device_properties af9005_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "af9005.fw", + .download_firmware = af9005_download_firmware, + .no_reconnect = 1, + + .size_of_priv = sizeof(struct af9005_device_state), + + .num_adapters = 1, + .adapter = { + { + .caps = + DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = af9005_pid_filter, + /* .pid_filter_ctrl = af9005_pid_filter_control, */ + .frontend_attach = af9005_frontend_attach, + /* .tuner_attach = af9005_tuner_attach, */ + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 10, + .endpoint = 0x04, + .u = { + .bulk = { + .buffersize = 4096, /* actual size seen is 3948 */ + } + } + }, + } + }, + .power_ctrl = af9005_power_ctrl, + .identify_state = af9005_identify_state, + + .i2c_algo = &af9005_i2c_algo, + + .rc_interval = 200, + .rc_key_map = NULL, + .rc_key_map_size = 0, + .rc_query = af9005_rc_query, + + .num_device_descs = 2, + .devices = { + {.name = "Afatech DVB-T USB1.1 stick", + .cold_ids = {&af9005_usb_table[0], NULL}, + .warm_ids = {NULL}, + }, + {.name = "TerraTec Cinergy T USB XE", + .cold_ids = {&af9005_usb_table[1], NULL}, + .warm_ids = {NULL}, + }, + {NULL}, + } +}; + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver af9005_usb_driver = { + .name = "dvb_usb_af9005", + .probe = af9005_usb_probe, + .disconnect = dvb_usb_device_exit, + .id_table = af9005_usb_table, +}; + +/* module stuff */ +static int __init af9005_usb_module_init(void) +{ + int result; + if ((result = usb_register(&af9005_usb_driver))) { + err("usb_register failed. (%d)", result); + return result; + } + rc_decode = symbol_request(af9005_rc_decode); + rc_keys = symbol_request(af9005_rc_keys); + rc_keys_size = symbol_request(af9005_rc_keys_size); + if (rc_decode == NULL || rc_keys == NULL || rc_keys_size == NULL) { + err("af9005_rc_decode function not found, disabling remote"); + af9005_properties.rc_query = NULL; + } else { + af9005_properties.rc_key_map = rc_keys; + af9005_properties.rc_key_map_size = *rc_keys_size; + } + + return 0; +} + +static void __exit af9005_usb_module_exit(void) +{ + /* release rc decode symbols */ + if (rc_decode != NULL) + symbol_put(af9005_rc_decode); + if (rc_keys != NULL) + symbol_put(af9005_rc_keys); + if (rc_keys_size != NULL) + symbol_put(af9005_rc_keys_size); + /* deregister this driver from the USB subsystem */ + usb_deregister(&af9005_usb_driver); +} + +module_init(af9005_usb_module_init); +module_exit(af9005_usb_module_exit); + +MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>"); +MODULE_DESCRIPTION("Driver for Afatech 9005 DVB-T USB1.1 stick"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/af9005.h b/drivers/media/dvb/dvb-usb/af9005.h new file mode 100644 index 000000000000..0bc48a012187 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/af9005.h @@ -0,0 +1,3496 @@ +/* Common header-file of the Linux driver for the Afatech 9005 + * USB1.1 DVB-T receiver. + * + * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org) + * + * Thanks to Afatech who kindly provided information. + * + * 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. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#ifndef _DVB_USB_AF9005_H_ +#define _DVB_USB_AF9005_H_ + +#define DVB_USB_LOG_PREFIX "af9005" +#include "dvb-usb.h" + +extern int dvb_usb_af9005_debug; +#define deb_info(args...) dprintk(dvb_usb_af9005_debug,0x01,args) +#define deb_xfer(args...) dprintk(dvb_usb_af9005_debug,0x02,args) +#define deb_rc(args...) dprintk(dvb_usb_af9005_debug,0x04,args) +#define deb_reg(args...) dprintk(dvb_usb_af9005_debug,0x08,args) +#define deb_i2c(args...) dprintk(dvb_usb_af9005_debug,0x10,args) +#define deb_fw(args...) dprintk(dvb_usb_af9005_debug,0x20,args) + +extern int dvb_usb_af9005_led; + +/* firmware */ +#define FW_BULKOUT_SIZE 250 +enum { + FW_CONFIG, + FW_CONFIRM, + FW_BOOT +}; + +/* af9005 commands */ +#define AF9005_OFDM_REG 0 +#define AF9005_TUNER_REG 1 + +#define AF9005_REGISTER_RW 0x20 +#define AF9005_REGISTER_RW_ACK 0x21 + +#define AF9005_CMD_OFDM_REG 0x00 +#define AF9005_CMD_TUNER 0x80 +#define AF9005_CMD_BURST 0x02 +#define AF9005_CMD_AUTOINC 0x04 +#define AF9005_CMD_READ 0x00 +#define AF9005_CMD_WRITE 0x01 + +/* af9005 registers */ +#define APO_REG_RESET 0xAEFF + +#define APO_REG_I2C_RW_CAN_TUNER 0xF000 +#define APO_REG_I2C_RW_SILICON_TUNER 0xF001 +#define APO_REG_GPIO_RW_SILICON_TUNER 0xFFFE /* also for OFSM */ +#define APO_REG_TRIGGER_OFSM 0xFFFF /* also for OFSM */ + +/*********************************************************************** + * Apollo Registers from VLSI * + ***********************************************************************/ +#define xd_p_reg_aagc_inverted_agc 0xA000 +#define reg_aagc_inverted_agc_pos 0 +#define reg_aagc_inverted_agc_len 1 +#define reg_aagc_inverted_agc_lsb 0 +#define xd_p_reg_aagc_sign_only 0xA000 +#define reg_aagc_sign_only_pos 1 +#define reg_aagc_sign_only_len 1 +#define reg_aagc_sign_only_lsb 0 +#define xd_p_reg_aagc_slow_adc_en 0xA000 +#define reg_aagc_slow_adc_en_pos 2 +#define reg_aagc_slow_adc_en_len 1 +#define reg_aagc_slow_adc_en_lsb 0 +#define xd_p_reg_aagc_slow_adc_scale 0xA000 +#define reg_aagc_slow_adc_scale_pos 3 +#define reg_aagc_slow_adc_scale_len 5 +#define reg_aagc_slow_adc_scale_lsb 0 +#define xd_p_reg_aagc_check_slow_adc_lock 0xA001 +#define reg_aagc_check_slow_adc_lock_pos 0 +#define reg_aagc_check_slow_adc_lock_len 1 +#define reg_aagc_check_slow_adc_lock_lsb 0 +#define xd_p_reg_aagc_init_control 0xA001 +#define reg_aagc_init_control_pos 1 +#define reg_aagc_init_control_len 1 +#define reg_aagc_init_control_lsb 0 +#define xd_p_reg_aagc_total_gain_sel 0xA001 +#define reg_aagc_total_gain_sel_pos 2 +#define reg_aagc_total_gain_sel_len 2 +#define reg_aagc_total_gain_sel_lsb 0 +#define xd_p_reg_aagc_out_inv 0xA001 +#define reg_aagc_out_inv_pos 5 +#define reg_aagc_out_inv_len 1 +#define reg_aagc_out_inv_lsb 0 +#define xd_p_reg_aagc_int_en 0xA001 +#define reg_aagc_int_en_pos 6 +#define reg_aagc_int_en_len 1 +#define reg_aagc_int_en_lsb 0 +#define xd_p_reg_aagc_lock_change_flag 0xA001 +#define reg_aagc_lock_change_flag_pos 7 +#define reg_aagc_lock_change_flag_len 1 +#define reg_aagc_lock_change_flag_lsb 0 +#define xd_p_reg_aagc_rf_loop_bw_scale_acquire 0xA002 +#define reg_aagc_rf_loop_bw_scale_acquire_pos 0 +#define reg_aagc_rf_loop_bw_scale_acquire_len 5 +#define reg_aagc_rf_loop_bw_scale_acquire_lsb 0 +#define xd_p_reg_aagc_rf_loop_bw_scale_track 0xA003 +#define reg_aagc_rf_loop_bw_scale_track_pos 0 +#define reg_aagc_rf_loop_bw_scale_track_len 5 +#define reg_aagc_rf_loop_bw_scale_track_lsb 0 +#define xd_p_reg_aagc_if_loop_bw_scale_acquire 0xA004 +#define reg_aagc_if_loop_bw_scale_acquire_pos 0 +#define reg_aagc_if_loop_bw_scale_acquire_len 5 +#define reg_aagc_if_loop_bw_scale_acquire_lsb 0 +#define xd_p_reg_aagc_if_loop_bw_scale_track 0xA005 +#define reg_aagc_if_loop_bw_scale_track_pos 0 +#define reg_aagc_if_loop_bw_scale_track_len 5 +#define reg_aagc_if_loop_bw_scale_track_lsb 0 +#define xd_p_reg_aagc_max_rf_agc_7_0 0xA006 +#define reg_aagc_max_rf_agc_7_0_pos 0 +#define reg_aagc_max_rf_agc_7_0_len 8 +#define reg_aagc_max_rf_agc_7_0_lsb 0 +#define xd_p_reg_aagc_max_rf_agc_9_8 0xA007 +#define reg_aagc_max_rf_agc_9_8_pos 0 +#define reg_aagc_max_rf_agc_9_8_len 2 +#define reg_aagc_max_rf_agc_9_8_lsb 8 +#define xd_p_reg_aagc_min_rf_agc_7_0 0xA008 +#define reg_aagc_min_rf_agc_7_0_pos 0 +#define reg_aagc_min_rf_agc_7_0_len 8 +#define reg_aagc_min_rf_agc_7_0_lsb 0 +#define xd_p_reg_aagc_min_rf_agc_9_8 0xA009 +#define reg_aagc_min_rf_agc_9_8_pos 0 +#define reg_aagc_min_rf_agc_9_8_len 2 +#define reg_aagc_min_rf_agc_9_8_lsb 8 +#define xd_p_reg_aagc_max_if_agc_7_0 0xA00A +#define reg_aagc_max_if_agc_7_0_pos 0 +#define reg_aagc_max_if_agc_7_0_len 8 +#define reg_aagc_max_if_agc_7_0_lsb 0 +#define xd_p_reg_aagc_max_if_agc_9_8 0xA00B +#define reg_aagc_max_if_agc_9_8_pos 0 +#define reg_aagc_max_if_agc_9_8_len 2 +#define reg_aagc_max_if_agc_9_8_lsb 8 +#define xd_p_reg_aagc_min_if_agc_7_0 0xA00C +#define reg_aagc_min_if_agc_7_0_pos 0 +#define reg_aagc_min_if_agc_7_0_len 8 +#define reg_aagc_min_if_agc_7_0_lsb 0 +#define xd_p_reg_aagc_min_if_agc_9_8 0xA00D +#define reg_aagc_min_if_agc_9_8_pos 0 +#define reg_aagc_min_if_agc_9_8_len 2 +#define reg_aagc_min_if_agc_9_8_lsb 8 +#define xd_p_reg_aagc_lock_sample_scale 0xA00E +#define reg_aagc_lock_sample_scale_pos 0 +#define reg_aagc_lock_sample_scale_len 5 +#define reg_aagc_lock_sample_scale_lsb 0 +#define xd_p_reg_aagc_rf_agc_lock_scale_acquire 0xA00F +#define reg_aagc_rf_agc_lock_scale_acquire_pos 0 +#define reg_aagc_rf_agc_lock_scale_acquire_len 3 +#define reg_aagc_rf_agc_lock_scale_acquire_lsb 0 +#define xd_p_reg_aagc_rf_agc_lock_scale_track 0xA00F +#define reg_aagc_rf_agc_lock_scale_track_pos 3 +#define reg_aagc_rf_agc_lock_scale_track_len 3 +#define reg_aagc_rf_agc_lock_scale_track_lsb 0 +#define xd_p_reg_aagc_if_agc_lock_scale_acquire 0xA010 +#define reg_aagc_if_agc_lock_scale_acquire_pos 0 +#define reg_aagc_if_agc_lock_scale_acquire_len 3 +#define reg_aagc_if_agc_lock_scale_acquire_lsb 0 +#define xd_p_reg_aagc_if_agc_lock_scale_track 0xA010 +#define reg_aagc_if_agc_lock_scale_track_pos 3 +#define reg_aagc_if_agc_lock_scale_track_len 3 +#define reg_aagc_if_agc_lock_scale_track_lsb 0 +#define xd_p_reg_aagc_rf_top_numerator_7_0 0xA011 +#define reg_aagc_rf_top_numerator_7_0_pos 0 +#define reg_aagc_rf_top_numerator_7_0_len 8 +#define reg_aagc_rf_top_numerator_7_0_lsb 0 +#define xd_p_reg_aagc_rf_top_numerator_9_8 0xA012 +#define reg_aagc_rf_top_numerator_9_8_pos 0 +#define reg_aagc_rf_top_numerator_9_8_len 2 +#define reg_aagc_rf_top_numerator_9_8_lsb 8 +#define xd_p_reg_aagc_if_top_numerator_7_0 0xA013 +#define reg_aagc_if_top_numerator_7_0_pos 0 +#define reg_aagc_if_top_numerator_7_0_len 8 +#define reg_aagc_if_top_numerator_7_0_lsb 0 +#define xd_p_reg_aagc_if_top_numerator_9_8 0xA014 +#define reg_aagc_if_top_numerator_9_8_pos 0 +#define reg_aagc_if_top_numerator_9_8_len 2 +#define reg_aagc_if_top_numerator_9_8_lsb 8 +#define xd_p_reg_aagc_adc_out_desired_7_0 0xA015 +#define reg_aagc_adc_out_desired_7_0_pos 0 +#define reg_aagc_adc_out_desired_7_0_len 8 +#define reg_aagc_adc_out_desired_7_0_lsb 0 +#define xd_p_reg_aagc_adc_out_desired_8 0xA016 +#define reg_aagc_adc_out_desired_8_pos 0 +#define reg_aagc_adc_out_desired_8_len 1 +#define reg_aagc_adc_out_desired_8_lsb 0 +#define xd_p_reg_aagc_fixed_gain 0xA016 +#define reg_aagc_fixed_gain_pos 3 +#define reg_aagc_fixed_gain_len 1 +#define reg_aagc_fixed_gain_lsb 0 +#define xd_p_reg_aagc_lock_count_th 0xA016 +#define reg_aagc_lock_count_th_pos 4 +#define reg_aagc_lock_count_th_len 4 +#define reg_aagc_lock_count_th_lsb 0 +#define xd_p_reg_aagc_fixed_rf_agc_control_7_0 0xA017 +#define reg_aagc_fixed_rf_agc_control_7_0_pos 0 +#define reg_aagc_fixed_rf_agc_control_7_0_len 8 +#define reg_aagc_fixed_rf_agc_control_7_0_lsb 0 +#define xd_p_reg_aagc_fixed_rf_agc_control_15_8 0xA018 +#define reg_aagc_fixed_rf_agc_control_15_8_pos 0 +#define reg_aagc_fixed_rf_agc_control_15_8_len 8 +#define reg_aagc_fixed_rf_agc_control_15_8_lsb 8 +#define xd_p_reg_aagc_fixed_rf_agc_control_23_16 0xA019 +#define reg_aagc_fixed_rf_agc_control_23_16_pos 0 +#define reg_aagc_fixed_rf_agc_control_23_16_len 8 +#define reg_aagc_fixed_rf_agc_control_23_16_lsb 16 +#define xd_p_reg_aagc_fixed_rf_agc_control_30_24 0xA01A +#define reg_aagc_fixed_rf_agc_control_30_24_pos 0 +#define reg_aagc_fixed_rf_agc_control_30_24_len 7 +#define reg_aagc_fixed_rf_agc_control_30_24_lsb 24 +#define xd_p_reg_aagc_fixed_if_agc_control_7_0 0xA01B +#define reg_aagc_fixed_if_agc_control_7_0_pos 0 +#define reg_aagc_fixed_if_agc_control_7_0_len 8 +#define reg_aagc_fixed_if_agc_control_7_0_lsb 0 +#define xd_p_reg_aagc_fixed_if_agc_control_15_8 0xA01C +#define reg_aagc_fixed_if_agc_control_15_8_pos 0 +#define reg_aagc_fixed_if_agc_control_15_8_len 8 +#define reg_aagc_fixed_if_agc_control_15_8_lsb 8 +#define xd_p_reg_aagc_fixed_if_agc_control_23_16 0xA01D +#define reg_aagc_fixed_if_agc_control_23_16_pos 0 +#define reg_aagc_fixed_if_agc_control_23_16_len 8 +#define reg_aagc_fixed_if_agc_control_23_16_lsb 16 +#define xd_p_reg_aagc_fixed_if_agc_control_30_24 0xA01E +#define reg_aagc_fixed_if_agc_control_30_24_pos 0 +#define reg_aagc_fixed_if_agc_control_30_24_len 7 +#define reg_aagc_fixed_if_agc_control_30_24_lsb 24 +#define xd_p_reg_aagc_rf_agc_unlock_numerator 0xA01F +#define reg_aagc_rf_agc_unlock_numerator_pos 0 +#define reg_aagc_rf_agc_unlock_numerator_len 6 +#define reg_aagc_rf_agc_unlock_numerator_lsb 0 +#define xd_p_reg_aagc_if_agc_unlock_numerator 0xA020 +#define reg_aagc_if_agc_unlock_numerator_pos 0 +#define reg_aagc_if_agc_unlock_numerator_len 6 +#define reg_aagc_if_agc_unlock_numerator_lsb 0 +#define xd_p_reg_unplug_th 0xA021 +#define reg_unplug_th_pos 0 +#define reg_unplug_th_len 8 +#define reg_aagc_rf_x0_lsb 0 +#define xd_p_reg_weak_signal_rfagc_thr 0xA022 +#define reg_weak_signal_rfagc_thr_pos 0 +#define reg_weak_signal_rfagc_thr_len 8 +#define reg_weak_signal_rfagc_thr_lsb 0 +#define xd_p_reg_unplug_rf_gain_th 0xA023 +#define reg_unplug_rf_gain_th_pos 0 +#define reg_unplug_rf_gain_th_len 8 +#define reg_unplug_rf_gain_th_lsb 0 +#define xd_p_reg_unplug_dtop_rf_gain_th 0xA024 +#define reg_unplug_dtop_rf_gain_th_pos 0 +#define reg_unplug_dtop_rf_gain_th_len 8 +#define reg_unplug_dtop_rf_gain_th_lsb 0 +#define xd_p_reg_unplug_dtop_if_gain_th 0xA025 +#define reg_unplug_dtop_if_gain_th_pos 0 +#define reg_unplug_dtop_if_gain_th_len 8 +#define reg_unplug_dtop_if_gain_th_lsb 0 +#define xd_p_reg_top_recover_at_unplug_en 0xA026 +#define reg_top_recover_at_unplug_en_pos 0 +#define reg_top_recover_at_unplug_en_len 1 +#define reg_top_recover_at_unplug_en_lsb 0 +#define xd_p_reg_aagc_rf_x6 0xA027 +#define reg_aagc_rf_x6_pos 0 +#define reg_aagc_rf_x6_len 8 +#define reg_aagc_rf_x6_lsb 0 +#define xd_p_reg_aagc_rf_x7 0xA028 +#define reg_aagc_rf_x7_pos 0 +#define reg_aagc_rf_x7_len 8 +#define reg_aagc_rf_x7_lsb 0 +#define xd_p_reg_aagc_rf_x8 0xA029 +#define reg_aagc_rf_x8_pos 0 +#define reg_aagc_rf_x8_len 8 +#define reg_aagc_rf_x8_lsb 0 +#define xd_p_reg_aagc_rf_x9 0xA02A +#define reg_aagc_rf_x9_pos 0 +#define reg_aagc_rf_x9_len 8 +#define reg_aagc_rf_x9_lsb 0 +#define xd_p_reg_aagc_rf_x10 0xA02B +#define reg_aagc_rf_x10_pos 0 +#define reg_aagc_rf_x10_len 8 +#define reg_aagc_rf_x10_lsb 0 +#define xd_p_reg_aagc_rf_x11 0xA02C +#define reg_aagc_rf_x11_pos 0 +#define reg_aagc_rf_x11_len 8 +#define reg_aagc_rf_x11_lsb 0 +#define xd_p_reg_aagc_rf_x12 0xA02D +#define reg_aagc_rf_x12_pos 0 +#define reg_aagc_rf_x12_len 8 +#define reg_aagc_rf_x12_lsb 0 +#define xd_p_reg_aagc_rf_x13 0xA02E +#define reg_aagc_rf_x13_pos 0 +#define reg_aagc_rf_x13_len 8 +#define reg_aagc_rf_x13_lsb 0 +#define xd_p_reg_aagc_if_x0 0xA02F +#define reg_aagc_if_x0_pos 0 +#define reg_aagc_if_x0_len 8 +#define reg_aagc_if_x0_lsb 0 +#define xd_p_reg_aagc_if_x1 0xA030 +#define reg_aagc_if_x1_pos 0 +#define reg_aagc_if_x1_len 8 +#define reg_aagc_if_x1_lsb 0 +#define xd_p_reg_aagc_if_x2 0xA031 +#define reg_aagc_if_x2_pos 0 +#define reg_aagc_if_x2_len 8 +#define reg_aagc_if_x2_lsb 0 +#define xd_p_reg_aagc_if_x3 0xA032 +#define reg_aagc_if_x3_pos 0 +#define reg_aagc_if_x3_len 8 +#define reg_aagc_if_x3_lsb 0 +#define xd_p_reg_aagc_if_x4 0xA033 +#define reg_aagc_if_x4_pos 0 +#define reg_aagc_if_x4_len 8 +#define reg_aagc_if_x4_lsb 0 +#define xd_p_reg_aagc_if_x5 0xA034 +#define reg_aagc_if_x5_pos 0 +#define reg_aagc_if_x5_len 8 +#define reg_aagc_if_x5_lsb 0 +#define xd_p_reg_aagc_if_x6 0xA035 +#define reg_aagc_if_x6_pos 0 +#define reg_aagc_if_x6_len 8 +#define reg_aagc_if_x6_lsb 0 +#define xd_p_reg_aagc_if_x7 0xA036 +#define reg_aagc_if_x7_pos 0 +#define reg_aagc_if_x7_len 8 +#define reg_aagc_if_x7_lsb 0 +#define xd_p_reg_aagc_if_x8 0xA037 +#define reg_aagc_if_x8_pos 0 +#define reg_aagc_if_x8_len 8 +#define reg_aagc_if_x8_lsb 0 +#define xd_p_reg_aagc_if_x9 0xA038 +#define reg_aagc_if_x9_pos 0 +#define reg_aagc_if_x9_len 8 +#define reg_aagc_if_x9_lsb 0 +#define xd_p_reg_aagc_if_x10 0xA039 +#define reg_aagc_if_x10_pos 0 +#define reg_aagc_if_x10_len 8 +#define reg_aagc_if_x10_lsb 0 +#define xd_p_reg_aagc_if_x11 0xA03A +#define reg_aagc_if_x11_pos 0 +#define reg_aagc_if_x11_len 8 +#define reg_aagc_if_x11_lsb 0 +#define xd_p_reg_aagc_if_x12 0xA03B +#define reg_aagc_if_x12_pos 0 +#define reg_aagc_if_x12_len 8 +#define reg_aagc_if_x12_lsb 0 +#define xd_p_reg_aagc_if_x13 0xA03C +#define reg_aagc_if_x13_pos 0 +#define reg_aagc_if_x13_len 8 +#define reg_aagc_if_x13_lsb 0 +#define xd_p_reg_aagc_min_rf_ctl_8bit_for_dca 0xA03D +#define reg_aagc_min_rf_ctl_8bit_for_dca_pos 0 +#define reg_aagc_min_rf_ctl_8bit_for_dca_len 8 +#define reg_aagc_min_rf_ctl_8bit_for_dca_lsb 0 +#define xd_p_reg_aagc_min_if_ctl_8bit_for_dca 0xA03E +#define reg_aagc_min_if_ctl_8bit_for_dca_pos 0 +#define reg_aagc_min_if_ctl_8bit_for_dca_len 8 +#define reg_aagc_min_if_ctl_8bit_for_dca_lsb 0 +#define xd_r_reg_aagc_total_gain_7_0 0xA070 +#define reg_aagc_total_gain_7_0_pos 0 +#define reg_aagc_total_gain_7_0_len 8 +#define reg_aagc_total_gain_7_0_lsb 0 +#define xd_r_reg_aagc_total_gain_15_8 0xA071 +#define reg_aagc_total_gain_15_8_pos 0 +#define reg_aagc_total_gain_15_8_len 8 +#define reg_aagc_total_gain_15_8_lsb 8 +#define xd_p_reg_aagc_in_sat_cnt_7_0 0xA074 +#define reg_aagc_in_sat_cnt_7_0_pos 0 +#define reg_aagc_in_sat_cnt_7_0_len 8 +#define reg_aagc_in_sat_cnt_7_0_lsb 0 +#define xd_p_reg_aagc_in_sat_cnt_15_8 0xA075 +#define reg_aagc_in_sat_cnt_15_8_pos 0 +#define reg_aagc_in_sat_cnt_15_8_len 8 +#define reg_aagc_in_sat_cnt_15_8_lsb 8 +#define xd_p_reg_aagc_in_sat_cnt_23_16 0xA076 +#define reg_aagc_in_sat_cnt_23_16_pos 0 +#define reg_aagc_in_sat_cnt_23_16_len 8 +#define reg_aagc_in_sat_cnt_23_16_lsb 16 +#define xd_p_reg_aagc_in_sat_cnt_31_24 0xA077 +#define reg_aagc_in_sat_cnt_31_24_pos 0 +#define reg_aagc_in_sat_cnt_31_24_len 8 +#define reg_aagc_in_sat_cnt_31_24_lsb 24 +#define xd_r_reg_aagc_digital_rf_volt_7_0 0xA078 +#define reg_aagc_digital_rf_volt_7_0_pos 0 +#define reg_aagc_digital_rf_volt_7_0_len 8 +#define reg_aagc_digital_rf_volt_7_0_lsb 0 +#define xd_r_reg_aagc_digital_rf_volt_9_8 0xA079 +#define reg_aagc_digital_rf_volt_9_8_pos 0 +#define reg_aagc_digital_rf_volt_9_8_len 2 +#define reg_aagc_digital_rf_volt_9_8_lsb 8 +#define xd_r_reg_aagc_digital_if_volt_7_0 0xA07A +#define reg_aagc_digital_if_volt_7_0_pos 0 +#define reg_aagc_digital_if_volt_7_0_len 8 +#define reg_aagc_digital_if_volt_7_0_lsb 0 +#define xd_r_reg_aagc_digital_if_volt_9_8 0xA07B +#define reg_aagc_digital_if_volt_9_8_pos 0 +#define reg_aagc_digital_if_volt_9_8_len 2 +#define reg_aagc_digital_if_volt_9_8_lsb 8 +#define xd_r_reg_aagc_rf_gain 0xA07C +#define reg_aagc_rf_gain_pos 0 +#define reg_aagc_rf_gain_len 8 +#define reg_aagc_rf_gain_lsb 0 +#define xd_r_reg_aagc_if_gain 0xA07D +#define reg_aagc_if_gain_pos 0 +#define reg_aagc_if_gain_len 8 +#define reg_aagc_if_gain_lsb 0 +#define xd_p_tinr_imp_indicator 0xA080 +#define tinr_imp_indicator_pos 0 +#define tinr_imp_indicator_len 2 +#define tinr_imp_indicator_lsb 0 +#define xd_p_reg_tinr_fifo_size 0xA080 +#define reg_tinr_fifo_size_pos 2 +#define reg_tinr_fifo_size_len 5 +#define reg_tinr_fifo_size_lsb 0 +#define xd_p_reg_tinr_saturation_cnt_th 0xA081 +#define reg_tinr_saturation_cnt_th_pos 0 +#define reg_tinr_saturation_cnt_th_len 4 +#define reg_tinr_saturation_cnt_th_lsb 0 +#define xd_p_reg_tinr_saturation_th_3_0 0xA081 +#define reg_tinr_saturation_th_3_0_pos 4 +#define reg_tinr_saturation_th_3_0_len 4 +#define reg_tinr_saturation_th_3_0_lsb 0 +#define xd_p_reg_tinr_saturation_th_8_4 0xA082 +#define reg_tinr_saturation_th_8_4_pos 0 +#define reg_tinr_saturation_th_8_4_len 5 +#define reg_tinr_saturation_th_8_4_lsb 4 +#define xd_p_reg_tinr_imp_duration_th_2k_7_0 0xA083 +#define reg_tinr_imp_duration_th_2k_7_0_pos 0 +#define reg_tinr_imp_duration_th_2k_7_0_len 8 +#define reg_tinr_imp_duration_th_2k_7_0_lsb 0 +#define xd_p_reg_tinr_imp_duration_th_2k_8 0xA084 +#define reg_tinr_imp_duration_th_2k_8_pos 0 +#define reg_tinr_imp_duration_th_2k_8_len 1 +#define reg_tinr_imp_duration_th_2k_8_lsb 0 +#define xd_p_reg_tinr_imp_duration_th_8k_7_0 0xA085 +#define reg_tinr_imp_duration_th_8k_7_0_pos 0 +#define reg_tinr_imp_duration_th_8k_7_0_len 8 +#define reg_tinr_imp_duration_th_8k_7_0_lsb 0 +#define xd_p_reg_tinr_imp_duration_th_8k_10_8 0xA086 +#define reg_tinr_imp_duration_th_8k_10_8_pos 0 +#define reg_tinr_imp_duration_th_8k_10_8_len 3 +#define reg_tinr_imp_duration_th_8k_10_8_lsb 8 +#define xd_p_reg_tinr_freq_ratio_6m_7_0 0xA087 +#define reg_tinr_freq_ratio_6m_7_0_pos 0 +#define reg_tinr_freq_ratio_6m_7_0_len 8 +#define reg_tinr_freq_ratio_6m_7_0_lsb 0 +#define xd_p_reg_tinr_freq_ratio_6m_12_8 0xA088 +#define reg_tinr_freq_ratio_6m_12_8_pos 0 +#define reg_tinr_freq_ratio_6m_12_8_len 5 +#define reg_tinr_freq_ratio_6m_12_8_lsb 8 +#define xd_p_reg_tinr_freq_ratio_7m_7_0 0xA089 +#define reg_tinr_freq_ratio_7m_7_0_pos 0 +#define reg_tinr_freq_ratio_7m_7_0_len 8 +#define reg_tinr_freq_ratio_7m_7_0_lsb 0 +#define xd_p_reg_tinr_freq_ratio_7m_12_8 0xA08A +#define reg_tinr_freq_ratio_7m_12_8_pos 0 +#define reg_tinr_freq_ratio_7m_12_8_len 5 +#define reg_tinr_freq_ratio_7m_12_8_lsb 8 +#define xd_p_reg_tinr_freq_ratio_8m_7_0 0xA08B +#define reg_tinr_freq_ratio_8m_7_0_pos 0 +#define reg_tinr_freq_ratio_8m_7_0_len 8 +#define reg_tinr_freq_ratio_8m_7_0_lsb 0 +#define xd_p_reg_tinr_freq_ratio_8m_12_8 0xA08C +#define reg_tinr_freq_ratio_8m_12_8_pos 0 +#define reg_tinr_freq_ratio_8m_12_8_len 5 +#define reg_tinr_freq_ratio_8m_12_8_lsb 8 +#define xd_p_reg_tinr_imp_duration_th_low_2k 0xA08D +#define reg_tinr_imp_duration_th_low_2k_pos 0 +#define reg_tinr_imp_duration_th_low_2k_len 8 +#define reg_tinr_imp_duration_th_low_2k_lsb 0 +#define xd_p_reg_tinr_imp_duration_th_low_8k 0xA08E +#define reg_tinr_imp_duration_th_low_8k_pos 0 +#define reg_tinr_imp_duration_th_low_8k_len 8 +#define reg_tinr_imp_duration_th_low_8k_lsb 0 +#define xd_r_reg_tinr_counter_7_0 0xA090 +#define reg_tinr_counter_7_0_pos 0 +#define reg_tinr_counter_7_0_len 8 +#define reg_tinr_counter_7_0_lsb 0 +#define xd_r_reg_tinr_counter_15_8 0xA091 +#define reg_tinr_counter_15_8_pos 0 +#define reg_tinr_counter_15_8_len 8 +#define reg_tinr_counter_15_8_lsb 8 +#define xd_p_reg_tinr_adative_tinr_en 0xA093 +#define reg_tinr_adative_tinr_en_pos 0 +#define reg_tinr_adative_tinr_en_len 1 +#define reg_tinr_adative_tinr_en_lsb 0 +#define xd_p_reg_tinr_peak_fifo_size 0xA093 +#define reg_tinr_peak_fifo_size_pos 1 +#define reg_tinr_peak_fifo_size_len 5 +#define reg_tinr_peak_fifo_size_lsb 0 +#define xd_p_reg_tinr_counter_rst 0xA093 +#define reg_tinr_counter_rst_pos 6 +#define reg_tinr_counter_rst_len 1 +#define reg_tinr_counter_rst_lsb 0 +#define xd_p_reg_tinr_search_period_7_0 0xA094 +#define reg_tinr_search_period_7_0_pos 0 +#define reg_tinr_search_period_7_0_len 8 +#define reg_tinr_search_period_7_0_lsb 0 +#define xd_p_reg_tinr_search_period_15_8 0xA095 +#define reg_tinr_search_period_15_8_pos 0 +#define reg_tinr_search_period_15_8_len 8 +#define reg_tinr_search_period_15_8_lsb 8 +#define xd_p_reg_ccifs_fcw_7_0 0xA0A0 +#define reg_ccifs_fcw_7_0_pos 0 +#define reg_ccifs_fcw_7_0_len 8 +#define reg_ccifs_fcw_7_0_lsb 0 +#define xd_p_reg_ccifs_fcw_12_8 0xA0A1 +#define reg_ccifs_fcw_12_8_pos 0 +#define reg_ccifs_fcw_12_8_len 5 +#define reg_ccifs_fcw_12_8_lsb 8 +#define xd_p_reg_ccifs_spec_inv 0xA0A1 +#define reg_ccifs_spec_inv_pos 5 +#define reg_ccifs_spec_inv_len 1 +#define reg_ccifs_spec_inv_lsb 0 +#define xd_p_reg_gp_trigger 0xA0A2 +#define reg_gp_trigger_pos 0 +#define reg_gp_trigger_len 1 +#define reg_gp_trigger_lsb 0 +#define xd_p_reg_trigger_sel 0xA0A2 +#define reg_trigger_sel_pos 1 +#define reg_trigger_sel_len 2 +#define reg_trigger_sel_lsb 0 +#define xd_p_reg_debug_ofdm 0xA0A2 +#define reg_debug_ofdm_pos 3 +#define reg_debug_ofdm_len 2 +#define reg_debug_ofdm_lsb 0 +#define xd_p_reg_trigger_module_sel 0xA0A3 +#define reg_trigger_module_sel_pos 0 +#define reg_trigger_module_sel_len 6 +#define reg_trigger_module_sel_lsb 0 +#define xd_p_reg_trigger_set_sel 0xA0A4 +#define reg_trigger_set_sel_pos 0 +#define reg_trigger_set_sel_len 6 +#define reg_trigger_set_sel_lsb 0 +#define xd_p_reg_fw_int_mask_n 0xA0A4 +#define reg_fw_int_mask_n_pos 6 +#define reg_fw_int_mask_n_len 1 +#define reg_fw_int_mask_n_lsb 0 +#define xd_p_reg_debug_group 0xA0A5 +#define reg_debug_group_pos 0 +#define reg_debug_group_len 4 +#define reg_debug_group_lsb 0 +#define xd_p_reg_odbg_clk_sel 0xA0A5 +#define reg_odbg_clk_sel_pos 4 +#define reg_odbg_clk_sel_len 2 +#define reg_odbg_clk_sel_lsb 0 +#define xd_p_reg_ccif_sc 0xA0C0 +#define reg_ccif_sc_pos 0 +#define reg_ccif_sc_len 4 +#define reg_ccif_sc_lsb 0 +#define xd_r_reg_ccif_saturate 0xA0C1 +#define reg_ccif_saturate_pos 0 +#define reg_ccif_saturate_len 2 +#define reg_ccif_saturate_lsb 0 +#define xd_r_reg_antif_saturate 0xA0C1 +#define reg_antif_saturate_pos 2 +#define reg_antif_saturate_len 4 +#define reg_antif_saturate_lsb 0 +#define xd_r_reg_acif_saturate 0xA0C2 +#define reg_acif_saturate_pos 0 +#define reg_acif_saturate_len 8 +#define reg_acif_saturate_lsb 0 +#define xd_p_reg_tmr_timer0_threshold_7_0 0xA0C8 +#define reg_tmr_timer0_threshold_7_0_pos 0 +#define reg_tmr_timer0_threshold_7_0_len 8 +#define reg_tmr_timer0_threshold_7_0_lsb 0 +#define xd_p_reg_tmr_timer0_threshold_15_8 0xA0C9 +#define reg_tmr_timer0_threshold_15_8_pos 0 +#define reg_tmr_timer0_threshold_15_8_len 8 +#define reg_tmr_timer0_threshold_15_8_lsb 8 +#define xd_p_reg_tmr_timer0_enable 0xA0CA +#define reg_tmr_timer0_enable_pos 0 +#define reg_tmr_timer0_enable_len 1 +#define reg_tmr_timer0_enable_lsb 0 +#define xd_p_reg_tmr_timer0_clk_sel 0xA0CA +#define reg_tmr_timer0_clk_sel_pos 1 +#define reg_tmr_timer0_clk_sel_len 1 +#define reg_tmr_timer0_clk_sel_lsb 0 +#define xd_p_reg_tmr_timer0_int 0xA0CA +#define reg_tmr_timer0_int_pos 2 +#define reg_tmr_timer0_int_len 1 +#define reg_tmr_timer0_int_lsb 0 +#define xd_p_reg_tmr_timer0_rst 0xA0CA +#define reg_tmr_timer0_rst_pos 3 +#define reg_tmr_timer0_rst_len 1 +#define reg_tmr_timer0_rst_lsb 0 +#define xd_r_reg_tmr_timer0_count_7_0 0xA0CB +#define reg_tmr_timer0_count_7_0_pos 0 +#define reg_tmr_timer0_count_7_0_len 8 +#define reg_tmr_timer0_count_7_0_lsb 0 +#define xd_r_reg_tmr_timer0_count_15_8 0xA0CC +#define reg_tmr_timer0_count_15_8_pos 0 +#define reg_tmr_timer0_count_15_8_len 8 +#define reg_tmr_timer0_count_15_8_lsb 8 +#define xd_p_reg_suspend 0xA0CD +#define reg_suspend_pos 0 +#define reg_suspend_len 1 +#define reg_suspend_lsb 0 +#define xd_p_reg_suspend_rdy 0xA0CD +#define reg_suspend_rdy_pos 1 +#define reg_suspend_rdy_len 1 +#define reg_suspend_rdy_lsb 0 +#define xd_p_reg_resume 0xA0CD +#define reg_resume_pos 2 +#define reg_resume_len 1 +#define reg_resume_lsb 0 +#define xd_p_reg_resume_rdy 0xA0CD +#define reg_resume_rdy_pos 3 +#define reg_resume_rdy_len 1 +#define reg_resume_rdy_lsb 0 +#define xd_p_reg_fmf 0xA0CE +#define reg_fmf_pos 0 +#define reg_fmf_len 8 +#define reg_fmf_lsb 0 +#define xd_p_ccid_accumulate_num_2k_7_0 0xA100 +#define ccid_accumulate_num_2k_7_0_pos 0 +#define ccid_accumulate_num_2k_7_0_len 8 +#define ccid_accumulate_num_2k_7_0_lsb 0 +#define xd_p_ccid_accumulate_num_2k_12_8 0xA101 +#define ccid_accumulate_num_2k_12_8_pos 0 +#define ccid_accumulate_num_2k_12_8_len 5 +#define ccid_accumulate_num_2k_12_8_lsb 8 +#define xd_p_ccid_accumulate_num_8k_7_0 0xA102 +#define ccid_accumulate_num_8k_7_0_pos 0 +#define ccid_accumulate_num_8k_7_0_len 8 +#define ccid_accumulate_num_8k_7_0_lsb 0 +#define xd_p_ccid_accumulate_num_8k_14_8 0xA103 +#define ccid_accumulate_num_8k_14_8_pos 0 +#define ccid_accumulate_num_8k_14_8_len 7 +#define ccid_accumulate_num_8k_14_8_lsb 8 +#define xd_p_ccid_desired_level_0 0xA103 +#define ccid_desired_level_0_pos 7 +#define ccid_desired_level_0_len 1 +#define ccid_desired_level_0_lsb 0 +#define xd_p_ccid_desired_level_8_1 0xA104 +#define ccid_desired_level_8_1_pos 0 +#define ccid_desired_level_8_1_len 8 +#define ccid_desired_level_8_1_lsb 1 +#define xd_p_ccid_apply_delay 0xA105 +#define ccid_apply_delay_pos 0 +#define ccid_apply_delay_len 7 +#define ccid_apply_delay_lsb 0 +#define xd_p_ccid_CCID_Threshold1 0xA106 +#define ccid_CCID_Threshold1_pos 0 +#define ccid_CCID_Threshold1_len 8 +#define ccid_CCID_Threshold1_lsb 0 +#define xd_p_ccid_CCID_Threshold2 0xA107 +#define ccid_CCID_Threshold2_pos 0 +#define ccid_CCID_Threshold2_len 8 +#define ccid_CCID_Threshold2_lsb 0 +#define xd_p_reg_ccid_gain_scale 0xA108 +#define reg_ccid_gain_scale_pos 0 +#define reg_ccid_gain_scale_len 4 +#define reg_ccid_gain_scale_lsb 0 +#define xd_p_reg_ccid2_passband_gain_set 0xA108 +#define reg_ccid2_passband_gain_set_pos 4 +#define reg_ccid2_passband_gain_set_len 4 +#define reg_ccid2_passband_gain_set_lsb 0 +#define xd_r_ccid_multiplier_7_0 0xA109 +#define ccid_multiplier_7_0_pos 0 +#define ccid_multiplier_7_0_len 8 +#define ccid_multiplier_7_0_lsb 0 +#define xd_r_ccid_multiplier_15_8 0xA10A +#define ccid_multiplier_15_8_pos 0 +#define ccid_multiplier_15_8_len 8 +#define ccid_multiplier_15_8_lsb 8 +#define xd_r_ccid_right_shift_bits 0xA10B +#define ccid_right_shift_bits_pos 0 +#define ccid_right_shift_bits_len 4 +#define ccid_right_shift_bits_lsb 0 +#define xd_r_reg_ccid_sx_7_0 0xA10C +#define reg_ccid_sx_7_0_pos 0 +#define reg_ccid_sx_7_0_len 8 +#define reg_ccid_sx_7_0_lsb 0 +#define xd_r_reg_ccid_sx_15_8 0xA10D +#define reg_ccid_sx_15_8_pos 0 +#define reg_ccid_sx_15_8_len 8 +#define reg_ccid_sx_15_8_lsb 8 +#define xd_r_reg_ccid_sx_21_16 0xA10E +#define reg_ccid_sx_21_16_pos 0 +#define reg_ccid_sx_21_16_len 6 +#define reg_ccid_sx_21_16_lsb 16 +#define xd_r_reg_ccid_sy_7_0 0xA110 +#define reg_ccid_sy_7_0_pos 0 +#define reg_ccid_sy_7_0_len 8 +#define reg_ccid_sy_7_0_lsb 0 +#define xd_r_reg_ccid_sy_15_8 0xA111 +#define reg_ccid_sy_15_8_pos 0 +#define reg_ccid_sy_15_8_len 8 +#define reg_ccid_sy_15_8_lsb 8 +#define xd_r_reg_ccid_sy_23_16 0xA112 +#define reg_ccid_sy_23_16_pos 0 +#define reg_ccid_sy_23_16_len 8 +#define reg_ccid_sy_23_16_lsb 16 +#define xd_r_reg_ccid2_sz_7_0 0xA114 +#define reg_ccid2_sz_7_0_pos 0 +#define reg_ccid2_sz_7_0_len 8 +#define reg_ccid2_sz_7_0_lsb 0 +#define xd_r_reg_ccid2_sz_15_8 0xA115 +#define reg_ccid2_sz_15_8_pos 0 +#define reg_ccid2_sz_15_8_len 8 +#define reg_ccid2_sz_15_8_lsb 8 +#define xd_r_reg_ccid2_sz_23_16 0xA116 +#define reg_ccid2_sz_23_16_pos 0 +#define reg_ccid2_sz_23_16_len 8 +#define reg_ccid2_sz_23_16_lsb 16 +#define xd_r_reg_ccid2_sz_25_24 0xA117 +#define reg_ccid2_sz_25_24_pos 0 +#define reg_ccid2_sz_25_24_len 2 +#define reg_ccid2_sz_25_24_lsb 24 +#define xd_r_reg_ccid2_sy_7_0 0xA118 +#define reg_ccid2_sy_7_0_pos 0 +#define reg_ccid2_sy_7_0_len 8 +#define reg_ccid2_sy_7_0_lsb 0 +#define xd_r_reg_ccid2_sy_15_8 0xA119 +#define reg_ccid2_sy_15_8_pos 0 +#define reg_ccid2_sy_15_8_len 8 +#define reg_ccid2_sy_15_8_lsb 8 +#define xd_r_reg_ccid2_sy_23_16 0xA11A +#define reg_ccid2_sy_23_16_pos 0 +#define reg_ccid2_sy_23_16_len 8 +#define reg_ccid2_sy_23_16_lsb 16 +#define xd_r_reg_ccid2_sy_25_24 0xA11B +#define reg_ccid2_sy_25_24_pos 0 +#define reg_ccid2_sy_25_24_len 2 +#define reg_ccid2_sy_25_24_lsb 24 +#define xd_p_dagc1_accumulate_num_2k_7_0 0xA120 +#define dagc1_accumulate_num_2k_7_0_pos 0 +#define dagc1_accumulate_num_2k_7_0_len 8 +#define dagc1_accumulate_num_2k_7_0_lsb 0 +#define xd_p_dagc1_accumulate_num_2k_12_8 0xA121 +#define dagc1_accumulate_num_2k_12_8_pos 0 +#define dagc1_accumulate_num_2k_12_8_len 5 +#define dagc1_accumulate_num_2k_12_8_lsb 8 +#define xd_p_dagc1_accumulate_num_8k_7_0 0xA122 +#define dagc1_accumulate_num_8k_7_0_pos 0 +#define dagc1_accumulate_num_8k_7_0_len 8 +#define dagc1_accumulate_num_8k_7_0_lsb 0 +#define xd_p_dagc1_accumulate_num_8k_14_8 0xA123 +#define dagc1_accumulate_num_8k_14_8_pos 0 +#define dagc1_accumulate_num_8k_14_8_len 7 +#define dagc1_accumulate_num_8k_14_8_lsb 8 +#define xd_p_dagc1_desired_level_0 0xA123 +#define dagc1_desired_level_0_pos 7 +#define dagc1_desired_level_0_len 1 +#define dagc1_desired_level_0_lsb 0 +#define xd_p_dagc1_desired_level_8_1 0xA124 +#define dagc1_desired_level_8_1_pos 0 +#define dagc1_desired_level_8_1_len 8 +#define dagc1_desired_level_8_1_lsb 1 +#define xd_p_dagc1_apply_delay 0xA125 +#define dagc1_apply_delay_pos 0 +#define dagc1_apply_delay_len 7 +#define dagc1_apply_delay_lsb 0 +#define xd_p_dagc1_bypass_scale_ctl 0xA126 +#define dagc1_bypass_scale_ctl_pos 0 +#define dagc1_bypass_scale_ctl_len 2 +#define dagc1_bypass_scale_ctl_lsb 0 +#define xd_p_reg_dagc1_in_sat_cnt_7_0 0xA127 +#define reg_dagc1_in_sat_cnt_7_0_pos 0 +#define reg_dagc1_in_sat_cnt_7_0_len 8 +#define reg_dagc1_in_sat_cnt_7_0_lsb 0 +#define xd_p_reg_dagc1_in_sat_cnt_15_8 0xA128 +#define reg_dagc1_in_sat_cnt_15_8_pos 0 +#define reg_dagc1_in_sat_cnt_15_8_len 8 +#define reg_dagc1_in_sat_cnt_15_8_lsb 8 +#define xd_p_reg_dagc1_in_sat_cnt_23_16 0xA129 +#define reg_dagc1_in_sat_cnt_23_16_pos 0 +#define reg_dagc1_in_sat_cnt_23_16_len 8 +#define reg_dagc1_in_sat_cnt_23_16_lsb 16 +#define xd_p_reg_dagc1_in_sat_cnt_31_24 0xA12A +#define reg_dagc1_in_sat_cnt_31_24_pos 0 +#define reg_dagc1_in_sat_cnt_31_24_len 8 +#define reg_dagc1_in_sat_cnt_31_24_lsb 24 +#define xd_p_reg_dagc1_out_sat_cnt_7_0 0xA12B +#define reg_dagc1_out_sat_cnt_7_0_pos 0 +#define reg_dagc1_out_sat_cnt_7_0_len 8 +#define reg_dagc1_out_sat_cnt_7_0_lsb 0 +#define xd_p_reg_dagc1_out_sat_cnt_15_8 0xA12C +#define reg_dagc1_out_sat_cnt_15_8_pos 0 +#define reg_dagc1_out_sat_cnt_15_8_len 8 +#define reg_dagc1_out_sat_cnt_15_8_lsb 8 +#define xd_p_reg_dagc1_out_sat_cnt_23_16 0xA12D +#define reg_dagc1_out_sat_cnt_23_16_pos 0 +#define reg_dagc1_out_sat_cnt_23_16_len 8 +#define reg_dagc1_out_sat_cnt_23_16_lsb 16 +#define xd_p_reg_dagc1_out_sat_cnt_31_24 0xA12E +#define reg_dagc1_out_sat_cnt_31_24_pos 0 +#define reg_dagc1_out_sat_cnt_31_24_len 8 +#define reg_dagc1_out_sat_cnt_31_24_lsb 24 +#define xd_r_dagc1_multiplier_7_0 0xA136 +#define dagc1_multiplier_7_0_pos 0 +#define dagc1_multiplier_7_0_len 8 +#define dagc1_multiplier_7_0_lsb 0 +#define xd_r_dagc1_multiplier_15_8 0xA137 +#define dagc1_multiplier_15_8_pos 0 +#define dagc1_multiplier_15_8_len 8 +#define dagc1_multiplier_15_8_lsb 8 +#define xd_r_dagc1_right_shift_bits 0xA138 +#define dagc1_right_shift_bits_pos 0 +#define dagc1_right_shift_bits_len 4 +#define dagc1_right_shift_bits_lsb 0 +#define xd_p_reg_bfs_fcw_7_0 0xA140 +#define reg_bfs_fcw_7_0_pos 0 +#define reg_bfs_fcw_7_0_len 8 +#define reg_bfs_fcw_7_0_lsb 0 +#define xd_p_reg_bfs_fcw_15_8 0xA141 +#define reg_bfs_fcw_15_8_pos 0 +#define reg_bfs_fcw_15_8_len 8 +#define reg_bfs_fcw_15_8_lsb 8 +#define xd_p_reg_bfs_fcw_22_16 0xA142 +#define reg_bfs_fcw_22_16_pos 0 +#define reg_bfs_fcw_22_16_len 7 +#define reg_bfs_fcw_22_16_lsb 16 +#define xd_p_reg_antif_sf_7_0 0xA144 +#define reg_antif_sf_7_0_pos 0 +#define reg_antif_sf_7_0_len 8 +#define reg_antif_sf_7_0_lsb 0 +#define xd_p_reg_antif_sf_11_8 0xA145 +#define reg_antif_sf_11_8_pos 0 +#define reg_antif_sf_11_8_len 4 +#define reg_antif_sf_11_8_lsb 8 +#define xd_r_bfs_fcw_q_7_0 0xA150 +#define bfs_fcw_q_7_0_pos 0 +#define bfs_fcw_q_7_0_len 8 +#define bfs_fcw_q_7_0_lsb 0 +#define xd_r_bfs_fcw_q_15_8 0xA151 +#define bfs_fcw_q_15_8_pos 0 +#define bfs_fcw_q_15_8_len 8 +#define bfs_fcw_q_15_8_lsb 8 +#define xd_r_bfs_fcw_q_22_16 0xA152 +#define bfs_fcw_q_22_16_pos 0 +#define bfs_fcw_q_22_16_len 7 +#define bfs_fcw_q_22_16_lsb 16 +#define xd_p_reg_dca_enu 0xA160 +#define reg_dca_enu_pos 0 +#define reg_dca_enu_len 1 +#define reg_dca_enu_lsb 0 +#define xd_p_reg_dca_enl 0xA160 +#define reg_dca_enl_pos 1 +#define reg_dca_enl_len 1 +#define reg_dca_enl_lsb 0 +#define xd_p_reg_dca_lower_chip 0xA160 +#define reg_dca_lower_chip_pos 2 +#define reg_dca_lower_chip_len 1 +#define reg_dca_lower_chip_lsb 0 +#define xd_p_reg_dca_upper_chip 0xA160 +#define reg_dca_upper_chip_pos 3 +#define reg_dca_upper_chip_len 1 +#define reg_dca_upper_chip_lsb 0 +#define xd_p_reg_dca_platch 0xA160 +#define reg_dca_platch_pos 4 +#define reg_dca_platch_len 1 +#define reg_dca_platch_lsb 0 +#define xd_p_reg_dca_th 0xA161 +#define reg_dca_th_pos 0 +#define reg_dca_th_len 5 +#define reg_dca_th_lsb 0 +#define xd_p_reg_dca_scale 0xA162 +#define reg_dca_scale_pos 0 +#define reg_dca_scale_len 4 +#define reg_dca_scale_lsb 0 +#define xd_p_reg_dca_tone_7_0 0xA163 +#define reg_dca_tone_7_0_pos 0 +#define reg_dca_tone_7_0_len 8 +#define reg_dca_tone_7_0_lsb 0 +#define xd_p_reg_dca_tone_12_8 0xA164 +#define reg_dca_tone_12_8_pos 0 +#define reg_dca_tone_12_8_len 5 +#define reg_dca_tone_12_8_lsb 8 +#define xd_p_reg_dca_time_7_0 0xA165 +#define reg_dca_time_7_0_pos 0 +#define reg_dca_time_7_0_len 8 +#define reg_dca_time_7_0_lsb 0 +#define xd_p_reg_dca_time_15_8 0xA166 +#define reg_dca_time_15_8_pos 0 +#define reg_dca_time_15_8_len 8 +#define reg_dca_time_15_8_lsb 8 +#define xd_r_dcasm 0xA167 +#define dcasm_pos 0 +#define dcasm_len 3 +#define dcasm_lsb 0 +#define xd_p_reg_qnt_valuew_7_0 0xA168 +#define reg_qnt_valuew_7_0_pos 0 +#define reg_qnt_valuew_7_0_len 8 +#define reg_qnt_valuew_7_0_lsb 0 +#define xd_p_reg_qnt_valuew_10_8 0xA169 +#define reg_qnt_valuew_10_8_pos 0 +#define reg_qnt_valuew_10_8_len 3 +#define reg_qnt_valuew_10_8_lsb 8 +#define xd_p_dca_sbx_gain_diff_7_0 0xA16A +#define dca_sbx_gain_diff_7_0_pos 0 +#define dca_sbx_gain_diff_7_0_len 8 +#define dca_sbx_gain_diff_7_0_lsb 0 +#define xd_p_dca_sbx_gain_diff_9_8 0xA16B +#define dca_sbx_gain_diff_9_8_pos 0 +#define dca_sbx_gain_diff_9_8_len 2 +#define dca_sbx_gain_diff_9_8_lsb 8 +#define xd_p_reg_dca_stand_alone 0xA16C +#define reg_dca_stand_alone_pos 0 +#define reg_dca_stand_alone_len 1 +#define reg_dca_stand_alone_lsb 0 +#define xd_p_reg_dca_upper_out_en 0xA16C +#define reg_dca_upper_out_en_pos 1 +#define reg_dca_upper_out_en_len 1 +#define reg_dca_upper_out_en_lsb 0 +#define xd_p_reg_dca_rc_en 0xA16C +#define reg_dca_rc_en_pos 2 +#define reg_dca_rc_en_len 1 +#define reg_dca_rc_en_lsb 0 +#define xd_p_reg_dca_retrain_send 0xA16C +#define reg_dca_retrain_send_pos 3 +#define reg_dca_retrain_send_len 1 +#define reg_dca_retrain_send_lsb 0 +#define xd_p_reg_dca_retrain_rec 0xA16C +#define reg_dca_retrain_rec_pos 4 +#define reg_dca_retrain_rec_len 1 +#define reg_dca_retrain_rec_lsb 0 +#define xd_p_reg_dca_api_tpsrdy 0xA16C +#define reg_dca_api_tpsrdy_pos 5 +#define reg_dca_api_tpsrdy_len 1 +#define reg_dca_api_tpsrdy_lsb 0 +#define xd_p_reg_dca_symbol_gap 0xA16D +#define reg_dca_symbol_gap_pos 0 +#define reg_dca_symbol_gap_len 4 +#define reg_dca_symbol_gap_lsb 0 +#define xd_p_reg_qnt_nfvaluew_7_0 0xA16E +#define reg_qnt_nfvaluew_7_0_pos 0 +#define reg_qnt_nfvaluew_7_0_len 8 +#define reg_qnt_nfvaluew_7_0_lsb 0 +#define xd_p_reg_qnt_nfvaluew_10_8 0xA16F +#define reg_qnt_nfvaluew_10_8_pos 0 +#define reg_qnt_nfvaluew_10_8_len 3 +#define reg_qnt_nfvaluew_10_8_lsb 8 +#define xd_p_reg_qnt_flatness_thr_7_0 0xA170 +#define reg_qnt_flatness_thr_7_0_pos 0 +#define reg_qnt_flatness_thr_7_0_len 8 +#define reg_qnt_flatness_thr_7_0_lsb 0 +#define xd_p_reg_qnt_flatness_thr_9_8 0xA171 +#define reg_qnt_flatness_thr_9_8_pos 0 +#define reg_qnt_flatness_thr_9_8_len 2 +#define reg_qnt_flatness_thr_9_8_lsb 8 +#define xd_p_reg_dca_tone_idx_5_0 0xA171 +#define reg_dca_tone_idx_5_0_pos 2 +#define reg_dca_tone_idx_5_0_len 6 +#define reg_dca_tone_idx_5_0_lsb 0 +#define xd_p_reg_dca_tone_idx_12_6 0xA172 +#define reg_dca_tone_idx_12_6_pos 0 +#define reg_dca_tone_idx_12_6_len 7 +#define reg_dca_tone_idx_12_6_lsb 6 +#define xd_p_reg_dca_data_vld 0xA173 +#define reg_dca_data_vld_pos 0 +#define reg_dca_data_vld_len 1 +#define reg_dca_data_vld_lsb 0 +#define xd_p_reg_dca_read_update 0xA173 +#define reg_dca_read_update_pos 1 +#define reg_dca_read_update_len 1 +#define reg_dca_read_update_lsb 0 +#define xd_r_reg_dca_data_re_5_0 0xA173 +#define reg_dca_data_re_5_0_pos 2 +#define reg_dca_data_re_5_0_len 6 +#define reg_dca_data_re_5_0_lsb 0 +#define xd_r_reg_dca_data_re_10_6 0xA174 +#define reg_dca_data_re_10_6_pos 0 +#define reg_dca_data_re_10_6_len 5 +#define reg_dca_data_re_10_6_lsb 6 +#define xd_r_reg_dca_data_im_7_0 0xA175 +#define reg_dca_data_im_7_0_pos 0 +#define reg_dca_data_im_7_0_len 8 +#define reg_dca_data_im_7_0_lsb 0 +#define xd_r_reg_dca_data_im_10_8 0xA176 +#define reg_dca_data_im_10_8_pos 0 +#define reg_dca_data_im_10_8_len 3 +#define reg_dca_data_im_10_8_lsb 8 +#define xd_r_reg_dca_data_h2_7_0 0xA178 +#define reg_dca_data_h2_7_0_pos 0 +#define reg_dca_data_h2_7_0_len 8 +#define reg_dca_data_h2_7_0_lsb 0 +#define xd_r_reg_dca_data_h2_9_8 0xA179 +#define reg_dca_data_h2_9_8_pos 0 +#define reg_dca_data_h2_9_8_len 2 +#define reg_dca_data_h2_9_8_lsb 8 +#define xd_p_reg_f_adc_7_0 0xA180 +#define reg_f_adc_7_0_pos 0 +#define reg_f_adc_7_0_len 8 +#define reg_f_adc_7_0_lsb 0 +#define xd_p_reg_f_adc_15_8 0xA181 +#define reg_f_adc_15_8_pos 0 +#define reg_f_adc_15_8_len 8 +#define reg_f_adc_15_8_lsb 8 +#define xd_p_reg_f_adc_23_16 0xA182 +#define reg_f_adc_23_16_pos 0 +#define reg_f_adc_23_16_len 8 +#define reg_f_adc_23_16_lsb 16 +#define xd_r_intp_mu_7_0 0xA190 +#define intp_mu_7_0_pos 0 +#define intp_mu_7_0_len 8 +#define intp_mu_7_0_lsb 0 +#define xd_r_intp_mu_15_8 0xA191 +#define intp_mu_15_8_pos 0 +#define intp_mu_15_8_len 8 +#define intp_mu_15_8_lsb 8 +#define xd_r_intp_mu_19_16 0xA192 +#define intp_mu_19_16_pos 0 +#define intp_mu_19_16_len 4 +#define intp_mu_19_16_lsb 16 +#define xd_p_reg_agc_rst 0xA1A0 +#define reg_agc_rst_pos 0 +#define reg_agc_rst_len 1 +#define reg_agc_rst_lsb 0 +#define xd_p_rf_agc_en 0xA1A0 +#define rf_agc_en_pos 1 +#define rf_agc_en_len 1 +#define rf_agc_en_lsb 0 +#define xd_p_rf_agc_dis 0xA1A0 +#define rf_agc_dis_pos 2 +#define rf_agc_dis_len 1 +#define rf_agc_dis_lsb 0 +#define xd_p_if_agc_rst 0xA1A0 +#define if_agc_rst_pos 3 +#define if_agc_rst_len 1 +#define if_agc_rst_lsb 0 +#define xd_p_if_agc_en 0xA1A0 +#define if_agc_en_pos 4 +#define if_agc_en_len 1 +#define if_agc_en_lsb 0 +#define xd_p_if_agc_dis 0xA1A0 +#define if_agc_dis_pos 5 +#define if_agc_dis_len 1 +#define if_agc_dis_lsb 0 +#define xd_p_agc_lock 0xA1A0 +#define agc_lock_pos 6 +#define agc_lock_len 1 +#define agc_lock_lsb 0 +#define xd_p_reg_tinr_rst 0xA1A1 +#define reg_tinr_rst_pos 0 +#define reg_tinr_rst_len 1 +#define reg_tinr_rst_lsb 0 +#define xd_p_reg_tinr_en 0xA1A1 +#define reg_tinr_en_pos 1 +#define reg_tinr_en_len 1 +#define reg_tinr_en_lsb 0 +#define xd_p_reg_ccifs_en 0xA1A2 +#define reg_ccifs_en_pos 0 +#define reg_ccifs_en_len 1 +#define reg_ccifs_en_lsb 0 +#define xd_p_reg_ccifs_dis 0xA1A2 +#define reg_ccifs_dis_pos 1 +#define reg_ccifs_dis_len 1 +#define reg_ccifs_dis_lsb 0 +#define xd_p_reg_ccifs_rst 0xA1A2 +#define reg_ccifs_rst_pos 2 +#define reg_ccifs_rst_len 1 +#define reg_ccifs_rst_lsb 0 +#define xd_p_reg_ccifs_byp 0xA1A2 +#define reg_ccifs_byp_pos 3 +#define reg_ccifs_byp_len 1 +#define reg_ccifs_byp_lsb 0 +#define xd_p_reg_ccif_en 0xA1A3 +#define reg_ccif_en_pos 0 +#define reg_ccif_en_len 1 +#define reg_ccif_en_lsb 0 +#define xd_p_reg_ccif_dis 0xA1A3 +#define reg_ccif_dis_pos 1 +#define reg_ccif_dis_len 1 +#define reg_ccif_dis_lsb 0 +#define xd_p_reg_ccif_rst 0xA1A3 +#define reg_ccif_rst_pos 2 +#define reg_ccif_rst_len 1 +#define reg_ccif_rst_lsb 0 +#define xd_p_reg_ccif_byp 0xA1A3 +#define reg_ccif_byp_pos 3 +#define reg_ccif_byp_len 1 +#define reg_ccif_byp_lsb 0 +#define xd_p_dagc1_rst 0xA1A4 +#define dagc1_rst_pos 0 +#define dagc1_rst_len 1 +#define dagc1_rst_lsb 0 +#define xd_p_dagc1_en 0xA1A4 +#define dagc1_en_pos 1 +#define dagc1_en_len 1 +#define dagc1_en_lsb 0 +#define xd_p_dagc1_mode 0xA1A4 +#define dagc1_mode_pos 2 +#define dagc1_mode_len 2 +#define dagc1_mode_lsb 0 +#define xd_p_dagc1_done 0xA1A4 +#define dagc1_done_pos 4 +#define dagc1_done_len 1 +#define dagc1_done_lsb 0 +#define xd_p_ccid_rst 0xA1A5 +#define ccid_rst_pos 0 +#define ccid_rst_len 1 +#define ccid_rst_lsb 0 +#define xd_p_ccid_en 0xA1A5 +#define ccid_en_pos 1 +#define ccid_en_len 1 +#define ccid_en_lsb 0 +#define xd_p_ccid_mode 0xA1A5 +#define ccid_mode_pos 2 +#define ccid_mode_len 2 +#define ccid_mode_lsb 0 +#define xd_p_ccid_done 0xA1A5 +#define ccid_done_pos 4 +#define ccid_done_len 1 +#define ccid_done_lsb 0 +#define xd_r_ccid_deted 0xA1A5 +#define ccid_deted_pos 5 +#define ccid_deted_len 1 +#define ccid_deted_lsb 0 +#define xd_p_ccid2_en 0xA1A5 +#define ccid2_en_pos 6 +#define ccid2_en_len 1 +#define ccid2_en_lsb 0 +#define xd_p_ccid2_done 0xA1A5 +#define ccid2_done_pos 7 +#define ccid2_done_len 1 +#define ccid2_done_lsb 0 +#define xd_p_reg_bfs_en 0xA1A6 +#define reg_bfs_en_pos 0 +#define reg_bfs_en_len 1 +#define reg_bfs_en_lsb 0 +#define xd_p_reg_bfs_dis 0xA1A6 +#define reg_bfs_dis_pos 1 +#define reg_bfs_dis_len 1 +#define reg_bfs_dis_lsb 0 +#define xd_p_reg_bfs_rst 0xA1A6 +#define reg_bfs_rst_pos 2 +#define reg_bfs_rst_len 1 +#define reg_bfs_rst_lsb 0 +#define xd_p_reg_bfs_byp 0xA1A6 +#define reg_bfs_byp_pos 3 +#define reg_bfs_byp_len 1 +#define reg_bfs_byp_lsb 0 +#define xd_p_reg_antif_en 0xA1A7 +#define reg_antif_en_pos 0 +#define reg_antif_en_len 1 +#define reg_antif_en_lsb 0 +#define xd_p_reg_antif_dis 0xA1A7 +#define reg_antif_dis_pos 1 +#define reg_antif_dis_len 1 +#define reg_antif_dis_lsb 0 +#define xd_p_reg_antif_rst 0xA1A7 +#define reg_antif_rst_pos 2 +#define reg_antif_rst_len 1 +#define reg_antif_rst_lsb 0 +#define xd_p_reg_antif_byp 0xA1A7 +#define reg_antif_byp_pos 3 +#define reg_antif_byp_len 1 +#define reg_antif_byp_lsb 0 +#define xd_p_intp_en 0xA1A8 +#define intp_en_pos 0 +#define intp_en_len 1 +#define intp_en_lsb 0 +#define xd_p_intp_dis 0xA1A8 +#define intp_dis_pos 1 +#define intp_dis_len 1 +#define intp_dis_lsb 0 +#define xd_p_intp_rst 0xA1A8 +#define intp_rst_pos 2 +#define intp_rst_len 1 +#define intp_rst_lsb 0 +#define xd_p_intp_byp 0xA1A8 +#define intp_byp_pos 3 +#define intp_byp_len 1 +#define intp_byp_lsb 0 +#define xd_p_reg_acif_en 0xA1A9 +#define reg_acif_en_pos 0 +#define reg_acif_en_len 1 +#define reg_acif_en_lsb 0 +#define xd_p_reg_acif_dis 0xA1A9 +#define reg_acif_dis_pos 1 +#define reg_acif_dis_len 1 +#define reg_acif_dis_lsb 0 +#define xd_p_reg_acif_rst 0xA1A9 +#define reg_acif_rst_pos 2 +#define reg_acif_rst_len 1 +#define reg_acif_rst_lsb 0 +#define xd_p_reg_acif_byp 0xA1A9 +#define reg_acif_byp_pos 3 +#define reg_acif_byp_len 1 +#define reg_acif_byp_lsb 0 +#define xd_p_reg_acif_sync_mode 0xA1A9 +#define reg_acif_sync_mode_pos 4 +#define reg_acif_sync_mode_len 1 +#define reg_acif_sync_mode_lsb 0 +#define xd_p_dagc2_rst 0xA1AA +#define dagc2_rst_pos 0 +#define dagc2_rst_len 1 +#define dagc2_rst_lsb 0 +#define xd_p_dagc2_en 0xA1AA +#define dagc2_en_pos 1 +#define dagc2_en_len 1 +#define dagc2_en_lsb 0 +#define xd_p_dagc2_mode 0xA1AA +#define dagc2_mode_pos 2 +#define dagc2_mode_len 2 +#define dagc2_mode_lsb 0 +#define xd_p_dagc2_done 0xA1AA +#define dagc2_done_pos 4 +#define dagc2_done_len 1 +#define dagc2_done_lsb 0 +#define xd_p_reg_dca_en 0xA1AB +#define reg_dca_en_pos 0 +#define reg_dca_en_len 1 +#define reg_dca_en_lsb 0 +#define xd_p_dagc2_accumulate_num_2k_7_0 0xA1C0 +#define dagc2_accumulate_num_2k_7_0_pos 0 +#define dagc2_accumulate_num_2k_7_0_len 8 +#define dagc2_accumulate_num_2k_7_0_lsb 0 +#define xd_p_dagc2_accumulate_num_2k_12_8 0xA1C1 +#define dagc2_accumulate_num_2k_12_8_pos 0 +#define dagc2_accumulate_num_2k_12_8_len 5 +#define dagc2_accumulate_num_2k_12_8_lsb 8 +#define xd_p_dagc2_accumulate_num_8k_7_0 0xA1C2 +#define dagc2_accumulate_num_8k_7_0_pos 0 +#define dagc2_accumulate_num_8k_7_0_len 8 +#define dagc2_accumulate_num_8k_7_0_lsb 0 +#define xd_p_dagc2_accumulate_num_8k_12_8 0xA1C3 +#define dagc2_accumulate_num_8k_12_8_pos 0 +#define dagc2_accumulate_num_8k_12_8_len 5 +#define dagc2_accumulate_num_8k_12_8_lsb 8 +#define xd_p_dagc2_desired_level_2_0 0xA1C3 +#define dagc2_desired_level_2_0_pos 5 +#define dagc2_desired_level_2_0_len 3 +#define dagc2_desired_level_2_0_lsb 0 +#define xd_p_dagc2_desired_level_8_3 0xA1C4 +#define dagc2_desired_level_8_3_pos 0 +#define dagc2_desired_level_8_3_len 6 +#define dagc2_desired_level_8_3_lsb 3 +#define xd_p_dagc2_apply_delay 0xA1C5 +#define dagc2_apply_delay_pos 0 +#define dagc2_apply_delay_len 7 +#define dagc2_apply_delay_lsb 0 +#define xd_p_dagc2_bypass_scale_ctl 0xA1C6 +#define dagc2_bypass_scale_ctl_pos 0 +#define dagc2_bypass_scale_ctl_len 3 +#define dagc2_bypass_scale_ctl_lsb 0 +#define xd_p_dagc2_programmable_shift1 0xA1C7 +#define dagc2_programmable_shift1_pos 0 +#define dagc2_programmable_shift1_len 8 +#define dagc2_programmable_shift1_lsb 0 +#define xd_p_dagc2_programmable_shift2 0xA1C8 +#define dagc2_programmable_shift2_pos 0 +#define dagc2_programmable_shift2_len 8 +#define dagc2_programmable_shift2_lsb 0 +#define xd_p_reg_dagc2_in_sat_cnt_7_0 0xA1C9 +#define reg_dagc2_in_sat_cnt_7_0_pos 0 +#define reg_dagc2_in_sat_cnt_7_0_len 8 +#define reg_dagc2_in_sat_cnt_7_0_lsb 0 +#define xd_p_reg_dagc2_in_sat_cnt_15_8 0xA1CA +#define reg_dagc2_in_sat_cnt_15_8_pos 0 +#define reg_dagc2_in_sat_cnt_15_8_len 8 +#define reg_dagc2_in_sat_cnt_15_8_lsb 8 +#define xd_p_reg_dagc2_in_sat_cnt_23_16 0xA1CB +#define reg_dagc2_in_sat_cnt_23_16_pos 0 +#define reg_dagc2_in_sat_cnt_23_16_len 8 +#define reg_dagc2_in_sat_cnt_23_16_lsb 16 +#define xd_p_reg_dagc2_in_sat_cnt_31_24 0xA1CC +#define reg_dagc2_in_sat_cnt_31_24_pos 0 +#define reg_dagc2_in_sat_cnt_31_24_len 8 +#define reg_dagc2_in_sat_cnt_31_24_lsb 24 +#define xd_p_reg_dagc2_out_sat_cnt_7_0 0xA1CD +#define reg_dagc2_out_sat_cnt_7_0_pos 0 +#define reg_dagc2_out_sat_cnt_7_0_len 8 +#define reg_dagc2_out_sat_cnt_7_0_lsb 0 +#define xd_p_reg_dagc2_out_sat_cnt_15_8 0xA1CE +#define reg_dagc2_out_sat_cnt_15_8_pos 0 +#define reg_dagc2_out_sat_cnt_15_8_len 8 +#define reg_dagc2_out_sat_cnt_15_8_lsb 8 +#define xd_p_reg_dagc2_out_sat_cnt_23_16 0xA1CF +#define reg_dagc2_out_sat_cnt_23_16_pos 0 +#define reg_dagc2_out_sat_cnt_23_16_len 8 +#define reg_dagc2_out_sat_cnt_23_16_lsb 16 +#define xd_p_reg_dagc2_out_sat_cnt_31_24 0xA1D0 +#define reg_dagc2_out_sat_cnt_31_24_pos 0 +#define reg_dagc2_out_sat_cnt_31_24_len 8 +#define reg_dagc2_out_sat_cnt_31_24_lsb 24 +#define xd_r_dagc2_multiplier_7_0 0xA1D6 +#define dagc2_multiplier_7_0_pos 0 +#define dagc2_multiplier_7_0_len 8 +#define dagc2_multiplier_7_0_lsb 0 +#define xd_r_dagc2_multiplier_15_8 0xA1D7 +#define dagc2_multiplier_15_8_pos 0 +#define dagc2_multiplier_15_8_len 8 +#define dagc2_multiplier_15_8_lsb 8 +#define xd_r_dagc2_right_shift_bits 0xA1D8 +#define dagc2_right_shift_bits_pos 0 +#define dagc2_right_shift_bits_len 4 +#define dagc2_right_shift_bits_lsb 0 +#define xd_p_cfoe_NS_coeff1_7_0 0xA200 +#define cfoe_NS_coeff1_7_0_pos 0 +#define cfoe_NS_coeff1_7_0_len 8 +#define cfoe_NS_coeff1_7_0_lsb 0 +#define xd_p_cfoe_NS_coeff1_15_8 0xA201 +#define cfoe_NS_coeff1_15_8_pos 0 +#define cfoe_NS_coeff1_15_8_len 8 +#define cfoe_NS_coeff1_15_8_lsb 8 +#define xd_p_cfoe_NS_coeff1_23_16 0xA202 +#define cfoe_NS_coeff1_23_16_pos 0 +#define cfoe_NS_coeff1_23_16_len 8 +#define cfoe_NS_coeff1_23_16_lsb 16 +#define xd_p_cfoe_NS_coeff1_25_24 0xA203 +#define cfoe_NS_coeff1_25_24_pos 0 +#define cfoe_NS_coeff1_25_24_len 2 +#define cfoe_NS_coeff1_25_24_lsb 24 +#define xd_p_cfoe_NS_coeff2_5_0 0xA203 +#define cfoe_NS_coeff2_5_0_pos 2 +#define cfoe_NS_coeff2_5_0_len 6 +#define cfoe_NS_coeff2_5_0_lsb 0 +#define xd_p_cfoe_NS_coeff2_13_6 0xA204 +#define cfoe_NS_coeff2_13_6_pos 0 +#define cfoe_NS_coeff2_13_6_len 8 +#define cfoe_NS_coeff2_13_6_lsb 6 +#define xd_p_cfoe_NS_coeff2_21_14 0xA205 +#define cfoe_NS_coeff2_21_14_pos 0 +#define cfoe_NS_coeff2_21_14_len 8 +#define cfoe_NS_coeff2_21_14_lsb 14 +#define xd_p_cfoe_NS_coeff2_24_22 0xA206 +#define cfoe_NS_coeff2_24_22_pos 0 +#define cfoe_NS_coeff2_24_22_len 3 +#define cfoe_NS_coeff2_24_22_lsb 22 +#define xd_p_cfoe_lf_c1_4_0 0xA206 +#define cfoe_lf_c1_4_0_pos 3 +#define cfoe_lf_c1_4_0_len 5 +#define cfoe_lf_c1_4_0_lsb 0 +#define xd_p_cfoe_lf_c1_12_5 0xA207 +#define cfoe_lf_c1_12_5_pos 0 +#define cfoe_lf_c1_12_5_len 8 +#define cfoe_lf_c1_12_5_lsb 5 +#define xd_p_cfoe_lf_c1_20_13 0xA208 +#define cfoe_lf_c1_20_13_pos 0 +#define cfoe_lf_c1_20_13_len 8 +#define cfoe_lf_c1_20_13_lsb 13 +#define xd_p_cfoe_lf_c1_25_21 0xA209 +#define cfoe_lf_c1_25_21_pos 0 +#define cfoe_lf_c1_25_21_len 5 +#define cfoe_lf_c1_25_21_lsb 21 +#define xd_p_cfoe_lf_c2_2_0 0xA209 +#define cfoe_lf_c2_2_0_pos 5 +#define cfoe_lf_c2_2_0_len 3 +#define cfoe_lf_c2_2_0_lsb 0 +#define xd_p_cfoe_lf_c2_10_3 0xA20A +#define cfoe_lf_c2_10_3_pos 0 +#define cfoe_lf_c2_10_3_len 8 +#define cfoe_lf_c2_10_3_lsb 3 +#define xd_p_cfoe_lf_c2_18_11 0xA20B +#define cfoe_lf_c2_18_11_pos 0 +#define cfoe_lf_c2_18_11_len 8 +#define cfoe_lf_c2_18_11_lsb 11 +#define xd_p_cfoe_lf_c2_25_19 0xA20C +#define cfoe_lf_c2_25_19_pos 0 +#define cfoe_lf_c2_25_19_len 7 +#define cfoe_lf_c2_25_19_lsb 19 +#define xd_p_cfoe_ifod_7_0 0xA20D +#define cfoe_ifod_7_0_pos 0 +#define cfoe_ifod_7_0_len 8 +#define cfoe_ifod_7_0_lsb 0 +#define xd_p_cfoe_ifod_10_8 0xA20E +#define cfoe_ifod_10_8_pos 0 +#define cfoe_ifod_10_8_len 3 +#define cfoe_ifod_10_8_lsb 8 +#define xd_p_cfoe_Divg_ctr_th 0xA20E +#define cfoe_Divg_ctr_th_pos 4 +#define cfoe_Divg_ctr_th_len 4 +#define cfoe_Divg_ctr_th_lsb 0 +#define xd_p_cfoe_FOT_divg_th 0xA20F +#define cfoe_FOT_divg_th_pos 0 +#define cfoe_FOT_divg_th_len 8 +#define cfoe_FOT_divg_th_lsb 0 +#define xd_p_cfoe_FOT_cnvg_th 0xA210 +#define cfoe_FOT_cnvg_th_pos 0 +#define cfoe_FOT_cnvg_th_len 8 +#define cfoe_FOT_cnvg_th_lsb 0 +#define xd_p_reg_cfoe_offset_7_0 0xA211 +#define reg_cfoe_offset_7_0_pos 0 +#define reg_cfoe_offset_7_0_len 8 +#define reg_cfoe_offset_7_0_lsb 0 +#define xd_p_reg_cfoe_offset_9_8 0xA212 +#define reg_cfoe_offset_9_8_pos 0 +#define reg_cfoe_offset_9_8_len 2 +#define reg_cfoe_offset_9_8_lsb 8 +#define xd_p_reg_cfoe_ifoe_sign_corr 0xA212 +#define reg_cfoe_ifoe_sign_corr_pos 2 +#define reg_cfoe_ifoe_sign_corr_len 1 +#define reg_cfoe_ifoe_sign_corr_lsb 0 +#define xd_r_cfoe_fot_LF_output_7_0 0xA218 +#define cfoe_fot_LF_output_7_0_pos 0 +#define cfoe_fot_LF_output_7_0_len 8 +#define cfoe_fot_LF_output_7_0_lsb 0 +#define xd_r_cfoe_fot_LF_output_15_8 0xA219 +#define cfoe_fot_LF_output_15_8_pos 0 +#define cfoe_fot_LF_output_15_8_len 8 +#define cfoe_fot_LF_output_15_8_lsb 8 +#define xd_r_cfoe_ifo_metric_7_0 0xA21A +#define cfoe_ifo_metric_7_0_pos 0 +#define cfoe_ifo_metric_7_0_len 8 +#define cfoe_ifo_metric_7_0_lsb 0 +#define xd_r_cfoe_ifo_metric_15_8 0xA21B +#define cfoe_ifo_metric_15_8_pos 0 +#define cfoe_ifo_metric_15_8_len 8 +#define cfoe_ifo_metric_15_8_lsb 8 +#define xd_r_cfoe_ifo_metric_23_16 0xA21C +#define cfoe_ifo_metric_23_16_pos 0 +#define cfoe_ifo_metric_23_16_len 8 +#define cfoe_ifo_metric_23_16_lsb 16 +#define xd_p_ste_Nu 0xA220 +#define ste_Nu_pos 0 +#define ste_Nu_len 2 +#define ste_Nu_lsb 0 +#define xd_p_ste_GI 0xA220 +#define ste_GI_pos 2 +#define ste_GI_len 3 +#define ste_GI_lsb 0 +#define xd_p_ste_symbol_num 0xA221 +#define ste_symbol_num_pos 0 +#define ste_symbol_num_len 2 +#define ste_symbol_num_lsb 0 +#define xd_p_ste_sample_num 0xA221 +#define ste_sample_num_pos 2 +#define ste_sample_num_len 2 +#define ste_sample_num_lsb 0 +#define xd_p_reg_ste_buf_en 0xA221 +#define reg_ste_buf_en_pos 7 +#define reg_ste_buf_en_len 1 +#define reg_ste_buf_en_lsb 0 +#define xd_p_ste_FFT_offset_7_0 0xA222 +#define ste_FFT_offset_7_0_pos 0 +#define ste_FFT_offset_7_0_len 8 +#define ste_FFT_offset_7_0_lsb 0 +#define xd_p_ste_FFT_offset_11_8 0xA223 +#define ste_FFT_offset_11_8_pos 0 +#define ste_FFT_offset_11_8_len 4 +#define ste_FFT_offset_11_8_lsb 8 +#define xd_p_reg_ste_tstmod 0xA223 +#define reg_ste_tstmod_pos 5 +#define reg_ste_tstmod_len 1 +#define reg_ste_tstmod_lsb 0 +#define xd_p_ste_adv_start_7_0 0xA224 +#define ste_adv_start_7_0_pos 0 +#define ste_adv_start_7_0_len 8 +#define ste_adv_start_7_0_lsb 0 +#define xd_p_ste_adv_start_10_8 0xA225 +#define ste_adv_start_10_8_pos 0 +#define ste_adv_start_10_8_len 3 +#define ste_adv_start_10_8_lsb 8 +#define xd_p_ste_adv_stop 0xA226 +#define ste_adv_stop_pos 0 +#define ste_adv_stop_len 8 +#define ste_adv_stop_lsb 0 +#define xd_r_ste_P_value_7_0 0xA228 +#define ste_P_value_7_0_pos 0 +#define ste_P_value_7_0_len 8 +#define ste_P_value_7_0_lsb 0 +#define xd_r_ste_P_value_10_8 0xA229 +#define ste_P_value_10_8_pos 0 +#define ste_P_value_10_8_len 3 +#define ste_P_value_10_8_lsb 8 +#define xd_r_ste_M_value_7_0 0xA22A +#define ste_M_value_7_0_pos 0 +#define ste_M_value_7_0_len 8 +#define ste_M_value_7_0_lsb 0 +#define xd_r_ste_M_value_10_8 0xA22B +#define ste_M_value_10_8_pos 0 +#define ste_M_value_10_8_len 3 +#define ste_M_value_10_8_lsb 8 +#define xd_r_ste_H1 0xA22C +#define ste_H1_pos 0 +#define ste_H1_len 7 +#define ste_H1_lsb 0 +#define xd_r_ste_H2 0xA22D +#define ste_H2_pos 0 +#define ste_H2_len 7 +#define ste_H2_lsb 0 +#define xd_r_ste_H3 0xA22E +#define ste_H3_pos 0 +#define ste_H3_len 7 +#define ste_H3_lsb 0 +#define xd_r_ste_H4 0xA22F +#define ste_H4_pos 0 +#define ste_H4_len 7 +#define ste_H4_lsb 0 +#define xd_r_ste_Corr_value_I_7_0 0xA230 +#define ste_Corr_value_I_7_0_pos 0 +#define ste_Corr_value_I_7_0_len 8 +#define ste_Corr_value_I_7_0_lsb 0 +#define xd_r_ste_Corr_value_I_15_8 0xA231 +#define ste_Corr_value_I_15_8_pos 0 +#define ste_Corr_value_I_15_8_len 8 +#define ste_Corr_value_I_15_8_lsb 8 +#define xd_r_ste_Corr_value_I_23_16 0xA232 +#define ste_Corr_value_I_23_16_pos 0 +#define ste_Corr_value_I_23_16_len 8 +#define ste_Corr_value_I_23_16_lsb 16 +#define xd_r_ste_Corr_value_I_27_24 0xA233 +#define ste_Corr_value_I_27_24_pos 0 +#define ste_Corr_value_I_27_24_len 4 +#define ste_Corr_value_I_27_24_lsb 24 +#define xd_r_ste_Corr_value_Q_7_0 0xA234 +#define ste_Corr_value_Q_7_0_pos 0 +#define ste_Corr_value_Q_7_0_len 8 +#define ste_Corr_value_Q_7_0_lsb 0 +#define xd_r_ste_Corr_value_Q_15_8 0xA235 +#define ste_Corr_value_Q_15_8_pos 0 +#define ste_Corr_value_Q_15_8_len 8 +#define ste_Corr_value_Q_15_8_lsb 8 +#define xd_r_ste_Corr_value_Q_23_16 0xA236 +#define ste_Corr_value_Q_23_16_pos 0 +#define ste_Corr_value_Q_23_16_len 8 +#define ste_Corr_value_Q_23_16_lsb 16 +#define xd_r_ste_Corr_value_Q_27_24 0xA237 +#define ste_Corr_value_Q_27_24_pos 0 +#define ste_Corr_value_Q_27_24_len 4 +#define ste_Corr_value_Q_27_24_lsb 24 +#define xd_r_ste_J_num_7_0 0xA238 +#define ste_J_num_7_0_pos 0 +#define ste_J_num_7_0_len 8 +#define ste_J_num_7_0_lsb 0 +#define xd_r_ste_J_num_15_8 0xA239 +#define ste_J_num_15_8_pos 0 +#define ste_J_num_15_8_len 8 +#define ste_J_num_15_8_lsb 8 +#define xd_r_ste_J_num_23_16 0xA23A +#define ste_J_num_23_16_pos 0 +#define ste_J_num_23_16_len 8 +#define ste_J_num_23_16_lsb 16 +#define xd_r_ste_J_num_31_24 0xA23B +#define ste_J_num_31_24_pos 0 +#define ste_J_num_31_24_len 8 +#define ste_J_num_31_24_lsb 24 +#define xd_r_ste_J_den_7_0 0xA23C +#define ste_J_den_7_0_pos 0 +#define ste_J_den_7_0_len 8 +#define ste_J_den_7_0_lsb 0 +#define xd_r_ste_J_den_15_8 0xA23D +#define ste_J_den_15_8_pos 0 +#define ste_J_den_15_8_len 8 +#define ste_J_den_15_8_lsb 8 +#define xd_r_ste_J_den_18_16 0xA23E +#define ste_J_den_18_16_pos 0 +#define ste_J_den_18_16_len 3 +#define ste_J_den_18_16_lsb 16 +#define xd_r_ste_Beacon_Indicator 0xA23E +#define ste_Beacon_Indicator_pos 4 +#define ste_Beacon_Indicator_len 1 +#define ste_Beacon_Indicator_lsb 0 +#define xd_r_tpsd_Frame_Num 0xA250 +#define tpsd_Frame_Num_pos 0 +#define tpsd_Frame_Num_len 2 +#define tpsd_Frame_Num_lsb 0 +#define xd_r_tpsd_Constel 0xA250 +#define tpsd_Constel_pos 2 +#define tpsd_Constel_len 2 +#define tpsd_Constel_lsb 0 +#define xd_r_tpsd_GI 0xA250 +#define tpsd_GI_pos 4 +#define tpsd_GI_len 2 +#define tpsd_GI_lsb 0 +#define xd_r_tpsd_Mode 0xA250 +#define tpsd_Mode_pos 6 +#define tpsd_Mode_len 2 +#define tpsd_Mode_lsb 0 +#define xd_r_tpsd_CR_HP 0xA251 +#define tpsd_CR_HP_pos 0 +#define tpsd_CR_HP_len 3 +#define tpsd_CR_HP_lsb 0 +#define xd_r_tpsd_CR_LP 0xA251 +#define tpsd_CR_LP_pos 3 +#define tpsd_CR_LP_len 3 +#define tpsd_CR_LP_lsb 0 +#define xd_r_tpsd_Hie 0xA252 +#define tpsd_Hie_pos 0 +#define tpsd_Hie_len 3 +#define tpsd_Hie_lsb 0 +#define xd_r_tpsd_Res_Bits 0xA252 +#define tpsd_Res_Bits_pos 3 +#define tpsd_Res_Bits_len 5 +#define tpsd_Res_Bits_lsb 0 +#define xd_r_tpsd_Res_Bits_0 0xA253 +#define tpsd_Res_Bits_0_pos 0 +#define tpsd_Res_Bits_0_len 1 +#define tpsd_Res_Bits_0_lsb 0 +#define xd_r_tpsd_LengthInd 0xA253 +#define tpsd_LengthInd_pos 1 +#define tpsd_LengthInd_len 6 +#define tpsd_LengthInd_lsb 0 +#define xd_r_tpsd_Cell_Id_7_0 0xA254 +#define tpsd_Cell_Id_7_0_pos 0 +#define tpsd_Cell_Id_7_0_len 8 +#define tpsd_Cell_Id_7_0_lsb 0 +#define xd_r_tpsd_Cell_Id_15_8 0xA255 +#define tpsd_Cell_Id_15_8_pos 0 +#define tpsd_Cell_Id_15_8_len 8 +#define tpsd_Cell_Id_15_8_lsb 0 +#define xd_p_reg_fft_mask_tone0_7_0 0xA260 +#define reg_fft_mask_tone0_7_0_pos 0 +#define reg_fft_mask_tone0_7_0_len 8 +#define reg_fft_mask_tone0_7_0_lsb 0 +#define xd_p_reg_fft_mask_tone0_12_8 0xA261 +#define reg_fft_mask_tone0_12_8_pos 0 +#define reg_fft_mask_tone0_12_8_len 5 +#define reg_fft_mask_tone0_12_8_lsb 8 +#define xd_p_reg_fft_mask_tone1_7_0 0xA262 +#define reg_fft_mask_tone1_7_0_pos 0 +#define reg_fft_mask_tone1_7_0_len 8 +#define reg_fft_mask_tone1_7_0_lsb 0 +#define xd_p_reg_fft_mask_tone1_12_8 0xA263 +#define reg_fft_mask_tone1_12_8_pos 0 +#define reg_fft_mask_tone1_12_8_len 5 +#define reg_fft_mask_tone1_12_8_lsb 8 +#define xd_p_reg_fft_mask_tone2_7_0 0xA264 +#define reg_fft_mask_tone2_7_0_pos 0 +#define reg_fft_mask_tone2_7_0_len 8 +#define reg_fft_mask_tone2_7_0_lsb 0 +#define xd_p_reg_fft_mask_tone2_12_8 0xA265 +#define reg_fft_mask_tone2_12_8_pos 0 +#define reg_fft_mask_tone2_12_8_len 5 +#define reg_fft_mask_tone2_12_8_lsb 8 +#define xd_p_reg_fft_mask_tone3_7_0 0xA266 +#define reg_fft_mask_tone3_7_0_pos 0 +#define reg_fft_mask_tone3_7_0_len 8 +#define reg_fft_mask_tone3_7_0_lsb 0 +#define xd_p_reg_fft_mask_tone3_12_8 0xA267 +#define reg_fft_mask_tone3_12_8_pos 0 +#define reg_fft_mask_tone3_12_8_len 5 +#define reg_fft_mask_tone3_12_8_lsb 8 +#define xd_p_reg_fft_mask_from0_7_0 0xA268 +#define reg_fft_mask_from0_7_0_pos 0 +#define reg_fft_mask_from0_7_0_len 8 +#define reg_fft_mask_from0_7_0_lsb 0 +#define xd_p_reg_fft_mask_from0_12_8 0xA269 +#define reg_fft_mask_from0_12_8_pos 0 +#define reg_fft_mask_from0_12_8_len 5 +#define reg_fft_mask_from0_12_8_lsb 8 +#define xd_p_reg_fft_mask_to0_7_0 0xA26A +#define reg_fft_mask_to0_7_0_pos 0 +#define reg_fft_mask_to0_7_0_len 8 +#define reg_fft_mask_to0_7_0_lsb 0 +#define xd_p_reg_fft_mask_to0_12_8 0xA26B +#define reg_fft_mask_to0_12_8_pos 0 +#define reg_fft_mask_to0_12_8_len 5 +#define reg_fft_mask_to0_12_8_lsb 8 +#define xd_p_reg_fft_mask_from1_7_0 0xA26C +#define reg_fft_mask_from1_7_0_pos 0 +#define reg_fft_mask_from1_7_0_len 8 +#define reg_fft_mask_from1_7_0_lsb 0 +#define xd_p_reg_fft_mask_from1_12_8 0xA26D +#define reg_fft_mask_from1_12_8_pos 0 +#define reg_fft_mask_from1_12_8_len 5 +#define reg_fft_mask_from1_12_8_lsb 8 +#define xd_p_reg_fft_mask_to1_7_0 0xA26E +#define reg_fft_mask_to1_7_0_pos 0 +#define reg_fft_mask_to1_7_0_len 8 +#define reg_fft_mask_to1_7_0_lsb 0 +#define xd_p_reg_fft_mask_to1_12_8 0xA26F +#define reg_fft_mask_to1_12_8_pos 0 +#define reg_fft_mask_to1_12_8_len 5 +#define reg_fft_mask_to1_12_8_lsb 8 +#define xd_p_reg_cge_idx0_7_0 0xA280 +#define reg_cge_idx0_7_0_pos 0 +#define reg_cge_idx0_7_0_len 8 +#define reg_cge_idx0_7_0_lsb 0 +#define xd_p_reg_cge_idx0_12_8 0xA281 +#define reg_cge_idx0_12_8_pos 0 +#define reg_cge_idx0_12_8_len 5 +#define reg_cge_idx0_12_8_lsb 8 +#define xd_p_reg_cge_idx1_7_0 0xA282 +#define reg_cge_idx1_7_0_pos 0 +#define reg_cge_idx1_7_0_len 8 +#define reg_cge_idx1_7_0_lsb 0 +#define xd_p_reg_cge_idx1_12_8 0xA283 +#define reg_cge_idx1_12_8_pos 0 +#define reg_cge_idx1_12_8_len 5 +#define reg_cge_idx1_12_8_lsb 8 +#define xd_p_reg_cge_idx2_7_0 0xA284 +#define reg_cge_idx2_7_0_pos 0 +#define reg_cge_idx2_7_0_len 8 +#define reg_cge_idx2_7_0_lsb 0 +#define xd_p_reg_cge_idx2_12_8 0xA285 +#define reg_cge_idx2_12_8_pos 0 +#define reg_cge_idx2_12_8_len 5 +#define reg_cge_idx2_12_8_lsb 8 +#define xd_p_reg_cge_idx3_7_0 0xA286 +#define reg_cge_idx3_7_0_pos 0 +#define reg_cge_idx3_7_0_len 8 +#define reg_cge_idx3_7_0_lsb 0 +#define xd_p_reg_cge_idx3_12_8 0xA287 +#define reg_cge_idx3_12_8_pos 0 +#define reg_cge_idx3_12_8_len 5 +#define reg_cge_idx3_12_8_lsb 8 +#define xd_p_reg_cge_idx4_7_0 0xA288 +#define reg_cge_idx4_7_0_pos 0 +#define reg_cge_idx4_7_0_len 8 +#define reg_cge_idx4_7_0_lsb 0 +#define xd_p_reg_cge_idx4_12_8 0xA289 +#define reg_cge_idx4_12_8_pos 0 +#define reg_cge_idx4_12_8_len 5 +#define reg_cge_idx4_12_8_lsb 8 +#define xd_p_reg_cge_idx5_7_0 0xA28A +#define reg_cge_idx5_7_0_pos 0 +#define reg_cge_idx5_7_0_len 8 +#define reg_cge_idx5_7_0_lsb 0 +#define xd_p_reg_cge_idx5_12_8 0xA28B +#define reg_cge_idx5_12_8_pos 0 +#define reg_cge_idx5_12_8_len 5 +#define reg_cge_idx5_12_8_lsb 8 +#define xd_p_reg_cge_idx6_7_0 0xA28C +#define reg_cge_idx6_7_0_pos 0 +#define reg_cge_idx6_7_0_len 8 +#define reg_cge_idx6_7_0_lsb 0 +#define xd_p_reg_cge_idx6_12_8 0xA28D +#define reg_cge_idx6_12_8_pos 0 +#define reg_cge_idx6_12_8_len 5 +#define reg_cge_idx6_12_8_lsb 8 +#define xd_p_reg_cge_idx7_7_0 0xA28E +#define reg_cge_idx7_7_0_pos 0 +#define reg_cge_idx7_7_0_len 8 +#define reg_cge_idx7_7_0_lsb 0 +#define xd_p_reg_cge_idx7_12_8 0xA28F +#define reg_cge_idx7_12_8_pos 0 +#define reg_cge_idx7_12_8_len 5 +#define reg_cge_idx7_12_8_lsb 8 +#define xd_p_reg_cge_idx8_7_0 0xA290 +#define reg_cge_idx8_7_0_pos 0 +#define reg_cge_idx8_7_0_len 8 +#define reg_cge_idx8_7_0_lsb 0 +#define xd_p_reg_cge_idx8_12_8 0xA291 +#define reg_cge_idx8_12_8_pos 0 +#define reg_cge_idx8_12_8_len 5 +#define reg_cge_idx8_12_8_lsb 8 +#define xd_p_reg_cge_idx9_7_0 0xA292 +#define reg_cge_idx9_7_0_pos 0 +#define reg_cge_idx9_7_0_len 8 +#define reg_cge_idx9_7_0_lsb 0 +#define xd_p_reg_cge_idx9_12_8 0xA293 +#define reg_cge_idx9_12_8_pos 0 +#define reg_cge_idx9_12_8_len 5 +#define reg_cge_idx9_12_8_lsb 8 +#define xd_p_reg_cge_idx10_7_0 0xA294 +#define reg_cge_idx10_7_0_pos 0 +#define reg_cge_idx10_7_0_len 8 +#define reg_cge_idx10_7_0_lsb 0 +#define xd_p_reg_cge_idx10_12_8 0xA295 +#define reg_cge_idx10_12_8_pos 0 +#define reg_cge_idx10_12_8_len 5 +#define reg_cge_idx10_12_8_lsb 8 +#define xd_p_reg_cge_idx11_7_0 0xA296 +#define reg_cge_idx11_7_0_pos 0 +#define reg_cge_idx11_7_0_len 8 +#define reg_cge_idx11_7_0_lsb 0 +#define xd_p_reg_cge_idx11_12_8 0xA297 +#define reg_cge_idx11_12_8_pos 0 +#define reg_cge_idx11_12_8_len 5 +#define reg_cge_idx11_12_8_lsb 8 +#define xd_p_reg_cge_idx12_7_0 0xA298 +#define reg_cge_idx12_7_0_pos 0 +#define reg_cge_idx12_7_0_len 8 +#define reg_cge_idx12_7_0_lsb 0 +#define xd_p_reg_cge_idx12_12_8 0xA299 +#define reg_cge_idx12_12_8_pos 0 +#define reg_cge_idx12_12_8_len 5 +#define reg_cge_idx12_12_8_lsb 8 +#define xd_p_reg_cge_idx13_7_0 0xA29A +#define reg_cge_idx13_7_0_pos 0 +#define reg_cge_idx13_7_0_len 8 +#define reg_cge_idx13_7_0_lsb 0 +#define xd_p_reg_cge_idx13_12_8 0xA29B +#define reg_cge_idx13_12_8_pos 0 +#define reg_cge_idx13_12_8_len 5 +#define reg_cge_idx13_12_8_lsb 8 +#define xd_p_reg_cge_idx14_7_0 0xA29C +#define reg_cge_idx14_7_0_pos 0 +#define reg_cge_idx14_7_0_len 8 +#define reg_cge_idx14_7_0_lsb 0 +#define xd_p_reg_cge_idx14_12_8 0xA29D +#define reg_cge_idx14_12_8_pos 0 +#define reg_cge_idx14_12_8_len 5 +#define reg_cge_idx14_12_8_lsb 8 +#define xd_p_reg_cge_idx15_7_0 0xA29E +#define reg_cge_idx15_7_0_pos 0 +#define reg_cge_idx15_7_0_len 8 +#define reg_cge_idx15_7_0_lsb 0 +#define xd_p_reg_cge_idx15_12_8 0xA29F +#define reg_cge_idx15_12_8_pos 0 +#define reg_cge_idx15_12_8_len 5 +#define reg_cge_idx15_12_8_lsb 8 +#define xd_r_reg_fft_crc 0xA2A8 +#define reg_fft_crc_pos 0 +#define reg_fft_crc_len 8 +#define reg_fft_crc_lsb 0 +#define xd_p_fd_fft_shift_max 0xA2A9 +#define fd_fft_shift_max_pos 0 +#define fd_fft_shift_max_len 4 +#define fd_fft_shift_max_lsb 0 +#define xd_r_fd_fft_shift 0xA2A9 +#define fd_fft_shift_pos 4 +#define fd_fft_shift_len 4 +#define fd_fft_shift_lsb 0 +#define xd_r_fd_fft_frame_num 0xA2AA +#define fd_fft_frame_num_pos 0 +#define fd_fft_frame_num_len 2 +#define fd_fft_frame_num_lsb 0 +#define xd_r_fd_fft_symbol_count 0xA2AB +#define fd_fft_symbol_count_pos 0 +#define fd_fft_symbol_count_len 7 +#define fd_fft_symbol_count_lsb 0 +#define xd_r_reg_fft_idx_max_7_0 0xA2AC +#define reg_fft_idx_max_7_0_pos 0 +#define reg_fft_idx_max_7_0_len 8 +#define reg_fft_idx_max_7_0_lsb 0 +#define xd_r_reg_fft_idx_max_12_8 0xA2AD +#define reg_fft_idx_max_12_8_pos 0 +#define reg_fft_idx_max_12_8_len 5 +#define reg_fft_idx_max_12_8_lsb 8 +#define xd_p_reg_cge_program 0xA2AE +#define reg_cge_program_pos 0 +#define reg_cge_program_len 1 +#define reg_cge_program_lsb 0 +#define xd_p_reg_cge_fixed 0xA2AE +#define reg_cge_fixed_pos 1 +#define reg_cge_fixed_len 1 +#define reg_cge_fixed_lsb 0 +#define xd_p_reg_fft_rotate_en 0xA2AE +#define reg_fft_rotate_en_pos 2 +#define reg_fft_rotate_en_len 1 +#define reg_fft_rotate_en_lsb 0 +#define xd_p_reg_fft_rotate_base_4_0 0xA2AE +#define reg_fft_rotate_base_4_0_pos 3 +#define reg_fft_rotate_base_4_0_len 5 +#define reg_fft_rotate_base_4_0_lsb 0 +#define xd_p_reg_fft_rotate_base_12_5 0xA2AF +#define reg_fft_rotate_base_12_5_pos 0 +#define reg_fft_rotate_base_12_5_len 8 +#define reg_fft_rotate_base_12_5_lsb 5 +#define xd_p_reg_gp_trigger_fd 0xA2B8 +#define reg_gp_trigger_fd_pos 0 +#define reg_gp_trigger_fd_len 1 +#define reg_gp_trigger_fd_lsb 0 +#define xd_p_reg_trigger_sel_fd 0xA2B8 +#define reg_trigger_sel_fd_pos 1 +#define reg_trigger_sel_fd_len 2 +#define reg_trigger_sel_fd_lsb 0 +#define xd_p_reg_trigger_module_sel_fd 0xA2B9 +#define reg_trigger_module_sel_fd_pos 0 +#define reg_trigger_module_sel_fd_len 6 +#define reg_trigger_module_sel_fd_lsb 0 +#define xd_p_reg_trigger_set_sel_fd 0xA2BA +#define reg_trigger_set_sel_fd_pos 0 +#define reg_trigger_set_sel_fd_len 6 +#define reg_trigger_set_sel_fd_lsb 0 +#define xd_p_reg_fd_noname_7_0 0xA2BC +#define reg_fd_noname_7_0_pos 0 +#define reg_fd_noname_7_0_len 8 +#define reg_fd_noname_7_0_lsb 0 +#define xd_p_reg_fd_noname_15_8 0xA2BD +#define reg_fd_noname_15_8_pos 0 +#define reg_fd_noname_15_8_len 8 +#define reg_fd_noname_15_8_lsb 8 +#define xd_p_reg_fd_noname_23_16 0xA2BE +#define reg_fd_noname_23_16_pos 0 +#define reg_fd_noname_23_16_len 8 +#define reg_fd_noname_23_16_lsb 16 +#define xd_p_reg_fd_noname_31_24 0xA2BF +#define reg_fd_noname_31_24_pos 0 +#define reg_fd_noname_31_24_len 8 +#define reg_fd_noname_31_24_lsb 24 +#define xd_r_fd_fpcc_cp_corr_signn 0xA2C0 +#define fd_fpcc_cp_corr_signn_pos 0 +#define fd_fpcc_cp_corr_signn_len 8 +#define fd_fpcc_cp_corr_signn_lsb 0 +#define xd_p_reg_feq_s1 0xA2C1 +#define reg_feq_s1_pos 0 +#define reg_feq_s1_len 5 +#define reg_feq_s1_lsb 0 +#define xd_p_fd_fpcc_cp_corr_tone_th 0xA2C2 +#define fd_fpcc_cp_corr_tone_th_pos 0 +#define fd_fpcc_cp_corr_tone_th_len 6 +#define fd_fpcc_cp_corr_tone_th_lsb 0 +#define xd_p_fd_fpcc_cp_corr_symbol_log_th 0xA2C3 +#define fd_fpcc_cp_corr_symbol_log_th_pos 0 +#define fd_fpcc_cp_corr_symbol_log_th_len 4 +#define fd_fpcc_cp_corr_symbol_log_th_lsb 0 +#define xd_p_fd_fpcc_cp_corr_int 0xA2C4 +#define fd_fpcc_cp_corr_int_pos 0 +#define fd_fpcc_cp_corr_int_len 1 +#define fd_fpcc_cp_corr_int_lsb 0 +#define xd_p_reg_sfoe_ns_7_0 0xA320 +#define reg_sfoe_ns_7_0_pos 0 +#define reg_sfoe_ns_7_0_len 8 +#define reg_sfoe_ns_7_0_lsb 0 +#define xd_p_reg_sfoe_ns_14_8 0xA321 +#define reg_sfoe_ns_14_8_pos 0 +#define reg_sfoe_ns_14_8_len 7 +#define reg_sfoe_ns_14_8_lsb 8 +#define xd_p_reg_sfoe_c1_7_0 0xA322 +#define reg_sfoe_c1_7_0_pos 0 +#define reg_sfoe_c1_7_0_len 8 +#define reg_sfoe_c1_7_0_lsb 0 +#define xd_p_reg_sfoe_c1_15_8 0xA323 +#define reg_sfoe_c1_15_8_pos 0 +#define reg_sfoe_c1_15_8_len 8 +#define reg_sfoe_c1_15_8_lsb 8 +#define xd_p_reg_sfoe_c1_17_16 0xA324 +#define reg_sfoe_c1_17_16_pos 0 +#define reg_sfoe_c1_17_16_len 2 +#define reg_sfoe_c1_17_16_lsb 16 +#define xd_p_reg_sfoe_c2_7_0 0xA325 +#define reg_sfoe_c2_7_0_pos 0 +#define reg_sfoe_c2_7_0_len 8 +#define reg_sfoe_c2_7_0_lsb 0 +#define xd_p_reg_sfoe_c2_15_8 0xA326 +#define reg_sfoe_c2_15_8_pos 0 +#define reg_sfoe_c2_15_8_len 8 +#define reg_sfoe_c2_15_8_lsb 8 +#define xd_p_reg_sfoe_c2_17_16 0xA327 +#define reg_sfoe_c2_17_16_pos 0 +#define reg_sfoe_c2_17_16_len 2 +#define reg_sfoe_c2_17_16_lsb 16 +#define xd_r_reg_sfoe_out_9_2 0xA328 +#define reg_sfoe_out_9_2_pos 0 +#define reg_sfoe_out_9_2_len 8 +#define reg_sfoe_out_9_2_lsb 0 +#define xd_r_reg_sfoe_out_1_0 0xA329 +#define reg_sfoe_out_1_0_pos 0 +#define reg_sfoe_out_1_0_len 2 +#define reg_sfoe_out_1_0_lsb 0 +#define xd_p_reg_sfoe_lm_counter_th 0xA32A +#define reg_sfoe_lm_counter_th_pos 0 +#define reg_sfoe_lm_counter_th_len 4 +#define reg_sfoe_lm_counter_th_lsb 0 +#define xd_p_reg_sfoe_convg_th 0xA32B +#define reg_sfoe_convg_th_pos 0 +#define reg_sfoe_convg_th_len 8 +#define reg_sfoe_convg_th_lsb 0 +#define xd_p_reg_sfoe_divg_th 0xA32C +#define reg_sfoe_divg_th_pos 0 +#define reg_sfoe_divg_th_len 8 +#define reg_sfoe_divg_th_lsb 0 +#define xd_p_fd_tpsd_en 0xA330 +#define fd_tpsd_en_pos 0 +#define fd_tpsd_en_len 1 +#define fd_tpsd_en_lsb 0 +#define xd_p_fd_tpsd_dis 0xA330 +#define fd_tpsd_dis_pos 1 +#define fd_tpsd_dis_len 1 +#define fd_tpsd_dis_lsb 0 +#define xd_p_fd_tpsd_rst 0xA330 +#define fd_tpsd_rst_pos 2 +#define fd_tpsd_rst_len 1 +#define fd_tpsd_rst_lsb 0 +#define xd_p_fd_tpsd_lock 0xA330 +#define fd_tpsd_lock_pos 3 +#define fd_tpsd_lock_len 1 +#define fd_tpsd_lock_lsb 0 +#define xd_r_fd_tpsd_s19 0xA330 +#define fd_tpsd_s19_pos 4 +#define fd_tpsd_s19_len 1 +#define fd_tpsd_s19_lsb 0 +#define xd_r_fd_tpsd_s17 0xA330 +#define fd_tpsd_s17_pos 5 +#define fd_tpsd_s17_len 1 +#define fd_tpsd_s17_lsb 0 +#define xd_p_fd_sfr_ste_en 0xA331 +#define fd_sfr_ste_en_pos 0 +#define fd_sfr_ste_en_len 1 +#define fd_sfr_ste_en_lsb 0 +#define xd_p_fd_sfr_ste_dis 0xA331 +#define fd_sfr_ste_dis_pos 1 +#define fd_sfr_ste_dis_len 1 +#define fd_sfr_ste_dis_lsb 0 +#define xd_p_fd_sfr_ste_rst 0xA331 +#define fd_sfr_ste_rst_pos 2 +#define fd_sfr_ste_rst_len 1 +#define fd_sfr_ste_rst_lsb 0 +#define xd_p_fd_sfr_ste_mode 0xA331 +#define fd_sfr_ste_mode_pos 3 +#define fd_sfr_ste_mode_len 1 +#define fd_sfr_ste_mode_lsb 0 +#define xd_p_fd_sfr_ste_done 0xA331 +#define fd_sfr_ste_done_pos 4 +#define fd_sfr_ste_done_len 1 +#define fd_sfr_ste_done_lsb 0 +#define xd_p_reg_cfoe_ffoe_en 0xA332 +#define reg_cfoe_ffoe_en_pos 0 +#define reg_cfoe_ffoe_en_len 1 +#define reg_cfoe_ffoe_en_lsb 0 +#define xd_p_reg_cfoe_ffoe_dis 0xA332 +#define reg_cfoe_ffoe_dis_pos 1 +#define reg_cfoe_ffoe_dis_len 1 +#define reg_cfoe_ffoe_dis_lsb 0 +#define xd_p_reg_cfoe_ffoe_rst 0xA332 +#define reg_cfoe_ffoe_rst_pos 2 +#define reg_cfoe_ffoe_rst_len 1 +#define reg_cfoe_ffoe_rst_lsb 0 +#define xd_p_reg_cfoe_ifoe_en 0xA332 +#define reg_cfoe_ifoe_en_pos 3 +#define reg_cfoe_ifoe_en_len 1 +#define reg_cfoe_ifoe_en_lsb 0 +#define xd_p_reg_cfoe_ifoe_dis 0xA332 +#define reg_cfoe_ifoe_dis_pos 4 +#define reg_cfoe_ifoe_dis_len 1 +#define reg_cfoe_ifoe_dis_lsb 0 +#define xd_p_reg_cfoe_ifoe_rst 0xA332 +#define reg_cfoe_ifoe_rst_pos 5 +#define reg_cfoe_ifoe_rst_len 1 +#define reg_cfoe_ifoe_rst_lsb 0 +#define xd_p_reg_cfoe_fot_en 0xA332 +#define reg_cfoe_fot_en_pos 6 +#define reg_cfoe_fot_en_len 1 +#define reg_cfoe_fot_en_lsb 0 +#define xd_p_reg_cfoe_fot_lm_en 0xA332 +#define reg_cfoe_fot_lm_en_pos 7 +#define reg_cfoe_fot_lm_en_len 1 +#define reg_cfoe_fot_lm_en_lsb 0 +#define xd_p_reg_cfoe_fot_rst 0xA333 +#define reg_cfoe_fot_rst_pos 0 +#define reg_cfoe_fot_rst_len 1 +#define reg_cfoe_fot_rst_lsb 0 +#define xd_r_fd_cfoe_ffoe_done 0xA333 +#define fd_cfoe_ffoe_done_pos 1 +#define fd_cfoe_ffoe_done_len 1 +#define fd_cfoe_ffoe_done_lsb 0 +#define xd_p_fd_cfoe_metric_vld 0xA333 +#define fd_cfoe_metric_vld_pos 2 +#define fd_cfoe_metric_vld_len 1 +#define fd_cfoe_metric_vld_lsb 0 +#define xd_p_reg_cfoe_ifod_vld 0xA333 +#define reg_cfoe_ifod_vld_pos 3 +#define reg_cfoe_ifod_vld_len 1 +#define reg_cfoe_ifod_vld_lsb 0 +#define xd_r_fd_cfoe_ifoe_done 0xA333 +#define fd_cfoe_ifoe_done_pos 4 +#define fd_cfoe_ifoe_done_len 1 +#define fd_cfoe_ifoe_done_lsb 0 +#define xd_r_fd_cfoe_fot_valid 0xA333 +#define fd_cfoe_fot_valid_pos 5 +#define fd_cfoe_fot_valid_len 1 +#define fd_cfoe_fot_valid_lsb 0 +#define xd_p_reg_cfoe_divg_int 0xA333 +#define reg_cfoe_divg_int_pos 6 +#define reg_cfoe_divg_int_len 1 +#define reg_cfoe_divg_int_lsb 0 +#define xd_r_reg_cfoe_divg_flag 0xA333 +#define reg_cfoe_divg_flag_pos 7 +#define reg_cfoe_divg_flag_len 1 +#define reg_cfoe_divg_flag_lsb 0 +#define xd_p_reg_sfoe_en 0xA334 +#define reg_sfoe_en_pos 0 +#define reg_sfoe_en_len 1 +#define reg_sfoe_en_lsb 0 +#define xd_p_reg_sfoe_dis 0xA334 +#define reg_sfoe_dis_pos 1 +#define reg_sfoe_dis_len 1 +#define reg_sfoe_dis_lsb 0 +#define xd_p_reg_sfoe_rst 0xA334 +#define reg_sfoe_rst_pos 2 +#define reg_sfoe_rst_len 1 +#define reg_sfoe_rst_lsb 0 +#define xd_p_reg_sfoe_vld_int 0xA334 +#define reg_sfoe_vld_int_pos 3 +#define reg_sfoe_vld_int_len 1 +#define reg_sfoe_vld_int_lsb 0 +#define xd_p_reg_sfoe_lm_en 0xA334 +#define reg_sfoe_lm_en_pos 4 +#define reg_sfoe_lm_en_len 1 +#define reg_sfoe_lm_en_lsb 0 +#define xd_p_reg_sfoe_divg_int 0xA334 +#define reg_sfoe_divg_int_pos 5 +#define reg_sfoe_divg_int_len 1 +#define reg_sfoe_divg_int_lsb 0 +#define xd_r_reg_sfoe_divg_flag 0xA334 +#define reg_sfoe_divg_flag_pos 6 +#define reg_sfoe_divg_flag_len 1 +#define reg_sfoe_divg_flag_lsb 0 +#define xd_p_reg_fft_rst 0xA335 +#define reg_fft_rst_pos 0 +#define reg_fft_rst_len 1 +#define reg_fft_rst_lsb 0 +#define xd_p_reg_fft_fast_beacon 0xA335 +#define reg_fft_fast_beacon_pos 1 +#define reg_fft_fast_beacon_len 1 +#define reg_fft_fast_beacon_lsb 0 +#define xd_p_reg_fft_fast_valid 0xA335 +#define reg_fft_fast_valid_pos 2 +#define reg_fft_fast_valid_len 1 +#define reg_fft_fast_valid_lsb 0 +#define xd_p_reg_fft_mask_en 0xA335 +#define reg_fft_mask_en_pos 3 +#define reg_fft_mask_en_len 1 +#define reg_fft_mask_en_lsb 0 +#define xd_p_reg_fft_crc_en 0xA335 +#define reg_fft_crc_en_pos 4 +#define reg_fft_crc_en_len 1 +#define reg_fft_crc_en_lsb 0 +#define xd_p_reg_finr_en 0xA336 +#define reg_finr_en_pos 0 +#define reg_finr_en_len 1 +#define reg_finr_en_lsb 0 +#define xd_p_fd_fste_en 0xA337 +#define fd_fste_en_pos 1 +#define fd_fste_en_len 1 +#define fd_fste_en_lsb 0 +#define xd_p_fd_sqi_tps_level_shift 0xA338 +#define fd_sqi_tps_level_shift_pos 0 +#define fd_sqi_tps_level_shift_len 8 +#define fd_sqi_tps_level_shift_lsb 0 +#define xd_p_fd_pilot_ma_len 0xA339 +#define fd_pilot_ma_len_pos 0 +#define fd_pilot_ma_len_len 6 +#define fd_pilot_ma_len_lsb 0 +#define xd_p_fd_tps_ma_len 0xA33A +#define fd_tps_ma_len_pos 0 +#define fd_tps_ma_len_len 6 +#define fd_tps_ma_len_lsb 0 +#define xd_p_fd_sqi_s3 0xA33B +#define fd_sqi_s3_pos 0 +#define fd_sqi_s3_len 8 +#define fd_sqi_s3_lsb 0 +#define xd_p_fd_sqi_dummy_reg_0 0xA33C +#define fd_sqi_dummy_reg_0_pos 0 +#define fd_sqi_dummy_reg_0_len 1 +#define fd_sqi_dummy_reg_0_lsb 0 +#define xd_p_fd_sqi_debug_sel 0xA33C +#define fd_sqi_debug_sel_pos 1 +#define fd_sqi_debug_sel_len 2 +#define fd_sqi_debug_sel_lsb 0 +#define xd_p_fd_sqi_s2 0xA33C +#define fd_sqi_s2_pos 3 +#define fd_sqi_s2_len 5 +#define fd_sqi_s2_lsb 0 +#define xd_p_fd_sqi_dummy_reg_1 0xA33D +#define fd_sqi_dummy_reg_1_pos 0 +#define fd_sqi_dummy_reg_1_len 1 +#define fd_sqi_dummy_reg_1_lsb 0 +#define xd_p_fd_inr_ignore 0xA33D +#define fd_inr_ignore_pos 1 +#define fd_inr_ignore_len 1 +#define fd_inr_ignore_lsb 0 +#define xd_p_fd_pilot_ignore 0xA33D +#define fd_pilot_ignore_pos 2 +#define fd_pilot_ignore_len 1 +#define fd_pilot_ignore_lsb 0 +#define xd_p_fd_etps_ignore 0xA33D +#define fd_etps_ignore_pos 3 +#define fd_etps_ignore_len 1 +#define fd_etps_ignore_lsb 0 +#define xd_p_fd_sqi_s1 0xA33D +#define fd_sqi_s1_pos 4 +#define fd_sqi_s1_len 4 +#define fd_sqi_s1_lsb 0 +#define xd_p_reg_fste_ehw_7_0 0xA33E +#define reg_fste_ehw_7_0_pos 0 +#define reg_fste_ehw_7_0_len 8 +#define reg_fste_ehw_7_0_lsb 0 +#define xd_p_reg_fste_ehw_9_8 0xA33F +#define reg_fste_ehw_9_8_pos 0 +#define reg_fste_ehw_9_8_len 2 +#define reg_fste_ehw_9_8_lsb 8 +#define xd_p_reg_fste_i_adj_vld 0xA33F +#define reg_fste_i_adj_vld_pos 2 +#define reg_fste_i_adj_vld_len 1 +#define reg_fste_i_adj_vld_lsb 0 +#define xd_p_reg_fste_phase_ini_7_0 0xA340 +#define reg_fste_phase_ini_7_0_pos 0 +#define reg_fste_phase_ini_7_0_len 8 +#define reg_fste_phase_ini_7_0_lsb 0 +#define xd_p_reg_fste_phase_ini_11_8 0xA341 +#define reg_fste_phase_ini_11_8_pos 0 +#define reg_fste_phase_ini_11_8_len 4 +#define reg_fste_phase_ini_11_8_lsb 8 +#define xd_p_reg_fste_phase_inc_3_0 0xA341 +#define reg_fste_phase_inc_3_0_pos 4 +#define reg_fste_phase_inc_3_0_len 4 +#define reg_fste_phase_inc_3_0_lsb 0 +#define xd_p_reg_fste_phase_inc_11_4 0xA342 +#define reg_fste_phase_inc_11_4_pos 0 +#define reg_fste_phase_inc_11_4_len 8 +#define reg_fste_phase_inc_11_4_lsb 4 +#define xd_p_reg_fste_acum_cost_cnt_max 0xA343 +#define reg_fste_acum_cost_cnt_max_pos 0 +#define reg_fste_acum_cost_cnt_max_len 4 +#define reg_fste_acum_cost_cnt_max_lsb 0 +#define xd_p_reg_fste_step_size_std 0xA343 +#define reg_fste_step_size_std_pos 4 +#define reg_fste_step_size_std_len 4 +#define reg_fste_step_size_std_lsb 0 +#define xd_p_reg_fste_step_size_max 0xA344 +#define reg_fste_step_size_max_pos 0 +#define reg_fste_step_size_max_len 4 +#define reg_fste_step_size_max_lsb 0 +#define xd_p_reg_fste_step_size_min 0xA344 +#define reg_fste_step_size_min_pos 4 +#define reg_fste_step_size_min_len 4 +#define reg_fste_step_size_min_lsb 0 +#define xd_p_reg_fste_frac_step_size_7_0 0xA345 +#define reg_fste_frac_step_size_7_0_pos 0 +#define reg_fste_frac_step_size_7_0_len 8 +#define reg_fste_frac_step_size_7_0_lsb 0 +#define xd_p_reg_fste_frac_step_size_15_8 0xA346 +#define reg_fste_frac_step_size_15_8_pos 0 +#define reg_fste_frac_step_size_15_8_len 8 +#define reg_fste_frac_step_size_15_8_lsb 8 +#define xd_p_reg_fste_frac_step_size_19_16 0xA347 +#define reg_fste_frac_step_size_19_16_pos 0 +#define reg_fste_frac_step_size_19_16_len 4 +#define reg_fste_frac_step_size_19_16_lsb 16 +#define xd_p_reg_fste_rpd_dir_cnt_max 0xA347 +#define reg_fste_rpd_dir_cnt_max_pos 4 +#define reg_fste_rpd_dir_cnt_max_len 4 +#define reg_fste_rpd_dir_cnt_max_lsb 0 +#define xd_p_reg_fste_ehs 0xA348 +#define reg_fste_ehs_pos 0 +#define reg_fste_ehs_len 4 +#define reg_fste_ehs_lsb 0 +#define xd_p_reg_fste_frac_cost_cnt_max_3_0 0xA348 +#define reg_fste_frac_cost_cnt_max_3_0_pos 4 +#define reg_fste_frac_cost_cnt_max_3_0_len 4 +#define reg_fste_frac_cost_cnt_max_3_0_lsb 0 +#define xd_p_reg_fste_frac_cost_cnt_max_9_4 0xA349 +#define reg_fste_frac_cost_cnt_max_9_4_pos 0 +#define reg_fste_frac_cost_cnt_max_9_4_len 6 +#define reg_fste_frac_cost_cnt_max_9_4_lsb 4 +#define xd_p_reg_fste_w0_7_0 0xA34A +#define reg_fste_w0_7_0_pos 0 +#define reg_fste_w0_7_0_len 8 +#define reg_fste_w0_7_0_lsb 0 +#define xd_p_reg_fste_w0_11_8 0xA34B +#define reg_fste_w0_11_8_pos 0 +#define reg_fste_w0_11_8_len 4 +#define reg_fste_w0_11_8_lsb 8 +#define xd_p_reg_fste_w1_3_0 0xA34B +#define reg_fste_w1_3_0_pos 4 +#define reg_fste_w1_3_0_len 4 +#define reg_fste_w1_3_0_lsb 0 +#define xd_p_reg_fste_w1_11_4 0xA34C +#define reg_fste_w1_11_4_pos 0 +#define reg_fste_w1_11_4_len 8 +#define reg_fste_w1_11_4_lsb 4 +#define xd_p_reg_fste_w2_7_0 0xA34D +#define reg_fste_w2_7_0_pos 0 +#define reg_fste_w2_7_0_len 8 +#define reg_fste_w2_7_0_lsb 0 +#define xd_p_reg_fste_w2_11_8 0xA34E +#define reg_fste_w2_11_8_pos 0 +#define reg_fste_w2_11_8_len 4 +#define reg_fste_w2_11_8_lsb 8 +#define xd_p_reg_fste_w3_3_0 0xA34E +#define reg_fste_w3_3_0_pos 4 +#define reg_fste_w3_3_0_len 4 +#define reg_fste_w3_3_0_lsb 0 +#define xd_p_reg_fste_w3_11_4 0xA34F +#define reg_fste_w3_11_4_pos 0 +#define reg_fste_w3_11_4_len 8 +#define reg_fste_w3_11_4_lsb 4 +#define xd_p_reg_fste_w4_7_0 0xA350 +#define reg_fste_w4_7_0_pos 0 +#define reg_fste_w4_7_0_len 8 +#define reg_fste_w4_7_0_lsb 0 +#define xd_p_reg_fste_w4_11_8 0xA351 +#define reg_fste_w4_11_8_pos 0 +#define reg_fste_w4_11_8_len 4 +#define reg_fste_w4_11_8_lsb 8 +#define xd_p_reg_fste_w5_3_0 0xA351 +#define reg_fste_w5_3_0_pos 4 +#define reg_fste_w5_3_0_len 4 +#define reg_fste_w5_3_0_lsb 0 +#define xd_p_reg_fste_w5_11_4 0xA352 +#define reg_fste_w5_11_4_pos 0 +#define reg_fste_w5_11_4_len 8 +#define reg_fste_w5_11_4_lsb 4 +#define xd_p_reg_fste_w6_7_0 0xA353 +#define reg_fste_w6_7_0_pos 0 +#define reg_fste_w6_7_0_len 8 +#define reg_fste_w6_7_0_lsb 0 +#define xd_p_reg_fste_w6_11_8 0xA354 +#define reg_fste_w6_11_8_pos 0 +#define reg_fste_w6_11_8_len 4 +#define reg_fste_w6_11_8_lsb 8 +#define xd_p_reg_fste_w7_3_0 0xA354 +#define reg_fste_w7_3_0_pos 4 +#define reg_fste_w7_3_0_len 4 +#define reg_fste_w7_3_0_lsb 0 +#define xd_p_reg_fste_w7_11_4 0xA355 +#define reg_fste_w7_11_4_pos 0 +#define reg_fste_w7_11_4_len 8 +#define reg_fste_w7_11_4_lsb 4 +#define xd_p_reg_fste_w8_7_0 0xA356 +#define reg_fste_w8_7_0_pos 0 +#define reg_fste_w8_7_0_len 8 +#define reg_fste_w8_7_0_lsb 0 +#define xd_p_reg_fste_w8_11_8 0xA357 +#define reg_fste_w8_11_8_pos 0 +#define reg_fste_w8_11_8_len 4 +#define reg_fste_w8_11_8_lsb 8 +#define xd_p_reg_fste_w9_3_0 0xA357 +#define reg_fste_w9_3_0_pos 4 +#define reg_fste_w9_3_0_len 4 +#define reg_fste_w9_3_0_lsb 0 +#define xd_p_reg_fste_w9_11_4 0xA358 +#define reg_fste_w9_11_4_pos 0 +#define reg_fste_w9_11_4_len 8 +#define reg_fste_w9_11_4_lsb 4 +#define xd_p_reg_fste_wa_7_0 0xA359 +#define reg_fste_wa_7_0_pos 0 +#define reg_fste_wa_7_0_len 8 +#define reg_fste_wa_7_0_lsb 0 +#define xd_p_reg_fste_wa_11_8 0xA35A +#define reg_fste_wa_11_8_pos 0 +#define reg_fste_wa_11_8_len 4 +#define reg_fste_wa_11_8_lsb 8 +#define xd_p_reg_fste_wb_3_0 0xA35A +#define reg_fste_wb_3_0_pos 4 +#define reg_fste_wb_3_0_len 4 +#define reg_fste_wb_3_0_lsb 0 +#define xd_p_reg_fste_wb_11_4 0xA35B +#define reg_fste_wb_11_4_pos 0 +#define reg_fste_wb_11_4_len 8 +#define reg_fste_wb_11_4_lsb 4 +#define xd_r_fd_fste_i_adj 0xA35C +#define fd_fste_i_adj_pos 0 +#define fd_fste_i_adj_len 5 +#define fd_fste_i_adj_lsb 0 +#define xd_r_fd_fste_f_adj_7_0 0xA35D +#define fd_fste_f_adj_7_0_pos 0 +#define fd_fste_f_adj_7_0_len 8 +#define fd_fste_f_adj_7_0_lsb 0 +#define xd_r_fd_fste_f_adj_15_8 0xA35E +#define fd_fste_f_adj_15_8_pos 0 +#define fd_fste_f_adj_15_8_len 8 +#define fd_fste_f_adj_15_8_lsb 8 +#define xd_r_fd_fste_f_adj_19_16 0xA35F +#define fd_fste_f_adj_19_16_pos 0 +#define fd_fste_f_adj_19_16_len 4 +#define fd_fste_f_adj_19_16_lsb 16 +#define xd_p_reg_feq_Leak_Bypass 0xA366 +#define reg_feq_Leak_Bypass_pos 0 +#define reg_feq_Leak_Bypass_len 1 +#define reg_feq_Leak_Bypass_lsb 0 +#define xd_p_reg_feq_Leak_Mneg1 0xA366 +#define reg_feq_Leak_Mneg1_pos 1 +#define reg_feq_Leak_Mneg1_len 3 +#define reg_feq_Leak_Mneg1_lsb 0 +#define xd_p_reg_feq_Leak_B_ShiftQ 0xA366 +#define reg_feq_Leak_B_ShiftQ_pos 4 +#define reg_feq_Leak_B_ShiftQ_len 4 +#define reg_feq_Leak_B_ShiftQ_lsb 0 +#define xd_p_reg_feq_Leak_B_Float0 0xA367 +#define reg_feq_Leak_B_Float0_pos 0 +#define reg_feq_Leak_B_Float0_len 8 +#define reg_feq_Leak_B_Float0_lsb 0 +#define xd_p_reg_feq_Leak_B_Float1 0xA368 +#define reg_feq_Leak_B_Float1_pos 0 +#define reg_feq_Leak_B_Float1_len 8 +#define reg_feq_Leak_B_Float1_lsb 0 +#define xd_p_reg_feq_Leak_B_Float2 0xA369 +#define reg_feq_Leak_B_Float2_pos 0 +#define reg_feq_Leak_B_Float2_len 8 +#define reg_feq_Leak_B_Float2_lsb 0 +#define xd_p_reg_feq_Leak_B_Float3 0xA36A +#define reg_feq_Leak_B_Float3_pos 0 +#define reg_feq_Leak_B_Float3_len 8 +#define reg_feq_Leak_B_Float3_lsb 0 +#define xd_p_reg_feq_Leak_B_Float4 0xA36B +#define reg_feq_Leak_B_Float4_pos 0 +#define reg_feq_Leak_B_Float4_len 8 +#define reg_feq_Leak_B_Float4_lsb 0 +#define xd_p_reg_feq_Leak_B_Float5 0xA36C +#define reg_feq_Leak_B_Float5_pos 0 +#define reg_feq_Leak_B_Float5_len 8 +#define reg_feq_Leak_B_Float5_lsb 0 +#define xd_p_reg_feq_Leak_B_Float6 0xA36D +#define reg_feq_Leak_B_Float6_pos 0 +#define reg_feq_Leak_B_Float6_len 8 +#define reg_feq_Leak_B_Float6_lsb 0 +#define xd_p_reg_feq_Leak_B_Float7 0xA36E +#define reg_feq_Leak_B_Float7_pos 0 +#define reg_feq_Leak_B_Float7_len 8 +#define reg_feq_Leak_B_Float7_lsb 0 +#define xd_r_reg_feq_data_h2_7_0 0xA36F +#define reg_feq_data_h2_7_0_pos 0 +#define reg_feq_data_h2_7_0_len 8 +#define reg_feq_data_h2_7_0_lsb 0 +#define xd_r_reg_feq_data_h2_9_8 0xA370 +#define reg_feq_data_h2_9_8_pos 0 +#define reg_feq_data_h2_9_8_len 2 +#define reg_feq_data_h2_9_8_lsb 8 +#define xd_p_reg_feq_leak_use_slice_tps 0xA371 +#define reg_feq_leak_use_slice_tps_pos 0 +#define reg_feq_leak_use_slice_tps_len 1 +#define reg_feq_leak_use_slice_tps_lsb 0 +#define xd_p_reg_feq_read_update 0xA371 +#define reg_feq_read_update_pos 1 +#define reg_feq_read_update_len 1 +#define reg_feq_read_update_lsb 0 +#define xd_p_reg_feq_data_vld 0xA371 +#define reg_feq_data_vld_pos 2 +#define reg_feq_data_vld_len 1 +#define reg_feq_data_vld_lsb 0 +#define xd_p_reg_feq_tone_idx_4_0 0xA371 +#define reg_feq_tone_idx_4_0_pos 3 +#define reg_feq_tone_idx_4_0_len 5 +#define reg_feq_tone_idx_4_0_lsb 0 +#define xd_p_reg_feq_tone_idx_12_5 0xA372 +#define reg_feq_tone_idx_12_5_pos 0 +#define reg_feq_tone_idx_12_5_len 8 +#define reg_feq_tone_idx_12_5_lsb 5 +#define xd_r_reg_feq_data_re_7_0 0xA373 +#define reg_feq_data_re_7_0_pos 0 +#define reg_feq_data_re_7_0_len 8 +#define reg_feq_data_re_7_0_lsb 0 +#define xd_r_reg_feq_data_re_10_8 0xA374 +#define reg_feq_data_re_10_8_pos 0 +#define reg_feq_data_re_10_8_len 3 +#define reg_feq_data_re_10_8_lsb 8 +#define xd_r_reg_feq_data_im_7_0 0xA375 +#define reg_feq_data_im_7_0_pos 0 +#define reg_feq_data_im_7_0_len 8 +#define reg_feq_data_im_7_0_lsb 0 +#define xd_r_reg_feq_data_im_10_8 0xA376 +#define reg_feq_data_im_10_8_pos 0 +#define reg_feq_data_im_10_8_len 3 +#define reg_feq_data_im_10_8_lsb 8 +#define xd_r_reg_feq_y_re 0xA377 +#define reg_feq_y_re_pos 0 +#define reg_feq_y_re_len 8 +#define reg_feq_y_re_lsb 0 +#define xd_r_reg_feq_y_im 0xA378 +#define reg_feq_y_im_pos 0 +#define reg_feq_y_im_len 8 +#define reg_feq_y_im_lsb 0 +#define xd_r_reg_feq_h_re_7_0 0xA379 +#define reg_feq_h_re_7_0_pos 0 +#define reg_feq_h_re_7_0_len 8 +#define reg_feq_h_re_7_0_lsb 0 +#define xd_r_reg_feq_h_re_8 0xA37A +#define reg_feq_h_re_8_pos 0 +#define reg_feq_h_re_8_len 1 +#define reg_feq_h_re_8_lsb 0 +#define xd_r_reg_feq_h_im_7_0 0xA37B +#define reg_feq_h_im_7_0_pos 0 +#define reg_feq_h_im_7_0_len 8 +#define reg_feq_h_im_7_0_lsb 0 +#define xd_r_reg_feq_h_im_8 0xA37C +#define reg_feq_h_im_8_pos 0 +#define reg_feq_h_im_8_len 1 +#define reg_feq_h_im_8_lsb 0 +#define xd_p_fec_super_frm_unit_7_0 0xA380 +#define fec_super_frm_unit_7_0_pos 0 +#define fec_super_frm_unit_7_0_len 8 +#define fec_super_frm_unit_7_0_lsb 0 +#define xd_p_fec_super_frm_unit_15_8 0xA381 +#define fec_super_frm_unit_15_8_pos 0 +#define fec_super_frm_unit_15_8_len 8 +#define fec_super_frm_unit_15_8_lsb 8 +#define xd_r_fec_vtb_err_bit_cnt_7_0 0xA382 +#define fec_vtb_err_bit_cnt_7_0_pos 0 +#define fec_vtb_err_bit_cnt_7_0_len 8 +#define fec_vtb_err_bit_cnt_7_0_lsb 0 +#define xd_r_fec_vtb_err_bit_cnt_15_8 0xA383 +#define fec_vtb_err_bit_cnt_15_8_pos 0 +#define fec_vtb_err_bit_cnt_15_8_len 8 +#define fec_vtb_err_bit_cnt_15_8_lsb 8 +#define xd_r_fec_vtb_err_bit_cnt_23_16 0xA384 +#define fec_vtb_err_bit_cnt_23_16_pos 0 +#define fec_vtb_err_bit_cnt_23_16_len 8 +#define fec_vtb_err_bit_cnt_23_16_lsb 16 +#define xd_p_fec_rsd_packet_unit_7_0 0xA385 +#define fec_rsd_packet_unit_7_0_pos 0 +#define fec_rsd_packet_unit_7_0_len 8 +#define fec_rsd_packet_unit_7_0_lsb 0 +#define xd_p_fec_rsd_packet_unit_15_8 0xA386 +#define fec_rsd_packet_unit_15_8_pos 0 +#define fec_rsd_packet_unit_15_8_len 8 +#define fec_rsd_packet_unit_15_8_lsb 8 +#define xd_r_fec_rsd_bit_err_cnt_7_0 0xA387 +#define fec_rsd_bit_err_cnt_7_0_pos 0 +#define fec_rsd_bit_err_cnt_7_0_len 8 +#define fec_rsd_bit_err_cnt_7_0_lsb 0 +#define xd_r_fec_rsd_bit_err_cnt_15_8 0xA388 +#define fec_rsd_bit_err_cnt_15_8_pos 0 +#define fec_rsd_bit_err_cnt_15_8_len 8 +#define fec_rsd_bit_err_cnt_15_8_lsb 8 +#define xd_r_fec_rsd_bit_err_cnt_23_16 0xA389 +#define fec_rsd_bit_err_cnt_23_16_pos 0 +#define fec_rsd_bit_err_cnt_23_16_len 8 +#define fec_rsd_bit_err_cnt_23_16_lsb 16 +#define xd_r_fec_rsd_abort_packet_cnt_7_0 0xA38A +#define fec_rsd_abort_packet_cnt_7_0_pos 0 +#define fec_rsd_abort_packet_cnt_7_0_len 8 +#define fec_rsd_abort_packet_cnt_7_0_lsb 0 +#define xd_r_fec_rsd_abort_packet_cnt_15_8 0xA38B +#define fec_rsd_abort_packet_cnt_15_8_pos 0 +#define fec_rsd_abort_packet_cnt_15_8_len 8 +#define fec_rsd_abort_packet_cnt_15_8_lsb 8 +#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_7_0 0xA38C +#define fec_RSD_PKT_NUM_PER_UNIT_7_0_pos 0 +#define fec_RSD_PKT_NUM_PER_UNIT_7_0_len 8 +#define fec_RSD_PKT_NUM_PER_UNIT_7_0_lsb 0 +#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_15_8 0xA38D +#define fec_RSD_PKT_NUM_PER_UNIT_15_8_pos 0 +#define fec_RSD_PKT_NUM_PER_UNIT_15_8_len 8 +#define fec_RSD_PKT_NUM_PER_UNIT_15_8_lsb 8 +#define xd_p_fec_RS_TH_1_7_0 0xA38E +#define fec_RS_TH_1_7_0_pos 0 +#define fec_RS_TH_1_7_0_len 8 +#define fec_RS_TH_1_7_0_lsb 0 +#define xd_p_fec_RS_TH_1_15_8 0xA38F +#define fec_RS_TH_1_15_8_pos 0 +#define fec_RS_TH_1_15_8_len 8 +#define fec_RS_TH_1_15_8_lsb 8 +#define xd_p_fec_RS_TH_2 0xA390 +#define fec_RS_TH_2_pos 0 +#define fec_RS_TH_2_len 8 +#define fec_RS_TH_2_lsb 0 +#define xd_p_fec_mon_en 0xA391 +#define fec_mon_en_pos 0 +#define fec_mon_en_len 1 +#define fec_mon_en_lsb 0 +#define xd_p_reg_b8to47 0xA391 +#define reg_b8to47_pos 1 +#define reg_b8to47_len 1 +#define reg_b8to47_lsb 0 +#define xd_p_reg_rsd_sync_rep 0xA391 +#define reg_rsd_sync_rep_pos 2 +#define reg_rsd_sync_rep_len 1 +#define reg_rsd_sync_rep_lsb 0 +#define xd_p_fec_rsd_retrain_rst 0xA391 +#define fec_rsd_retrain_rst_pos 3 +#define fec_rsd_retrain_rst_len 1 +#define fec_rsd_retrain_rst_lsb 0 +#define xd_r_fec_rsd_ber_rdy 0xA391 +#define fec_rsd_ber_rdy_pos 4 +#define fec_rsd_ber_rdy_len 1 +#define fec_rsd_ber_rdy_lsb 0 +#define xd_p_fec_rsd_ber_rst 0xA391 +#define fec_rsd_ber_rst_pos 5 +#define fec_rsd_ber_rst_len 1 +#define fec_rsd_ber_rst_lsb 0 +#define xd_r_fec_vtb_ber_rdy 0xA391 +#define fec_vtb_ber_rdy_pos 6 +#define fec_vtb_ber_rdy_len 1 +#define fec_vtb_ber_rdy_lsb 0 +#define xd_p_fec_vtb_ber_rst 0xA391 +#define fec_vtb_ber_rst_pos 7 +#define fec_vtb_ber_rst_len 1 +#define fec_vtb_ber_rst_lsb 0 +#define xd_p_reg_vtb_clk40en 0xA392 +#define reg_vtb_clk40en_pos 0 +#define reg_vtb_clk40en_len 1 +#define reg_vtb_clk40en_lsb 0 +#define xd_p_fec_vtb_rsd_mon_en 0xA392 +#define fec_vtb_rsd_mon_en_pos 1 +#define fec_vtb_rsd_mon_en_len 1 +#define fec_vtb_rsd_mon_en_lsb 0 +#define xd_p_reg_fec_data_en 0xA392 +#define reg_fec_data_en_pos 2 +#define reg_fec_data_en_len 1 +#define reg_fec_data_en_lsb 0 +#define xd_p_fec_dummy_reg_2 0xA392 +#define fec_dummy_reg_2_pos 3 +#define fec_dummy_reg_2_len 3 +#define fec_dummy_reg_2_lsb 0 +#define xd_p_reg_sync_chk 0xA392 +#define reg_sync_chk_pos 6 +#define reg_sync_chk_len 1 +#define reg_sync_chk_lsb 0 +#define xd_p_fec_rsd_bypass 0xA392 +#define fec_rsd_bypass_pos 7 +#define fec_rsd_bypass_len 1 +#define fec_rsd_bypass_lsb 0 +#define xd_p_fec_sw_rst 0xA393 +#define fec_sw_rst_pos 0 +#define fec_sw_rst_len 1 +#define fec_sw_rst_lsb 0 +#define xd_r_fec_vtb_pm_crc 0xA394 +#define fec_vtb_pm_crc_pos 0 +#define fec_vtb_pm_crc_len 8 +#define fec_vtb_pm_crc_lsb 0 +#define xd_r_fec_vtb_tb_7_crc 0xA395 +#define fec_vtb_tb_7_crc_pos 0 +#define fec_vtb_tb_7_crc_len 8 +#define fec_vtb_tb_7_crc_lsb 0 +#define xd_r_fec_vtb_tb_6_crc 0xA396 +#define fec_vtb_tb_6_crc_pos 0 +#define fec_vtb_tb_6_crc_len 8 +#define fec_vtb_tb_6_crc_lsb 0 +#define xd_r_fec_vtb_tb_5_crc 0xA397 +#define fec_vtb_tb_5_crc_pos 0 +#define fec_vtb_tb_5_crc_len 8 +#define fec_vtb_tb_5_crc_lsb 0 +#define xd_r_fec_vtb_tb_4_crc 0xA398 +#define fec_vtb_tb_4_crc_pos 0 +#define fec_vtb_tb_4_crc_len 8 +#define fec_vtb_tb_4_crc_lsb 0 +#define xd_r_fec_vtb_tb_3_crc 0xA399 +#define fec_vtb_tb_3_crc_pos 0 +#define fec_vtb_tb_3_crc_len 8 +#define fec_vtb_tb_3_crc_lsb 0 +#define xd_r_fec_vtb_tb_2_crc 0xA39A +#define fec_vtb_tb_2_crc_pos 0 +#define fec_vtb_tb_2_crc_len 8 +#define fec_vtb_tb_2_crc_lsb 0 +#define xd_r_fec_vtb_tb_1_crc 0xA39B +#define fec_vtb_tb_1_crc_pos 0 +#define fec_vtb_tb_1_crc_len 8 +#define fec_vtb_tb_1_crc_lsb 0 +#define xd_r_fec_vtb_tb_0_crc 0xA39C +#define fec_vtb_tb_0_crc_pos 0 +#define fec_vtb_tb_0_crc_len 8 +#define fec_vtb_tb_0_crc_lsb 0 +#define xd_r_fec_rsd_bank0_crc 0xA39D +#define fec_rsd_bank0_crc_pos 0 +#define fec_rsd_bank0_crc_len 8 +#define fec_rsd_bank0_crc_lsb 0 +#define xd_r_fec_rsd_bank1_crc 0xA39E +#define fec_rsd_bank1_crc_pos 0 +#define fec_rsd_bank1_crc_len 8 +#define fec_rsd_bank1_crc_lsb 0 +#define xd_r_fec_idi_vtb_crc 0xA39F +#define fec_idi_vtb_crc_pos 0 +#define fec_idi_vtb_crc_len 8 +#define fec_idi_vtb_crc_lsb 0 +#define xd_g_reg_tpsd_txmod 0xA3C0 +#define reg_tpsd_txmod_pos 0 +#define reg_tpsd_txmod_len 2 +#define reg_tpsd_txmod_lsb 0 +#define xd_g_reg_tpsd_gi 0xA3C0 +#define reg_tpsd_gi_pos 2 +#define reg_tpsd_gi_len 2 +#define reg_tpsd_gi_lsb 0 +#define xd_g_reg_tpsd_hier 0xA3C0 +#define reg_tpsd_hier_pos 4 +#define reg_tpsd_hier_len 3 +#define reg_tpsd_hier_lsb 0 +#define xd_g_reg_bw 0xA3C1 +#define reg_bw_pos 2 +#define reg_bw_len 2 +#define reg_bw_lsb 0 +#define xd_g_reg_dec_pri 0xA3C1 +#define reg_dec_pri_pos 4 +#define reg_dec_pri_len 1 +#define reg_dec_pri_lsb 0 +#define xd_g_reg_tpsd_const 0xA3C1 +#define reg_tpsd_const_pos 6 +#define reg_tpsd_const_len 2 +#define reg_tpsd_const_lsb 0 +#define xd_g_reg_tpsd_hpcr 0xA3C2 +#define reg_tpsd_hpcr_pos 0 +#define reg_tpsd_hpcr_len 3 +#define reg_tpsd_hpcr_lsb 0 +#define xd_g_reg_tpsd_lpcr 0xA3C2 +#define reg_tpsd_lpcr_pos 3 +#define reg_tpsd_lpcr_len 3 +#define reg_tpsd_lpcr_lsb 0 +#define xd_g_reg_ofsm_clk 0xA3D0 +#define reg_ofsm_clk_pos 0 +#define reg_ofsm_clk_len 3 +#define reg_ofsm_clk_lsb 0 +#define xd_g_reg_fclk_cfg 0xA3D1 +#define reg_fclk_cfg_pos 0 +#define reg_fclk_cfg_len 1 +#define reg_fclk_cfg_lsb 0 +#define xd_g_reg_fclk_idi 0xA3D1 +#define reg_fclk_idi_pos 1 +#define reg_fclk_idi_len 1 +#define reg_fclk_idi_lsb 0 +#define xd_g_reg_fclk_odi 0xA3D1 +#define reg_fclk_odi_pos 2 +#define reg_fclk_odi_len 1 +#define reg_fclk_odi_lsb 0 +#define xd_g_reg_fclk_rsd 0xA3D1 +#define reg_fclk_rsd_pos 3 +#define reg_fclk_rsd_len 1 +#define reg_fclk_rsd_lsb 0 +#define xd_g_reg_fclk_vtb 0xA3D1 +#define reg_fclk_vtb_pos 4 +#define reg_fclk_vtb_len 1 +#define reg_fclk_vtb_lsb 0 +#define xd_g_reg_fclk_cste 0xA3D1 +#define reg_fclk_cste_pos 5 +#define reg_fclk_cste_len 1 +#define reg_fclk_cste_lsb 0 +#define xd_g_reg_fclk_mp2if 0xA3D1 +#define reg_fclk_mp2if_pos 6 +#define reg_fclk_mp2if_len 1 +#define reg_fclk_mp2if_lsb 0 +#define xd_I2C_i2c_m_slave_addr 0xA400 +#define i2c_m_slave_addr_pos 0 +#define i2c_m_slave_addr_len 8 +#define i2c_m_slave_addr_lsb 0 +#define xd_I2C_i2c_m_data1 0xA401 +#define i2c_m_data1_pos 0 +#define i2c_m_data1_len 8 +#define i2c_m_data1_lsb 0 +#define xd_I2C_i2c_m_data2 0xA402 +#define i2c_m_data2_pos 0 +#define i2c_m_data2_len 8 +#define i2c_m_data2_lsb 0 +#define xd_I2C_i2c_m_data3 0xA403 +#define i2c_m_data3_pos 0 +#define i2c_m_data3_len 8 +#define i2c_m_data3_lsb 0 +#define xd_I2C_i2c_m_data4 0xA404 +#define i2c_m_data4_pos 0 +#define i2c_m_data4_len 8 +#define i2c_m_data4_lsb 0 +#define xd_I2C_i2c_m_data5 0xA405 +#define i2c_m_data5_pos 0 +#define i2c_m_data5_len 8 +#define i2c_m_data5_lsb 0 +#define xd_I2C_i2c_m_data6 0xA406 +#define i2c_m_data6_pos 0 +#define i2c_m_data6_len 8 +#define i2c_m_data6_lsb 0 +#define xd_I2C_i2c_m_data7 0xA407 +#define i2c_m_data7_pos 0 +#define i2c_m_data7_len 8 +#define i2c_m_data7_lsb 0 +#define xd_I2C_i2c_m_data8 0xA408 +#define i2c_m_data8_pos 0 +#define i2c_m_data8_len 8 +#define i2c_m_data8_lsb 0 +#define xd_I2C_i2c_m_data9 0xA409 +#define i2c_m_data9_pos 0 +#define i2c_m_data9_len 8 +#define i2c_m_data9_lsb 0 +#define xd_I2C_i2c_m_data10 0xA40A +#define i2c_m_data10_pos 0 +#define i2c_m_data10_len 8 +#define i2c_m_data10_lsb 0 +#define xd_I2C_i2c_m_data11 0xA40B +#define i2c_m_data11_pos 0 +#define i2c_m_data11_len 8 +#define i2c_m_data11_lsb 0 +#define xd_I2C_i2c_m_cmd_rw 0xA40C +#define i2c_m_cmd_rw_pos 0 +#define i2c_m_cmd_rw_len 1 +#define i2c_m_cmd_rw_lsb 0 +#define xd_I2C_i2c_m_cmd_rwlen 0xA40C +#define i2c_m_cmd_rwlen_pos 3 +#define i2c_m_cmd_rwlen_len 4 +#define i2c_m_cmd_rwlen_lsb 0 +#define xd_I2C_i2c_m_status_cmd_exe 0xA40D +#define i2c_m_status_cmd_exe_pos 0 +#define i2c_m_status_cmd_exe_len 1 +#define i2c_m_status_cmd_exe_lsb 0 +#define xd_I2C_i2c_m_status_wdat_done 0xA40D +#define i2c_m_status_wdat_done_pos 1 +#define i2c_m_status_wdat_done_len 1 +#define i2c_m_status_wdat_done_lsb 0 +#define xd_I2C_i2c_m_status_wdat_fail 0xA40D +#define i2c_m_status_wdat_fail_pos 2 +#define i2c_m_status_wdat_fail_len 1 +#define i2c_m_status_wdat_fail_lsb 0 +#define xd_I2C_i2c_m_period 0xA40E +#define i2c_m_period_pos 0 +#define i2c_m_period_len 8 +#define i2c_m_period_lsb 0 +#define xd_I2C_i2c_m_reg_msb_lsb 0xA40F +#define i2c_m_reg_msb_lsb_pos 0 +#define i2c_m_reg_msb_lsb_len 1 +#define i2c_m_reg_msb_lsb_lsb 0 +#define xd_I2C_reg_ofdm_rst 0xA40F +#define reg_ofdm_rst_pos 1 +#define reg_ofdm_rst_len 1 +#define reg_ofdm_rst_lsb 0 +#define xd_I2C_reg_sample_period_on_tuner 0xA40F +#define reg_sample_period_on_tuner_pos 2 +#define reg_sample_period_on_tuner_len 1 +#define reg_sample_period_on_tuner_lsb 0 +#define xd_I2C_reg_rst_i2c 0xA40F +#define reg_rst_i2c_pos 3 +#define reg_rst_i2c_len 1 +#define reg_rst_i2c_lsb 0 +#define xd_I2C_reg_ofdm_rst_en 0xA40F +#define reg_ofdm_rst_en_pos 4 +#define reg_ofdm_rst_en_len 1 +#define reg_ofdm_rst_en_lsb 0 +#define xd_I2C_reg_tuner_sda_sync_on 0xA40F +#define reg_tuner_sda_sync_on_pos 5 +#define reg_tuner_sda_sync_on_len 1 +#define reg_tuner_sda_sync_on_lsb 0 +#define xd_p_mp2if_data_access_disable_ofsm 0xA500 +#define mp2if_data_access_disable_ofsm_pos 0 +#define mp2if_data_access_disable_ofsm_len 1 +#define mp2if_data_access_disable_ofsm_lsb 0 +#define xd_p_reg_mp2_sw_rst_ofsm 0xA500 +#define reg_mp2_sw_rst_ofsm_pos 1 +#define reg_mp2_sw_rst_ofsm_len 1 +#define reg_mp2_sw_rst_ofsm_lsb 0 +#define xd_p_reg_mp2if_clk_en_ofsm 0xA500 +#define reg_mp2if_clk_en_ofsm_pos 2 +#define reg_mp2if_clk_en_ofsm_len 1 +#define reg_mp2if_clk_en_ofsm_lsb 0 +#define xd_r_mp2if_sync_byte_locked 0xA500 +#define mp2if_sync_byte_locked_pos 3 +#define mp2if_sync_byte_locked_len 1 +#define mp2if_sync_byte_locked_lsb 0 +#define xd_r_mp2if_ts_not_188 0xA500 +#define mp2if_ts_not_188_pos 4 +#define mp2if_ts_not_188_len 1 +#define mp2if_ts_not_188_lsb 0 +#define xd_r_mp2if_psb_empty 0xA500 +#define mp2if_psb_empty_pos 5 +#define mp2if_psb_empty_len 1 +#define mp2if_psb_empty_lsb 0 +#define xd_r_mp2if_psb_overflow 0xA500 +#define mp2if_psb_overflow_pos 6 +#define mp2if_psb_overflow_len 1 +#define mp2if_psb_overflow_lsb 0 +#define xd_p_mp2if_keep_sf_sync_byte_ofsm 0xA500 +#define mp2if_keep_sf_sync_byte_ofsm_pos 7 +#define mp2if_keep_sf_sync_byte_ofsm_len 1 +#define mp2if_keep_sf_sync_byte_ofsm_lsb 0 +#define xd_r_mp2if_psb_mp2if_num_pkt 0xA501 +#define mp2if_psb_mp2if_num_pkt_pos 0 +#define mp2if_psb_mp2if_num_pkt_len 6 +#define mp2if_psb_mp2if_num_pkt_lsb 0 +#define xd_p_reg_mpeg_full_speed_ofsm 0xA501 +#define reg_mpeg_full_speed_ofsm_pos 6 +#define reg_mpeg_full_speed_ofsm_len 1 +#define reg_mpeg_full_speed_ofsm_lsb 0 +#define xd_p_mp2if_mpeg_ser_mode_ofsm 0xA501 +#define mp2if_mpeg_ser_mode_ofsm_pos 7 +#define mp2if_mpeg_ser_mode_ofsm_len 1 +#define mp2if_mpeg_ser_mode_ofsm_lsb 0 +#define xd_p_reg_sw_mon51 0xA600 +#define reg_sw_mon51_pos 0 +#define reg_sw_mon51_len 8 +#define reg_sw_mon51_lsb 0 +#define xd_p_reg_top_pcsel 0xA601 +#define reg_top_pcsel_pos 0 +#define reg_top_pcsel_len 1 +#define reg_top_pcsel_lsb 0 +#define xd_p_reg_top_rs232 0xA601 +#define reg_top_rs232_pos 1 +#define reg_top_rs232_len 1 +#define reg_top_rs232_lsb 0 +#define xd_p_reg_top_pcout 0xA601 +#define reg_top_pcout_pos 2 +#define reg_top_pcout_len 1 +#define reg_top_pcout_lsb 0 +#define xd_p_reg_top_debug 0xA601 +#define reg_top_debug_pos 3 +#define reg_top_debug_len 1 +#define reg_top_debug_lsb 0 +#define xd_p_reg_top_adcdly 0xA601 +#define reg_top_adcdly_pos 4 +#define reg_top_adcdly_len 2 +#define reg_top_adcdly_lsb 0 +#define xd_p_reg_top_pwrdw 0xA601 +#define reg_top_pwrdw_pos 6 +#define reg_top_pwrdw_len 1 +#define reg_top_pwrdw_lsb 0 +#define xd_p_reg_top_pwrdw_inv 0xA601 +#define reg_top_pwrdw_inv_pos 7 +#define reg_top_pwrdw_inv_len 1 +#define reg_top_pwrdw_inv_lsb 0 +#define xd_p_reg_top_int_inv 0xA602 +#define reg_top_int_inv_pos 0 +#define reg_top_int_inv_len 1 +#define reg_top_int_inv_lsb 0 +#define xd_p_reg_top_dio_sel 0xA602 +#define reg_top_dio_sel_pos 1 +#define reg_top_dio_sel_len 1 +#define reg_top_dio_sel_lsb 0 +#define xd_p_reg_top_gpioon0 0xA603 +#define reg_top_gpioon0_pos 0 +#define reg_top_gpioon0_len 1 +#define reg_top_gpioon0_lsb 0 +#define xd_p_reg_top_gpioon1 0xA603 +#define reg_top_gpioon1_pos 1 +#define reg_top_gpioon1_len 1 +#define reg_top_gpioon1_lsb 0 +#define xd_p_reg_top_gpioon2 0xA603 +#define reg_top_gpioon2_pos 2 +#define reg_top_gpioon2_len 1 +#define reg_top_gpioon2_lsb 0 +#define xd_p_reg_top_gpioon3 0xA603 +#define reg_top_gpioon3_pos 3 +#define reg_top_gpioon3_len 1 +#define reg_top_gpioon3_lsb 0 +#define xd_p_reg_top_lockon1 0xA603 +#define reg_top_lockon1_pos 4 +#define reg_top_lockon1_len 1 +#define reg_top_lockon1_lsb 0 +#define xd_p_reg_top_lockon2 0xA603 +#define reg_top_lockon2_pos 5 +#define reg_top_lockon2_len 1 +#define reg_top_lockon2_lsb 0 +#define xd_p_reg_top_gpioo0 0xA604 +#define reg_top_gpioo0_pos 0 +#define reg_top_gpioo0_len 1 +#define reg_top_gpioo0_lsb 0 +#define xd_p_reg_top_gpioo1 0xA604 +#define reg_top_gpioo1_pos 1 +#define reg_top_gpioo1_len 1 +#define reg_top_gpioo1_lsb 0 +#define xd_p_reg_top_gpioo2 0xA604 +#define reg_top_gpioo2_pos 2 +#define reg_top_gpioo2_len 1 +#define reg_top_gpioo2_lsb 0 +#define xd_p_reg_top_gpioo3 0xA604 +#define reg_top_gpioo3_pos 3 +#define reg_top_gpioo3_len 1 +#define reg_top_gpioo3_lsb 0 +#define xd_p_reg_top_lock1 0xA604 +#define reg_top_lock1_pos 4 +#define reg_top_lock1_len 1 +#define reg_top_lock1_lsb 0 +#define xd_p_reg_top_lock2 0xA604 +#define reg_top_lock2_pos 5 +#define reg_top_lock2_len 1 +#define reg_top_lock2_lsb 0 +#define xd_p_reg_top_gpioen0 0xA605 +#define reg_top_gpioen0_pos 0 +#define reg_top_gpioen0_len 1 +#define reg_top_gpioen0_lsb 0 +#define xd_p_reg_top_gpioen1 0xA605 +#define reg_top_gpioen1_pos 1 +#define reg_top_gpioen1_len 1 +#define reg_top_gpioen1_lsb 0 +#define xd_p_reg_top_gpioen2 0xA605 +#define reg_top_gpioen2_pos 2 +#define reg_top_gpioen2_len 1 +#define reg_top_gpioen2_lsb 0 +#define xd_p_reg_top_gpioen3 0xA605 +#define reg_top_gpioen3_pos 3 +#define reg_top_gpioen3_len 1 +#define reg_top_gpioen3_lsb 0 +#define xd_p_reg_top_locken1 0xA605 +#define reg_top_locken1_pos 4 +#define reg_top_locken1_len 1 +#define reg_top_locken1_lsb 0 +#define xd_p_reg_top_locken2 0xA605 +#define reg_top_locken2_pos 5 +#define reg_top_locken2_len 1 +#define reg_top_locken2_lsb 0 +#define xd_r_reg_top_gpioi0 0xA606 +#define reg_top_gpioi0_pos 0 +#define reg_top_gpioi0_len 1 +#define reg_top_gpioi0_lsb 0 +#define xd_r_reg_top_gpioi1 0xA606 +#define reg_top_gpioi1_pos 1 +#define reg_top_gpioi1_len 1 +#define reg_top_gpioi1_lsb 0 +#define xd_r_reg_top_gpioi2 0xA606 +#define reg_top_gpioi2_pos 2 +#define reg_top_gpioi2_len 1 +#define reg_top_gpioi2_lsb 0 +#define xd_r_reg_top_gpioi3 0xA606 +#define reg_top_gpioi3_pos 3 +#define reg_top_gpioi3_len 1 +#define reg_top_gpioi3_lsb 0 +#define xd_r_reg_top_locki1 0xA606 +#define reg_top_locki1_pos 4 +#define reg_top_locki1_len 1 +#define reg_top_locki1_lsb 0 +#define xd_r_reg_top_locki2 0xA606 +#define reg_top_locki2_pos 5 +#define reg_top_locki2_len 1 +#define reg_top_locki2_lsb 0 +#define xd_p_reg_dummy_7_0 0xA608 +#define reg_dummy_7_0_pos 0 +#define reg_dummy_7_0_len 8 +#define reg_dummy_7_0_lsb 0 +#define xd_p_reg_dummy_15_8 0xA609 +#define reg_dummy_15_8_pos 0 +#define reg_dummy_15_8_len 8 +#define reg_dummy_15_8_lsb 8 +#define xd_p_reg_dummy_23_16 0xA60A +#define reg_dummy_23_16_pos 0 +#define reg_dummy_23_16_len 8 +#define reg_dummy_23_16_lsb 16 +#define xd_p_reg_dummy_31_24 0xA60B +#define reg_dummy_31_24_pos 0 +#define reg_dummy_31_24_len 8 +#define reg_dummy_31_24_lsb 24 +#define xd_p_reg_dummy_39_32 0xA60C +#define reg_dummy_39_32_pos 0 +#define reg_dummy_39_32_len 8 +#define reg_dummy_39_32_lsb 32 +#define xd_p_reg_dummy_47_40 0xA60D +#define reg_dummy_47_40_pos 0 +#define reg_dummy_47_40_len 8 +#define reg_dummy_47_40_lsb 40 +#define xd_p_reg_dummy_55_48 0xA60E +#define reg_dummy_55_48_pos 0 +#define reg_dummy_55_48_len 8 +#define reg_dummy_55_48_lsb 48 +#define xd_p_reg_dummy_63_56 0xA60F +#define reg_dummy_63_56_pos 0 +#define reg_dummy_63_56_len 8 +#define reg_dummy_63_56_lsb 56 +#define xd_p_reg_dummy_71_64 0xA610 +#define reg_dummy_71_64_pos 0 +#define reg_dummy_71_64_len 8 +#define reg_dummy_71_64_lsb 64 +#define xd_p_reg_dummy_79_72 0xA611 +#define reg_dummy_79_72_pos 0 +#define reg_dummy_79_72_len 8 +#define reg_dummy_79_72_lsb 72 +#define xd_p_reg_dummy_87_80 0xA612 +#define reg_dummy_87_80_pos 0 +#define reg_dummy_87_80_len 8 +#define reg_dummy_87_80_lsb 80 +#define xd_p_reg_dummy_95_88 0xA613 +#define reg_dummy_95_88_pos 0 +#define reg_dummy_95_88_len 8 +#define reg_dummy_95_88_lsb 88 +#define xd_p_reg_dummy_103_96 0xA614 +#define reg_dummy_103_96_pos 0 +#define reg_dummy_103_96_len 8 +#define reg_dummy_103_96_lsb 96 + +#define xd_p_reg_unplug_flag 0xA615 +#define reg_unplug_flag_pos 0 +#define reg_unplug_flag_len 1 +#define reg_unplug_flag_lsb 104 + +#define xd_p_reg_api_dca_stes_request 0xA615 +#define reg_api_dca_stes_request_pos 1 +#define reg_api_dca_stes_request_len 1 +#define reg_api_dca_stes_request_lsb 0 + +#define xd_p_reg_back_to_dca_flag 0xA615 +#define reg_back_to_dca_flag_pos 2 +#define reg_back_to_dca_flag_len 1 +#define reg_back_to_dca_flag_lsb 106 + +#define xd_p_reg_api_retrain_request 0xA615 +#define reg_api_retrain_request_pos 3 +#define reg_api_retrain_request_len 1 +#define reg_api_retrain_request_lsb 0 + +#define xd_p_reg_Dyn_Top_Try_flag 0xA615 +#define reg_Dyn_Top_Try_flag_pos 3 +#define reg_Dyn_Top_Try_flag_len 1 +#define reg_Dyn_Top_Try_flag_lsb 107 + +#define xd_p_reg_API_retrain_freeze_flag 0xA615 +#define reg_API_retrain_freeze_flag_pos 4 +#define reg_API_retrain_freeze_flag_len 1 +#define reg_API_retrain_freeze_flag_lsb 108 + +#define xd_p_reg_dummy_111_104 0xA615 +#define reg_dummy_111_104_pos 0 +#define reg_dummy_111_104_len 8 +#define reg_dummy_111_104_lsb 104 +#define xd_p_reg_dummy_119_112 0xA616 +#define reg_dummy_119_112_pos 0 +#define reg_dummy_119_112_len 8 +#define reg_dummy_119_112_lsb 112 +#define xd_p_reg_dummy_127_120 0xA617 +#define reg_dummy_127_120_pos 0 +#define reg_dummy_127_120_len 8 +#define reg_dummy_127_120_lsb 120 +#define xd_p_reg_dummy_135_128 0xA618 +#define reg_dummy_135_128_pos 0 +#define reg_dummy_135_128_len 8 +#define reg_dummy_135_128_lsb 128 + +#define xd_p_reg_dummy_143_136 0xA619 +#define reg_dummy_143_136_pos 0 +#define reg_dummy_143_136_len 8 +#define reg_dummy_143_136_lsb 136 + +#define xd_p_reg_CCIR_dis 0xA619 +#define reg_CCIR_dis_pos 0 +#define reg_CCIR_dis_len 1 +#define reg_CCIR_dis_lsb 0 + +#define xd_p_reg_dummy_151_144 0xA61A +#define reg_dummy_151_144_pos 0 +#define reg_dummy_151_144_len 8 +#define reg_dummy_151_144_lsb 144 + +#define xd_p_reg_dummy_159_152 0xA61B +#define reg_dummy_159_152_pos 0 +#define reg_dummy_159_152_len 8 +#define reg_dummy_159_152_lsb 152 + +#define xd_p_reg_dummy_167_160 0xA61C +#define reg_dummy_167_160_pos 0 +#define reg_dummy_167_160_len 8 +#define reg_dummy_167_160_lsb 160 + +#define xd_p_reg_dummy_175_168 0xA61D +#define reg_dummy_175_168_pos 0 +#define reg_dummy_175_168_len 8 +#define reg_dummy_175_168_lsb 168 + +#define xd_p_reg_dummy_183_176 0xA61E +#define reg_dummy_183_176_pos 0 +#define reg_dummy_183_176_len 8 +#define reg_dummy_183_176_lsb 176 + +#define xd_p_reg_ofsm_read_rbc_en 0xA61E +#define reg_ofsm_read_rbc_en_pos 2 +#define reg_ofsm_read_rbc_en_len 1 +#define reg_ofsm_read_rbc_en_lsb 0 + +#define xd_p_reg_ce_filter_selection_dis 0xA61E +#define reg_ce_filter_selection_dis_pos 1 +#define reg_ce_filter_selection_dis_len 1 +#define reg_ce_filter_selection_dis_lsb 0 + +#define xd_p_reg_OFSM_version_control_7_0 0xA611 +#define reg_OFSM_version_control_7_0_pos 0 +#define reg_OFSM_version_control_7_0_len 8 +#define reg_OFSM_version_control_7_0_lsb 0 + +#define xd_p_reg_OFSM_version_control_15_8 0xA61F +#define reg_OFSM_version_control_15_8_pos 0 +#define reg_OFSM_version_control_15_8_len 8 +#define reg_OFSM_version_control_15_8_lsb 0 + +#define xd_p_reg_OFSM_version_control_23_16 0xA620 +#define reg_OFSM_version_control_23_16_pos 0 +#define reg_OFSM_version_control_23_16_len 8 +#define reg_OFSM_version_control_23_16_lsb 0 + +#define xd_p_reg_dummy_191_184 0xA61F +#define reg_dummy_191_184_pos 0 +#define reg_dummy_191_184_len 8 +#define reg_dummy_191_184_lsb 184 + +#define xd_p_reg_dummy_199_192 0xA620 +#define reg_dummy_199_192_pos 0 +#define reg_dummy_199_192_len 8 +#define reg_dummy_199_192_lsb 192 + +#define xd_p_reg_ce_en 0xABC0 +#define reg_ce_en_pos 0 +#define reg_ce_en_len 1 +#define reg_ce_en_lsb 0 +#define xd_p_reg_ce_fctrl_en 0xABC0 +#define reg_ce_fctrl_en_pos 1 +#define reg_ce_fctrl_en_len 1 +#define reg_ce_fctrl_en_lsb 0 +#define xd_p_reg_ce_fste_tdi 0xABC0 +#define reg_ce_fste_tdi_pos 2 +#define reg_ce_fste_tdi_len 1 +#define reg_ce_fste_tdi_lsb 0 +#define xd_p_reg_ce_dynamic 0xABC0 +#define reg_ce_dynamic_pos 3 +#define reg_ce_dynamic_len 1 +#define reg_ce_dynamic_lsb 0 +#define xd_p_reg_ce_conf 0xABC0 +#define reg_ce_conf_pos 4 +#define reg_ce_conf_len 2 +#define reg_ce_conf_lsb 0 +#define xd_p_reg_ce_dyn12 0xABC0 +#define reg_ce_dyn12_pos 6 +#define reg_ce_dyn12_len 1 +#define reg_ce_dyn12_lsb 0 +#define xd_p_reg_ce_derot_en 0xABC0 +#define reg_ce_derot_en_pos 7 +#define reg_ce_derot_en_len 1 +#define reg_ce_derot_en_lsb 0 +#define xd_p_reg_ce_dynamic_th_7_0 0xABC1 +#define reg_ce_dynamic_th_7_0_pos 0 +#define reg_ce_dynamic_th_7_0_len 8 +#define reg_ce_dynamic_th_7_0_lsb 0 +#define xd_p_reg_ce_dynamic_th_15_8 0xABC2 +#define reg_ce_dynamic_th_15_8_pos 0 +#define reg_ce_dynamic_th_15_8_len 8 +#define reg_ce_dynamic_th_15_8_lsb 8 +#define xd_p_reg_ce_s1 0xABC3 +#define reg_ce_s1_pos 0 +#define reg_ce_s1_len 5 +#define reg_ce_s1_lsb 0 +#define xd_p_reg_ce_var_forced_value 0xABC3 +#define reg_ce_var_forced_value_pos 5 +#define reg_ce_var_forced_value_len 3 +#define reg_ce_var_forced_value_lsb 0 +#define xd_p_reg_ce_data_im_7_0 0xABC4 +#define reg_ce_data_im_7_0_pos 0 +#define reg_ce_data_im_7_0_len 8 +#define reg_ce_data_im_7_0_lsb 0 +#define xd_p_reg_ce_data_im_8 0xABC5 +#define reg_ce_data_im_8_pos 0 +#define reg_ce_data_im_8_len 1 +#define reg_ce_data_im_8_lsb 0 +#define xd_p_reg_ce_data_re_6_0 0xABC5 +#define reg_ce_data_re_6_0_pos 1 +#define reg_ce_data_re_6_0_len 7 +#define reg_ce_data_re_6_0_lsb 0 +#define xd_p_reg_ce_data_re_8_7 0xABC6 +#define reg_ce_data_re_8_7_pos 0 +#define reg_ce_data_re_8_7_len 2 +#define reg_ce_data_re_8_7_lsb 7 +#define xd_p_reg_ce_tone_5_0 0xABC6 +#define reg_ce_tone_5_0_pos 2 +#define reg_ce_tone_5_0_len 6 +#define reg_ce_tone_5_0_lsb 0 +#define xd_p_reg_ce_tone_12_6 0xABC7 +#define reg_ce_tone_12_6_pos 0 +#define reg_ce_tone_12_6_len 7 +#define reg_ce_tone_12_6_lsb 6 +#define xd_p_reg_ce_centroid_drift_th 0xABC8 +#define reg_ce_centroid_drift_th_pos 0 +#define reg_ce_centroid_drift_th_len 8 +#define reg_ce_centroid_drift_th_lsb 0 +#define xd_p_reg_ce_centroid_count_max 0xABC9 +#define reg_ce_centroid_count_max_pos 0 +#define reg_ce_centroid_count_max_len 4 +#define reg_ce_centroid_count_max_lsb 0 +#define xd_p_reg_ce_centroid_bias_inc_7_0 0xABCA +#define reg_ce_centroid_bias_inc_7_0_pos 0 +#define reg_ce_centroid_bias_inc_7_0_len 8 +#define reg_ce_centroid_bias_inc_7_0_lsb 0 +#define xd_p_reg_ce_centroid_bias_inc_8 0xABCB +#define reg_ce_centroid_bias_inc_8_pos 0 +#define reg_ce_centroid_bias_inc_8_len 1 +#define reg_ce_centroid_bias_inc_8_lsb 0 +#define xd_p_reg_ce_var_th0_7_0 0xABCC +#define reg_ce_var_th0_7_0_pos 0 +#define reg_ce_var_th0_7_0_len 8 +#define reg_ce_var_th0_7_0_lsb 0 +#define xd_p_reg_ce_var_th0_15_8 0xABCD +#define reg_ce_var_th0_15_8_pos 0 +#define reg_ce_var_th0_15_8_len 8 +#define reg_ce_var_th0_15_8_lsb 8 +#define xd_p_reg_ce_var_th1_7_0 0xABCE +#define reg_ce_var_th1_7_0_pos 0 +#define reg_ce_var_th1_7_0_len 8 +#define reg_ce_var_th1_7_0_lsb 0 +#define xd_p_reg_ce_var_th1_15_8 0xABCF +#define reg_ce_var_th1_15_8_pos 0 +#define reg_ce_var_th1_15_8_len 8 +#define reg_ce_var_th1_15_8_lsb 8 +#define xd_p_reg_ce_var_th2_7_0 0xABD0 +#define reg_ce_var_th2_7_0_pos 0 +#define reg_ce_var_th2_7_0_len 8 +#define reg_ce_var_th2_7_0_lsb 0 +#define xd_p_reg_ce_var_th2_15_8 0xABD1 +#define reg_ce_var_th2_15_8_pos 0 +#define reg_ce_var_th2_15_8_len 8 +#define reg_ce_var_th2_15_8_lsb 8 +#define xd_p_reg_ce_var_th3_7_0 0xABD2 +#define reg_ce_var_th3_7_0_pos 0 +#define reg_ce_var_th3_7_0_len 8 +#define reg_ce_var_th3_7_0_lsb 0 +#define xd_p_reg_ce_var_th3_15_8 0xABD3 +#define reg_ce_var_th3_15_8_pos 0 +#define reg_ce_var_th3_15_8_len 8 +#define reg_ce_var_th3_15_8_lsb 8 +#define xd_p_reg_ce_var_th4_7_0 0xABD4 +#define reg_ce_var_th4_7_0_pos 0 +#define reg_ce_var_th4_7_0_len 8 +#define reg_ce_var_th4_7_0_lsb 0 +#define xd_p_reg_ce_var_th4_15_8 0xABD5 +#define reg_ce_var_th4_15_8_pos 0 +#define reg_ce_var_th4_15_8_len 8 +#define reg_ce_var_th4_15_8_lsb 8 +#define xd_p_reg_ce_var_th5_7_0 0xABD6 +#define reg_ce_var_th5_7_0_pos 0 +#define reg_ce_var_th5_7_0_len 8 +#define reg_ce_var_th5_7_0_lsb 0 +#define xd_p_reg_ce_var_th5_15_8 0xABD7 +#define reg_ce_var_th5_15_8_pos 0 +#define reg_ce_var_th5_15_8_len 8 +#define reg_ce_var_th5_15_8_lsb 8 +#define xd_p_reg_ce_var_th6_7_0 0xABD8 +#define reg_ce_var_th6_7_0_pos 0 +#define reg_ce_var_th6_7_0_len 8 +#define reg_ce_var_th6_7_0_lsb 0 +#define xd_p_reg_ce_var_th6_15_8 0xABD9 +#define reg_ce_var_th6_15_8_pos 0 +#define reg_ce_var_th6_15_8_len 8 +#define reg_ce_var_th6_15_8_lsb 8 +#define xd_p_reg_ce_fctrl_reset 0xABDA +#define reg_ce_fctrl_reset_pos 0 +#define reg_ce_fctrl_reset_len 1 +#define reg_ce_fctrl_reset_lsb 0 +#define xd_p_reg_ce_cent_auto_clr_en 0xABDA +#define reg_ce_cent_auto_clr_en_pos 1 +#define reg_ce_cent_auto_clr_en_len 1 +#define reg_ce_cent_auto_clr_en_lsb 0 +#define xd_p_reg_ce_fctrl_auto_reset_en 0xABDA +#define reg_ce_fctrl_auto_reset_en_pos 2 +#define reg_ce_fctrl_auto_reset_en_len 1 +#define reg_ce_fctrl_auto_reset_en_lsb 0 +#define xd_p_reg_ce_var_forced_en 0xABDA +#define reg_ce_var_forced_en_pos 3 +#define reg_ce_var_forced_en_len 1 +#define reg_ce_var_forced_en_lsb 0 +#define xd_p_reg_ce_cent_forced_en 0xABDA +#define reg_ce_cent_forced_en_pos 4 +#define reg_ce_cent_forced_en_len 1 +#define reg_ce_cent_forced_en_lsb 0 +#define xd_p_reg_ce_var_max 0xABDA +#define reg_ce_var_max_pos 5 +#define reg_ce_var_max_len 3 +#define reg_ce_var_max_lsb 0 +#define xd_p_reg_ce_cent_forced_value_7_0 0xABDB +#define reg_ce_cent_forced_value_7_0_pos 0 +#define reg_ce_cent_forced_value_7_0_len 8 +#define reg_ce_cent_forced_value_7_0_lsb 0 +#define xd_p_reg_ce_cent_forced_value_11_8 0xABDC +#define reg_ce_cent_forced_value_11_8_pos 0 +#define reg_ce_cent_forced_value_11_8_len 4 +#define reg_ce_cent_forced_value_11_8_lsb 8 +#define xd_p_reg_ce_fctrl_rd 0xABDD +#define reg_ce_fctrl_rd_pos 0 +#define reg_ce_fctrl_rd_len 1 +#define reg_ce_fctrl_rd_lsb 0 +#define xd_p_reg_ce_centroid_max_6_0 0xABDD +#define reg_ce_centroid_max_6_0_pos 1 +#define reg_ce_centroid_max_6_0_len 7 +#define reg_ce_centroid_max_6_0_lsb 0 +#define xd_p_reg_ce_centroid_max_11_7 0xABDE +#define reg_ce_centroid_max_11_7_pos 0 +#define reg_ce_centroid_max_11_7_len 5 +#define reg_ce_centroid_max_11_7_lsb 7 +#define xd_p_reg_ce_var 0xABDF +#define reg_ce_var_pos 0 +#define reg_ce_var_len 3 +#define reg_ce_var_lsb 0 +#define xd_p_reg_ce_fctrl_rdy 0xABDF +#define reg_ce_fctrl_rdy_pos 3 +#define reg_ce_fctrl_rdy_len 1 +#define reg_ce_fctrl_rdy_lsb 0 +#define xd_p_reg_ce_centroid_out_3_0 0xABDF +#define reg_ce_centroid_out_3_0_pos 4 +#define reg_ce_centroid_out_3_0_len 4 +#define reg_ce_centroid_out_3_0_lsb 0 +#define xd_p_reg_ce_centroid_out_11_4 0xABE0 +#define reg_ce_centroid_out_11_4_pos 0 +#define reg_ce_centroid_out_11_4_len 8 +#define reg_ce_centroid_out_11_4_lsb 4 +#define xd_p_reg_ce_bias_7_0 0xABE1 +#define reg_ce_bias_7_0_pos 0 +#define reg_ce_bias_7_0_len 8 +#define reg_ce_bias_7_0_lsb 0 +#define xd_p_reg_ce_bias_11_8 0xABE2 +#define reg_ce_bias_11_8_pos 0 +#define reg_ce_bias_11_8_len 4 +#define reg_ce_bias_11_8_lsb 8 +#define xd_p_reg_ce_m1_3_0 0xABE2 +#define reg_ce_m1_3_0_pos 4 +#define reg_ce_m1_3_0_len 4 +#define reg_ce_m1_3_0_lsb 0 +#define xd_p_reg_ce_m1_11_4 0xABE3 +#define reg_ce_m1_11_4_pos 0 +#define reg_ce_m1_11_4_len 8 +#define reg_ce_m1_11_4_lsb 4 +#define xd_p_reg_ce_rh0_7_0 0xABE4 +#define reg_ce_rh0_7_0_pos 0 +#define reg_ce_rh0_7_0_len 8 +#define reg_ce_rh0_7_0_lsb 0 +#define xd_p_reg_ce_rh0_15_8 0xABE5 +#define reg_ce_rh0_15_8_pos 0 +#define reg_ce_rh0_15_8_len 8 +#define reg_ce_rh0_15_8_lsb 8 +#define xd_p_reg_ce_rh0_23_16 0xABE6 +#define reg_ce_rh0_23_16_pos 0 +#define reg_ce_rh0_23_16_len 8 +#define reg_ce_rh0_23_16_lsb 16 +#define xd_p_reg_ce_rh0_31_24 0xABE7 +#define reg_ce_rh0_31_24_pos 0 +#define reg_ce_rh0_31_24_len 8 +#define reg_ce_rh0_31_24_lsb 24 +#define xd_p_reg_ce_rh3_real_7_0 0xABE8 +#define reg_ce_rh3_real_7_0_pos 0 +#define reg_ce_rh3_real_7_0_len 8 +#define reg_ce_rh3_real_7_0_lsb 0 +#define xd_p_reg_ce_rh3_real_15_8 0xABE9 +#define reg_ce_rh3_real_15_8_pos 0 +#define reg_ce_rh3_real_15_8_len 8 +#define reg_ce_rh3_real_15_8_lsb 8 +#define xd_p_reg_ce_rh3_real_23_16 0xABEA +#define reg_ce_rh3_real_23_16_pos 0 +#define reg_ce_rh3_real_23_16_len 8 +#define reg_ce_rh3_real_23_16_lsb 16 +#define xd_p_reg_ce_rh3_real_31_24 0xABEB +#define reg_ce_rh3_real_31_24_pos 0 +#define reg_ce_rh3_real_31_24_len 8 +#define reg_ce_rh3_real_31_24_lsb 24 +#define xd_p_reg_ce_rh3_imag_7_0 0xABEC +#define reg_ce_rh3_imag_7_0_pos 0 +#define reg_ce_rh3_imag_7_0_len 8 +#define reg_ce_rh3_imag_7_0_lsb 0 +#define xd_p_reg_ce_rh3_imag_15_8 0xABED +#define reg_ce_rh3_imag_15_8_pos 0 +#define reg_ce_rh3_imag_15_8_len 8 +#define reg_ce_rh3_imag_15_8_lsb 8 +#define xd_p_reg_ce_rh3_imag_23_16 0xABEE +#define reg_ce_rh3_imag_23_16_pos 0 +#define reg_ce_rh3_imag_23_16_len 8 +#define reg_ce_rh3_imag_23_16_lsb 16 +#define xd_p_reg_ce_rh3_imag_31_24 0xABEF +#define reg_ce_rh3_imag_31_24_pos 0 +#define reg_ce_rh3_imag_31_24_len 8 +#define reg_ce_rh3_imag_31_24_lsb 24 +#define xd_p_reg_feq_fix_eh2_7_0 0xABF0 +#define reg_feq_fix_eh2_7_0_pos 0 +#define reg_feq_fix_eh2_7_0_len 8 +#define reg_feq_fix_eh2_7_0_lsb 0 +#define xd_p_reg_feq_fix_eh2_15_8 0xABF1 +#define reg_feq_fix_eh2_15_8_pos 0 +#define reg_feq_fix_eh2_15_8_len 8 +#define reg_feq_fix_eh2_15_8_lsb 8 +#define xd_p_reg_feq_fix_eh2_23_16 0xABF2 +#define reg_feq_fix_eh2_23_16_pos 0 +#define reg_feq_fix_eh2_23_16_len 8 +#define reg_feq_fix_eh2_23_16_lsb 16 +#define xd_p_reg_feq_fix_eh2_31_24 0xABF3 +#define reg_feq_fix_eh2_31_24_pos 0 +#define reg_feq_fix_eh2_31_24_len 8 +#define reg_feq_fix_eh2_31_24_lsb 24 +#define xd_p_reg_ce_m2_central_7_0 0xABF4 +#define reg_ce_m2_central_7_0_pos 0 +#define reg_ce_m2_central_7_0_len 8 +#define reg_ce_m2_central_7_0_lsb 0 +#define xd_p_reg_ce_m2_central_15_8 0xABF5 +#define reg_ce_m2_central_15_8_pos 0 +#define reg_ce_m2_central_15_8_len 8 +#define reg_ce_m2_central_15_8_lsb 8 +#define xd_p_reg_ce_fftshift 0xABF6 +#define reg_ce_fftshift_pos 0 +#define reg_ce_fftshift_len 4 +#define reg_ce_fftshift_lsb 0 +#define xd_p_reg_ce_fftshift1 0xABF6 +#define reg_ce_fftshift1_pos 4 +#define reg_ce_fftshift1_len 4 +#define reg_ce_fftshift1_lsb 0 +#define xd_p_reg_ce_fftshift2 0xABF7 +#define reg_ce_fftshift2_pos 0 +#define reg_ce_fftshift2_len 4 +#define reg_ce_fftshift2_lsb 0 +#define xd_p_reg_ce_top_mobile 0xABF7 +#define reg_ce_top_mobile_pos 4 +#define reg_ce_top_mobile_len 1 +#define reg_ce_top_mobile_lsb 0 +#define xd_p_reg_strong_sginal_detected 0xA2BC +#define reg_strong_sginal_detected_pos 2 +#define reg_strong_sginal_detected_len 1 +#define reg_strong_sginal_detected_lsb 0 + +#define XD_MP2IF_BASE 0xB000 +#define XD_MP2IF_CSR (0x00 + XD_MP2IF_BASE) +#define XD_MP2IF_DMX_CTRL (0x03 + XD_MP2IF_BASE) +#define XD_MP2IF_PID_IDX (0x04 + XD_MP2IF_BASE) +#define XD_MP2IF_PID_DATA_L (0x05 + XD_MP2IF_BASE) +#define XD_MP2IF_PID_DATA_H (0x06 + XD_MP2IF_BASE) +#define XD_MP2IF_MISC (0x07 + XD_MP2IF_BASE) + +extern struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d); +extern int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg, + u8 * value); +extern int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg, + u8 * values, int len); +extern int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg, + u8 value); +extern int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg, + u8 * values, int len); +extern int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg, + u8 addr, u8 * values, int len); +extern int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg, + u8 * values, int len); +extern int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg, + u8 pos, u8 len, u8 * value); +extern int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg, + u8 pos, u8 len, u8 value); +extern int af9005_send_command(struct dvb_usb_device *d, u8 command, + u8 * wbuf, int wlen, u8 * rbuf, int rlen); +extern int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, + u8 * values, int len); +extern int af9005_tuner_attach(struct dvb_usb_adapter *adap); +extern int af9005_led_control(struct dvb_usb_device *d, int onoff); + +extern u8 regmask[8]; + +/* remote control decoder */ +extern int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, + u32 * event, int *state); +extern struct dvb_usb_rc_key af9005_rc_keys[]; +extern int af9005_rc_keys_size; + +#endif diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index bac2ae3b4a1f..04e31cf7d530 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -354,41 +354,35 @@ static struct mt352_config cxusb_mt352_config = { /* Callbacks for DVB USB */ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) { - u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 }; - adap->pll_addr = 0x61; - memcpy(adap->pll_init, bpll, 4); - adap->pll_desc = &dvb_pll_fmd1216me; - - adap->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c; - adap->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c; - + dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap, + DVB_PLL_FMD1216ME); return 0; } static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap) { dvb_attach(dvb_pll_attach, adap->fe, 0x61, - NULL, &dvb_pll_thomson_dtt7579); + NULL, DVB_PLL_THOMSON_DTT7579); return 0; } static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, &dvb_pll_lg_z201); + dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_LG_Z201); return 0; } static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap) { dvb_attach(dvb_pll_attach, adap->fe, 0x60, - NULL, &dvb_pll_thomson_dtt7579); + NULL, DVB_PLL_THOMSON_DTT7579); return 0; } static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap) { dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap, - &dvb_pll_lg_tdvs_h06xf); + DVB_PLL_LG_TDVS_H06XF); return 0; } diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c index 5143e426d283..9a184da01c47 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-common.c +++ b/drivers/media/dvb/dvb-usb/dibusb-common.c @@ -295,7 +295,7 @@ int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap) tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1); if (dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) { /* not found - use panasonic pll parameters */ - if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, &dvb_pll_env57h1xd5) == NULL) + if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL) return -ENOMEM; } else { st->mt2060_present = 1; diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index 7a6ae8f482e0..043cadae0859 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -14,6 +14,14 @@ */ #include "dibusb.h" +static int dib3000mb_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dibusb_state *st = adap->priv; + + return st->ops.tuner_pass_ctrl(fe, enable, st->tuner_addr); +} + static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap) { struct dib3000_config demod_cfg; @@ -21,21 +29,34 @@ static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap) demod_cfg.demod_address = 0x8; - if ((adap->fe = dib3000mb_attach(&demod_cfg,&adap->dev->i2c_adap,&st->ops)) == NULL) + if ((adap->fe = dvb_attach(dib3000mb_attach, &demod_cfg, + &adap->dev->i2c_adap, &st->ops)) == NULL) return -ENODEV; - adap->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c; - adap->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c; - - adap->tuner_pass_ctrl = st->ops.tuner_pass_ctrl; + adap->fe->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl; return 0; } static int dibusb_thomson_tuner_attach(struct dvb_usb_adapter *adap) { - adap->pll_addr = 0x61; - adap->pll_desc = &dvb_pll_tua6010xs; + struct dibusb_state *st = adap->priv; + + st->tuner_addr = 0x61; + + dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap, + DVB_PLL_TUA6010XS); + return 0; +} + +static int dibusb_panasonic_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dibusb_state *st = adap->priv; + + st->tuner_addr = 0x60; + + dvb_attach(dvb_pll_attach, adap->fe, 0x60, &adap->dev->i2c_adap, + DVB_PLL_TDA665X); return 0; } @@ -50,30 +71,28 @@ static int dibusb_tuner_probe_and_attach(struct dvb_usb_adapter *adap) { .flags = 0, .buf = b, .len = 2 }, { .flags = I2C_M_RD, .buf = b2, .len = 1 }, }; + struct dibusb_state *st = adap->priv; /* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */ - msg[0].addr = msg[1].addr = 0x60; + msg[0].addr = msg[1].addr = st->tuner_addr = 0x60; - if (adap->tuner_pass_ctrl) - adap->tuner_pass_ctrl(adap->fe,1,msg[0].addr); + if (adap->fe->ops.i2c_gate_ctrl) + adap->fe->ops.i2c_gate_ctrl(adap->fe,1); if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) { err("tuner i2c write failed."); ret = -EREMOTEIO; } - if (adap->tuner_pass_ctrl) - adap->tuner_pass_ctrl(adap->fe,0,msg[0].addr); + if (adap->fe->ops.i2c_gate_ctrl) + adap->fe->ops.i2c_gate_ctrl(adap->fe,0); if (b2[0] == 0xfe) { info("This device has the Thomson Cable onboard. Which is default."); - dibusb_thomson_tuner_attach(adap); + ret = dibusb_thomson_tuner_attach(adap); } else { - u8 bpll[4] = { 0x0b, 0xf5, 0x85, 0xab }; info("This device has the Panasonic ENV77H11D5 onboard."); - adap->pll_addr = 0x60; - memcpy(adap->pll_init,bpll,4); - adap->pll_desc = &dvb_pll_tda665x; + ret = dibusb_panasonic_tuner_attach(adap); } return ret; diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/dvb/dvb-usb/dibusb.h index b60781032742..8e847aa73ba1 100644 --- a/drivers/media/dvb/dvb-usb/dibusb.h +++ b/drivers/media/dvb/dvb-usb/dibusb.h @@ -99,6 +99,7 @@ struct dibusb_state { struct dib_fe_xfer_ops ops; int mt2060_present; + u8 tuner_addr; }; struct dibusb_device_state { diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index b5acb11c0bc9..bca1e0905739 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -118,7 +118,8 @@ static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe, struct dvb_f { struct dvb_usb_adapter *adap = fe->dvb->priv; u8 b[5]; - dvb_usb_tuner_calc_regs(fe,fep,b, 5); + + fe->ops.tuner_ops.calc_regs(fe, fep, b, sizeof(b)); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0); @@ -130,12 +131,14 @@ static struct nxt6000_config digitv_nxt6000_config = { static int digitv_frontend_attach(struct dvb_usb_adapter *adap) { + struct digitv_state *st = adap->dev->priv; + if ((adap->fe = dvb_attach(mt352_attach, &digitv_mt352_config, &adap->dev->i2c_adap)) != NULL) { - adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs; + st->is_nxt6000 = 0; return 0; } if ((adap->fe = dvb_attach(nxt6000_attach, &digitv_nxt6000_config, &adap->dev->i2c_adap)) != NULL) { - adap->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params; + st->is_nxt6000 = 1; return 0; } return -EIO; @@ -143,8 +146,14 @@ static int digitv_frontend_attach(struct dvb_usb_adapter *adap) static int digitv_tuner_attach(struct dvb_usb_adapter *adap) { - adap->pll_addr = 0x60; - adap->pll_desc = &dvb_pll_tded4; + struct digitv_state *st = adap->dev->priv; + + if (!dvb_attach(dvb_pll_attach, adap->fe, 0x60, NULL, DVB_PLL_TDED4)) + return -ENODEV; + + if (st->is_nxt6000) + adap->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params; + return 0; } @@ -273,6 +282,8 @@ static struct dvb_usb_device_properties digitv_properties = { .usb_ctrl = CYPRESS_FX2, .firmware = "dvb-usb-digitv-02.fw", + .size_of_priv = sizeof(struct digitv_state), + .num_adapters = 1, .adapter = { { diff --git a/drivers/media/dvb/dvb-usb/digitv.h b/drivers/media/dvb/dvb-usb/digitv.h index 477ee428a70e..8b43e3db8691 100644 --- a/drivers/media/dvb/dvb-usb/digitv.h +++ b/drivers/media/dvb/dvb-usb/digitv.h @@ -4,6 +4,10 @@ #define DVB_USB_LOG_PREFIX "digitv" #include "dvb-usb.h" +struct digitv_state { + int is_nxt6000; +}; + extern int dvb_usb_digitv_debug; #define deb_rc(args...) dprintk(dvb_usb_digitv_debug,0x01,args) diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c index 088b6dee3a7f..23428cd30756 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c @@ -46,82 +46,3 @@ int dvb_usb_i2c_exit(struct dvb_usb_device *d) d->state &= ~DVB_USB_STATE_I2C; return 0; } - -int dvb_usb_tuner_init_i2c(struct dvb_frontend *fe) -{ - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct i2c_msg msg = { .addr = adap->pll_addr, .flags = 0, .buf = adap->pll_init, .len = 4 }; - int ret = 0; - - /* if pll_desc is not used */ - if (adap->pll_desc == NULL) - return 0; - - if (adap->tuner_pass_ctrl) - adap->tuner_pass_ctrl(fe, 1, adap->pll_addr); - - deb_pll("pll init: %x\n",adap->pll_addr); - deb_pll("pll-buf: %x %x %x %x\n",adap->pll_init[0], adap->pll_init[1], - adap->pll_init[2], adap->pll_init[3]); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&adap->dev->i2c_adap, &msg, 1) != 1) { - err("tuner i2c write failed for pll_init."); - ret = -EREMOTEIO; - } - msleep(1); - - if (adap->tuner_pass_ctrl) - adap->tuner_pass_ctrl(fe,0,adap->pll_addr); - return ret; -} -EXPORT_SYMBOL(dvb_usb_tuner_init_i2c); - -int dvb_usb_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 *b, int buf_len) -{ - struct dvb_usb_adapter *adap = fe->dvb->priv; - - if (buf_len != 5) - return -EINVAL; - if (adap->pll_desc == NULL) - return 0; - - deb_pll("pll addr: %x, freq: %d %p\n",adap->pll_addr, fep->frequency, adap->pll_desc); - - b[0] = adap->pll_addr; - dvb_pll_configure(adap->pll_desc, &b[1], fep->frequency, fep->u.ofdm.bandwidth); - - deb_pll("pll-buf: %x %x %x %x %x\n",b[0],b[1],b[2],b[3],b[4]); - - return 5; -} -EXPORT_SYMBOL(dvb_usb_tuner_calc_regs); - -int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) -{ - struct dvb_usb_adapter *adap = fe->dvb->priv; - int ret = 0; - u8 b[5]; - struct i2c_msg msg = { .addr = adap->pll_addr, .flags = 0, .buf = &b[1], .len = 4 }; - - dvb_usb_tuner_calc_regs(fe,fep,b,5); - - if (adap->tuner_pass_ctrl) - adap->tuner_pass_ctrl(fe, 1, adap->pll_addr); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - if (i2c_transfer(&adap->dev->i2c_adap, &msg, 1) != 1) { - err("tuner i2c write failed for pll_set."); - ret = -EREMOTEIO; - } - msleep(1); - - if (adap->tuner_pass_ctrl) - adap->tuner_pass_ctrl(fe, 0, adap->pll_addr); - - return ret; -} -EXPORT_SYMBOL(dvb_usb_tuner_set_params_i2c); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 403081689de1..4dfab02a8a0d 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -11,7 +11,9 @@ /* Vendor IDs */ #define USB_VID_ADSTECH 0x06e1 +#define USB_VID_AFATECH 0x15a4 #define USB_VID_ALCOR_MICRO 0x058f +#define USB_VID_ALINK 0x05e3 #define USB_VID_ANCHOR 0x0547 #define USB_VID_ANUBIS_ELECTRONIC 0x10fd #define USB_VID_AVERMEDIA 0x07ca @@ -35,6 +37,7 @@ #define USB_VID_MSI 0x0db0 #define USB_VID_OPERA1 0x695c #define USB_VID_PINNACLE 0x2304 +#define USB_VID_TERRATEC 0x0ccd #define USB_VID_VISIONPLUS 0x13d3 #define USB_VID_TWINHAN 0x1822 #define USB_VID_ULTIMA_ELECTRONIC 0x05d8 @@ -44,6 +47,8 @@ /* Product IDs */ #define USB_PID_ADSTECH_USB2_COLD 0xa333 #define USB_PID_ADSTECH_USB2_WARM 0xa334 +#define USB_PID_AFATECH_AF9005 0x9020 +#define USB_VID_ALINK_DTU 0xf170 #define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001 #define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002 #define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800 @@ -69,6 +74,7 @@ #define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1 #define USB_PID_KWORLD_VSTREAM_COLD 0x17de #define USB_PID_KWORLD_VSTREAM_WARM 0x17df +#define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055 #define USB_PID_TWINHAN_VP7041_COLD 0x3201 #define USB_PID_TWINHAN_VP7041_WARM 0x3202 #define USB_PID_TWINHAN_VP7020_COLD 0x3203 diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c index 9200a30dd1b9..7b9f35bfb4f0 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c @@ -110,7 +110,7 @@ int dvb_usb_remote_init(struct dvb_usb_device *d) input_dev->name = "IR-receiver inside an USB DVB receiver"; input_dev->phys = d->rc_phys; usb_to_input_id(d->udev, &input_dev->id); - input_dev->cdev.dev = &d->udev->dev; + input_dev->dev.parent = &d->udev->dev; /* set the bits for the keys */ deb_rc("key map size: %d\n", d->props.rc_key_map_size); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index 6f824a569e14..d1b3c7b81fff 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -297,12 +297,6 @@ struct dvb_usb_adapter { int feedcount; int pid_filtering; - /* tuner programming information */ - u8 pll_addr; - u8 pll_init[4]; - struct dvb_pll_desc *pll_desc; - int (*tuner_pass_ctrl) (struct dvb_frontend *, int, u8); - /* dvb */ struct dvb_adapter dvb_adap; struct dmxdev dmxdev; @@ -388,11 +382,6 @@ extern int dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16); /* commonly used remote control parsing */ extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *); -/* commonly used pll init and set functions */ -extern int dvb_usb_tuner_init_i2c(struct dvb_frontend *); -extern int dvb_usb_tuner_calc_regs(struct dvb_frontend *, struct dvb_frontend_parameters *, u8 *buf, int buf_len); -extern int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *); - /* commonly used firmware download types and function */ struct hexline { u8 len; diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c index e0587e663591..f01d99c1c43c 100644 --- a/drivers/media/dvb/dvb-usb/gl861.c +++ b/drivers/media/dvb/dvb-usb/gl861.c @@ -157,6 +157,7 @@ static int gl861_probe(struct usb_interface *intf, static struct usb_device_id gl861_table [] = { { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801) }, + { USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, gl861_table); @@ -187,12 +188,16 @@ static struct dvb_usb_device_properties gl861_properties = { }}, .i2c_algo = &gl861_i2c_algo, - .num_device_descs = 1, + .num_device_descs = 2, .devices = { { "MSI Mega Sky 55801 DVB-T USB2.0", { &gl861_table[0], NULL }, { NULL }, }, + { "A-LINK DTU DVB-T USB2.0", + { &gl861_table[1], NULL }, + { NULL }, + }, } }; diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c index c546ddeda5d4..a956bc503a4c 100644 --- a/drivers/media/dvb/dvb-usb/m920x.c +++ b/drivers/media/dvb/dvb-usb/m920x.c @@ -22,6 +22,8 @@ static int dvb_usb_m920x_debug; module_param_named(debug,dvb_usb_m920x_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); +static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid); + static inline int m920x_read(struct usb_device *udev, u8 request, u16 value, u16 index, void *data, int size) { @@ -57,7 +59,8 @@ static inline int m920x_write(struct usb_device *udev, u8 request, static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq) { - int ret = 0; + int ret = 0, i, epi, flags = 0; + int adap_enabled[M9206_MAX_ADAPTERS] = { 0 }; /* Remote controller init. */ if (d->props.rc_query) { @@ -76,9 +79,51 @@ static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq) deb("Initialising remote control success\n"); } + for (i = 0; i < d->props.num_adapters; i++) + flags |= d->adapter[i].props.caps; + + /* Some devices(Dposh) might crash if we attempt touch at all. */ + if (flags & DVB_USB_ADAP_HAS_PID_FILTER) { + for (i = 0; i < d->props.num_adapters; i++) { + epi = d->adapter[i].props.stream.endpoint - 0x81; + + if (epi < 0 || epi >= M9206_MAX_ADAPTERS) { + printk(KERN_INFO "m920x: Unexpected adapter endpoint!\n"); + return -EINVAL; + } + + adap_enabled[epi] = 1; + } + + for (i = 0; i < M9206_MAX_ADAPTERS; i++) { + if (adap_enabled[i]) + continue; + + if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x0)) != 0) + return ret; + + if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x02f5)) != 0) + return ret; + } + } + return ret; } +static int m920x_init_ep(struct usb_interface *intf) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct usb_host_interface *alt; + + if ((alt = usb_altnum_to_altsetting(intf, 1)) == NULL) { + deb("No alt found!\n"); + return -ENODEV; + } + + return usb_set_interface(udev, alt->desc.bInterfaceNumber, + alt->desc.bAlternateSetting); +} + static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { struct m920x_state *m = d->priv; @@ -211,8 +256,7 @@ static struct i2c_algorithm m920x_i2c_algo = { }; /* pid filter */ -static int m920x_set_filter(struct dvb_usb_adapter *adap, - int type, int idx, int pid) +static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid) { int ret = 0; @@ -221,10 +265,10 @@ static int m920x_set_filter(struct dvb_usb_adapter *adap, pid |= 0x8000; - if ((ret = m920x_write(adap->dev->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0) + if ((ret = m920x_write(d->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0) return ret; - if ((ret = m920x_write(adap->dev->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0) + if ((ret = m920x_write(d->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0) return ret; return ret; @@ -233,40 +277,35 @@ static int m920x_set_filter(struct dvb_usb_adapter *adap, static int m920x_update_filters(struct dvb_usb_adapter *adap) { struct m920x_state *m = adap->dev->priv; - int enabled = m->filtering_enabled; + int enabled = m->filtering_enabled[adap->id]; int i, ret = 0, filter = 0; + int ep = adap->props.stream.endpoint; for (i = 0; i < M9206_MAX_FILTERS; i++) - if (m->filters[i] == 8192) + if (m->filters[adap->id][i] == 8192) enabled = 0; /* Disable all filters */ - if ((ret = m920x_set_filter(adap, 0x81, 1, enabled)) != 0) + if ((ret = m920x_set_filter(adap->dev, ep, 1, enabled)) != 0) return ret; for (i = 0; i < M9206_MAX_FILTERS; i++) - if ((ret = m920x_set_filter(adap, 0x81, i + 2, 0)) != 0) + if ((ret = m920x_set_filter(adap->dev, ep, i + 2, 0)) != 0) return ret; - if ((ret = m920x_set_filter(adap, 0x82, 0, 0x0)) != 0) - return ret; - /* Set */ if (enabled) { for (i = 0; i < M9206_MAX_FILTERS; i++) { - if (m->filters[i] == 0) + if (m->filters[adap->id][i] == 0) continue; - if ((ret = m920x_set_filter(adap, 0x81, filter + 2, m->filters[i])) != 0) + if ((ret = m920x_set_filter(adap->dev, ep, filter + 2, m->filters[adap->id][i])) != 0) return ret; filter++; } } - if ((ret = m920x_set_filter(adap, 0x82, 0, 0x02f5)) != 0) - return ret; - return ret; } @@ -274,7 +313,7 @@ static int m920x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) { struct m920x_state *m = adap->dev->priv; - m->filtering_enabled = onoff ? 1 : 0; + m->filtering_enabled[adap->id] = onoff ? 1 : 0; return m920x_update_filters(adap); } @@ -283,7 +322,7 @@ static int m920x_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, in { struct m920x_state *m = adap->dev->priv; - m->filters[index] = onoff ? pid : 0; + m->filters[adap->id][index] = onoff ? pid : 0; return m920x_update_filters(adap); } @@ -368,6 +407,7 @@ static int m920x_identify_state(struct usb_device *udev, /* demod configurations */ static int m920x_mt352_demod_init(struct dvb_frontend *fe) { + int ret; u8 config[] = { CONFIG, 0x3d }; u8 clock[] = { CLOCK_CTL, 0x30 }; u8 reset[] = { RESET, 0x80 }; @@ -377,17 +417,25 @@ static int m920x_mt352_demod_init(struct dvb_frontend *fe) u8 unk1[] = { 0x93, 0x1a }; u8 unk2[] = { 0xb5, 0x7a }; - mt352_write(fe, config, ARRAY_SIZE(config)); - mt352_write(fe, clock, ARRAY_SIZE(clock)); - mt352_write(fe, reset, ARRAY_SIZE(reset)); - mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl)); - mt352_write(fe, agc, ARRAY_SIZE(agc)); - mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc)); - mt352_write(fe, unk1, ARRAY_SIZE(unk1)); - mt352_write(fe, unk2, ARRAY_SIZE(unk2)); - deb("Demod init!\n"); + if ((ret = mt352_write(fe, config, ARRAY_SIZE(config))) != 0) + return ret; + if ((ret = mt352_write(fe, clock, ARRAY_SIZE(clock))) != 0) + return ret; + if ((ret = mt352_write(fe, reset, ARRAY_SIZE(reset))) != 0) + return ret; + if ((ret = mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl))) != 0) + return ret; + if ((ret = mt352_write(fe, agc, ARRAY_SIZE(agc))) != 0) + return ret; + if ((ret = mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc))) != 0) + return ret; + if ((ret = mt352_write(fe, unk1, ARRAY_SIZE(unk1))) != 0) + return ret; + if ((ret = mt352_write(fe, unk2, ARRAY_SIZE(unk2))) != 0) + return ret; + return 0; } @@ -558,8 +606,7 @@ static struct dvb_usb_device_properties dposh_properties; static int m920x_probe(struct usb_interface *intf, const struct usb_device_id *id) { - struct dvb_usb_device *d; - struct usb_host_interface *alt; + struct dvb_usb_device *d = NULL; int ret; struct m920x_inits *rc_init_seq = NULL; int bInterfaceNumber = intf->cur_altsetting->desc.bInterfaceNumber; @@ -604,23 +651,13 @@ static int m920x_probe(struct usb_interface *intf, * tvwalkertwin_properties already configured both * tuners, so there is nothing for us to do here */ - - return -ENODEV; } found: - alt = usb_altnum_to_altsetting(intf, 1); - if (alt == NULL) { - deb("No alt found!\n"); - return -ENODEV; - } - - ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber, - alt->desc.bAlternateSetting); - if (ret < 0) + if ((ret = m920x_init_ep(intf)) < 0) return ret; - if ((ret = m920x_init(d, rc_init_seq)) != 0) + if (d && (ret = m920x_init(d, rc_init_seq)) != 0) return ret; return ret; @@ -737,9 +774,9 @@ static struct dvb_usb_device_properties digivox_mini_ii_properties = { * * LifeView TV Walker Twin has 1 x M9206, 2 x TDA10046, 2 x TDA8275A * TDA10046 #0 is located at i2c address 0x08 - * TDA10046 #1 is located at i2c address 0x0b (presently disabled - not yet working) + * TDA10046 #1 is located at i2c address 0x0b * TDA8275A #0 is located at i2c address 0x60 - * TDA8275A #1 is located at i2c address 0x61 (presently disabled - not yet working) + * TDA8275A #1 is located at i2c address 0x61 */ static struct dvb_usb_device_properties tvwalkertwin_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, @@ -756,7 +793,7 @@ static struct dvb_usb_device_properties tvwalkertwin_properties = { .size_of_priv = sizeof(struct m920x_state), .identify_state = m920x_identify_state, - .num_adapters = 1, + .num_adapters = 2, .adapter = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, diff --git a/drivers/media/dvb/dvb-usb/m920x.h b/drivers/media/dvb/dvb-usb/m920x.h index 2c8942d04222..37532890accd 100644 --- a/drivers/media/dvb/dvb-usb/m920x.h +++ b/drivers/media/dvb/dvb-usb/m920x.h @@ -18,6 +18,7 @@ #define M9206_FW 0x30 #define M9206_MAX_FILTERS 8 +#define M9206_MAX_ADAPTERS 2 /* sequences found in logs: @@ -60,8 +61,8 @@ response to a write, is unknown. */ struct m920x_state { - u16 filters[M9206_MAX_FILTERS]; - int filtering_enabled; + u16 filters[M9206_MAX_ADAPTERS][M9206_MAX_FILTERS]; + int filtering_enabled[M9206_MAX_ADAPTERS]; int rep_count; }; diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c index 518d7ad217df..d7c04951ceab 100644 --- a/drivers/media/dvb/dvb-usb/opera1.c +++ b/drivers/media/dvb/dvb-usb/opera1.c @@ -263,7 +263,7 @@ static int opera1_tuner_attach(struct dvb_usb_adapter *adap) { dvb_attach( dvb_pll_attach, adap->fe, 0xc0>>1, - &adap->dev->i2c_adap, &dvb_pll_opera1 + &adap->dev->i2c_adap, DVB_PLL_OPERA1 ); return 0; } @@ -435,9 +435,9 @@ static int opera1_xilinx_load_firmware(struct usb_device *dev, { const struct firmware *fw = NULL; u8 *b, *p; - int ret = 0, i; + int ret = 0, i,fpgasize=40; u8 testval; - info("start downloading fpga firmware"); + info("start downloading fpga firmware %s",filename); if ((ret = request_firmware(&fw, filename, &dev->dev)) != 0) { err("did not find the firmware file. (%s) " @@ -454,17 +454,20 @@ static int opera1_xilinx_load_firmware(struct usb_device *dev, /* clear fpga ? */ opera1_xilinx_rw(dev, 0xbc, 0xaa, &fpga_command, 1, OPERA_WRITE_MSG); - for (i = 0; p[i] != 0 && i < fw->size;) { + for (i = 0; i < fw->size;) { + if ( (fw->size - i) <fpgasize){ + fpgasize=fw->size-i; + } b = (u8 *) p + i; if (opera1_xilinx_rw - (dev, OPERA_WRITE_FX2, 0x0, b + 1, b[0], - OPERA_WRITE_MSG) != b[0] + (dev, OPERA_WRITE_FX2, 0x0, b , fpgasize, + OPERA_WRITE_MSG) != fpgasize ) { err("error while transferring firmware"); ret = -EINVAL; break; } - i = i + 1 + b[0]; + i = i + fpgasize; } /* restart the CPU */ if (ret || opera1_xilinx_rw @@ -534,18 +537,16 @@ static struct dvb_usb_device_properties opera1_properties = { static int opera1_probe(struct usb_interface *intf, const struct usb_device_id *id) { - struct dvb_usb_device *d; struct usb_device *udev = interface_to_usbdev(intf); if (udev->descriptor.idProduct == USB_PID_OPERA1_WARM && udev->descriptor.idVendor == USB_VID_OPERA1 && - (d == NULL - || opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga.fw") != 0) - ) { + opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga-01.fw") != 0 + ) { return -EINVAL; } - if (dvb_usb_device_init(intf, &opera1_properties, THIS_MODULE, &d) != 0) + if (dvb_usb_device_init(intf, &opera1_properties, THIS_MODULE, NULL) != 0) return -EINVAL; return 0; } diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c index f77b48f76582..0dcab3d4e236 100644 --- a/drivers/media/dvb/dvb-usb/umt-010.c +++ b/drivers/media/dvb/dvb-usb/umt-010.c @@ -65,9 +65,7 @@ static int umt_mt352_frontend_attach(struct dvb_usb_adapter *adap) static int umt_tuner_attach (struct dvb_usb_adapter *adap) { - adap->pll_addr = 0x61; - adap->pll_desc = &dvb_pll_tua6034; - adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs; + dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_TUA6034); return 0; } @@ -84,8 +82,8 @@ static int umt_probe(struct usb_interface *intf, /* do not change the order of the ID table */ static struct usb_device_id umt_table [] = { -/* 00 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_COLD) }, -/* 01 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_WARM) }, +/* 00 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_COLD) }, +/* 01 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_WARM) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, umt_table); diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 27f386585d43..156b062e02c4 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -2,7 +2,7 @@ # Makefile for the kernel DVB frontend device drivers. # -EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ obj-$(CONFIG_DVB_PLL) += dvb-pll.o obj-$(CONFIG_DVB_STV0299) += stv0299.o diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c index 335219ebce2d..1dc164d5488c 100644 --- a/drivers/media/dvb/frontends/cx22702.c +++ b/drivers/media/dvb/frontends/cx22702.c @@ -32,7 +32,6 @@ #include <linux/slab.h> #include <linux/delay.h> #include "dvb_frontend.h" -#include "dvb-pll.h" #include "cx22702.h" diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c index 732e94aaa364..0834c0677fef 100644 --- a/drivers/media/dvb/frontends/cx24123.c +++ b/drivers/media/dvb/frontends/cx24123.c @@ -917,7 +917,7 @@ static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) static int cx24123_tune(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, unsigned int mode_flags, - int *delay, + unsigned int *delay, fe_status_t *status) { int retval = 0; diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 5f96ffda91ad..0c0b94767bc1 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -24,6 +24,23 @@ #include "dvb-pll.h" +struct dvb_pll_desc { + char *name; + u32 min; + u32 max; + u32 iffreq; + void (*set)(u8 *buf, const struct dvb_frontend_parameters *params); + u8 *initdata; + u8 *sleepdata; + int count; + struct { + u32 limit; + u32 stepsize; + u8 config; + u8 cb; + } entries[12]; +}; + /* ----------------------------------------------------------- */ /* descriptions */ @@ -38,7 +55,13 @@ 0x50 = AGC Take over point = 103 dBuV */ static u8 tua603x_agc103[] = { 2, 0x80|0x40|0x18|0x06|0x01, 0x00|0x50 }; -struct dvb_pll_desc dvb_pll_thomson_dtt7579 = { +/* 0x04 = 166.67 kHz divider + + 0x80 = AGC Time constant 50ms Iagc = 9 uA + 0x20 = AGC Take over point = 112 dBuV */ +static u8 tua603x_agc112[] = { 2, 0x80|0x40|0x18|0x04|0x01, 0x80|0x20 }; + +static struct dvb_pll_desc dvb_pll_thomson_dtt7579 = { .name = "Thomson dtt7579", .min = 177000000, .max = 858000000, @@ -52,9 +75,8 @@ struct dvb_pll_desc dvb_pll_thomson_dtt7579 = { { 999999999, 166667, 0xf4, 0x08 }, }, }; -EXPORT_SYMBOL(dvb_pll_thomson_dtt7579); -struct dvb_pll_desc dvb_pll_thomson_dtt7610 = { +static struct dvb_pll_desc dvb_pll_thomson_dtt7610 = { .name = "Thomson dtt7610", .min = 44000000, .max = 958000000, @@ -66,19 +88,19 @@ struct dvb_pll_desc dvb_pll_thomson_dtt7610 = { { 999999999, 62500, 0x8e, 0x3c }, }, }; -EXPORT_SYMBOL(dvb_pll_thomson_dtt7610); -static void thomson_dtt759x_bw(u8 *buf, u32 freq, int bandwidth) +static void thomson_dtt759x_bw(u8 *buf, + const struct dvb_frontend_parameters *params) { - if (BANDWIDTH_7_MHZ == bandwidth) + if (BANDWIDTH_7_MHZ == params->u.ofdm.bandwidth) buf[3] |= 0x10; } -struct dvb_pll_desc dvb_pll_thomson_dtt759x = { +static struct dvb_pll_desc dvb_pll_thomson_dtt759x = { .name = "Thomson dtt759x", .min = 177000000, .max = 896000000, - .setbw = thomson_dtt759x_bw, + .set = thomson_dtt759x_bw, .iffreq= 36166667, .sleepdata = (u8[]){ 2, 0x84, 0x03 }, .count = 5, @@ -90,9 +112,8 @@ struct dvb_pll_desc dvb_pll_thomson_dtt759x = { { 999999999, 166667, 0xfc, 0x08 }, }, }; -EXPORT_SYMBOL(dvb_pll_thomson_dtt759x); -struct dvb_pll_desc dvb_pll_lg_z201 = { +static struct dvb_pll_desc dvb_pll_lg_z201 = { .name = "LG z201", .min = 174000000, .max = 862000000, @@ -107,9 +128,8 @@ struct dvb_pll_desc dvb_pll_lg_z201 = { { 999999999, 166667, 0xfc, 0x04 }, }, }; -EXPORT_SYMBOL(dvb_pll_lg_z201); -struct dvb_pll_desc dvb_pll_microtune_4042 = { +static struct dvb_pll_desc dvb_pll_microtune_4042 = { .name = "Microtune 4042 FI5", .min = 57000000, .max = 858000000, @@ -121,9 +141,8 @@ struct dvb_pll_desc dvb_pll_microtune_4042 = { { 999999999, 62500, 0x8e, 0x31 }, }, }; -EXPORT_SYMBOL(dvb_pll_microtune_4042); -struct dvb_pll_desc dvb_pll_thomson_dtt761x = { +static struct dvb_pll_desc dvb_pll_thomson_dtt761x = { /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */ .name = "Thomson dtt761x", .min = 57000000, @@ -137,9 +156,8 @@ struct dvb_pll_desc dvb_pll_thomson_dtt761x = { { 999999999, 62500, 0x8e, 0x3c }, }, }; -EXPORT_SYMBOL(dvb_pll_thomson_dtt761x); -struct dvb_pll_desc dvb_pll_unknown_1 = { +static struct dvb_pll_desc dvb_pll_unknown_1 = { .name = "unknown 1", /* used by dntv live dvb-t */ .min = 174000000, .max = 862000000, @@ -157,12 +175,11 @@ struct dvb_pll_desc dvb_pll_unknown_1 = { { 999999999, 166667, 0xfc, 0x08 }, }, }; -EXPORT_SYMBOL(dvb_pll_unknown_1); /* Infineon TUA6010XS * used in Thomson Cable Tuner */ -struct dvb_pll_desc dvb_pll_tua6010xs = { +static struct dvb_pll_desc dvb_pll_tua6010xs = { .name = "Infineon TUA6010XS", .min = 44250000, .max = 858000000, @@ -174,10 +191,9 @@ struct dvb_pll_desc dvb_pll_tua6010xs = { { 999999999, 62500, 0x8e, 0x85 }, }, }; -EXPORT_SYMBOL(dvb_pll_tua6010xs); /* Panasonic env57h1xd5 (some Philips PLL ?) */ -struct dvb_pll_desc dvb_pll_env57h1xd5 = { +static struct dvb_pll_desc dvb_pll_env57h1xd5 = { .name = "Panasonic ENV57H1XD5", .min = 44250000, .max = 858000000, @@ -190,23 +206,23 @@ struct dvb_pll_desc dvb_pll_env57h1xd5 = { { 999999999, 166667, 0xc2, 0xa4 }, }, }; -EXPORT_SYMBOL(dvb_pll_env57h1xd5); /* Philips TDA6650/TDA6651 * used in Panasonic ENV77H11D5 */ -static void tda665x_bw(u8 *buf, u32 freq, int bandwidth) +static void tda665x_bw(u8 *buf, const struct dvb_frontend_parameters *params) { - if (bandwidth == BANDWIDTH_8_MHZ) + if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) buf[3] |= 0x08; } -struct dvb_pll_desc dvb_pll_tda665x = { +static struct dvb_pll_desc dvb_pll_tda665x = { .name = "Philips TDA6650/TDA6651", .min = 44250000, .max = 858000000, - .setbw = tda665x_bw, + .set = tda665x_bw, .iffreq= 36166667, + .initdata = (u8[]){ 4, 0x0b, 0xf5, 0x85, 0xab }, .count = 12, .entries = { { 93834000, 166667, 0xca, 0x61 /* 011 0 0 0 01 */ }, @@ -223,36 +239,34 @@ struct dvb_pll_desc dvb_pll_tda665x = { { 861000000, 166667, 0xca, 0xe4 /* 111 0 0 1 00 */ }, } }; -EXPORT_SYMBOL(dvb_pll_tda665x); /* Infineon TUA6034 * used in LG TDTP E102P */ -static void tua6034_bw(u8 *buf, u32 freq, int bandwidth) +static void tua6034_bw(u8 *buf, const struct dvb_frontend_parameters *params) { - if (BANDWIDTH_7_MHZ != bandwidth) + if (BANDWIDTH_7_MHZ != params->u.ofdm.bandwidth) buf[3] |= 0x08; } -struct dvb_pll_desc dvb_pll_tua6034 = { +static struct dvb_pll_desc dvb_pll_tua6034 = { .name = "Infineon TUA6034", .min = 44250000, .max = 858000000, .iffreq= 36166667, .count = 3, - .setbw = tua6034_bw, + .set = tua6034_bw, .entries = { { 174500000, 62500, 0xce, 0x01 }, { 230000000, 62500, 0xce, 0x02 }, { 999999999, 62500, 0xce, 0x04 }, }, }; -EXPORT_SYMBOL(dvb_pll_tua6034); /* Infineon TUA6034 * used in LG TDVS-H061F, LG TDVS-H062F and LG TDVS-H064F */ -struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = { +static struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = { .name = "LG TDVS-H06xF", .min = 54000000, .max = 863000000, @@ -265,23 +279,25 @@ struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = { { 999999999, 62500, 0xce, 0x04 }, }, }; -EXPORT_SYMBOL(dvb_pll_lg_tdvs_h06xf); /* Philips FMD1216ME * used in Medion Hybrid PCMCIA card and USB Box */ -static void fmd1216me_bw(u8 *buf, u32 freq, int bandwidth) +static void fmd1216me_bw(u8 *buf, const struct dvb_frontend_parameters *params) { - if (bandwidth == BANDWIDTH_8_MHZ && freq >= 158870000) + if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ && + params->frequency >= 158870000) buf[3] |= 0x08; } -struct dvb_pll_desc dvb_pll_fmd1216me = { +static struct dvb_pll_desc dvb_pll_fmd1216me = { .name = "Philips FMD1216ME", .min = 50870000, .max = 858000000, .iffreq= 36125000, - .setbw = fmd1216me_bw, + .set = fmd1216me_bw, + .initdata = tua603x_agc112, + .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 }, .count = 7, .entries = { { 143870000, 166667, 0xbc, 0x41 }, @@ -293,23 +309,22 @@ struct dvb_pll_desc dvb_pll_fmd1216me = { { 999999999, 166667, 0xfc, 0x44 }, } }; -EXPORT_SYMBOL(dvb_pll_fmd1216me); /* ALPS TDED4 * used in Nebula-Cards and USB boxes */ -static void tded4_bw(u8 *buf, u32 freq, int bandwidth) +static void tded4_bw(u8 *buf, const struct dvb_frontend_parameters *params) { - if (bandwidth == BANDWIDTH_8_MHZ) + if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) buf[3] |= 0x04; } -struct dvb_pll_desc dvb_pll_tded4 = { +static struct dvb_pll_desc dvb_pll_tded4 = { .name = "ALPS TDED4", .min = 47000000, .max = 863000000, .iffreq= 36166667, - .setbw = tded4_bw, + .set = tded4_bw, .count = 4, .entries = { { 153000000, 166667, 0x85, 0x01 }, @@ -318,12 +333,11 @@ struct dvb_pll_desc dvb_pll_tded4 = { { 999999999, 166667, 0x85, 0x88 }, } }; -EXPORT_SYMBOL(dvb_pll_tded4); /* ALPS TDHU2 * used in AverTVHD MCE A180 */ -struct dvb_pll_desc dvb_pll_tdhu2 = { +static struct dvb_pll_desc dvb_pll_tdhu2 = { .name = "ALPS TDHU2", .min = 54000000, .max = 864000000, @@ -336,16 +350,29 @@ struct dvb_pll_desc dvb_pll_tdhu2 = { { 999999999, 62500, 0x85, 0x88 }, } }; -EXPORT_SYMBOL(dvb_pll_tdhu2); /* Philips TUV1236D * used in ATI HDTV Wonder */ -struct dvb_pll_desc dvb_pll_tuv1236d = { +static void tuv1236d_rf(u8 *buf, const struct dvb_frontend_parameters *params) +{ + switch (params->u.vsb.modulation) { + case QAM_64: + case QAM_256: + buf[3] |= 0x08; + break; + case VSB_8: + default: + buf[3] &= ~0x08; + } +} + +static struct dvb_pll_desc dvb_pll_tuv1236d = { .name = "Philips TUV1236D", .min = 54000000, .max = 864000000, .iffreq= 44000000, + .set = tuv1236d_rf, .count = 3, .entries = { { 157250000, 62500, 0xc6, 0x41 }, @@ -353,12 +380,11 @@ struct dvb_pll_desc dvb_pll_tuv1236d = { { 999999999, 62500, 0xc6, 0x44 }, }, }; -EXPORT_SYMBOL(dvb_pll_tuv1236d); /* Samsung TBMV30111IN / TBMV30712IN1 * used in Air2PC ATSC - 2nd generation (nxt2002) */ -struct dvb_pll_desc dvb_pll_samsung_tbmv = { +static struct dvb_pll_desc dvb_pll_samsung_tbmv = { .name = "Samsung TBMV30111IN / TBMV30712IN1", .min = 54000000, .max = 860000000, @@ -373,12 +399,11 @@ struct dvb_pll_desc dvb_pll_samsung_tbmv = { { 999999999, 166667, 0xfc, 0x02 }, } }; -EXPORT_SYMBOL(dvb_pll_samsung_tbmv); /* * Philips SD1878 Tuner. */ -struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = { +static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = { .name = "Philips SD1878", .min = 950000, .max = 2150000, @@ -391,19 +416,18 @@ struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = { { 2150000, 500, 0xc4, 0xc0}, }, }; -EXPORT_SYMBOL(dvb_pll_philips_sd1878_tda8261); /* * Philips TD1316 Tuner. */ -static void td1316_bw(u8 *buf, u32 freq, int bandwidth) +static void td1316_bw(u8 *buf, const struct dvb_frontend_parameters *params) { u8 band; /* determine band */ - if (freq < 161000000) + if (params->frequency < 161000000) band = 1; - else if (freq < 444000000) + else if (params->frequency < 444000000) band = 2; else band = 4; @@ -411,16 +435,16 @@ static void td1316_bw(u8 *buf, u32 freq, int bandwidth) buf[3] |= band; /* setup PLL filter */ - if (bandwidth == BANDWIDTH_8_MHZ) + if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) buf[3] |= 1 << 3; } -struct dvb_pll_desc dvb_pll_philips_td1316 = { +static struct dvb_pll_desc dvb_pll_philips_td1316 = { .name = "Philips TD1316", .min = 87000000, .max = 895000000, .iffreq= 36166667, - .setbw = td1316_bw, + .set = td1316_bw, .count = 9, .entries = { { 93834000, 166667, 0xca, 0x60}, @@ -434,10 +458,9 @@ struct dvb_pll_desc dvb_pll_philips_td1316 = { { 858834000, 166667, 0xca, 0xe0}, }, }; -EXPORT_SYMBOL(dvb_pll_philips_td1316); /* FE6600 used on DViCO Hybrid */ -struct dvb_pll_desc dvb_pll_thomson_fe6600 = { +static struct dvb_pll_desc dvb_pll_thomson_fe6600 = { .name = "Thomson FE6600", .min = 44250000, .max = 858000000, @@ -450,19 +473,19 @@ struct dvb_pll_desc dvb_pll_thomson_fe6600 = { { 999999999, 166667, 0xf4, 0x18 }, } }; -EXPORT_SYMBOL(dvb_pll_thomson_fe6600); -static void opera1_bw(u8 *buf, u32 freq, int bandwidth) + +static void opera1_bw(u8 *buf, const struct dvb_frontend_parameters *params) { - if (bandwidth == BANDWIDTH_8_MHZ) + if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) buf[2] |= 0x08; } -struct dvb_pll_desc dvb_pll_opera1 = { +static struct dvb_pll_desc dvb_pll_opera1 = { .name = "Opera Tuner", .min = 900000, .max = 2250000, .iffreq= 0, - .setbw = opera1_bw, + .set = opera1_bw, .count = 8, .entries = { { 1064000, 500, 0xe5, 0xc6 }, @@ -475,7 +498,54 @@ struct dvb_pll_desc dvb_pll_opera1 = { { 2250000, 500, 0xe5, 0xc4 }, } }; -EXPORT_SYMBOL(dvb_pll_opera1); + +/* Philips FCV1236D + */ +struct dvb_pll_desc dvb_pll_fcv1236d = { +/* Bit_0: RF Input select + * Bit_1: 0=digital, 1=analog + */ + .name = "Philips FCV1236D", + .min = 53000000, + .max = 803000000, + .iffreq= 44000000, + .count = 3, + .entries = { + { 159000000, 62500, 0x8e, 0xa0 }, + { 453000000, 62500, 0x8e, 0x90 }, + { 999999999, 62500, 0x8e, 0x30 }, + }, +}; + +/* ----------------------------------------------------------- */ + +static struct dvb_pll_desc *pll_list[] = { + [DVB_PLL_UNDEFINED] = NULL, + [DVB_PLL_THOMSON_DTT7579] = &dvb_pll_thomson_dtt7579, + [DVB_PLL_THOMSON_DTT759X] = &dvb_pll_thomson_dtt759x, + [DVB_PLL_THOMSON_DTT7610] = &dvb_pll_thomson_dtt7610, + [DVB_PLL_LG_Z201] = &dvb_pll_lg_z201, + [DVB_PLL_MICROTUNE_4042] = &dvb_pll_microtune_4042, + [DVB_PLL_THOMSON_DTT761X] = &dvb_pll_thomson_dtt761x, + [DVB_PLL_UNKNOWN_1] = &dvb_pll_unknown_1, + [DVB_PLL_TUA6010XS] = &dvb_pll_tua6010xs, + [DVB_PLL_ENV57H1XD5] = &dvb_pll_env57h1xd5, + [DVB_PLL_TUA6034] = &dvb_pll_tua6034, + [DVB_PLL_LG_TDVS_H06XF] = &dvb_pll_lg_tdvs_h06xf, + [DVB_PLL_TDA665X] = &dvb_pll_tda665x, + [DVB_PLL_FMD1216ME] = &dvb_pll_fmd1216me, + [DVB_PLL_TDED4] = &dvb_pll_tded4, + [DVB_PLL_TUV1236D] = &dvb_pll_tuv1236d, + [DVB_PLL_TDHU2] = &dvb_pll_tdhu2, + [DVB_PLL_SAMSUNG_TBMV] = &dvb_pll_samsung_tbmv, + [DVB_PLL_PHILIPS_SD1878_TDA8261] = &dvb_pll_philips_sd1878_tda8261, + [DVB_PLL_PHILIPS_TD1316] = &dvb_pll_philips_td1316, + [DVB_PLL_THOMSON_FE6600] = &dvb_pll_thomson_fe6600, + [DVB_PLL_OPERA1] = &dvb_pll_opera1, + [DVB_PLL_FCV1236D] = &dvb_pll_fcv1236d, +}; + +/* ----------------------------------------------------------- */ struct dvb_pll_priv { /* i2c details */ @@ -497,35 +567,37 @@ static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); -int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, - u32 freq, int bandwidth) +static int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, + const struct dvb_frontend_parameters *params) { u32 div; int i; - if (freq != 0 && (freq < desc->min || freq > desc->max)) - return -EINVAL; + if (params->frequency != 0 && (params->frequency < desc->min || + params->frequency > desc->max)) + return -EINVAL; for (i = 0; i < desc->count; i++) { - if (freq > desc->entries[i].limit) + if (params->frequency > desc->entries[i].limit) continue; break; } + if (debug) - printk("pll: %s: freq=%d bw=%d | i=%d/%d\n", - desc->name, freq, bandwidth, i, desc->count); + printk("pll: %s: freq=%d | i=%d/%d\n", desc->name, + params->frequency, i, desc->count); if (i == desc->count) return -EINVAL; - div = (freq + desc->iffreq + desc->entries[i].stepsize/2) / - desc->entries[i].stepsize; + div = (params->frequency + desc->iffreq + + desc->entries[i].stepsize/2) / desc->entries[i].stepsize; buf[0] = div >> 8; buf[1] = div & 0xff; buf[2] = desc->entries[i].config; buf[3] = desc->entries[i].cb; - if (desc->setbw) - desc->setbw(buf, freq, bandwidth); + if (desc->set) + desc->set(buf, params); if (debug) printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n", @@ -534,7 +606,6 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, // calculate the frequency we set it to return (div * desc->entries[i].stepsize) - desc->iffreq; } -EXPORT_SYMBOL(dvb_pll_configure); static int dvb_pll_release(struct dvb_frontend *fe) { @@ -578,18 +649,12 @@ static int dvb_pll_set_params(struct dvb_frontend *fe, { .addr = priv->pll_i2c_address, .flags = 0, .buf = buf, .len = sizeof(buf) }; int result; - u32 bandwidth = 0, frequency = 0; + u32 frequency = 0; if (priv->i2c == NULL) return -EINVAL; - // DVBT bandwidth only just now - if (fe->ops.info.type == FE_OFDM) { - bandwidth = params->u.ofdm.bandwidth; - } - - if ((result = dvb_pll_configure(priv->pll_desc, buf, - params->frequency, bandwidth)) < 0) + if ((result = dvb_pll_configure(priv->pll_desc, buf, params)) < 0) return result; else frequency = result; @@ -601,7 +666,7 @@ static int dvb_pll_set_params(struct dvb_frontend *fe, } priv->frequency = frequency; - priv->bandwidth = bandwidth; + priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; return 0; } @@ -612,18 +677,12 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe, { struct dvb_pll_priv *priv = fe->tuner_priv; int result; - u32 bandwidth = 0, frequency = 0; + u32 frequency = 0; if (buf_len < 5) return -EINVAL; - // DVBT bandwidth only just now - if (fe->ops.info.type == FE_OFDM) { - bandwidth = params->u.ofdm.bandwidth; - } - - if ((result = dvb_pll_configure(priv->pll_desc, buf+1, - params->frequency, bandwidth)) < 0) + if ((result = dvb_pll_configure(priv->pll_desc, buf+1, params)) < 0) return result; else frequency = result; @@ -631,7 +690,7 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe, buf[0] = priv->pll_i2c_address; priv->frequency = frequency; - priv->bandwidth = bandwidth; + priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; return 5; } @@ -687,13 +746,18 @@ static struct dvb_tuner_ops dvb_pll_tuner_ops = { struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, - struct dvb_pll_desc *desc) + unsigned int pll_desc_id) { u8 b1 [] = { 0 }; struct i2c_msg msg = { .addr = pll_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 }; struct dvb_pll_priv *priv = NULL; int ret; + struct dvb_pll_desc *desc; + + BUG_ON(pll_desc_id < 1 || pll_desc_id >= ARRAY_SIZE(pll_list)); + + desc = pll_list[pll_desc_id]; if (i2c != NULL) { if (fe->ops.i2c_gate_ctrl) diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h index 5209f46f0893..e93a8104052b 100644 --- a/drivers/media/dvb/frontends/dvb-pll.h +++ b/drivers/media/dvb/frontends/dvb-pll.h @@ -8,50 +8,29 @@ #include <linux/i2c.h> #include "dvb_frontend.h" -struct dvb_pll_desc { - char *name; - u32 min; - u32 max; - u32 iffreq; - void (*setbw)(u8 *buf, u32 freq, int bandwidth); - u8 *initdata; - u8 *sleepdata; - int count; - struct { - u32 limit; - u32 stepsize; - u8 config; - u8 cb; - } entries[12]; -}; - -extern struct dvb_pll_desc dvb_pll_thomson_dtt7579; -extern struct dvb_pll_desc dvb_pll_thomson_dtt759x; -extern struct dvb_pll_desc dvb_pll_thomson_dtt7610; -extern struct dvb_pll_desc dvb_pll_lg_z201; -extern struct dvb_pll_desc dvb_pll_microtune_4042; -extern struct dvb_pll_desc dvb_pll_thomson_dtt761x; -extern struct dvb_pll_desc dvb_pll_unknown_1; - -extern struct dvb_pll_desc dvb_pll_tua6010xs; -extern struct dvb_pll_desc dvb_pll_env57h1xd5; -extern struct dvb_pll_desc dvb_pll_tua6034; -extern struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf; -extern struct dvb_pll_desc dvb_pll_tda665x; -extern struct dvb_pll_desc dvb_pll_fmd1216me; -extern struct dvb_pll_desc dvb_pll_tded4; - -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; -extern struct dvb_pll_desc dvb_pll_opera1; - -extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, - u32 freq, int bandwidth); +#define DVB_PLL_UNDEFINED 0 +#define DVB_PLL_THOMSON_DTT7579 1 +#define DVB_PLL_THOMSON_DTT759X 2 +#define DVB_PLL_THOMSON_DTT7610 3 +#define DVB_PLL_LG_Z201 4 +#define DVB_PLL_MICROTUNE_4042 5 +#define DVB_PLL_THOMSON_DTT761X 6 +#define DVB_PLL_UNKNOWN_1 7 +#define DVB_PLL_TUA6010XS 8 +#define DVB_PLL_ENV57H1XD5 9 +#define DVB_PLL_TUA6034 10 +#define DVB_PLL_LG_TDVS_H06XF 11 +#define DVB_PLL_TDA665X 12 +#define DVB_PLL_FMD1216ME 13 +#define DVB_PLL_TDED4 14 +#define DVB_PLL_TUV1236D 15 +#define DVB_PLL_TDHU2 16 +#define DVB_PLL_SAMSUNG_TBMV 17 +#define DVB_PLL_PHILIPS_SD1878_TDA8261 18 +#define DVB_PLL_PHILIPS_TD1316 19 +#define DVB_PLL_THOMSON_FE6600 20 +#define DVB_PLL_OPERA1 21 +#define DVB_PLL_FCV1236D 22 /** * Attach a dvb-pll to the supplied frontend structure. @@ -59,19 +38,19 @@ extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, * @param fe Frontend to attach to. * @param pll_addr i2c address of the PLL (if used). * @param i2c i2c adapter to use (set to NULL if not used). - * @param desc dvb_pll_desc to use. + * @param pll_desc_id dvb_pll_desc to use. * @return Frontend pointer on success, NULL on failure */ #if defined(CONFIG_DVB_PLL) || (defined(CONFIG_DVB_PLL_MODULE) && defined(MODULE)) extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, - struct dvb_pll_desc *desc); + unsigned int pll_desc_id); #else static inline struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, - struct dvb_pll_desc *desc) + unsigned int pll_desc_id) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); return NULL; diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c index b809f83d9563..ddc84899cf86 100644 --- a/drivers/media/dvb/frontends/nxt200x.c +++ b/drivers/media/dvb/frontends/nxt200x.c @@ -49,7 +49,6 @@ #include <linux/string.h> #include "dvb_frontend.h" -#include "dvb-pll.h" #include "nxt200x.h" struct nxt200x_state { @@ -546,11 +545,6 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe, nxt200x_writebytes(state, 0x17, buf, 1); } - /* get tuning information */ - if (fe->ops.tuner_ops.calc_regs) { - fe->ops.tuner_ops.calc_regs(fe, p, buf, 5); - } - /* set additional params */ switch (p->u.vsb.modulation) { case QAM_64: @@ -559,27 +553,24 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe, /* This is just a guess since I am unable to test it */ if (state->config->set_ts_params) state->config->set_ts_params(fe, 1); - - /* set input */ - if (state->config->set_pll_input) - state->config->set_pll_input(buf+1, 1); break; case VSB_8: /* Set non-punctured clock for VSB */ if (state->config->set_ts_params) state->config->set_ts_params(fe, 0); - - /* set input */ - if (state->config->set_pll_input) - state->config->set_pll_input(buf+1, 0); break; default: return -EINVAL; break; } - /* write frequency information */ - nxt200x_writetuner(state, buf); + if (fe->ops.tuner_ops.calc_regs) { + /* get tuning information */ + fe->ops.tuner_ops.calc_regs(fe, p, buf, 5); + + /* write frequency information */ + nxt200x_writetuner(state, buf); + } /* reset the agc now that tuning has been completed */ nxt200x_agc_reset(state); diff --git a/drivers/media/dvb/frontends/nxt200x.h b/drivers/media/dvb/frontends/nxt200x.h index 28bc5591b319..bb0ef58d7972 100644 --- a/drivers/media/dvb/frontends/nxt200x.h +++ b/drivers/media/dvb/frontends/nxt200x.h @@ -38,9 +38,6 @@ struct nxt200x_config /* the demodulator's i2c address */ u8 demod_address; - /* used to set pll input */ - int (*set_pll_input)(u8* buf, int input); - /* need to set device param for start_dma */ int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); }; diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c index 4e0aca7c67aa..3cc8b444b8f2 100644 --- a/drivers/media/dvb/frontends/or51132.c +++ b/drivers/media/dvb/frontends/or51132.c @@ -45,7 +45,6 @@ #include "dvb_math.h" #include "dvb_frontend.h" -#include "dvb-pll.h" #include "or51132.h" static int debug; diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c index 048d7cfe12d3..f46d5a46683a 100644 --- a/drivers/media/dvb/frontends/or51211.c +++ b/drivers/media/dvb/frontends/or51211.c @@ -223,38 +223,13 @@ static int or51211_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_parameters *param) { struct or51211_state* state = fe->demodulator_priv; - u32 freq = 0; - u16 tunerfreq = 0; - u8 buf[4]; /* Change only if we are actually changing the channel */ if (state->current_frequency != param->frequency) { - freq = 44000 + (param->frequency/1000); - tunerfreq = freq * 16/1000; - - dprintk("set_parameters frequency = %d (tunerfreq = %d)\n", - param->frequency,tunerfreq); - - buf[0] = (tunerfreq >> 8) & 0x7F; - buf[1] = (tunerfreq & 0xFF); - buf[2] = 0x8E; - - if (param->frequency < 157250000) { - buf[3] = 0xA0; - dprintk("set_parameters VHF low range\n"); - } else if (param->frequency < 454000000) { - buf[3] = 0x90; - dprintk("set_parameters VHF high range\n"); - } else { - buf[3] = 0x30; - dprintk("set_parameters UHF range\n"); + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, param); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } - dprintk("set_parameters tuner bytes: 0x%02x 0x%02x " - "0x%02x 0x%02x\n",buf[0],buf[1],buf[2],buf[3]); - - if (i2c_writebytes(state,0xC2>>1,buf,4)) - printk(KERN_WARNING "or51211:set_parameters error " - "writing to tuner\n"); /* Set to ATSC mode */ or51211_setmode(fe,0); diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index 18768d2f6d40..6c607302c1b6 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c @@ -249,7 +249,7 @@ static int stv0299_get_symbolrate (struct stv0299_state* state) dprintk ("%s\n", __FUNCTION__); stv0299_readregs (state, 0x1f, sfr, 3); - stv0299_readregs (state, 0x1a, &rtf, 1); + stv0299_readregs (state, 0x1a, (u8 *)&rtf, 1); srate = (sfr[0] << 8) | sfr[1]; srate *= Mclk; diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c index da796e784be3..4bb06f97938b 100644 --- a/drivers/media/dvb/frontends/tda10023.c +++ b/drivers/media/dvb/frontends/tda10023.c @@ -478,7 +478,7 @@ struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config, state->i2c = i2c; memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops)); state->pwm = pwm; - for (i=0; i < sizeof(tda10023_inittab)/sizeof(*tda10023_inittab);i+=3) { + for (i=0; i < ARRAY_SIZE(tda10023_inittab);i+=3) { if (tda10023_inittab[i] == 0x00) { state->reg0 = tda10023_inittab[i+2]; break; diff --git a/drivers/media/dvb/pluto2/Makefile b/drivers/media/dvb/pluto2/Makefile index ce6a9aaf937e..7ac128724df8 100644 --- a/drivers/media/dvb/pluto2/Makefile +++ b/drivers/media/dvb/pluto2/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_DVB_PLUTO2) += pluto2.o -EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index 7751628e1415..6d53289b3276 100644 --- a/drivers/media/dvb/ttpci/Kconfig +++ b/drivers/media/dvb/ttpci/Kconfig @@ -108,7 +108,7 @@ config DVB_BUDGET_AV tristate "Budget cards with analog video inputs" depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 select VIDEO_SAA7146_VV - select DVB_PLL + select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_TDA1004X if !DVB_FE_CUSTOMISE select DVB_TDA10021 if !DVB_FE_CUSTOMISE diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile index aa85ecdc6c80..2c1145236ee6 100644 --- a/drivers/media/dvb/ttpci/Makefile +++ b/drivers/media/dvb/ttpci/Makefile @@ -11,7 +11,7 @@ obj-$(CONFIG_DVB_BUDGET_CI) += budget-core.o budget-ci.o ttpci-eeprom.o obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-core.o budget-patch.o ttpci-eeprom.o obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o ttpci-eeprom.o -EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ hostprogs-y := fdump diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index ef1108c0bf11..2cee9e3bd29f 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -137,6 +137,15 @@ 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, SetMonitorType, + 1, (u16) av7110->display_ar); + if (ret < 0) + printk("dvb-ttpci: unable to set aspect ratio\n"); + ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType, + 1, av7110->display_panscan); + if (ret < 0) + printk("dvb-ttpci: unable to set pan scan\n"); + 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"); @@ -2639,12 +2648,12 @@ static int __devinit av7110_attach(struct saa7146_dev* dev, av7110->mixer.volume_left = volume; av7110->mixer.volume_right = volume; - init_av7110_av(av7110); - ret = av7110_register(av7110); if (ret < 0) goto err_arm_thread_stop_10; + init_av7110_av(av7110); + /* special case DVB-C: these cards have an analog tuner plus need some special handling, so we have separate saa7146_ext_vv data for these... */ diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h index 115002b0390c..0cb439527498 100644 --- a/drivers/media/dvb/ttpci/av7110.h +++ b/drivers/media/dvb/ttpci/av7110.h @@ -194,6 +194,7 @@ struct av7110 { int video_blank; struct video_status videostate; + u16 display_panscan; int display_ar; int trickmode; #define TRICK_NONE 0 diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index 58678c05aa53..d75e7e48addc 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c @@ -391,7 +391,7 @@ static int get_video_format(struct av7110 *av7110, u8 *buf, int count) ****************************************************************************/ static inline long aux_ring_buffer_write(struct dvb_ringbuffer *rbuf, - const char *buf, unsigned long count) + const u8 *buf, unsigned long count) { unsigned long todo = count; int free; @@ -436,7 +436,7 @@ static void play_audio_cb(u8 *buf, int count, void *priv) #define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \ dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024) -static ssize_t dvb_play(struct av7110 *av7110, const u8 __user *buf, +static ssize_t dvb_play(struct av7110 *av7110, const char __user *buf, unsigned long count, int nonblock, int type) { unsigned long todo = count, n; @@ -499,7 +499,7 @@ static ssize_t dvb_play_kernel(struct av7110 *av7110, const u8 *buf, return count - todo; } -static ssize_t dvb_aplay(struct av7110 *av7110, const u8 __user *buf, +static ssize_t dvb_aplay(struct av7110 *av7110, const char __user *buf, unsigned long count, int nonblock, int type) { unsigned long todo = count, n; @@ -959,7 +959,7 @@ static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x #define MIN_IFRAME 400000 -static int play_iframe(struct av7110 *av7110, u8 __user *buf, unsigned int len, int nonblock) +static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len, int nonblock) { int i, n; @@ -1082,19 +1082,18 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, case VIDEO_SET_DISPLAY_FORMAT: { video_displayformat_t format = (video_displayformat_t) arg; - u16 val = 0; switch (format) { case VIDEO_PAN_SCAN: - val = VID_PAN_SCAN_PREF; + av7110->display_panscan = VID_PAN_SCAN_PREF; break; case VIDEO_LETTER_BOX: - val = VID_VC_AND_PS_PREF; + av7110->display_panscan = VID_VC_AND_PS_PREF; break; case VIDEO_CENTER_CUT_OUT: - val = VID_CENTRE_CUT_PREF; + av7110->display_panscan = VID_CENTRE_CUT_PREF; break; default: @@ -1104,7 +1103,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, break; av7110->videostate.display_format = format; ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType, - 1, (u16) val); + 1, av7110->display_panscan); break; } @@ -1466,8 +1465,9 @@ int av7110_av_register(struct av7110 *av7110) av7110->videostate.play_state = VIDEO_STOPPED; av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX; av7110->videostate.video_format = VIDEO_FORMAT_4_3; - av7110->videostate.display_format = VIDEO_CENTER_CUT_OUT; + av7110->videostate.display_format = VIDEO_LETTER_BOX; av7110->display_ar = VIDEO_FORMAT_4_3; + av7110->display_panscan = VID_VC_AND_PS_PREF; init_waitqueue_head(&av7110->video_events.wait_queue); spin_lock_init(&av7110->video_events.lock); diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c index e1c1294bb767..c58e3fc509ed 100644 --- a/drivers/media/dvb/ttpci/av7110_ca.c +++ b/drivers/media/dvb/ttpci/av7110_ca.c @@ -151,7 +151,7 @@ static ssize_t ci_ll_write(struct dvb_ringbuffer *cibuf, struct file *file, { int free; int non_blocking = file->f_flags & O_NONBLOCK; - char *page = (char *)__get_free_page(GFP_USER); + u8 *page = (u8 *)__get_free_page(GFP_USER); int res; if (!page) @@ -208,7 +208,7 @@ static ssize_t ci_ll_read(struct dvb_ringbuffer *cibuf, struct file *file, return -EINVAL; DVB_RINGBUFFER_SKIP(cibuf, 2); - return dvb_ringbuffer_read(cibuf, buf, len, 1); + return dvb_ringbuffer_read(cibuf, (u8 *)buf, len, 1); } static int dvb_ca_open(struct inode *inode, struct file *file) diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c index 70aee4eb5da4..515e8232e020 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.c +++ b/drivers/media/dvb/ttpci/av7110_hw.c @@ -158,7 +158,7 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len) } dprintk(4, "writing DRAM block %d\n", i); mwdebi(av7110, DEBISWAB, bootblock, - ((char*)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE); + ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE); bootblock ^= 0x1400; iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4); iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2); @@ -173,10 +173,10 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len) } if (rest > 4) mwdebi(av7110, DEBISWAB, bootblock, - ((char*)data) + i * AV7110_BOOT_MAX_SIZE, rest); + ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, rest); else mwdebi(av7110, DEBISWAB, bootblock, - ((char*)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4); + ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4); iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4); iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2); @@ -751,7 +751,7 @@ static int FlushText(struct av7110 *av7110) return 0; } -static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf) +static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, char *buf) { int i, ret; unsigned long start; diff --git a/drivers/media/dvb/ttpci/av7110_hw.h b/drivers/media/dvb/ttpci/av7110_hw.h index 673d9b3f064c..74d940f75da6 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.h +++ b/drivers/media/dvb/ttpci/av7110_hw.h @@ -393,7 +393,7 @@ static inline void iwdebi(struct av7110 *av7110, u32 config, int addr, u32 val, } /* buffer writes */ -static inline void mwdebi(struct av7110 *av7110, u32 config, int addr, char *val, int count) +static inline void mwdebi(struct av7110 *av7110, u32 config, int addr, u8 *val, int count) { memcpy(av7110->debi_virt, val, count); av7110_debiwrite(av7110, config, addr, 0, count); diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c index a97f166bb523..6322800ee12b 100644 --- a/drivers/media/dvb/ttpci/av7110_ir.c +++ b/drivers/media/dvb/ttpci/av7110_ir.c @@ -356,7 +356,7 @@ int __devinit av7110_ir_init(struct av7110 *av7110) input_dev->id.vendor = av7110->dev->pci->vendor; input_dev->id.product = av7110->dev->pci->device; } - input_dev->cdev.dev = &av7110->dev->pci->dev; + input_dev->dev.parent = &av7110->dev->pci->dev; /* initial keymap */ memcpy(av7110->ir.key_map, default_key_map, sizeof av7110->ir.key_map); input_register_keys(&av7110->ir); diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c index fcd9994058d0..87afaebc0703 100644 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/drivers/media/dvb/ttpci/av7110_v4l.c @@ -333,7 +333,7 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) return -EINVAL; memset(t, 0, sizeof(*t)); - strcpy(t->name, "Television"); + strcpy((char *)t->name, "Television"); t->type = V4L2_TUNER_ANALOG_TV; t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 0e817d6f1ce5..0aee7a13a070 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -828,29 +828,6 @@ static u8 philips_sd1878_inittab[] = { 0xff, 0xff }; -static int philips_sd1878_tda8261_tuner_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - u8 buf[4]; - int rc; - struct i2c_msg tuner_msg = {.addr=0x60,.flags=0,.buf=buf,.len=sizeof(buf)}; - struct budget *budget = (struct budget *) fe->dvb->priv; - - if((params->frequency < 950000) || (params->frequency > 2150000)) - return -EINVAL; - - rc=dvb_pll_configure(&dvb_pll_philips_sd1878_tda8261, buf, - params->frequency, 0); - if(rc < 0) return rc; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if(i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1) - return -EIO; - - return 0; -} - static int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio) { @@ -921,6 +898,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_1 0x001a +#define SUBID_DVBS_EASYWATCH_2 0x001b #define SUBID_DVBS_EASYWATCH 0x001e #define SUBID_DVBC_EASYWATCH 0x002a @@ -982,10 +960,13 @@ static void frontend_init(struct budget_av *budget_av) case SUBID_DVBS_TV_STAR_CI: case SUBID_DVBS_CYNERGY1200N: case SUBID_DVBS_EASYWATCH: + case SUBID_DVBS_EASYWATCH_2: fe = dvb_attach(stv0299_attach, &philips_sd1878_config, &budget_av->budget.i2c_adap); if (fe) { - fe->ops.tuner_ops.set_params = philips_sd1878_tda8261_tuner_set_params; + dvb_attach(dvb_pll_attach, fe, 0x60, + &budget_av->budget.i2c_adap, + DVB_PLL_PHILIPS_SD1878_TDA8261); } break; @@ -1264,6 +1245,7 @@ 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(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S); +MAKE_BUDGET_INFO(satewps, "Satelco EasyWatch DVB-S", BUDGET_KNC1S); MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP); MAKE_BUDGET_INFO(satewcmk3, "Satelco EasyWatch DVB-C MK3", BUDGET_KNC1C_MK3); MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP); @@ -1287,6 +1269,7 @@ static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016), MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e), MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a), + MAKE_EXTENSION_PCI(satewps, 0x1894, 0x001b), MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a), MAKE_EXTENSION_PCI(satewcmk3, 0x1894, 0x002c), MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020), diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 9d42f88ebb0e..873c3ba296f2 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -206,7 +206,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci) input_dev->id.vendor = saa->pci->vendor; input_dev->id.product = saa->pci->device; } - input_dev->cdev.dev = &saa->pci->dev; + input_dev->dev.parent = &saa->pci->dev; /* Select keymap and address */ switch (budget_ci->budget.dev->pci->subsystem_device) { diff --git a/drivers/media/dvb/ttusb-budget/Makefile b/drivers/media/dvb/ttusb-budget/Makefile index 6ab97f6b53fc..fbe2b9514c21 100644 --- a/drivers/media/dvb/ttusb-budget/Makefile +++ b/drivers/media/dvb/ttusb-budget/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_DVB_TTUSB_BUDGET) += dvb-ttusb-budget.o -EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends diff --git a/drivers/media/dvb/ttusb-dec/Makefile b/drivers/media/dvb/ttusb-dec/Makefile index b41bf1f06a9f..2d70a8269391 100644 --- a/drivers/media/dvb/ttusb-dec/Makefile +++ b/drivers/media/dvb/ttusb-dec/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o ttusbdecfe.o -EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 194b102140ef..f8bf9fe37d36 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -324,8 +324,8 @@ config RADIO_ZOLTRIX_PORT Enter the I/O port of your Zoltrix radio card. config USB_DSBR - tristate "D-Link USB FM radio support (EXPERIMENTAL)" - depends on USB && VIDEO_V4L2 && EXPERIMENTAL + tristate "D-Link/GemTek USB FM radio support" + depends on USB && VIDEO_V4L2 ---help--- Say Y here if you want to connect this type of radio to your computer's USB port. Note that the audio is not digital, and diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index 5adc27c3ced9..ce940b1b787f 100644 --- a/drivers/media/radio/radio-aimslab.c +++ b/drivers/media/radio/radio-aimslab.c @@ -392,7 +392,6 @@ static struct video_device rtrack_radio= .owner = THIS_MODULE, .name = "RadioTrack radio", .type = VID_TYPE_TUNER, - .hardware = 0, .fops = &rtrack_fops, .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c index 9f1addae6928..9b1f7a99dac0 100644 --- a/drivers/media/radio/radio-aztech.c +++ b/drivers/media/radio/radio-aztech.c @@ -355,7 +355,6 @@ static struct video_device aztech_radio= .owner = THIS_MODULE, .name = "Aztech radio", .type = VID_TYPE_TUNER, - .hardware = 0, .fops = &aztech_fops, .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c index 5e6f17df204b..4db05b2b1b6e 100644 --- a/drivers/media/radio/radio-gemtek-pci.c +++ b/drivers/media/radio/radio-gemtek-pci.c @@ -377,7 +377,6 @@ static struct video_device vdev_template = { .owner = THIS_MODULE, .name = "Gemtek PCI Radio", .type = VID_TYPE_TUNER, - .hardware = 0, .fops = &gemtek_pci_fops, .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index b04b6a7fff7c..eab8c80a2e47 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -330,7 +330,6 @@ static struct video_device gemtek_radio= .owner = THIS_MODULE, .name = "GemTek radio", .type = VID_TYPE_TUNER, - .hardware = 0, .fops = &gemtek_fops, .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c index 9b493b3298cd..82aedfc95d4f 100644 --- a/drivers/media/radio/radio-rtrack2.c +++ b/drivers/media/radio/radio-rtrack2.c @@ -297,7 +297,6 @@ static struct video_device rtrack2_radio= .owner = THIS_MODULE, .name = "RadioTrack II radio", .type = VID_TYPE_TUNER, - .hardware = 0, .fops = &rtrack2_fops, .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index dc33f19c0e2c..395165367f37 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -297,7 +297,6 @@ static struct video_device fmi_radio= .owner = THIS_MODULE, .name = "SF16FMx radio", .type = VID_TYPE_TUNER, - .hardware = 0, .fops = &fmi_fops, .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index e6c125def5cb..c432c44bd634 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -442,7 +442,6 @@ static struct video_device fmr2_radio= .owner = THIS_MODULE, .name = "SF16FMR2 radio", . type = VID_TYPE_TUNER, - .hardware = 0, .fops = &fmr2_fops, .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c index e43acfd7e533..7e1911c3d54e 100644 --- a/drivers/media/radio/radio-terratec.c +++ b/drivers/media/radio/radio-terratec.c @@ -369,7 +369,6 @@ static struct video_device terratec_radio= .owner = THIS_MODULE, .name = "TerraTec ActiveRadio", .type = VID_TYPE_TUNER, - .hardware = 0, .fops = &terratec_fops, .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c index c27c629d99df..c11981fed827 100644 --- a/drivers/media/radio/radio-trust.c +++ b/drivers/media/radio/radio-trust.c @@ -349,7 +349,6 @@ static struct video_device trust_radio= .owner = THIS_MODULE, .name = "Trust FM Radio", .type = VID_TYPE_TUNER, - .hardware = 0, .fops = &trust_fops, .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c index 8ff5a23a9f01..1366326474e5 100644 --- a/drivers/media/radio/radio-typhoon.c +++ b/drivers/media/radio/radio-typhoon.c @@ -349,7 +349,6 @@ static struct video_device typhoon_radio = .owner = THIS_MODULE, .name = "Typhoon Radio", .type = VID_TYPE_TUNER, - .hardware = 0, .fops = &typhoon_fops, .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 4d45a40016de..9dcbffd0aa15 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -489,6 +489,15 @@ config TUNER_3036 Say Y here to include support for Philips SAB3036 compatible tuners. If in doubt, say N. +config TUNER_TEA5761 + bool "TEA 5761 radio tuner (EXPERIMENTAL)" + depends on EXPERIMENTAL + depends on I2C + select VIDEO_TUNER + help + Say Y here to include support for Philips TEA5761 radio tuner. + If in doubt, say N. + config VIDEO_VINO tristate "SGI Vino Video For Linux (EXPERIMENTAL)" depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2 diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 9c2de501612f..10b4d4469016 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -7,6 +7,8 @@ zr36067-objs := zoran_procfs.o zoran_device.o \ tuner-objs := tuner-core.o tuner-types.o tuner-simple.o \ mt20xx.o tda8290.o tea5767.o tda9887.o +tuner-$(CONFIG_TUNER_TEA5761) += tea5761.o + msp3400-objs := msp3400-driver.o msp3400-kthreads.o obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o @@ -16,7 +18,7 @@ ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y) endif obj-$(CONFIG_VIDEO_BT848) += bt8xx/ -obj-$(CONFIG_VIDEO_BT848) += ir-kbd-i2c.o +obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o @@ -59,7 +61,7 @@ obj-$(CONFIG_VIDEO_CPIA) += cpia.o obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o obj-$(CONFIG_VIDEO_MEYE) += meye.o -obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/ +obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ obj-$(CONFIG_VIDEO_CX88) += cx88/ obj-$(CONFIG_VIDEO_IVTV) += ivtv/ obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c index 823cd6cc471e..cbab53fc6243 100644 --- a/drivers/media/video/adv7170.c +++ b/drivers/media/video/adv7170.c @@ -38,23 +38,23 @@ #include <linux/slab.h> #include <linux/mm.h> #include <linux/signal.h> +#include <linux/types.h> +#include <linux/i2c.h> #include <asm/io.h> #include <asm/pgtable.h> #include <asm/page.h> -#include <linux/types.h> +#include <asm/uaccess.h> #include <linux/videodev.h> -#include <asm/uaccess.h> +#include <linux/video_encoder.h> MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver"); MODULE_AUTHOR("Maxim Yevtyushkin"); MODULE_LICENSE("GPL"); -#include <linux/i2c.h> #define I2C_NAME(x) (x)->name -#include <linux/video_encoder.h> static int debug = 0; module_param(debug, int, 0); diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c index 05c7820fe53e..0d0c554bfdf7 100644 --- a/drivers/media/video/adv7175.c +++ b/drivers/media/video/adv7175.c @@ -34,23 +34,23 @@ #include <linux/slab.h> #include <linux/mm.h> #include <linux/signal.h> +#include <linux/types.h> +#include <linux/i2c.h> #include <asm/io.h> #include <asm/pgtable.h> #include <asm/page.h> -#include <linux/types.h> +#include <asm/uaccess.h> #include <linux/videodev.h> -#include <asm/uaccess.h> +#include <linux/video_encoder.h> MODULE_DESCRIPTION("Analog Devices ADV7175 video encoder driver"); MODULE_AUTHOR("Dave Perks"); MODULE_LICENSE("GPL"); -#include <linux/i2c.h> #define I2C_NAME(s) (s)->name -#include <linux/video_encoder.h> static int debug = 0; module_param(debug, int, 0); diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c index 59a43603b5cb..12d1b9248be5 100644 --- a/drivers/media/video/bt819.c +++ b/drivers/media/video/bt819.c @@ -38,23 +38,24 @@ #include <linux/slab.h> #include <linux/mm.h> #include <linux/signal.h> +#include <linux/types.h> +#include <linux/i2c.h> #include <asm/io.h> #include <asm/pgtable.h> #include <asm/page.h> -#include <linux/types.h> +#include <asm/uaccess.h> #include <linux/videodev.h> -#include <asm/uaccess.h> +#include <linux/video_decoder.h> + MODULE_DESCRIPTION("Brooktree-819 video decoder driver"); MODULE_AUTHOR("Mike Bernson & Dave Perks"); MODULE_LICENSE("GPL"); -#include <linux/i2c.h> #define I2C_NAME(s) (s)->name -#include <linux/video_decoder.h> static int debug = 0; module_param(debug, int, 0); diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c index 853b1a3d6a1d..e1028a76c042 100644 --- a/drivers/media/video/bt856.c +++ b/drivers/media/video/bt856.c @@ -38,23 +38,23 @@ #include <linux/slab.h> #include <linux/mm.h> #include <linux/signal.h> +#include <linux/types.h> +#include <linux/i2c.h> +#include <linux/video_encoder.h> #include <asm/io.h> #include <asm/pgtable.h> #include <asm/page.h> -#include <linux/types.h> +#include <asm/uaccess.h> #include <linux/videodev.h> -#include <asm/uaccess.h> MODULE_DESCRIPTION("Brooktree-856A video encoder driver"); MODULE_AUTHOR("Mike Bernson & Dave Perks"); MODULE_LICENSE("GPL"); -#include <linux/i2c.h> #define I2C_NAME(s) (s)->name -#include <linux/video_encoder.h> static int debug = 0; module_param(debug, int, 0); diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 6b31e50fb951..2aea09c72093 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -178,8 +178,8 @@ static struct CARD { /* this seems to happen as well ... */ { 0xff1211bd, BTTV_BOARD_PINNACLE, "Pinnacle PCTV" }, - { 0x3000121a, BTTV_BOARD_VOODOOTV_FM, "3Dfx VoodooTV FM/ VoodooTV 200" }, - { 0x263710b4, BTTV_BOARD_VOODOOTV_FM, "3Dfx VoodooTV FM/ VoodooTV 200" }, + { 0x3000121a, BTTV_BOARD_VOODOOTV_200, "3Dfx VoodooTV 200" }, + { 0x263710b4, BTTV_BOARD_VOODOOTV_FM, "3Dfx VoodooTV FM" }, { 0x3060121a, BTTV_BOARD_STB2, "3Dfx VoodooTV 100/ STB OEM" }, { 0x3000144f, BTTV_BOARD_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" }, @@ -313,6 +313,7 @@ static struct CARD { { 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE, "Ultraview DVB-T Lite" }, { 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" }, { 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini "}, + { 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2, "DViCO FusionHDTV 2" }, { 0, -1, NULL } }; @@ -329,7 +330,7 @@ struct tvcard bttv_tvcards[] = { .tuner = 0, .svhs = 2, .muxsel = { 2, 3, 1, 0 }, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -344,7 +345,7 @@ struct tvcard bttv_tvcards[] = { .gpiomux = { 2, 0, 0, 0 }, .gpiomute = 10, .needs_tvaudio = 1, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -359,7 +360,7 @@ struct tvcard bttv_tvcards[] = { .gpiomux = { 0, 1, 2, 3 }, .gpiomute = 4, .needs_tvaudio = 1, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -387,13 +388,13 @@ struct tvcard bttv_tvcards[] = { .name = "Intel Create and Share PCI/ Smart Video Recorder III", .video_inputs = 4, .audio_inputs = 0, - .tuner = -1, + .tuner = UNSET, .svhs = 2, .gpiomask = 0, .muxsel = { 2, 3, 1, 1 }, .gpiomux = { 0 }, .needs_tvaudio = 0, - .tuner_type = 4, + .tuner_type = TUNER_ABSENT, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -408,7 +409,7 @@ struct tvcard bttv_tvcards[] = { .gpiomux = { 0, 1, 0, 1 }, .gpiomute = 3, .needs_tvaudio = 1, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -423,7 +424,7 @@ struct tvcard bttv_tvcards[] = { .gpiomux = { 0x0c, 0x04, 0x08, 0x04 }, /* 0x04 for some cards ?? */ .needs_tvaudio = 1, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .audio_hook = avermedia_tvphone_audio, @@ -433,13 +434,13 @@ struct tvcard bttv_tvcards[] = { .name = "MATRIX-Vision MV-Delta", .video_inputs = 5, .audio_inputs = 1, - .tuner = -1, + .tuner = UNSET, .svhs = 3, .gpiomask = 0, .muxsel = { 2, 3, 1, 0, 0 }, .gpiomux = { 0 }, .needs_tvaudio = 1, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -457,7 +458,7 @@ struct tvcard bttv_tvcards[] = { .gpiomute = 0xc00, .needs_tvaudio = 1, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -488,7 +489,7 @@ struct tvcard bttv_tvcards[] = { .gpiomute = 4, .needs_tvaudio = 1, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -503,7 +504,7 @@ struct tvcard bttv_tvcards[] = { .gpiomux = { 0x20001,0x10001, 0, 0 }, .gpiomute = 10, .needs_tvaudio = 1, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -519,7 +520,7 @@ struct tvcard bttv_tvcards[] = { .muxsel = { 2, 3, 1, 1 }, .gpiomux = { 13, 14, 11, 7 }, .needs_tvaudio = 1, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -553,7 +554,7 @@ struct tvcard bttv_tvcards[] = { .gpiomute = 4, .needs_tvaudio = 1, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -568,7 +569,7 @@ struct tvcard bttv_tvcards[] = { .gpiomux = { 0, 0, 1, 0 }, .gpiomute = 10, .needs_tvaudio = 1, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -587,7 +588,7 @@ struct tvcard bttv_tvcards[] = { .gpiomute = 0x002000, .needs_tvaudio = 1, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, }, [BTTV_BOARD_WINVIEW_601] = { .name = "Leadtek WinView 601", @@ -600,7 +601,7 @@ struct tvcard bttv_tvcards[] = { .gpiomux = { 0x4fa007,0xcfa007,0xcfa007,0xcfa007 }, .gpiomute = 0xcfa007, .needs_tvaudio = 1, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .audio_hook = winview_audio, @@ -616,7 +617,7 @@ struct tvcard bttv_tvcards[] = { .muxsel = { 2, 3, 1, 1 }, .gpiomux = { 1, 0, 0, 0 }, .needs_tvaudio = 1, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -624,13 +625,13 @@ struct tvcard bttv_tvcards[] = { .name = "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)", .video_inputs = 4, .audio_inputs = 1, - .tuner = -1, - .svhs = -1, + .tuner = UNSET, + .svhs = UNSET, .gpiomask = 0x8dff00, .muxsel = { 2, 3, 1, 1 }, .gpiomux = { 0 }, .no_msp34xx = 1, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -643,7 +644,7 @@ struct tvcard bttv_tvcards[] = { .tuner = 0, .svhs = 2, .muxsel = { 2, 3, 1, 1 }, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -674,7 +675,7 @@ struct tvcard bttv_tvcards[] = { .gpiomute = 0xc00, .needs_tvaudio = 1, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -683,7 +684,7 @@ struct tvcard bttv_tvcards[] = { .video_inputs = 3, .audio_inputs = 1, .tuner = 0, - .svhs = -1, + .svhs = UNSET, .gpiomask = 7, .muxsel = { 2, 3, -1 }, .digital_mode = DIGITAL_MODE_CAMERA, @@ -708,7 +709,7 @@ struct tvcard bttv_tvcards[] = { .gpiomute = 0xc00, .needs_tvaudio = 1, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .has_remote = 1, @@ -740,7 +741,7 @@ struct tvcard bttv_tvcards[] = { .gpiomux = { 0, 1, 2, 3 }, .gpiomute = 4, .needs_tvaudio = 1, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -813,13 +814,13 @@ struct tvcard bttv_tvcards[] = { .name = "Imagenation PXC200", .video_inputs = 5, .audio_inputs = 1, - .tuner = -1, + .tuner = UNSET, .svhs = 1, /* was: 4 */ .gpiomask = 0, .muxsel = { 2, 3, 1, 0, 0}, .gpiomux = { 0 }, .needs_tvaudio = 1, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .muxsel_hook = PXC200_muxsel, @@ -836,7 +837,7 @@ struct tvcard bttv_tvcards[] = { .gpiomux = { 0, 0x0800, 0x1000, 0x1000 }, .gpiomute = 0x1800, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -860,13 +861,13 @@ struct tvcard bttv_tvcards[] = { .name = "Intel Create and Share PCI/ Smart Video Recorder III", .video_inputs = 4, .audio_inputs = 0, - .tuner = -1, + .tuner = UNSET, .svhs = 2, .gpiomask = 0, .muxsel = { 2, 3, 1, 1 }, .gpiomux = { 0 }, .needs_tvaudio = 0, - .tuner_type = 4, + .tuner_type = TUNER_ABSENT, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -911,7 +912,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 0, .pll = PLL_28, .has_radio = 1, - .tuner_type = 5, /* default for now, gpio reads BFFF06 for Pal bg+dk */ + .tuner_type = TUNER_PHILIPS_PAL, /* default for now, gpio reads BFFF06 for Pal bg+dk */ .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .audio_hook = winfast2000_audio, @@ -928,7 +929,7 @@ struct tvcard bttv_tvcards[] = { .gpiomux = { 0, 0x800, 0x1000, 0x1000 }, .gpiomute = 0x1800, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -945,7 +946,7 @@ struct tvcard bttv_tvcards[] = { .gpiomux = { 0, 0x800, 0x1000, 0x1000 }, .gpiomute = 0x1800, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .has_radio = 1, @@ -962,7 +963,7 @@ struct tvcard bttv_tvcards[] = { .gpiomute = 0x29, .no_msp34xx = 1, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -978,7 +979,7 @@ struct tvcard bttv_tvcards[] = { .gpiomute = 0x551c00, .needs_tvaudio = 1, .pll = PLL_28, - .tuner_type = 1, + .tuner_type = TUNER_PHILIPS_PAL_I, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .has_remote = 1, @@ -995,7 +996,7 @@ struct tvcard bttv_tvcards[] = { .gpiomute = 1, .needs_tvaudio = 0, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -1030,7 +1031,7 @@ struct tvcard bttv_tvcards[] = { .gpiomux = { 13, 4, 11, 7 }, .needs_tvaudio = 1, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .has_radio = 1, @@ -1048,7 +1049,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .no_msp34xx = 1, .pll = PLL_28, - .tuner_type = 1, + .tuner_type = TUNER_PHILIPS_PAL_I, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -1063,7 +1064,7 @@ struct tvcard bttv_tvcards[] = { .gpiomux = { 0xff9ff6, 0xff9ff6, 0xff1ff7, 0 }, .gpiomute = 0xff3ffc, .no_msp34xx = 1, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -1074,14 +1075,14 @@ struct tvcard bttv_tvcards[] = { .video_inputs = 2, .audio_inputs = 1, .tuner = 0, - .svhs = -1, + .svhs = UNSET, .gpiomask = 3, .muxsel = { 2, 3, 1, 1 }, .gpiomux = { 1, 1, 0, 2 }, .gpiomute = 3, .no_msp34xx = 1, .pll = PLL_NONE, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -1089,14 +1090,14 @@ struct tvcard bttv_tvcards[] = { .name = "MATRIX-Vision MV-Delta 2", .video_inputs = 5, .audio_inputs = 1, - .tuner = -1, + .tuner = UNSET, .svhs = 3, .gpiomask = 0, .muxsel = { 2, 3, 1, 0, 0 }, .gpiomux = { 0 }, .no_msp34xx = 1, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -1112,7 +1113,7 @@ struct tvcard bttv_tvcards[] = { .gpiomute = 0xbcb03f, .no_msp34xx = 1, .pll = PLL_28, - .tuner_type = 21, + .tuner_type = TUNER_TEMIC_4039FR5_NTSC, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -1129,7 +1130,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .no_msp34xx = 1, .pll = PLL_35, - .tuner_type = 1, + .tuner_type = TUNER_PHILIPS_PAL_I, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .has_radio = 1, @@ -1148,7 +1149,7 @@ struct tvcard bttv_tvcards[] = { .gpiomute = 1, .needs_tvaudio = 1, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -1206,7 +1207,7 @@ struct tvcard bttv_tvcards[] = { .gpiomux = { 0, 1, 2, 3 }, .gpiomute = 4, .pll = PLL_28, - .tuner_type = -1 /* TUNER_ALPS_TMDH2_NTSC */, + .tuner_type = UNSET /* TUNER_ALPS_TMDH2_NTSC */, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -1234,7 +1235,7 @@ struct tvcard bttv_tvcards[] = { 1= FM stereo Radio from Tuner */ .needs_tvaudio = 0, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -1277,7 +1278,7 @@ struct tvcard bttv_tvcards[] = { 0x0080: Tuner A2 SAP (second audio program = Zweikanalton) 0x0880: Tuner A2 stereo */ .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -1313,7 +1314,7 @@ struct tvcard bttv_tvcards[] = { .gpiomux = { 0, 0x800, 0x1000, 0x1000 }, .gpiomute = 0x1800, .pll = PLL_28, - .tuner_type = 5, + .tuner_type = TUNER_PHILIPS_PAL, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -1324,7 +1325,7 @@ struct tvcard bttv_tvcards[] = { .name = "GrandTec 'Grand Video Capture' (Bt848)", .video_inputs = 2, .audio_inputs = 0, - .tuner = -1, + .tuner = UNSET, .svhs = 1, .gpiomask = 0, .muxsel = { 3, 1 }, @@ -1332,7 +1333,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 0, .no_msp34xx = 1, .pll = PLL_35, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -1365,7 +1366,7 @@ struct tvcard bttv_tvcards[] = { .gpiomux = { 2, 0, 0, 0 }, .gpiomute = 1, .pll = PLL_28, - .tuner_type = 0, + .tuner_type = TUNER_TEMIC_PAL, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -1377,7 +1378,7 @@ struct tvcard bttv_tvcards[] = { .video_inputs = 2, .audio_inputs = 2, .tuner = 0, - .svhs = -1, + .svhs = UNSET, .gpiomask = 11, .muxsel = { 2, 3, 1, 1 }, .gpiomux = { 2, 0, 0, 1 }, @@ -1392,7 +1393,7 @@ struct tvcard bttv_tvcards[] = { .name = "AG Electronics GMV1", .video_inputs = 2, .audio_inputs = 0, - .tuner = -1, + .tuner = UNSET, .svhs = 1, .gpiomask = 0xF, .muxsel = { 2, 2 }, @@ -1400,7 +1401,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .needs_tvaudio = 0, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -1447,7 +1448,7 @@ struct tvcard bttv_tvcards[] = { .video_inputs = 2, .audio_inputs = 1, .tuner = 0, - .svhs = -1, + .svhs = UNSET, .gpiomask = 1, .muxsel = { 2, 3, 0, 1 }, .gpiomux = { 0, 0, 1, 0 }, @@ -1476,7 +1477,7 @@ struct tvcard bttv_tvcards[] = { .no_tda9875 = 1, .needs_tvaudio = 1, .pll = PLL_28, - .tuner_type = 5, + .tuner_type = TUNER_PHILIPS_PAL, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -1517,13 +1518,35 @@ struct tvcard bttv_tvcards[] = { /* ---- card 0x44 ---------------------------------- */ [BTTV_BOARD_VOODOOTV_FM] = { - .name = "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)", + .name = "3Dfx VoodooTV FM (Euro)", + /* try "insmod msp3400 simple=0" if you have + * sound problems with this card. */ + .video_inputs = 4, + .audio_inputs = 1, + .tuner = 0, + .svhs = UNSET, + .gpiomask = 0x4f8a00, + /* 0x100000: 1=MSP enabled (0=disable again) + * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */ + .gpiomux = {0x947fff, 0x987fff,0x947fff,0x947fff }, + .gpiomute = 0x947fff, + /* tvtuner, radio, external,internal, mute, stereo + * tuner, Composit, SVid, Composit-on-Svid-adapter */ + .muxsel = { 2, 3 ,0 ,1 }, + .tuner_type = TUNER_MT2032, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .pll = PLL_28, + .has_radio = 1, + }, + [BTTV_BOARD_VOODOOTV_200] = { + .name = "VoodooTV 200 (USA)", /* try "insmod msp3400 simple=0" if you have * sound problems with this card. */ .video_inputs = 4, .audio_inputs = 1, .tuner = 0, - .svhs = -1, + .svhs = UNSET, .gpiomask = 0x4f8a00, /* 0x100000: 1=MSP enabled (0=disable again) * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */ @@ -1543,8 +1566,8 @@ struct tvcard bttv_tvcards[] = { .name = "Active Imaging AIMMS", .video_inputs = 1, .audio_inputs = 0, - .tuner = -1, - .tuner_type = -1, + .tuner = UNSET, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .pll = PLL_28, @@ -1564,7 +1587,7 @@ struct tvcard bttv_tvcards[] = { .gpiomute = 13, .needs_tvaudio = 1, .pll = PLL_28, - .tuner_type = 25, + .tuner_type = TUNER_LG_PAL_I_FM, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .has_remote = 1, @@ -1580,7 +1603,7 @@ struct tvcard bttv_tvcards[] = { .name = "Lifeview FlyVideo 98EZ (capture only) LR51", .video_inputs = 4, .audio_inputs = 0, - .tuner = -1, + .tuner = UNSET, .svhs = 2, .muxsel = { 2, 3, 1, 1 }, /* AV1, AV2, SVHS, CVid adapter on SVHS */ .pll = PLL_28, @@ -1606,7 +1629,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .no_tda9875 = 1, .pll = PLL_28, - .tuner_type = 5, + .tuner_type = TUNER_PHILIPS_PAL, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .audio_hook = pvbt878p9b_audio, /* Note: not all cards have stereo */ @@ -1626,13 +1649,13 @@ struct tvcard bttv_tvcards[] = { .name = "Sensoray 311", .video_inputs = 5, .audio_inputs = 0, - .tuner = -1, + .tuner = UNSET, .svhs = 4, .gpiomask = 0, .muxsel = { 2, 3, 1, 0, 0 }, .gpiomux = { 0 }, .needs_tvaudio = 0, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -1641,15 +1664,15 @@ struct tvcard bttv_tvcards[] = { .name = "RemoteVision MX (RV605)", .video_inputs = 16, .audio_inputs = 0, - .tuner = -1, - .svhs = -1, + .tuner = UNSET, + .svhs = UNSET, .gpiomask = 0x00, .gpiomask2 = 0x07ff, .muxsel = { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03, 0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 }, .no_msp34xx = 1, .no_tda9875 = 1, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .muxsel_hook = rv605_muxsel, @@ -1693,15 +1716,15 @@ struct tvcard bttv_tvcards[] = { .name = "GrandTec Multi Capture Card (Bt878)", .video_inputs = 4, .audio_inputs = 0, - .tuner = -1, - .svhs = -1, + .tuner = UNSET, + .svhs = UNSET, .gpiomask = 0, .muxsel = { 2, 3, 1, 0 }, .gpiomux = { 0 }, .needs_tvaudio = 0, .no_msp34xx = 1, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -1724,7 +1747,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 0, .no_msp34xx = 1, .pll = PLL_28, - .tuner_type = 5, + .tuner_type = TUNER_PHILIPS_PAL, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, /* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and @@ -1744,10 +1767,10 @@ struct tvcard bttv_tvcards[] = { /* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */ .name = "DSP Design TCVIDEO", .video_inputs = 4, - .svhs = -1, + .svhs = UNSET, .muxsel = { 2, 3, 1, 0 }, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -1762,7 +1785,7 @@ struct tvcard bttv_tvcards[] = { .muxsel = { 2, 0, 1, 1 }, .needs_tvaudio = 1, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, @@ -1791,11 +1814,11 @@ struct tvcard bttv_tvcards[] = { .name = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */ .video_inputs = 4, /* id-inputs-clock */ .audio_inputs = 0, - .tuner = -1, + .tuner = UNSET, .svhs = 3, .muxsel = { 3, 2, 0, 1 }, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .no_msp34xx = 1, @@ -1806,11 +1829,11 @@ struct tvcard bttv_tvcards[] = { .name = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */ .video_inputs = 3, .audio_inputs = 0, - .tuner = -1, + .tuner = UNSET, .svhs = 2, .muxsel = { 2, 3, 1 }, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .no_msp34xx = 1, @@ -1823,11 +1846,11 @@ struct tvcard bttv_tvcards[] = { .name = "Osprey 101 (848)", /* 0x05-40C0-C1 */ .video_inputs = 2, .audio_inputs = 0, - .tuner = -1, + .tuner = UNSET, .svhs = 1, .muxsel = { 3, 1 }, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .no_msp34xx = 1, @@ -1838,11 +1861,11 @@ struct tvcard bttv_tvcards[] = { .name = "Osprey 101/151", /* 0x1(4|5)-0004-C4 */ .video_inputs = 1, .audio_inputs = 0, - .tuner = -1, - .svhs = -1, + .tuner = UNSET, + .svhs = UNSET, .muxsel = { 0 }, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .no_msp34xx = 1, @@ -1853,11 +1876,11 @@ struct tvcard bttv_tvcards[] = { .name = "Osprey 101/151 w/ svid", /* 0x(16|17|20)-00C4-C1 */ .video_inputs = 2, .audio_inputs = 0, - .tuner = -1, + .tuner = UNSET, .svhs = 1, .muxsel = { 0, 1 }, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .no_msp34xx = 1, @@ -1868,8 +1891,8 @@ struct tvcard bttv_tvcards[] = { .name = "Osprey 200/201/250/251", /* 0x1(8|9|E|F)-0004-C4 */ .video_inputs = 1, .audio_inputs = 1, - .tuner = -1, - .svhs = -1, + .tuner = UNSET, + .svhs = UNSET, .muxsel = { 0 }, .pll = PLL_28, .tuner_type = UNSET, @@ -1885,7 +1908,7 @@ struct tvcard bttv_tvcards[] = { .name = "Osprey 200/250", /* 0x1(A|B)-00C4-C1 */ .video_inputs = 2, .audio_inputs = 1, - .tuner = -1, + .tuner = UNSET, .svhs = 1, .muxsel = { 0, 1 }, .pll = PLL_28, @@ -1900,7 +1923,7 @@ struct tvcard bttv_tvcards[] = { .name = "Osprey 210/220/230", /* 0x1(A|B)-04C0-C1 */ .video_inputs = 2, .audio_inputs = 1, - .tuner = -1, + .tuner = UNSET, .svhs = 1, .muxsel = { 2, 3 }, .pll = PLL_28, @@ -1915,11 +1938,11 @@ struct tvcard bttv_tvcards[] = { .name = "Osprey 500", /* 500 */ .video_inputs = 2, .audio_inputs = 1, - .tuner = -1, + .tuner = UNSET, .svhs = 1, .muxsel = { 2, 3 }, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .no_msp34xx = 1, @@ -1930,9 +1953,9 @@ struct tvcard bttv_tvcards[] = { .name = "Osprey 540", /* 540 */ .video_inputs = 4, .audio_inputs = 1, - .tuner = -1, + .tuner = UNSET, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .no_msp34xx = 1, @@ -1945,7 +1968,7 @@ struct tvcard bttv_tvcards[] = { .name = "Osprey 2000", /* 2000 */ .video_inputs = 2, .audio_inputs = 1, - .tuner = -1, + .tuner = UNSET, .svhs = 1, .muxsel = { 2, 3 }, .pll = PLL_28, @@ -1961,11 +1984,11 @@ struct tvcard bttv_tvcards[] = { .name = "IDS Eagle", .video_inputs = 4, .audio_inputs = 0, - .tuner = -1, - .tuner_type = -1, + .tuner = UNSET, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .svhs = -1, + .svhs = UNSET, .gpiomask = 0, .muxsel = { 0, 1, 2, 3 }, .muxsel_hook = eagle_muxsel, @@ -1978,8 +2001,8 @@ struct tvcard bttv_tvcards[] = { .video_inputs = 2, .audio_inputs = 0, .svhs = 1, - .tuner = -1, - .tuner_type = -1, + .tuner = UNSET, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .no_msp34xx = 1, @@ -2020,13 +2043,13 @@ struct tvcard bttv_tvcards[] = { .video_inputs = 3, .audio_inputs = 1, .tuner = 0, - .svhs = -1, + .svhs = UNSET, .gpiomask = 7, .muxsel = { 2, 3, 1, 1}, .gpiomux = { 0, 1, 2, 3}, .gpiomute = 4, .needs_tvaudio = 1, - .tuner_type = 5, + .tuner_type = TUNER_PHILIPS_PAL, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .pll = PLL_28, @@ -2035,7 +2058,7 @@ struct tvcard bttv_tvcards[] = { .name = "Euresys Picolo", .video_inputs = 3, .audio_inputs = 0, - .tuner = -1, + .tuner = UNSET, .svhs = 2, .gpiomask = 0, .no_msp34xx = 1, @@ -2052,8 +2075,8 @@ struct tvcard bttv_tvcards[] = { .name = "ProVideo PV150", /* 0x4f */ .video_inputs = 2, .audio_inputs = 0, - .tuner = -1, - .svhs = -1, + .tuner = UNSET, + .svhs = UNSET, .gpiomask = 0, .muxsel = { 2, 3 }, .gpiomux = { 0 }, @@ -2080,7 +2103,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 0, .no_msp34xx = 1, .pll = PLL_28, - .tuner_type = 2, + .tuner_type = TUNER_PHILIPS_NTSC, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .audio_hook = adtvk503_audio, @@ -2098,7 +2121,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .no_msp34xx = 1, .pll = PLL_28, - .tuner_type = 5, + .tuner_type = TUNER_PHILIPS_PAL, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, /* Notes: @@ -2121,7 +2144,7 @@ struct tvcard bttv_tvcards[] = { .gpiomask = 0, .no_tda9875 = 1, .no_tda7432 = 1, - .tuner_type = 1, + .tuner_type = TUNER_PHILIPS_PAL_I, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .has_radio = 1, @@ -2138,11 +2161,11 @@ struct tvcard bttv_tvcards[] = { .name = "IVC-200", .video_inputs = 1, .audio_inputs = 0, - .tuner = -1, - .tuner_type = -1, + .tuner = UNSET, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .svhs = -1, + .svhs = UNSET, .gpiomask = 0xdf, .muxsel = { 2 }, .pll = PLL_28, @@ -2151,9 +2174,9 @@ struct tvcard bttv_tvcards[] = { .name = "Grand X-Guard / Trust 814PCI", .video_inputs = 16, .audio_inputs = 0, - .tuner = -1, - .svhs = -1, - .tuner_type = 4, + .tuner = UNSET, + .svhs = UNSET, + .tuner_type = TUNER_ABSENT, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .gpiomask2 = 0xff, @@ -2169,14 +2192,14 @@ struct tvcard bttv_tvcards[] = { [BTTV_BOARD_NEBULA_DIGITV] = { .name = "Nebula Electronics DigiTV", .video_inputs = 1, - .tuner = -1, - .svhs = -1, + .tuner = UNSET, + .svhs = UNSET, .muxsel = { 2, 3, 1, 0 }, .no_msp34xx = 1, .no_tda9875 = 1, .no_tda7432 = 1, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .has_dvb = 1, @@ -2189,15 +2212,15 @@ struct tvcard bttv_tvcards[] = { .name = "ProVideo PV143", .video_inputs = 4, .audio_inputs = 0, - .tuner = -1, - .svhs = -1, + .tuner = UNSET, + .svhs = UNSET, .gpiomask = 0, .muxsel = { 2, 3, 1, 0 }, .gpiomux = { 0 }, .needs_tvaudio = 0, .no_msp34xx = 1, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -2206,14 +2229,14 @@ struct tvcard bttv_tvcards[] = { .name = "PHYTEC VD-009-X1 MiniDIN (bt878)", .video_inputs = 4, .audio_inputs = 0, - .tuner = -1, /* card has no tuner */ + .tuner = UNSET, /* card has no tuner */ .svhs = 3, .gpiomask = 0x00, .muxsel = { 2, 3, 1, 0 }, .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ .needs_tvaudio = 1, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -2221,14 +2244,14 @@ struct tvcard bttv_tvcards[] = { .name = "PHYTEC VD-009-X1 Combi (bt878)", .video_inputs = 4, .audio_inputs = 0, - .tuner = -1, /* card has no tuner */ + .tuner = UNSET, /* card has no tuner */ .svhs = 3, .gpiomask = 0x00, .muxsel = { 2, 3, 1, 1 }, .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ .needs_tvaudio = 1, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -2238,7 +2261,7 @@ struct tvcard bttv_tvcards[] = { .name = "PHYTEC VD-009 MiniDIN (bt878)", .video_inputs = 10, .audio_inputs = 0, - .tuner = -1, /* card has no tuner */ + .tuner = UNSET, /* card has no tuner */ .svhs = 9, .gpiomask = 0x00, .gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio @@ -2248,7 +2271,7 @@ struct tvcard bttv_tvcards[] = { .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ .needs_tvaudio = 1, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -2256,7 +2279,7 @@ struct tvcard bttv_tvcards[] = { .name = "PHYTEC VD-009 Combi (bt878)", .video_inputs = 10, .audio_inputs = 0, - .tuner = -1, /* card has no tuner */ + .tuner = UNSET, /* card has no tuner */ .svhs = 9, .gpiomask = 0x00, .gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio @@ -2266,7 +2289,7 @@ struct tvcard bttv_tvcards[] = { .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ .needs_tvaudio = 1, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -2274,11 +2297,11 @@ struct tvcard bttv_tvcards[] = { .name = "IVC-100", .video_inputs = 4, .audio_inputs = 0, - .tuner = -1, - .tuner_type = -1, + .tuner = UNSET, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .svhs = -1, + .svhs = UNSET, .gpiomask = 0xdf, .muxsel = { 2, 3, 1, 0 }, .pll = PLL_28, @@ -2288,11 +2311,11 @@ struct tvcard bttv_tvcards[] = { .name = "IVC-120G", .video_inputs = 16, .audio_inputs = 0, /* card has no audio */ - .tuner = -1, /* card has no tuner */ - .tuner_type = -1, + .tuner = UNSET, /* card has no tuner */ + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .svhs = -1, /* card has no svhs */ + .svhs = UNSET, /* card has no svhs */ .needs_tvaudio = 0, .no_msp34xx = 1, .no_tda9875 = 1, @@ -2333,7 +2356,7 @@ struct tvcard bttv_tvcards[] = { .video_inputs = 3, .audio_inputs = 0, .svhs = 1, - .tuner = -1, + .tuner = UNSET, .muxsel = { 3, 1, 1, 3 }, /* Vid In, SVid In, Vid over SVid in connector */ .no_msp34xx = 1, .no_tda9875 = 1, @@ -2364,9 +2387,9 @@ struct tvcard bttv_tvcards[] = { .name = "SIMUS GVC1100", .video_inputs = 4, .audio_inputs = 0, - .tuner = -1, - .svhs = -1, - .tuner_type = -1, + .tuner = UNSET, + .svhs = UNSET, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .pll = PLL_28, @@ -2395,14 +2418,14 @@ struct tvcard bttv_tvcards[] = { .name = "LMLBT4", .video_inputs = 4, /* IN1,IN2,IN3,IN4 */ .audio_inputs = 0, - .tuner = -1, - .svhs = -1, + .tuner = UNSET, + .svhs = UNSET, .muxsel = { 2, 3, 1, 0 }, .no_msp34xx = 1, .no_tda9875 = 1, .no_tda7432 = 1, .needs_tvaudio = 0, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -2452,8 +2475,8 @@ struct tvcard bttv_tvcards[] = { .name = "Euresys Picolo Tetra", .video_inputs = 4, .audio_inputs = 0, - .tuner = -1, - .svhs = -1, + .tuner = UNSET, + .svhs = UNSET, .gpiomask = 0, .gpiomask2 = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/ .no_msp34xx = 1, @@ -2464,7 +2487,7 @@ struct tvcard bttv_tvcards[] = { .pll = PLL_28, .needs_tvaudio = 0, .muxsel_hook = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/ - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -2490,7 +2513,7 @@ struct tvcard bttv_tvcards[] = { .name = "AVerMedia AVerTV DVB-T 771", .video_inputs = 2, .svhs = 1, - .tuner = -1, + .tuner = UNSET, .tuner_type = TUNER_ABSENT, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, @@ -2509,14 +2532,14 @@ struct tvcard bttv_tvcards[] = { /* Based on the Nebula card data - added remote and new card number - BTTV_BOARD_AVDVBT_761, see also ir-kbd-gpio.c */ .name = "AverMedia AverTV DVB-T 761", .video_inputs = 2, - .tuner = -1, + .tuner = UNSET, .svhs = 1, .muxsel = { 3, 1, 2, 0 }, /* Comp0, S-Video, ?, ? */ .no_msp34xx = 1, .no_tda9875 = 1, .no_tda7432 = 1, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .has_dvb = 1, @@ -2528,8 +2551,8 @@ struct tvcard bttv_tvcards[] = { .name = "MATRIX Vision Sigma-SQ", .video_inputs = 16, .audio_inputs = 0, - .tuner = -1, - .svhs = -1, + .tuner = UNSET, + .svhs = UNSET, .gpiomask = 0x0, .muxsel = { 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 }, @@ -2537,7 +2560,7 @@ struct tvcard bttv_tvcards[] = { .gpiomux = { 0 }, .no_msp34xx = 1, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -2546,15 +2569,15 @@ struct tvcard bttv_tvcards[] = { .name = "MATRIX Vision Sigma-SLC", .video_inputs = 4, .audio_inputs = 0, - .tuner = -1, - .svhs = -1, + .tuner = UNSET, + .svhs = UNSET, .gpiomask = 0x0, .muxsel = { 2, 2, 2, 2 }, .muxsel_hook = sigmaSLC_muxsel, .gpiomux = { 0 }, .no_msp34xx = 1, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -2566,7 +2589,7 @@ struct tvcard bttv_tvcards[] = { .video_inputs = 2, .audio_inputs = 1, .tuner = 0, - .svhs = -1, + .svhs = UNSET, .gpiomask = 0xFF, .muxsel = { 2, 3, 1, 1 }, .gpiomux = { 2, 0, 0, 0 }, @@ -2584,14 +2607,14 @@ struct tvcard bttv_tvcards[] = { [BTTV_BOARD_DVICO_DVBT_LITE] = { /* Chris Pascoe <c.pascoe@itee.uq.edu.au> */ .name = "DViCO FusionHDTV DVB-T Lite", - .tuner = -1, + .tuner = UNSET, .no_msp34xx = 1, .no_tda9875 = 1, .no_tda7432 = 1, .pll = PLL_28, .no_video = 1, .has_dvb = 1, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -2634,14 +2657,14 @@ struct tvcard bttv_tvcards[] = { .name = "Tibet Systems 'Progress DVR' CS16", .video_inputs = 16, .audio_inputs = 0, - .tuner = -1, - .svhs = -1, + .tuner = UNSET, + .svhs = UNSET, .muxsel = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, .pll = PLL_28, .no_msp34xx = 1, .no_tda9875 = 1, .no_tda7432 = 1, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .muxsel_hook = tibetCS16_muxsel, @@ -2661,11 +2684,11 @@ struct tvcard bttv_tvcards[] = { .name = "Kodicom 4400R (master)", .video_inputs = 16, .audio_inputs = 0, - .tuner = -1, - .tuner_type = -1, + .tuner = UNSET, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .svhs = -1, + .svhs = UNSET, /* GPIO bits 0-9 used for analog switch: * 00 - 03: camera selector * 04 - 06: channel (controller) selector @@ -2693,11 +2716,11 @@ struct tvcard bttv_tvcards[] = { .name = "Kodicom 4400R (slave)", .video_inputs = 16, .audio_inputs = 0, - .tuner = -1, - .tuner_type = -1, + .tuner = UNSET, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .svhs = -1, + .svhs = UNSET, .gpiomask = 0x010000, .no_gpioirq = 1, .muxsel = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, @@ -2717,7 +2740,7 @@ struct tvcard bttv_tvcards[] = { .tuner = 0, .svhs = 2, .muxsel = { 2, 3, 1, 0 }, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .pll = PLL_28, @@ -2824,7 +2847,7 @@ struct tvcard bttv_tvcards[] = { .name = "Osprey 440", .video_inputs = 1, .audio_inputs = 1, - .tuner = -1, + .tuner = UNSET, .svhs = 1, .muxsel = { 2 }, .pll = PLL_28, @@ -2848,7 +2871,7 @@ struct tvcard bttv_tvcards[] = { .gpiomute = 1, .needs_tvaudio = 1, .pll = PLL_28, - .tuner_type = 2, + .tuner_type = TUNER_PHILIPS_NTSC, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -2875,14 +2898,14 @@ struct tvcard bttv_tvcards[] = { .name = "Hauppauge ImpactVCB (bt878)", .video_inputs = 4, .audio_inputs = 0, - .tuner = -1, - .svhs = -1, + .tuner = UNSET, + .svhs = UNSET, .gpiomask = 0x0f, /* old: 7 */ .muxsel = { 0, 1, 3, 2 }, /* Composite 0-3 */ .no_msp34xx = 1, .no_tda9875 = 1, .no_tda7432 = 1, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -2914,10 +2937,10 @@ struct tvcard bttv_tvcards[] = { .name = "SSAI Security Video Interface", .video_inputs = 4, .audio_inputs = 0, - .tuner = -1, - .svhs = -1, + .tuner = UNSET, + .svhs = UNSET, .muxsel = { 0, 1, 2, 3 }, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, @@ -2925,13 +2948,31 @@ struct tvcard bttv_tvcards[] = { .name = "SSAI Ultrasound Video Interface", .video_inputs = 2, .audio_inputs = 0, - .tuner = -1, + .tuner = UNSET, .svhs = 1, .muxsel = { 2, 0, 1, 3 }, - .tuner_type = -1, + .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, + /* ---- card 0x94---------------------------------- */ + [BTTV_BOARD_DVICO_FUSIONHDTV_2] = { + .name = "DViCO FusionHDTV 2", + .tuner = 0, + .tuner_type = TUNER_PHILIPS_ATSC, /* FCV1236D */ + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .video_inputs = 3, + .audio_inputs = 1, + .svhs = 2, + .muxsel = { 2, 3, 1 }, + .gpiomask = 0x00e00007, + .gpiomux = { 0x00400005, 0, 0x00000001, 0 }, + .gpiomute = 0x00c00007, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, + }, }; static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); @@ -3040,7 +3081,7 @@ static void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256]) static void flyvideo_gpio(struct bttv *btv) { int gpio,has_remote,has_radio,is_capture_only,is_lr90,has_tda9820_tda9821; - int tuner=-1,ttype; + int tuner=UNSET,ttype; gpio_inout(0xffffff, 0); udelay(8); /* without this we would see the 0x1800 mask */ @@ -3085,7 +3126,7 @@ static void flyvideo_gpio(struct bttv *btv) * gpio & 0x001000 output bit for audio routing */ if(is_capture_only) - tuner=4; /* No tuner present */ + tuner = TUNER_ABSENT; /* No tuner present */ printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n", btv->c.nr, has_radio? "yes":"no ", has_remote? "yes":"no ", tuner, gpio); @@ -3093,7 +3134,7 @@ static void flyvideo_gpio(struct bttv *btv) btv->c.nr, is_lr90?"yes":"no ", has_tda9820_tda9821?"yes":"no ", is_capture_only?"yes":"no "); - if(tuner!= -1) /* only set if known tuner autodetected, else let insmod option through */ + if (tuner != UNSET) /* only set if known tuner autodetected, else let insmod option through */ btv->tuner_type = tuner; btv->has_radio = has_radio; @@ -3302,6 +3343,7 @@ void __devinit bttv_init_card1(struct bttv *btv) case BTTV_BOARD_HAUPPAUGE878: boot_msp34xx(btv,5); break; + case BTTV_BOARD_VOODOOTV_200: case BTTV_BOARD_VOODOOTV_FM: boot_msp34xx(btv,20); break; @@ -3328,10 +3370,9 @@ void __devinit bttv_init_card1(struct bttv *btv) /* initialization part two -- after registering i2c bus */ void __devinit bttv_init_card2(struct bttv *btv) { - int tda9887; int addr=ADDR_UNSET; - btv->tuner_type = -1; + btv->tuner_type = UNSET; if (BTTV_BOARD_UNKNOWN == btv->c.type) { bttv_readee(btv,eeprom_data,0xa0); @@ -3479,7 +3520,15 @@ void __devinit bttv_init_card2(struct bttv *btv) btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type; if (UNSET != tuner[btv->c.nr]) btv->tuner_type = tuner[btv->c.nr]; - printk("bttv%d: using tuner=%d\n",btv->c.nr,btv->tuner_type); + + if (btv->tuner_type == TUNER_ABSENT || + bttv_tvcards[btv->c.type].tuner == UNSET) + printk(KERN_INFO "bttv%d: tuner absent\n", btv->c.nr); + else if(btv->tuner_type == UNSET) + printk(KERN_WARNING "bttv%d: tuner type unset\n", btv->c.nr); + else + printk(KERN_INFO "bttv%d: tuner type=%d\n", btv->c.nr, + btv->tuner_type); if (btv->tuner_type != UNSET) { struct tuner_setup tun_setup; @@ -3521,6 +3570,9 @@ void __devinit bttv_init_card2(struct bttv *btv) if (!autoload) return; + if (bttv_tvcards[btv->c.type].tuner == UNSET) + return; /* no tuner or related drivers to load */ + /* try to detect audio/fader chips */ if (!bttv_tvcards[btv->c.type].no_msp34xx && bttv_I2CRead(btv, I2C_ADDR_MSP3400, "MSP34xx") >=0) @@ -3541,17 +3593,7 @@ void __devinit bttv_init_card2(struct bttv *btv) if (bttv_tvcards[btv->c.type].needs_tvaudio) request_module("tvaudio"); - /* tuner modules */ - tda9887 = 0; - if (btv->tda9887_conf) - tda9887 = 1; - if (0 == tda9887 && 0 == bttv_tvcards[btv->c.type].has_dvb && - bttv_I2CRead(btv, I2C_ADDR_TDA9887, "TDA9887") >=0) - tda9887 = 1; - /* Hybrid DVB card, DOES have a tda9887 */ - if (btv->c.type == BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE) - tda9887 = 1; - if (btv->tuner_type != UNSET) + if (btv->tuner_type != UNSET && btv->tuner_type != TUNER_ABSENT) request_module("tuner"); } @@ -3865,11 +3907,15 @@ void bttv_tda9880_setnorm(struct bttv *btv, int norm) if(norm==VIDEO_MODE_NTSC) { bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff; bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x957fff; + bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff; + bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomute=0x957fff; dprintk("bttv_tda9880_setnorm to NTSC\n"); } else { bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x947fff; bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x947fff; + bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x947fff; + bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomute=0x947fff; dprintk("bttv_tda9880_setnorm to PAL\n"); } /* set GPIO according */ diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index b1fedb0f6431..cb555f2c40f9 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -1218,7 +1218,14 @@ audio_mux(struct bttv *btv, int input, int mute) break; case TVAUDIO_INPUT_TUNER: default: - route.input = MSP_INPUT_DEFAULT; + /* This is the only card that uses TUNER2, and afaik, + is the only difference between the VOODOOTV_FM + and VOODOOTV_200 */ + if (btv->c.type == BTTV_BOARD_VOODOOTV_200) + route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER2, \ + MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER); + else + route.input = MSP_INPUT_DEFAULT; break; } route.output = MSP_OUTPUT_DEFAULT; @@ -1253,7 +1260,7 @@ i2c_vidiocschan(struct bttv *btv) v4l2_std_id std = bttv_tvnorms[btv->tvnorm].v4l2_id; bttv_call_i2c_clients(btv, VIDIOC_S_STD, &std); - if (btv->c.type == BTTV_BOARD_VOODOOTV_FM) + if (btv->c.type == BTTV_BOARD_VOODOOTV_FM || btv->c.type == BTTV_BOARD_VOODOOTV_200) bttv_tda9880_setnorm(btv,btv->tvnorm); } @@ -1323,6 +1330,7 @@ set_tvnorm(struct bttv *btv, unsigned int norm) switch (btv->c.type) { case BTTV_BOARD_VOODOOTV_FM: + case BTTV_BOARD_VOODOOTV_200: bttv_tda9880_setnorm(btv,norm); break; } @@ -2251,6 +2259,24 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) printk(KERN_INFO "bttv%d: ================== END STATUS CARD #%d ==================\n", btv->c.nr, btv->c.nr); return 0; } +#ifdef CONFIG_VIDEO_ADV_DEBUG + case VIDIOC_DBG_G_REGISTER: + case VIDIOC_DBG_S_REGISTER: + { + struct v4l2_register *reg = arg; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return -EINVAL; + /* bt848 has a 12-bit register space */ + reg->reg &= 0xfff; + if (cmd == VIDIOC_DBG_G_REGISTER) + reg->val = btread(reg->reg); + else + btwrite(reg->val, reg->reg); + return 0; + } +#endif default: return -ENOIOCTLCMD; @@ -3561,6 +3587,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_G_FREQUENCY: case VIDIOC_S_FREQUENCY: case VIDIOC_LOG_STATUS: + case VIDIOC_DBG_G_REGISTER: + case VIDIOC_DBG_S_REGISTER: return bttv_common_ioctls(btv,cmd,arg); default: @@ -3943,6 +3971,8 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, case VIDIOCGAUDIO: case VIDIOCSAUDIO: case VIDIOC_LOG_STATUS: + case VIDIOC_DBG_G_REGISTER: + case VIDIOC_DBG_S_REGISTER: return bttv_common_ioctls(btv,cmd,arg); default: diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c index 6f74c8042bc3..94a13d0ee614 100644 --- a/drivers/media/video/bt8xx/bttv-input.c +++ b/drivers/media/video/bt8xx/bttv-input.c @@ -313,7 +313,7 @@ int bttv_input_init(struct bttv *btv) input_dev->id.vendor = btv->c.pci->vendor; input_dev->id.product = btv->c.pci->device; } - input_dev->cdev.dev = &btv->c.pci->dev; + input_dev->dev.parent = &btv->c.pci->dev; btv->remote = ir; bttv_ir_start(btv, ir); diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h index f821ba69db99..dcc847dc2486 100644 --- a/drivers/media/video/bt8xx/bttv.h +++ b/drivers/media/video/bt8xx/bttv.h @@ -170,6 +170,8 @@ #define BTTV_BOARD_MACHTV_MAGICTV 0x90 #define BTTV_BOARD_SSAI_SECURITY 0x91 #define BTTV_BOARD_SSAI_ULTRASOUND 0x92 +#define BTTV_BOARD_VOODOOTV_200 0x93 +#define BTTV_BOARD_DVICO_FUSIONHDTV_2 0x94 /* more card-specific defines */ #define PT2254_L_CHANNEL 0x10 diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h index 8f44f02029be..bd85f6d0fbe3 100644 --- a/drivers/media/video/bt8xx/bttvp.h +++ b/drivers/media/video/bt8xx/bttvp.h @@ -33,12 +33,12 @@ #include <linux/i2c.h> #include <linux/i2c-algo-bit.h> #include <linux/videodev.h> -#include <media/v4l2-common.h> #include <linux/pci.h> #include <linux/input.h> #include <linux/mutex.h> #include <asm/scatterlist.h> #include <asm/io.h> +#include <media/v4l2-common.h> #include <linux/device.h> #include <media/video-buf.h> diff --git a/drivers/media/video/cpia2/cpia2_core.c b/drivers/media/video/cpia2/cpia2_core.c index fd771c7a2fe2..55aab8d38880 100644 --- a/drivers/media/video/cpia2/cpia2_core.c +++ b/drivers/media/video/cpia2/cpia2_core.c @@ -663,15 +663,13 @@ int cpia2_reset_camera(struct camera_data *cam) cpia2_send_command(cam, &cmd); } - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(100 * HZ / 1000); /* wait for 100 msecs */ + schedule_timeout_interruptible(msecs_to_jiffies(100)); 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 */ + schedule_timeout_interruptible(msecs_to_jiffies(100)); /*** * If this is a 676, apply VP5 fixes before we start streaming @@ -720,8 +718,7 @@ int cpia2_reset_camera(struct camera_data *cam) set_default_user_mode(cam); /* Give VP time to wake up */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(100 * HZ / 1000); /* wait for 100 msecs */ + schedule_timeout_interruptible(msecs_to_jiffies(100)); set_all_properties(cam); diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c index 1bda7ad9de11..92778cd1d735 100644 --- a/drivers/media/video/cpia2/cpia2_v4l.c +++ b/drivers/media/video/cpia2/cpia2_v4l.c @@ -105,7 +105,7 @@ static struct control_menu_info framerate_controls[] = { CPIA2_VP_FRAMERATE_25, "25 fps" }, { CPIA2_VP_FRAMERATE_30, "30 fps" }, }; -#define NUM_FRAMERATE_CONTROLS (sizeof(framerate_controls)/sizeof(framerate_controls[0])) +#define NUM_FRAMERATE_CONTROLS (ARRAY_SIZE(framerate_controls)) static struct control_menu_info flicker_controls[] = { @@ -113,7 +113,7 @@ static struct control_menu_info flicker_controls[] = { FLICKER_50, "50 Hz" }, { FLICKER_60, "60 Hz" }, }; -#define NUM_FLICKER_CONTROLS (sizeof(flicker_controls)/sizeof(flicker_controls[0])) +#define NUM_FLICKER_CONTROLS (ARRAY_SIZE(flicker_controls)) static struct control_menu_info lights_controls[] = { @@ -122,7 +122,7 @@ static struct control_menu_info lights_controls[] = { 128, "Bottom" }, { 192, "Both" }, }; -#define NUM_LIGHTS_CONTROLS (sizeof(lights_controls)/sizeof(lights_controls[0])) +#define NUM_LIGHTS_CONTROLS (ARRAY_SIZE(lights_controls)) #define GPIO_LIGHTS_MASK 192 static struct v4l2_queryctrl controls[] = { @@ -235,7 +235,7 @@ static struct v4l2_queryctrl controls[] = { .default_value = 0, }, }; -#define NUM_CONTROLS (sizeof(controls)/sizeof(controls[0])) +#define NUM_CONTROLS (ARRAY_SIZE(controls)) /****************************************************************************** diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index 0f9d96963618..f750a543c961 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig @@ -47,7 +47,7 @@ config VIDEO_CX88_DVB tristate "DVB/ATSC Support for cx2388x based TV cards" depends on VIDEO_CX88 && DVB_CORE select VIDEO_BUF_DVB - select DVB_PLL + select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_MT352 if !DVB_FE_CUSTOMISE select DVB_ZL10353 if !DVB_FE_CUSTOMISE select DVB_OR51132 if !DVB_FE_CUSTOMISE diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index a80b1cb1abe8..f2fcdb92ecce 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -56,8 +56,7 @@ MODULE_PARM_DESC(debug,"enable debug messages [blackbird]"); /* ------------------------------------------------------------------ */ -#define OLD_BLACKBIRD_FIRM_IMAGE_SIZE 262144 -#define BLACKBIRD_FIRM_IMAGE_SIZE 376836 +#define BLACKBIRD_FIRM_IMAGE_SIZE 376836 /* defines below are from ivtv-driver.h */ @@ -405,7 +404,7 @@ static int blackbird_find_mailbox(struct cx8802_dev *dev) u32 value; int i; - for (i = 0; i < dev->fw_size; i++) { + for (i = 0; i < BLACKBIRD_FIRM_IMAGE_SIZE; i++) { memory_read(dev->core, i, &value); if (value == signature[signaturecnt]) signaturecnt++; @@ -453,15 +452,12 @@ static int blackbird_load_firmware(struct cx8802_dev *dev) return -1; } - if ((firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) && - (firmware->size != OLD_BLACKBIRD_FIRM_IMAGE_SIZE)) { - dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d or %d)\n", - firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE, - OLD_BLACKBIRD_FIRM_IMAGE_SIZE); + if (firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) { + dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d)\n", + firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE); release_firmware(firmware); return -1; } - dev->fw_size = firmware->size; if (0 != memcmp(firmware->data, magic, 8)) { dprintk(0, "ERROR: Firmware magic mismatch, wrong file?\n"); diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index e61102dc8ad7..6a136ddbccf8 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1335,6 +1335,26 @@ struct cx88_board cx88_boards[] = { /* fixme: Add radio support */ .mpeg = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD, }, + [CX88_BOARD_ADSTECH_PTV_390] = { + .name = "ADS Tech Instant Video PCI", + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DEBUG, + .vmux = 3, + .gpio0 = 0x04ff, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x07fa, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x07fa, + }}, + }, }; const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards); @@ -1641,6 +1661,10 @@ struct cx88_subid cx88_subids[] = { .subvendor = 0x1421, .subdevice = 0x0341, /* ADS Tech InstantTV DVB-S */ .card = CX88_BOARD_KWORLD_DVBS_100, + },{ + .subvendor = 0x1421, + .subdevice = 0x0390, + .card = CX88_BOARD_ADSTECH_PTV_390, }, }; const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index dbfe4dc9cf8c..1773b40467dc 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -35,9 +35,7 @@ #include "mt352.h" #include "mt352_priv.h" -#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE) -# include "cx88-vp3054-i2c.h" -#endif +#include "cx88-vp3054-i2c.h" #include "zl10353.h" #include "cx22702.h" #include "or51132.h" @@ -199,7 +197,7 @@ static struct mt352_config dvico_fusionhdtv_dual = { .demod_init = dvico_dual_demod_init, }; -#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE) +#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE)) static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe) { static u8 clock_config [] = { 0x89, 0x38, 0x38 }; @@ -223,64 +221,6 @@ static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe) return 0; } -static int philips_fmd1216_pll_init(struct dvb_frontend *fe) -{ - struct cx8802_dev *dev= fe->dvb->priv; - - /* this message is to set up ATC and ALC */ - static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 }; - struct i2c_msg msg = - { .addr = dev->core->pll_addr, .flags = 0, - .buf = fmd1216_init, .len = sizeof(fmd1216_init) }; - int err; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) { - if (err < 0) - return err; - else - return -EREMOTEIO; - } - - return 0; -} - -static int dntv_live_dvbt_pro_tuner_set_params(struct dvb_frontend* fe, - struct dvb_frontend_parameters* params) -{ - struct cx8802_dev *dev= fe->dvb->priv; - u8 buf[4]; - struct i2c_msg msg = - { .addr = dev->core->pll_addr, .flags = 0, - .buf = buf, .len = 4 }; - int err; - - /* Switch PLL to DVB mode */ - err = philips_fmd1216_pll_init(fe); - if (err) - return err; - - /* Tune PLL */ - dvb_pll_configure(dev->core->pll_desc, buf, - params->frequency, - params->u.ofdm.bandwidth); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - 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__, dev->core->pll_addr, buf[0], err); - if (err < 0) - return err; - else - return -EREMOTEIO; - } - - return 0; -} - static struct mt352_config dntv_live_dvbt_pro_config = { .demod_address = 0x0f, .no_tuner = 1, @@ -370,18 +310,8 @@ static int nxt200x_set_ts_param(struct dvb_frontend* fe, int is_punctured) return 0; } -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 ati_hdtvwonder = { .demod_address = 0x0a, - .set_pll_input = nxt200x_set_pll_input, .set_ts_params = nxt200x_set_ts_param, }; @@ -456,7 +386,7 @@ static int dvb_register(struct cx8802_dev *dev) if (dev->dvb.frontend != NULL) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, &dev->core->i2c_adap, - &dvb_pll_thomson_dtt759x); + DVB_PLL_THOMSON_DTT759X); } break; case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1: @@ -469,7 +399,7 @@ static int dvb_register(struct cx8802_dev *dev) if (dev->dvb.frontend != NULL) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60, &dev->core->i2c_adap, - &dvb_pll_thomson_dtt7579); + DVB_PLL_THOMSON_DTT7579); } break; case CX88_BOARD_WINFAST_DTV2000H: @@ -482,7 +412,7 @@ static int dvb_register(struct cx8802_dev *dev) &dev->core->i2c_adap); if (dev->dvb.frontend != NULL) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, - &dev->core->i2c_adap, &dvb_pll_fmd1216me); + &dev->core->i2c_adap, DVB_PLL_FMD1216ME); } break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS: @@ -491,7 +421,7 @@ static int dvb_register(struct cx8802_dev *dev) &dev->core->i2c_adap); if (dev->dvb.frontend != NULL) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60, - NULL, &dvb_pll_thomson_dtt7579); + NULL, DVB_PLL_THOMSON_DTT7579); break; } /* ZL10353 replaces MT352 on later cards */ @@ -500,7 +430,7 @@ static int dvb_register(struct cx8802_dev *dev) &dev->core->i2c_adap); if (dev->dvb.frontend != NULL) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60, - NULL, &dvb_pll_thomson_dtt7579); + NULL, DVB_PLL_THOMSON_DTT7579); } break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL: @@ -511,7 +441,7 @@ static int dvb_register(struct cx8802_dev *dev) &dev->core->i2c_adap); if (dev->dvb.frontend != NULL) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, - NULL, &dvb_pll_thomson_dtt7579); + NULL, DVB_PLL_THOMSON_DTT7579); break; } /* ZL10353 replaces MT352 on later cards */ @@ -520,7 +450,7 @@ static int dvb_register(struct cx8802_dev *dev) &dev->core->i2c_adap); if (dev->dvb.frontend != NULL) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, - NULL, &dvb_pll_thomson_dtt7579); + NULL, DVB_PLL_THOMSON_DTT7579); } break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1: @@ -529,7 +459,7 @@ static int dvb_register(struct cx8802_dev *dev) &dev->core->i2c_adap); if (dev->dvb.frontend != NULL) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, - NULL, &dvb_pll_lg_z201); + NULL, DVB_PLL_LG_Z201); } break; case CX88_BOARD_KWORLD_DVB_T: @@ -540,17 +470,16 @@ static int dvb_register(struct cx8802_dev *dev) &dev->core->i2c_adap); if (dev->dvb.frontend != NULL) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, - NULL, &dvb_pll_unknown_1); + NULL, DVB_PLL_UNKNOWN_1); } break; case CX88_BOARD_DNTV_LIVE_DVB_T_PRO: -#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE) - dev->core->pll_addr = 0x61; - dev->core->pll_desc = &dvb_pll_fmd1216me; +#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE)) dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config, &((struct vp3054_i2c_state *)dev->card_priv)->adap); if (dev->dvb.frontend != NULL) { - dev->dvb.frontend->ops.tuner_ops.set_params = dntv_live_dvbt_pro_tuner_set_params; + dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, + &dev->core->i2c_adap, DVB_PLL_FMD1216ME); } #else printk("%s: built without vp3054 support\n", dev->core->name); @@ -563,7 +492,7 @@ static int dvb_register(struct cx8802_dev *dev) if (dev->dvb.frontend != NULL) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, &dev->core->i2c_adap, - &dvb_pll_thomson_fe6600); + DVB_PLL_THOMSON_FE6600); } break; case CX88_BOARD_PCHDTV_HD3000: @@ -572,7 +501,7 @@ static int dvb_register(struct cx8802_dev *dev) if (dev->dvb.frontend != NULL) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, &dev->core->i2c_adap, - &dvb_pll_thomson_dtt761x); + DVB_PLL_THOMSON_DTT761X); } break; case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q: @@ -594,7 +523,7 @@ static int dvb_register(struct cx8802_dev *dev) if (dev->dvb.frontend != NULL) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, &dev->core->i2c_adap, - &dvb_pll_microtune_4042); + DVB_PLL_MICROTUNE_4042); } } break; @@ -614,7 +543,7 @@ static int dvb_register(struct cx8802_dev *dev) if (dev->dvb.frontend != NULL) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, &dev->core->i2c_adap, - &dvb_pll_thomson_dtt761x); + DVB_PLL_THOMSON_DTT761X); } } break; @@ -634,7 +563,7 @@ static int dvb_register(struct cx8802_dev *dev) if (dev->dvb.frontend != NULL) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, &dev->core->i2c_adap, - &dvb_pll_lg_tdvs_h06xf); + DVB_PLL_LG_TDVS_H06XF); } } break; @@ -654,7 +583,7 @@ static int dvb_register(struct cx8802_dev *dev) if (dev->dvb.frontend != NULL) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, &dev->core->i2c_adap, - &dvb_pll_lg_tdvs_h06xf); + DVB_PLL_LG_TDVS_H06XF); } } break; @@ -664,7 +593,7 @@ static int dvb_register(struct cx8802_dev *dev) &dev->core->i2c_adap); if (dev->dvb.frontend != NULL) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, - NULL, &dvb_pll_tuv1236d); + NULL, DVB_PLL_TUV1236D); } break; case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: @@ -705,10 +634,6 @@ static int dvb_register(struct cx8802_dev *dev) return -1; } - if (dev->core->pll_desc) { - dev->dvb.frontend->ops.info.frequency_min = dev->core->pll_desc->min; - dev->dvb.frontend->ops.info.frequency_max = dev->core->pll_desc->max; - } /* Ensure all frontends negotiate bus access */ dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl; @@ -778,11 +703,10 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) if (!(cx88_boards[core->board].mpeg & CX88_MPEG_DVB)) goto fail_core; -#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE) + /* If vp3054 isn't enabled, a stub will just return 0 */ err = vp3054_i2c_probe(dev); if (0 != err) goto fail_core; -#endif /* dvb stuff */ printk("%s/2: cx2388x based dvb card\n", core->name); @@ -807,9 +731,7 @@ static int cx8802_dvb_remove(struct cx8802_driver *drv) /* dvb */ videobuf_dvb_unregister(&dev->dvb); -#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE) vp3054_i2c_remove(dev); -#endif return 0; } diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index 7919a1f9da06..78bbcfab9670 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -160,7 +160,7 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg) i2c_clients_command(&core->i2c_adap, cmd, arg); } -static struct i2c_algo_bit_data cx8800_i2c_algo_template = { +static const struct i2c_algo_bit_data cx8800_i2c_algo_template = { .setsda = cx8800_bit_setsda, .setscl = cx8800_bit_setscl, .getsda = cx8800_bit_getsda, @@ -171,18 +171,6 @@ static struct i2c_algo_bit_data cx8800_i2c_algo_template = { /* ----------------------------------------------------------------------- */ -static struct i2c_adapter cx8800_i2c_adap_template = { - .name = "cx2388x", - .owner = THIS_MODULE, - .id = I2C_HW_B_CX2388x, - .client_register = attach_inform, - .client_unregister = detach_inform, -}; - -static struct i2c_client cx8800_i2c_client_template = { - .name = "cx88xx internal", -}; - static char *i2c_devs[128] = { [ 0x1c >> 1 ] = "lgdt330x", [ 0x86 >> 1 ] = "tda9887/cx22702", @@ -212,14 +200,9 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) /* Prevents usage of invalid delay values */ if (i2c_udelay<5) i2c_udelay=5; - cx8800_i2c_algo_template.udelay=i2c_udelay; - memcpy(&core->i2c_adap, &cx8800_i2c_adap_template, - sizeof(core->i2c_adap)); memcpy(&core->i2c_algo, &cx8800_i2c_algo_template, sizeof(core->i2c_algo)); - memcpy(&core->i2c_client, &cx8800_i2c_client_template, - sizeof(core->i2c_client)); if (core->tuner_type != TUNER_ABSENT) core->i2c_adap.class |= I2C_CLASS_TV_ANALOG; @@ -228,10 +211,16 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) core->i2c_adap.dev.parent = &pci->dev; strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name)); + core->i2c_adap.owner = THIS_MODULE; + core->i2c_adap.id = I2C_HW_B_CX2388x; + core->i2c_adap.client_register = attach_inform; + core->i2c_adap.client_unregister = detach_inform; + core->i2c_algo.udelay = i2c_udelay; core->i2c_algo.data = core; i2c_set_adapdata(&core->i2c_adap,core); core->i2c_adap.algo_data = &core->i2c_algo; core->i2c_client.adapter = &core->i2c_adap; + strlcpy(core->i2c_client.name, "cx88xx internal", I2C_NAME_SIZE); cx8800_bit_setscl(core,1); cx8800_bit_setsda(core,1); diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index 8136673fe9e8..f5d4a565346e 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -74,7 +74,8 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) /* read gpio value */ gpio = cx_read(ir->gpio_addr); - if (core->board == CX88_BOARD_NPGTECH_REALTV_TOP10FM) { + switch (core->board) { + case CX88_BOARD_NPGTECH_REALTV_TOP10FM: /* This board apparently uses a combination of 2 GPIO to represent the keys. Additionally, the second GPIO can be used for parity. @@ -90,9 +91,14 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) auxgpio = cx_read(MO_GP1_IO); /* Take out the parity part */ gpio=(gpio & 0x7fd) + (auxgpio & 0xef); - } else + break; + case CX88_BOARD_WINFAST_DTV1000: + gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900); auxgpio = gpio; - + break; + default: + auxgpio = gpio; + } if (ir->polling) { if (ir->last_gpio == auxgpio) return; @@ -148,20 +154,16 @@ static void ir_timer(unsigned long data) static void cx88_ir_work(struct work_struct *work) { struct cx88_IR *ir = container_of(work, struct cx88_IR, work); - unsigned long timeout; cx88_ir_handle_key(ir); - timeout = jiffies + (ir->polling * HZ / 1000); - mod_timer(&ir->timer, timeout); + mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); } static void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir) { if (ir->polling) { + setup_timer(&ir->timer, ir_timer, (unsigned long)ir); INIT_WORK(&ir->work, cx88_ir_work); - init_timer(&ir->timer); - ir->timer.function = ir_timer; - ir->timer.data = (unsigned long)ir; schedule_work(&ir->work); } if (ir->sampling) { @@ -222,7 +224,6 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: case CX88_BOARD_HAUPPAUGE_HVR1100: - case CX88_BOARD_HAUPPAUGE_HVR1300: case CX88_BOARD_HAUPPAUGE_HVR3000: ir_codes = ir_codes_hauppauge_new; ir_type = IR_TYPE_RC5; @@ -236,6 +237,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->polling = 50; /* ms */ break; case CX88_BOARD_WINFAST2000XP_EXPERT: + case CX88_BOARD_WINFAST_DTV1000: ir_codes = ir_codes_winfast; ir->gpio_addr = MO_GP0_IO; ir->mask_keycode = 0x8f8; @@ -328,7 +330,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) input_dev->id.vendor = pci->vendor; input_dev->id.product = pci->device; } - input_dev->cdev.dev = &pci->dev; + input_dev->dev.parent = &pci->dev; /* record handles to ourself */ ir->core = core; core->ir = ir; @@ -442,7 +444,6 @@ void cx88_ir_irq(struct cx88_core *core) case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: case CX88_BOARD_HAUPPAUGE_HVR1100: - case CX88_BOARD_HAUPPAUGE_HVR1300: case CX88_BOARD_HAUPPAUGE_HVR3000: ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7); ir_dprintk("biphase decoded: %x\n", ircode); diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 543b05ebc0e7..317a2a3f9cc1 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -336,7 +336,7 @@ static void cx8802_timeout(unsigned long data) { struct cx8802_dev *dev = (struct cx8802_dev*)data; - dprintk(0, "%s\n",__FUNCTION__); + dprintk(1, "%s\n",__FUNCTION__); if (debug) cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]); diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c index 82bc3a28aa22..cd0877636a32 100644 --- a/drivers/media/video/cx88/cx88-vp3054-i2c.c +++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c @@ -94,7 +94,7 @@ static int vp3054_bit_getsda(void *data) /* ----------------------------------------------------------------------- */ -static struct i2c_algo_bit_data vp3054_i2c_algo_template = { +static const struct i2c_algo_bit_data vp3054_i2c_algo_template = { .setsda = vp3054_bit_setsda, .setscl = vp3054_bit_setscl, .getsda = vp3054_bit_getsda, @@ -105,12 +105,6 @@ static struct i2c_algo_bit_data vp3054_i2c_algo_template = { /* ----------------------------------------------------------------------- */ -static struct i2c_adapter vp3054_i2c_adap_template = { - .name = "cx2388x", - .owner = THIS_MODULE, - .id = I2C_HW_B_CX2388x, -}; - int vp3054_i2c_probe(struct cx8802_dev *dev) { struct cx88_core *core = dev->core; @@ -125,8 +119,6 @@ int vp3054_i2c_probe(struct cx8802_dev *dev) return -ENOMEM; vp3054_i2c = dev->card_priv; - memcpy(&vp3054_i2c->adap, &vp3054_i2c_adap_template, - sizeof(vp3054_i2c->adap)); memcpy(&vp3054_i2c->algo, &vp3054_i2c_algo_template, sizeof(vp3054_i2c->algo)); @@ -135,6 +127,8 @@ int vp3054_i2c_probe(struct cx8802_dev *dev) vp3054_i2c->adap.dev.parent = &dev->pci->dev; strlcpy(vp3054_i2c->adap.name, core->name, sizeof(vp3054_i2c->adap.name)); + vp3054_i2c->adap.owner = THIS_MODULE; + vp3054_i2c->adap.id = I2C_HW_B_CX2388x; vp3054_i2c->algo.data = dev; i2c_set_adapdata(&vp3054_i2c->adap, dev); vp3054_i2c->adap.algo_data = &vp3054_i2c->algo; diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.h b/drivers/media/video/cx88/cx88-vp3054-i2c.h index 637a7d232238..be99c931dc3e 100644 --- a/drivers/media/video/cx88/cx88-vp3054-i2c.h +++ b/drivers/media/video/cx88/cx88-vp3054-i2c.h @@ -30,5 +30,12 @@ struct vp3054_i2c_state { }; /* ----------------------------------------------------------------------- */ +#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE)) int vp3054_i2c_probe(struct cx8802_dev *dev); void vp3054_i2c_remove(struct cx8802_dev *dev); +#else +static inline int vp3054_i2c_probe(struct cx8802_dev *dev) +{ return 0; } +static inline void vp3054_i2c_remove(struct cx8802_dev *dev) +{ } +#endif diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 738d4f20c580..c4f656ec46b0 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -209,6 +209,7 @@ extern struct sram_channel cx88_sram_channels[]; #define CX88_BOARD_NORWOOD_MICRO 54 #define CX88_BOARD_TE_DTV_250_OEM_SWANN 55 #define CX88_BOARD_HAUPPAUGE_HVR1300 56 +#define CX88_BOARD_ADSTECH_PTV_390 57 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, @@ -316,8 +317,6 @@ struct cx88_core { /* config info -- dvb */ #if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) - struct dvb_pll_desc *pll_desc; - unsigned int pll_addr; int (*prev_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); #endif @@ -463,13 +462,10 @@ struct cx8802_dev { u32 mailbox; int width; int height; - int fw_size; #if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) /* for dvb only */ struct videobuf_dvb dvb; - void* fe_handle; - int (*fe_release)(void *handle); void *card_priv; #endif diff --git a/drivers/media/video/et61x251/Kconfig b/drivers/media/video/et61x251/Kconfig index 664676f44068..dcc1a0335440 100644 --- a/drivers/media/video/et61x251/Kconfig +++ b/drivers/media/video/et61x251/Kconfig @@ -1,6 +1,6 @@ config USB_ET61X251 tristate "USB ET61X[12]51 PC Camera Controller support" - depends on VIDEO_V4L1 + depends on VIDEO_V4L2 ---help--- Say Y here if you want support for cameras based on Etoms ET61X151 or ET61X251 PC Camera Controllers. diff --git a/drivers/media/video/et61x251/et61x251.h b/drivers/media/video/et61x251/et61x251.h index 262f98e12409..02c741d8f85a 100644 --- a/drivers/media/video/et61x251/et61x251.h +++ b/drivers/media/video/et61x251/et61x251.h @@ -36,6 +36,7 @@ #include <linux/mutex.h> #include <linux/stddef.h> #include <linux/string.h> +#include <linux/kref.h> #include "et61x251_sensor.h" @@ -134,7 +135,7 @@ struct et61x251_module_param { }; static DEFINE_MUTEX(et61x251_sysfs_lock); -static DECLARE_RWSEM(et61x251_disconnect); +static DECLARE_RWSEM(et61x251_dev_lock); struct et61x251_device { struct video_device* v4ldev; @@ -158,12 +159,14 @@ struct et61x251_device { struct et61x251_sysfs_attr sysfs; struct et61x251_module_param module_param; + struct kref kref; enum et61x251_dev_state state; u8 users; - struct mutex dev_mutex, fileop_mutex; + struct completion probe; + struct mutex open_mutex, fileop_mutex; spinlock_t queue_lock; - wait_queue_head_t open, wait_frame, wait_stream; + wait_queue_head_t wait_open, wait_frame, wait_stream; }; /*****************************************************************************/ @@ -177,7 +180,7 @@ et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id) void et61x251_attach_sensor(struct et61x251_device* cam, - struct et61x251_sensor* sensor) + const struct et61x251_sensor* sensor) { memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor)); } @@ -195,8 +198,8 @@ do { \ else if ((level) == 2) \ dev_info(&cam->usbdev->dev, fmt "\n", ## args); \ else if ((level) >= 3) \ - dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ - __FUNCTION__, __LINE__ , ## args); \ + dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \ + __FILE__, __FUNCTION__, __LINE__ , ## args); \ } \ } while (0) # define KDBG(level, fmt, args...) \ @@ -205,8 +208,8 @@ do { \ if ((level) == 1 || (level) == 2) \ pr_info("et61x251: " fmt "\n", ## args); \ else if ((level) == 3) \ - pr_debug("et61x251: [%s:%d] " fmt "\n", __FUNCTION__, \ - __LINE__ , ## args); \ + pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__, \ + __FUNCTION__, __LINE__ , ## args); \ } \ } while (0) # define V4LDBG(level, name, cmd) \ @@ -222,8 +225,8 @@ do { \ #undef PDBG #define PDBG(fmt, args...) \ -dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ - __FUNCTION__, __LINE__ , ## args) +dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__, \ + __LINE__ , ## args) #undef PDBGG #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index a6525513cd1e..585bd1fe0765 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -45,11 +45,11 @@ #define ET61X251_MODULE_NAME "V4L2 driver for ET61X[12]51 " \ "PC Camera Controllers" -#define ET61X251_MODULE_AUTHOR "(C) 2006 Luca Risolia" +#define ET61X251_MODULE_AUTHOR "(C) 2006-2007 Luca Risolia" #define ET61X251_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>" #define ET61X251_MODULE_LICENSE "GPL" -#define ET61X251_MODULE_VERSION "1:1.04" -#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 4) +#define ET61X251_MODULE_VERSION "1:1.09" +#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 9) /*****************************************************************************/ @@ -245,7 +245,8 @@ int et61x251_read_reg(struct et61x251_device* cam, u16 index) static int -et61x251_i2c_wait(struct et61x251_device* cam, struct et61x251_sensor* sensor) +et61x251_i2c_wait(struct et61x251_device* cam, + const struct et61x251_sensor* sensor) { int i, r; @@ -270,7 +271,7 @@ et61x251_i2c_wait(struct et61x251_device* cam, struct et61x251_sensor* sensor) int et61x251_i2c_try_read(struct et61x251_device* cam, - struct et61x251_sensor* sensor, u8 address) + const struct et61x251_sensor* sensor, u8 address) { struct usb_device* udev = cam->usbdev; u8* data = cam->control_buffer; @@ -303,7 +304,8 @@ et61x251_i2c_try_read(struct et61x251_device* cam, int et61x251_i2c_try_write(struct et61x251_device* cam, - struct et61x251_sensor* sensor, u8 address, u8 value) + const struct et61x251_sensor* sensor, u8 address, + u8 value) { struct usb_device* udev = cam->usbdev; u8* data = cam->control_buffer; @@ -615,7 +617,7 @@ static int et61x251_start_transfer(struct et61x251_device* cam) return 0; free_urbs: - for (i = 0; (i < ET61X251_URBS) && cam->urb[i]; i++) + for (i = 0; (i < ET61X251_URBS) && cam->urb[i]; i++) usb_free_urb(cam->urb[i]); free_buffers: @@ -682,7 +684,7 @@ static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count) if (len < 4) { strncpy(str, buff, len); - str[len+1] = '\0'; + str[len] = '\0'; } else { strncpy(str, buff, 4); str[4] = '\0'; @@ -977,30 +979,30 @@ static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, static int et61x251_create_sysfs(struct et61x251_device* cam) { - struct video_device *v4ldev = cam->v4ldev; + struct class_device *classdev = &(cam->v4ldev->class_dev); int err = 0; - if ((err = video_device_create_file(v4ldev, &class_device_attr_reg))) + if ((err = class_device_create_file(classdev, &class_device_attr_reg))) goto err_out; - if ((err = video_device_create_file(v4ldev, &class_device_attr_val))) + if ((err = class_device_create_file(classdev, &class_device_attr_val))) goto err_reg; if (cam->sensor.sysfs_ops) { - if ((err = video_device_create_file(v4ldev, + if ((err = class_device_create_file(classdev, &class_device_attr_i2c_reg))) goto err_val; - if ((err = video_device_create_file(v4ldev, + if ((err = class_device_create_file(classdev, &class_device_attr_i2c_val))) goto err_i2c_reg; } err_i2c_reg: if (cam->sensor.sysfs_ops) - video_device_remove_file(v4ldev, &class_device_attr_i2c_reg); + class_device_remove_file(classdev, &class_device_attr_i2c_reg); err_val: - video_device_remove_file(v4ldev, &class_device_attr_val); + class_device_remove_file(classdev, &class_device_attr_val); err_reg: - video_device_remove_file(v4ldev, &class_device_attr_reg); + class_device_remove_file(classdev, &class_device_attr_reg); err_out: return err; } @@ -1103,7 +1105,8 @@ static int et61x251_init(struct et61x251_device* cam) int err = 0; if (!(cam->state & DEV_INITIALIZED)) { - init_waitqueue_head(&cam->open); + mutex_init(&cam->open_mutex); + init_waitqueue_head(&cam->wait_open); qctrl = s->qctrl; rect = &(s->cropcap.defrect); cam->compression.quality = ET61X251_COMPRESSION_QUALITY; @@ -1177,64 +1180,80 @@ static int et61x251_init(struct et61x251_device* cam) return 0; } +/*****************************************************************************/ -static void et61x251_release_resources(struct et61x251_device* cam) +static void et61x251_release_resources(struct kref *kref) { + struct et61x251_device *cam; + mutex_lock(&et61x251_sysfs_lock); + cam = container_of(kref, struct et61x251_device, kref); + DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor); video_set_drvdata(cam->v4ldev, NULL); video_unregister_device(cam->v4ldev); + usb_put_dev(cam->usbdev); + kfree(cam->control_buffer); + kfree(cam); mutex_unlock(&et61x251_sysfs_lock); - - kfree(cam->control_buffer); } -/*****************************************************************************/ static int et61x251_open(struct inode* inode, struct file* filp) { struct et61x251_device* cam; int err = 0; - /* - This is the only safe way to prevent race conditions with - disconnect - */ - if (!down_read_trylock(&et61x251_disconnect)) + if (!down_read_trylock(&et61x251_dev_lock)) return -ERESTARTSYS; cam = video_get_drvdata(video_devdata(filp)); - if (mutex_lock_interruptible(&cam->dev_mutex)) { - up_read(&et61x251_disconnect); + if (wait_for_completion_interruptible(&cam->probe)) { + up_read(&et61x251_dev_lock); return -ERESTARTSYS; } + kref_get(&cam->kref); + + if (mutex_lock_interruptible(&cam->open_mutex)) { + kref_put(&cam->kref, et61x251_release_resources); + up_read(&et61x251_dev_lock); + return -ERESTARTSYS; + } + + if (cam->state & DEV_DISCONNECTED) { + DBG(1, "Device not present"); + err = -ENODEV; + goto out; + } + if (cam->users) { - DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor); + DBG(2, "Device /dev/video%d is already in use", + cam->v4ldev->minor); + DBG(3, "Simultaneous opens are not supported"); if ((filp->f_flags & O_NONBLOCK) || (filp->f_flags & O_NDELAY)) { err = -EWOULDBLOCK; goto out; } - mutex_unlock(&cam->dev_mutex); - err = wait_event_interruptible_exclusive(cam->open, - cam->state & DEV_DISCONNECTED + DBG(2, "A blocking open() has been requested. Wait for the " + "device to be released..."); + up_read(&et61x251_dev_lock); + err = wait_event_interruptible_exclusive(cam->wait_open, + (cam->state & DEV_DISCONNECTED) || !cam->users); - if (err) { - up_read(&et61x251_disconnect); - return err; - } + down_read(&et61x251_dev_lock); + if (err) + goto out; if (cam->state & DEV_DISCONNECTED) { - up_read(&et61x251_disconnect); - return -ENODEV; + err = -ENODEV; + goto out; } - mutex_lock(&cam->dev_mutex); } - if (cam->state & DEV_MISCONFIGURED) { err = et61x251_init(cam); if (err) { @@ -1259,36 +1278,32 @@ static int et61x251_open(struct inode* inode, struct file* filp) DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor); out: - mutex_unlock(&cam->dev_mutex); - up_read(&et61x251_disconnect); + mutex_unlock(&cam->open_mutex); + if (err) + kref_put(&cam->kref, et61x251_release_resources); + up_read(&et61x251_dev_lock); return err; } static int et61x251_release(struct inode* inode, struct file* filp) { - struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); + struct et61x251_device* cam; - mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */ + down_write(&et61x251_dev_lock); - et61x251_stop_transfer(cam); + cam = video_get_drvdata(video_devdata(filp)); + et61x251_stop_transfer(cam); et61x251_release_buffers(cam); - - if (cam->state & DEV_DISCONNECTED) { - et61x251_release_resources(cam); - usb_put_dev(cam->usbdev); - mutex_unlock(&cam->dev_mutex); - kfree(cam); - return 0; - } - cam->users--; - wake_up_interruptible_nr(&cam->open, 1); + wake_up_interruptible_nr(&cam->wait_open, 1); DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor); - mutex_unlock(&cam->dev_mutex); + kref_put(&cam->kref, et61x251_release_resources); + + up_write(&et61x251_dev_lock); return 0; } @@ -1324,7 +1339,7 @@ et61x251_read(struct file* filp, char __user * buf, DBG(3, "Close and open the device again to choose the read " "method"); mutex_unlock(&cam->fileop_mutex); - return -EINVAL; + return -EBUSY; } if (cam->io == IO_NONE) { @@ -1504,7 +1519,12 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma) return -EIO; } - if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || + if (!(vma->vm_flags & (VM_WRITE | VM_READ))) { + mutex_unlock(&cam->fileop_mutex); + return -EACCES; + } + + if (cam->io != IO_MMAP || size != PAGE_ALIGN(cam->frame[0].buf.length)) { mutex_unlock(&cam->fileop_mutex); return -EINVAL; @@ -1535,7 +1555,6 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma) vma->vm_ops = &et61x251_vm_ops; vma->vm_private_data = &cam->frame[i]; - et61x251_vm_open(vma); mutex_unlock(&cam->fileop_mutex); @@ -1764,7 +1783,7 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg) if (cam->frame[i].vma_use_count) { DBG(3, "VIDIOC_S_CROP failed. " "Unmap the buffers first."); - return -EINVAL; + return -EBUSY; } /* Preserve R,G or B origin */ @@ -1921,6 +1940,8 @@ et61x251_vidioc_g_fmt(struct et61x251_device* cam, void __user * arg) if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; + pfmt->colorspace = (pfmt->pixelformat == V4L2_PIX_FMT_ET61X251) ? + 0 : V4L2_COLORSPACE_SRGB; pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_ET61X251) ? 0 : (pfmt->width * pfmt->priv) / 8; pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8); @@ -1996,6 +2017,8 @@ et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd, pix->pixelformat != V4L2_PIX_FMT_SBGGR8) pix->pixelformat = pfmt->pixelformat; pix->priv = pfmt->priv; /* bpp */ + pix->colorspace = (pix->pixelformat == V4L2_PIX_FMT_ET61X251) ? + 0 : V4L2_COLORSPACE_SRGB; pix->colorspace = pfmt->colorspace; pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_ET61X251) ? 0 : (pix->width * pix->priv) / 8; @@ -2013,7 +2036,7 @@ et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd, if (cam->frame[i].vma_use_count) { DBG(3, "VIDIOC_S_FMT failed. " "Unmap the buffers first."); - return -EINVAL; + return -EBUSY; } if (cam->stream == STREAM_ON) @@ -2129,14 +2152,14 @@ et61x251_vidioc_reqbufs(struct et61x251_device* cam, void __user * arg) if (cam->io == IO_READ) { DBG(3, "Close and open the device again to choose the mmap " "I/O method"); - return -EINVAL; + return -EBUSY; } for (i = 0; i < cam->nbuffers; i++) if (cam->frame[i].vma_use_count) { DBG(3, "VIDIOC_REQBUFS failed. " "Previous buffers are still mapped."); - return -EINVAL; + return -EBUSY; } if (cam->stream == STREAM_ON) @@ -2284,9 +2307,6 @@ et61x251_vidioc_streamon(struct et61x251_device* cam, void __user * arg) if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) return -EINVAL; - if (list_empty(&cam->inqueue)) - return -EINVAL; - cam->stream = STREAM_ON; DBG(3, "Stream on"); @@ -2535,8 +2555,6 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) goto fail; } - mutex_init(&cam->dev_mutex); - DBG(2, "ET61X[12]51 PC Camera Controller detected " "(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct); @@ -2568,7 +2586,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) cam->v4ldev->release = video_device_release; video_set_drvdata(cam->v4ldev, cam); - mutex_lock(&cam->dev_mutex); + init_completion(&cam->probe); err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, video_nr[dev_nr]); @@ -2578,7 +2596,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) DBG(1, "Free /dev/videoX node not found"); video_nr[dev_nr] = -1; dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0; - mutex_unlock(&cam->dev_mutex); + complete_all(&cam->probe); goto fail; } @@ -2599,11 +2617,15 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) "device controlling. Error #%d", err); #else DBG(2, "Optional device control through 'sysfs' interface disabled"); + DBG(3, "Compile the kernel with the 'CONFIG_VIDEO_ADV_DEBUG' " + "configuration option to enable it."); #endif usb_set_intfdata(intf, cam); + kref_init(&cam->kref); + usb_get_dev(cam->usbdev); - mutex_unlock(&cam->dev_mutex); + complete_all(&cam->probe); return 0; @@ -2620,40 +2642,31 @@ fail: static void et61x251_usb_disconnect(struct usb_interface* intf) { - struct et61x251_device* cam = usb_get_intfdata(intf); - - if (!cam) - return; + struct et61x251_device* cam; - down_write(&et61x251_disconnect); + down_write(&et61x251_dev_lock); - mutex_lock(&cam->dev_mutex); + cam = usb_get_intfdata(intf); DBG(2, "Disconnecting %s...", cam->v4ldev->name); - wake_up_interruptible_all(&cam->open); - if (cam->users) { DBG(2, "Device /dev/video%d is open! Deregistration and " - "memory deallocation are deferred on close.", + "memory deallocation are deferred.", cam->v4ldev->minor); cam->state |= DEV_MISCONFIGURED; et61x251_stop_transfer(cam); cam->state |= DEV_DISCONNECTED; wake_up_interruptible(&cam->wait_frame); wake_up(&cam->wait_stream); - usb_get_dev(cam->usbdev); - } else { + } else cam->state |= DEV_DISCONNECTED; - et61x251_release_resources(cam); - } - mutex_unlock(&cam->dev_mutex); + wake_up_interruptible_all(&cam->wait_open); - if (!cam->users) - kfree(cam); + kref_put(&cam->kref, et61x251_release_resources); - up_write(&et61x251_disconnect); + up_write(&et61x251_dev_lock); } diff --git a/drivers/media/video/et61x251/et61x251_sensor.h b/drivers/media/video/et61x251/et61x251_sensor.h index 5fadb5de68bf..e14586330623 100644 --- a/drivers/media/video/et61x251/et61x251_sensor.h +++ b/drivers/media/video/et61x251/et61x251_sensor.h @@ -22,7 +22,7 @@ #define _ET61X251_SENSOR_H_ #include <linux/usb.h> -#include <linux/videodev.h> +#include <linux/videodev2.h> #include <linux/device.h> #include <linux/stddef.h> #include <linux/errno.h> @@ -47,7 +47,7 @@ et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id); extern void et61x251_attach_sensor(struct et61x251_device* cam, - struct et61x251_sensor* sensor); + const struct et61x251_sensor* sensor); /*****************************************************************************/ @@ -56,10 +56,10 @@ extern int et61x251_read_reg(struct et61x251_device*, u16 index); extern int et61x251_i2c_write(struct et61x251_device*, u8 address, u8 value); extern int et61x251_i2c_read(struct et61x251_device*, u8 address); extern int et61x251_i2c_try_write(struct et61x251_device*, - struct et61x251_sensor*, u8 address, + const struct et61x251_sensor*, u8 address, u8 value); extern int et61x251_i2c_try_read(struct et61x251_device*, - struct et61x251_sensor*, u8 address); + const struct et61x251_sensor*, u8 address); extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1, u8 data2, u8 data3, u8 data4, u8 data5, u8 data6, u8 data7, u8 data8, u8 address); diff --git a/drivers/media/video/et61x251/et61x251_tas5130d1b.c b/drivers/media/video/et61x251/et61x251_tas5130d1b.c index b06643409842..04b7fbb310a8 100644 --- a/drivers/media/video/et61x251/et61x251_tas5130d1b.c +++ b/drivers/media/video/et61x251/et61x251_tas5130d1b.c @@ -69,7 +69,7 @@ static int tas5130d1b_set_ctrl(struct et61x251_device* cam, } -static struct et61x251_sensor tas5130d1b = { +static const struct et61x251_sensor tas5130d1b = { .name = "TAS5130D1B", .interface = ET61X251_I2C_3WIRES, .rsta = ET61X251_I2C_RSTA_STOP, diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index ed92b6f7187a..2d709e064679 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -37,6 +37,7 @@ #include <linux/errno.h> #include <linux/slab.h> #include <linux/i2c.h> +#include <linux/i2c-id.h> #include <linux/workqueue.h> #include <asm/semaphore.h> @@ -60,21 +61,22 @@ MODULE_PARM_DESC(hauppauge, "Specify Hauppauge remote: 0=black, 1=grey (defaults /* ----------------------------------------------------------------------- */ -static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw, + int size, int offset) { - unsigned char buf[3]; + unsigned char buf[6]; int start, range, toggle, dev, code; /* poll IR chip */ - if (3 != i2c_master_recv(&ir->c,buf,3)) + if (size != i2c_master_recv(&ir->c,buf,size)) return -EIO; /* split rc5 data block ... */ - start = (buf[0] >> 7) & 1; - range = (buf[0] >> 6) & 1; - toggle = (buf[0] >> 5) & 1; - dev = buf[0] & 0x1f; - code = (buf[1] >> 2) & 0x3f; + start = (buf[offset] >> 7) & 1; + range = (buf[offset] >> 6) & 1; + toggle = (buf[offset] >> 5) & 1; + dev = buf[offset] & 0x1f; + code = (buf[offset+1] >> 2) & 0x3f; /* rc5 has two start bits * the first bit must be one @@ -96,6 +98,16 @@ static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) return 1; } +static inline int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +{ + return get_key_haup_common (ir, ir_key, ir_raw, 3, 0); +} + +static inline int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +{ + return get_key_haup_common (ir, ir_key, ir_raw, 6, 3); +} + static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char b; @@ -270,8 +282,9 @@ static void ir_timer(unsigned long data) static void ir_work(struct work_struct *work) { struct IR_i2c *ir = container_of(work, struct IR_i2c, work); + ir_key_poll(ir); - mod_timer(&ir->timer, jiffies+HZ/10); + mod_timer(&ir->timer, jiffies + msecs_to_jiffies(100)); } /* ----------------------------------------------------------------------- */ @@ -354,9 +367,21 @@ static int ir_attach(struct i2c_adapter *adap, int addr, case 0x7a: case 0x47: case 0x71: - /* Handled by saa7134-input */ - name = "SAA713x remote"; - ir_type = IR_TYPE_OTHER; + if (adap->id == I2C_HW_B_CX2388x) { + /* Handled by cx88-input */ + name = "CX2388x remote"; + ir_type = IR_TYPE_RC5; + ir->get_key = get_key_haup_xvr; + if (hauppauge == 1) { + ir_codes = ir_codes_hauppauge_new; + } else { + ir_codes = ir_codes_rc5_tv; + } + } else { + /* Handled by saa7134-input */ + name = "SAA713x remote"; + ir_type = IR_TYPE_OTHER; + } break; default: /* shouldn't happen */ @@ -450,6 +475,7 @@ static int ir_probe(struct i2c_adapter *adap) static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1}; static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, -1 }; static const int probe_em28XX[] = { 0x30, 0x47, -1 }; + static const int probe_cx88[] = { 0x18, 0x71, -1 }; const int *probe = NULL; struct i2c_client c; unsigned char buf; @@ -468,6 +494,9 @@ static int ir_probe(struct i2c_adapter *adap) case I2C_HW_B_EM28XX: probe = probe_em28XX; break; + case I2C_HW_B_CX2388x: + probe = probe_cx88; + break; } if (NULL == probe) return 0; diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index efc66355339a..4c93466a89e5 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -181,7 +181,7 @@ MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC"); MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K"); MODULE_PARM_DESC(debug, "Debug level (bitmask). Default: errors only\n" - "\t\t\t(debug = 511 gives full debugging)"); + "\t\t\t(debug = 1023 gives full debugging)"); MODULE_PARM_DESC(ivtv_pci_latency, "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n" "\t\t\tDefault: Yes"); @@ -339,6 +339,7 @@ static void ivtv_process_eeprom(struct ivtv *itv) /* In a few cases the PCI subsystem IDs do not correctly identify the card. A better method is to check the model number from the eeprom instead. */ + case 30012 ... 30039: /* Low profile PVR250 */ case 32000 ... 32999: case 48000 ... 48099: /* 48??? range are PVR250s with a cx23415 */ case 48400 ... 48599: @@ -622,6 +623,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv) itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */ itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */ + mutex_init(&itv->serialize_lock); mutex_init(&itv->i2c_bus_lock); mutex_init(&itv->udma.lock); @@ -1288,10 +1290,7 @@ static void ivtv_remove(struct pci_dev *pci_dev) IVTV_DEBUG_INFO(" Releasing irq.\n"); free_irq(itv->dev->irq, (void *)itv); - - if (itv->dev) { - ivtv_iounmap(itv); - } + ivtv_iounmap(itv); IVTV_DEBUG_INFO(" Releasing mem.\n"); release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); @@ -1326,9 +1325,9 @@ static int module_start(void) return -1; } - if (ivtv_debug < 0 || ivtv_debug > 511) { + if (ivtv_debug < 0 || ivtv_debug > 1023) { ivtv_debug = 0; - printk(KERN_INFO "ivtv: debug value must be >= 0 and <= 511!\n"); + printk(KERN_INFO "ivtv: debug value must be >= 0 and <= 1023!\n"); } if (pci_register_driver(&ivtv_pci_driver)) { diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index e6e56f175f3f..6c1a85f1ee1b 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -268,6 +268,8 @@ extern const u32 yuv_offset[4]; #define IVTV_DBGFLG_IRQ (1 << 6) #define IVTV_DBGFLG_DEC (1 << 7) #define IVTV_DBGFLG_YUV (1 << 8) +/* Flag to turn on high volume debugging */ +#define IVTV_DBGFLG_HIGHVOL (1 << 9) /* NOTE: extra space before comma in 'itv->num , ## args' is required for gcc-2.95, otherwise it won't compile. */ @@ -286,6 +288,21 @@ extern const u32 yuv_offset[4]; #define IVTV_DEBUG_DEC(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args) #define IVTV_DEBUG_YUV(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) +#define IVTV_DEBUG_HIGH_VOL(x, type, fmt, args...) \ + do { \ + if (((x) & ivtv_debug) && (ivtv_debug & IVTV_DBGFLG_HIGHVOL)) \ + printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \ + } while (0) +#define IVTV_DEBUG_HI_WARN(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN, "warning", fmt , ## args) +#define IVTV_DEBUG_HI_INFO(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO, "info",fmt , ## args) +#define IVTV_DEBUG_HI_API(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_API, "api", fmt , ## args) +#define IVTV_DEBUG_HI_DMA(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DMA, "dma", fmt , ## args) +#define IVTV_DEBUG_HI_IOCTL(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args) +#define IVTV_DEBUG_HI_I2C(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) +#define IVTV_DEBUG_HI_IRQ(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) +#define IVTV_DEBUG_HI_DEC(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DEC, "dec", fmt , ## args) +#define IVTV_DEBUG_HI_YUV(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) + #define IVTV_FB_DEBUG(x, type, fmt, args...) \ do { \ if ((x) & ivtv_debug) \ @@ -650,7 +667,6 @@ struct vbi_info { /* convenience pointer to sliced struct in vbi_in union */ struct v4l2_sliced_vbi_format *sliced_in; u32 service_set_in; - u32 service_set_out; int insert_mpeg; /* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines. @@ -723,6 +739,7 @@ struct ivtv { int search_pack_header; spinlock_t dma_reg_lock; /* lock access to DMA engine registers */ + struct mutex serialize_lock; /* lock used to serialize starting streams */ /* User based DMA for OSD */ struct ivtv_user_dma udma; diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 555d5e6369c3..ee7e884e9c4f 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -406,7 +406,7 @@ static ssize_t ivtv_read_pos(struct ivtv_stream *s, char __user *ubuf, size_t co ssize_t rc = count ? ivtv_read(s, ubuf, count, non_block) : 0; struct ivtv *itv = s->itv; - IVTV_DEBUG_INFO("read %zd from %s, got %zd\n", count, s->name, rc); + IVTV_DEBUG_HI_INFO("read %zd from %s, got %zd\n", count, s->name, rc); if (rc > 0) pos += rc; return rc; @@ -497,7 +497,7 @@ ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_ struct ivtv_stream *s = &itv->streams[id->type]; int rc; - IVTV_DEBUG_IOCTL("read %zd bytes from %s\n", count, s->name); + IVTV_DEBUG_HI_IOCTL("read %zd bytes from %s\n", count, s->name); rc = ivtv_start_capture(id); if (rc) @@ -535,7 +535,7 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c int rc; DEFINE_WAIT(wait); - IVTV_DEBUG_IOCTL("write %zd bytes to %s\n", count, s->name); + IVTV_DEBUG_HI_IOCTL("write %zd bytes to %s\n", count, s->name); if (s->type != IVTV_DEC_STREAM_TYPE_MPG && s->type != IVTV_DEC_STREAM_TYPE_YUV && @@ -643,7 +643,7 @@ retry: to transfer the rest. */ if (count && !(filp->f_flags & O_NONBLOCK)) goto retry; - IVTV_DEBUG_INFO("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused); + IVTV_DEBUG_HI_INFO("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused); return bytes_written; } diff --git a/drivers/media/video/ivtv/ivtv-firmware.c b/drivers/media/video/ivtv/ivtv-firmware.c index d4c910b782af..2b6208a6a108 100644 --- a/drivers/media/video/ivtv/ivtv-firmware.c +++ b/drivers/media/video/ivtv/ivtv-firmware.c @@ -56,9 +56,7 @@ retry: volatile u32 __iomem *dst = (volatile u32 __iomem *)mem; const u32 *src = (const u32 *)fw->data; - /* temporarily allow 256 KB encoding firmwares as well for - compatibility with blackbird cards */ - if (fw->size != size && fw->size != 256 * 1024) { + if (fw->size != size) { /* Due to race conditions in firmware loading (esp. with udev <0.95) the wrong file was sometimes loaded. So we check filesizes to see if at least the right-sized file was loaded. If not, then we diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c index bc8f8ca2961f..676418cbaaad 100644 --- a/drivers/media/video/ivtv/ivtv-gpio.c +++ b/drivers/media/video/ivtv/ivtv-gpio.c @@ -115,8 +115,7 @@ void ivtv_reset_ir_gpio(struct ivtv *itv) curout = (curout & ~0xF) | 1; write_reg(curout, IVTV_REG_GPIO_OUT); /* We could use something else for smaller time */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); + schedule_timeout_interruptible(msecs_to_jiffies(1)); curout |= 2; write_reg(curout, IVTV_REG_GPIO_OUT); curdir &= ~0x80; @@ -138,13 +137,11 @@ int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr) curout &= ~(1 << 12); write_reg(curout, IVTV_REG_GPIO_OUT); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); + schedule_timeout_interruptible(msecs_to_jiffies(1)); curout |= (1 << 12); write_reg(curout, IVTV_REG_GPIO_OUT); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); + schedule_timeout_interruptible(msecs_to_jiffies(1)); return 0; } diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 57af1762de1f..4773453e8dab 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1159,7 +1159,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void memset(fb, 0, sizeof(*fb)); if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) - break; + return -EINVAL; fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY | V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_GLOBAL_ALPHA; fb->fmt.pixelformat = itv->osd_pixelformat; @@ -1179,7 +1179,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void struct v4l2_framebuffer *fb = arg; if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) - break; + return -EINVAL; itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0; itv->osd_local_alpha_state = (fb->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) != 0; itv->osd_color_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0; diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index ba98bf054f2e..1a3ee464a826 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -48,7 +48,7 @@ static void ivtv_pio_work_handler(struct ivtv *itv) struct list_head *p; int i = 0; - IVTV_DEBUG_DMA("ivtv_pio_work_handler\n"); + IVTV_DEBUG_HI_DMA("ivtv_pio_work_handler\n"); if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS || s->v4l2dev == NULL || !ivtv_use_pio(s)) { itv->cur_pio_stream = -1; @@ -56,7 +56,7 @@ static void ivtv_pio_work_handler(struct ivtv *itv) write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44); return; } - IVTV_DEBUG_DMA("Process PIO %s\n", s->name); + IVTV_DEBUG_HI_DMA("Process PIO %s\n", s->name); buf = list_entry(s->q_dma.list.next, struct ivtv_buffer, list); list_for_each(p, &s->q_dma.list) { struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); @@ -187,7 +187,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA bytes_needed += UVsize; } - IVTV_DEBUG_DMA("%s %s: 0x%08x bytes at 0x%08x\n", + IVTV_DEBUG_HI_DMA("%s %s: 0x%08x bytes at 0x%08x\n", ivtv_use_pio(s) ? "PIO" : "DMA", s->name, bytes_needed, offset); rc = ivtv_queue_move(s, &s->q_free, &s->q_full, &s->q_predma, bytes_needed); @@ -242,7 +242,7 @@ static void dma_post(struct ivtv_stream *s) u32 *u32buf; int x = 0; - IVTV_DEBUG_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA", + IVTV_DEBUG_HI_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA", s->name, s->dma_offset); list_for_each(p, &s->q_dma.list) { buf = list_entry(p, struct ivtv_buffer, list); @@ -321,7 +321,7 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) unsigned long flags = 0; int idx = 0; - IVTV_DEBUG_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset); + IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset); buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list); list_for_each(p, &s->q_predma.list) { struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); @@ -368,7 +368,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s) struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; int i; - IVTV_DEBUG_DMA("start %s for %s\n", ivtv_use_dma(s) ? "DMA" : "PIO", s->name); + IVTV_DEBUG_HI_DMA("start %s for %s\n", ivtv_use_dma(s) ? "DMA" : "PIO", s->name); if (s->q_predma.bytesused) ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); @@ -397,7 +397,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s) itv->vbi.dma_offset = s_vbi->dma_offset; s_vbi->SG_length = 0; set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); - IVTV_DEBUG_DMA("include DMA for %s\n", s->name); + IVTV_DEBUG_HI_DMA("include DMA for %s\n", s->name); } /* Mark last buffer size for Interrupt flag */ @@ -431,7 +431,7 @@ static void ivtv_dma_dec_start(struct ivtv_stream *s) if (s->q_predma.bytesused) ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); - IVTV_DEBUG_DMA("start DMA for %s\n", s->name); + IVTV_DEBUG_HI_DMA("start DMA for %s\n", s->name); /* put SG Handle into register 0x0c */ write_reg(s->SG_handle, IVTV_REG_DECDMAADDR); write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER); @@ -447,7 +447,7 @@ static void ivtv_irq_dma_read(struct ivtv *itv) struct ivtv_buffer *buf; int hw_stream_type; - IVTV_DEBUG_IRQ("DEC DMA READ\n"); + IVTV_DEBUG_HI_IRQ("DEC DMA READ\n"); del_timer(&itv->dma_timer); if (read_reg(IVTV_REG_DMASTATUS) & 0x14) { IVTV_DEBUG_WARN("DEC DMA ERROR %x\n", read_reg(IVTV_REG_DMASTATUS)); @@ -462,7 +462,7 @@ static void ivtv_irq_dma_read(struct ivtv *itv) s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; hw_stream_type = 0; } - IVTV_DEBUG_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused); + IVTV_DEBUG_HI_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused); ivtv_stream_sync_for_cpu(s); @@ -495,7 +495,7 @@ static void ivtv_irq_enc_dma_complete(struct ivtv *itv) del_timer(&itv->dma_timer); ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data); - IVTV_DEBUG_IRQ("ENC DMA COMPLETE %x %d\n", data[0], data[1]); + IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d\n", data[0], data[1]); if (test_and_clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags)) data[1] = 3; else if (data[1] > 2) @@ -532,7 +532,7 @@ static void ivtv_irq_enc_pio_complete(struct ivtv *itv) return; } s = &itv->streams[itv->cur_pio_stream]; - IVTV_DEBUG_IRQ("ENC PIO COMPLETE %s\n", s->name); + IVTV_DEBUG_HI_IRQ("ENC PIO COMPLETE %s\n", s->name); s->SG_length = 0; clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags); clear_bit(IVTV_F_I_PIO, &itv->i_flags); @@ -590,7 +590,7 @@ static void ivtv_irq_enc_start_cap(struct ivtv *itv) /* Get DMA destination and size arguments from card */ ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA, data); - IVTV_DEBUG_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]); + IVTV_DEBUG_HI_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]); if (data[0] > 2 || data[1] == 0 || data[2] == 0) { IVTV_DEBUG_WARN("Unknown input: %08x %08x %08x\n", @@ -610,7 +610,7 @@ static void ivtv_irq_enc_vbi_cap(struct ivtv *itv) u32 data[CX2341X_MBOX_MAX_DATA]; struct ivtv_stream *s; - IVTV_DEBUG_IRQ("ENC START VBI CAP\n"); + IVTV_DEBUG_HI_IRQ("ENC START VBI CAP\n"); s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; /* If more than two VBI buffers are pending, then @@ -644,7 +644,7 @@ static void ivtv_irq_dec_vbi_reinsert(struct ivtv *itv) u32 data[CX2341X_MBOX_MAX_DATA]; struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI]; - IVTV_DEBUG_IRQ("DEC VBI REINSERT\n"); + IVTV_DEBUG_HI_IRQ("DEC VBI REINSERT\n"); if (test_bit(IVTV_F_S_CLAIMED, &s->s_flags) && !stream_enc_dma_append(s, data)) { set_bit(IVTV_F_S_PIO_PENDING, &s->s_flags); @@ -669,7 +669,7 @@ static void ivtv_irq_dec_data_req(struct ivtv *itv) itv->dma_data_req_offset = data[1]; s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; } - IVTV_DEBUG_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused, + IVTV_DEBUG_HI_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused, itv->dma_data_req_offset, itv->dma_data_req_size); if (itv->dma_data_req_size == 0 || s->q_full.bytesused < itv->dma_data_req_size) { set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); @@ -791,10 +791,10 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id) /* Exclude interrupts noted below from the output, otherwise the log is flooded with these messages */ if (combo & ~0xff6d0400) - IVTV_DEBUG_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo); + IVTV_DEBUG_HI_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo); if (combo & IVTV_IRQ_DEC_DMA_COMPLETE) { - IVTV_DEBUG_IRQ("DEC DMA COMPLETE\n"); + IVTV_DEBUG_HI_IRQ("DEC DMA COMPLETE\n"); } if (combo & IVTV_IRQ_DMA_READ) { diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 6af88ae9295f..287117187499 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -446,6 +446,9 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) if (s->v4l2dev == NULL) return -EINVAL; + /* Big serialization lock to ensure no two streams are started + simultaneously: that can give all sorts of weird results. */ + mutex_lock(&itv->serialize_lock); IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name); switch (s->type) { @@ -487,6 +490,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) 0, sizeof(itv->vbi.sliced_mpeg_size)); break; default: + mutex_unlock(&itv->serialize_lock); return -EINVAL; } s->subtype = subtype; @@ -568,6 +572,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype)) { IVTV_DEBUG_WARN( "Error starting capture!\n"); + mutex_unlock(&itv->serialize_lock); return -EINVAL; } @@ -583,6 +588,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) /* you're live! sit back and await interrupts :) */ atomic_inc(&itv->capturing); + mutex_unlock(&itv->serialize_lock); return 0; } @@ -762,17 +768,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) /* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */ ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype); - /* only run these if we're shutting down the last cap */ - if (atomic_read(&itv->capturing) - 1 == 0) { - /* event notification (off) */ - if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) { - /* type: 0 = refresh */ - /* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */ - ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1); - ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST); - } - } - then = jiffies; if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) { @@ -812,7 +807,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) then = jiffies; /* Make sure DMA is complete */ add_wait_queue(&s->waitq, &wait); - set_current_state(TASK_INTERRUPTIBLE); do { /* check if DMA is pending */ if ((s->type == IVTV_ENC_STREAM_TYPE_MPG) && /* MPG Only */ @@ -827,9 +821,7 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) } else if (read_reg(IVTV_REG_DMASTATUS) & 0x02) { break; } - - ivtv_sleep_timeout(HZ / 100, 1); - } while (then + HZ * 2 > jiffies); + } while (!ivtv_sleep_timeout(HZ / 100, 1) && then + HZ * 2 > jiffies); set_current_state(TASK_RUNNING); remove_wait_queue(&s->waitq, &wait); @@ -840,17 +832,30 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) /* Clear capture and no-read bits */ clear_bit(IVTV_F_S_STREAMING, &s->s_flags); + /* ensure these global cleanup actions are done only once */ + mutex_lock(&itv->serialize_lock); + if (s->type == IVTV_ENC_STREAM_TYPE_VBI) ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP); if (atomic_read(&itv->capturing) > 0) { + mutex_unlock(&itv->serialize_lock); return 0; } /* Set the following Interrupt mask bits for capture */ ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); + /* event notification (off) */ + if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) { + /* type: 0 = refresh */ + /* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */ + ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1); + ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST); + } + wake_up(&s->waitq); + mutex_unlock(&itv->serialize_lock); return 0; } diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c index 3ba46e07ea1f..a7282a91bd97 100644 --- a/drivers/media/video/ivtv/ivtv-vbi.c +++ b/drivers/media/video/ivtv/ivtv-vbi.c @@ -219,31 +219,23 @@ ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count) int found_cc = 0; int cc_pos = itv->vbi.cc_pos; - if (itv->vbi.service_set_out == 0) - return -EPERM; - while (count >= sizeof(struct v4l2_sliced_vbi_data)) { switch (p->id) { case V4L2_SLICED_CAPTION_525: - if (p->id == V4L2_SLICED_CAPTION_525 && - p->line == 21 && - (itv->vbi.service_set_out & - V4L2_SLICED_CAPTION_525) == 0) { - break; - } - found_cc = 1; - if (p->field) { - cc[2] = p->data[0]; - cc[3] = p->data[1]; - } else { - cc[0] = p->data[0]; - cc[1] = p->data[1]; + if (p->line == 21) { + found_cc = 1; + if (p->field) { + cc[2] = p->data[0]; + cc[3] = p->data[1]; + } else { + cc[0] = p->data[0]; + cc[1] = p->data[1]; + } } break; case V4L2_SLICED_VPS: - if (p->line == 16 && p->field == 0 && - (itv->vbi.service_set_out & V4L2_SLICED_VPS)) { + if (p->line == 16 && p->field == 0) { itv->vbi.vps[0] = p->data[2]; itv->vbi.vps[1] = p->data[8]; itv->vbi.vps[2] = p->data[9]; @@ -255,8 +247,7 @@ ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count) break; case V4L2_SLICED_WSS_625: - if (p->line == 23 && p->field == 0 && - (itv->vbi.service_set_out & V4L2_SLICED_WSS_625)) { + if (p->line == 23 && p->field == 0) { /* No lock needed for WSS */ itv->vbi.wss = p->data[0] | (p->data[1] << 8); itv->vbi.wss_found = 1; diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index 3bb7d6634862..507b1d4260ed 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -157,8 +157,7 @@ static int msp_read(struct i2c_client *client, int dev, int addr) break; v4l_warn(client, "I/O error #%d (read 0x%02x/0x%02x)\n", err, dev, addr); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(msecs_to_jiffies(10)); + schedule_timeout_interruptible(msecs_to_jiffies(10)); } if (err == 3) { v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n"); @@ -197,8 +196,7 @@ static int msp_write(struct i2c_client *client, int dev, int addr, int val) break; v4l_warn(client, "I/O error #%d (write 0x%02x/0x%02x)\n", err, dev, addr); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(msecs_to_jiffies(10)); + schedule_timeout_interruptible(msecs_to_jiffies(10)); } if (err == 3) { v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n"); diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c index c7c9f3f8715c..7549114aaaca 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/video/mt20xx.c @@ -7,7 +7,7 @@ #include <linux/i2c.h> #include <linux/videodev.h> #include <linux/moduleparam.h> -#include <media/tuner.h> +#include "tuner-driver.h" /* ---------------------------------------------------------------------- */ @@ -37,6 +37,19 @@ static char *microtune_part[] = { [ MT2050 ] = "MT2050", }; +struct microtune_priv { + unsigned int xogc; + unsigned int radio_if2; +}; + +static void microtune_release(struct i2c_client *c) +{ + struct tuner *t = i2c_get_clientdata(c); + + kfree(t->priv); + t->priv = NULL; +} + // IsSpurInBand()? static int mt2032_spurcheck(struct i2c_client *c, int f1, int f2, int spectrum_from,int spectrum_to) @@ -218,6 +231,7 @@ static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin, unsigned char buf[21]; int lint_try,ret,sel,lock=0; struct tuner *t = i2c_get_clientdata(c); + struct microtune_priv *priv = t->priv; tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n", rfin,if1,if2,from,to); @@ -227,7 +241,7 @@ static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin, i2c_master_recv(c,buf,21); buf[0]=0; - ret=mt2032_compute_freq(c,rfin,if1,if2,from,to,&buf[1],&sel,t->xogc); + ret=mt2032_compute_freq(c,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc); if (ret<0) return; @@ -251,10 +265,10 @@ static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin, tuner_dbg("mt2032: re-init PLLs by LINT\n"); buf[0]=7; - buf[1]=0x80 +8+t->xogc; // set LINT to re-init PLLs + buf[1]=0x80 +8+priv->xogc; // set LINT to re-init PLLs i2c_master_send(c,buf,2); mdelay(10); - buf[1]=8+t->xogc; + buf[1]=8+priv->xogc; i2c_master_send(c,buf,2); } @@ -294,17 +308,25 @@ static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq) static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq) { struct tuner *t = i2c_get_clientdata(c); - int if2 = t->radio_if2; + struct microtune_priv *priv = t->priv; + int if2 = priv->radio_if2; // per Manual for FM tuning: first if center freq. 1085 MHz mt2032_set_if_freq(c, freq * 1000 / 16, 1085*1000*1000,if2,if2,if2); } +static struct tuner_operations mt2032_tuner_ops = { + .set_tv_freq = mt2032_set_tv_freq, + .set_radio_freq = mt2032_set_radio_freq, + .release = microtune_release, +}; + // Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 static int mt2032_init(struct i2c_client *c) { struct tuner *t = i2c_get_clientdata(c); + struct microtune_priv *priv = t->priv; unsigned char buf[21]; int ret,xogc,xok=0; @@ -351,23 +373,23 @@ static int mt2032_init(struct i2c_client *c) if (ret!=2) tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret); } while (xok != 1 ); - t->xogc=xogc; + priv->xogc=xogc; + + memcpy(&t->ops, &mt2032_tuner_ops, sizeof(struct tuner_operations)); - t->set_tv_freq = mt2032_set_tv_freq; - t->set_radio_freq = mt2032_set_radio_freq; return(1); } static void mt2050_set_antenna(struct i2c_client *c, unsigned char antenna) { struct tuner *t = i2c_get_clientdata(c); - unsigned char buf[2]; - int ret; + unsigned char buf[2]; + int ret; - buf[0] = 6; - buf[1] = antenna ? 0x11 : 0x10; - ret=i2c_master_send(c,buf,2); - tuner_dbg("mt2050: enabled antenna connector %d\n", antenna); + buf[0] = 6; + buf[1] = antenna ? 0x11 : 0x10; + ret=i2c_master_send(c,buf,2); + tuner_dbg("mt2050: enabled antenna connector %d\n", antenna); } static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned int if2) @@ -456,12 +478,19 @@ static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq) static void mt2050_set_radio_freq(struct i2c_client *c, unsigned int freq) { struct tuner *t = i2c_get_clientdata(c); - int if2 = t->radio_if2; + struct microtune_priv *priv = t->priv; + int if2 = priv->radio_if2; mt2050_set_if_freq(c, freq * 1000 / 16, if2); mt2050_set_antenna(c, radio_antenna); } +static struct tuner_operations mt2050_tuner_ops = { + .set_tv_freq = mt2050_set_tv_freq, + .set_radio_freq = mt2050_set_radio_freq, + .release = microtune_release, +}; + static int mt2050_init(struct i2c_client *c) { struct tuner *t = i2c_get_clientdata(c); @@ -481,28 +510,35 @@ static int mt2050_init(struct i2c_client *c) i2c_master_recv(c,buf,1); tuner_dbg("mt2050: sro is %x\n",buf[0]); - t->set_tv_freq = mt2050_set_tv_freq; - t->set_radio_freq = mt2050_set_radio_freq; + + memcpy(&t->ops, &mt2050_tuner_ops, sizeof(struct tuner_operations)); + return 0; } int microtune_init(struct i2c_client *c) { + struct microtune_priv *priv = NULL; struct tuner *t = i2c_get_clientdata(c); char *name; unsigned char buf[21]; int company_code; + priv = kzalloc(sizeof(struct microtune_priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + t->priv = priv; + + priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */ + memset(buf,0,sizeof(buf)); - t->set_tv_freq = NULL; - t->set_radio_freq = NULL; - t->standby = NULL; + if (t->std & V4L2_STD_525_60) { tuner_dbg("pinnacle ntsc\n"); - t->radio_if2 = 41300 * 1000; + priv->radio_if2 = 41300 * 1000; } else { tuner_dbg("pinnacle pal\n"); - t->radio_if2 = 33300 * 1000; + priv->radio_if2 = 33300 * 1000; } name = "unknown"; diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c index 3ceb8a6249dd..f8f21ddd9843 100644 --- a/drivers/media/video/ov7670.c +++ b/drivers/media/video/ov7670.c @@ -617,7 +617,7 @@ static struct ov7670_win_size { }, }; -#define N_WIN_SIZES (sizeof(ov7670_win_sizes)/sizeof(ov7670_win_sizes[0])) +#define N_WIN_SIZES (ARRAY_SIZE(ov7670_win_sizes)) /* @@ -1183,7 +1183,7 @@ static struct ov7670_control { .query = ov7670_q_hflip, }, }; -#define N_CONTROLS (sizeof(ov7670_controls)/sizeof(ov7670_controls[0])) +#define N_CONTROLS (ARRAY_SIZE(ov7670_controls)) static struct ov7670_control *ov7670_find_control(__u32 id) { diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 085332a503de..9c0e8d18c2f6 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -1099,7 +1099,7 @@ static int pwc_video_open(struct inode *inode, struct file *file) return -EBUSY; } - down(&pdev->modlock); + mutex_lock(&pdev->modlock); if (!pdev->usb_init) { PWC_DEBUG_OPEN("Doing first time initialization.\n"); pdev->usb_init = 1; @@ -1131,7 +1131,7 @@ static int pwc_video_open(struct inode *inode, struct file *file) if (i < 0) { PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n"); pwc_free_buffers(pdev); - up(&pdev->modlock); + mutex_unlock(&pdev->modlock); return i; } @@ -1172,7 +1172,7 @@ static int pwc_video_open(struct inode *inode, struct file *file) if (i) { PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n"); pwc_free_buffers(pdev); - up(&pdev->modlock); + mutex_unlock(&pdev->modlock); return i; } @@ -1181,7 +1181,7 @@ static int pwc_video_open(struct inode *inode, struct file *file) PWC_DEBUG_OPEN("Failed to init ISOC stuff = %d.\n", i); pwc_isoc_cleanup(pdev); pwc_free_buffers(pdev); - up(&pdev->modlock); + mutex_unlock(&pdev->modlock); return i; } @@ -1191,7 +1191,7 @@ static int pwc_video_open(struct inode *inode, struct file *file) pdev->vopen++; file->private_data = vdev; - up(&pdev->modlock); + mutex_unlock(&pdev->modlock); PWC_DEBUG_OPEN("<< video_open() returns 0.\n"); return 0; } @@ -1685,7 +1685,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pdev->angle_range.tilt_max = 2500; } - init_MUTEX(&pdev->modlock); + mutex_init(&pdev->modlock); spin_lock_init(&pdev->ptrlock); pdev->udev = udev; diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h index acbb9312960a..910a04f53920 100644 --- a/drivers/media/video/pwc/pwc.h +++ b/drivers/media/video/pwc/pwc.h @@ -31,7 +31,7 @@ #include <linux/wait.h> #include <linux/smp_lock.h> #include <linux/version.h> -#include <asm/semaphore.h> +#include <linux/mutex.h> #include <asm/errno.h> #include <linux/videodev.h> #include <media/v4l2-common.h> @@ -244,7 +244,7 @@ struct pwc_device int image_read_pos; /* In case we read data in pieces, keep track of were we are in the imagebuffer */ int image_used[MAX_IMAGES]; /* For MCAPTURE and SYNC */ - struct semaphore modlock; /* to prevent races in video_open(), etc */ + struct mutex modlock; /* to prevent races in video_open(), etc */ spinlock_t ptrlock; /* for manipulating the buffer pointers */ /*** motorized pan/tilt feature */ diff --git a/drivers/media/video/saa7111.c b/drivers/media/video/saa7111.c index c1a392e47170..7ae2d646d000 100644 --- a/drivers/media/video/saa7111.c +++ b/drivers/media/video/saa7111.c @@ -37,23 +37,23 @@ #include <linux/slab.h> #include <linux/mm.h> #include <linux/signal.h> +#include <linux/types.h> +#include <linux/i2c.h> #include <asm/io.h> #include <asm/pgtable.h> #include <asm/page.h> -#include <linux/types.h> +#include <asm/uaccess.h> #include <linux/videodev.h> -#include <asm/uaccess.h> +#include <linux/video_decoder.h> MODULE_DESCRIPTION("Philips SAA7111 video decoder driver"); MODULE_AUTHOR("Dave Perks"); MODULE_LICENSE("GPL"); -#include <linux/i2c.h> #define I2C_NAME(s) (s)->name -#include <linux/video_decoder.h> static int debug = 0; module_param(debug, int, 0644); diff --git a/drivers/media/video/saa7114.c b/drivers/media/video/saa7114.c index 87c3144ec7fc..677df51de1a9 100644 --- a/drivers/media/video/saa7114.c +++ b/drivers/media/video/saa7114.c @@ -35,28 +35,26 @@ #include <linux/fs.h> #include <linux/kernel.h> #include <linux/major.h> - #include <linux/slab.h> - #include <linux/mm.h> #include <linux/signal.h> +#include <linux/types.h> +#include <linux/i2c.h> #include <asm/io.h> #include <asm/pgtable.h> #include <asm/page.h> -#include <linux/types.h> +#include <asm/uaccess.h> #include <linux/videodev.h> -#include <asm/uaccess.h> +#include <linux/video_decoder.h> MODULE_DESCRIPTION("Philips SAA7114H video decoder driver"); MODULE_AUTHOR("Maxim Yevtyushkin"); MODULE_LICENSE("GPL"); -#include <linux/i2c.h> #define I2C_NAME(x) (x)->name -#include <linux/video_decoder.h> static int debug = 0; module_param(debug, int, 0); diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig index 309dca368f4a..9f1417a4f7d2 100644 --- a/drivers/media/video/saa7134/Kconfig +++ b/drivers/media/video/saa7134/Kconfig @@ -40,7 +40,7 @@ config VIDEO_SAA7134_DVB depends on VIDEO_SAA7134 && DVB_CORE select VIDEO_BUF_DVB select FW_LOADER - select DVB_PLL + select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_MT352 if !DVB_FE_CUSTOMISE select DVB_TDA1004X if !DVB_FE_CUSTOMISE select DVB_NXT200X if !DVB_FE_CUSTOMISE diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c index ffb0f647a86d..3c0fc9027ad0 100644 --- a/drivers/media/video/saa7134/saa7134-alsa.c +++ b/drivers/media/video/saa7134/saa7134-alsa.c @@ -75,7 +75,8 @@ typedef struct snd_card_saa7134 { struct saa7134_dev *dev; unsigned long iobase; - int irq; + s16 irq; + u16 mute_was_on; spinlock_t lock; } snd_card_saa7134_t; @@ -589,8 +590,10 @@ static int snd_card_saa7134_capture_close(struct snd_pcm_substream * substream) snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream); struct saa7134_dev *dev = saa7134->dev; - dev->ctl_mute = 1; - saa7134_tvaudio_setmute(dev); + if (saa7134->mute_was_on) { + dev->ctl_mute = 1; + saa7134_tvaudio_setmute(dev); + } return 0; } @@ -637,8 +640,11 @@ static int snd_card_saa7134_capture_open(struct snd_pcm_substream * substream) runtime->private_free = snd_card_saa7134_runtime_free; runtime->hw = snd_card_saa7134_capture; - dev->ctl_mute = 0; - saa7134_tvaudio_setmute(dev); + if (dev->ctl_mute != 0) { + saa7134->mute_was_on = 1; + dev->ctl_mute = 0; + saa7134_tvaudio_setmute(dev); + } if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 50f15adfa7c8..8ec83bd70094 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -400,7 +400,7 @@ struct saa7134_board saa7134_boards[] = { .inputs = {{ .name = name_tv, .vmux = 1, - .amux = LINE2, + .amux = TV, .tv = 1, .gpio = 0x20000, },{ @@ -3502,6 +3502,38 @@ struct saa7134_board saa7134_boards[] = { .amux = TV, }, }, + [SAA7134_BOARD_10MOONSTVMASTER3] = { + /* Tony Wan <aloha_cn@hotmail.com> */ + .name = "10MOONS TM300 TV Card", + .audio_clock = 0x00200000, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .gpiomask = 0x7000, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .gpio = 0x0000, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + .gpio = 0x2000, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + .gpio = 0x2000, + }}, + .mute = { + .name = name_mute, + .amux = LINE2, + .gpio = 0x3000, + }, + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -4219,6 +4251,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subdevice = 0x2003, /* OEM cardbus */ .driver_data = SAA7134_BOARD_SABRENT_TV_PCB05, },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = PCI_VENDOR_ID_PHILIPS, + .subdevice = 0x2304, + .driver_data = SAA7134_BOARD_10MOONSTVMASTER3, + },{ /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, @@ -4330,6 +4368,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_AVERMEDIA_A16AR: case SAA7134_BOARD_ENCORE_ENLTV: case SAA7134_BOARD_ENCORE_ENLTV_FM: + case SAA7134_BOARD_10MOONSTVMASTER3: dev->has_remote = SAA7134_REMOTE_GPIO; break; case SAA7134_BOARD_FLYDVBS_LR300: diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index e0eec80088c7..1f6bd3300715 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -175,18 +175,6 @@ static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe, return mt352_pinnacle_init(fe); } -static int mt352_aver777_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len) -{ - if (buf_len < 5) - return -EINVAL; - - pllbuf[0] = 0x61; - dvb_pll_configure(&dvb_pll_philips_td1316, pllbuf+1, - params->frequency, - params->u.ofdm.bandwidth); - return 5; -} - static struct mt352_config pinnacle_300i = { .demod_address = 0x3c >> 1, .adc_clock = 20333, @@ -444,135 +432,6 @@ static struct tda1004x_config philips_europa_config = { /* ------------------------------------------------------------------ */ -static int philips_fmd1216_tuner_init(struct dvb_frontend *fe) -{ - struct saa7134_dev *dev = fe->dvb->priv; - struct tda1004x_state *state = fe->demodulator_priv; - u8 addr = state->config->tuner_address; - /* this message is to set up ATC and ALC */ - static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 }; - struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) }; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) - return -EIO; - msleep(1); - - return 0; -} - -static int philips_fmd1216_tuner_sleep(struct dvb_frontend *fe) -{ - struct saa7134_dev *dev = fe->dvb->priv; - struct tda1004x_state *state = fe->demodulator_priv; - u8 addr = state->config->tuner_address; - /* this message actually turns the tuner back to analog mode */ - u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0x60 }; - struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) }; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - i2c_transfer(&dev->i2c_adap, &tuner_msg, 1); - msleep(1); - fmd1216_init[2] = 0x86; - fmd1216_init[3] = 0x54; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - i2c_transfer(&dev->i2c_adap, &tuner_msg, 1); - msleep(1); - return 0; -} - -static int philips_fmd1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) -{ - struct saa7134_dev *dev = fe->dvb->priv; - struct tda1004x_state *state = fe->demodulator_priv; - u8 addr = state->config->tuner_address; - u8 tuner_buf[4]; - struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len = - sizeof(tuner_buf) }; - int tuner_frequency = 0; - int divider = 0; - u8 band, mode, cp; - - /* determine charge pump */ - tuner_frequency = params->frequency + 36130000; - if (tuner_frequency < 87000000) - return -EINVAL; - /* low band */ - else if (tuner_frequency < 180000000) { - band = 1; - mode = 7; - cp = 0; - } else if (tuner_frequency < 195000000) { - band = 1; - mode = 6; - cp = 1; - /* mid band */ - } else if (tuner_frequency < 366000000) { - if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) { - band = 10; - } else { - band = 2; - } - mode = 7; - cp = 0; - } else if (tuner_frequency < 478000000) { - if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) { - band = 10; - } else { - band = 2; - } - mode = 6; - cp = 1; - /* high band */ - } else if (tuner_frequency < 662000000) { - if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) { - band = 12; - } else { - band = 4; - } - mode = 7; - cp = 0; - } else if (tuner_frequency < 840000000) { - if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) { - band = 12; - } else { - band = 4; - } - mode = 6; - cp = 1; - } else { - if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) { - band = 12; - } else { - band = 4; - } - mode = 7; - cp = 1; - - } - /* calculate divisor */ - /* ((36166000 + Finput) / 166666) rounded! */ - divider = (tuner_frequency + 83333) / 166667; - - /* setup tuner buffer */ - tuner_buf[0] = (divider >> 8) & 0x7f; - tuner_buf[1] = divider & 0xff; - tuner_buf[2] = 0x80 | (cp << 6) | (mode << 3) | 4; - tuner_buf[3] = 0x40 | band; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) { - wprintk("could not write to tuner at addr: 0x%02x\n", - addr << 1); - return -EIO; - } - return 0; -} - static struct tda1004x_config medion_cardbus = { .demod_address = 0x08, .invert = 1, @@ -958,18 +817,8 @@ static struct nxt200x_config avertvhda180 = { .demod_address = 0x0a, }; -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, - .set_pll_input = nxt200x_set_pll_input, }; /* ================================================================== @@ -1005,7 +854,8 @@ static int dvb_init(struct saa7134_dev *dev) dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777, &dev->i2c_adap); if (dev->dvb.frontend) { - dev->dvb.frontend->ops.tuner_ops.calc_regs = mt352_aver777_tuner_calc_regs; + dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, + NULL, DVB_PLL_PHILIPS_TD1316); } break; case SAA7134_BOARD_MD7134: @@ -1013,9 +863,8 @@ static int dvb_init(struct saa7134_dev *dev) &medion_cardbus, &dev->i2c_adap); if (dev->dvb.frontend) { - dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init; - dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep; - dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params; + dvb_attach(dvb_pll_attach, dev->dvb.frontend, medion_cardbus.tuner_address, + &dev->i2c_adap, DVB_PLL_FMD1216ME); } break; case SAA7134_BOARD_PHILIPS_TOUGH: @@ -1113,7 +962,7 @@ static int dvb_init(struct saa7134_dev *dev) &dev->i2c_adap); if (dev->dvb.frontend) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, - NULL, &dvb_pll_tdhu2); + NULL, DVB_PLL_TDHU2); } break; case SAA7134_BOARD_KWORLD_ATSC110: @@ -1121,7 +970,7 @@ static int dvb_init(struct saa7134_dev *dev) &dev->i2c_adap); if (dev->dvb.frontend) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, - NULL, &dvb_pll_tuv1236d); + NULL, DVB_PLL_TUV1236D); } break; case SAA7134_BOARD_FLYDVBS_LR300: @@ -1144,9 +993,9 @@ static int dvb_init(struct saa7134_dev *dev) if (dev->dvb.frontend) { dev->original_demod_sleep = dev->dvb.frontend->ops.sleep; dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep; - dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init; - dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep; - dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params; + + dvb_attach(dvb_pll_attach, dev->dvb.frontend, medion_cardbus.tuner_address, + &dev->i2c_adap, DVB_PLL_FMD1216ME); } break; case SAA7134_BOARD_VIDEOMATE_DVBT_200A: diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index f521603482ca..fc260ec8fdc2 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -96,6 +96,10 @@ static int ts_open(struct inode *inode, struct file *file) if (dev->empress_users) goto done_up; + /* Unmute audio */ + saa_writeb(SAA7134_AUDIO_MUTE_CTRL, + saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6)); + dev->empress_users++; file->private_data = dev; err = 0; @@ -121,6 +125,10 @@ static int ts_release(struct inode *inode, struct file *file) /* stop the encoder */ ts_reset_encoder(dev); + /* Mute audio */ + saa_writeb(SAA7134_AUDIO_MUTE_CTRL, + saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6)); + 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 c0de37e3f5c6..1b6dfd801cc1 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -153,21 +153,18 @@ void saa7134_input_irq(struct saa7134_dev *dev) static void saa7134_input_timer(unsigned long data) { - struct saa7134_dev *dev = (struct saa7134_dev*)data; + struct saa7134_dev *dev = (struct saa7134_dev *)data; struct card_ir *ir = dev->remote; - unsigned long timeout; build_key(dev); - timeout = jiffies + (ir->polling * HZ / 1000); - mod_timer(&ir->timer, timeout); + mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); } static void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir) { if (ir->polling) { - init_timer(&ir->timer); - ir->timer.function = saa7134_input_timer; - ir->timer.data = (unsigned long)dev; + setup_timer(&ir->timer, saa7134_input_timer, + (unsigned long)dev); ir->timer.expires = jiffies + HZ; add_timer(&ir->timer); } else if (ir->rc5_gpio) { @@ -314,6 +311,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) mask_keycode = 0x003F00; mask_keyup = 0x040000; break; + case SAA7134_BOARD_FLYDVBS_LR300: case SAA7134_BOARD_FLYDVBT_LR301: case SAA7134_BOARD_FLYDVBTDUO: ir_codes = ir_codes_flydvb; @@ -333,6 +331,12 @@ int saa7134_input_init1(struct saa7134_dev *dev) mask_keyup = 0x040000; polling = 50; // ms break; + case SAA7134_BOARD_10MOONSTVMASTER3: + ir_codes = ir_codes_encore_enltv; + mask_keycode = 0x5f80000; + mask_keyup = 0x8000000; + polling = 50; //ms + break; } if (NULL == ir_codes) { printk("%s: Oops: IR config error [card=%d]\n", @@ -374,7 +378,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) input_dev->id.vendor = dev->pci->vendor; input_dev->id.product = dev->pci->device; } - input_dev->cdev.dev = &dev->pci->dev; + input_dev->dev.parent = &dev->pci->dev; dev->remote = ir; saa7134_ir_start(dev, ir); diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c index 30395d6b5f14..18b4817b4aac 100644 --- a/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -25,6 +25,7 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> +#include <linux/kthread.h> #include <linux/slab.h> #include <linux/delay.h> #include <asm/div64.h> @@ -341,10 +342,8 @@ static void tvaudio_setmode(struct saa7134_dev *dev, static int tvaudio_sleep(struct saa7134_dev *dev, int timeout) { - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue(&dev->thread.wq, &wait); - if (dev->thread.scan1 == dev->thread.scan2 && !dev->thread.shutdown) { + if (dev->thread.scan1 == dev->thread.scan2 && + !kthread_should_stop()) { if (timeout < 0) { set_current_state(TASK_INTERRUPTIBLE); schedule(); @@ -353,7 +352,6 @@ static int tvaudio_sleep(struct saa7134_dev *dev, int timeout) (msecs_to_jiffies(timeout)); } } - remove_wait_queue(&dev->thread.wq, &wait); return dev->thread.scan1 != dev->thread.scan2; } @@ -505,11 +503,10 @@ static int tvaudio_thread(void *data) unsigned int i, audio, nscan; int max1,max2,carrier,rx,mode,lastmode,default_carrier; - daemonize("%s", dev->name); allow_signal(SIGTERM); for (;;) { tvaudio_sleep(dev,-1); - if (dev->thread.shutdown || signal_pending(current)) + if (kthread_should_stop() || signal_pending(current)) goto done; restart: @@ -618,7 +615,7 @@ static int tvaudio_thread(void *data) for (;;) { if (tvaudio_sleep(dev,5000)) goto restart; - if (dev->thread.shutdown || signal_pending(current)) + if (kthread_should_stop() || signal_pending(current)) break; if (UNSET == dev->thread.mode) { rx = tvaudio_getstereo(dev,&tvaudio[i]); @@ -634,7 +631,6 @@ static int tvaudio_thread(void *data) } done: - complete_and_exit(&dev->thread.exit, 0); return 0; } @@ -782,7 +778,6 @@ static int tvaudio_thread_ddep(void *data) struct saa7134_dev *dev = data; u32 value, norms, clock; - daemonize("%s", dev->name); allow_signal(SIGTERM); clock = saa7134_boards[dev->board].audio_clock; @@ -796,7 +791,7 @@ static int tvaudio_thread_ddep(void *data) for (;;) { tvaudio_sleep(dev,-1); - if (dev->thread.shutdown || signal_pending(current)) + if (kthread_should_stop() || signal_pending(current)) goto done; restart: @@ -876,7 +871,6 @@ static int tvaudio_thread_ddep(void *data) } done: - complete_and_exit(&dev->thread.exit, 0); return 0; } @@ -973,7 +967,6 @@ int saa7134_tvaudio_getstereo(struct saa7134_dev *dev) int saa7134_tvaudio_init2(struct saa7134_dev *dev) { - DECLARE_MUTEX_LOCKED(sem); int (*my_thread)(void *data) = NULL; switch (dev->pci->device) { @@ -986,15 +979,15 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev) break; } - dev->thread.pid = -1; + dev->thread.thread = NULL; if (my_thread) { /* start tvaudio thread */ - init_waitqueue_head(&dev->thread.wq); - init_completion(&dev->thread.exit); - dev->thread.pid = kernel_thread(my_thread,dev,0); - if (dev->thread.pid < 0) + dev->thread.thread = kthread_run(my_thread, dev, "%s", dev->name); + if (IS_ERR(dev->thread.thread)) { printk(KERN_WARNING "%s: kernel_thread() failed\n", dev->name); + /* XXX: missing error handling here */ + } saa7134_tvaudio_do_scan(dev); } @@ -1005,11 +998,9 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev) int saa7134_tvaudio_fini(struct saa7134_dev *dev) { /* shutdown tvaudio thread */ - if (dev->thread.pid > 0) { - dev->thread.shutdown = 1; - wake_up_interruptible(&dev->thread.wq); - wait_for_completion(&dev->thread.exit); - } + if (dev->thread.thread) + kthread_stop(dev->thread.thread); + saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, 0x00); /* LINE1 */ return 0; } @@ -1020,10 +1011,10 @@ int saa7134_tvaudio_do_scan(struct saa7134_dev *dev) dprintk("sound IF not in use, skipping scan\n"); dev->automute = 0; saa7134_tvaudio_setmute(dev); - } else if (dev->thread.pid >= 0) { + } else if (dev->thread.thread) { dev->thread.mode = UNSET; dev->thread.scan2++; - wake_up_interruptible(&dev->thread.wq); + wake_up_process(dev->thread.thread); } else { dev->automute = 0; saa7134_tvaudio_setmute(dev); @@ -1040,4 +1031,3 @@ EXPORT_SYMBOL(saa7134_tvaudio_setmute); * c-basic-offset: 8 * End: */ - diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 15623b27ad2e..d32a856192d7 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -238,6 +238,7 @@ struct saa7134_format { #define SAA7134_BOARD_ECS_TVP3XP_4CB6 113 #define SAA7134_BOARD_KWORLD_DVBT_210 114 #define SAA7134_BOARD_SABRENT_TV_PCB05 115 +#define SAA7134_BOARD_10MOONSTVMASTER3 116 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 @@ -327,10 +328,7 @@ struct saa7134_pgtable { /* tvaudio thread status */ struct saa7134_thread { - pid_t pid; - struct completion exit; - wait_queue_head_t wq; - unsigned int shutdown; + struct task_struct *thread; unsigned int scan1; unsigned int scan2; unsigned int mode; diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c index 339592e7722d..66cc92c0ea66 100644 --- a/drivers/media/video/saa7185.c +++ b/drivers/media/video/saa7185.c @@ -34,23 +34,23 @@ #include <linux/slab.h> #include <linux/mm.h> #include <linux/signal.h> +#include <linux/types.h> +#include <linux/i2c.h> #include <asm/io.h> #include <asm/pgtable.h> #include <asm/page.h> -#include <linux/types.h> +#include <asm/uaccess.h> #include <linux/videodev.h> -#include <asm/uaccess.h> +#include <linux/video_encoder.h> MODULE_DESCRIPTION("Philips SAA7185 video encoder driver"); MODULE_AUTHOR("Dave Perks"); MODULE_LICENSE("GPL"); -#include <linux/i2c.h> #define I2C_NAME(s) (s)->name -#include <linux/video_encoder.h> static int debug = 0; module_param(debug, int, 0); diff --git a/drivers/media/video/sn9c102/sn9c102.h b/drivers/media/video/sn9c102/sn9c102.h index 11fcb49f5b99..2e3c3de793a7 100644 --- a/drivers/media/video/sn9c102/sn9c102.h +++ b/drivers/media/video/sn9c102/sn9c102.h @@ -36,6 +36,7 @@ #include <linux/mutex.h> #include <linux/string.h> #include <linux/stddef.h> +#include <linux/kref.h> #include "sn9c102_config.h" #include "sn9c102_sensor.h" @@ -94,7 +95,7 @@ struct sn9c102_module_param { }; static DEFINE_MUTEX(sn9c102_sysfs_lock); -static DECLARE_RWSEM(sn9c102_disconnect); +static DECLARE_RWSEM(sn9c102_dev_lock); struct sn9c102_device { struct video_device* v4ldev; @@ -122,12 +123,14 @@ struct sn9c102_device { struct sn9c102_module_param module_param; + struct kref kref; enum sn9c102_dev_state state; u8 users; - struct mutex dev_mutex, fileop_mutex; + struct completion probe; + struct mutex open_mutex, fileop_mutex; spinlock_t queue_lock; - wait_queue_head_t open, wait_frame, wait_stream; + wait_queue_head_t wait_open, wait_frame, wait_stream; }; /*****************************************************************************/ diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 74a204f8ebc8..36d8a455e0ec 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -48,8 +48,8 @@ #define SN9C102_MODULE_AUTHOR "(C) 2004-2007 Luca Risolia" #define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>" #define SN9C102_MODULE_LICENSE "GPL" -#define SN9C102_MODULE_VERSION "1:1.44" -#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 44) +#define SN9C102_MODULE_VERSION "1:1.47" +#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 47) /*****************************************************************************/ @@ -64,9 +64,10 @@ MODULE_LICENSE(SN9C102_MODULE_LICENSE); static short video_nr[] = {[0 ... SN9C102_MAX_DEVICES-1] = -1}; module_param_array(video_nr, short, NULL, 0444); MODULE_PARM_DESC(video_nr, - "\n<-1|n[,...]> Specify V4L2 minor mode number." - "\n -1 = use next available (default)" - "\n n = use minor number n (integer >= 0)" + " <-1|n[,...]>" + "\nSpecify V4L2 minor mode number." + "\n-1 = use next available (default)" + "\n n = use minor number n (integer >= 0)" "\nYou can specify up to "__MODULE_STRING(SN9C102_MAX_DEVICES) " cameras this way." "\nFor example:" @@ -79,13 +80,14 @@ static short force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] = SN9C102_FORCE_MUNMAP}; module_param_array(force_munmap, bool, NULL, 0444); MODULE_PARM_DESC(force_munmap, - "\n<0|1[,...]> Force the application to unmap previously" + " <0|1[,...]>" + "\nForce the application to unmap previously" "\nmapped buffer memory before calling any VIDIOC_S_CROP or" "\nVIDIOC_S_FMT ioctl's. Not all the applications support" "\nthis feature. This parameter is specific for each" "\ndetected camera." - "\n 0 = do not force memory unmapping" - "\n 1 = force memory unmapping (save memory)" + "\n0 = do not force memory unmapping" + "\n1 = force memory unmapping (save memory)" "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"." "\n"); @@ -93,7 +95,8 @@ static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] = SN9C102_FRAME_TIMEOUT}; module_param_array(frame_timeout, uint, NULL, 0644); MODULE_PARM_DESC(frame_timeout, - "\n<0|n[,...]> Timeout for a video frame in seconds before" + " <0|n[,...]>" + "\nTimeout for a video frame in seconds before" "\nreturning an I/O error; 0 for infinity." "\nThis parameter is specific for each detected camera." "\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"." @@ -103,7 +106,8 @@ MODULE_PARM_DESC(frame_timeout, static unsigned short debug = SN9C102_DEBUG_LEVEL; module_param(debug, ushort, 0644); MODULE_PARM_DESC(debug, - "\n<n> Debugging information level, from 0 to 3:" + " <n>" + "\nDebugging information level, from 0 to 3:" "\n0 = none (use carefully)" "\n1 = critical errors" "\n2 = significant informations" @@ -1616,7 +1620,8 @@ static int sn9c102_init(struct sn9c102_device* cam) int err = 0; if (!(cam->state & DEV_INITIALIZED)) { - init_waitqueue_head(&cam->open); + mutex_init(&cam->open_mutex); + init_waitqueue_head(&cam->wait_open); qctrl = s->qctrl; rect = &(s->cropcap.defrect); } else { /* use current values */ @@ -1706,21 +1711,27 @@ static int sn9c102_init(struct sn9c102_device* cam) return 0; } +/*****************************************************************************/ -static void sn9c102_release_resources(struct sn9c102_device* cam) +static void sn9c102_release_resources(struct kref *kref) { + struct sn9c102_device *cam; + mutex_lock(&sn9c102_sysfs_lock); + cam = container_of(kref, struct sn9c102_device, kref); + DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor); video_set_drvdata(cam->v4ldev, NULL); video_unregister_device(cam->v4ldev); + usb_put_dev(cam->usbdev); + kfree(cam->control_buffer); + kfree(cam); mutex_unlock(&sn9c102_sysfs_lock); - kfree(cam->control_buffer); } -/*****************************************************************************/ static int sn9c102_open(struct inode* inode, struct file* filp) { @@ -1728,43 +1739,78 @@ static int sn9c102_open(struct inode* inode, struct file* filp) int err = 0; /* - This is the only safe way to prevent race conditions with - disconnect + A read_trylock() in open() is the only safe way to prevent race + conditions with disconnect(), one close() and multiple (not + necessarily simultaneous) attempts to open(). For example, it + prevents from waiting for a second access, while the device + structure is being deallocated, after a possible disconnect() and + during a following close() holding the write lock: given that, after + this deallocation, no access will be possible anymore, using the + non-trylock version would have let open() gain the access to the + device structure improperly. + For this reason the lock must also not be per-device. */ - if (!down_read_trylock(&sn9c102_disconnect)) + if (!down_read_trylock(&sn9c102_dev_lock)) return -ERESTARTSYS; cam = video_get_drvdata(video_devdata(filp)); - if (mutex_lock_interruptible(&cam->dev_mutex)) { - up_read(&sn9c102_disconnect); + if (wait_for_completion_interruptible(&cam->probe)) { + up_read(&sn9c102_dev_lock); + return -ERESTARTSYS; + } + + kref_get(&cam->kref); + + /* + Make sure to isolate all the simultaneous opens. + */ + if (mutex_lock_interruptible(&cam->open_mutex)) { + kref_put(&cam->kref, sn9c102_release_resources); + up_read(&sn9c102_dev_lock); return -ERESTARTSYS; } + if (cam->state & DEV_DISCONNECTED) { + DBG(1, "Device not present"); + err = -ENODEV; + goto out; + } + if (cam->users) { - DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor); + DBG(2, "Device /dev/video%d is already in use", + cam->v4ldev->minor); DBG(3, "Simultaneous opens are not supported"); + /* + open() must follow the open flags and should block + eventually while the device is in use. + */ if ((filp->f_flags & O_NONBLOCK) || (filp->f_flags & O_NDELAY)) { err = -EWOULDBLOCK; goto out; } - mutex_unlock(&cam->dev_mutex); - err = wait_event_interruptible_exclusive(cam->open, - cam->state & DEV_DISCONNECTED + DBG(2, "A blocking open() has been requested. Wait for the " + "device to be released..."); + up_read(&sn9c102_dev_lock); + /* + We will not release the "open_mutex" lock, so that only one + process can be in the wait queue below. This way the process + will be sleeping while holding the lock, without loosing its + priority after any wake_up(). + */ + err = wait_event_interruptible_exclusive(cam->wait_open, + (cam->state & DEV_DISCONNECTED) || !cam->users); - if (err) { - up_read(&sn9c102_disconnect); - return err; - } + down_read(&sn9c102_dev_lock); + if (err) + goto out; if (cam->state & DEV_DISCONNECTED) { - up_read(&sn9c102_disconnect); - return -ENODEV; + err = -ENODEV; + goto out; } - mutex_lock(&cam->dev_mutex); } - if (cam->state & DEV_MISCONFIGURED) { err = sn9c102_init(cam); if (err) { @@ -1789,36 +1835,33 @@ static int sn9c102_open(struct inode* inode, struct file* filp) DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor); out: - mutex_unlock(&cam->dev_mutex); - up_read(&sn9c102_disconnect); + mutex_unlock(&cam->open_mutex); + if (err) + kref_put(&cam->kref, sn9c102_release_resources); + + up_read(&sn9c102_dev_lock); return err; } static int sn9c102_release(struct inode* inode, struct file* filp) { - struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); + struct sn9c102_device* cam; - mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */ + down_write(&sn9c102_dev_lock); - sn9c102_stop_transfer(cam); + cam = video_get_drvdata(video_devdata(filp)); + sn9c102_stop_transfer(cam); sn9c102_release_buffers(cam); - - if (cam->state & DEV_DISCONNECTED) { - sn9c102_release_resources(cam); - usb_put_dev(cam->usbdev); - mutex_unlock(&cam->dev_mutex); - kfree(cam); - return 0; - } - cam->users--; - wake_up_interruptible_nr(&cam->open, 1); + wake_up_interruptible_nr(&cam->wait_open, 1); DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor); - mutex_unlock(&cam->dev_mutex); + kref_put(&cam->kref, sn9c102_release_resources); + + up_write(&sn9c102_dev_lock); return 0; } @@ -2085,7 +2128,6 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma) vma->vm_ops = &sn9c102_vm_ops; vma->vm_private_data = &cam->frame[i]; - sn9c102_vm_open(vma); mutex_unlock(&cam->fileop_mutex); @@ -3215,8 +3257,6 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) goto fail; } - mutex_init(&cam->dev_mutex); - r = sn9c102_read_reg(cam, 0x00); if (r < 0 || (r != 0x10 && r != 0x11 && r != 0x12)) { DBG(1, "Sorry, this is not a SN9C1xx-based camera " @@ -3282,7 +3322,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) cam->v4ldev->release = video_device_release; video_set_drvdata(cam->v4ldev, cam); - mutex_lock(&cam->dev_mutex); + init_completion(&cam->probe); err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, video_nr[dev_nr]); @@ -3292,7 +3332,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) DBG(1, "Free /dev/videoX node not found"); video_nr[dev_nr] = -1; dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; - mutex_unlock(&cam->dev_mutex); + complete_all(&cam->probe); goto fail; } @@ -3318,8 +3358,10 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) #endif usb_set_intfdata(intf, cam); + kref_init(&cam->kref); + usb_get_dev(cam->usbdev); - mutex_unlock(&cam->dev_mutex); + complete_all(&cam->probe); return 0; @@ -3336,40 +3378,31 @@ fail: static void sn9c102_usb_disconnect(struct usb_interface* intf) { - struct sn9c102_device* cam = usb_get_intfdata(intf); - - if (!cam) - return; + struct sn9c102_device* cam; - down_write(&sn9c102_disconnect); + down_write(&sn9c102_dev_lock); - mutex_lock(&cam->dev_mutex); + cam = usb_get_intfdata(intf); DBG(2, "Disconnecting %s...", cam->v4ldev->name); - wake_up_interruptible_all(&cam->open); - if (cam->users) { DBG(2, "Device /dev/video%d is open! Deregistration and " - "memory deallocation are deferred on close.", + "memory deallocation are deferred.", cam->v4ldev->minor); cam->state |= DEV_MISCONFIGURED; sn9c102_stop_transfer(cam); cam->state |= DEV_DISCONNECTED; wake_up_interruptible(&cam->wait_frame); wake_up(&cam->wait_stream); - usb_get_dev(cam->usbdev); - } else { + } else cam->state |= DEV_DISCONNECTED; - sn9c102_release_resources(cam); - } - mutex_unlock(&cam->dev_mutex); + wake_up_interruptible_all(&cam->wait_open); - if (!cam->users) - kfree(cam); + kref_put(&cam->kref, sn9c102_release_resources); - up_write(&sn9c102_disconnect); + up_write(&sn9c102_dev_lock); } diff --git a/drivers/media/video/sn9c102/sn9c102_ov7630.c b/drivers/media/video/sn9c102/sn9c102_ov7630.c index e6832347894f..e4856fd77982 100644 --- a/drivers/media/video/sn9c102/sn9c102_ov7630.c +++ b/drivers/media/video/sn9c102/sn9c102_ov7630.c @@ -104,6 +104,145 @@ static int ov7630_init(struct sn9c102_device* cam) err += sn9c102_i2c_write(cam, 0x74, 0x21); err += sn9c102_i2c_write(cam, 0x7d, 0xf7); break; + case BRIDGE_SN9C105: + case BRIDGE_SN9C120: + err = sn9c102_write_const_regs(cam, {0x40, 0x02}, {0x00, 0x03}, + {0x1a, 0x04}, {0x03, 0x10}, + {0x0a, 0x14}, {0xe2, 0x17}, + {0x0b, 0x18}, {0x00, 0x19}, + {0x1d, 0x1a}, {0x10, 0x1b}, + {0x02, 0x1c}, {0x03, 0x1d}, + {0x0f, 0x1e}, {0x0c, 0x1f}, + {0x00, 0x20}, {0x24, 0x21}, + {0x3b, 0x22}, {0x47, 0x23}, + {0x60, 0x24}, {0x71, 0x25}, + {0x80, 0x26}, {0x8f, 0x27}, + {0x9d, 0x28}, {0xaa, 0x29}, + {0xb8, 0x2a}, {0xc4, 0x2b}, + {0xd1, 0x2c}, {0xdd, 0x2d}, + {0xe8, 0x2e}, {0xf4, 0x2f}, + {0xff, 0x30}, {0x00, 0x3f}, + {0xc7, 0x40}, {0x01, 0x41}, + {0x44, 0x42}, {0x00, 0x43}, + {0x44, 0x44}, {0x00, 0x45}, + {0x44, 0x46}, {0x00, 0x47}, + {0xc7, 0x48}, {0x01, 0x49}, + {0xc7, 0x4a}, {0x01, 0x4b}, + {0xc7, 0x4c}, {0x01, 0x4d}, + {0x44, 0x4e}, {0x00, 0x4f}, + {0x44, 0x50}, {0x00, 0x51}, + {0x44, 0x52}, {0x00, 0x53}, + {0xc7, 0x54}, {0x01, 0x55}, + {0xc7, 0x56}, {0x01, 0x57}, + {0xc7, 0x58}, {0x01, 0x59}, + {0x44, 0x5a}, {0x00, 0x5b}, + {0x44, 0x5c}, {0x00, 0x5d}, + {0x44, 0x5e}, {0x00, 0x5f}, + {0xc7, 0x60}, {0x01, 0x61}, + {0xc7, 0x62}, {0x01, 0x63}, + {0xc7, 0x64}, {0x01, 0x65}, + {0x44, 0x66}, {0x00, 0x67}, + {0x44, 0x68}, {0x00, 0x69}, + {0x44, 0x6a}, {0x00, 0x6b}, + {0xc7, 0x6c}, {0x01, 0x6d}, + {0xc7, 0x6e}, {0x01, 0x6f}, + {0xc7, 0x70}, {0x01, 0x71}, + {0x44, 0x72}, {0x00, 0x73}, + {0x44, 0x74}, {0x00, 0x75}, + {0x44, 0x76}, {0x00, 0x77}, + {0xc7, 0x78}, {0x01, 0x79}, + {0xc7, 0x7a}, {0x01, 0x7b}, + {0xc7, 0x7c}, {0x01, 0x7d}, + {0x44, 0x7e}, {0x00, 0x7f}, + {0x17, 0x84}, {0x00, 0x85}, + {0x2e, 0x86}, {0x00, 0x87}, + {0x09, 0x88}, {0x00, 0x89}, + {0xe8, 0x8a}, {0x0f, 0x8b}, + {0xda, 0x8c}, {0x0f, 0x8d}, + {0x40, 0x8e}, {0x00, 0x8f}, + {0x37, 0x90}, {0x00, 0x91}, + {0xcf, 0x92}, {0x0f, 0x93}, + {0xfa, 0x94}, {0x0f, 0x95}, + {0x00, 0x96}, {0x00, 0x97}, + {0x00, 0x98}, {0x66, 0x99}, + {0x00, 0x9a}, {0x40, 0x9b}, + {0x20, 0x9c}, {0x00, 0x9d}, + {0x00, 0x9e}, {0x00, 0x9f}, + {0x2d, 0xc0}, {0x2d, 0xc1}, + {0x3a, 0xc2}, {0x00, 0xc3}, + {0x04, 0xc4}, {0x3f, 0xc5}, + {0x00, 0xc6}, {0x00, 0xc7}, + {0x50, 0xc8}, {0x3c, 0xc9}, + {0x28, 0xca}, {0xd8, 0xcb}, + {0x14, 0xcc}, {0xec, 0xcd}, + {0x32, 0xce}, {0xdd, 0xcf}, + {0x32, 0xd0}, {0xdd, 0xd1}, + {0x6a, 0xd2}, {0x50, 0xd3}, + {0x60, 0xd4}, {0x00, 0xd5}, + {0x00, 0xd6}); + + err += sn9c102_i2c_write(cam, 0x12, 0x80); + err += sn9c102_i2c_write(cam, 0x12, 0x48); + err += sn9c102_i2c_write(cam, 0x01, 0x80); + err += sn9c102_i2c_write(cam, 0x02, 0x80); + err += sn9c102_i2c_write(cam, 0x03, 0x80); + err += sn9c102_i2c_write(cam, 0x04, 0x10); + err += sn9c102_i2c_write(cam, 0x05, 0x20); + err += sn9c102_i2c_write(cam, 0x06, 0x80); + err += sn9c102_i2c_write(cam, 0x11, 0x00); + err += sn9c102_i2c_write(cam, 0x0c, 0x20); + err += sn9c102_i2c_write(cam, 0x0d, 0x20); + err += sn9c102_i2c_write(cam, 0x15, 0x80); + err += sn9c102_i2c_write(cam, 0x16, 0x03); + err += sn9c102_i2c_write(cam, 0x17, 0x1b); + err += sn9c102_i2c_write(cam, 0x18, 0xbd); + err += sn9c102_i2c_write(cam, 0x19, 0x05); + err += sn9c102_i2c_write(cam, 0x1a, 0xf6); + err += sn9c102_i2c_write(cam, 0x1b, 0x04); + err += sn9c102_i2c_write(cam, 0x21, 0x1b); + err += sn9c102_i2c_write(cam, 0x22, 0x00); + err += sn9c102_i2c_write(cam, 0x23, 0xde); + err += sn9c102_i2c_write(cam, 0x24, 0x10); + err += sn9c102_i2c_write(cam, 0x25, 0x8a); + err += sn9c102_i2c_write(cam, 0x26, 0xa0); + err += sn9c102_i2c_write(cam, 0x27, 0xca); + err += sn9c102_i2c_write(cam, 0x28, 0xa2); + err += sn9c102_i2c_write(cam, 0x29, 0x74); + err += sn9c102_i2c_write(cam, 0x2a, 0x88); + err += sn9c102_i2c_write(cam, 0x2b, 0x34); + err += sn9c102_i2c_write(cam, 0x2c, 0x88); + err += sn9c102_i2c_write(cam, 0x2e, 0x00); + err += sn9c102_i2c_write(cam, 0x2f, 0x00); + err += sn9c102_i2c_write(cam, 0x30, 0x00); + err += sn9c102_i2c_write(cam, 0x32, 0xc2); + err += sn9c102_i2c_write(cam, 0x33, 0x08); + err += sn9c102_i2c_write(cam, 0x4c, 0x40); + err += sn9c102_i2c_write(cam, 0x4d, 0xf3); + err += sn9c102_i2c_write(cam, 0x60, 0x05); + err += sn9c102_i2c_write(cam, 0x61, 0x40); + err += sn9c102_i2c_write(cam, 0x62, 0x12); + err += sn9c102_i2c_write(cam, 0x63, 0x57); + err += sn9c102_i2c_write(cam, 0x64, 0x73); + err += sn9c102_i2c_write(cam, 0x65, 0x00); + err += sn9c102_i2c_write(cam, 0x66, 0x55); + err += sn9c102_i2c_write(cam, 0x67, 0x01); + err += sn9c102_i2c_write(cam, 0x68, 0xac); + err += sn9c102_i2c_write(cam, 0x69, 0x38); + err += sn9c102_i2c_write(cam, 0x6f, 0x1f); + err += sn9c102_i2c_write(cam, 0x70, 0x01); + err += sn9c102_i2c_write(cam, 0x71, 0x00); + err += sn9c102_i2c_write(cam, 0x72, 0x10); + err += sn9c102_i2c_write(cam, 0x73, 0x50); + err += sn9c102_i2c_write(cam, 0x74, 0x20); + err += sn9c102_i2c_write(cam, 0x76, 0x01); + err += sn9c102_i2c_write(cam, 0x77, 0xf3); + err += sn9c102_i2c_write(cam, 0x78, 0x90); + err += sn9c102_i2c_write(cam, 0x79, 0x98); + err += sn9c102_i2c_write(cam, 0x7a, 0x98); + err += sn9c102_i2c_write(cam, 0x7b, 0x00); + err += sn9c102_i2c_write(cam, 0x7c, 0x38); + err += sn9c102_i2c_write(cam, 0x7d, 0xff); + break; default: break; } @@ -115,6 +254,7 @@ static int ov7630_init(struct sn9c102_device* cam) static int ov7630_get_ctrl(struct sn9c102_device* cam, struct v4l2_control* ctrl) { + enum sn9c102_bridge bridge = sn9c102_get_bridge(cam); int err = 0; switch (ctrl->id) { @@ -123,13 +263,20 @@ static int ov7630_get_ctrl(struct sn9c102_device* cam, return -EIO; break; case V4L2_CID_RED_BALANCE: - ctrl->value = sn9c102_pread_reg(cam, 0x07); + if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120) + ctrl->value = sn9c102_pread_reg(cam, 0x05); + else + ctrl->value = sn9c102_pread_reg(cam, 0x07); break; case V4L2_CID_BLUE_BALANCE: ctrl->value = sn9c102_pread_reg(cam, 0x06); break; case SN9C102_V4L2_CID_GREEN_BALANCE: - ctrl->value = sn9c102_pread_reg(cam, 0x05); + if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120) + ctrl->value = sn9c102_pread_reg(cam, 0x07); + else + ctrl->value = sn9c102_pread_reg(cam, 0x05); + break; break; case V4L2_CID_GAIN: if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0) @@ -177,6 +324,7 @@ static int ov7630_get_ctrl(struct sn9c102_device* cam, static int ov7630_set_ctrl(struct sn9c102_device* cam, const struct v4l2_control* ctrl) { + enum sn9c102_bridge bridge = sn9c102_get_bridge(cam); int err = 0; switch (ctrl->id) { @@ -184,13 +332,19 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam, err += sn9c102_i2c_write(cam, 0x10, ctrl->value); break; case V4L2_CID_RED_BALANCE: - err += sn9c102_write_reg(cam, ctrl->value, 0x07); + if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120) + err += sn9c102_write_reg(cam, ctrl->value, 0x05); + else + err += sn9c102_write_reg(cam, ctrl->value, 0x07); break; case V4L2_CID_BLUE_BALANCE: err += sn9c102_write_reg(cam, ctrl->value, 0x06); break; case SN9C102_V4L2_CID_GREEN_BALANCE: - err += sn9c102_write_reg(cam, ctrl->value, 0x05); + if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120) + err += sn9c102_write_reg(cam, ctrl->value, 0x07); + else + err += sn9c102_write_reg(cam, ctrl->value, 0x05); break; case V4L2_CID_GAIN: err += sn9c102_i2c_write(cam, 0x00, ctrl->value); @@ -227,8 +381,21 @@ static int ov7630_set_crop(struct sn9c102_device* cam, { struct sn9c102_sensor* s = sn9c102_get_sensor(cam); int err = 0; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; + u8 h_start = 0, v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; + + switch (sn9c102_get_bridge(cam)) { + case BRIDGE_SN9C101: + case BRIDGE_SN9C102: + case BRIDGE_SN9C103: + h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1; + break; + case BRIDGE_SN9C105: + case BRIDGE_SN9C120: + h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4; + break; + default: + break; + } err += sn9c102_write_reg(cam, h_start, 0x12); err += sn9c102_write_reg(cam, v_start, 0x13); @@ -242,10 +409,28 @@ static int ov7630_set_pix_format(struct sn9c102_device* cam, { int err = 0; - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) - err += sn9c102_write_reg(cam, 0x20, 0x19); - else - err += sn9c102_write_reg(cam, 0x50, 0x19); + switch (sn9c102_get_bridge(cam)) { + case BRIDGE_SN9C101: + case BRIDGE_SN9C102: + case BRIDGE_SN9C103: + if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) + err += sn9c102_write_reg(cam, 0x50, 0x19); + else + err += sn9c102_write_reg(cam, 0x20, 0x19); + break; + case BRIDGE_SN9C105: + case BRIDGE_SN9C120: + if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { + err += sn9c102_write_reg(cam, 0xe5, 0x17); + err += sn9c102_i2c_write(cam, 0x11, 0x04); + } else { + err += sn9c102_write_reg(cam, 0xe2, 0x17); + err += sn9c102_i2c_write(cam, 0x11, 0x02); + } + break; + default: + break; + } return err; } @@ -254,7 +439,8 @@ static int ov7630_set_pix_format(struct sn9c102_device* cam, static const struct sn9c102_sensor ov7630 = { .name = "OV7630", .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, + .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103 | + BRIDGE_SN9C105 | BRIDGE_SN9C120, .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, .frequency = SN9C102_I2C_100KHZ, .interface = SN9C102_I2C_2WIRES, @@ -417,6 +603,12 @@ int sn9c102_probe_ov7630(struct sn9c102_device* cam) err += sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01}); break; + case BRIDGE_SN9C105: + case BRIDGE_SN9C120: + err = sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1}, + {0x29, 0x01}, {0x74, 0x02}, + {0x0e, 0x01}, {0x44, 0x01}); + break; default: break; } diff --git a/drivers/media/video/sn9c102/sn9c102_ov7660.c b/drivers/media/video/sn9c102/sn9c102_ov7660.c index 4b6474048a72..8aae416ba8ec 100644 --- a/drivers/media/video/sn9c102/sn9c102_ov7660.c +++ b/drivers/media/video/sn9c102/sn9c102_ov7660.c @@ -41,65 +41,65 @@ static int ov7660_init(struct sn9c102_device* cam) {0xbb, 0x2a}, {0xc7, 0x2b}, {0xd3, 0x2c}, {0xde, 0x2d}, {0xea, 0x2e}, {0xf4, 0x2f}, - {0xff, 0x30}, {0x00, 0x3F}, - {0xC7, 0x40}, {0x01, 0x41}, + {0xff, 0x30}, {0x00, 0x3f}, + {0xc7, 0x40}, {0x01, 0x41}, {0x44, 0x42}, {0x00, 0x43}, {0x44, 0x44}, {0x00, 0x45}, {0x44, 0x46}, {0x00, 0x47}, - {0xC7, 0x48}, {0x01, 0x49}, - {0xC7, 0x4A}, {0x01, 0x4B}, - {0xC7, 0x4C}, {0x01, 0x4D}, - {0x44, 0x4E}, {0x00, 0x4F}, + {0xc7, 0x48}, {0x01, 0x49}, + {0xc7, 0x4a}, {0x01, 0x4b}, + {0xc7, 0x4c}, {0x01, 0x4d}, + {0x44, 0x4e}, {0x00, 0x4f}, {0x44, 0x50}, {0x00, 0x51}, {0x44, 0x52}, {0x00, 0x53}, - {0xC7, 0x54}, {0x01, 0x55}, - {0xC7, 0x56}, {0x01, 0x57}, - {0xC7, 0x58}, {0x01, 0x59}, - {0x44, 0x5A}, {0x00, 0x5B}, - {0x44, 0x5C}, {0x00, 0x5D}, - {0x44, 0x5E}, {0x00, 0x5F}, - {0xC7, 0x60}, {0x01, 0x61}, - {0xC7, 0x62}, {0x01, 0x63}, - {0xC7, 0x64}, {0x01, 0x65}, + {0xc7, 0x54}, {0x01, 0x55}, + {0xc7, 0x56}, {0x01, 0x57}, + {0xc7, 0x58}, {0x01, 0x59}, + {0x44, 0x5a}, {0x00, 0x5b}, + {0x44, 0x5c}, {0x00, 0x5d}, + {0x44, 0x5e}, {0x00, 0x5f}, + {0xc7, 0x60}, {0x01, 0x61}, + {0xc7, 0x62}, {0x01, 0x63}, + {0xc7, 0x64}, {0x01, 0x65}, {0x44, 0x66}, {0x00, 0x67}, {0x44, 0x68}, {0x00, 0x69}, - {0x44, 0x6A}, {0x00, 0x6B}, - {0xC7, 0x6C}, {0x01, 0x6D}, - {0xC7, 0x6E}, {0x01, 0x6F}, - {0xC7, 0x70}, {0x01, 0x71}, + {0x44, 0x6a}, {0x00, 0x6b}, + {0xc7, 0x6c}, {0x01, 0x6d}, + {0xc7, 0x6e}, {0x01, 0x6f}, + {0xc7, 0x70}, {0x01, 0x71}, {0x44, 0x72}, {0x00, 0x73}, {0x44, 0x74}, {0x00, 0x75}, {0x44, 0x76}, {0x00, 0x77}, - {0xC7, 0x78}, {0x01, 0x79}, - {0xC7, 0x7A}, {0x01, 0x7B}, - {0xC7, 0x7C}, {0x01, 0x7D}, - {0x44, 0x7E}, {0x00, 0x7F}, + {0xc7, 0x78}, {0x01, 0x79}, + {0xc7, 0x7a}, {0x01, 0x7b}, + {0xc7, 0x7c}, {0x01, 0x7d}, + {0x44, 0x7e}, {0x00, 0x7f}, {0x14, 0x84}, {0x00, 0x85}, {0x27, 0x86}, {0x00, 0x87}, {0x07, 0x88}, {0x00, 0x89}, - {0xEC, 0x8A}, {0x0f, 0x8B}, - {0xD8, 0x8C}, {0x0f, 0x8D}, - {0x3D, 0x8E}, {0x00, 0x8F}, - {0x3D, 0x90}, {0x00, 0x91}, - {0xCD, 0x92}, {0x0f, 0x93}, + {0xec, 0x8a}, {0x0f, 0x8b}, + {0xd8, 0x8c}, {0x0f, 0x8d}, + {0x3d, 0x8e}, {0x00, 0x8f}, + {0x3d, 0x90}, {0x00, 0x91}, + {0xcd, 0x92}, {0x0f, 0x93}, {0xf7, 0x94}, {0x0f, 0x95}, - {0x0C, 0x96}, {0x00, 0x97}, + {0x0c, 0x96}, {0x00, 0x97}, {0x00, 0x98}, {0x66, 0x99}, - {0x05, 0x9A}, {0x00, 0x9B}, - {0x04, 0x9C}, {0x00, 0x9D}, - {0x08, 0x9E}, {0x00, 0x9F}, - {0x2D, 0xC0}, {0x2D, 0xC1}, - {0x3A, 0xC2}, {0x05, 0xC3}, - {0x04, 0xC4}, {0x3F, 0xC5}, - {0x00, 0xC6}, {0x00, 0xC7}, - {0x50, 0xC8}, {0x3C, 0xC9}, - {0x28, 0xCA}, {0xD8, 0xCB}, - {0x14, 0xCC}, {0xEC, 0xCD}, - {0x32, 0xCE}, {0xDD, 0xCF}, - {0x32, 0xD0}, {0xDD, 0xD1}, - {0x6A, 0xD2}, {0x50, 0xD3}, - {0x00, 0xD4}, {0x00, 0xD5}, - {0x00, 0xD6}); + {0x05, 0x9a}, {0x00, 0x9b}, + {0x04, 0x9c}, {0x00, 0x9d}, + {0x08, 0x9e}, {0x00, 0x9f}, + {0x2d, 0xc0}, {0x2d, 0xc1}, + {0x3a, 0xc2}, {0x05, 0xc3}, + {0x04, 0xc4}, {0x3f, 0xc5}, + {0x00, 0xc6}, {0x00, 0xc7}, + {0x50, 0xc8}, {0x3C, 0xc9}, + {0x28, 0xca}, {0xd8, 0xcb}, + {0x14, 0xcc}, {0xec, 0xcd}, + {0x32, 0xce}, {0xdd, 0xcf}, + {0x32, 0xd0}, {0xdd, 0xd1}, + {0x6a, 0xd2}, {0x50, 0xd3}, + {0x00, 0xd4}, {0x00, 0xd5}, + {0x00, 0xd6}); err += sn9c102_i2c_write(cam, 0x12, 0x80); err += sn9c102_i2c_write(cam, 0x11, 0x09); diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c index 3e736be5de84..eb220461ac77 100644 --- a/drivers/media/video/stradis.c +++ b/drivers/media/video/stradis.c @@ -1321,7 +1321,7 @@ static int saa_ioctl(struct inode *inode, struct file *file, u32 format; if (copy_from_user(&p, arg, sizeof(p))) return -EFAULT; - if (p.palette < sizeof(palette2fmt) / sizeof(u32)) { + if (p.palette < ARRAY_SIZE(palette2fmt)) { format = palette2fmt[p.palette]; saa->win.color_fmt = format; saawrite(format | 0x60, diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c index bf3aa8d2d57e..4dc5bc714b95 100644 --- a/drivers/media/video/stv680.c +++ b/drivers/media/video/stv680.c @@ -715,8 +715,11 @@ static int stv680_start_stream (struct usb_stv *stv680) stv680_video_irq, stv680); stv680->urb[i] = urb; err = usb_submit_urb (stv680->urb[i], GFP_KERNEL); - if (err) - PDEBUG (0, "STV(e): urb burned down in start stream"); + if (err) { + PDEBUG (0, "STV(e): urb burned down with err " + "%d in start stream %d", err, i); + goto nomem_err; + } } /* i STV680_NUMSBUF */ stv680->framecount = 0; diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 1a1bef0e9c3d..59cff5a3c59e 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -21,7 +21,17 @@ #include <linux/i2c.h> #include <linux/videodev.h> #include <linux/delay.h> -#include <media/tuner.h> +#include "tuner-driver.h" + +/* ---------------------------------------------------------------------- */ + +struct tda8290_priv { + unsigned char tda8290_easy_mode; + unsigned char tda827x_lpsel; + unsigned char tda827x_addr; + unsigned char tda827x_ver; + unsigned int sgIF; +}; /* ---------------------------------------------------------------------- */ @@ -76,7 +86,8 @@ static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq) u32 N; int i; struct tuner *t = i2c_get_clientdata(c); - struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0}; + struct tda8290_priv *priv = t->priv; + struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0}; if (t->mode == V4L2_TUNER_RADIO) freq = freq / 1000; @@ -95,7 +106,7 @@ static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq) tuner_reg[1] = (unsigned char)(N>>8); tuner_reg[2] = (unsigned char) N; tuner_reg[3] = 0x40; - tuner_reg[4] = 0x52 + (t->tda827x_lpsel << 5); + tuner_reg[4] = 0x52 + (priv->tda827x_lpsel << 5); tuner_reg[5] = (tda827x_analog[i].spd << 6) + (tda827x_analog[i].div1p5 <<5) + (tda827x_analog[i].bs <<3) + tda827x_analog[i].bp; tuner_reg[6] = 0x8f + (tda827x_analog[i].gc3 << 4); @@ -146,8 +157,9 @@ static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq) static void tda827x_agcf(struct i2c_client *c) { struct tuner *t = i2c_get_clientdata(c); + struct tda8290_priv *priv = t->priv; unsigned char data[] = {0x80, 0x0c}; - struct i2c_msg msg = {.addr = t->tda827x_addr, .buf = data, + struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data, .flags = 0, .len = 2}; i2c_transfer(c->adapter, &msg, 1); } @@ -234,7 +246,8 @@ static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq) u32 N; int i; struct tuner *t = i2c_get_clientdata(c); - struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0, .buf = tuner_reg}; + struct tda8290_priv *priv = t->priv; + struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0, .buf = tuner_reg}; tda827xa_lna_gain( c, 1); msleep(10); @@ -271,7 +284,7 @@ static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq) tuner_reg[1] = 0xff; tuner_reg[2] = 0xe0; tuner_reg[3] = 0; - tuner_reg[4] = 0x99 + (t->tda827x_lpsel << 1); + tuner_reg[4] = 0x99 + (priv->tda827x_lpsel << 1); msg.len = 5; i2c_transfer(c->adapter, &msg, 1); @@ -311,15 +324,16 @@ static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq) i2c_transfer(c->adapter, &msg, 1); tuner_reg[0] = 0xc0; - tuner_reg[1] = 0x19 + (t->tda827x_lpsel << 1); + tuner_reg[1] = 0x19 + (priv->tda827x_lpsel << 1); i2c_transfer(c->adapter, &msg, 1); } static void tda827xa_agcf(struct i2c_client *c) { struct tuner *t = i2c_get_clientdata(c); + struct tda8290_priv *priv = t->priv; unsigned char data[] = {0x80, 0x2c}; - struct i2c_msg msg = {.addr = t->tda827x_addr, .buf = data, + struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data, .flags = 0, .len = 2}; i2c_transfer(c->adapter, &msg, 1); } @@ -347,8 +361,9 @@ static void tda8290_i2c_bridge(struct i2c_client *c, int close) static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) { struct tuner *t = i2c_get_clientdata(c); + struct tda8290_priv *priv = t->priv; unsigned char soft_reset[] = { 0x00, 0x00 }; - unsigned char easy_mode[] = { 0x01, t->tda8290_easy_mode }; + unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode }; unsigned char expert_mode[] = { 0x01, 0x80 }; unsigned char agc_out_on[] = { 0x02, 0x00 }; unsigned char gainset_off[] = { 0x28, 0x14 }; @@ -375,18 +390,18 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) i2c_master_send(c, soft_reset, 2); msleep(1); - expert_mode[1] = t->tda8290_easy_mode + 0x80; + expert_mode[1] = priv->tda8290_easy_mode + 0x80; i2c_master_send(c, expert_mode, 2); i2c_master_send(c, gainset_off, 2); i2c_master_send(c, if_agc_spd, 2); - if (t->tda8290_easy_mode & 0x60) + if (priv->tda8290_easy_mode & 0x60) i2c_master_send(c, adc_head_9, 2); else i2c_master_send(c, adc_head_6, 2); i2c_master_send(c, pll_bw_nom, 2); tda8290_i2c_bridge(c, 1); - if (t->tda827x_ver != 0) + if (priv->tda827x_ver != 0) tda827xa_tune(c, ifc, freq); else tda827x_tune(c, ifc, freq); @@ -418,7 +433,7 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) if ((agc_stat > 115) || !(pll_stat & 0x80)) { tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n", agc_stat, pll_stat & 0x80); - if (t->tda827x_ver != 0) + if (priv->tda827x_ver != 0) tda827xa_agcf(c); else tda827x_agcf(c); @@ -437,7 +452,7 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) } /* l/ l' deadlock? */ - if(t->tda8290_easy_mode & 0x60) { + if(priv->tda8290_easy_mode & 0x60) { i2c_master_send(c, &addr_adc_sat, 1); i2c_master_recv(c, &adc_sat, 1); i2c_master_send(c, &addr_pll_stat, 1); @@ -459,41 +474,42 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) static void set_audio(struct tuner *t) { + struct tda8290_priv *priv = t->priv; char* mode; - t->tda827x_lpsel = 0; + priv->tda827x_lpsel = 0; if (t->std & V4L2_STD_MN) { - t->sgIF = 92; - t->tda8290_easy_mode = 0x01; - t->tda827x_lpsel = 1; + priv->sgIF = 92; + priv->tda8290_easy_mode = 0x01; + priv->tda827x_lpsel = 1; mode = "MN"; } else if (t->std & V4L2_STD_B) { - t->sgIF = 108; - t->tda8290_easy_mode = 0x02; + priv->sgIF = 108; + priv->tda8290_easy_mode = 0x02; mode = "B"; } else if (t->std & V4L2_STD_GH) { - t->sgIF = 124; - t->tda8290_easy_mode = 0x04; + priv->sgIF = 124; + priv->tda8290_easy_mode = 0x04; mode = "GH"; } else if (t->std & V4L2_STD_PAL_I) { - t->sgIF = 124; - t->tda8290_easy_mode = 0x08; + priv->sgIF = 124; + priv->tda8290_easy_mode = 0x08; mode = "I"; } else if (t->std & V4L2_STD_DK) { - t->sgIF = 124; - t->tda8290_easy_mode = 0x10; + priv->sgIF = 124; + priv->tda8290_easy_mode = 0x10; mode = "DK"; } else if (t->std & V4L2_STD_SECAM_L) { - t->sgIF = 124; - t->tda8290_easy_mode = 0x20; + priv->sgIF = 124; + priv->tda8290_easy_mode = 0x20; mode = "L"; } else if (t->std & V4L2_STD_SECAM_LC) { - t->sgIF = 20; - t->tda8290_easy_mode = 0x40; + priv->sgIF = 20; + priv->tda8290_easy_mode = 0x40; mode = "LC"; } else { - t->sgIF = 124; - t->tda8290_easy_mode = 0x10; + priv->sgIF = 124; + priv->tda8290_easy_mode = 0x10; mode = "xx"; } tuner_dbg("setting tda8290 to system %s\n", mode); @@ -502,9 +518,10 @@ static void set_audio(struct tuner *t) static void set_tv_freq(struct i2c_client *c, unsigned int freq) { struct tuner *t = i2c_get_clientdata(c); + struct tda8290_priv *priv = t->priv; set_audio(t); - tda8290_tune(c, t->sgIF, freq); + tda8290_tune(c, priv->sgIF, freq); } static void set_radio_freq(struct i2c_client *c, unsigned int freq) @@ -528,13 +545,14 @@ static int has_signal(struct i2c_client *c) static void standby(struct i2c_client *c) { struct tuner *t = i2c_get_clientdata(c); + struct tda8290_priv *priv = t->priv; 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}; + struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2}; tda8290_i2c_bridge(c, 1); - if (t->tda827x_ver != 0) + if (priv->tda827x_ver != 0) cb1[1] = 0x90; i2c_transfer(c->adapter, &msg, 1); tda8290_i2c_bridge(c, 0); @@ -560,13 +578,14 @@ static void tda8290_init_if(struct i2c_client *c) static void tda8290_init_tuner(struct i2c_client *c) { struct tuner *t = i2c_get_clientdata(c); + struct tda8290_priv *priv = t->priv; unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf, 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 }; unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b, 0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b }; - struct i2c_msg msg = {.addr = t->tda827x_addr, .flags=0, + struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=tda8275_init, .len = 14}; - if (t->tda827x_ver != 0) + if (priv->tda827x_ver != 0) msg.buf = tda8275a_init; tda8290_i2c_bridge(c, 1); @@ -576,14 +595,36 @@ static void tda8290_init_tuner(struct i2c_client *c) /*---------------------------------------------------------------------*/ +static void tda8290_release(struct i2c_client *c) +{ + struct tuner *t = i2c_get_clientdata(c); + + kfree(t->priv); + t->priv = NULL; +} + +static struct tuner_operations tda8290_tuner_ops = { + .set_tv_freq = set_tv_freq, + .set_radio_freq = set_radio_freq, + .has_signal = has_signal, + .standby = standby, + .release = tda8290_release, +}; + int tda8290_init(struct i2c_client *c) { + struct tda8290_priv *priv = NULL; struct tuner *t = i2c_get_clientdata(c); u8 data; int i, ret, tuners_found; u32 tuner_addrs; struct i2c_msg msg = {.flags=I2C_M_RD, .buf=&data, .len = 1}; + priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + t->priv = priv; + tda8290_i2c_bridge(c, 1); /* probe for tuner chip */ tuners_found = 0; @@ -618,7 +659,7 @@ int tda8290_init(struct i2c_client *c) tuner_addrs = tuner_addrs & 0xff; tuner_info ("setting tuner address to %x\n", tuner_addrs); } - t->tda827x_addr = tuner_addrs; + priv->tda827x_addr = tuner_addrs; msg.addr = tuner_addrs; tda8290_i2c_bridge(c, 1); @@ -627,18 +668,16 @@ int tda8290_init(struct i2c_client *c) tuner_warn ("TDA827x access failed!\n"); if ((data & 0x3c) == 0) { strlcpy(c->name, "tda8290+75", sizeof(c->name)); - t->tda827x_ver = 0; + priv->tda827x_ver = 0; } else { strlcpy(c->name, "tda8290+75a", sizeof(c->name)); - t->tda827x_ver = 2; + priv->tda827x_ver = 2; } tuner_info("type set to %s\n", c->name); - t->set_tv_freq = set_tv_freq; - t->set_radio_freq = set_radio_freq; - t->has_signal = has_signal; - t->standby = standby; - t->tda827x_lpsel = 0; + memcpy(&t->ops, &tda8290_tuner_ops, sizeof(struct tuner_operations)); + + priv->tda827x_lpsel = 0; t->mode = V4L2_TUNER_ANALOG_TV; tda8290_init_tuner(c); diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index fde576f1101c..a8f773274fe3 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -11,6 +11,7 @@ #include <media/v4l2-common.h> #include <media/tuner.h> +#include "tuner-driver.h" /* Chips: @@ -29,6 +30,9 @@ printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) +struct tda9887_priv { + unsigned char data[4]; +}; /* ---------------------------------------------------------------------- */ @@ -508,10 +512,11 @@ static int tda9887_status(struct tuner *t) static void tda9887_configure(struct i2c_client *client) { struct tuner *t = i2c_get_clientdata(client); + struct tda9887_priv *priv = t->priv; int rc; - memset(t->tda9887_data,0,sizeof(t->tda9887_data)); - tda9887_set_tvnorm(t,t->tda9887_data); + memset(priv->data,0,sizeof(priv->data)); + tda9887_set_tvnorm(t,priv->data); /* A note on the port settings: These settings tend to depend on the specifics of the board. @@ -526,22 +531,22 @@ static void tda9887_configure(struct i2c_client *client) the ports should be set to active (0), but, again, that may differ depending on the precise hardware configuration. */ - t->tda9887_data[1] |= cOutputPort1Inactive; - t->tda9887_data[1] |= cOutputPort2Inactive; + priv->data[1] |= cOutputPort1Inactive; + priv->data[1] |= cOutputPort2Inactive; - tda9887_set_config(t,t->tda9887_data); - tda9887_set_insmod(t,t->tda9887_data); + tda9887_set_config(t,priv->data); + tda9887_set_insmod(t,priv->data); if (t->mode == T_STANDBY) { - t->tda9887_data[1] |= cForcedMuteAudioON; + priv->data[1] |= cForcedMuteAudioON; } tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n", - t->tda9887_data[1],t->tda9887_data[2],t->tda9887_data[3]); + priv->data[1],priv->data[2],priv->data[3]); if (tuner_debug > 1) - dump_write_message(t, t->tda9887_data); + dump_write_message(t, priv->data); - if (4 != (rc = i2c_master_send(&t->i2c,t->tda9887_data,4))) + if (4 != (rc = i2c_master_send(&t->i2c,priv->data,4))) tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc); if (tuner_debug > 2) { @@ -555,7 +560,8 @@ static void tda9887_configure(struct i2c_client *client) static void tda9887_tuner_status(struct i2c_client *client) { struct tuner *t = i2c_get_clientdata(client); - tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->tda9887_data[1], t->tda9887_data[2], t->tda9887_data[3]); + struct tda9887_priv *priv = t->priv; + tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1], priv->data[2], priv->data[3]); } static int tda9887_get_afc(struct i2c_client *client) @@ -586,20 +592,39 @@ static void tda9887_set_freq(struct i2c_client *client, unsigned int freq) tda9887_configure(client); } +static void tda9887_release(struct i2c_client *c) +{ + struct tuner *t = i2c_get_clientdata(c); + + kfree(t->priv); + t->priv = NULL; +} + +static struct tuner_operations tda9887_tuner_ops = { + .set_tv_freq = tda9887_set_freq, + .set_radio_freq = tda9887_set_freq, + .standby = tda9887_standby, + .tuner_status = tda9887_tuner_status, + .get_afc = tda9887_get_afc, + .release = tda9887_release, +}; + int tda9887_tuner_init(struct i2c_client *c) { + struct tda9887_priv *priv = NULL; struct tuner *t = i2c_get_clientdata(c); + priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + t->priv = priv; + strlcpy(c->name, "tda9887", sizeof(c->name)); tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr, t->i2c.driver->driver.name); - t->set_tv_freq = tda9887_set_freq; - t->set_radio_freq = tda9887_set_freq; - t->standby = tda9887_standby; - t->tuner_status = tda9887_tuner_status; - t->get_afc = tda9887_get_afc; + memcpy(&t->ops, &tda9887_tuner_ops, sizeof(struct tuner_operations)); return 0; } diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c new file mode 100644 index 000000000000..ae105c2cd0ac --- /dev/null +++ b/drivers/media/video/tea5761.c @@ -0,0 +1,243 @@ +/* + * For Philips TEA5761 FM Chip + * I2C address is allways 0x20 (0x10 at 7-bit mode). + * + * Copyright (c) 2005-2007 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNUv2 General Public License + * + */ + +#include <linux/i2c.h> +#include <linux/videodev.h> +#include <linux/delay.h> +#include <media/tuner.h> +#include "tuner-driver.h" + +#define PREFIX "TEA5761 " + +/* from tuner-core.c */ +extern int tuner_debug; + +/*****************************************************************************/ + +/*************************** + * TEA5761HN I2C registers * + ***************************/ + +/* INTREG - Read: bytes 0 and 1 / Write: byte 0 */ + + /* first byte for reading */ +#define TEA5761_INTREG_IFFLAG 0x10 +#define TEA5761_INTREG_LEVFLAG 0x8 +#define TEA5761_INTREG_FRRFLAG 0x2 +#define TEA5761_INTREG_BLFLAG 0x1 + + /* second byte for reading / byte for writing */ +#define TEA5761_INTREG_IFMSK 0x10 +#define TEA5761_INTREG_LEVMSK 0x8 +#define TEA5761_INTREG_FRMSK 0x2 +#define TEA5761_INTREG_BLMSK 0x1 + +/* FRQSET - Read: bytes 2 and 3 / Write: byte 1 and 2 */ + + /* First byte */ +#define TEA5761_FRQSET_SEARCH_UP 0x80 /* 1=Station search from botton to up */ +#define TEA5761_FRQSET_SEARCH_MODE 0x40 /* 1=Search mode */ + + /* Bits 0-5 for divider MSB */ + + /* Second byte */ + /* Bits 0-7 for divider LSB */ + +/* TNCTRL - Read: bytes 4 and 5 / Write: Bytes 3 and 4 */ + + /* first byte */ + +#define TEA5761_TNCTRL_PUPD_0 0x40 /* Power UP/Power Down MSB */ +#define TEA5761_TNCTRL_BLIM 0X20 /* 1= Japan Frequencies, 0= European frequencies */ +#define TEA5761_TNCTRL_SWPM 0x10 /* 1= software port is FRRFLAG */ +#define TEA5761_TNCTRL_IFCTC 0x08 /* 1= IF count time 15.02 ms, 0= IF count time 2.02 ms */ +#define TEA5761_TNCTRL_AFM 0x04 +#define TEA5761_TNCTRL_SMUTE 0x02 /* 1= Soft mute */ +#define TEA5761_TNCTRL_SNC 0x01 + + /* second byte */ + +#define TEA5761_TNCTRL_MU 0x80 /* 1=Hard mute */ +#define TEA5761_TNCTRL_SSL_1 0x40 +#define TEA5761_TNCTRL_SSL_0 0x20 +#define TEA5761_TNCTRL_HLSI 0x10 +#define TEA5761_TNCTRL_MST 0x08 /* 1 = mono */ +#define TEA5761_TNCTRL_SWP 0x04 +#define TEA5761_TNCTRL_DTC 0x02 /* 1 = deemphasis 50 us, 0 = deemphasis 75 us */ +#define TEA5761_TNCTRL_AHLSI 0x01 + +/* FRQCHECK - Read: bytes 6 and 7 */ + /* First byte */ + + /* Bits 0-5 for divider MSB */ + + /* Second byte */ + /* Bits 0-7 for divider LSB */ + +/* TUNCHECK - Read: bytes 8 and 9 */ + + /* First byte */ +#define TEA5761_TUNCHECK_IF_MASK 0x7e /* IF count */ +#define TEA5761_TUNCHECK_TUNTO 0x01 + + /* Second byte */ +#define TEA5761_TUNCHECK_LEV_MASK 0xf0 /* Level Count */ +#define TEA5761_TUNCHECK_LD 0x08 +#define TEA5761_TUNCHECK_STEREO 0x04 + +/* TESTREG - Read: bytes 10 and 11 / Write: bytes 5 and 6 */ + + /* All zero = no test mode */ + +/* MANID - Read: bytes 12 and 13 */ + + /* First byte - should be 0x10 */ +#define TEA5767_MANID_VERSION_MASK 0xf0 /* Version = 1 */ +#define TEA5767_MANID_ID_MSB_MASK 0x0f /* Manufacurer ID - should be 0 */ + + /* Second byte - Should be 0x2b */ + +#define TEA5767_MANID_ID_LSB_MASK 0xfe /* Manufacturer ID - should be 0x15 */ +#define TEA5767_MANID_IDAV 0x01 /* 1 = Chip has ID, 0 = Chip has no ID */ + +/* Chip ID - Read: bytes 14 and 15 */ + + /* First byte - should be 0x57 */ + + /* Second byte - should be 0x61 */ + +/*****************************************************************************/ + +static void set_tv_freq(struct i2c_client *c, unsigned int freq) +{ + struct tuner *t = i2c_get_clientdata(c); + + tuner_warn("This tuner doesn't support TV freq.\n"); +} + +#define FREQ_OFFSET 0 /* for TEA5767, it is 700 to give the right freq */ +static void tea5761_status_dump(unsigned char *buffer) +{ + unsigned int div, frq; + + div = ((buffer[2] & 0x3f) << 8) | buffer[3]; + + frq = 1000 * (div * 32768 / 1000 + FREQ_OFFSET + 225) / 4; /* Freq in KHz */ + + printk(PREFIX "Frequency %d.%03d KHz (divider = 0x%04x)\n", + frq / 1000, frq % 1000, div); +} + +/* Freq should be specifyed at 62.5 Hz */ +static void set_radio_freq(struct i2c_client *c, unsigned int frq) +{ + struct tuner *t = i2c_get_clientdata(c); + unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 }; + unsigned div; + int rc; + + tuner_dbg (PREFIX "radio freq counter %d\n", frq); + + if (t->mode == T_STANDBY) { + tuner_dbg("TEA5761 set to standby mode\n"); + buffer[5] |= TEA5761_TNCTRL_MU; + } else { + buffer[4] |= TEA5761_TNCTRL_PUPD_0; + } + + + if (t->audmode == V4L2_TUNER_MODE_MONO) { + tuner_dbg("TEA5761 set to mono\n"); + buffer[5] |= TEA5761_TNCTRL_MST; +; + } else { + tuner_dbg("TEA5761 set to stereo\n"); + } + + div = (1000 * (frq * 4 / 16 + 700 + 225) ) >> 15; + buffer[1] = (div >> 8) & 0x3f; + buffer[2] = div & 0xff; + + if (tuner_debug) + tea5761_status_dump(buffer); + + if (7 != (rc = i2c_master_send(c, buffer, 7))) + tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); +} + +static int tea5761_signal(struct i2c_client *c) +{ + unsigned char buffer[16]; + int rc; + struct tuner *t = i2c_get_clientdata(c); + + memset(buffer, 0, sizeof(buffer)); + if (16 != (rc = i2c_master_recv(c, buffer, 16))) + tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + + return ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4)); +} + +static int tea5761_stereo(struct i2c_client *c) +{ + unsigned char buffer[16]; + int rc; + struct tuner *t = i2c_get_clientdata(c); + + memset(buffer, 0, sizeof(buffer)); + if (16 != (rc = i2c_master_recv(c, buffer, 16))) + tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + + rc = buffer[9] & TEA5761_TUNCHECK_STEREO; + + tuner_dbg("TEA5761 radio ST GET = %02x\n", rc); + + return (rc ? V4L2_TUNER_SUB_STEREO : 0); +} + +int tea5761_autodetection(struct i2c_client *c) +{ + unsigned char buffer[16]; + int rc; + struct tuner *t = i2c_get_clientdata(c); + + if (16 != (rc = i2c_master_recv(c, buffer, 16))) { + tuner_warn("it is not a TEA5761. Received %i chars.\n", rc); + return EINVAL; + } + + if (!((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061))) { + tuner_warn("Manufacturer ID= 0x%02x, Chip ID = %02x%02x. It is not a TEA5761\n",buffer[13],buffer[14],buffer[15]); + return EINVAL; + } + tuner_warn("TEA5761 detected.\n"); + return 0; +} + +static struct tuner_operations tea5761_tuner_ops = { + .set_tv_freq = set_tv_freq, + .set_radio_freq = set_radio_freq, + .has_signal = tea5761_signal, + .is_stereo = tea5761_stereo, +}; + +int tea5761_tuner_init(struct i2c_client *c) +{ + struct tuner *t = i2c_get_clientdata(c); + + if (tea5761_autodetection(c) == EINVAL) + return EINVAL; + + tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5761HN FM Radio"); + strlcpy(c->name, "tea5761", sizeof(c->name)); + + memcpy(&t->ops, &tea5761_tuner_ops, sizeof(struct tuner_operations)); + + return (0); +} diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c index d1c41781ccc4..4985d47a508f 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/video/tea5767.c @@ -13,7 +13,7 @@ #include <linux/i2c.h> #include <linux/videodev.h> #include <linux/delay.h> -#include <media/tuner.h> +#include "tuner-driver.h" #define PREFIX "TEA5767 " @@ -343,6 +343,14 @@ int tea5767_autodetection(struct i2c_client *c) return 0; } +static struct tuner_operations tea5767_tuner_ops = { + .set_tv_freq = set_tv_freq, + .set_radio_freq = set_radio_freq, + .has_signal = tea5767_signal, + .is_stereo = tea5767_stereo, + .standby = tea5767_standby, +}; + int tea5767_tuner_init(struct i2c_client *c) { struct tuner *t = i2c_get_clientdata(c); @@ -350,11 +358,7 @@ int tea5767_tuner_init(struct i2c_client *c) tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5767HN FM Radio"); strlcpy(c->name, "tea5767", sizeof(c->name)); - t->set_tv_freq = set_tv_freq; - t->set_radio_freq = set_radio_freq; - t->has_signal = tea5767_signal; - t->is_stereo = tea5767_stereo; - t->standby = tea5767_standby; + memcpy(&t->ops, &tea5767_tuner_ops, sizeof(struct tuner_operations)); return (0); } diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 505591a7abe9..e646465464a1 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -20,11 +20,15 @@ #include <media/tuner.h> #include <media/v4l2-common.h> +#include "tuner-driver.h" #define UNSET (-1U) /* standard i2c insmod options */ static unsigned short normal_i2c[] = { +#ifdef CONFIG_TUNER_TEA5761 + 0x10, +#endif 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, @@ -77,7 +81,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) tuner_warn ("tuner type not set\n"); return; } - if (NULL == t->set_tv_freq) { + if (NULL == t->ops.set_tv_freq) { tuner_warn ("Tuner has no way to set tv freq\n"); return; } @@ -92,7 +96,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) else freq = tv_range[1] * 16; } - t->set_tv_freq(c, freq); + t->ops.set_tv_freq(c, freq); } static void set_radio_freq(struct i2c_client *c, unsigned int freq) @@ -103,7 +107,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) tuner_warn ("tuner type not set\n"); return; } - if (NULL == t->set_radio_freq) { + if (NULL == t->ops.set_radio_freq) { tuner_warn ("tuner has no way to set radio frequency\n"); return; } @@ -119,7 +123,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) freq = radio_range[1] * 16000; } - t->set_radio_freq(c, freq); + t->ops.set_radio_freq(c, freq); } static void set_freq(struct i2c_client *c, unsigned long freq) @@ -174,6 +178,14 @@ static void set_type(struct i2c_client *c, unsigned int type, return; } + /* discard private data, in case set_type() was previously called */ + if (t->ops.release) + t->ops.release(c); + else { + kfree(t->priv); + t->priv = NULL; + } + switch (t->type) { case TUNER_MT2032: microtune_init(c); @@ -189,6 +201,16 @@ static void set_type(struct i2c_client *c, unsigned int type, } t->mode_mask = T_RADIO; break; +#ifdef CONFIG_TUNER_TEA5761 + case TUNER_TEA5761: + if (tea5761_tuner_init(c) == EINVAL) { + t->type = TUNER_ABSENT; + t->mode_mask = T_UNINITIALIZED; + return; + } + t->mode_mask = T_RADIO; + break; +#endif case TUNER_PHILIPS_FMD1216ME_MK3: buffer[0] = 0x0b; buffer[1] = 0xdc; @@ -408,11 +430,11 @@ static void tuner_status(struct i2c_client *client) tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std); if (t->mode != V4L2_TUNER_RADIO) return; - if (t->has_signal) { - tuner_info("Signal strength: %d\n", t->has_signal(client)); + if (t->ops.has_signal) { + tuner_info("Signal strength: %d\n", t->ops.has_signal(client)); } - if (t->is_stereo) { - tuner_info("Stereo: %s\n", t->is_stereo(client) ? "yes" : "no"); + if (t->ops.is_stereo) { + tuner_info("Stereo: %s\n", t->ops.is_stereo(client) ? "yes" : "no"); } } @@ -437,10 +459,9 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) memcpy(&t->i2c, &client_template, sizeof(struct i2c_client)); i2c_set_clientdata(&t->i2c, t); t->type = UNSET; - t->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */ t->audmode = V4L2_TUNER_MODE_STEREO; t->mode_mask = T_UNINITIALIZED; - t->tuner_status = tuner_status; + t->ops.tuner_status = tuner_status; if (show_i2c) { unsigned char buffer[16]; @@ -460,6 +481,19 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) /* autodetection code based on the i2c addr */ if (!no_autodetect) { switch (addr) { +#ifdef CONFIG_TUNER_TEA5761 + case 0x10: + if (tea5761_autodetection(&t->i2c) != EINVAL) { + t->type = TUNER_TEA5761; + t->mode_mask = T_RADIO; + t->mode = T_STANDBY; + t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */ + default_mode_mask &= ~T_RADIO; + + goto register_client; + } + break; +#endif case 0x42: case 0x43: case 0x4a: @@ -533,6 +567,11 @@ static int tuner_detach(struct i2c_client *client) return err; } + if (t->ops.release) + t->ops.release(client); + else { + kfree(t->priv); + } kfree(t); return 0; } @@ -553,8 +592,8 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, if (check_mode(t, cmd) == EINVAL) { t->mode = T_STANDBY; - if (t->standby) - t->standby (client); + if (t->ops.standby) + t->ops.standby (client); return EINVAL; } return 0; @@ -602,8 +641,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL) return 0; t->mode = T_STANDBY; - if (t->standby) - t->standby (client); + if (t->ops.standby) + t->ops.standby (client); break; #ifdef CONFIG_VIDEO_V4L1 case VIDIOCSAUDIO: @@ -662,10 +701,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; if (V4L2_TUNER_RADIO == t->mode) { - if (t->has_signal) - vt->signal = t->has_signal(client); - if (t->is_stereo) { - if (t->is_stereo(client)) + if (t->ops.has_signal) + vt->signal = t->ops.has_signal(client); + if (t->ops.is_stereo) { + if (t->ops.is_stereo(client)) vt->flags |= VIDEO_TUNER_STEREO_ON; else @@ -693,8 +732,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) if (check_v4l2(t) == EINVAL) return 0; - if (V4L2_TUNER_RADIO == t->mode && t->is_stereo) - va->mode = t->is_stereo(client) + if (V4L2_TUNER_RADIO == t->mode && t->ops.is_stereo) + va->mode = t->ops.is_stereo(client) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; return 0; } @@ -759,8 +798,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) switch_v4l2(); tuner->type = t->mode; - if (t->get_afc) - tuner->afc=t->get_afc(client); + if (t->ops.get_afc) + tuner->afc=t->ops.get_afc(client); if (t->mode == V4L2_TUNER_ANALOG_TV) tuner->capability |= V4L2_TUNER_CAP_NORM; if (t->mode != V4L2_TUNER_RADIO) { @@ -770,13 +809,13 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) } /* radio mode */ - if (t->has_signal) - tuner->signal = t->has_signal(client); + if (t->ops.has_signal) + tuner->signal = t->ops.has_signal(client); tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - if (t->is_stereo) { - tuner->rxsubchans = t->is_stereo(client) ? + if (t->ops.is_stereo) { + tuner->rxsubchans = t->ops.is_stereo(client) ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; } @@ -804,8 +843,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) break; } case VIDIOC_LOG_STATUS: - if (t->tuner_status) - t->tuner_status(client); + if (t->ops.tuner_status) + t->ops.tuner_status(client); break; } diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h new file mode 100644 index 000000000000..0334a9125077 --- /dev/null +++ b/drivers/media/video/tuner-driver.h @@ -0,0 +1,107 @@ +/* + tuner-driver.h - interface for different tuners + + Copyright (C) 1997 Markus Schroeder (schroedm@uni-duesseldorf.de) + minor modifications by Ralph Metzler (rjkm@thp.uni-koeln.de) + + 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 __TUNER_HW_H__ +#define __TUNER_HW_H__ + +#include <linux/videodev2.h> +#include <linux/i2c.h> + +extern unsigned const int tuner_count; + +struct tuner_operations { + void (*set_tv_freq)(struct i2c_client *c, unsigned int freq); + void (*set_radio_freq)(struct i2c_client *c, unsigned int freq); + int (*has_signal)(struct i2c_client *c); + int (*is_stereo)(struct i2c_client *c); + int (*get_afc)(struct i2c_client *c); + void (*tuner_status)(struct i2c_client *c); + void (*standby)(struct i2c_client *c); + void (*release)(struct i2c_client *c); +}; + +struct tuner { + /* device */ + struct i2c_client i2c; + + unsigned int type; /* chip type */ + + unsigned int mode; + unsigned int mode_mask; /* Combination of allowable modes */ + + unsigned int tv_freq; /* keep track of the current settings */ + unsigned int radio_freq; + u16 last_div; + unsigned int audmode; + v4l2_std_id std; + + int using_v4l2; + void *priv; + + /* used by tda9887 */ + unsigned int tda9887_config; + + unsigned int config; + int (*tuner_callback) (void *dev, int command,int arg); + + struct tuner_operations ops; +}; + +/* ------------------------------------------------------------------------ */ + +extern int default_tuner_init(struct i2c_client *c); + +extern int tda9887_tuner_init(struct i2c_client *c); + +extern int microtune_init(struct i2c_client *c); + +extern int tda8290_init(struct i2c_client *c); +extern int tda8290_probe(struct i2c_client *c); + +extern int tea5761_tuner_init(struct i2c_client *c); +extern int tea5761_autodetection(struct i2c_client *c); + +extern int tea5767_autodetection(struct i2c_client *c); +extern int tea5767_tuner_init(struct i2c_client *c); + +/* ------------------------------------------------------------------------ */ + +#define tuner_warn(fmt, arg...) do {\ + printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ + i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) +#define tuner_info(fmt, arg...) do {\ + printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ + i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) +#define tuner_dbg(fmt, arg...) do {\ + extern int tuner_debug; \ + if (tuner_debug) \ + printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ + i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) + +#endif /* __TUNER_HW_H__ */ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index c40b92ce1fad..2d57e8bc0db3 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -8,6 +8,8 @@ #include <linux/videodev.h> #include <media/tuner.h> #include <media/v4l2-common.h> +#include <media/tuner-types.h> +#include "tuner-driver.h" static int offset = 0; module_param(offset, int, 0664); @@ -54,9 +56,9 @@ MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner"); sound 2 33.16 - - NICAM 33.05 33.05 39.80 */ -#define PHILIPS_MF_SET_BG 0x01 /* Bit 2 must be zero, Bit 3 is system output */ -#define PHILIPS_MF_SET_PAL_L 0x03 // France -#define PHILIPS_MF_SET_PAL_L2 0x02 // L' +#define PHILIPS_MF_SET_STD_BG 0x01 /* Bit 2 must be zero, Bit 3 is system output */ +#define PHILIPS_MF_SET_STD_L 0x03 /* Used on Secam France */ +#define PHILIPS_MF_SET_STD_LC 0x02 /* Used on SECAM L' */ /* Control byte */ @@ -207,11 +209,11 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) /* 0x04 -> ??? PAL others / SECAM others ??? */ cb &= ~0x03; if (t->std & V4L2_STD_SECAM_L) //also valid for V4L2_STD_SECAM - cb |= PHILIPS_MF_SET_PAL_L; + cb |= PHILIPS_MF_SET_STD_L; else if (t->std & V4L2_STD_SECAM_LC) - cb |= PHILIPS_MF_SET_PAL_L2; + cb |= PHILIPS_MF_SET_STD_LC; else /* V4L2_STD_B|V4L2_STD_GH */ - cb |= PHILIPS_MF_SET_BG; + cb |= PHILIPS_MF_SET_STD_BG; break; case TUNER_TEMIC_4046FM5: @@ -479,6 +481,13 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); } +static struct tuner_operations simple_tuner_ops = { + .set_tv_freq = default_set_tv_freq, + .set_radio_freq = default_set_radio_freq, + .has_signal = tuner_signal, + .is_stereo = tuner_stereo, +}; + int default_tuner_init(struct i2c_client *c) { struct tuner *t = i2c_get_clientdata(c); @@ -487,11 +496,7 @@ int default_tuner_init(struct i2c_client *c) t->type, tuners[t->type].name); strlcpy(c->name, tuners[t->type].name, sizeof(c->name)); - t->set_tv_freq = default_set_tv_freq; - t->set_radio_freq = default_set_radio_freq; - t->has_signal = tuner_signal; - t->is_stereo = tuner_stereo; - t->standby = NULL; + memcpy(&t->ops, &simple_tuner_ops, sizeof(struct tuner_operations)); return 0; } diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c index 74c3e6f96f1a..417f642b4359 100644 --- a/drivers/media/video/tuner-types.c +++ b/drivers/media/video/tuner-types.c @@ -594,19 +594,19 @@ static struct tuner_params tuner_philips_pal_mk_params[] = { }, }; -/* ------------ TUNER_PHILIPS_ATSC - Philips ATSC ------------ */ +/* ---- TUNER_PHILIPS_ATSC - Philips FCV1236D (ATSC/NTSC) ---- */ -static struct tuner_range tuner_philips_atsc_ranges[] = { +static struct tuner_range tuner_philips_fcv1236d_ranges[] = { { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, }, - { 16 * 454.00 /*MHz*/, 0x8e, 0x90, }, + { 16 * 451.25 /*MHz*/, 0x8e, 0x90, }, { 16 * 999.99 , 0x8e, 0x30, }, }; -static struct tuner_params tuner_philips_atsc_params[] = { +static struct tuner_params tuner_philips_fcv1236d_params[] = { { .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_philips_atsc_ranges, - .count = ARRAY_SIZE(tuner_philips_atsc_ranges), + .ranges = tuner_philips_fcv1236d_ranges, + .count = ARRAY_SIZE(tuner_philips_fcv1236d_ranges), }, }; @@ -1296,9 +1296,9 @@ struct tunertype tuners[] = { .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), + .name = "Philips FCV1236D ATSC/NTSC dual in", + .params = tuner_philips_fcv1236d_params, + .count = ARRAY_SIZE(tuner_philips_fcv1236d_params), }, [TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */ .name = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", @@ -1463,6 +1463,10 @@ struct tunertype tuners[] = { .name = "Philips TDA988[5,6,7] IF PLL Demodulator", /* see tda9887.c for details */ }, + [TUNER_TEA5761] = { /* Philips RADIO */ + .name = "Philips TEA5761 FM Radio", + /* see tea5767.c for details */ + }, }; unsigned const int tuner_count = ARRAY_SIZE(tuners); diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index a1136da74ba8..fdc3def437b1 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -183,7 +183,7 @@ hauppauge_tuner[] = { TUNER_ABSENT, "Silicon TDA8275C1 8290 FM"}, { TUNER_ABSENT, "Thompson DTT757"}, /* 80-89 */ - { TUNER_ABSENT, "Philips FQ1216LME MK3"}, + { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216LME MK3"}, { TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"}, { TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"}, { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"}, @@ -490,7 +490,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, to indicate 4052 mux was removed in favor of using MSP inputs directly. */ audioic = eeprom_data[i+2] & 0x7f; - if (audioic < sizeof(audioIC)/sizeof(*audioIC)) + if (audioic < ARRAY_SIZE(audioIC)) tvee->audio_processor = audioIC[audioic].id; else tvee->audio_processor = AUDIO_CHIP_UNKNOWN; @@ -523,7 +523,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, to indicate 4052 mux was removed in favor of using MSP inputs directly. */ audioic = eeprom_data[i+1] & 0x7f; - if (audioic < sizeof(audioIC)/sizeof(*audioIC)) + if (audioic < ARRAY_SIZE(audioIC)) tvee->audio_processor = audioIC[audioic].id; else tvee->audio_processor = AUDIO_CHIP_UNKNOWN; @@ -678,7 +678,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, tveeprom_info("audio processor is unknown (no idx)\n"); tvee->audio_processor=AUDIO_CHIP_UNKNOWN; } else { - if (audioic < sizeof(audioIC)/sizeof(*audioIC)) + if (audioic < ARRAY_SIZE(audioIC)) tveeprom_info("audio processor is %s (idx %d)\n", audioIC[audioic].name,audioic); else diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c index d5ec05f56adf..e2f1c972754b 100644 --- a/drivers/media/video/tvp5150.c +++ b/drivers/media/video/tvp5150.c @@ -1006,7 +1006,7 @@ static int tvp5150_command(struct i2c_client *c, { struct v4l2_control *ctrl = arg; u8 i, n; - n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]); + n = ARRAY_SIZE(tvp5150_qctrl); for (i = 0; i < n; i++) if (ctrl->id == tvp5150_qctrl[i].id) { if (ctrl->value < diff --git a/drivers/media/video/usbvideo/konicawc.c b/drivers/media/video/usbvideo/konicawc.c index abe214619092..491505d6fdee 100644 --- a/drivers/media/video/usbvideo/konicawc.c +++ b/drivers/media/video/usbvideo/konicawc.c @@ -236,7 +236,7 @@ static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev input_dev->name = "Konicawc snapshot button"; input_dev->phys = cam->input_physname; usb_to_input_id(dev, &input_dev->id); - input_dev->cdev.dev = &dev->dev; + input_dev->dev.parent = &dev->dev; input_dev->evbit[0] = BIT(EV_KEY); input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0); diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c index ec0ff2247f06..dd1a6d6bbc9e 100644 --- a/drivers/media/video/usbvideo/quickcam_messenger.c +++ b/drivers/media/video/usbvideo/quickcam_messenger.c @@ -100,7 +100,7 @@ static void qcm_register_input(struct qcm *cam, struct usb_device *dev) input_dev->name = "QCM button"; input_dev->phys = cam->input_physname; usb_to_input_id(dev, &input_dev->id); - input_dev->cdev.dev = &dev->dev; + input_dev->dev.parent = &dev->dev; input_dev->evbit[0] = BIT(EV_KEY); input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0); @@ -439,7 +439,7 @@ static int qcm_sensor_init(struct uvd *uvd) int ret; int i; - for (i=0; i < sizeof(regval_table)/sizeof(regval_table[0]) ; i++) { + for (i=0; i < ARRAY_SIZE(regval_table) ; i++) { CHECK_RET(ret, qcm_stv_setb(uvd->dev, regval_table[i].reg, regval_table[i].val)); diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c index 982b115193f8..2d9c0dd3b733 100644 --- a/drivers/media/video/usbvideo/vicam.c +++ b/drivers/media/video/usbvideo/vicam.c @@ -42,7 +42,6 @@ #include <linux/usb.h> #include <linux/vmalloc.h> #include <linux/slab.h> -#include <linux/proc_fs.h> #include <linux/mutex.h> #include "usbvideo.h" @@ -417,11 +416,6 @@ struct vicam_camera { u8 open_count; u8 bulkEndpoint; int needsDummyRead; - -#if defined(CONFIG_VIDEO_PROC_FS) - struct proc_dir_entry *proc_dir; -#endif - }; static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id); @@ -1065,175 +1059,6 @@ vicam_mmap(struct file *file, struct vm_area_struct *vma) return 0; } -#if defined(CONFIG_VIDEO_PROC_FS) - -static struct proc_dir_entry *vicam_proc_root = NULL; - -static int vicam_read_helper(char *page, char **start, off_t off, - int count, int *eof, int value) -{ - char *out = page; - int len; - - out += sprintf(out, "%d",value); - - len = out - page; - len -= off; - if (len < count) { - *eof = 1; - if (len <= 0) - return 0; - } else - len = count; - - *start = page + off; - return len; -} - -static int vicam_read_proc_shutter(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - return vicam_read_helper(page,start,off,count,eof, - ((struct vicam_camera *)data)->shutter_speed); -} - -static int vicam_read_proc_gain(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - return vicam_read_helper(page,start,off,count,eof, - ((struct vicam_camera *)data)->gain); -} - -static int -vicam_write_proc_shutter(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - u16 stmp; - char kbuf[8]; - struct vicam_camera *cam = (struct vicam_camera *) data; - - if (count > 6) - return -EINVAL; - - if (copy_from_user(kbuf, buffer, count)) - return -EFAULT; - - stmp = (u16) simple_strtoul(kbuf, NULL, 10); - if (stmp < 4 || stmp > 32000) - return -EINVAL; - - cam->shutter_speed = stmp; - - return count; -} - -static int -vicam_write_proc_gain(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - u16 gtmp; - char kbuf[8]; - - struct vicam_camera *cam = (struct vicam_camera *) data; - - if (count > 4) - return -EINVAL; - - if (copy_from_user(kbuf, buffer, count)) - return -EFAULT; - - gtmp = (u16) simple_strtoul(kbuf, NULL, 10); - if (gtmp > 255) - return -EINVAL; - cam->gain = gtmp; - - return count; -} - -static void -vicam_create_proc_root(void) -{ - vicam_proc_root = proc_mkdir("video/vicam", NULL); - - if (vicam_proc_root) - vicam_proc_root->owner = THIS_MODULE; - else - printk(KERN_ERR - "could not create /proc entry for vicam!"); -} - -static void -vicam_destroy_proc_root(void) -{ - if (vicam_proc_root) - remove_proc_entry("video/vicam", 0); -} - -static void -vicam_create_proc_entry(struct vicam_camera *cam) -{ - char name[64]; - struct proc_dir_entry *ent; - - DBG(KERN_INFO "vicam: creating proc entry\n"); - - if (!vicam_proc_root || !cam) { - printk(KERN_INFO - "vicam: could not create proc entry, %s pointer is null.\n", - (!cam ? "camera" : "root")); - return; - } - - sprintf(name, "video%d", cam->vdev.minor); - - cam->proc_dir = proc_mkdir(name, vicam_proc_root); - - if ( !cam->proc_dir ) - return; // FIXME: We should probably return an error here - - ent = create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR, - cam->proc_dir); - if (ent) { - ent->data = cam; - ent->read_proc = vicam_read_proc_shutter; - ent->write_proc = vicam_write_proc_shutter; - ent->size = 64; - } - - ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR, - cam->proc_dir); - if (ent) { - ent->data = cam; - ent->read_proc = vicam_read_proc_gain; - ent->write_proc = vicam_write_proc_gain; - ent->size = 64; - } -} - -static void -vicam_destroy_proc_entry(void *ptr) -{ - struct vicam_camera *cam = (struct vicam_camera *) ptr; - char name[16]; - - if ( !cam->proc_dir ) - return; - - sprintf(name, "video%d", cam->vdev.minor); - remove_proc_entry("shutter", cam->proc_dir); - remove_proc_entry("gain", cam->proc_dir); - remove_proc_entry(name,vicam_proc_root); - cam->proc_dir = NULL; - -} - -#else -static inline void vicam_create_proc_root(void) { } -static inline void vicam_destroy_proc_root(void) { } -static inline void vicam_create_proc_entry(struct vicam_camera *cam) { } -static inline void vicam_destroy_proc_entry(void *ptr) { } -#endif - static const struct file_operations vicam_fops = { .owner = THIS_MODULE, .open = vicam_open, @@ -1330,8 +1155,6 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id) return -EIO; } - vicam_create_proc_entry(cam); - printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor); usb_set_intfdata (intf, cam); @@ -1363,8 +1186,6 @@ vicam_disconnect(struct usb_interface *intf) cam->udev = NULL; - vicam_destroy_proc_entry(cam); - /* the only thing left to do is synchronize with * our close/release function on who should release * the camera memory. if there are any users using the @@ -1390,7 +1211,6 @@ usb_vicam_init(void) { int retval; DBG(KERN_INFO "ViCam-based WebCam driver startup\n"); - vicam_create_proc_root(); retval = usb_register(&vicam_driver); if (retval) printk(KERN_WARNING "usb_register failed!\n"); @@ -1404,7 +1224,6 @@ usb_vicam_exit(void) "ViCam-based WebCam driver shutdown\n"); usb_deregister(&vicam_driver); - vicam_destroy_proc_root(); } module_init(usb_vicam_init); diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c index 51ab265d566a..380564cd3317 100644 --- a/drivers/media/video/usbvision/usbvision-cards.c +++ b/drivers/media/video/usbvision/usbvision-cards.c @@ -79,7 +79,7 @@ struct usbvision_device_data_st usbvision_device_data[] = { .Interface = -1, .Codec = CODEC_SAA7113, .VideoChannels = 2, - .VideoNorm = V4L2_STD_PAL, + .VideoNorm = V4L2_STD_NTSC, .AudioChannels = 1, .Radio = 0, .vbi = 1, @@ -311,8 +311,8 @@ struct usbvision_device_data_st usbvision_device_data[] = { .vbi = 1, .Tuner = 1, .TunerType = TUNER_PHILIPS_SECAM, - .X_Offset = -1, - .Y_Offset = -1, + .X_Offset = 0x80, + .Y_Offset = 0x16, .ModelString = "Hauppauge WinTV USB (PAL/SECAM L)", }, [HPG_WINTV_PAL_D_K] = { @@ -586,7 +586,7 @@ struct usbvision_device_data_st usbvision_device_data[] = { .Radio = 0, .vbi = 1, .Tuner = 1, - .TunerType = TUNER_PHILIPS_PAL, + .TunerType = TUNER_LG_PAL_NEW_TAPC, .X_Offset = 0, .Y_Offset = 3, .Dvi_yuv_override = 1, diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index 7df071eb0a3b..5b1e346df206 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -1742,7 +1742,7 @@ static int usbvision_set_video_format(struct usb_usbvision *usbvision, int forma format = ISOC_MODE_YUV420; } value[0] = 0x0A; //TODO: See the effect of the filter - value[1] = format; + value[1] = format; // Sets the VO_MODE register which follows FILT_CONT rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1), USBVISION_OP_CODE, USB_DIR_OUT | USB_TYPE_VENDOR | @@ -1831,10 +1831,10 @@ int usbvision_set_output(struct usb_usbvision *usbvision, int width, frameRate = FRAMERATE_MAX; } - if (usbvision->tvnorm->id & V4L2_STD_625_50) { + if (usbvision->tvnormId & V4L2_STD_625_50) { frameDrop = frameRate * 32 / 25 - 1; } - else if (usbvision->tvnorm->id & V4L2_STD_525_60) { + else if (usbvision->tvnormId & V4L2_STD_525_60) { frameDrop = frameRate * 32 / 30 - 1; } @@ -2067,7 +2067,7 @@ int usbvision_set_input(struct usb_usbvision *usbvision) } - if (usbvision->tvnorm->id & V4L2_STD_PAL) { + if (usbvision->tvnormId & V4L2_STD_PAL) { value[0] = 0xC0; value[1] = 0x02; //0x02C0 -> 704 Input video line length value[2] = 0x20; @@ -2076,7 +2076,7 @@ int usbvision_set_input(struct usb_usbvision *usbvision) value[5] = 0x00; //0x0060 -> 96 Input video h offset value[6] = 0x16; value[7] = 0x00; //0x0016 -> 22 Input video v offset - } else if (usbvision->tvnorm->id & V4L2_STD_SECAM) { + } else if (usbvision->tvnormId & V4L2_STD_SECAM) { value[0] = 0xC0; value[1] = 0x02; //0x02C0 -> 704 Input video line length value[2] = 0x20; @@ -2537,7 +2537,9 @@ void usbvision_stop_isoc(struct usb_usbvision *usbvision) int usbvision_muxsel(struct usb_usbvision *usbvision, int channel) { - int mode[4]; + /* inputs #0 and #3 are constant for every SAA711x. */ + /* inputs #1 and #2 are variable for SAA7111 and SAA7113 */ + int mode[4]= {SAA7115_COMPOSITE0, 0, 0, SAA7115_COMPOSITE3}; int audio[]= {1, 0, 0, 0}; struct v4l2_routing route; //channel 0 is TV with audiochannel 1 (tuner mono) @@ -2547,10 +2549,6 @@ int usbvision_muxsel(struct usb_usbvision *usbvision, int channel) RESTRICT_TO_RANGE(channel, 0, usbvision->video_inputs); usbvision->ctl_input = channel; - route.input = SAA7115_COMPOSITE1; - route.output = 0; - call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route); - call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->ctl_input); // set the new channel // Regular USB TV Tuners -> channel: 0 = Television, 1 = Composite, 2 = S-Video @@ -2558,28 +2556,27 @@ int usbvision_muxsel(struct usb_usbvision *usbvision, int channel) switch (usbvision_device_data[usbvision->DevModel].Codec) { case CODEC_SAA7113: - if (SwitchSVideoInput) { // To handle problems with S-Video Input for some devices. Use SwitchSVideoInput parameter when loading the module. - mode[2] = 1; + mode[1] = SAA7115_COMPOSITE2; + if (SwitchSVideoInput) { + /* To handle problems with S-Video Input for + * some devices. Use SwitchSVideoInput + * parameter when loading the module.*/ + mode[2] = SAA7115_COMPOSITE1; } else { - mode[2] = 7; - } - if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) { - mode[0] = 0; mode[1] = 2; mode[3] = 3; // Special for four input devices - } - else { - mode[0] = 0; mode[1] = 2; //modes for regular saa7113 devices + mode[2] = SAA7115_SVIDEO1; } break; case CODEC_SAA7111: - mode[0] = 0; mode[1] = 1; mode[2] = 7; //modes for saa7111 - break; default: - mode[0] = 0; mode[1] = 1; mode[2] = 7; //default modes + /* modes for saa7111 */ + mode[1] = SAA7115_COMPOSITE1; + mode[2] = SAA7115_SVIDEO1; + break; } route.input = mode[channel]; + route.output = 0; call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route); - usbvision->channel = channel; usbvision_set_audio(usbvision, audio[channel]); return 0; } diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index aa3258bbb4af..868b6886fe7f 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -36,7 +36,8 @@ * - use submit_urb for all setup packets * - Fix memory settings for nt1004. It is 4 times as big as the * nt1003 memory. - * - Add audio on endpoint 3 for nt1004 chip. Seems impossible, needs a codec interface. Which one? + * - Add audio on endpoint 3 for nt1004 chip. + * Seems impossible, needs a codec interface. Which one? * - Clean up the driver. * - optimization for performance. * - Add Videotext capability (VBI). Working on it..... @@ -77,7 +78,8 @@ #include "usbvision.h" #include "usbvision-cards.h" -#define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>, Dwaine Garden <DwaineGarden@rogers.com>" +#define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>,\ + Dwaine Garden <DwaineGarden@rogers.com>" #define DRIVER_NAME "usbvision" #define DRIVER_ALIAS "USBVision" #define DRIVER_DESC "USBVision USB Video Device Driver for Linux" @@ -85,20 +87,25 @@ #define USBVISION_DRIVER_VERSION_MAJOR 0 #define USBVISION_DRIVER_VERSION_MINOR 9 #define USBVISION_DRIVER_VERSION_PATCHLEVEL 9 -#define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,USBVISION_DRIVER_VERSION_MINOR,USBVISION_DRIVER_VERSION_PATCHLEVEL) -#define USBVISION_VERSION_STRING __stringify(USBVISION_DRIVER_VERSION_MAJOR) "." __stringify(USBVISION_DRIVER_VERSION_MINOR) "." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL) +#define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,\ +USBVISION_DRIVER_VERSION_MINOR,\ +USBVISION_DRIVER_VERSION_PATCHLEVEL) +#define USBVISION_VERSION_STRING __stringify(USBVISION_DRIVER_VERSION_MAJOR)\ + "." __stringify(USBVISION_DRIVER_VERSION_MINOR)\ + "." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL) #define ENABLE_HEXDUMP 0 /* Enable if you need it */ #ifdef USBVISION_DEBUG #define PDEBUG(level, fmt, args...) \ - if (video_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args) + if (video_debug & (level)) \ + info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ ,\ + ## args) #else #define PDEBUG(level, fmt, args...) do {} while(0) #endif -#define DBG_IOCTL 1<<0 #define DBG_IO 1<<1 #define DBG_PROBE 1<<2 #define DBG_MMAP 1<<3 @@ -108,7 +115,8 @@ #define goto2next(str) while(*str!=' ') str++; while(*str==' ') str++; -static int usbvision_nr = 0; // sequential number of usbvision device +/* sequential number of usbvision device */ +static int usbvision_nr = 0; static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = { { 1, 1, 8, V4L2_PIX_FMT_GREY , "GREY" }, @@ -121,55 +129,32 @@ static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = { { 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" } }; -/* supported tv norms */ -static struct usbvision_tvnorm tvnorms[] = { - { - .name = "PAL", - .id = V4L2_STD_PAL, - }, { - .name = "NTSC", - .id = V4L2_STD_NTSC, - }, { - .name = "SECAM", - .id = V4L2_STD_SECAM, - }, { - .name = "PAL-M", - .id = V4L2_STD_PAL_M, - } -}; - -#define TVNORMS ARRAY_SIZE(tvnorms) - -// Function prototypes +/* Function prototypes */ static void usbvision_release(struct usb_usbvision *usbvision); -// Default initalization of device driver parameters -static int isocMode = ISOC_MODE_COMPRESS; // Set the default format for ISOC endpoint -static int video_debug = 0; // Set the default Debug Mode of the device driver -static int PowerOnAtOpen = 1; // Set the default device to power on at startup -static int video_nr = -1; // Sequential Number of Video Device -static int radio_nr = -1; // Sequential Number of Radio Device -static int vbi_nr = -1; // Sequential Number of VBI Device - -// Grab parameters for the device driver - -#if defined(module_param) // Showing parameters under SYSFS +/* Default initalization of device driver parameters */ +/* Set the default format for ISOC endpoint */ +static int isocMode = ISOC_MODE_COMPRESS; +/* Set the default Debug Mode of the device driver */ +static int video_debug = 0; +/* Set the default device to power on at startup */ +static int PowerOnAtOpen = 1; +/* Sequential Number of Video Device */ +static int video_nr = -1; +/* Sequential Number of Radio Device */ +static int radio_nr = -1; +/* Sequential Number of VBI Device */ +static int vbi_nr = -1; + +/* Grab parameters for the device driver */ + +/* Showing parameters under SYSFS */ module_param(isocMode, int, 0444); module_param(video_debug, int, 0444); module_param(PowerOnAtOpen, int, 0444); module_param(video_nr, int, 0444); module_param(radio_nr, int, 0444); module_param(vbi_nr, int, 0444); -#else // Old Style -MODULE_PARAM(isocMode, "i"); -MODULE_PARM(video_debug, "i"); // Grab the Debug Mode of the device driver -MODULE_PARM(adjustCompression, "i"); // Grab the compression to be adaptive -MODULE_PARM(PowerOnAtOpen, "i"); // Grab the device to power on at startup -MODULE_PARM(SwitchSVideoInput, "i"); // To help people with Black and White output with using s-video input. Some cables and input device are wired differently. -MODULE_PARM(video_nr, "i"); // video_nr option allows to specify a certain /dev/videoX device (like /dev/video0 or /dev/video1 ...) -MODULE_PARM(radio_nr, "i"); // radio_nr option allows to specify a certain /dev/radioX device (like /dev/radio0 or /dev/radio1 ...) -MODULE_PARM(vbi_nr, "i"); // vbi_nr option allows to specify a certain /dev/vbiX device (like /dev/vbi0 or /dev/vbi1 ...) -#endif MODULE_PARM_DESC(isocMode, " Set the default format for ISOC endpoint. Default: 0x60 (Compression On)"); MODULE_PARM_DESC(video_debug, " Set the default Debug Mode of the device driver. Default: 0 (Off)"); @@ -187,19 +172,21 @@ MODULE_VERSION(USBVISION_VERSION_STRING); MODULE_ALIAS(DRIVER_ALIAS); -/****************************************************************************************/ -/* SYSFS Code - Copied from the stv680.c usb module. */ -/* Device information is located at /sys/class/video4linux/video0 */ -/* Device parameters information is located at /sys/module/usbvision */ -/* Device USB Information is located at /sys/bus/usb/drivers/USBVision Video Grabber */ -/****************************************************************************************/ +/*****************************************************************************/ +/* SYSFS Code - Copied from the stv680.c usb module. */ +/* Device information is located at /sys/class/video4linux/video0 */ +/* Device parameters information is located at /sys/module/usbvision */ +/* Device USB Information is located at */ +/* /sys/bus/usb/drivers/USBVision Video Grabber */ +/*****************************************************************************/ #define YES_NO(x) ((x) ? "Yes" : "No") static inline struct usb_usbvision *cd_to_usbvision(struct class_device *cd) { - struct video_device *vdev = container_of(cd, struct video_device, class_dev); + struct video_device *vdev = + container_of(cd, struct video_device, class_dev); return video_get_drvdata(vdev); } @@ -211,15 +198,18 @@ static CLASS_DEVICE_ATTR(version, S_IRUGO, show_version, NULL); static ssize_t show_model(struct class_device *cd, char *buf) { - struct video_device *vdev = container_of(cd, struct video_device, class_dev); + struct video_device *vdev = + container_of(cd, struct video_device, class_dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); - return sprintf(buf, "%s\n", usbvision_device_data[usbvision->DevModel].ModelString); + return sprintf(buf, "%s\n", + usbvision_device_data[usbvision->DevModel].ModelString); } static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL); static ssize_t show_hue(struct class_device *cd, char *buf) { - struct video_device *vdev = container_of(cd, struct video_device, class_dev); + struct video_device *vdev = + container_of(cd, struct video_device, class_dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); struct v4l2_control ctrl; ctrl.id = V4L2_CID_HUE; @@ -232,7 +222,8 @@ static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); static ssize_t show_contrast(struct class_device *cd, char *buf) { - struct video_device *vdev = container_of(cd, struct video_device, class_dev); + struct video_device *vdev = + container_of(cd, struct video_device, class_dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); struct v4l2_control ctrl; ctrl.id = V4L2_CID_CONTRAST; @@ -245,7 +236,8 @@ static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); static ssize_t show_brightness(struct class_device *cd, char *buf) { - struct video_device *vdev = container_of(cd, struct video_device, class_dev); + struct video_device *vdev = + container_of(cd, struct video_device, class_dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); struct v4l2_control ctrl; ctrl.id = V4L2_CID_BRIGHTNESS; @@ -258,7 +250,8 @@ static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); static ssize_t show_saturation(struct class_device *cd, char *buf) { - struct video_device *vdev = container_of(cd, struct video_device, class_dev); + struct video_device *vdev = + container_of(cd, struct video_device, class_dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); struct v4l2_control ctrl; ctrl.id = V4L2_CID_SATURATION; @@ -271,23 +264,28 @@ static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); static ssize_t show_streaming(struct class_device *cd, char *buf) { - struct video_device *vdev = container_of(cd, struct video_device, class_dev); + struct video_device *vdev = + container_of(cd, struct video_device, class_dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); - return sprintf(buf, "%s\n", YES_NO(usbvision->streaming==Stream_On?1:0)); + return sprintf(buf, "%s\n", + YES_NO(usbvision->streaming==Stream_On?1:0)); } static CLASS_DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL); static ssize_t show_compression(struct class_device *cd, char *buf) { - struct video_device *vdev = container_of(cd, struct video_device, class_dev); + struct video_device *vdev = + container_of(cd, struct video_device, class_dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); - return sprintf(buf, "%s\n", YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS)); + return sprintf(buf, "%s\n", + YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS)); } static CLASS_DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL); static ssize_t show_device_bridge(struct class_device *cd, char *buf) { - struct video_device *vdev = container_of(cd, struct video_device, class_dev); + struct video_device *vdev = + container_of(cd, struct video_device, class_dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%d\n", usbvision->bridgeType); } @@ -376,7 +374,8 @@ static void usbvision_remove_sysfs(struct video_device *vdev) static int usbvision_v4l2_open(struct inode *inode, struct file *file) { struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); int errCode = 0; PDEBUG(DBG_IO, "open"); @@ -390,7 +389,8 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) /* Allocate memory for the scratch ring buffer */ errCode = usbvision_scratch_alloc(usbvision); if (isocMode==ISOC_MODE_COMPRESS) { - /* Allocate intermediate decompression buffers only if needed */ + /* Allocate intermediate decompression buffers + only if needed */ errCode = usbvision_decompress_alloc(usbvision); } if (errCode) { @@ -421,11 +421,10 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) if (!errCode) { usbvision_begin_streaming(usbvision); errCode = usbvision_init_isoc(usbvision); - /* device needs to be initialized before isoc transfer */ + /* device must be initialized before isoc transfer */ usbvision_muxsel(usbvision,0); usbvision->user++; - } - else { + } else { if (PowerOnAtOpen) { usbvision_i2c_unregister(usbvision); usbvision_power_off(usbvision); @@ -456,7 +455,8 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) static int usbvision_v4l2_close(struct inode *inode, struct file *file) { struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); PDEBUG(DBG_IO, "close"); down(&usbvision->lock); @@ -473,7 +473,8 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file) usbvision->user--; if (PowerOnAtOpen) { - /* power off in a little while to avoid off/on every close/open short sequences */ + /* power off in a little while + to avoid off/on every close/open short sequences */ usbvision_set_powerOffTimer(usbvision); usbvision->initialized = 0; } @@ -498,583 +499,612 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file) * This is part of Video 4 Linux API. The procedure handles ioctl() calls. * */ -static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int vidioc_g_register (struct file *file, void *priv, + struct v4l2_register *reg) { struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); - - if (!USBVISION_IS_OPERATIONAL(usbvision)) - return -EFAULT; + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); + int errCode; - switch (cmd) { + if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return -EINVAL; + /* NT100x has a 8-bit register space */ + errCode = usbvision_read_reg(usbvision, reg->reg&0xff); + if (errCode < 0) { + err("%s: VIDIOC_DBG_G_REGISTER failed: error %d", + __FUNCTION__, errCode); + return errCode; + } + return 0; +} -#ifdef CONFIG_VIDEO_ADV_DEBUG - /* ioctls to allow direct acces to the NT100x registers */ - case VIDIOC_DBG_G_REGISTER: - case VIDIOC_DBG_S_REGISTER: - { - struct v4l2_register *reg = arg; - int errCode; - - if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - /* NT100x has a 8-bit register space */ - if (cmd == VIDIOC_DBG_G_REGISTER) - errCode = usbvision_read_reg(usbvision, reg->reg&0xff); - else - errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val); - if (errCode < 0) { - err("%s: VIDIOC_DBG_%c_REGISTER failed: error %d", __FUNCTION__, - cmd == VIDIOC_DBG_G_REGISTER ? 'G' : 'S', errCode); - return errCode; - } - if (cmd == VIDIOC_DBG_S_REGISTER) - reg->val = (u8)errCode; +static int vidioc_s_register (struct file *file, void *priv, + struct v4l2_register *reg) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); + int errCode; - PDEBUG(DBG_IOCTL, "VIDIOC_DBG_%c_REGISTER reg=0x%02X, value=0x%02X", - cmd == VIDIOC_DBG_G_REGISTER ? 'G' : 'S', - (unsigned int)reg->reg, (unsigned int)reg->val); - return 0; - } + if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return -EINVAL; + /* NT100x has a 8-bit register space */ + reg->val = (u8)usbvision_write_reg(usbvision, reg->reg&0xff, reg->val); + if (reg->val < 0) { + err("%s: VIDIOC_DBG_S_REGISTER failed: error %d", + __FUNCTION__, errCode); + return errCode; + } + return 0; +} #endif - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *vc=arg; - - memset(vc, 0, sizeof(*vc)); - strlcpy(vc->driver, "USBVision", sizeof(vc->driver)); - strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString, - sizeof(vc->card)); - strlcpy(vc->bus_info, usbvision->dev->dev.bus_id, - sizeof(vc->bus_info)); - vc->version = USBVISION_DRIVER_VERSION; - vc->capabilities = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_AUDIO | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - (usbvision->have_tuner ? V4L2_CAP_TUNER : 0); - PDEBUG(DBG_IOCTL, "VIDIOC_QUERYCAP"); - return 0; - } - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *vi = arg; - int chan; - - if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) ) - return -EINVAL; - if (usbvision->have_tuner) { - chan = vi->index; - } - else { - chan = vi->index + 1; //skip Television string - } - switch(chan) { - case 0: - if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) { - strcpy(vi->name, "White Video Input"); - } - else { - strcpy(vi->name, "Television"); - vi->type = V4L2_INPUT_TYPE_TUNER; - vi->audioset = 1; - vi->tuner = chan; - vi->std = V4L2_STD_PAL | V4L2_STD_NTSC | V4L2_STD_SECAM; - } - break; - case 1: - vi->type = V4L2_INPUT_TYPE_CAMERA; - if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) { - strcpy(vi->name, "Green Video Input"); - } - else { - strcpy(vi->name, "Composite Video Input"); - } - vi->std = V4L2_STD_PAL; - break; - case 2: - vi->type = V4L2_INPUT_TYPE_CAMERA; - if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) { - strcpy(vi->name, "Yellow Video Input"); - } - else { - strcpy(vi->name, "S-Video Input"); - } - vi->std = V4L2_STD_PAL; - break; - case 3: - vi->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(vi->name, "Red Video Input"); - vi->std = V4L2_STD_PAL; - break; - } - PDEBUG(DBG_IOCTL, "VIDIOC_ENUMINPUT name=%s:%d tuners=%d type=%d norm=%x", - vi->name, vi->index, vi->tuner,vi->type,(int)vi->std); - return 0; - } - case VIDIOC_ENUMSTD: - { - struct v4l2_standard *e = arg; - unsigned int i; - int ret; - - 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; + +static int vidioc_querycap (struct file *file, void *priv, + struct v4l2_capability *vc) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); + + strlcpy(vc->driver, "USBVision", sizeof(vc->driver)); + strlcpy(vc->card, + usbvision_device_data[usbvision->DevModel].ModelString, + sizeof(vc->card)); + strlcpy(vc->bus_info, usbvision->dev->dev.bus_id, + sizeof(vc->bus_info)); + vc->version = USBVISION_DRIVER_VERSION; + vc->capabilities = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_AUDIO | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | + (usbvision->have_tuner ? V4L2_CAP_TUNER : 0); + return 0; +} + +static int vidioc_enum_input (struct file *file, void *priv, + struct v4l2_input *vi) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); + int chan; + + if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) ) + return -EINVAL; + if (usbvision->have_tuner) { + chan = vi->index; + } else { + chan = vi->index + 1; /*skip Television string*/ + } + /* Determine the requested input characteristics + specific for each usbvision card model */ + switch(chan) { + case 0: + if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) { + strcpy(vi->name, "White Video Input"); + } else { + strcpy(vi->name, "Television"); + vi->type = V4L2_INPUT_TYPE_TUNER; + vi->audioset = 1; + vi->tuner = chan; + vi->std = USBVISION_NORMS; } - case VIDIOC_G_INPUT: - { - int *input = arg; - *input = usbvision->ctl_input; - return 0; + break; + case 1: + vi->type = V4L2_INPUT_TYPE_CAMERA; + if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) { + strcpy(vi->name, "Green Video Input"); + } else { + strcpy(vi->name, "Composite Video Input"); } - case VIDIOC_S_INPUT: - { - int *input = arg; - if ((*input >= usbvision->video_inputs) || (*input < 0) ) - return -EINVAL; - usbvision->ctl_input = *input; - - down(&usbvision->lock); - usbvision_muxsel(usbvision, usbvision->ctl_input); - usbvision_set_input(usbvision); - usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight); - up(&usbvision->lock); - return 0; + vi->std = V4L2_STD_PAL; + break; + case 2: + vi->type = V4L2_INPUT_TYPE_CAMERA; + if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) { + strcpy(vi->name, "Yellow Video Input"); + } else { + strcpy(vi->name, "S-Video Input"); } - case VIDIOC_G_STD: - { - v4l2_std_id *id = arg; + vi->std = V4L2_STD_PAL; + break; + case 3: + vi->type = V4L2_INPUT_TYPE_CAMERA; + strcpy(vi->name, "Red Video Input"); + vi->std = V4L2_STD_PAL; + break; + } + return 0; +} - *id = usbvision->tvnorm->id; +static int vidioc_g_input (struct file *file, void *priv, unsigned int *input) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); - PDEBUG(DBG_IOCTL, "VIDIOC_G_STD std_id=%s", usbvision->tvnorm->name); - return 0; - } - case VIDIOC_S_STD: - { - 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) - break; - if (i == TVNORMS) - return -EINVAL; - - down(&usbvision->lock); - usbvision->tvnorm = &tvnorms[i]; - - call_i2c_clients(usbvision, VIDIOC_S_STD, - &usbvision->tvnorm->id); + *input = usbvision->ctl_input; + return 0; +} - up(&usbvision->lock); +static int vidioc_s_input (struct file *file, void *priv, unsigned int input) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); - PDEBUG(DBG_IOCTL, "VIDIOC_S_STD std_id=%s", usbvision->tvnorm->name); - return 0; - } - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *vt = arg; - - if (!usbvision->have_tuner || vt->index) // Only tuner 0 - return -EINVAL; - strcpy(vt->name, "Television"); - /* Let clients fill in the remainder of this struct */ - call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt); - - PDEBUG(DBG_IOCTL, "VIDIOC_G_TUNER signal=%x, afc=%x",vt->signal,vt->afc); - return 0; - } - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *vt = arg; - - // Only no or one tuner for now - if (!usbvision->have_tuner || vt->index) - return -EINVAL; - /* let clients handle this */ - call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt); - - PDEBUG(DBG_IOCTL, "VIDIOC_S_TUNER"); - return 0; - } - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *freq = arg; - - freq->tuner = 0; // Only one tuner - freq->type = V4L2_TUNER_ANALOG_TV; - freq->frequency = usbvision->freq; - PDEBUG(DBG_IOCTL, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)freq->frequency); - return 0; - } - case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *freq = arg; - - // Only no or one tuner for now - if (!usbvision->have_tuner || freq->tuner) - return -EINVAL; - - usbvision->freq = freq->frequency; - call_i2c_clients(usbvision, cmd, freq); - PDEBUG(DBG_IOCTL, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)freq->frequency); - return 0; - } - case VIDIOC_G_AUDIO: - { - struct v4l2_audio *v = arg; - memset(v,0, sizeof(v)); - strcpy(v->name, "TV"); - PDEBUG(DBG_IOCTL, "VIDIOC_G_AUDIO"); - return 0; - } - case VIDIOC_S_AUDIO: - { - struct v4l2_audio *v = arg; - if(v->index) { - return -EINVAL; - } - PDEBUG(DBG_IOCTL, "VIDIOC_S_AUDIO"); - return 0; - } - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *ctrl = arg; - int id=ctrl->id; + if ((input >= usbvision->video_inputs) || (input < 0) ) + return -EINVAL; - memset(ctrl,0,sizeof(*ctrl)); - ctrl->id=id; + down(&usbvision->lock); + usbvision_muxsel(usbvision, input); + usbvision_set_input(usbvision); + usbvision_set_output(usbvision, + usbvision->curwidth, + usbvision->curheight); + up(&usbvision->lock); + return 0; +} - call_i2c_clients(usbvision, cmd, arg); +static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); + usbvision->tvnormId=*id; - if (ctrl->type) - return 0; - else - return -EINVAL; + down(&usbvision->lock); + call_i2c_clients(usbvision, VIDIOC_S_STD, + &usbvision->tvnormId); + up(&usbvision->lock); + /* propagate the change to the decoder */ + usbvision_muxsel(usbvision, usbvision->ctl_input); - PDEBUG(DBG_IOCTL,"VIDIOC_QUERYCTRL id=%x value=%x",ctrl->id,ctrl->type); - } - case VIDIOC_G_CTRL: - { - struct v4l2_control *ctrl = arg; - call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl); - PDEBUG(DBG_IOCTL,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value); - return 0; - } - case VIDIOC_S_CTRL: - { - struct v4l2_control *ctrl = arg; + return 0; +} - PDEBUG(DBG_IOCTL, "VIDIOC_S_CTRL id=%x value=%x",ctrl->id,ctrl->value); - call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl); - return 0; - } - case VIDIOC_REQBUFS: - { - struct v4l2_requestbuffers *vr = arg; - int ret; +static int vidioc_g_tuner (struct file *file, void *priv, + struct v4l2_tuner *vt) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); - RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES); + if (!usbvision->have_tuner || vt->index) // Only tuner 0 + return -EINVAL; + if(usbvision->radio) { + strcpy(vt->name, "Radio"); + vt->type = V4L2_TUNER_RADIO; + } else { + strcpy(vt->name, "Television"); + } + /* Let clients fill in the remainder of this struct */ + call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt); - // Check input validity : the user must do a VIDEO CAPTURE and MMAP method. - if((vr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) || - (vr->memory != V4L2_MEMORY_MMAP)) - return -EINVAL; + return 0; +} - if(usbvision->streaming == Stream_On) { - if ((ret = usbvision_stream_interrupt(usbvision))) - return ret; - } +static int vidioc_s_tuner (struct file *file, void *priv, + struct v4l2_tuner *vt) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); - usbvision_frames_free(usbvision); - usbvision_empty_framequeues(usbvision); - vr->count = usbvision_frames_alloc(usbvision,vr->count); + // Only no or one tuner for now + if (!usbvision->have_tuner || vt->index) + return -EINVAL; + /* let clients handle this */ + call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt); - usbvision->curFrame = NULL; + return 0; +} - PDEBUG(DBG_IOCTL, "VIDIOC_REQBUFS count=%d",vr->count); - return 0; - } - case VIDIOC_QUERYBUF: - { - struct v4l2_buffer *vb = arg; - struct usbvision_frame *frame; +static int vidioc_g_frequency (struct file *file, void *priv, + struct v4l2_frequency *freq) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); - // FIXME : must control that buffers are mapped (VIDIOC_REQBUFS has been called) + freq->tuner = 0; // Only one tuner + if(usbvision->radio) { + freq->type = V4L2_TUNER_RADIO; + } else { + freq->type = V4L2_TUNER_ANALOG_TV; + } + freq->frequency = usbvision->freq; - if(vb->type != V4L2_CAP_VIDEO_CAPTURE) { - return -EINVAL; - } - if(vb->index>=usbvision->num_frames) { - return -EINVAL; - } - // Updating the corresponding frame state - vb->flags = 0; - frame = &usbvision->frame[vb->index]; - if(frame->grabstate >= FrameState_Ready) - vb->flags |= V4L2_BUF_FLAG_QUEUED; - if(frame->grabstate >= FrameState_Done) - vb->flags |= V4L2_BUF_FLAG_DONE; - if(frame->grabstate == FrameState_Unused) - vb->flags |= V4L2_BUF_FLAG_MAPPED; - vb->memory = V4L2_MEMORY_MMAP; - - vb->m.offset = vb->index*PAGE_ALIGN(usbvision->max_frame_size); - - vb->memory = V4L2_MEMORY_MMAP; - vb->field = V4L2_FIELD_NONE; - vb->length = usbvision->curwidth*usbvision->curheight*usbvision->palette.bytes_per_pixel; - vb->timestamp = usbvision->frame[vb->index].timestamp; - vb->sequence = usbvision->frame[vb->index].sequence; - return 0; - } - case VIDIOC_QBUF: - { - struct v4l2_buffer *vb = arg; - struct usbvision_frame *frame; - unsigned long lock_flags; - - // FIXME : works only on VIDEO_CAPTURE MODE, MMAP. - if(vb->type != V4L2_CAP_VIDEO_CAPTURE) { - return -EINVAL; - } - if(vb->index>=usbvision->num_frames) { - return -EINVAL; - } + return 0; +} - frame = &usbvision->frame[vb->index]; +static int vidioc_s_frequency (struct file *file, void *priv, + struct v4l2_frequency *freq) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); - if (frame->grabstate != FrameState_Unused) { - return -EAGAIN; - } + // Only no or one tuner for now + if (!usbvision->have_tuner || freq->tuner) + return -EINVAL; - /* Mark it as ready and enqueue frame */ - frame->grabstate = FrameState_Ready; - frame->scanstate = ScanState_Scanning; - frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */ + usbvision->freq = freq->frequency; + call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, freq); - vb->flags &= ~V4L2_BUF_FLAG_DONE; + return 0; +} - /* set v4l2_format index */ - frame->v4l2_format = usbvision->palette; +static int vidioc_g_audio (struct file *file, void *priv, struct v4l2_audio *a) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); - spin_lock_irqsave(&usbvision->queue_lock, lock_flags); - list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue); - spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); + memset(a,0,sizeof(*a)); + if(usbvision->radio) { + strcpy(a->name,"Radio"); + } else { + strcpy(a->name, "TV"); + } - PDEBUG(DBG_IOCTL, "VIDIOC_QBUF frame #%d",vb->index); - return 0; - } - case VIDIOC_DQBUF: - { - struct v4l2_buffer *vb = arg; - int ret; - struct usbvision_frame *f; - unsigned long lock_flags; - - if (vb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (list_empty(&(usbvision->outqueue))) { - if (usbvision->streaming == Stream_Idle) - return -EINVAL; - ret = wait_event_interruptible - (usbvision->wait_frame, - !list_empty(&(usbvision->outqueue))); - if (ret) - return ret; - } + return 0; +} - spin_lock_irqsave(&usbvision->queue_lock, lock_flags); - f = list_entry(usbvision->outqueue.next, - struct usbvision_frame, frame); - list_del(usbvision->outqueue.next); - spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); - - f->grabstate = FrameState_Unused; - - vb->memory = V4L2_MEMORY_MMAP; - vb->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE; - vb->index = f->index; - vb->sequence = f->sequence; - vb->timestamp = f->timestamp; - vb->field = V4L2_FIELD_NONE; - vb->bytesused = f->scanlength; - - return 0; - } - case VIDIOC_STREAMON: - { - int b=V4L2_BUF_TYPE_VIDEO_CAPTURE; +static int vidioc_s_audio (struct file *file, void *fh, + struct v4l2_audio *a) +{ + if(a->index) { + return -EINVAL; + } - usbvision->streaming = Stream_On; + return 0; +} - call_i2c_clients(usbvision,VIDIOC_STREAMON , &b); +static int vidioc_queryctrl (struct file *file, void *priv, + struct v4l2_queryctrl *ctrl) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); + int id=ctrl->id; - PDEBUG(DBG_IOCTL, "VIDIOC_STREAMON"); + memset(ctrl,0,sizeof(*ctrl)); + ctrl->id=id; - return 0; - } - case VIDIOC_STREAMOFF: - { - int *type = arg; - int b=V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if(usbvision->streaming == Stream_On) { - usbvision_stream_interrupt(usbvision); - // Stop all video streamings - call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b); - } - usbvision_empty_framequeues(usbvision); + call_i2c_clients(usbvision, VIDIOC_QUERYCTRL, ctrl); - PDEBUG(DBG_IOCTL, "VIDIOC_STREAMOFF"); - return 0; - } - case VIDIOC_ENUM_FMT: - { - struct v4l2_fmtdesc *vfd = arg; + if (!ctrl->type) + return -EINVAL; - if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) { - return -EINVAL; - } - vfd->flags = 0; - vfd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc); - vfd->pixelformat = usbvision_v4l2_format[vfd->index].format; - memset(vfd->reserved, 0, sizeof(vfd->reserved)); - return 0; - } - case VIDIOC_G_FMT: - { - struct v4l2_format *vf = arg; - - switch (vf->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - { - vf->fmt.pix.width = usbvision->curwidth; - vf->fmt.pix.height = usbvision->curheight; - vf->fmt.pix.pixelformat = usbvision->palette.format; - vf->fmt.pix.bytesperline = usbvision->curwidth*usbvision->palette.bytes_per_pixel; - vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*usbvision->curheight; - vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */ - PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT w=%d, h=%d, format=%s", - vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc); - return 0; - } - default: - PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT invalid type %d",vf->type); - return -EINVAL; - } - return 0; - } - case VIDIOC_TRY_FMT: - case VIDIOC_S_FMT: - { - struct v4l2_format *vf = arg; - int formatIdx,ret; - - switch(vf->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - { - /* Find requested format in available ones */ - for(formatIdx=0;formatIdx<USBVISION_SUPPORTED_PALETTES;formatIdx++) { - if(vf->fmt.pix.pixelformat == usbvision_v4l2_format[formatIdx].format) { - usbvision->palette = usbvision_v4l2_format[formatIdx]; - break; - } - } - /* robustness */ - if(formatIdx == USBVISION_SUPPORTED_PALETTES) { - return -EINVAL; - } - RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH); - RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT); - - vf->fmt.pix.bytesperline = vf->fmt.pix.width*usbvision->palette.bytes_per_pixel; - vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*vf->fmt.pix.height; - - if(cmd == VIDIOC_TRY_FMT) { - PDEBUG(DBG_IOCTL, "VIDIOC_TRY_FMT grabdisplay w=%d, h=%d, format=%s", - vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc); - return 0; - } - - /* stop io in case it is already in progress */ - if(usbvision->streaming == Stream_On) { - if ((ret = usbvision_stream_interrupt(usbvision))) - return ret; - } - usbvision_frames_free(usbvision); - usbvision_empty_framequeues(usbvision); - - usbvision->curFrame = NULL; - - // by now we are committed to the new data... - down(&usbvision->lock); - usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height); - up(&usbvision->lock); - - PDEBUG(DBG_IOCTL, "VIDIOC_S_FMT grabdisplay w=%d, h=%d, format=%s", - vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc); - return 0; - } - default: - return -EINVAL; - } - } - default: - return -ENOIOCTLCMD; + return 0; +} + +static int vidioc_g_ctrl (struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); + call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl); + + return 0; +} + +static int vidioc_s_ctrl (struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); + call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl); + + return 0; +} + +static int vidioc_reqbufs (struct file *file, + void *priv, struct v4l2_requestbuffers *vr) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); + int ret; + + RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES); + + /* Check input validity: + the user must do a VIDEO CAPTURE and MMAP method. */ + if((vr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) || + (vr->memory != V4L2_MEMORY_MMAP)) + return -EINVAL; + + if(usbvision->streaming == Stream_On) { + if ((ret = usbvision_stream_interrupt(usbvision))) + return ret; } + + usbvision_frames_free(usbvision); + usbvision_empty_framequeues(usbvision); + vr->count = usbvision_frames_alloc(usbvision,vr->count); + + usbvision->curFrame = NULL; + return 0; } -static int usbvision_v4l2_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int vidioc_querybuf (struct file *file, + void *priv, struct v4l2_buffer *vb) { - return video_usercopy(inode, file, cmd, arg, usbvision_v4l2_do_ioctl); + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); + struct usbvision_frame *frame; + + /* FIXME : must control + that buffers are mapped (VIDIOC_REQBUFS has been called) */ + if(vb->type != V4L2_CAP_VIDEO_CAPTURE) { + return -EINVAL; + } + if(vb->index>=usbvision->num_frames) { + return -EINVAL; + } + /* Updating the corresponding frame state */ + vb->flags = 0; + frame = &usbvision->frame[vb->index]; + if(frame->grabstate >= FrameState_Ready) + vb->flags |= V4L2_BUF_FLAG_QUEUED; + if(frame->grabstate >= FrameState_Done) + vb->flags |= V4L2_BUF_FLAG_DONE; + if(frame->grabstate == FrameState_Unused) + vb->flags |= V4L2_BUF_FLAG_MAPPED; + vb->memory = V4L2_MEMORY_MMAP; + + vb->m.offset = vb->index*PAGE_ALIGN(usbvision->max_frame_size); + + vb->memory = V4L2_MEMORY_MMAP; + vb->field = V4L2_FIELD_NONE; + vb->length = usbvision->curwidth* + usbvision->curheight* + usbvision->palette.bytes_per_pixel; + vb->timestamp = usbvision->frame[vb->index].timestamp; + vb->sequence = usbvision->frame[vb->index].sequence; + return 0; +} + +static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *vb) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); + struct usbvision_frame *frame; + unsigned long lock_flags; + + /* FIXME : works only on VIDEO_CAPTURE MODE, MMAP. */ + if(vb->type != V4L2_CAP_VIDEO_CAPTURE) { + return -EINVAL; + } + if(vb->index>=usbvision->num_frames) { + return -EINVAL; + } + + frame = &usbvision->frame[vb->index]; + + if (frame->grabstate != FrameState_Unused) { + return -EAGAIN; + } + + /* Mark it as ready and enqueue frame */ + frame->grabstate = FrameState_Ready; + frame->scanstate = ScanState_Scanning; + frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */ + + vb->flags &= ~V4L2_BUF_FLAG_DONE; + + /* set v4l2_format index */ + frame->v4l2_format = usbvision->palette; + + spin_lock_irqsave(&usbvision->queue_lock, lock_flags); + list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue); + spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); + + return 0; } +static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *vb) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); + int ret; + struct usbvision_frame *f; + unsigned long lock_flags; + + if (vb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (list_empty(&(usbvision->outqueue))) { + if (usbvision->streaming == Stream_Idle) + return -EINVAL; + ret = wait_event_interruptible + (usbvision->wait_frame, + !list_empty(&(usbvision->outqueue))); + if (ret) + return ret; + } + + spin_lock_irqsave(&usbvision->queue_lock, lock_flags); + f = list_entry(usbvision->outqueue.next, + struct usbvision_frame, frame); + list_del(usbvision->outqueue.next); + spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); + + f->grabstate = FrameState_Unused; + + vb->memory = V4L2_MEMORY_MMAP; + vb->flags = V4L2_BUF_FLAG_MAPPED | + V4L2_BUF_FLAG_QUEUED | + V4L2_BUF_FLAG_DONE; + vb->index = f->index; + vb->sequence = f->sequence; + vb->timestamp = f->timestamp; + vb->field = V4L2_FIELD_NONE; + vb->bytesused = f->scanlength; + + return 0; +} + +static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); + int b=V4L2_BUF_TYPE_VIDEO_CAPTURE; + + usbvision->streaming = Stream_On; + call_i2c_clients(usbvision,VIDIOC_STREAMON , &b); + + return 0; +} + +static int vidioc_streamoff(struct file *file, + void *priv, enum v4l2_buf_type type) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); + int b=V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if(usbvision->streaming == Stream_On) { + usbvision_stream_interrupt(usbvision); + /* Stop all video streamings */ + call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b); + } + usbvision_empty_framequeues(usbvision); + + return 0; +} + +static int vidioc_enum_fmt_cap (struct file *file, void *priv, + struct v4l2_fmtdesc *vfd) +{ + if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) { + return -EINVAL; + } + vfd->flags = 0; + vfd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc); + vfd->pixelformat = usbvision_v4l2_format[vfd->index].format; + memset(vfd->reserved, 0, sizeof(vfd->reserved)); + return 0; +} + +static int vidioc_g_fmt_cap (struct file *file, void *priv, + struct v4l2_format *vf) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); + vf->fmt.pix.width = usbvision->curwidth; + vf->fmt.pix.height = usbvision->curheight; + vf->fmt.pix.pixelformat = usbvision->palette.format; + vf->fmt.pix.bytesperline = + usbvision->curwidth*usbvision->palette.bytes_per_pixel; + vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*usbvision->curheight; + vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */ + + return 0; +} + +static int vidioc_try_fmt_cap (struct file *file, void *priv, + struct v4l2_format *vf) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); + int formatIdx; + + /* Find requested format in available ones */ + for(formatIdx=0;formatIdx<USBVISION_SUPPORTED_PALETTES;formatIdx++) { + if(vf->fmt.pix.pixelformat == + usbvision_v4l2_format[formatIdx].format) { + usbvision->palette = usbvision_v4l2_format[formatIdx]; + break; + } + } + /* robustness */ + if(formatIdx == USBVISION_SUPPORTED_PALETTES) { + return -EINVAL; + } + RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH); + RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT); + + vf->fmt.pix.bytesperline = vf->fmt.pix.width* + usbvision->palette.bytes_per_pixel; + vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*vf->fmt.pix.height; + + return 0; +} + +static int vidioc_s_fmt_cap(struct file *file, void *priv, + struct v4l2_format *vf) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); + int ret; + + if( 0 != (ret=vidioc_try_fmt_cap (file, priv, vf)) ) { + return ret; + } + + /* stop io in case it is already in progress */ + if(usbvision->streaming == Stream_On) { + if ((ret = usbvision_stream_interrupt(usbvision))) + return ret; + } + usbvision_frames_free(usbvision); + usbvision_empty_framequeues(usbvision); + + usbvision->curFrame = NULL; + + /* by now we are committed to the new data... */ + down(&usbvision->lock); + usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height); + up(&usbvision->lock); + + return 0; +} static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); int noblock = file->f_flags & O_NONBLOCK; unsigned long lock_flags; int ret,i; struct usbvision_frame *frame; - PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__, (unsigned long)count, noblock); + PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__, + (unsigned long)count, noblock); if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL)) return -EFAULT; - /* This entry point is compatible with the mmap routines so that a user can do either - VIDIOC_QBUF/VIDIOC_DQBUF to get frames or call read on the device. */ + /* This entry point is compatible with the mmap routines + so that a user can do either VIDIOC_QBUF/VIDIOC_DQBUF + to get frames or call read on the device. */ if(!usbvision->num_frames) { - /* First, allocate some frames to work with if this has not been done with - VIDIOC_REQBUF */ + /* First, allocate some frames to work with + if this has not been done with VIDIOC_REQBUF */ usbvision_frames_free(usbvision); usbvision_empty_framequeues(usbvision); usbvision_frames_alloc(usbvision,USBVISION_NUMFRAMES); @@ -1086,21 +1116,24 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf, call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL); } - /* Then, enqueue as many frames as possible (like a user of VIDIOC_QBUF would do) */ + /* Then, enqueue as many frames as possible + (like a user of VIDIOC_QBUF would do) */ for(i=0;i<usbvision->num_frames;i++) { frame = &usbvision->frame[i]; if(frame->grabstate == FrameState_Unused) { /* Mark it as ready and enqueue frame */ frame->grabstate = FrameState_Ready; frame->scanstate = ScanState_Scanning; - frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */ + /* Accumulated in usbvision_parse_data() */ + frame->scanlength = 0; /* set v4l2_format index */ frame->v4l2_format = usbvision->palette; spin_lock_irqsave(&usbvision->queue_lock, lock_flags); list_add_tail(&frame->frame, &usbvision->inqueue); - spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); + spin_unlock_irqrestore(&usbvision->queue_lock, + lock_flags); } } @@ -1128,8 +1161,9 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf, return 0; } - PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld", __FUNCTION__, - frame->index, frame->bytes_read, frame->scanlength); + PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld", + __FUNCTION__, + frame->index, frame->bytes_read, frame->scanlength); /* copy bytes to user space; we allow for partials reads */ if ((count + frame->bytes_read) > (unsigned long)frame->scanlength) @@ -1140,10 +1174,11 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf, } frame->bytes_read += count; - PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld", __FUNCTION__, - (unsigned long)count, frame->bytes_read); + PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld", + __FUNCTION__, + (unsigned long)count, frame->bytes_read); - // For now, forget the frame if it has not been read in one shot. + /* For now, forget the frame if it has not been read in one shot. */ /* if (frame->bytes_read >= frame->scanlength) {// All data has been read */ frame->bytes_read = 0; @@ -1162,7 +1197,8 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) u32 i; struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); PDEBUG(DBG_MMAP, "mmap"); @@ -1180,11 +1216,13 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) } for (i = 0; i < usbvision->num_frames; i++) { - if (((PAGE_ALIGN(usbvision->max_frame_size)*i) >> PAGE_SHIFT) == vma->vm_pgoff) + if (((PAGE_ALIGN(usbvision->max_frame_size)*i) >> PAGE_SHIFT) == + vma->vm_pgoff) break; } if (i == usbvision->num_frames) { - PDEBUG(DBG_MMAP, "mmap: user supplied mapping address is out of range"); + PDEBUG(DBG_MMAP, + "mmap: user supplied mapping address is out of range"); up(&usbvision->lock); return -EINVAL; } @@ -1218,8 +1256,8 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) static int usbvision_radio_open(struct inode *inode, struct file *file) { struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); - struct v4l2_frequency freq; + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); int errCode = 0; PDEBUG(DBG_IO, "%s:", __FUNCTION__); @@ -1249,8 +1287,6 @@ static int usbvision_radio_open(struct inode *inode, struct file *file) // If so far no errors then we shall start the radio usbvision->radio = 1; call_i2c_clients(usbvision,AUDC_SET_RADIO,&usbvision->tuner_type); - freq.frequency = 1517; //SWR3 @ 94.8MHz - call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, &freq); usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO); usbvision->user++; } @@ -1270,7 +1306,8 @@ static int usbvision_radio_open(struct inode *inode, struct file *file) static int usbvision_radio_close(struct inode *inode, struct file *file) { struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = + (struct usb_usbvision *) video_get_drvdata(dev); int errCode = 0; PDEBUG(DBG_IO, ""); @@ -1304,149 +1341,6 @@ static int usbvision_radio_close(struct inode *inode, struct file *file) return errCode; } -static int usbvision_do_radio_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) -{ - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); - - if (!USBVISION_IS_OPERATIONAL(usbvision)) - return -EIO; - - switch (cmd) { - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *vc=arg; - - memset(vc, 0, sizeof(*vc)); - strlcpy(vc->driver, "USBVision", sizeof(vc->driver)); - strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString, - sizeof(vc->card)); - strlcpy(vc->bus_info, usbvision->dev->dev.bus_id, - sizeof(vc->bus_info)); - vc->version = USBVISION_DRIVER_VERSION; - vc->capabilities = (usbvision->have_tuner ? V4L2_CAP_TUNER : 0); - PDEBUG(DBG_IO, "VIDIOC_QUERYCAP"); - return 0; - } - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *ctrl = arg; - int id=ctrl->id; - - memset(ctrl,0,sizeof(*ctrl)); - ctrl->id=id; - - call_i2c_clients(usbvision, cmd, arg); - PDEBUG(DBG_IO,"VIDIOC_QUERYCTRL id=%x value=%x",ctrl->id,ctrl->type); - - if (ctrl->type) - return 0; - else - return -EINVAL; - - } - case VIDIOC_G_CTRL: - { - struct v4l2_control *ctrl = arg; - - call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl); - PDEBUG(DBG_IO,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value); - return 0; - } - case VIDIOC_S_CTRL: - { - struct v4l2_control *ctrl = arg; - - call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl); - PDEBUG(DBG_IO, "VIDIOC_S_CTRL id=%x value=%x",ctrl->id,ctrl->value); - return 0; - } - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *t = arg; - - if (t->index > 0) - return -EINVAL; - - memset(t,0,sizeof(*t)); - strcpy(t->name, "Radio"); - t->type = V4L2_TUNER_RADIO; - - /* Let clients fill in the remainder of this struct */ - call_i2c_clients(usbvision,VIDIOC_G_TUNER,t); - PDEBUG(DBG_IO, "VIDIOC_G_TUNER signal=%x, afc=%x",t->signal,t->afc); - return 0; - } - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *vt = arg; - - // Only no or one tuner for now - if (!usbvision->have_tuner || vt->index) - return -EINVAL; - /* let clients handle this */ - call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt); - - PDEBUG(DBG_IO, "VIDIOC_S_TUNER"); - return 0; - } - case VIDIOC_G_AUDIO: - { - struct v4l2_audio *a = arg; - - memset(a,0,sizeof(*a)); - strcpy(a->name,"Radio"); - PDEBUG(DBG_IO, "VIDIOC_G_AUDIO"); - return 0; - } - case VIDIOC_S_AUDIO: - case VIDIOC_S_INPUT: - case VIDIOC_S_STD: - return 0; - - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *f = arg; - - memset(f,0,sizeof(*f)); - - f->type = V4L2_TUNER_RADIO; - f->frequency = usbvision->freq; - call_i2c_clients(usbvision, cmd, f); - PDEBUG(DBG_IO, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)f->frequency); - - return 0; - } - case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *f = arg; - - if (f->tuner != 0) - return -EINVAL; - usbvision->freq = f->frequency; - call_i2c_clients(usbvision, cmd, f); - PDEBUG(DBG_IO, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)f->frequency); - - return 0; - } - default: - { - PDEBUG(DBG_IO, "%s: Unknown command %x", __FUNCTION__, cmd); - return -ENOIOCTLCMD; - } - } - return 0; -} - - -static int usbvision_radio_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return video_usercopy(inode, file, cmd, arg, usbvision_do_radio_ioctl); -} - - /* * Here comes the stuff for vbi on usbvision based devices * @@ -1454,21 +1348,21 @@ static int usbvision_radio_ioctl(struct inode *inode, struct file *file, static int usbvision_vbi_open(struct inode *inode, struct file *file) { /* TODO */ - return -EINVAL; + return -ENODEV; } static int usbvision_vbi_close(struct inode *inode, struct file *file) { /* TODO */ - return -EINVAL; + return -ENODEV; } static int usbvision_do_vbi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg) { /* TODO */ - return -EINVAL; + return -ENOIOCTLCMD; } static int usbvision_vbi_ioctl(struct inode *inode, struct file *file, @@ -1489,8 +1383,11 @@ static const struct file_operations usbvision_fops = { .release = usbvision_v4l2_close, .read = usbvision_v4l2_read, .mmap = usbvision_v4l2_mmap, - .ioctl = usbvision_v4l2_ioctl, + .ioctl = video_ioctl2, .llseek = no_llseek, +/* .poll = video_poll, */ + .mmap = usbvision_v4l2_mmap, + .compat_ioctl = v4l_compat_ioctl32, }; static struct video_device usbvision_video_template = { .owner = THIS_MODULE, @@ -1500,6 +1397,39 @@ static struct video_device usbvision_video_template = { .name = "usbvision-video", .release = video_device_release, .minor = -1, + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, + .vidioc_g_fmt_cap = vidioc_g_fmt_cap, + .vidioc_try_fmt_cap = vidioc_try_fmt_cap, + .vidioc_s_fmt_cap = vidioc_s_fmt_cap, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_s_std = vidioc_s_std, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_g_audio = vidioc_s_audio, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, +#ifdef CONFIG_VIDEO_V4L1_COMPAT +/* .vidiocgmbuf = vidiocgmbuf, */ +#endif + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, +#endif + .tvnorms = USBVISION_NORMS, + .current_norm = V4L2_STD_PAL }; @@ -1508,8 +1438,9 @@ static const struct file_operations usbvision_radio_fops = { .owner = THIS_MODULE, .open = usbvision_radio_open, .release = usbvision_radio_close, - .ioctl = usbvision_radio_ioctl, + .ioctl = video_ioctl2, .llseek = no_llseek, + .compat_ioctl = v4l_compat_ioctl32, }; static struct video_device usbvision_radio_template= @@ -1518,12 +1449,27 @@ static struct video_device usbvision_radio_template= .type = VID_TYPE_TUNER, .hardware = VID_HARDWARE_USBVISION, .fops = &usbvision_radio_fops, - .release = video_device_release, .name = "usbvision-radio", + .release = video_device_release, .minor = -1, + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_g_audio = vidioc_s_audio, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + + .tvnorms = USBVISION_NORMS, + .current_norm = V4L2_STD_PAL }; - // vbi template static const struct file_operations usbvision_vbi_fops = { .owner = THIS_MODULE, @@ -1531,6 +1477,7 @@ static const struct file_operations usbvision_vbi_fops = { .release = usbvision_vbi_close, .ioctl = usbvision_vbi_ioctl, .llseek = no_llseek, + .compat_ioctl = v4l_compat_ioctl32, }; static struct video_device usbvision_vbi_template= @@ -1574,11 +1521,11 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision) { // vbi Device: if (usbvision->vbi) { - PDEBUG(DBG_PROBE, "unregister /dev/vbi%d [v4l2]", usbvision->vbi->minor & 0x1f); + PDEBUG(DBG_PROBE, "unregister /dev/vbi%d [v4l2]", + usbvision->vbi->minor & 0x1f); if (usbvision->vbi->minor != -1) { video_unregister_device(usbvision->vbi); - } - else { + } else { video_device_release(usbvision->vbi); } usbvision->vbi = NULL; @@ -1586,11 +1533,11 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision) // Radio Device: if (usbvision->rdev) { - PDEBUG(DBG_PROBE, "unregister /dev/radio%d [v4l2]", usbvision->rdev->minor & 0x1f); + PDEBUG(DBG_PROBE, "unregister /dev/radio%d [v4l2]", + usbvision->rdev->minor & 0x1f); if (usbvision->rdev->minor != -1) { video_unregister_device(usbvision->rdev); - } - else { + } else { video_device_release(usbvision->rdev); } usbvision->rdev = NULL; @@ -1598,11 +1545,11 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision) // Video Device: if (usbvision->vdev) { - PDEBUG(DBG_PROBE, "unregister /dev/video%d [v4l2]", usbvision->vdev->minor & 0x1f); + PDEBUG(DBG_PROBE, "unregister /dev/video%d [v4l2]", + usbvision->vdev->minor & 0x1f); if (usbvision->vdev->minor != -1) { video_unregister_device(usbvision->vdev); - } - else { + } else { video_device_release(usbvision->vdev); } usbvision->vdev = NULL; @@ -1613,37 +1560,52 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision) static int __devinit usbvision_register_video(struct usb_usbvision *usbvision) { // Video Device: - usbvision->vdev = usbvision_vdev_init(usbvision, &usbvision_video_template, "USBVision Video"); + usbvision->vdev = usbvision_vdev_init(usbvision, + &usbvision_video_template, + "USBVision Video"); if (usbvision->vdev == NULL) { goto err_exit; } - if (video_register_device(usbvision->vdev, VFL_TYPE_GRABBER, video_nr)<0) { + if (video_register_device(usbvision->vdev, + VFL_TYPE_GRABBER, + video_nr)<0) { goto err_exit; } - printk(KERN_INFO "USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]\n", usbvision->nr,usbvision->vdev->minor & 0x1f); + printk(KERN_INFO "USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]\n", + usbvision->nr,usbvision->vdev->minor & 0x1f); // Radio Device: if (usbvision_device_data[usbvision->DevModel].Radio) { // usbvision has radio - usbvision->rdev = usbvision_vdev_init(usbvision, &usbvision_radio_template, "USBVision Radio"); + usbvision->rdev = usbvision_vdev_init(usbvision, + &usbvision_radio_template, + "USBVision Radio"); if (usbvision->rdev == NULL) { goto err_exit; } - if (video_register_device(usbvision->rdev, VFL_TYPE_RADIO, radio_nr)<0) { + if (video_register_device(usbvision->rdev, + VFL_TYPE_RADIO, + radio_nr)<0) { goto err_exit; } - printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]\n", usbvision->nr, usbvision->rdev->minor & 0x1f); + printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]\n", + usbvision->nr, usbvision->rdev->minor & 0x1f); } // vbi Device: if (usbvision_device_data[usbvision->DevModel].vbi) { - usbvision->vbi = usbvision_vdev_init(usbvision, &usbvision_vbi_template, "USBVision VBI"); + usbvision->vbi = usbvision_vdev_init(usbvision, + &usbvision_vbi_template, + "USBVision VBI"); if (usbvision->vdev == NULL) { goto err_exit; } - if (video_register_device(usbvision->vbi, VFL_TYPE_VBI, vbi_nr)<0) { + if (video_register_device(usbvision->vbi, + VFL_TYPE_VBI, + vbi_nr)<0) { goto err_exit; } - printk(KERN_INFO "USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)\n", usbvision->nr,usbvision->vbi->minor & 0x1f); + printk(KERN_INFO "USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)\n", + usbvision->nr,usbvision->vbi->minor & 0x1f); } // all done return 0; @@ -1657,7 +1619,8 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision) /* * usbvision_alloc() * - * This code allocates the struct usb_usbvision. It is filled with default values. + * This code allocates the struct usb_usbvision. + * It is filled with default values. * * Returns NULL on error, a pointer to usb_usbvision else. * @@ -1666,7 +1629,8 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev) { struct usb_usbvision *usbvision; - if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) == NULL) { + if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) == + NULL) { goto err_exit; } @@ -1728,11 +1692,11 @@ static void usbvision_release(struct usb_usbvision *usbvision) } -/******************************** usb interface *****************************************/ +/*********************** usb interface **********************************/ static void usbvision_configure_video(struct usb_usbvision *usbvision) { - int model,i; + int model; if (usbvision == NULL) return; @@ -1741,25 +1705,23 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision) usbvision->palette = usbvision_v4l2_format[2]; // V4L2_PIX_FMT_RGB24; if (usbvision_device_data[usbvision->DevModel].Vin_Reg2_override) { - usbvision->Vin_Reg2_Preset = usbvision_device_data[usbvision->DevModel].Vin_Reg2; + usbvision->Vin_Reg2_Preset = + usbvision_device_data[usbvision->DevModel].Vin_Reg2; } else { usbvision->Vin_Reg2_Preset = 0; } - for (i = 0; i < TVNORMS; i++) - if (usbvision_device_data[model].VideoNorm == tvnorms[i].mode) - break; - if (i == TVNORMS) - i = 0; - usbvision->tvnorm = &tvnorms[i]; /* set default norm */ + usbvision->tvnormId = usbvision_device_data[model].VideoNorm; usbvision->video_inputs = usbvision_device_data[model].VideoChannels; usbvision->ctl_input = 0; /* This should be here to make i2c clients to be able to register */ - usbvision_audio_off(usbvision); //first switch off audio + /* first switch off audio */ + usbvision_audio_off(usbvision); if (!PowerOnAtOpen) { - usbvision_power_on(usbvision); //and then power up the noisy tuner + /* and then power up the noisy tuner */ + usbvision_power_on(usbvision); usbvision_i2c_register(usbvision); } } @@ -1796,18 +1758,22 @@ static int __devinit usbvision_probe(struct usb_interface *intf, if (usbvision_device_data[model].Interface >= 0) { interface = &dev->actconfig->interface[usbvision_device_data[model].Interface]->altsetting[0]; - } - else { + } else { interface = &dev->actconfig->interface[ifnum]->altsetting[0]; } endpoint = &interface->endpoint[1].desc; - if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC) { - err("%s: interface %d. has non-ISO endpoint!", __FUNCTION__, ifnum); - err("%s: Endpoint attributes %d", __FUNCTION__, endpoint->bmAttributes); + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != + USB_ENDPOINT_XFER_ISOC) { + err("%s: interface %d. has non-ISO endpoint!", + __FUNCTION__, ifnum); + err("%s: Endpoint attributes %d", + __FUNCTION__, endpoint->bmAttributes); return -ENODEV; } - if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) { - err("%s: interface %d. has ISO OUT endpoint!", __FUNCTION__, ifnum); + if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == + USB_DIR_OUT) { + err("%s: interface %d. has ISO OUT endpoint!", + __FUNCTION__, ifnum); return -ENODEV; } @@ -1818,11 +1784,9 @@ static int __devinit usbvision_probe(struct usb_interface *intf, if (dev->descriptor.bNumConfigurations > 1) { usbvision->bridgeType = BRIDGE_NT1004; - } - else if (model == DAZZLE_DVC_90_REV_1_SECAM) { + } else if (model == DAZZLE_DVC_90_REV_1_SECAM) { usbvision->bridgeType = BRIDGE_NT1005; - } - else { + } else { usbvision->bridgeType = BRIDGE_NT1003; } PDEBUG(DBG_PROBE, "bridgeType %d", usbvision->bridgeType); @@ -1919,11 +1883,11 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf) up(&usbvision->lock); if (usbvision->user) { - printk(KERN_INFO "%s: In use, disconnect pending\n", __FUNCTION__); + printk(KERN_INFO "%s: In use, disconnect pending\n", + __FUNCTION__); wake_up_interruptible(&usbvision->wait_frame); wake_up_interruptible(&usbvision->wait_stream); - } - else { + } else { usbvision_release(usbvision); } @@ -1950,7 +1914,6 @@ static int __init usbvision_init(void) PDEBUG(DBG_PROBE, ""); - PDEBUG(DBG_IOCTL, "IOCTL debugging is enabled [video]"); PDEBUG(DBG_IO, "IO debugging is enabled [video]"); PDEBUG(DBG_PROBE, "PROBE debugging is enabled [video]"); PDEBUG(DBG_MMAP, "MMAP debugging is enabled [video]"); diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h index c759d00d7014..c5b6c501c869 100644 --- a/drivers/media/video/usbvision/usbvision.h +++ b/drivers/media/video/usbvision/usbvision.h @@ -221,6 +221,8 @@ enum { #define I2C_USB_ADAP_MAX 16 +#define USBVISION_NORMS (V4L2_STD_PAL | V4L2_STD_NTSC | V4L2_STD_SECAM | V4L2_STD_PAL_M) + /* ----------------------------------------------------------------- */ /* usbvision video structures */ /* ----------------------------------------------------------------- */ @@ -301,14 +303,6 @@ struct usbvision_frame_header { __u16 frameHeight; /* 10 - 11 after endian correction*/ }; -/* tvnorms */ -struct usbvision_tvnorm { - char *name; - v4l2_std_id id; - /* mode for saa7113h */ - int mode; -}; - struct usbvision_frame { char *data; /* Frame buffer */ struct usbvision_frame_header isocHeader; /* Header from stream */ @@ -386,7 +380,6 @@ struct usb_usbvision { int tuner_type; int tuner_addr; int bridgeType; // NT1003, NT1004, NT1005 - int channel; int radio; int video_inputs; // # of inputs unsigned long freq; @@ -441,7 +434,7 @@ struct usb_usbvision { struct v4l2_capability vcap; /* Video capabilities */ unsigned int ctl_input; /* selected input */ - struct usbvision_tvnorm *tvnorm; /* selected tv norm */ + v4l2_std_id tvnormId; /* selected tv norm */ unsigned char video_endp; /* 0x82 for USBVISION devices based */ // Decompression stuff: diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index 0c658b74f2c4..e94a9a6036f5 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c @@ -2077,12 +2077,10 @@ static int vino_wait_for_frame(struct vino_channel_settings *vcs) init_waitqueue_entry(&wait, current); /* add ourselves into wait queue */ add_wait_queue(&vcs->fb_queue.frame_wait_queue, &wait); - /* and set current state */ - set_current_state(TASK_INTERRUPTIBLE); /* to ensure that schedule_timeout will return immediately - * if VINO interrupt was triggred meanwhile */ - schedule_timeout(HZ / 10); + * if VINO interrupt was triggered meanwhile */ + schedule_timeout_interruptible(HZ / 10); if (signal_pending(current)) err = -EINTR; diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 3ef4d0159c33..f6d3a9460ccc 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -25,6 +25,7 @@ #include <linux/pci.h> #include <linux/random.h> #include <linux/version.h> +#include <linux/mutex.h> #include <linux/videodev2.h> #include <linux/dma-mapping.h> #ifdef CONFIG_VIDEO_V4L1_COMPAT @@ -145,9 +146,6 @@ struct vivi_buffer { struct vivi_fmt *fmt; -#ifdef CONFIG_VIVI_SCATTER - struct sg_to_addr *to_addr; -#endif }; struct vivi_dmaqueue { @@ -168,7 +166,7 @@ static LIST_HEAD(vivi_devlist); struct vivi_dev { struct list_head vivi_devlist; - struct semaphore lock; + struct mutex lock; int users; @@ -232,68 +230,13 @@ static u8 bars[8][3] = { #define TSTAMP_MAX_Y TSTAMP_MIN_Y+15 #define TSTAMP_MIN_X 64 -#ifdef CONFIG_VIVI_SCATTER -static void prep_to_addr(struct sg_to_addr to_addr[], - struct videobuf_buffer *vb) -{ - int i, pos=0; - - for (i=0;i<vb->dma.nr_pages;i++) { - to_addr[i].sg=&vb->dma.sglist[i]; - to_addr[i].pos=pos; - pos += vb->dma.sglist[i].length; - } -} - -static int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[]) -{ - int p1=0,p2=pages-1,p3=pages/2; - - /* Sanity test */ - BUG_ON (pos>=to_addr[p2].pos+to_addr[p2].sg->length); - - while (p1+1<p2) { - if (pos < to_addr[p3].pos) { - p2=p3; - } else { - p1=p3; - } - p3=(p1+p2)/2; - } - if (pos >= to_addr[p2].pos) - p1=p2; - - return (p1); -} -#endif -#ifdef CONFIG_VIVI_SCATTER -static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, - int hmax, int line, char *timestr) -#else static void gen_line(char *basep,int inipos,int wmax, int hmax, int line, char *timestr) -#endif { int w,i,j,pos=inipos,y; char *p,*s; u8 chr,r,g,b,color; -#ifdef CONFIG_VIVI_SCATTER - int pgpos,oldpg; - char *basep; - struct page *pg; - - unsigned long flags; - spinlock_t spinlock; - - spin_lock_init(&spinlock); - - /* Get first addr pointed to pixel position */ - oldpg=get_addr_pos(pos,pages,to_addr); - pg=pfn_to_page(sg_dma_address(to_addr[oldpg].sg) >> PAGE_SHIFT); - spin_lock_irqsave(&spinlock,flags); - basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset; -#endif /* We will just duplicate the second pixel at the packet */ wmax/=2; @@ -305,18 +248,7 @@ static void gen_line(char *basep,int inipos,int wmax, b=bars[w*7/wmax][2]; for (color=0;color<4;color++) { -#ifdef CONFIG_VIVI_SCATTER - pgpos=get_addr_pos(pos,pages,to_addr); - if (pgpos!=oldpg) { - pg=pfn_to_page(sg_dma_address(to_addr[pgpos].sg) >> PAGE_SHIFT); - kunmap_atomic(basep, KM_BOUNCE_READ); - basep= kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[pgpos].sg->offset; - oldpg=pgpos; - } - p=basep+pos-to_addr[pgpos].pos; -#else p=basep+pos; -#endif switch (color) { case 0: @@ -361,23 +293,7 @@ static void gen_line(char *basep,int inipos,int wmax, pos=inipos+j*2; for (color=0;color<4;color++) { -#ifdef CONFIG_VIVI_SCATTER - pgpos=get_addr_pos(pos,pages,to_addr); - if (pgpos!=oldpg) { - pg=pfn_to_page(sg_dma_address( - to_addr[pgpos].sg) - >> PAGE_SHIFT); - kunmap_atomic(basep, - KM_BOUNCE_READ); - basep= kmap_atomic(pg, - KM_BOUNCE_READ)+ - to_addr[pgpos].sg->offset; - oldpg=pgpos; - } - p=basep+pos-to_addr[pgpos].pos; -#else p=basep+pos; -#endif y=TO_Y(r,g,b); @@ -402,12 +318,7 @@ static void gen_line(char *basep,int inipos,int wmax, end: -#ifdef CONFIG_VIVI_SCATTER - kunmap_atomic(basep, KM_BOUNCE_READ); - spin_unlock_irqrestore(&spinlock,flags); -#else return; -#endif } static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) { @@ -415,35 +326,16 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) int hmax = buf->vb.height; int wmax = buf->vb.width; struct timeval ts; -#ifdef CONFIG_VIVI_SCATTER - struct sg_to_addr *to_addr=buf->to_addr; - struct videobuf_buffer *vb=&buf->vb; -#else char *tmpbuf; -#endif - -#ifdef CONFIG_VIVI_SCATTER - /* Test if DMA mapping is ready */ - if (!sg_dma_address(&vb->dma.sglist[0])) - return; - - prep_to_addr(to_addr,vb); - /* Check if there is enough memory */ - BUG_ON(buf->vb.dma.nr_pages << PAGE_SHIFT < (buf->vb.width*buf->vb.height)*2); -#else if (buf->vb.dma.varea) { tmpbuf=kmalloc (wmax*2, GFP_KERNEL); } else { tmpbuf=buf->vb.dma.vmalloc; } -#endif for (h=0;h<hmax;h++) { -#ifdef CONFIG_VIVI_SCATTER - gen_line(to_addr,pos,vb->dma.nr_pages,wmax,hmax,h,dev->timestr); -#else if (buf->vb.dma.varea) { gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr); /* FIXME: replacing to __copy_to_user */ @@ -452,7 +344,6 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) } else { gen_line(tmpbuf,pos,wmax,hmax,h,dev->timestr); } -#endif pos += wmax*2; } @@ -718,11 +609,6 @@ static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) if (in_interrupt()) BUG(); -#ifdef CONFIG_VIVI_SCATTER - /*FIXME: Maybe a spinlock is required here */ - kfree(buf->to_addr); - buf->to_addr=NULL; -#endif videobuf_waiton(&buf->vb,0,0); videobuf_dma_unmap(vq, &buf->vb.dma); @@ -768,12 +654,6 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, buf->vb.state = STATE_PREPARED; -#ifdef CONFIG_VIVI_SCATTER - if (NULL == (buf->to_addr = kmalloc(sizeof(*buf->to_addr) * vb->dma.nr_pages,GFP_KERNEL))) { - rc=-ENOMEM; - goto fail; - } -#endif return 0; fail: @@ -838,40 +718,6 @@ static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb free_buffer(vq,buf); } -#ifdef CONFIG_VIVI_SCATTER -static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents, - int direction) -{ - int i; - - dprintk(1,"%s, number of pages=%d\n",__FUNCTION__,nents); - BUG_ON(direction == DMA_NONE); - - for (i = 0; i < nents; i++ ) { - BUG_ON(!sg[i].page); - - sg_dma_address(&sg[i]) = page_to_phys(sg[i].page) + sg[i].offset; - } - - return nents; -} - -static int vivi_unmap_sg(void *dev,struct scatterlist *sglist,int nr_pages, - int direction) -{ - dprintk(1,"%s\n",__FUNCTION__); - return 0; -} - -static int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist, int nr_pages, - int direction) -{ -// dprintk(1,"%s\n",__FUNCTION__); - -// flush_write_buffers(); - return 0; -} -#endif static struct videobuf_queue_ops vivi_video_qops = { .buf_setup = buffer_setup, @@ -893,16 +739,16 @@ static struct videobuf_queue_ops vivi_video_qops = { static int res_get(struct vivi_dev *dev, struct vivi_fh *fh) { /* is it free? */ - down(&dev->lock); + mutex_lock(&dev->lock); if (dev->resources) { /* no, someone else uses it */ - up(&dev->lock); + mutex_unlock(&dev->lock); return 0; } /* it's free, grab it */ dev->resources =1; dprintk(1,"res: get\n"); - up(&dev->lock); + mutex_unlock(&dev->lock); return 1; } @@ -913,10 +759,10 @@ static int res_locked(struct vivi_dev *dev) static void res_free(struct vivi_dev *dev, struct vivi_fh *fh) { - down(&dev->lock); + mutex_lock(&dev->lock); dev->resources = 0; dprintk(1,"res: put\n"); - up(&dev->lock); + mutex_lock(&dev->lock); } /* ------------------------------------------------------------------ @@ -1260,19 +1106,11 @@ static int vivi_open(struct inode *inode, struct file *file) sprintf(dev->timestr,"%02d:%02d:%02d:%03d", dev->h,dev->m,dev->s,(dev->us+500)/1000); -#ifdef CONFIG_VIVI_SCATTER - videobuf_queue_init(&fh->vb_vidq,VIDEOBUF_DMA_SCATTER, &vivi_video_qops, - NULL, NULL, - fh->type, - V4L2_FIELD_INTERLACED, - sizeof(struct vivi_buffer),fh); -#else videobuf_queue_init(&fh->vb_vidq, &vivi_video_qops, NULL, NULL, fh->type, V4L2_FIELD_INTERLACED, sizeof(struct vivi_buffer),fh); -#endif return 0; } @@ -1423,7 +1261,7 @@ static int __init vivi_init(void) init_waitqueue_head(&dev->vidq.wq); /* initialize locks */ - init_MUTEX(&dev->lock); + mutex_init(&dev->lock); dev->vidq.timeout.function = vivi_vid_timeout; dev->vidq.timeout.data = (unsigned long)dev; diff --git a/drivers/media/video/zc0301/Kconfig b/drivers/media/video/zc0301/Kconfig index 47cd93f9c7de..edb00293cd59 100644 --- a/drivers/media/video/zc0301/Kconfig +++ b/drivers/media/video/zc0301/Kconfig @@ -1,6 +1,6 @@ config USB_ZC0301 tristate "USB ZC0301[P] Image Processor and Control Chip support" - depends on VIDEO_V4L1 + depends on VIDEO_V4L2 ---help--- Say Y here if you want support for cameras based on the ZC0301 or ZC0301P Image Processors and Control Chips. diff --git a/drivers/media/video/zc0301/zc0301.h b/drivers/media/video/zc0301/zc0301.h index 710f12eb9126..a2de50efa31a 100644 --- a/drivers/media/video/zc0301/zc0301.h +++ b/drivers/media/video/zc0301/zc0301.h @@ -36,6 +36,7 @@ #include <linux/rwsem.h> #include <linux/stddef.h> #include <linux/string.h> +#include <linux/kref.h> #include "zc0301_sensor.h" @@ -98,7 +99,7 @@ struct zc0301_module_param { u16 frame_timeout; }; -static DECLARE_RWSEM(zc0301_disconnect); +static DECLARE_RWSEM(zc0301_dev_lock); struct zc0301_device { struct video_device* v4ldev; @@ -121,12 +122,14 @@ struct zc0301_device { struct zc0301_module_param module_param; + struct kref kref; enum zc0301_dev_state state; u8 users; - struct mutex dev_mutex, fileop_mutex; + struct completion probe; + struct mutex open_mutex, fileop_mutex; spinlock_t queue_lock; - wait_queue_head_t open, wait_frame, wait_stream; + wait_queue_head_t wait_open, wait_frame, wait_stream; }; /*****************************************************************************/ @@ -156,8 +159,8 @@ do { \ else if ((level) == 2) \ dev_info(&cam->usbdev->dev, fmt "\n", ## args); \ else if ((level) >= 3) \ - dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ - __FUNCTION__, __LINE__ , ## args); \ + dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \ + __FILE__, __FUNCTION__, __LINE__ , ## args); \ } \ } while (0) # define KDBG(level, fmt, args...) \ @@ -166,8 +169,8 @@ do { \ if ((level) == 1 || (level) == 2) \ pr_info("zc0301: " fmt "\n", ## args); \ else if ((level) == 3) \ - pr_debug("zc0301: [%s:%d] " fmt "\n", __FUNCTION__, \ - __LINE__ , ## args); \ + pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__, \ + __FUNCTION__, __LINE__ , ## args); \ } \ } while (0) # define V4LDBG(level, name, cmd) \ @@ -183,8 +186,8 @@ do { \ #undef PDBG #define PDBG(fmt, args...) \ -dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ - __FUNCTION__, __LINE__ , ## args) +dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__, \ + __LINE__ , ## args) #undef PDBGG #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c index f1120551c70c..703b741e46df 100644 --- a/drivers/media/video/zc0301/zc0301_core.c +++ b/drivers/media/video/zc0301/zc0301_core.c @@ -49,11 +49,11 @@ #define ZC0301_MODULE_NAME "V4L2 driver for ZC0301[P] " \ "Image Processor and Control Chip" -#define ZC0301_MODULE_AUTHOR "(C) 2006 Luca Risolia" +#define ZC0301_MODULE_AUTHOR "(C) 2006-2007 Luca Risolia" #define ZC0301_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>" #define ZC0301_MODULE_LICENSE "GPL" -#define ZC0301_MODULE_VERSION "1:1.07" -#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 7) +#define ZC0301_MODULE_VERSION "1:1.10" +#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 10) /*****************************************************************************/ @@ -573,7 +573,8 @@ static int zc0301_init(struct zc0301_device* cam) int err = 0; if (!(cam->state & DEV_INITIALIZED)) { - init_waitqueue_head(&cam->open); + mutex_init(&cam->open_mutex); + init_waitqueue_head(&cam->wait_open); qctrl = s->qctrl; rect = &(s->cropcap.defrect); cam->compression.quality = ZC0301_COMPRESSION_QUALITY; @@ -634,59 +635,73 @@ static int zc0301_init(struct zc0301_device* cam) return 0; } +/*****************************************************************************/ -static void zc0301_release_resources(struct zc0301_device* cam) +static void zc0301_release_resources(struct kref *kref) { + struct zc0301_device *cam = container_of(kref, struct zc0301_device, + kref); DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor); video_set_drvdata(cam->v4ldev, NULL); video_unregister_device(cam->v4ldev); + usb_put_dev(cam->usbdev); kfree(cam->control_buffer); + kfree(cam); } -/*****************************************************************************/ static int zc0301_open(struct inode* inode, struct file* filp) { struct zc0301_device* cam; int err = 0; - /* - This is the only safe way to prevent race conditions with - disconnect - */ - if (!down_read_trylock(&zc0301_disconnect)) + if (!down_read_trylock(&zc0301_dev_lock)) return -ERESTARTSYS; cam = video_get_drvdata(video_devdata(filp)); - if (mutex_lock_interruptible(&cam->dev_mutex)) { - up_read(&zc0301_disconnect); + if (wait_for_completion_interruptible(&cam->probe)) { + up_read(&zc0301_dev_lock); return -ERESTARTSYS; } + kref_get(&cam->kref); + + if (mutex_lock_interruptible(&cam->open_mutex)) { + kref_put(&cam->kref, zc0301_release_resources); + up_read(&zc0301_dev_lock); + return -ERESTARTSYS; + } + + if (cam->state & DEV_DISCONNECTED) { + DBG(1, "Device not present"); + err = -ENODEV; + goto out; + } + if (cam->users) { DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor); + DBG(3, "Simultaneous opens are not supported"); if ((filp->f_flags & O_NONBLOCK) || (filp->f_flags & O_NDELAY)) { err = -EWOULDBLOCK; goto out; } - mutex_unlock(&cam->dev_mutex); - err = wait_event_interruptible_exclusive(cam->open, - cam->state & DEV_DISCONNECTED + DBG(2, "A blocking open() has been requested. Wait for the " + "device to be released..."); + up_read(&zc0301_dev_lock); + err = wait_event_interruptible_exclusive(cam->wait_open, + (cam->state & DEV_DISCONNECTED) || !cam->users); - if (err) { - up_read(&zc0301_disconnect); - return err; - } + down_read(&zc0301_dev_lock); + if (err) + goto out; if (cam->state & DEV_DISCONNECTED) { - up_read(&zc0301_disconnect); - return -ENODEV; + err = -ENODEV; + goto out; } - mutex_lock(&cam->dev_mutex); } - if (cam->state & DEV_MISCONFIGURED) { err = zc0301_init(cam); if (err) { @@ -711,36 +726,32 @@ static int zc0301_open(struct inode* inode, struct file* filp) DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor); out: - mutex_unlock(&cam->dev_mutex); - up_read(&zc0301_disconnect); + mutex_unlock(&cam->open_mutex); + if (err) + kref_put(&cam->kref, zc0301_release_resources); + up_read(&zc0301_dev_lock); return err; } static int zc0301_release(struct inode* inode, struct file* filp) { - struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); + struct zc0301_device* cam; - mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */ + down_write(&zc0301_dev_lock); - zc0301_stop_transfer(cam); + cam = video_get_drvdata(video_devdata(filp)); + zc0301_stop_transfer(cam); zc0301_release_buffers(cam); - - if (cam->state & DEV_DISCONNECTED) { - zc0301_release_resources(cam); - usb_put_dev(cam->usbdev); - mutex_unlock(&cam->dev_mutex); - kfree(cam); - return 0; - } - cam->users--; - wake_up_interruptible_nr(&cam->open, 1); + wake_up_interruptible_nr(&cam->wait_open, 1); DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor); - mutex_unlock(&cam->dev_mutex); + kref_put(&cam->kref, zc0301_release_resources); + + up_write(&zc0301_dev_lock); return 0; } @@ -775,7 +786,7 @@ zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) DBG(3, "Close and open the device again to choose the read " "method"); mutex_unlock(&cam->fileop_mutex); - return -EINVAL; + return -EBUSY; } if (cam->io == IO_NONE) { @@ -953,7 +964,12 @@ static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma) return -EIO; } - if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || + if (!(vma->vm_flags & (VM_WRITE | VM_READ))) { + mutex_unlock(&cam->fileop_mutex); + return -EACCES; + } + + if (cam->io != IO_MMAP || size != PAGE_ALIGN(cam->frame[0].buf.length)) { mutex_unlock(&cam->fileop_mutex); return -EINVAL; @@ -984,7 +1000,6 @@ static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma) vma->vm_ops = &zc0301_vm_ops; vma->vm_private_data = &cam->frame[i]; - zc0301_vm_open(vma); mutex_unlock(&cam->fileop_mutex); @@ -1211,7 +1226,7 @@ zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg) if (cam->frame[i].vma_use_count) { DBG(3, "VIDIOC_S_CROP failed. " "Unmap the buffers first."); - return -EINVAL; + return -EBUSY; } if (!s->set_crop) { @@ -1434,7 +1449,7 @@ zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd, if (cam->frame[i].vma_use_count) { DBG(3, "VIDIOC_S_FMT failed. " "Unmap the buffers first."); - return -EINVAL; + return -EBUSY; } if (cam->stream == STREAM_ON) @@ -1544,14 +1559,14 @@ zc0301_vidioc_reqbufs(struct zc0301_device* cam, void __user * arg) if (cam->io == IO_READ) { DBG(3, "Close and open the device again to choose the mmap " "I/O method"); - return -EINVAL; + return -EBUSY; } for (i = 0; i < cam->nbuffers; i++) if (cam->frame[i].vma_use_count) { DBG(3, "VIDIOC_REQBUFS failed. " "Previous buffers are still mapped."); - return -EINVAL; + return -EBUSY; } if (cam->stream == STREAM_ON) @@ -1699,9 +1714,6 @@ zc0301_vidioc_streamon(struct zc0301_device* cam, void __user * arg) if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) return -EINVAL; - if (list_empty(&cam->inqueue)) - return -EINVAL; - cam->stream = STREAM_ON; DBG(3, "Stream on"); @@ -1949,8 +1961,6 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) goto fail; } - mutex_init(&cam->dev_mutex); - DBG(2, "ZC0301[P] Image Processor and Control Chip detected " "(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct); @@ -1982,7 +1992,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) cam->v4ldev->release = video_device_release; video_set_drvdata(cam->v4ldev, cam); - mutex_lock(&cam->dev_mutex); + init_completion(&cam->probe); err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, video_nr[dev_nr]); @@ -1992,7 +2002,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) DBG(1, "Free /dev/videoX node not found"); video_nr[dev_nr] = -1; dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0; - mutex_unlock(&cam->dev_mutex); + complete_all(&cam->probe); goto fail; } @@ -2004,8 +2014,10 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0; usb_set_intfdata(intf, cam); + kref_init(&cam->kref); + usb_get_dev(cam->usbdev); - mutex_unlock(&cam->dev_mutex); + complete_all(&cam->probe); return 0; @@ -2022,40 +2034,31 @@ fail: static void zc0301_usb_disconnect(struct usb_interface* intf) { - struct zc0301_device* cam = usb_get_intfdata(intf); - - if (!cam) - return; + struct zc0301_device* cam; - down_write(&zc0301_disconnect); + down_write(&zc0301_dev_lock); - mutex_lock(&cam->dev_mutex); + cam = usb_get_intfdata(intf); DBG(2, "Disconnecting %s...", cam->v4ldev->name); - wake_up_interruptible_all(&cam->open); - if (cam->users) { DBG(2, "Device /dev/video%d is open! Deregistration and " - "memory deallocation are deferred on close.", + "memory deallocation are deferred.", cam->v4ldev->minor); cam->state |= DEV_MISCONFIGURED; zc0301_stop_transfer(cam); cam->state |= DEV_DISCONNECTED; wake_up_interruptible(&cam->wait_frame); wake_up(&cam->wait_stream); - usb_get_dev(cam->usbdev); - } else { + } else cam->state |= DEV_DISCONNECTED; - zc0301_release_resources(cam); - } - mutex_unlock(&cam->dev_mutex); + wake_up_interruptible_all(&cam->wait_open); - if (!cam->users) - kfree(cam); + kref_put(&cam->kref, zc0301_release_resources); - up_write(&zc0301_disconnect); + up_write(&zc0301_dev_lock); } diff --git a/drivers/media/video/zc0301/zc0301_pas202bcb.c b/drivers/media/video/zc0301/zc0301_pas202bcb.c index 3efb92a0d0da..24b0dfba357e 100644 --- a/drivers/media/video/zc0301/zc0301_pas202bcb.c +++ b/drivers/media/video/zc0301/zc0301_pas202bcb.c @@ -327,6 +327,7 @@ static struct zc0301_sensor pas202bcb = { .height = 480, .pixelformat = V4L2_PIX_FMT_JPEG, .priv = 8, + .colorspace = V4L2_COLORSPACE_JPEG, }, }; diff --git a/drivers/media/video/zc0301/zc0301_pb0330.c b/drivers/media/video/zc0301/zc0301_pb0330.c index 5784b1d1491c..9519aba3612e 100644 --- a/drivers/media/video/zc0301/zc0301_pb0330.c +++ b/drivers/media/video/zc0301/zc0301_pb0330.c @@ -157,6 +157,7 @@ static struct zc0301_sensor pb0330 = { .height = 480, .pixelformat = V4L2_PIX_FMT_JPEG, .priv = 8, + .colorspace = V4L2_COLORSPACE_JPEG, }, }; diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h index 44e82cff9319..70fe6fc6cdd5 100644 --- a/drivers/media/video/zc0301/zc0301_sensor.h +++ b/drivers/media/video/zc0301/zc0301_sensor.h @@ -23,7 +23,7 @@ #define _ZC0301_SENSOR_H_ #include <linux/usb.h> -#include <linux/videodev.h> +#include <linux/videodev2.h> #include <linux/device.h> #include <linux/stddef.h> #include <linux/errno.h> diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c index cf0ed6cbb0e3..17118a490f81 100644 --- a/drivers/media/video/zoran_driver.c +++ b/drivers/media/video/zoran_driver.c @@ -183,14 +183,7 @@ static const int zoran_num_formats = (sizeof(zoran_formats) / sizeof(struct zoran_format)); // RJ: Test only - want to test BUZ_USE_HIMEM even when CONFIG_BIGPHYS_AREA is defined -#if !defined(CONFIG_BIGPHYS_AREA) -//#undef CONFIG_BIGPHYS_AREA -#define BUZ_USE_HIMEM -#endif -#if defined(CONFIG_BIGPHYS_AREA) -# include <linux/bigphysarea.h> -#endif extern int *zr_debug; @@ -250,7 +243,6 @@ static void jpg_fbuffer_free(struct file *file); * Linux with the necessary memory left over). */ -#if defined(BUZ_USE_HIMEM) && !defined(CONFIG_BIGPHYS_AREA) static unsigned long get_high_mem (unsigned long size) { @@ -314,7 +306,6 @@ get_high_mem (unsigned long size) return hi_mem_ph; } -#endif static int v4l_fbuffer_alloc (struct file *file) @@ -323,9 +314,7 @@ v4l_fbuffer_alloc (struct file *file) struct zoran *zr = fh->zr; int i, off; unsigned char *mem; -#if defined(BUZ_USE_HIMEM) && !defined(CONFIG_BIGPHYS_AREA) unsigned long pmem = 0; -#endif /* we might have old buffers lying around... */ if (fh->v4l_buffers.ready_to_be_freed) { @@ -369,39 +358,6 @@ v4l_fbuffer_alloc (struct file *file) ZR_DEVNAME(zr), i, (unsigned long) mem, virt_to_bus(mem)); } else { -#if defined(CONFIG_BIGPHYS_AREA) - /* Use bigphysarea_alloc_pages */ - - int n = - (fh->v4l_buffers.buffer_size + PAGE_SIZE - - 1) / PAGE_SIZE; - - mem = - (unsigned char *) bigphysarea_alloc_pages(n, 0, - GFP_KERNEL); - if (mem == 0) { - dprintk(1, - KERN_ERR - "%s: v4l_fbuffer_alloc() - bigphysarea_alloc_pages for V4L buf %d failed\n", - ZR_DEVNAME(zr), i); - v4l_fbuffer_free(file); - return -ENOBUFS; - } - fh->v4l_buffers.buffer[i].fbuffer = mem; - fh->v4l_buffers.buffer[i].fbuffer_phys = - virt_to_phys(mem); - fh->v4l_buffers.buffer[i].fbuffer_bus = - virt_to_bus(mem); - dprintk(4, - KERN_INFO - "%s: Bigphysarea frame %d mem 0x%x (bus: 0x%x)\n", - ZR_DEVNAME(zr), i, (unsigned) mem, - (unsigned) virt_to_bus(mem)); - - /* Zero out the allocated memory */ - memset(fh->v4l_buffers.buffer[i].fbuffer, 0, - fh->v4l_buffers.buffer_size); -#elif defined(BUZ_USE_HIMEM) /* Use high memory which has been left at boot time */ @@ -441,20 +397,6 @@ v4l_fbuffer_alloc (struct file *file) fh->v4l_buffers.buffer[i].fbuffer_bus = pmem + i * fh->v4l_buffers.buffer_size; } -#else - /* No bigphysarea present, usage of high memory disabled, - * but user wants buffers of more than MAX_KMALLOC_MEM */ - dprintk(1, - KERN_ERR - "%s: v4l_fbuffer_alloc() - no bigphysarea_patch present, usage of high memory disabled,\n", - ZR_DEVNAME(zr)); - dprintk(1, - KERN_ERR - "%s: v4l_fbuffer_alloc() - sorry, could not allocate %d V4L buffers of size %d KB.\n", - ZR_DEVNAME(zr), fh->v4l_buffers.num_buffers, - fh->v4l_buffers.buffer_size >> 10); - return -ENOBUFS; -#endif } } @@ -485,11 +427,6 @@ v4l_fbuffer_free (struct file *file) ClearPageReserved(MAP_NR(mem + off)); kfree((void *) fh->v4l_buffers.buffer[i].fbuffer); } -#if defined(CONFIG_BIGPHYS_AREA) - else - bigphysarea_free_pages((void *) fh->v4l_buffers. - buffer[i].fbuffer); -#endif fh->v4l_buffers.buffer[i].fbuffer = NULL; } diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c index b5d3364c94c7..6f1892585cbb 100644 --- a/drivers/media/video/zr364xx.c +++ b/drivers/media/video/zr364xx.c @@ -92,6 +92,7 @@ static struct usb_device_id device_table[] = { {USB_DEVICE(0x0784, 0x0040), .driver_info = METHOD1 }, {USB_DEVICE(0x06d6, 0x0034), .driver_info = METHOD0 }, {USB_DEVICE(0x0a17, 0x0062), .driver_info = METHOD2 }, + {USB_DEVICE(0x06d6, 0x003b), .driver_info = METHOD0 }, {} /* Terminating entry */ }; @@ -792,6 +793,7 @@ static int zr364xx_probe(struct usb_interface *intf, { struct usb_device *udev = interface_to_usbdev(intf); struct zr364xx_camera *cam = NULL; + int err; DBG("probing..."); @@ -799,12 +801,11 @@ static int zr364xx_probe(struct usb_interface *intf, info("model %04x:%04x detected", udev->descriptor.idVendor, udev->descriptor.idProduct); - if ((cam = - kmalloc(sizeof(struct zr364xx_camera), GFP_KERNEL)) == NULL) { + cam = kzalloc(sizeof(struct zr364xx_camera), GFP_KERNEL); + if (cam == NULL) { info("cam: out of memory !"); - return -ENODEV; + return -ENOMEM; } - memset(cam, 0x00, sizeof(struct zr364xx_camera)); /* save the init method used by this camera */ cam->method = id->driver_info; @@ -812,7 +813,7 @@ static int zr364xx_probe(struct usb_interface *intf, if (cam->vdev == NULL) { info("cam->vdev: out of memory !"); kfree(cam); - return -ENODEV; + return -ENOMEM; } memcpy(cam->vdev, &zr364xx_template, sizeof(zr364xx_template)); video_set_drvdata(cam->vdev, cam); @@ -858,12 +859,13 @@ static int zr364xx_probe(struct usb_interface *intf, cam->brightness = 64; mutex_init(&cam->lock); - if (video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1) == -1) { + err = video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1); + if (err) { info("video_register_device failed"); video_device_release(cam->vdev); kfree(cam->buffer); kfree(cam); - return -ENODEV; + return err; } usb_set_intfdata(intf, cam); @@ -905,7 +907,7 @@ static struct usb_driver zr364xx_driver = { static int __init zr364xx_init(void) { int retval; - retval = usb_register(&zr364xx_driver) < 0; + retval = usb_register(&zr364xx_driver); if (retval) info("usb_register failed!"); else diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 555d594d1811..1cb22bfae750 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -33,6 +33,7 @@ #include <linux/moduleparam.h> #include <linux/stringify.h> #include <linux/stat.h> +#include <linux/log2.h> #include "ubi.h" /* Maximum length of the 'mtd=' parameter */ @@ -369,7 +370,7 @@ static int attach_by_scanning(struct ubi_device *ubi) out_wl: ubi_wl_close(ubi); out_vtbl: - kfree(ubi->vtbl); + vfree(ubi->vtbl); out_si: ubi_scan_destroy_si(si); return err; @@ -422,8 +423,7 @@ static int io_init(struct ubi_device *ubi) ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft; /* Make sure minimal I/O unit is power of 2 */ - if (ubi->min_io_size == 0 || - (ubi->min_io_size & (ubi->min_io_size - 1))) { + if (!is_power_of_2(ubi->min_io_size)) { ubi_err("bad min. I/O unit"); return -EINVAL; } @@ -593,8 +593,6 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset, if (err) goto out_detach; - ubi_devices_cnt += 1; - ubi_msg("attached mtd%d to ubi%d", ubi->mtd->index, ubi_devices_cnt); ubi_msg("MTD device name: \"%s\"", ubi->mtd->name); ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20); @@ -624,12 +622,13 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset, wake_up_process(ubi->bgt_thread); } + ubi_devices_cnt += 1; return 0; out_detach: ubi_eba_close(ubi); ubi_wl_close(ubi); - kfree(ubi->vtbl); + vfree(ubi->vtbl); out_free: kfree(ubi); out_mtd: @@ -650,7 +649,7 @@ static void detach_mtd_dev(struct ubi_device *ubi) uif_close(ubi); ubi_eba_close(ubi); ubi_wl_close(ubi); - kfree(ubi->vtbl); + vfree(ubi->vtbl); put_mtd_device(ubi->mtd); kfree(ubi_devices[ubi_num]); ubi_devices[ubi_num] = NULL; @@ -686,13 +685,6 @@ static int __init ubi_init(void) struct mtd_dev_param *p = &mtd_dev_param[i]; cond_resched(); - - if (!p->name) { - dbg_err("empty name"); - err = -EINVAL; - goto out_detach; - } - err = attach_mtd_dev(p->name, p->vid_hdr_offs, p->data_offs); if (err) goto out_detach; @@ -799,7 +791,7 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) /* Get rid of the final newline */ if (buf[len - 1] == '\n') - buf[len - 1] = 0; + buf[len - 1] = '\0'; for (i = 0; i < 3; i++) tokens[i] = strsep(&pbuf, ","); @@ -809,9 +801,6 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) return -EINVAL; } - if (tokens[0] == '\0') - return -EINVAL; - p = &mtd_dev_param[mtd_devs]; strcpy(&p->name[0], tokens[0]); diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index 6612eb79bf17..fe4da1e96c52 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c @@ -64,6 +64,7 @@ static struct ubi_device *major_to_device(int major) if (ubi_devices[i] && ubi_devices[i]->major == major) return ubi_devices[i]; BUG(); + return NULL; } /** @@ -153,7 +154,7 @@ static int vol_cdev_release(struct inode *inode, struct file *file) ubi_warn("update of volume %d not finished, volume is damaged", vol->vol_id); vol->updating = 0; - kfree(vol->upd_buf); + vfree(vol->upd_buf); } ubi_close_volume(desc); @@ -232,7 +233,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count, tbuf_size = vol->usable_leb_size; if (count < tbuf_size) tbuf_size = ALIGN(count, ubi->min_io_size); - tbuf = kmalloc(tbuf_size, GFP_KERNEL); + tbuf = vmalloc(tbuf_size); if (!tbuf) return -ENOMEM; @@ -271,7 +272,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count, len = count > tbuf_size ? tbuf_size : count; } while (count); - kfree(tbuf); + vfree(tbuf); return err ? err : count_save - count; } @@ -320,7 +321,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf, tbuf_size = vol->usable_leb_size; if (count < tbuf_size) tbuf_size = ALIGN(count, ubi->min_io_size); - tbuf = kmalloc(tbuf_size, GFP_KERNEL); + tbuf = vmalloc(tbuf_size); if (!tbuf) return -ENOMEM; @@ -355,7 +356,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf, len = count > tbuf_size ? tbuf_size : count; } - kfree(tbuf); + vfree(tbuf); return err ? err : count_save - count; } @@ -397,6 +398,7 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf, vol->corrupted = 1; } vol->checked = 1; + ubi_gluebi_updated(vol); revoke_exclusive(desc, UBI_READWRITE); } @@ -413,19 +415,7 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file, struct ubi_device *ubi = vol->ubi; void __user *argp = (void __user *)arg; - if (_IOC_NR(cmd) > VOL_CDEV_IOC_MAX_SEQ || - _IOC_TYPE(cmd) != UBI_VOL_IOC_MAGIC) - return -ENOTTY; - - if (_IOC_DIR(cmd) && _IOC_READ) - err = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd)); - else if (_IOC_DIR(cmd) && _IOC_WRITE) - err = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd)); - if (err) - return -EFAULT; - switch (cmd) { - /* Volume update command */ case UBI_IOCVOLUP: { @@ -471,7 +461,7 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file, { int32_t lnum; - err = __get_user(lnum, (__user int32_t *)argp); + err = get_user(lnum, (__user int32_t *)argp); if (err) { err = -EFAULT; break; @@ -587,17 +577,6 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, struct ubi_volume_desc *desc; void __user *argp = (void __user *)arg; - if (_IOC_NR(cmd) > UBI_CDEV_IOC_MAX_SEQ || - _IOC_TYPE(cmd) != UBI_IOC_MAGIC) - return -ENOTTY; - - if (_IOC_DIR(cmd) && _IOC_READ) - err = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd)); - else if (_IOC_DIR(cmd) && _IOC_WRITE) - err = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd)); - if (err) - return -EFAULT; - if (!capable(CAP_SYS_RESOURCE)) return -EPERM; @@ -612,7 +591,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, struct ubi_mkvol_req req; dbg_msg("create volume"); - err = __copy_from_user(&req, argp, + err = copy_from_user(&req, argp, sizeof(struct ubi_mkvol_req)); if (err) { err = -EFAULT; @@ -629,7 +608,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, if (err) break; - err = __put_user(req.vol_id, (__user int32_t *)argp); + err = put_user(req.vol_id, (__user int32_t *)argp); if (err) err = -EFAULT; @@ -642,7 +621,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, int vol_id; dbg_msg("remove volume"); - err = __get_user(vol_id, (__user int32_t *)argp); + err = get_user(vol_id, (__user int32_t *)argp); if (err) { err = -EFAULT; break; @@ -669,7 +648,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, struct ubi_rsvol_req req; dbg_msg("re-size volume"); - err = __copy_from_user(&req, argp, + err = copy_from_user(&req, argp, sizeof(struct ubi_rsvol_req)); if (err) { err = -EFAULT; @@ -707,7 +686,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, struct file_operations ubi_cdev_operations = { .owner = THIS_MODULE, .ioctl = ubi_cdev_ioctl, - .llseek = no_llseek + .llseek = no_llseek, }; /* UBI volume character device operations */ @@ -718,5 +697,5 @@ struct file_operations ubi_vol_cdev_operations = { .llseek = vol_cdev_llseek, .read = vol_cdev_read, .write = vol_cdev_write, - .ioctl = vol_cdev_ioctl + .ioctl = vol_cdev_ioctl, }; diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c index 86364221fafe..310341e5cd43 100644 --- a/drivers/mtd/ubi/debug.c +++ b/drivers/mtd/ubi/debug.c @@ -35,12 +35,12 @@ void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr) { dbg_msg("erase counter header dump:"); - dbg_msg("magic %#08x", ubi32_to_cpu(ec_hdr->magic)); + dbg_msg("magic %#08x", be32_to_cpu(ec_hdr->magic)); dbg_msg("version %d", (int)ec_hdr->version); - dbg_msg("ec %llu", (long long)ubi64_to_cpu(ec_hdr->ec)); - dbg_msg("vid_hdr_offset %d", ubi32_to_cpu(ec_hdr->vid_hdr_offset)); - dbg_msg("data_offset %d", ubi32_to_cpu(ec_hdr->data_offset)); - dbg_msg("hdr_crc %#08x", ubi32_to_cpu(ec_hdr->hdr_crc)); + dbg_msg("ec %llu", (long long)be64_to_cpu(ec_hdr->ec)); + dbg_msg("vid_hdr_offset %d", be32_to_cpu(ec_hdr->vid_hdr_offset)); + dbg_msg("data_offset %d", be32_to_cpu(ec_hdr->data_offset)); + dbg_msg("hdr_crc %#08x", be32_to_cpu(ec_hdr->hdr_crc)); dbg_msg("erase counter header hexdump:"); ubi_dbg_hexdump(ec_hdr, UBI_EC_HDR_SIZE); } @@ -52,20 +52,20 @@ void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr) void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr) { dbg_msg("volume identifier header dump:"); - dbg_msg("magic %08x", ubi32_to_cpu(vid_hdr->magic)); + dbg_msg("magic %08x", be32_to_cpu(vid_hdr->magic)); dbg_msg("version %d", (int)vid_hdr->version); dbg_msg("vol_type %d", (int)vid_hdr->vol_type); dbg_msg("copy_flag %d", (int)vid_hdr->copy_flag); dbg_msg("compat %d", (int)vid_hdr->compat); - dbg_msg("vol_id %d", ubi32_to_cpu(vid_hdr->vol_id)); - dbg_msg("lnum %d", ubi32_to_cpu(vid_hdr->lnum)); - dbg_msg("leb_ver %u", ubi32_to_cpu(vid_hdr->leb_ver)); - dbg_msg("data_size %d", ubi32_to_cpu(vid_hdr->data_size)); - dbg_msg("used_ebs %d", ubi32_to_cpu(vid_hdr->used_ebs)); - dbg_msg("data_pad %d", ubi32_to_cpu(vid_hdr->data_pad)); + dbg_msg("vol_id %d", be32_to_cpu(vid_hdr->vol_id)); + dbg_msg("lnum %d", be32_to_cpu(vid_hdr->lnum)); + dbg_msg("leb_ver %u", be32_to_cpu(vid_hdr->leb_ver)); + dbg_msg("data_size %d", be32_to_cpu(vid_hdr->data_size)); + dbg_msg("used_ebs %d", be32_to_cpu(vid_hdr->used_ebs)); + dbg_msg("data_pad %d", be32_to_cpu(vid_hdr->data_pad)); dbg_msg("sqnum %llu", - (unsigned long long)ubi64_to_cpu(vid_hdr->sqnum)); - dbg_msg("hdr_crc %08x", ubi32_to_cpu(vid_hdr->hdr_crc)); + (unsigned long long)be64_to_cpu(vid_hdr->sqnum)); + dbg_msg("hdr_crc %08x", be32_to_cpu(vid_hdr->hdr_crc)); dbg_msg("volume identifier header hexdump:"); } @@ -91,7 +91,7 @@ void ubi_dbg_dump_vol_info(const struct ubi_volume *vol) if (vol->name_len <= UBI_VOL_NAME_MAX && strnlen(vol->name, vol->name_len + 1) == vol->name_len) { - dbg_msg("name %s", vol->name); + dbg_msg("name %s", vol->name); } else { dbg_msg("the 1st 5 characters of the name: %c%c%c%c%c", vol->name[0], vol->name[1], vol->name[2], @@ -106,30 +106,30 @@ void ubi_dbg_dump_vol_info(const struct ubi_volume *vol) */ void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx) { - int name_len = ubi16_to_cpu(r->name_len); + int name_len = be16_to_cpu(r->name_len); dbg_msg("volume table record %d dump:", idx); - dbg_msg("reserved_pebs %d", ubi32_to_cpu(r->reserved_pebs)); - dbg_msg("alignment %d", ubi32_to_cpu(r->alignment)); - dbg_msg("data_pad %d", ubi32_to_cpu(r->data_pad)); + dbg_msg("reserved_pebs %d", be32_to_cpu(r->reserved_pebs)); + dbg_msg("alignment %d", be32_to_cpu(r->alignment)); + dbg_msg("data_pad %d", be32_to_cpu(r->data_pad)); dbg_msg("vol_type %d", (int)r->vol_type); dbg_msg("upd_marker %d", (int)r->upd_marker); dbg_msg("name_len %d", name_len); if (r->name[0] == '\0') { - dbg_msg("name NULL"); + dbg_msg("name NULL"); return; } if (name_len <= UBI_VOL_NAME_MAX && strnlen(&r->name[0], name_len + 1) == name_len) { - dbg_msg("name %s", &r->name[0]); + dbg_msg("name %s", &r->name[0]); } else { dbg_msg("1st 5 characters of the name: %c%c%c%c%c", r->name[0], r->name[1], r->name[2], r->name[3], r->name[4]); } - dbg_msg("crc %#08x", ubi32_to_cpu(r->crc)); + dbg_msg("crc %#08x", be32_to_cpu(r->crc)); } /** diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h index f816ad9a36c0..ff8f39548cd8 100644 --- a/drivers/mtd/ubi/debug.h +++ b/drivers/mtd/ubi/debug.h @@ -52,7 +52,6 @@ struct ubi_scan_volume; struct ubi_scan_leb; struct ubi_mkvol_req; -void ubi_dbg_print(int type, const char *func, const char *fmt, ...); void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr); void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr); void ubi_dbg_dump_vol_info(const struct ubi_volume *vol); @@ -66,7 +65,6 @@ void ubi_dbg_hexdump(const void *buf, int size); #define dbg_msg(fmt, ...) ({}) #define ubi_dbg_dump_stack() ({}) -#define ubi_dbg_print(func, fmt, ...) ({}) #define ubi_dbg_dump_ec_hdr(ec_hdr) ({}) #define ubi_dbg_dump_vid_hdr(vid_hdr) ({}) #define ubi_dbg_dump_vol_info(vol) ({}) diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 7c6b223b3f8a..8aff9385613f 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -425,10 +425,10 @@ retry: } else if (err == UBI_IO_BITFLIPS) scrub = 1; - ubi_assert(lnum < ubi32_to_cpu(vid_hdr->used_ebs)); - ubi_assert(len == ubi32_to_cpu(vid_hdr->data_size)); + ubi_assert(lnum < be32_to_cpu(vid_hdr->used_ebs)); + ubi_assert(len == be32_to_cpu(vid_hdr->data_size)); - crc = ubi32_to_cpu(vid_hdr->data_crc); + crc = be32_to_cpu(vid_hdr->data_crc); ubi_free_vid_hdr(ubi, vid_hdr); } @@ -518,13 +518,13 @@ retry: goto out_put; } - vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi)); + vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr); if (err) goto write_error; data_size = offset + len; - new_buf = kmalloc(data_size, GFP_KERNEL); + new_buf = vmalloc(data_size); if (!new_buf) { err = -ENOMEM; goto out_put; @@ -535,7 +535,7 @@ retry: if (offset > 0) { err = ubi_io_read_data(ubi, new_buf, pnum, 0, offset); if (err && err != UBI_IO_BITFLIPS) { - kfree(new_buf); + vfree(new_buf); goto out_put; } } @@ -544,11 +544,11 @@ retry: err = ubi_io_write_data(ubi, new_buf, new_pnum, 0, data_size); if (err) { - kfree(new_buf); + vfree(new_buf); goto write_error; } - kfree(new_buf); + vfree(new_buf); ubi_free_vid_hdr(ubi, vid_hdr); vol->eba_tbl[lnum] = new_pnum; @@ -634,11 +634,11 @@ int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum, } vid_hdr->vol_type = UBI_VID_DYNAMIC; - vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi)); - vid_hdr->vol_id = cpu_to_ubi32(vol_id); - vid_hdr->lnum = cpu_to_ubi32(lnum); + vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); + vid_hdr->vol_id = cpu_to_be32(vol_id); + vid_hdr->lnum = cpu_to_be32(lnum); vid_hdr->compat = ubi_get_compat(ubi, vol_id); - vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad); + vid_hdr->data_pad = cpu_to_be32(vol->data_pad); retry: pnum = ubi_wl_get_peb(ubi, dtype); @@ -692,7 +692,7 @@ write_error: return err; } - vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi)); + vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); ubi_msg("try another PEB"); goto retry; } @@ -748,17 +748,17 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum, return err; } - vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi)); - vid_hdr->vol_id = cpu_to_ubi32(vol_id); - vid_hdr->lnum = cpu_to_ubi32(lnum); + vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); + vid_hdr->vol_id = cpu_to_be32(vol_id); + vid_hdr->lnum = cpu_to_be32(lnum); vid_hdr->compat = ubi_get_compat(ubi, vol_id); - vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad); + vid_hdr->data_pad = cpu_to_be32(vol->data_pad); crc = crc32(UBI_CRC32_INIT, buf, data_size); vid_hdr->vol_type = UBI_VID_STATIC; - vid_hdr->data_size = cpu_to_ubi32(data_size); - vid_hdr->used_ebs = cpu_to_ubi32(used_ebs); - vid_hdr->data_crc = cpu_to_ubi32(crc); + vid_hdr->data_size = cpu_to_be32(data_size); + vid_hdr->used_ebs = cpu_to_be32(used_ebs); + vid_hdr->data_crc = cpu_to_be32(crc); retry: pnum = ubi_wl_get_peb(ubi, dtype); @@ -813,7 +813,7 @@ write_error: return err; } - vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi)); + vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); ubi_msg("try another PEB"); goto retry; } @@ -854,17 +854,17 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum, return err; } - vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi)); - vid_hdr->vol_id = cpu_to_ubi32(vol_id); - vid_hdr->lnum = cpu_to_ubi32(lnum); + vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); + vid_hdr->vol_id = cpu_to_be32(vol_id); + vid_hdr->lnum = cpu_to_be32(lnum); vid_hdr->compat = ubi_get_compat(ubi, vol_id); - vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad); + vid_hdr->data_pad = cpu_to_be32(vol->data_pad); crc = crc32(UBI_CRC32_INIT, buf, len); - vid_hdr->vol_type = UBI_VID_STATIC; - vid_hdr->data_size = cpu_to_ubi32(len); + vid_hdr->vol_type = UBI_VID_DYNAMIC; + vid_hdr->data_size = cpu_to_be32(len); vid_hdr->copy_flag = 1; - vid_hdr->data_crc = cpu_to_ubi32(crc); + vid_hdr->data_crc = cpu_to_be32(crc); retry: pnum = ubi_wl_get_peb(ubi, dtype); @@ -891,11 +891,13 @@ retry: goto write_error; } - err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1); - if (err) { - ubi_free_vid_hdr(ubi, vid_hdr); - leb_write_unlock(ubi, vol_id, lnum); - return err; + if (vol->eba_tbl[lnum] >= 0) { + err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1); + if (err) { + ubi_free_vid_hdr(ubi, vid_hdr); + leb_write_unlock(ubi, vol_id, lnum); + return err; + } } vol->eba_tbl[lnum] = pnum; @@ -924,7 +926,7 @@ write_error: return err; } - vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi)); + vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); ubi_msg("try another PEB"); goto retry; } @@ -965,19 +967,19 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, uint32_t crc; void *buf, *buf1 = NULL; - vol_id = ubi32_to_cpu(vid_hdr->vol_id); - lnum = ubi32_to_cpu(vid_hdr->lnum); + vol_id = be32_to_cpu(vid_hdr->vol_id); + lnum = be32_to_cpu(vid_hdr->lnum); dbg_eba("copy LEB %d:%d, PEB %d to PEB %d", vol_id, lnum, from, to); if (vid_hdr->vol_type == UBI_VID_STATIC) { - data_size = ubi32_to_cpu(vid_hdr->data_size); + data_size = be32_to_cpu(vid_hdr->data_size); aldata_size = ALIGN(data_size, ubi->min_io_size); } else data_size = aldata_size = - ubi->leb_size - ubi32_to_cpu(vid_hdr->data_pad); + ubi->leb_size - be32_to_cpu(vid_hdr->data_pad); - buf = kmalloc(aldata_size, GFP_KERNEL); + buf = vmalloc(aldata_size); if (!buf) return -ENOMEM; @@ -987,7 +989,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, */ err = leb_write_lock(ubi, vol_id, lnum); if (err) { - kfree(buf); + vfree(buf); return err; } @@ -1054,10 +1056,10 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, */ if (data_size > 0) { vid_hdr->copy_flag = 1; - vid_hdr->data_size = cpu_to_ubi32(data_size); - vid_hdr->data_crc = cpu_to_ubi32(crc); + vid_hdr->data_size = cpu_to_be32(data_size); + vid_hdr->data_crc = cpu_to_be32(crc); } - vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi)); + vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); err = ubi_io_write_vid_hdr(ubi, to, vid_hdr); if (err) @@ -1082,7 +1084,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, * We've written the data and are going to read it back to make * sure it was written correctly. */ - buf1 = kmalloc(aldata_size, GFP_KERNEL); + buf1 = vmalloc(aldata_size); if (!buf1) { err = -ENOMEM; goto out_unlock; @@ -1111,15 +1113,15 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, vol->eba_tbl[lnum] = to; leb_write_unlock(ubi, vol_id, lnum); - kfree(buf); - kfree(buf1); + vfree(buf); + vfree(buf1); return 0; out_unlock: leb_write_unlock(ubi, vol_id, lnum); - kfree(buf); - kfree(buf1); + vfree(buf); + vfree(buf1); return err; } diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c index fc9478d605ff..41ff74c60e14 100644 --- a/drivers/mtd/ubi/gluebi.c +++ b/drivers/mtd/ubi/gluebi.c @@ -282,7 +282,6 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol) mtd->flags = MTD_WRITEABLE; mtd->writesize = ubi->min_io_size; mtd->owner = THIS_MODULE; - mtd->size = vol->usable_leb_size * vol->reserved_pebs; mtd->erasesize = vol->usable_leb_size; mtd->read = gluebi_read; mtd->write = gluebi_write; @@ -290,6 +289,15 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol) mtd->get_device = gluebi_get_device; mtd->put_device = gluebi_put_device; + /* + * In case of dynamic volume, MTD device size is just volume size. In + * case of a static volume the size is equivalent to the amount of data + * bytes, which is zero at this moment and will be changed after volume + * update. + */ + if (vol->vol_type == UBI_DYNAMIC_VOLUME) + mtd->size = vol->usable_leb_size * vol->reserved_pebs; + if (add_mtd_device(mtd)) { ubi_err("cannot not add MTD device\n"); kfree(mtd->name); @@ -321,3 +329,20 @@ int ubi_destroy_gluebi(struct ubi_volume *vol) kfree(mtd->name); return 0; } + +/** + * ubi_gluebi_updated - UBI volume was updated notifier. + * @vol: volume description object + * + * This function is called every time an UBI volume is updated. This function + * does nothing if volume @vol is dynamic, and changes MTD device size if the + * volume is static. This is needed because static volumes cannot be read past + * data they contain. + */ +void ubi_gluebi_updated(struct ubi_volume *vol) +{ + struct mtd_info *mtd = &vol->gluebi_mtd; + + if (vol->vol_type == UBI_STATIC_VOLUME) + mtd->size = vol->used_bytes; +} diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index 438914d05151..b0d8f4cede97 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -125,9 +125,9 @@ static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum, * o %UBI_IO_BITFLIPS if all the requested data were successfully read, but * correctable bit-flips were detected; this is harmless but may indicate * that this eraseblock may become bad soon (but do not have to); - * o %-EBADMSG if the MTD subsystem reported about data data integrity - * problems, for example it can me an ECC error in case of NAND; this most - * probably means that the data is corrupted; + * o %-EBADMSG if the MTD subsystem reported about data integrity problems, for + * example it can be an ECC error in case of NAND; this most probably means + * that the data is corrupted; * o %-EIO if some I/O error occurred; * o other negative error codes in case of other errors. */ @@ -298,7 +298,7 @@ retry: memset(&ei, 0, sizeof(struct erase_info)); ei.mtd = ubi->mtd; - ei.addr = pnum * ubi->peb_size; + ei.addr = (loff_t)pnum * ubi->peb_size; ei.len = ubi->peb_size; ei.callback = erase_callback; ei.priv = (unsigned long)&wq; @@ -382,7 +382,7 @@ static int torture_peb(const struct ubi_device *ubi, int pnum) void *buf; int err, i, patt_count; - buf = kmalloc(ubi->peb_size, GFP_KERNEL); + buf = vmalloc(ubi->peb_size); if (!buf) return -ENOMEM; @@ -437,7 +437,7 @@ out: * physical eraseblock which means something is wrong with it. */ err = -EIO; - kfree(buf); + vfree(buf); return err; } @@ -557,9 +557,9 @@ static int validate_ec_hdr(const struct ubi_device *ubi, long long ec; int vid_hdr_offset, leb_start; - ec = ubi64_to_cpu(ec_hdr->ec); - vid_hdr_offset = ubi32_to_cpu(ec_hdr->vid_hdr_offset); - leb_start = ubi32_to_cpu(ec_hdr->data_offset); + ec = be64_to_cpu(ec_hdr->ec); + vid_hdr_offset = be32_to_cpu(ec_hdr->vid_hdr_offset); + leb_start = be32_to_cpu(ec_hdr->data_offset); if (ec_hdr->version != UBI_VERSION) { ubi_err("node with incompatible UBI version found: " @@ -640,7 +640,7 @@ int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum, read_err = err; } - magic = ubi32_to_cpu(ec_hdr->magic); + magic = be32_to_cpu(ec_hdr->magic); if (magic != UBI_EC_HDR_MAGIC) { /* * The magic field is wrong. Let's check if we have read all @@ -684,7 +684,7 @@ int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum, } crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC); - hdr_crc = ubi32_to_cpu(ec_hdr->hdr_crc); + hdr_crc = be32_to_cpu(ec_hdr->hdr_crc); if (hdr_crc != crc) { if (verbose) { @@ -729,12 +729,12 @@ int ubi_io_write_ec_hdr(const struct ubi_device *ubi, int pnum, dbg_io("write EC header to PEB %d", pnum); ubi_assert(pnum >= 0 && pnum < ubi->peb_count); - ec_hdr->magic = cpu_to_ubi32(UBI_EC_HDR_MAGIC); + ec_hdr->magic = cpu_to_be32(UBI_EC_HDR_MAGIC); ec_hdr->version = UBI_VERSION; - ec_hdr->vid_hdr_offset = cpu_to_ubi32(ubi->vid_hdr_offset); - ec_hdr->data_offset = cpu_to_ubi32(ubi->leb_start); + ec_hdr->vid_hdr_offset = cpu_to_be32(ubi->vid_hdr_offset); + ec_hdr->data_offset = cpu_to_be32(ubi->leb_start); crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC); - ec_hdr->hdr_crc = cpu_to_ubi32(crc); + ec_hdr->hdr_crc = cpu_to_be32(crc); err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr); if (err) @@ -757,13 +757,13 @@ static int validate_vid_hdr(const struct ubi_device *ubi, { int vol_type = vid_hdr->vol_type; int copy_flag = vid_hdr->copy_flag; - int vol_id = ubi32_to_cpu(vid_hdr->vol_id); - int lnum = ubi32_to_cpu(vid_hdr->lnum); + int vol_id = be32_to_cpu(vid_hdr->vol_id); + int lnum = be32_to_cpu(vid_hdr->lnum); int compat = vid_hdr->compat; - int data_size = ubi32_to_cpu(vid_hdr->data_size); - int used_ebs = ubi32_to_cpu(vid_hdr->used_ebs); - int data_pad = ubi32_to_cpu(vid_hdr->data_pad); - int data_crc = ubi32_to_cpu(vid_hdr->data_crc); + int data_size = be32_to_cpu(vid_hdr->data_size); + int used_ebs = be32_to_cpu(vid_hdr->used_ebs); + int data_pad = be32_to_cpu(vid_hdr->data_pad); + int data_crc = be32_to_cpu(vid_hdr->data_crc); int usable_leb_size = ubi->leb_size - data_pad; if (copy_flag != 0 && copy_flag != 1) { @@ -914,7 +914,7 @@ int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum, read_err = err; } - magic = ubi32_to_cpu(vid_hdr->magic); + magic = be32_to_cpu(vid_hdr->magic); if (magic != UBI_VID_HDR_MAGIC) { /* * If we have read all 0xFF bytes, the VID header probably does @@ -957,7 +957,7 @@ int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum, } crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC); - hdr_crc = ubi32_to_cpu(vid_hdr->hdr_crc); + hdr_crc = be32_to_cpu(vid_hdr->hdr_crc); if (hdr_crc != crc) { if (verbose) { @@ -1007,10 +1007,10 @@ int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum, if (err) return err > 0 ? -EINVAL: err; - vid_hdr->magic = cpu_to_ubi32(UBI_VID_HDR_MAGIC); + vid_hdr->magic = cpu_to_be32(UBI_VID_HDR_MAGIC); vid_hdr->version = UBI_VERSION; crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC); - vid_hdr->hdr_crc = cpu_to_ubi32(crc); + vid_hdr->hdr_crc = cpu_to_be32(crc); err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr); if (err) @@ -1060,7 +1060,7 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum, int err; uint32_t magic; - magic = ubi32_to_cpu(ec_hdr->magic); + magic = be32_to_cpu(ec_hdr->magic); if (magic != UBI_EC_HDR_MAGIC) { ubi_err("bad magic %#08x, must be %#08x", magic, UBI_EC_HDR_MAGIC); @@ -1105,7 +1105,7 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum) goto exit; crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC); - hdr_crc = ubi32_to_cpu(ec_hdr->hdr_crc); + hdr_crc = be32_to_cpu(ec_hdr->hdr_crc); if (hdr_crc != crc) { ubi_err("bad CRC, calculated %#08x, read %#08x", crc, hdr_crc); ubi_err("paranoid check failed for PEB %d", pnum); @@ -1137,7 +1137,7 @@ static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum, int err; uint32_t magic; - magic = ubi32_to_cpu(vid_hdr->magic); + magic = be32_to_cpu(vid_hdr->magic); if (magic != UBI_VID_HDR_MAGIC) { ubi_err("bad VID header magic %#08x at PEB %d, must be %#08x", magic, pnum, UBI_VID_HDR_MAGIC); @@ -1187,7 +1187,7 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum) goto exit; crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC); - hdr_crc = ubi32_to_cpu(vid_hdr->hdr_crc); + hdr_crc = be32_to_cpu(vid_hdr->hdr_crc); if (hdr_crc != crc) { ubi_err("bad VID header CRC at PEB %d, calculated %#08x, " "read %#08x", pnum, crc, hdr_crc); @@ -1224,9 +1224,10 @@ static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum, void *buf; loff_t addr = (loff_t)pnum * ubi->peb_size + offset; - buf = kzalloc(len, GFP_KERNEL); + buf = vmalloc(len); if (!buf) return -ENOMEM; + memset(buf, 0, len); err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf); if (err && err != -EUCLEAN) { @@ -1242,7 +1243,7 @@ static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum, goto fail; } - kfree(buf); + vfree(buf); return 0; fail: @@ -1252,7 +1253,7 @@ fail: err = 1; error: ubi_dbg_dump_stack(); - kfree(buf); + vfree(buf); return err; } diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c index d352c4575c3d..4a458e83e4e9 100644 --- a/drivers/mtd/ubi/kapi.c +++ b/drivers/mtd/ubi/kapi.c @@ -37,14 +37,9 @@ int ubi_get_device_info(int ubi_num, struct ubi_device_info *di) { const struct ubi_device *ubi; - if (!try_module_get(THIS_MODULE)) - return -ENODEV; - if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || - !ubi_devices[ubi_num]) { - module_put(THIS_MODULE); + !ubi_devices[ubi_num]) return -ENODEV; - } ubi = ubi_devices[ubi_num]; di->ubi_num = ubi->ubi_num; @@ -52,7 +47,6 @@ int ubi_get_device_info(int ubi_num, struct ubi_device_info *di) di->min_io_size = ubi->min_io_size; di->ro_mode = ubi->ro_mode; di->cdev = MKDEV(ubi->major, 0); - module_put(THIS_MODULE); return 0; } EXPORT_SYMBOL_GPL(ubi_get_device_info); @@ -319,9 +313,14 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset, offset + len > vol->usable_leb_size) return -EINVAL; - if (vol->vol_type == UBI_STATIC_VOLUME && lnum == vol->used_ebs - 1 && - offset + len > vol->last_eb_bytes) - return -EINVAL; + if (vol->vol_type == UBI_STATIC_VOLUME) { + if (vol->used_ebs == 0) + /* Empty static UBI volume */ + return 0; + if (lnum == vol->used_ebs - 1 && + offset + len > vol->last_eb_bytes) + return -EINVAL; + } if (vol->upd_marker) return -EBADF; diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c index 38d4e6757dc7..9e2338c8e2cf 100644 --- a/drivers/mtd/ubi/misc.c +++ b/drivers/mtd/ubi/misc.c @@ -67,7 +67,7 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id) if (vol->vol_type != UBI_STATIC_VOLUME) return 0; - buf = kmalloc(vol->usable_leb_size, GFP_KERNEL); + buf = vmalloc(vol->usable_leb_size); if (!buf) return -ENOMEM; @@ -87,7 +87,7 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id) } } - kfree(buf); + vfree(buf); return err; } diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index 473f3200b868..94ee54934411 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -24,7 +24,7 @@ * This unit is responsible for scanning the flash media, checking UBI * headers and providing complete information about the UBI flash image. * - * The scanning information is reoresented by a &struct ubi_scan_info' object. + * The scanning information is represented by a &struct ubi_scan_info' object. * Information about found volumes is represented by &struct ubi_scan_volume * objects which are kept in volume RB-tree with root at the @volumes field. * The RB-tree is indexed by the volume ID. @@ -55,8 +55,19 @@ static int paranoid_check_si(const struct ubi_device *ubi, static struct ubi_ec_hdr *ech; static struct ubi_vid_hdr *vidh; -int ubi_scan_add_to_list(struct ubi_scan_info *si, int pnum, int ec, - struct list_head *list) +/** + * add_to_list - add physical eraseblock to a list. + * @si: scanning information + * @pnum: physical eraseblock number to add + * @ec: erase counter of the physical eraseblock + * @list: the list to add to + * + * This function adds physical eraseblock @pnum to free, erase, corrupted or + * alien lists. Returns zero in case of success and a negative error code in + * case of failure. + */ +static int add_to_list(struct ubi_scan_info *si, int pnum, int ec, + struct list_head *list) { struct ubi_scan_leb *seb; @@ -121,9 +132,9 @@ static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr, const struct ubi_scan_volume *sv, int pnum) { int vol_type = vid_hdr->vol_type; - int vol_id = ubi32_to_cpu(vid_hdr->vol_id); - int used_ebs = ubi32_to_cpu(vid_hdr->used_ebs); - int data_pad = ubi32_to_cpu(vid_hdr->data_pad); + int vol_id = be32_to_cpu(vid_hdr->vol_id); + int used_ebs = be32_to_cpu(vid_hdr->used_ebs); + int data_pad = be32_to_cpu(vid_hdr->data_pad); if (sv->leb_count != 0) { int sv_vol_type; @@ -189,7 +200,7 @@ static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id, struct ubi_scan_volume *sv; struct rb_node **p = &si->volumes.rb_node, *parent = NULL; - ubi_assert(vol_id == ubi32_to_cpu(vid_hdr->vol_id)); + ubi_assert(vol_id == be32_to_cpu(vid_hdr->vol_id)); /* Walk the volume RB-tree to look if this volume is already present */ while (*p) { @@ -211,11 +222,10 @@ static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id, return ERR_PTR(-ENOMEM); sv->highest_lnum = sv->leb_count = 0; - si->max_sqnum = 0; sv->vol_id = vol_id; sv->root = RB_ROOT; - sv->used_ebs = ubi32_to_cpu(vid_hdr->used_ebs); - sv->data_pad = ubi32_to_cpu(vid_hdr->data_pad); + sv->used_ebs = be32_to_cpu(vid_hdr->used_ebs); + sv->data_pad = be32_to_cpu(vid_hdr->data_pad); sv->compat = vid_hdr->compat; sv->vol_type = vid_hdr->vol_type == UBI_VID_DYNAMIC ? UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME; @@ -257,10 +267,10 @@ static int compare_lebs(const struct ubi_device *ubi, int len, err, second_is_newer, bitflips = 0, corrupted = 0; uint32_t data_crc, crc; struct ubi_vid_hdr *vidh = NULL; - unsigned long long sqnum2 = ubi64_to_cpu(vid_hdr->sqnum); + unsigned long long sqnum2 = be64_to_cpu(vid_hdr->sqnum); if (seb->sqnum == 0 && sqnum2 == 0) { - long long abs, v1 = seb->leb_ver, v2 = ubi32_to_cpu(vid_hdr->leb_ver); + long long abs, v1 = seb->leb_ver, v2 = be32_to_cpu(vid_hdr->leb_ver); /* * UBI constantly increases the logical eraseblock version @@ -344,8 +354,8 @@ static int compare_lebs(const struct ubi_device *ubi, /* Read the data of the copy and check the CRC */ - len = ubi32_to_cpu(vid_hdr->data_size); - buf = kmalloc(len, GFP_KERNEL); + len = be32_to_cpu(vid_hdr->data_size); + buf = vmalloc(len); if (!buf) { err = -ENOMEM; goto out_free_vidh; @@ -355,7 +365,7 @@ static int compare_lebs(const struct ubi_device *ubi, if (err && err != UBI_IO_BITFLIPS) goto out_free_buf; - data_crc = ubi32_to_cpu(vid_hdr->data_crc); + data_crc = be32_to_cpu(vid_hdr->data_crc); crc = crc32(UBI_CRC32_INIT, buf, len); if (crc != data_crc) { dbg_bld("PEB %d CRC error: calculated %#08x, must be %#08x", @@ -368,7 +378,7 @@ static int compare_lebs(const struct ubi_device *ubi, bitflips = !!err; } - kfree(buf); + vfree(buf); ubi_free_vid_hdr(ubi, vidh); if (second_is_newer) @@ -379,7 +389,7 @@ static int compare_lebs(const struct ubi_device *ubi, return second_is_newer | (bitflips << 1) | (corrupted << 2); out_free_buf: - kfree(buf); + vfree(buf); out_free_vidh: ubi_free_vid_hdr(ubi, vidh); ubi_assert(err < 0); @@ -396,8 +406,12 @@ out_free_vidh: * @vid_hdr: the volume identifier header * @bitflips: if bit-flips were detected when this physical eraseblock was read * - * This function returns zero in case of success and a negative error code in - * case of failure. + * This function adds information about a used physical eraseblock to the + * 'used' tree of the corresponding volume. The function is rather complex + * because it has to handle cases when this is not the first physical + * eraseblock belonging to the same logical eraseblock, and the newer one has + * to be picked, while the older one has to be dropped. This function returns + * zero in case of success and a negative error code in case of failure. */ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si, int pnum, int ec, const struct ubi_vid_hdr *vid_hdr, @@ -410,10 +424,10 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si, struct ubi_scan_leb *seb; struct rb_node **p, *parent = NULL; - vol_id = ubi32_to_cpu(vid_hdr->vol_id); - lnum = ubi32_to_cpu(vid_hdr->lnum); - sqnum = ubi64_to_cpu(vid_hdr->sqnum); - leb_ver = ubi32_to_cpu(vid_hdr->leb_ver); + vol_id = be32_to_cpu(vid_hdr->vol_id); + lnum = be32_to_cpu(vid_hdr->lnum); + sqnum = be64_to_cpu(vid_hdr->sqnum); + leb_ver = be32_to_cpu(vid_hdr->leb_ver); dbg_bld("PEB %d, LEB %d:%d, EC %d, sqnum %llu, ver %u, bitflips %d", pnum, vol_id, lnum, ec, sqnum, leb_ver, bitflips); @@ -422,6 +436,9 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si, if (IS_ERR(sv) < 0) return PTR_ERR(sv); + if (si->max_sqnum < sqnum) + si->max_sqnum = sqnum; + /* * Walk the RB-tree of logical eraseblocks of volume @vol_id to look * if this is the first instance of this logical eraseblock or not. @@ -492,11 +509,11 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si, return err; if (cmp_res & 4) - err = ubi_scan_add_to_list(si, seb->pnum, - seb->ec, &si->corr); + err = add_to_list(si, seb->pnum, seb->ec, + &si->corr); else - err = ubi_scan_add_to_list(si, seb->pnum, - seb->ec, &si->erase); + err = add_to_list(si, seb->pnum, seb->ec, + &si->erase); if (err) return err; @@ -508,7 +525,7 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si, if (sv->highest_lnum == lnum) sv->last_data_size = - ubi32_to_cpu(vid_hdr->data_size); + be32_to_cpu(vid_hdr->data_size); return 0; } else { @@ -517,11 +534,9 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si, * previously. */ if (cmp_res & 4) - return ubi_scan_add_to_list(si, pnum, ec, - &si->corr); + return add_to_list(si, pnum, ec, &si->corr); else - return ubi_scan_add_to_list(si, pnum, ec, - &si->erase); + return add_to_list(si, pnum, ec, &si->erase); } } @@ -547,12 +562,9 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si, if (sv->highest_lnum <= lnum) { sv->highest_lnum = lnum; - sv->last_data_size = ubi32_to_cpu(vid_hdr->data_size); + sv->last_data_size = be32_to_cpu(vid_hdr->data_size); } - if (si->max_sqnum < sqnum) - si->max_sqnum = sqnum; - sv->leb_count += 1; rb_link_node(&seb->u.rb, parent, p); rb_insert_color(&seb->u.rb, &sv->root); @@ -674,7 +686,7 @@ int ubi_scan_erase_peb(const struct ubi_device *ubi, return -EINVAL; } - ec_hdr->ec = cpu_to_ubi64(ec); + ec_hdr->ec = cpu_to_be64(ec); err = ubi_io_sync_erase(ubi, pnum, 0); if (err < 0) @@ -754,7 +766,7 @@ struct ubi_scan_leb *ubi_scan_get_free_peb(const struct ubi_device *ubi, * @si: scanning information * @pnum: the physical eraseblock number * - * This function returns a zero if the physical eraseblock was succesfully + * This function returns a zero if the physical eraseblock was successfully * handled and a negative error code in case of failure. */ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum) @@ -783,8 +795,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum else if (err == UBI_IO_BITFLIPS) bitflips = 1; else if (err == UBI_IO_PEB_EMPTY) - return ubi_scan_add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, - &si->erase); + return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, &si->erase); else if (err == UBI_IO_BAD_EC_HDR) { /* * We have to also look at the VID header, possibly it is not @@ -806,7 +817,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum return -EINVAL; } - ec = ubi64_to_cpu(ech->ec); + ec = be64_to_cpu(ech->ec); if (ec > UBI_MAX_ERASECOUNTER) { /* * Erase counter overflow. The EC headers have 64 bits @@ -832,28 +843,28 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum else if (err == UBI_IO_BAD_VID_HDR || (err == UBI_IO_PEB_FREE && ec_corr)) { /* VID header is corrupted */ - err = ubi_scan_add_to_list(si, pnum, ec, &si->corr); + err = add_to_list(si, pnum, ec, &si->corr); if (err) return err; goto adjust_mean_ec; } else if (err == UBI_IO_PEB_FREE) { /* No VID header - the physical eraseblock is free */ - err = ubi_scan_add_to_list(si, pnum, ec, &si->free); + err = add_to_list(si, pnum, ec, &si->free); if (err) return err; goto adjust_mean_ec; } - vol_id = ubi32_to_cpu(vidh->vol_id); + vol_id = be32_to_cpu(vidh->vol_id); if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOL_ID) { - int lnum = ubi32_to_cpu(vidh->lnum); + int lnum = be32_to_cpu(vidh->lnum); /* Unsupported internal volume */ switch (vidh->compat) { case UBI_COMPAT_DELETE: ubi_msg("\"delete\" compatible internal volume %d:%d" " found, remove it", vol_id, lnum); - err = ubi_scan_add_to_list(si, pnum, ec, &si->corr); + err = add_to_list(si, pnum, ec, &si->corr); if (err) return err; break; @@ -868,7 +879,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum case UBI_COMPAT_PRESERVE: ubi_msg("\"preserve\" compatible internal volume %d:%d" " found", vol_id, lnum); - err = ubi_scan_add_to_list(si, pnum, ec, &si->alien); + err = add_to_list(si, pnum, ec, &si->alien); if (err) return err; si->alien_peb_count += 1; @@ -1109,7 +1120,7 @@ static int paranoid_check_si(const struct ubi_device *ubi, uint8_t *buf; /* - * At first, check that scanning information is ok. + * At first, check that scanning information is OK. */ ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) { int leb_count = 0; @@ -1249,12 +1260,12 @@ static int paranoid_check_si(const struct ubi_device *ubi, goto bad_vid_hdr; } - if (seb->sqnum != ubi64_to_cpu(vidh->sqnum)) { + if (seb->sqnum != be64_to_cpu(vidh->sqnum)) { ubi_err("bad sqnum %llu", seb->sqnum); goto bad_vid_hdr; } - if (sv->vol_id != ubi32_to_cpu(vidh->vol_id)) { + if (sv->vol_id != be32_to_cpu(vidh->vol_id)) { ubi_err("bad vol_id %d", sv->vol_id); goto bad_vid_hdr; } @@ -1264,22 +1275,22 @@ static int paranoid_check_si(const struct ubi_device *ubi, goto bad_vid_hdr; } - if (seb->lnum != ubi32_to_cpu(vidh->lnum)) { + if (seb->lnum != be32_to_cpu(vidh->lnum)) { ubi_err("bad lnum %d", seb->lnum); goto bad_vid_hdr; } - if (sv->used_ebs != ubi32_to_cpu(vidh->used_ebs)) { + if (sv->used_ebs != be32_to_cpu(vidh->used_ebs)) { ubi_err("bad used_ebs %d", sv->used_ebs); goto bad_vid_hdr; } - if (sv->data_pad != ubi32_to_cpu(vidh->data_pad)) { + if (sv->data_pad != be32_to_cpu(vidh->data_pad)) { ubi_err("bad data_pad %d", sv->data_pad); goto bad_vid_hdr; } - if (seb->leb_ver != ubi32_to_cpu(vidh->leb_ver)) { + if (seb->leb_ver != be32_to_cpu(vidh->leb_ver)) { ubi_err("bad leb_ver %u", seb->leb_ver); goto bad_vid_hdr; } @@ -1288,12 +1299,12 @@ static int paranoid_check_si(const struct ubi_device *ubi, if (!last_seb) continue; - if (sv->highest_lnum != ubi32_to_cpu(vidh->lnum)) { + if (sv->highest_lnum != be32_to_cpu(vidh->lnum)) { ubi_err("bad highest_lnum %d", sv->highest_lnum); goto bad_vid_hdr; } - if (sv->last_data_size != ubi32_to_cpu(vidh->data_size)) { + if (sv->last_data_size != be32_to_cpu(vidh->data_size)) { ubi_err("bad last_data_size %d", sv->last_data_size); goto bad_vid_hdr; } @@ -1310,8 +1321,10 @@ static int paranoid_check_si(const struct ubi_device *ubi, memset(buf, 1, ubi->peb_count); for (pnum = 0; pnum < ubi->peb_count; pnum++) { err = ubi_io_is_bad(ubi, pnum); - if (err < 0) + if (err < 0) { + kfree(buf); return err; + } else if (err) buf[pnum] = 0; } diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h index 3949f6192c76..140e82e26534 100644 --- a/drivers/mtd/ubi/scan.h +++ b/drivers/mtd/ubi/scan.h @@ -147,8 +147,6 @@ static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv, list_add_tail(&seb->u.list, list); } -int ubi_scan_add_to_list(struct ubi_scan_info *si, int pnum, int ec, - struct list_head *list); int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si, int pnum, int ec, const struct ubi_vid_hdr *vid_hdr, int bitflips); diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index feb647f108f0..5959f91be240 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -35,6 +35,7 @@ #include <linux/cdev.h> #include <linux/device.h> #include <linux/string.h> +#include <linux/vmalloc.h> #include <linux/mtd/mtd.h> #include <mtd/ubi-header.h> @@ -374,9 +375,11 @@ void ubi_calculate_reserved(struct ubi_device *ubi); #ifdef CONFIG_MTD_UBI_GLUEBI int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol); int ubi_destroy_gluebi(struct ubi_volume *vol); +void ubi_gluebi_updated(struct ubi_volume *vol); #else #define ubi_create_gluebi(ubi, vol) 0 #define ubi_destroy_gluebi(vol) 0 +#define ubi_gluebi_updated(vol) #endif /* eba.c */ diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c index 8925b977e3dc..0efc586a8328 100644 --- a/drivers/mtd/ubi/upd.c +++ b/drivers/mtd/ubi/upd.c @@ -150,7 +150,7 @@ int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes) vol->updating = 0; } - vol->upd_buf = kmalloc(ubi->leb_size, GFP_KERNEL); + vol->upd_buf = vmalloc(ubi->leb_size); if (!vol->upd_buf) return -ENOMEM; @@ -339,7 +339,7 @@ int ubi_more_update_data(struct ubi_device *ubi, int vol_id, err = ubi_wl_flush(ubi); if (err == 0) { err = to_write; - kfree(vol->upd_buf); + vfree(vol->upd_buf); vol->updating = 0; } } diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 622d0d18952c..ea0d5c825ab4 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -228,7 +228,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) for (i = 0; i < ubi->vtbl_slots; i++) if (ubi->volumes[i] && ubi->volumes[i]->name_len == req->name_len && - strcmp(ubi->volumes[i]->name, req->name) == 0) { + !strcmp(ubi->volumes[i]->name, req->name)) { dbg_err("volume \"%s\" exists (ID %d)", req->name, i); goto out_unlock; } @@ -243,7 +243,6 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) /* Reserve physical eraseblocks */ if (vol->reserved_pebs > ubi->avail_pebs) { dbg_err("not enough PEBs, only %d available", ubi->avail_pebs); - spin_unlock(&ubi->volumes_lock); err = -ENOSPC; goto out_unlock; } @@ -281,7 +280,8 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) if (vol->vol_type == UBI_DYNAMIC_VOLUME) { vol->used_ebs = vol->reserved_pebs; vol->last_eb_bytes = vol->usable_leb_size; - vol->used_bytes = vol->used_ebs * vol->usable_leb_size; + vol->used_bytes = + (long long)vol->used_ebs * vol->usable_leb_size; } else { bytes = vol->used_bytes; vol->last_eb_bytes = do_div(bytes, vol->usable_leb_size); @@ -320,10 +320,10 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) /* Fill volume table record */ memset(&vtbl_rec, 0, sizeof(struct ubi_vtbl_record)); - vtbl_rec.reserved_pebs = cpu_to_ubi32(vol->reserved_pebs); - vtbl_rec.alignment = cpu_to_ubi32(vol->alignment); - vtbl_rec.data_pad = cpu_to_ubi32(vol->data_pad); - vtbl_rec.name_len = cpu_to_ubi16(vol->name_len); + vtbl_rec.reserved_pebs = cpu_to_be32(vol->reserved_pebs); + vtbl_rec.alignment = cpu_to_be32(vol->alignment); + vtbl_rec.data_pad = cpu_to_be32(vol->data_pad); + vtbl_rec.name_len = cpu_to_be16(vol->name_len); if (vol->vol_type == UBI_DYNAMIC_VOLUME) vtbl_rec.vol_type = UBI_VID_DYNAMIC; else @@ -352,6 +352,7 @@ out_acc: spin_lock(&ubi->volumes_lock); ubi->rsvd_pebs -= vol->reserved_pebs; ubi->avail_pebs += vol->reserved_pebs; + ubi->volumes[vol_id] = NULL; out_unlock: spin_unlock(&ubi->volumes_lock); kfree(vol); @@ -368,6 +369,7 @@ out_sysfs: spin_lock(&ubi->volumes_lock); ubi->rsvd_pebs -= vol->reserved_pebs; ubi->avail_pebs += vol->reserved_pebs; + ubi->volumes[vol_id] = NULL; spin_unlock(&ubi->volumes_lock); volume_sysfs_close(vol); return err; @@ -503,7 +505,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) /* Change volume table record */ memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record)); - vtbl_rec.reserved_pebs = cpu_to_ubi32(reserved_pebs); + vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs); err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); if (err) goto out_acc; @@ -537,7 +539,8 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) if (vol->vol_type == UBI_DYNAMIC_VOLUME) { vol->used_ebs = reserved_pebs; vol->last_eb_bytes = vol->usable_leb_size; - vol->used_bytes = vol->used_ebs * vol->usable_leb_size; + vol->used_bytes = + (long long)vol->used_ebs * vol->usable_leb_size; } paranoid_check_volumes(ubi); @@ -643,21 +646,33 @@ void ubi_free_volume(struct ubi_device *ubi, int vol_id) * @ubi: UBI device description object * @vol_id: volume ID */ -static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id) +static void paranoid_check_volume(struct ubi_device *ubi, int vol_id) { int idx = vol_id2idx(ubi, vol_id); int reserved_pebs, alignment, data_pad, vol_type, name_len, upd_marker; - const struct ubi_volume *vol = ubi->volumes[idx]; + const struct ubi_volume *vol; long long n; const char *name; - reserved_pebs = ubi32_to_cpu(ubi->vtbl[vol_id].reserved_pebs); + spin_lock(&ubi->volumes_lock); + reserved_pebs = be32_to_cpu(ubi->vtbl[vol_id].reserved_pebs); + vol = ubi->volumes[idx]; if (!vol) { if (reserved_pebs) { ubi_err("no volume info, but volume exists"); goto fail; } + spin_unlock(&ubi->volumes_lock); + return; + } + + if (vol->exclusive) { + /* + * The volume may be being created at the moment, do not check + * it (e.g., it may be in the middle of ubi_create_volume(). + */ + spin_unlock(&ubi->volumes_lock); return; } @@ -726,7 +741,7 @@ static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id) goto fail; } - n = vol->used_ebs * vol->usable_leb_size; + n = (long long)vol->used_ebs * vol->usable_leb_size; if (vol->vol_type == UBI_DYNAMIC_VOLUME) { if (vol->corrupted != 0) { ubi_err("corrupted dynamic volume"); @@ -765,9 +780,9 @@ static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id) } } - alignment = ubi32_to_cpu(ubi->vtbl[vol_id].alignment); - data_pad = ubi32_to_cpu(ubi->vtbl[vol_id].data_pad); - name_len = ubi16_to_cpu(ubi->vtbl[vol_id].name_len); + alignment = be32_to_cpu(ubi->vtbl[vol_id].alignment); + data_pad = be32_to_cpu(ubi->vtbl[vol_id].data_pad); + name_len = be16_to_cpu(ubi->vtbl[vol_id].name_len); upd_marker = ubi->vtbl[vol_id].upd_marker; name = &ubi->vtbl[vol_id].name[0]; if (ubi->vtbl[vol_id].vol_type == UBI_VID_DYNAMIC) @@ -782,12 +797,14 @@ static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id) goto fail; } + spin_unlock(&ubi->volumes_lock); return; fail: - ubi_err("paranoid check failed"); + ubi_err("paranoid check failed for volume %d", vol_id); ubi_dbg_dump_vol_info(vol); ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id); + spin_unlock(&ubi->volumes_lock); BUG(); } @@ -800,10 +817,8 @@ static void paranoid_check_volumes(struct ubi_device *ubi) int i; mutex_lock(&ubi->vtbl_mutex); - spin_lock(&ubi->volumes_lock); for (i = 0; i < ubi->vtbl_slots; i++) paranoid_check_volume(ubi, i); - spin_unlock(&ubi->volumes_lock); mutex_unlock(&ubi->vtbl_mutex); } #endif diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index b6fd6bbd941e..bc5df50813d6 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -93,12 +93,9 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, vtbl_rec = &empty_vtbl_record; else { crc = crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC); - vtbl_rec->crc = cpu_to_ubi32(crc); + vtbl_rec->crc = cpu_to_be32(crc); } - dbg_msg("change record %d", idx); - ubi_dbg_dump_vtbl_record(vtbl_rec, idx); - mutex_lock(&ubi->vtbl_mutex); memcpy(&ubi->vtbl[idx], vtbl_rec, sizeof(struct ubi_vtbl_record)); for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) { @@ -141,18 +138,18 @@ static int vtbl_check(const struct ubi_device *ubi, for (i = 0; i < ubi->vtbl_slots; i++) { cond_resched(); - reserved_pebs = ubi32_to_cpu(vtbl[i].reserved_pebs); - alignment = ubi32_to_cpu(vtbl[i].alignment); - data_pad = ubi32_to_cpu(vtbl[i].data_pad); + reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs); + alignment = be32_to_cpu(vtbl[i].alignment); + data_pad = be32_to_cpu(vtbl[i].data_pad); upd_marker = vtbl[i].upd_marker; vol_type = vtbl[i].vol_type; - name_len = ubi16_to_cpu(vtbl[i].name_len); + name_len = be16_to_cpu(vtbl[i].name_len); name = &vtbl[i].name[0]; crc = crc32(UBI_CRC32_INIT, &vtbl[i], UBI_VTBL_RECORD_SIZE_CRC); - if (ubi32_to_cpu(vtbl[i].crc) != crc) { + if (be32_to_cpu(vtbl[i].crc) != crc) { ubi_err("bad CRC at record %u: %#08x, not %#08x", - i, crc, ubi32_to_cpu(vtbl[i].crc)); + i, crc, be32_to_cpu(vtbl[i].crc)); ubi_dbg_dump_vtbl_record(&vtbl[i], i); return 1; } @@ -225,8 +222,8 @@ static int vtbl_check(const struct ubi_device *ubi, /* Checks that all names are unique */ for (i = 0; i < ubi->vtbl_slots - 1; i++) { for (n = i + 1; n < ubi->vtbl_slots; n++) { - int len1 = ubi16_to_cpu(vtbl[i].name_len); - int len2 = ubi16_to_cpu(vtbl[n].name_len); + int len1 = be16_to_cpu(vtbl[i].name_len); + int len2 = be16_to_cpu(vtbl[n].name_len); if (len1 > 0 && len1 == len2 && !strncmp(vtbl[i].name, vtbl[n].name, len1)) { @@ -288,13 +285,13 @@ retry: } vid_hdr->vol_type = UBI_VID_DYNAMIC; - vid_hdr->vol_id = cpu_to_ubi32(UBI_LAYOUT_VOL_ID); + vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOL_ID); vid_hdr->compat = UBI_LAYOUT_VOLUME_COMPAT; vid_hdr->data_size = vid_hdr->used_ebs = - vid_hdr->data_pad = cpu_to_ubi32(0); - vid_hdr->lnum = cpu_to_ubi32(copy); - vid_hdr->sqnum = cpu_to_ubi64(++si->max_sqnum); - vid_hdr->leb_ver = cpu_to_ubi32(old_seb ? old_seb->leb_ver + 1: 0); + vid_hdr->data_pad = cpu_to_be32(0); + vid_hdr->lnum = cpu_to_be32(copy); + vid_hdr->sqnum = cpu_to_be64(++si->max_sqnum); + vid_hdr->leb_ver = cpu_to_be32(old_seb ? old_seb->leb_ver + 1: 0); /* The EC header is already there, write the VID header */ err = ubi_io_write_vid_hdr(ubi, new_seb->pnum, vid_hdr); @@ -317,14 +314,15 @@ retry: return err; write_error: - kfree(new_seb); - /* May be this physical eraseblock went bad, try to pick another one */ - if (++tries <= 5) { - err = ubi_scan_add_to_list(si, new_seb->pnum, new_seb->ec, - &si->corr); - if (!err) - goto retry; + if (err == -EIO && ++tries <= 5) { + /* + * Probably this physical eraseblock went bad, try to pick + * another one. + */ + list_add_tail(&new_seb->u.list, &si->corr); + goto retry; } + kfree(new_seb); out_free: ubi_free_vid_hdr(ubi, vid_hdr); return err; @@ -380,11 +378,12 @@ static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi, /* Read both LEB 0 and LEB 1 into memory */ ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) { - leb[seb->lnum] = kzalloc(ubi->vtbl_size, GFP_KERNEL); + leb[seb->lnum] = vmalloc(ubi->vtbl_size); if (!leb[seb->lnum]) { err = -ENOMEM; goto out_free; } + memset(leb[seb->lnum], 0, ubi->vtbl_size); err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0, ubi->vtbl_size); @@ -415,7 +414,7 @@ static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi, } /* Both LEB 1 and LEB 2 are OK and consistent */ - kfree(leb[1]); + vfree(leb[1]); return leb[0]; } else { /* LEB 0 is corrupted or does not exist */ @@ -436,13 +435,13 @@ static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi, goto out_free; ubi_msg("volume table was restored"); - kfree(leb[0]); + vfree(leb[0]); return leb[1]; } out_free: - kfree(leb[0]); - kfree(leb[1]); + vfree(leb[0]); + vfree(leb[1]); return ERR_PTR(err); } @@ -460,9 +459,10 @@ static struct ubi_vtbl_record *create_empty_lvol(const struct ubi_device *ubi, int i; struct ubi_vtbl_record *vtbl; - vtbl = kzalloc(ubi->vtbl_size, GFP_KERNEL); + vtbl = vmalloc(ubi->vtbl_size); if (!vtbl) return ERR_PTR(-ENOMEM); + memset(vtbl, 0, ubi->vtbl_size); for (i = 0; i < ubi->vtbl_slots; i++) memcpy(&vtbl[i], &empty_vtbl_record, UBI_VTBL_RECORD_SIZE); @@ -472,7 +472,7 @@ static struct ubi_vtbl_record *create_empty_lvol(const struct ubi_device *ubi, err = create_vtbl(ubi, si, i, vtbl); if (err) { - kfree(vtbl); + vfree(vtbl); return ERR_PTR(err); } } @@ -500,19 +500,19 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si, for (i = 0; i < ubi->vtbl_slots; i++) { cond_resched(); - if (ubi32_to_cpu(vtbl[i].reserved_pebs) == 0) + if (be32_to_cpu(vtbl[i].reserved_pebs) == 0) continue; /* Empty record */ vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL); if (!vol) return -ENOMEM; - vol->reserved_pebs = ubi32_to_cpu(vtbl[i].reserved_pebs); - vol->alignment = ubi32_to_cpu(vtbl[i].alignment); - vol->data_pad = ubi32_to_cpu(vtbl[i].data_pad); + vol->reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs); + vol->alignment = be32_to_cpu(vtbl[i].alignment); + vol->data_pad = be32_to_cpu(vtbl[i].data_pad); vol->vol_type = vtbl[i].vol_type == UBI_VID_DYNAMIC ? UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME; - vol->name_len = ubi16_to_cpu(vtbl[i].name_len); + vol->name_len = be16_to_cpu(vtbl[i].name_len); vol->usable_leb_size = ubi->leb_size - vol->data_pad; memcpy(vol->name, vtbl[i].name, vol->name_len); vol->name[vol->name_len] = '\0'; @@ -531,7 +531,8 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si, if (vol->vol_type == UBI_DYNAMIC_VOLUME) { vol->used_ebs = vol->reserved_pebs; vol->last_eb_bytes = vol->usable_leb_size; - vol->used_bytes = vol->used_ebs * vol->usable_leb_size; + vol->used_bytes = + (long long)vol->used_ebs * vol->usable_leb_size; continue; } @@ -561,7 +562,8 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si, } vol->used_ebs = sv->used_ebs; - vol->used_bytes = (vol->used_ebs - 1) * vol->usable_leb_size; + vol->used_bytes = + (long long)(vol->used_ebs - 1) * vol->usable_leb_size; vol->used_bytes += sv->last_data_size; vol->last_eb_bytes = sv->last_data_size; } @@ -578,7 +580,8 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si, vol->usable_leb_size = ubi->leb_size; vol->used_ebs = vol->reserved_pebs; vol->last_eb_bytes = vol->reserved_pebs; - vol->used_bytes = vol->used_ebs * (ubi->leb_size - vol->data_pad); + vol->used_bytes = + (long long)vol->used_ebs * (ubi->leb_size - vol->data_pad); vol->vol_id = UBI_LAYOUT_VOL_ID; ubi_assert(!ubi->volumes[i]); @@ -718,7 +721,7 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si) int i, err; struct ubi_scan_volume *sv; - empty_vtbl_record.crc = cpu_to_ubi32(0xf116c36b); + empty_vtbl_record.crc = cpu_to_be32(0xf116c36b); /* * The number of supported volumes is limited by the eraseblock size @@ -783,7 +786,7 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si) return 0; out_free: - kfree(ubi->vtbl); + vfree(ubi->vtbl); for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) if (ubi->volumes[i]) { kfree(ubi->volumes[i]); diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index ab2174a56bc2..9de953762097 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -667,7 +667,7 @@ static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int tortur dbg_wl("erased PEB %d, new EC %llu", e->pnum, ec); - ec_hdr->ec = cpu_to_ubi64(ec); + ec_hdr->ec = cpu_to_be64(ec); err = ubi_io_write_ec_hdr(ubi, e->pnum, ec_hdr); if (err) @@ -1060,9 +1060,8 @@ out_unlock: static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, int cancel) { - int err; struct ubi_wl_entry *e = wl_wrk->e; - int pnum = e->pnum; + int pnum = e->pnum, err, need; if (cancel) { dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec); @@ -1097,62 +1096,70 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, kfree(wl_wrk); kmem_cache_free(wl_entries_slab, e); - if (err != -EIO) { + if (err == -EINTR || err == -ENOMEM || err == -EAGAIN || + err == -EBUSY) { + int err1; + + /* Re-schedule the LEB for erasure */ + err1 = schedule_erase(ubi, e, 0); + if (err1) { + err = err1; + goto out_ro; + } + return err; + } else if (err != -EIO) { /* * If this is not %-EIO, we have no idea what to do. Scheduling * this physical eraseblock for erasure again would cause * errors again and again. Well, lets switch to RO mode. */ - ubi_ro_mode(ubi); - return err; + goto out_ro; } /* It is %-EIO, the PEB went bad */ if (!ubi->bad_allowed) { ubi_err("bad physical eraseblock %d detected", pnum); - ubi_ro_mode(ubi); - err = -EIO; - } else { - int need; - - spin_lock(&ubi->volumes_lock); - need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1; - if (need > 0) { - need = ubi->avail_pebs >= need ? need : ubi->avail_pebs; - ubi->avail_pebs -= need; - ubi->rsvd_pebs += need; - ubi->beb_rsvd_pebs += need; - if (need > 0) - ubi_msg("reserve more %d PEBs", need); - } + goto out_ro; + } - if (ubi->beb_rsvd_pebs == 0) { - spin_unlock(&ubi->volumes_lock); - ubi_err("no reserved physical eraseblocks"); - ubi_ro_mode(ubi); - return -EIO; - } + spin_lock(&ubi->volumes_lock); + need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1; + if (need > 0) { + need = ubi->avail_pebs >= need ? need : ubi->avail_pebs; + ubi->avail_pebs -= need; + ubi->rsvd_pebs += need; + ubi->beb_rsvd_pebs += need; + if (need > 0) + ubi_msg("reserve more %d PEBs", need); + } + if (ubi->beb_rsvd_pebs == 0) { spin_unlock(&ubi->volumes_lock); - ubi_msg("mark PEB %d as bad", pnum); + ubi_err("no reserved physical eraseblocks"); + goto out_ro; + } - err = ubi_io_mark_bad(ubi, pnum); - if (err) { - ubi_ro_mode(ubi); - return err; - } + spin_unlock(&ubi->volumes_lock); + ubi_msg("mark PEB %d as bad", pnum); - spin_lock(&ubi->volumes_lock); - ubi->beb_rsvd_pebs -= 1; - ubi->bad_peb_count += 1; - ubi->good_peb_count -= 1; - ubi_calculate_reserved(ubi); - if (ubi->beb_rsvd_pebs == 0) - ubi_warn("last PEB from the reserved pool was used"); - spin_unlock(&ubi->volumes_lock); - } + err = ubi_io_mark_bad(ubi, pnum); + if (err) + goto out_ro; + + spin_lock(&ubi->volumes_lock); + ubi->beb_rsvd_pebs -= 1; + ubi->bad_peb_count += 1; + ubi->good_peb_count -= 1; + ubi_calculate_reserved(ubi); + if (ubi->beb_rsvd_pebs == 0) + ubi_warn("last PEB from the reserved pool was used"); + spin_unlock(&ubi->volumes_lock); + + return err; +out_ro: + ubi_ro_mode(ubi); return err; } @@ -1634,7 +1641,7 @@ static int paranoid_check_ec(const struct ubi_device *ubi, int pnum, int ec) goto out_free; } - read_ec = ubi64_to_cpu(ec_hdr->ec); + read_ec = be64_to_cpu(ec_hdr->ec); if (ec != read_ec) { ubi_err("paranoid check failed for PEB %d", pnum); ubi_err("read EC is %lld, should be %d", read_ec, ec); diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 43d03178064d..5fb659f8b20e 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2486,6 +2486,18 @@ source "drivers/atm/Kconfig" source "drivers/s390/net/Kconfig" +config XEN_NETDEV_FRONTEND + tristate "Xen network device frontend driver" + depends on XEN + default y + help + The network device frontend driver allows the kernel to + access network devices exported exported by a virtual + machine containing a physical network device driver. The + frontend driver is intended for unprivileged guest domains; + if you are compiling a kernel for a Xen guest, you almost + certainly want to enable this. + config ISERIES_VETH tristate "iSeries Virtual Ethernet driver support" depends on PPC_ISERIES diff --git a/drivers/net/Makefile b/drivers/net/Makefile index eb4167622a6a..0e286ab8855a 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -127,6 +127,8 @@ obj-$(CONFIG_PPPOL2TP) += pppox.o pppol2tp.o obj-$(CONFIG_SLIP) += slip.o obj-$(CONFIG_SLHC) += slhc.o +obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o + obj-$(CONFIG_DUMMY) += dummy.o obj-$(CONFIG_IFB) += ifb.o obj-$(CONFIG_MACVLAN) += macvlan.o diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index d23861c8658c..a729da061bbb 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -54,8 +54,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.6.2" -#define DRV_MODULE_RELDATE "July 6, 2007" +#define DRV_MODULE_VERSION "1.6.3" +#define DRV_MODULE_RELDATE "July 16, 2007" #define RUN_AT(x) (jiffies + (x)) @@ -126,91 +126,102 @@ static struct pci_device_id bnx2_pci_tbl[] = { static struct flash_spec flash_table[] = { +#define BUFFERED_FLAGS (BNX2_NV_BUFFERED | BNX2_NV_TRANSLATE) +#define NONBUFFERED_FLAGS (BNX2_NV_WREN) /* Slow EEPROM */ {0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400, - 1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE, + BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE, SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE, "EEPROM - slow"}, /* Expansion entry 0001 */ {0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406, - 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, + NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, SAIFUN_FLASH_BYTE_ADDR_MASK, 0, "Entry 0001"}, /* Saifun SA25F010 (non-buffered flash) */ /* strap, cfg1, & write1 need updates */ {0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406, - 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, + NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2, "Non-buffered flash (128kB)"}, /* Saifun SA25F020 (non-buffered flash) */ /* strap, cfg1, & write1 need updates */ {0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406, - 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, + NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4, "Non-buffered flash (256kB)"}, /* Expansion entry 0100 */ {0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406, - 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, + NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, SAIFUN_FLASH_BYTE_ADDR_MASK, 0, "Entry 0100"}, /* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */ {0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406, - 0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE, + NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE, ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2, "Entry 0101: ST M45PE10 (128kB non-bufferred)"}, /* Entry 0110: ST M45PE20 (non-buffered flash)*/ {0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406, - 0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE, + NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE, ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4, "Entry 0110: ST M45PE20 (256kB non-bufferred)"}, /* Saifun SA25F005 (non-buffered flash) */ /* strap, cfg1, & write1 need updates */ {0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406, - 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, + NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE, "Non-buffered flash (64kB)"}, /* Fast EEPROM */ {0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400, - 1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE, + BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE, SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE, "EEPROM - fast"}, /* Expansion entry 1001 */ {0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406, - 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, + NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, SAIFUN_FLASH_BYTE_ADDR_MASK, 0, "Entry 1001"}, /* Expansion entry 1010 */ {0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406, - 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, + NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, SAIFUN_FLASH_BYTE_ADDR_MASK, 0, "Entry 1010"}, /* ATMEL AT45DB011B (buffered flash) */ {0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400, - 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE, + BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE, BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE, "Buffered flash (128kB)"}, /* Expansion entry 1100 */ {0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406, - 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, + NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, SAIFUN_FLASH_BYTE_ADDR_MASK, 0, "Entry 1100"}, /* Expansion entry 1101 */ {0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406, - 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, + NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, SAIFUN_FLASH_BYTE_ADDR_MASK, 0, "Entry 1101"}, /* Ateml Expansion entry 1110 */ {0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400, - 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE, + BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE, BUFFERED_FLASH_BYTE_ADDR_MASK, 0, "Entry 1110 (Atmel)"}, /* ATMEL AT45DB021B (buffered flash) */ {0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400, - 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE, + BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE, BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2, "Buffered flash (256kB)"}, }; +static struct flash_spec flash_5709 = { + .flags = BNX2_NV_BUFFERED, + .page_bits = BCM5709_FLASH_PAGE_BITS, + .page_size = BCM5709_FLASH_PAGE_SIZE, + .addr_mask = BCM5709_FLASH_BYTE_ADDR_MASK, + .total_size = BUFFERED_FLASH_TOTAL_SIZE*2, + .name = "5709 Buffered flash (256kB)", +}; + MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl); static inline u32 bnx2_tx_avail(struct bnx2 *bp) @@ -3289,7 +3300,7 @@ bnx2_enable_nvram_write(struct bnx2 *bp) val = REG_RD(bp, BNX2_MISC_CFG); REG_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI); - if (!bp->flash_info->buffered) { + if (bp->flash_info->flags & BNX2_NV_WREN) { int j; REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE); @@ -3349,7 +3360,7 @@ bnx2_nvram_erase_page(struct bnx2 *bp, u32 offset) u32 cmd; int j; - if (bp->flash_info->buffered) + if (bp->flash_info->flags & BNX2_NV_BUFFERED) /* Buffered flash, no erase needed */ return 0; @@ -3392,8 +3403,8 @@ bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags) /* Build the command word. */ cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags; - /* Calculate an offset of a buffered flash. */ - if (bp->flash_info->buffered) { + /* Calculate an offset of a buffered flash, not needed for 5709. */ + if (bp->flash_info->flags & BNX2_NV_TRANSLATE) { offset = ((offset / bp->flash_info->page_size) << bp->flash_info->page_bits) + (offset % bp->flash_info->page_size); @@ -3439,8 +3450,8 @@ bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags) /* Build the command word. */ cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags; - /* Calculate an offset of a buffered flash. */ - if (bp->flash_info->buffered) { + /* Calculate an offset of a buffered flash, not needed for 5709. */ + if (bp->flash_info->flags & BNX2_NV_TRANSLATE) { offset = ((offset / bp->flash_info->page_size) << bp->flash_info->page_bits) + (offset % bp->flash_info->page_size); @@ -3478,15 +3489,19 @@ static int bnx2_init_nvram(struct bnx2 *bp) { u32 val; - int j, entry_count, rc; + int j, entry_count, rc = 0; struct flash_spec *flash; + if (CHIP_NUM(bp) == CHIP_NUM_5709) { + bp->flash_info = &flash_5709; + goto get_flash_size; + } + /* Determine the selected interface. */ val = REG_RD(bp, BNX2_NVM_CFG1); entry_count = sizeof(flash_table) / sizeof(struct flash_spec); - rc = 0; if (val & 0x40000000) { /* Flash interface has been reconfigured */ @@ -3542,6 +3557,7 @@ bnx2_init_nvram(struct bnx2 *bp) return -ENODEV; } +get_flash_size: val = REG_RD_IND(bp, bp->shmem_base + BNX2_SHARED_HW_CFG_CONFIG2); val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK; if (val) @@ -3706,7 +3722,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf, buf = align_buf; } - if (bp->flash_info->buffered == 0) { + if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) { flash_buffer = kmalloc(264, GFP_KERNEL); if (flash_buffer == NULL) { rc = -ENOMEM; @@ -3739,7 +3755,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf, bnx2_enable_nvram_access(bp); cmd_flags = BNX2_NVM_COMMAND_FIRST; - if (bp->flash_info->buffered == 0) { + if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) { int j; /* Read the whole page into the buffer @@ -3767,7 +3783,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf, /* Loop to write back the buffer data from page_start to * data_start */ i = 0; - if (bp->flash_info->buffered == 0) { + if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) { /* Erase the page */ if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0) goto nvram_write_end; @@ -3791,7 +3807,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf, /* Loop to write the new data from data_start to data_end */ for (addr = data_start; addr < data_end; addr += 4, i += 4) { if ((addr == page_end - 4) || - ((bp->flash_info->buffered) && + ((bp->flash_info->flags & BNX2_NV_BUFFERED) && (addr == data_end - 4))) { cmd_flags |= BNX2_NVM_COMMAND_LAST; @@ -3808,7 +3824,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf, /* Loop to write back the buffer data from data_end * to page_end */ - if (bp->flash_info->buffered == 0) { + if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) { for (addr = data_end; addr < page_end; addr += 4, i += 4) { @@ -4107,7 +4123,7 @@ bnx2_init_chip(struct bnx2 *bp) if (CHIP_NUM(bp) == CHIP_NUM_5708) REG_WR(bp, BNX2_HC_STATS_TICKS, 0); else - REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks & 0xffff00); + REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks); REG_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */ if (CHIP_ID(bp) == CHIP_ID_5706_A1) @@ -4127,10 +4143,6 @@ bnx2_init_chip(struct bnx2 *bp) REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS); - if (REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE) & - BNX2_PORT_FEATURE_ASF_ENABLED) - bp->flags |= ASF_ENABLE_FLAG; - /* Initialize the receive filter. */ bnx2_set_rx_mode(bp->dev); @@ -5786,8 +5798,9 @@ bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal) if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC) bp->stats_ticks = USEC_PER_SEC; } - if (bp->stats_ticks > 0xffff00) bp->stats_ticks = 0xffff00; - bp->stats_ticks &= 0xffff00; + if (bp->stats_ticks > BNX2_HC_STATS_TICKS_HC_STAT_TICKS) + bp->stats_ticks = BNX2_HC_STATS_TICKS_HC_STAT_TICKS; + bp->stats_ticks &= BNX2_HC_STATS_TICKS_HC_STAT_TICKS; if (netif_running(bp->dev)) { bnx2_netif_stop(bp); @@ -6629,6 +6642,18 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) if (i != 2) bp->fw_version[j++] = '.'; } + if (REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE) & + BNX2_PORT_FEATURE_ASF_ENABLED) { + bp->flags |= ASF_ENABLE_FLAG; + + for (i = 0; i < 30; i++) { + reg = REG_RD_IND(bp, bp->shmem_base + + BNX2_BC_STATE_CONDITION); + if (reg & BNX2_CONDITION_MFW_RUN_MASK) + break; + msleep(10); + } + } reg = REG_RD_IND(bp, bp->shmem_base + BNX2_BC_STATE_CONDITION); reg &= BNX2_CONDITION_MFW_RUN_MASK; if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN && @@ -6672,7 +6697,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->rx_ticks_int = 18; bp->rx_ticks = 18; - bp->stats_ticks = 1000000 & 0xffff00; + bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS; bp->timer_interval = HZ; bp->current_interval = HZ; diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index d8cd1afeb23d..102adfe1e923 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6433,6 +6433,11 @@ struct sw_bd { #define ST_MICRO_FLASH_PAGE_SIZE 256 #define ST_MICRO_FLASH_BASE_TOTAL_SIZE 65536 +#define BCM5709_FLASH_PAGE_BITS 8 +#define BCM5709_FLASH_PHY_PAGE_SIZE (1 << BCM5709_FLASH_PAGE_BITS) +#define BCM5709_FLASH_BYTE_ADDR_MASK (BCM5709_FLASH_PHY_PAGE_SIZE-1) +#define BCM5709_FLASH_PAGE_SIZE 256 + #define NVRAM_TIMEOUT_COUNT 30000 @@ -6449,7 +6454,10 @@ struct flash_spec { u32 config2; u32 config3; u32 write1; - u32 buffered; + u32 flags; +#define BNX2_NV_BUFFERED 0x00000001 +#define BNX2_NV_TRANSLATE 0x00000002 +#define BNX2_NV_WREN 0x00000004 u32 page_bits; u32 page_size; u32 addr_mask; diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index 84aa2117c0ee..355c6cf3d112 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -320,7 +320,7 @@ static int eppconfig(struct baycom_state *bc) sprintf(portarg, "%ld", bc->pdev->port->base); printk(KERN_DEBUG "%s: %s -s -p %s -m %s\n", bc_drvname, eppconfig_path, portarg, modearg); - return call_usermodehelper(eppconfig_path, argv, envp, 1); + return call_usermodehelper(eppconfig_path, argv, envp, UMH_WAIT_PROC); } /* ---------------------------------------------------------------------- */ diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index 5891a0fbdc8b..f87176055d0e 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -824,6 +824,7 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh struct pppol2tp_session *session; struct pppol2tp_tunnel *tunnel; struct udphdr *uh; + unsigned int len; error = -ENOTCONN; if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) @@ -912,14 +913,15 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh } /* Queue the packet to IP for output */ + len = skb->len; error = ip_queue_xmit(skb, 1); /* Update stats */ if (error >= 0) { tunnel->stats.tx_packets++; - tunnel->stats.tx_bytes += skb->len; + tunnel->stats.tx_bytes += len; session->stats.tx_packets++; - session->stats.tx_bytes += skb->len; + session->stats.tx_bytes += len; } else { tunnel->stats.tx_errors++; session->stats.tx_errors++; @@ -958,6 +960,7 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) __wsum csum = 0; struct sk_buff *skb2 = NULL; struct udphdr *uh; + unsigned int len; if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) goto abort; @@ -1046,18 +1049,25 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) printk("\n"); } + memset(&(IPCB(skb2)->opt), 0, sizeof(IPCB(skb2)->opt)); + IPCB(skb2)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | + IPSKB_REROUTED); + nf_reset(skb2); + /* Get routing info from the tunnel socket */ + dst_release(skb2->dst); skb2->dst = sk_dst_get(sk_tun); /* Queue the packet to IP for output */ + len = skb2->len; rc = ip_queue_xmit(skb2, 1); /* Update stats */ if (rc >= 0) { tunnel->stats.tx_packets++; - tunnel->stats.tx_bytes += skb2->len; + tunnel->stats.tx_bytes += len; session->stats.tx_packets++; - session->stats.tx_bytes += skb2->len; + session->stats.tx_bytes += len; } else { tunnel->stats.tx_errors++; session->stats.tx_errors++; diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c index 8a667c13faef..b801e3b3a11a 100644 --- a/drivers/net/sunvnet.c +++ b/drivers/net/sunvnet.c @@ -12,6 +12,7 @@ #include <linux/netdevice.h> #include <linux/ethtool.h> #include <linux/etherdevice.h> +#include <linux/mutex.h> #include <asm/vio.h> #include <asm/ldc.h> @@ -497,6 +498,8 @@ static void vnet_event(void *arg, int event) vio_link_state_change(vio, event); spin_unlock_irqrestore(&vio->lock, flags); + if (event == LDC_EVENT_RESET) + vio_port_up(vio); return; } @@ -875,6 +878,115 @@ err_out: return err; } +static LIST_HEAD(vnet_list); +static DEFINE_MUTEX(vnet_list_mutex); + +static struct vnet * __devinit vnet_new(const u64 *local_mac) +{ + struct net_device *dev; + struct vnet *vp; + int err, i; + + dev = alloc_etherdev(sizeof(*vp)); + if (!dev) { + printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n"); + return ERR_PTR(-ENOMEM); + } + + for (i = 0; i < ETH_ALEN; i++) + dev->dev_addr[i] = (*local_mac >> (5 - i) * 8) & 0xff; + + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); + + vp = netdev_priv(dev); + + spin_lock_init(&vp->lock); + vp->dev = dev; + + INIT_LIST_HEAD(&vp->port_list); + for (i = 0; i < VNET_PORT_HASH_SIZE; i++) + INIT_HLIST_HEAD(&vp->port_hash[i]); + INIT_LIST_HEAD(&vp->list); + vp->local_mac = *local_mac; + + dev->open = vnet_open; + dev->stop = vnet_close; + dev->set_multicast_list = vnet_set_rx_mode; + dev->set_mac_address = vnet_set_mac_addr; + dev->tx_timeout = vnet_tx_timeout; + dev->ethtool_ops = &vnet_ethtool_ops; + dev->watchdog_timeo = VNET_TX_TIMEOUT; + dev->change_mtu = vnet_change_mtu; + dev->hard_start_xmit = vnet_start_xmit; + + err = register_netdev(dev); + if (err) { + printk(KERN_ERR PFX "Cannot register net device, " + "aborting.\n"); + goto err_out_free_dev; + } + + printk(KERN_INFO "%s: Sun LDOM vnet ", dev->name); + + for (i = 0; i < 6; i++) + printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); + + list_add(&vp->list, &vnet_list); + + return vp; + +err_out_free_dev: + free_netdev(dev); + + return ERR_PTR(err); +} + +static struct vnet * __devinit vnet_find_or_create(const u64 *local_mac) +{ + struct vnet *iter, *vp; + + mutex_lock(&vnet_list_mutex); + vp = NULL; + list_for_each_entry(iter, &vnet_list, list) { + if (iter->local_mac == *local_mac) { + vp = iter; + break; + } + } + if (!vp) + vp = vnet_new(local_mac); + mutex_unlock(&vnet_list_mutex); + + return vp; +} + +static const char *local_mac_prop = "local-mac-address"; + +static struct vnet * __devinit vnet_find_parent(struct mdesc_handle *hp, + u64 port_node) +{ + const u64 *local_mac = NULL; + u64 a; + + mdesc_for_each_arc(a, hp, port_node, MDESC_ARC_TYPE_BACK) { + u64 target = mdesc_arc_target(hp, a); + const char *name; + + name = mdesc_get_property(hp, target, "name", NULL); + if (!name || strcmp(name, "network")) + continue; + + local_mac = mdesc_get_property(hp, target, + local_mac_prop, NULL); + if (local_mac) + break; + } + if (!local_mac) + return ERR_PTR(-ENODEV); + + return vnet_find_or_create(local_mac); +} + static struct ldc_channel_config vnet_ldc_cfg = { .event = vnet_event, .mtu = 64, @@ -887,6 +999,14 @@ static struct vio_driver_ops vnet_vio_ops = { .handshake_complete = vnet_handshake_complete, }; +static void print_version(void) +{ + static int version_printed; + + if (version_printed++ == 0) + printk(KERN_INFO "%s", version); +} + const char *remote_macaddr_prop = "remote-mac-address"; static int __devinit vnet_port_probe(struct vio_dev *vdev, @@ -899,14 +1019,17 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev, const u64 *rmac; int len, i, err, switch_port; - vp = dev_get_drvdata(vdev->dev.parent); - if (!vp) { - printk(KERN_ERR PFX "Cannot find port parent vnet.\n"); - return -ENODEV; - } + print_version(); hp = mdesc_grab(); + vp = vnet_find_parent(hp, vdev->mp); + if (IS_ERR(vp)) { + printk(KERN_ERR PFX "Cannot find port parent vnet.\n"); + err = PTR_ERR(vp); + goto err_out_put_mdesc; + } + rmac = mdesc_get_property(hp, vdev->mp, remote_macaddr_prop, &len); err = -ENODEV; if (!rmac) { @@ -1025,139 +1148,14 @@ static struct vio_driver vnet_port_driver = { } }; -const char *local_mac_prop = "local-mac-address"; - -static int __devinit vnet_probe(struct vio_dev *vdev, - const struct vio_device_id *id) -{ - static int vnet_version_printed; - struct mdesc_handle *hp; - struct net_device *dev; - struct vnet *vp; - const u64 *mac; - int err, i, len; - - if (vnet_version_printed++ == 0) - printk(KERN_INFO "%s", version); - - hp = mdesc_grab(); - - mac = mdesc_get_property(hp, vdev->mp, local_mac_prop, &len); - if (!mac) { - printk(KERN_ERR PFX "vnet lacks %s property.\n", - local_mac_prop); - err = -ENODEV; - goto err_out; - } - - dev = alloc_etherdev(sizeof(*vp)); - if (!dev) { - printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n"); - err = -ENOMEM; - goto err_out; - } - - for (i = 0; i < ETH_ALEN; i++) - dev->dev_addr[i] = (*mac >> (5 - i) * 8) & 0xff; - - memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); - - SET_NETDEV_DEV(dev, &vdev->dev); - - vp = netdev_priv(dev); - - spin_lock_init(&vp->lock); - vp->dev = dev; - vp->vdev = vdev; - - INIT_LIST_HEAD(&vp->port_list); - for (i = 0; i < VNET_PORT_HASH_SIZE; i++) - INIT_HLIST_HEAD(&vp->port_hash[i]); - - dev->open = vnet_open; - dev->stop = vnet_close; - dev->set_multicast_list = vnet_set_rx_mode; - dev->set_mac_address = vnet_set_mac_addr; - dev->tx_timeout = vnet_tx_timeout; - dev->ethtool_ops = &vnet_ethtool_ops; - dev->watchdog_timeo = VNET_TX_TIMEOUT; - dev->change_mtu = vnet_change_mtu; - dev->hard_start_xmit = vnet_start_xmit; - - err = register_netdev(dev); - if (err) { - printk(KERN_ERR PFX "Cannot register net device, " - "aborting.\n"); - goto err_out_free_dev; - } - - printk(KERN_INFO "%s: Sun LDOM vnet ", dev->name); - - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); - - dev_set_drvdata(&vdev->dev, vp); - - mdesc_release(hp); - - return 0; - -err_out_free_dev: - free_netdev(dev); - -err_out: - mdesc_release(hp); - return err; -} - -static int vnet_remove(struct vio_dev *vdev) -{ - - struct vnet *vp = dev_get_drvdata(&vdev->dev); - - if (vp) { - /* XXX unregister port, or at least check XXX */ - unregister_netdevice(vp->dev); - dev_set_drvdata(&vdev->dev, NULL); - } - return 0; -} - -static struct vio_device_id vnet_match[] = { - { - .type = "network", - }, - {}, -}; -MODULE_DEVICE_TABLE(vio, vnet_match); - -static struct vio_driver vnet_driver = { - .id_table = vnet_match, - .probe = vnet_probe, - .remove = vnet_remove, - .driver = { - .name = "vnet", - .owner = THIS_MODULE, - } -}; - static int __init vnet_init(void) { - int err = vio_register_driver(&vnet_driver); - - if (!err) { - err = vio_register_driver(&vnet_port_driver); - if (err) - vio_unregister_driver(&vnet_driver); - } - - return err; + return vio_register_driver(&vnet_port_driver); } static void __exit vnet_exit(void) { vio_unregister_driver(&vnet_port_driver); - vio_unregister_driver(&vnet_driver); } module_init(vnet_init); diff --git a/drivers/net/sunvnet.h b/drivers/net/sunvnet.h index 1c887302d46d..7d3a0cac727b 100644 --- a/drivers/net/sunvnet.h +++ b/drivers/net/sunvnet.h @@ -60,11 +60,13 @@ struct vnet { struct net_device *dev; u32 msg_enable; - struct vio_dev *vdev; struct list_head port_list; struct hlist_head port_hash[VNET_PORT_HASH_SIZE]; + + struct list_head list; + u64 local_mac; }; #endif /* _SUNVNET_H */ diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c new file mode 100644 index 000000000000..489f69c5d6ca --- /dev/null +++ b/drivers/net/xen-netfront.c @@ -0,0 +1,1863 @@ +/* + * Virtual network driver for conversing with remote driver backends. + * + * Copyright (c) 2002-2005, K A Fraser + * Copyright (c) 2005, XenSource Ltd + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/ethtool.h> +#include <linux/if_ether.h> +#include <linux/tcp.h> +#include <linux/udp.h> +#include <linux/moduleparam.h> +#include <linux/mm.h> +#include <net/ip.h> + +#include <xen/xenbus.h> +#include <xen/events.h> +#include <xen/page.h> +#include <xen/grant_table.h> + +#include <xen/interface/io/netif.h> +#include <xen/interface/memory.h> +#include <xen/interface/grant_table.h> + +static struct ethtool_ops xennet_ethtool_ops; + +struct netfront_cb { + struct page *page; + unsigned offset; +}; + +#define NETFRONT_SKB_CB(skb) ((struct netfront_cb *)((skb)->cb)) + +#define RX_COPY_THRESHOLD 256 + +#define GRANT_INVALID_REF 0 + +#define NET_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE) +#define NET_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE) +#define TX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256) + +struct netfront_info { + struct list_head list; + struct net_device *netdev; + + struct net_device_stats stats; + + struct xen_netif_tx_front_ring tx; + struct xen_netif_rx_front_ring rx; + + spinlock_t tx_lock; + spinlock_t rx_lock; + + unsigned int evtchn; + + /* Receive-ring batched refills. */ +#define RX_MIN_TARGET 8 +#define RX_DFL_MIN_TARGET 64 +#define RX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256) + unsigned rx_min_target, rx_max_target, rx_target; + struct sk_buff_head rx_batch; + + struct timer_list rx_refill_timer; + + /* + * {tx,rx}_skbs store outstanding skbuffs. Free tx_skb entries + * are linked from tx_skb_freelist through skb_entry.link. + * + * NB. Freelist index entries are always going to be less than + * PAGE_OFFSET, whereas pointers to skbs will always be equal or + * greater than PAGE_OFFSET: we use this property to distinguish + * them. + */ + union skb_entry { + struct sk_buff *skb; + unsigned link; + } tx_skbs[NET_TX_RING_SIZE]; + grant_ref_t gref_tx_head; + grant_ref_t grant_tx_ref[NET_TX_RING_SIZE]; + unsigned tx_skb_freelist; + + struct sk_buff *rx_skbs[NET_RX_RING_SIZE]; + grant_ref_t gref_rx_head; + grant_ref_t grant_rx_ref[NET_RX_RING_SIZE]; + + struct xenbus_device *xbdev; + int tx_ring_ref; + int rx_ring_ref; + + unsigned long rx_pfn_array[NET_RX_RING_SIZE]; + struct multicall_entry rx_mcl[NET_RX_RING_SIZE+1]; + struct mmu_update rx_mmu[NET_RX_RING_SIZE]; +}; + +struct netfront_rx_info { + struct xen_netif_rx_response rx; + struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1]; +}; + +/* + * Access macros for acquiring freeing slots in tx_skbs[]. + */ + +static void add_id_to_freelist(unsigned *head, union skb_entry *list, + unsigned short id) +{ + list[id].link = *head; + *head = id; +} + +static unsigned short get_id_from_freelist(unsigned *head, + union skb_entry *list) +{ + unsigned int id = *head; + *head = list[id].link; + return id; +} + +static int xennet_rxidx(RING_IDX idx) +{ + return idx & (NET_RX_RING_SIZE - 1); +} + +static struct sk_buff *xennet_get_rx_skb(struct netfront_info *np, + RING_IDX ri) +{ + int i = xennet_rxidx(ri); + struct sk_buff *skb = np->rx_skbs[i]; + np->rx_skbs[i] = NULL; + return skb; +} + +static grant_ref_t xennet_get_rx_ref(struct netfront_info *np, + RING_IDX ri) +{ + int i = xennet_rxidx(ri); + grant_ref_t ref = np->grant_rx_ref[i]; + np->grant_rx_ref[i] = GRANT_INVALID_REF; + return ref; +} + +#ifdef CONFIG_SYSFS +static int xennet_sysfs_addif(struct net_device *netdev); +static void xennet_sysfs_delif(struct net_device *netdev); +#else /* !CONFIG_SYSFS */ +#define xennet_sysfs_addif(dev) (0) +#define xennet_sysfs_delif(dev) do { } while (0) +#endif + +static int xennet_can_sg(struct net_device *dev) +{ + return dev->features & NETIF_F_SG; +} + + +static void rx_refill_timeout(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + netif_rx_schedule(dev); +} + +static int netfront_tx_slot_available(struct netfront_info *np) +{ + return ((np->tx.req_prod_pvt - np->tx.rsp_cons) < + (TX_MAX_TARGET - MAX_SKB_FRAGS - 2)); +} + +static void xennet_maybe_wake_tx(struct net_device *dev) +{ + struct netfront_info *np = netdev_priv(dev); + + if (unlikely(netif_queue_stopped(dev)) && + netfront_tx_slot_available(np) && + likely(netif_running(dev))) + netif_wake_queue(dev); +} + +static void xennet_alloc_rx_buffers(struct net_device *dev) +{ + unsigned short id; + struct netfront_info *np = netdev_priv(dev); + struct sk_buff *skb; + struct page *page; + int i, batch_target, notify; + RING_IDX req_prod = np->rx.req_prod_pvt; + struct xen_memory_reservation reservation; + grant_ref_t ref; + unsigned long pfn; + void *vaddr; + int nr_flips; + struct xen_netif_rx_request *req; + + if (unlikely(!netif_carrier_ok(dev))) + return; + + /* + * Allocate skbuffs greedily, even though we batch updates to the + * receive ring. This creates a less bursty demand on the memory + * allocator, so should reduce the chance of failed allocation requests + * both for ourself and for other kernel subsystems. + */ + batch_target = np->rx_target - (req_prod - np->rx.rsp_cons); + for (i = skb_queue_len(&np->rx_batch); i < batch_target; i++) { + skb = __netdev_alloc_skb(dev, RX_COPY_THRESHOLD, + GFP_ATOMIC | __GFP_NOWARN); + if (unlikely(!skb)) + goto no_skb; + + page = alloc_page(GFP_ATOMIC | __GFP_NOWARN); + if (!page) { + kfree_skb(skb); +no_skb: + /* Any skbuffs queued for refill? Force them out. */ + if (i != 0) + goto refill; + /* Could not allocate any skbuffs. Try again later. */ + mod_timer(&np->rx_refill_timer, + jiffies + (HZ/10)); + break; + } + + skb_shinfo(skb)->frags[0].page = page; + skb_shinfo(skb)->nr_frags = 1; + __skb_queue_tail(&np->rx_batch, skb); + } + + /* Is the batch large enough to be worthwhile? */ + if (i < (np->rx_target/2)) { + if (req_prod > np->rx.sring->req_prod) + goto push; + return; + } + + /* Adjust our fill target if we risked running out of buffers. */ + if (((req_prod - np->rx.sring->rsp_prod) < (np->rx_target / 4)) && + ((np->rx_target *= 2) > np->rx_max_target)) + np->rx_target = np->rx_max_target; + + refill: + for (nr_flips = i = 0; ; i++) { + skb = __skb_dequeue(&np->rx_batch); + if (skb == NULL) + break; + + skb->dev = dev; + + id = xennet_rxidx(req_prod + i); + + BUG_ON(np->rx_skbs[id]); + np->rx_skbs[id] = skb; + + ref = gnttab_claim_grant_reference(&np->gref_rx_head); + BUG_ON((signed short)ref < 0); + np->grant_rx_ref[id] = ref; + + pfn = page_to_pfn(skb_shinfo(skb)->frags[0].page); + vaddr = page_address(skb_shinfo(skb)->frags[0].page); + + req = RING_GET_REQUEST(&np->rx, req_prod + i); + gnttab_grant_foreign_access_ref(ref, + np->xbdev->otherend_id, + pfn_to_mfn(pfn), + 0); + + req->id = id; + req->gref = ref; + } + + if (nr_flips != 0) { + reservation.extent_start = np->rx_pfn_array; + reservation.nr_extents = nr_flips; + reservation.extent_order = 0; + reservation.address_bits = 0; + reservation.domid = DOMID_SELF; + + if (!xen_feature(XENFEAT_auto_translated_physmap)) { + /* After all PTEs have been zapped, flush the TLB. */ + np->rx_mcl[i-1].args[MULTI_UVMFLAGS_INDEX] = + UVMF_TLB_FLUSH|UVMF_ALL; + + /* Give away a batch of pages. */ + np->rx_mcl[i].op = __HYPERVISOR_memory_op; + np->rx_mcl[i].args[0] = XENMEM_decrease_reservation; + np->rx_mcl[i].args[1] = (unsigned long)&reservation; + + /* Zap PTEs and give away pages in one big + * multicall. */ + (void)HYPERVISOR_multicall(np->rx_mcl, i+1); + + /* Check return status of HYPERVISOR_memory_op(). */ + if (unlikely(np->rx_mcl[i].result != i)) + panic("Unable to reduce memory reservation\n"); + } else { + if (HYPERVISOR_memory_op(XENMEM_decrease_reservation, + &reservation) != i) + panic("Unable to reduce memory reservation\n"); + } + } else { + wmb(); /* barrier so backend seens requests */ + } + + /* Above is a suitable barrier to ensure backend will see requests. */ + np->rx.req_prod_pvt = req_prod + i; + push: + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->rx, notify); + if (notify) + notify_remote_via_irq(np->netdev->irq); +} + +static int xennet_open(struct net_device *dev) +{ + struct netfront_info *np = netdev_priv(dev); + + memset(&np->stats, 0, sizeof(np->stats)); + + spin_lock_bh(&np->rx_lock); + if (netif_carrier_ok(dev)) { + xennet_alloc_rx_buffers(dev); + np->rx.sring->rsp_event = np->rx.rsp_cons + 1; + if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx)) + netif_rx_schedule(dev); + } + spin_unlock_bh(&np->rx_lock); + + xennet_maybe_wake_tx(dev); + + return 0; +} + +static void xennet_tx_buf_gc(struct net_device *dev) +{ + RING_IDX cons, prod; + unsigned short id; + struct netfront_info *np = netdev_priv(dev); + struct sk_buff *skb; + + BUG_ON(!netif_carrier_ok(dev)); + + do { + prod = np->tx.sring->rsp_prod; + rmb(); /* Ensure we see responses up to 'rp'. */ + + for (cons = np->tx.rsp_cons; cons != prod; cons++) { + struct xen_netif_tx_response *txrsp; + + txrsp = RING_GET_RESPONSE(&np->tx, cons); + if (txrsp->status == NETIF_RSP_NULL) + continue; + + id = txrsp->id; + skb = np->tx_skbs[id].skb; + if (unlikely(gnttab_query_foreign_access( + np->grant_tx_ref[id]) != 0)) { + printk(KERN_ALERT "xennet_tx_buf_gc: warning " + "-- grant still in use by backend " + "domain.\n"); + BUG(); + } + gnttab_end_foreign_access_ref( + np->grant_tx_ref[id], GNTMAP_readonly); + gnttab_release_grant_reference( + &np->gref_tx_head, np->grant_tx_ref[id]); + np->grant_tx_ref[id] = GRANT_INVALID_REF; + add_id_to_freelist(&np->tx_skb_freelist, np->tx_skbs, id); + dev_kfree_skb_irq(skb); + } + + np->tx.rsp_cons = prod; + + /* + * Set a new event, then check for race with update of tx_cons. + * Note that it is essential to schedule a callback, no matter + * how few buffers are pending. Even if there is space in the + * transmit ring, higher layers may be blocked because too much + * data is outstanding: in such cases notification from Xen is + * likely to be the only kick that we'll get. + */ + np->tx.sring->rsp_event = + prod + ((np->tx.sring->req_prod - prod) >> 1) + 1; + mb(); /* update shared area */ + } while ((cons == prod) && (prod != np->tx.sring->rsp_prod)); + + xennet_maybe_wake_tx(dev); +} + +static void xennet_make_frags(struct sk_buff *skb, struct net_device *dev, + struct xen_netif_tx_request *tx) +{ + struct netfront_info *np = netdev_priv(dev); + char *data = skb->data; + unsigned long mfn; + RING_IDX prod = np->tx.req_prod_pvt; + int frags = skb_shinfo(skb)->nr_frags; + unsigned int offset = offset_in_page(data); + unsigned int len = skb_headlen(skb); + unsigned int id; + grant_ref_t ref; + int i; + + /* While the header overlaps a page boundary (including being + larger than a page), split it it into page-sized chunks. */ + while (len > PAGE_SIZE - offset) { + tx->size = PAGE_SIZE - offset; + tx->flags |= NETTXF_more_data; + len -= tx->size; + data += tx->size; + offset = 0; + + id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs); + np->tx_skbs[id].skb = skb_get(skb); + tx = RING_GET_REQUEST(&np->tx, prod++); + tx->id = id; + ref = gnttab_claim_grant_reference(&np->gref_tx_head); + BUG_ON((signed short)ref < 0); + + mfn = virt_to_mfn(data); + gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id, + mfn, GNTMAP_readonly); + + tx->gref = np->grant_tx_ref[id] = ref; + tx->offset = offset; + tx->size = len; + tx->flags = 0; + } + + /* Grant backend access to each skb fragment page. */ + for (i = 0; i < frags; i++) { + skb_frag_t *frag = skb_shinfo(skb)->frags + i; + + tx->flags |= NETTXF_more_data; + + id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs); + np->tx_skbs[id].skb = skb_get(skb); + tx = RING_GET_REQUEST(&np->tx, prod++); + tx->id = id; + ref = gnttab_claim_grant_reference(&np->gref_tx_head); + BUG_ON((signed short)ref < 0); + + mfn = pfn_to_mfn(page_to_pfn(frag->page)); + gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id, + mfn, GNTMAP_readonly); + + tx->gref = np->grant_tx_ref[id] = ref; + tx->offset = frag->page_offset; + tx->size = frag->size; + tx->flags = 0; + } + + np->tx.req_prod_pvt = prod; +} + +static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + unsigned short id; + struct netfront_info *np = netdev_priv(dev); + struct xen_netif_tx_request *tx; + struct xen_netif_extra_info *extra; + char *data = skb->data; + RING_IDX i; + grant_ref_t ref; + unsigned long mfn; + int notify; + int frags = skb_shinfo(skb)->nr_frags; + unsigned int offset = offset_in_page(data); + unsigned int len = skb_headlen(skb); + + frags += (offset + len + PAGE_SIZE - 1) / PAGE_SIZE; + if (unlikely(frags > MAX_SKB_FRAGS + 1)) { + printk(KERN_ALERT "xennet: skb rides the rocket: %d frags\n", + frags); + dump_stack(); + goto drop; + } + + spin_lock_irq(&np->tx_lock); + + if (unlikely(!netif_carrier_ok(dev) || + (frags > 1 && !xennet_can_sg(dev)) || + netif_needs_gso(dev, skb))) { + spin_unlock_irq(&np->tx_lock); + goto drop; + } + + i = np->tx.req_prod_pvt; + + id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs); + np->tx_skbs[id].skb = skb; + + tx = RING_GET_REQUEST(&np->tx, i); + + tx->id = id; + ref = gnttab_claim_grant_reference(&np->gref_tx_head); + BUG_ON((signed short)ref < 0); + mfn = virt_to_mfn(data); + gnttab_grant_foreign_access_ref( + ref, np->xbdev->otherend_id, mfn, GNTMAP_readonly); + tx->gref = np->grant_tx_ref[id] = ref; + tx->offset = offset; + tx->size = len; + extra = NULL; + + tx->flags = 0; + if (skb->ip_summed == CHECKSUM_PARTIAL) + /* local packet? */ + tx->flags |= NETTXF_csum_blank | NETTXF_data_validated; + else if (skb->ip_summed == CHECKSUM_UNNECESSARY) + /* remote but checksummed. */ + tx->flags |= NETTXF_data_validated; + + if (skb_shinfo(skb)->gso_size) { + struct xen_netif_extra_info *gso; + + gso = (struct xen_netif_extra_info *) + RING_GET_REQUEST(&np->tx, ++i); + + if (extra) + extra->flags |= XEN_NETIF_EXTRA_FLAG_MORE; + else + tx->flags |= NETTXF_extra_info; + + gso->u.gso.size = skb_shinfo(skb)->gso_size; + gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4; + gso->u.gso.pad = 0; + gso->u.gso.features = 0; + + gso->type = XEN_NETIF_EXTRA_TYPE_GSO; + gso->flags = 0; + extra = gso; + } + + np->tx.req_prod_pvt = i + 1; + + xennet_make_frags(skb, dev, tx); + tx->size = skb->len; + + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->tx, notify); + if (notify) + notify_remote_via_irq(np->netdev->irq); + + xennet_tx_buf_gc(dev); + + if (!netfront_tx_slot_available(np)) + netif_stop_queue(dev); + + spin_unlock_irq(&np->tx_lock); + + np->stats.tx_bytes += skb->len; + np->stats.tx_packets++; + + return 0; + + drop: + np->stats.tx_dropped++; + dev_kfree_skb(skb); + return 0; +} + +static int xennet_close(struct net_device *dev) +{ + struct netfront_info *np = netdev_priv(dev); + netif_stop_queue(np->netdev); + return 0; +} + +static struct net_device_stats *xennet_get_stats(struct net_device *dev) +{ + struct netfront_info *np = netdev_priv(dev); + return &np->stats; +} + +static void xennet_move_rx_slot(struct netfront_info *np, struct sk_buff *skb, + grant_ref_t ref) +{ + int new = xennet_rxidx(np->rx.req_prod_pvt); + + BUG_ON(np->rx_skbs[new]); + np->rx_skbs[new] = skb; + np->grant_rx_ref[new] = ref; + RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->id = new; + RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->gref = ref; + np->rx.req_prod_pvt++; +} + +static int xennet_get_extras(struct netfront_info *np, + struct xen_netif_extra_info *extras, + RING_IDX rp) + +{ + struct xen_netif_extra_info *extra; + struct device *dev = &np->netdev->dev; + RING_IDX cons = np->rx.rsp_cons; + int err = 0; + + do { + struct sk_buff *skb; + grant_ref_t ref; + + if (unlikely(cons + 1 == rp)) { + if (net_ratelimit()) + dev_warn(dev, "Missing extra info\n"); + err = -EBADR; + break; + } + + extra = (struct xen_netif_extra_info *) + RING_GET_RESPONSE(&np->rx, ++cons); + + if (unlikely(!extra->type || + extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) { + if (net_ratelimit()) + dev_warn(dev, "Invalid extra type: %d\n", + extra->type); + err = -EINVAL; + } else { + memcpy(&extras[extra->type - 1], extra, + sizeof(*extra)); + } + + skb = xennet_get_rx_skb(np, cons); + ref = xennet_get_rx_ref(np, cons); + xennet_move_rx_slot(np, skb, ref); + } while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE); + + np->rx.rsp_cons = cons; + return err; +} + +static int xennet_get_responses(struct netfront_info *np, + struct netfront_rx_info *rinfo, RING_IDX rp, + struct sk_buff_head *list) +{ + struct xen_netif_rx_response *rx = &rinfo->rx; + struct xen_netif_extra_info *extras = rinfo->extras; + struct device *dev = &np->netdev->dev; + RING_IDX cons = np->rx.rsp_cons; + struct sk_buff *skb = xennet_get_rx_skb(np, cons); + grant_ref_t ref = xennet_get_rx_ref(np, cons); + int max = MAX_SKB_FRAGS + (rx->status <= RX_COPY_THRESHOLD); + int frags = 1; + int err = 0; + unsigned long ret; + + if (rx->flags & NETRXF_extra_info) { + err = xennet_get_extras(np, extras, rp); + cons = np->rx.rsp_cons; + } + + for (;;) { + if (unlikely(rx->status < 0 || + rx->offset + rx->status > PAGE_SIZE)) { + if (net_ratelimit()) + dev_warn(dev, "rx->offset: %x, size: %u\n", + rx->offset, rx->status); + xennet_move_rx_slot(np, skb, ref); + err = -EINVAL; + goto next; + } + + /* + * This definitely indicates a bug, either in this driver or in + * the backend driver. In future this should flag the bad + * situation to the system controller to reboot the backed. + */ + if (ref == GRANT_INVALID_REF) { + if (net_ratelimit()) + dev_warn(dev, "Bad rx response id %d.\n", + rx->id); + err = -EINVAL; + goto next; + } + + ret = gnttab_end_foreign_access_ref(ref, 0); + BUG_ON(!ret); + + gnttab_release_grant_reference(&np->gref_rx_head, ref); + + __skb_queue_tail(list, skb); + +next: + if (!(rx->flags & NETRXF_more_data)) + break; + + if (cons + frags == rp) { + if (net_ratelimit()) + dev_warn(dev, "Need more frags\n"); + err = -ENOENT; + break; + } + + rx = RING_GET_RESPONSE(&np->rx, cons + frags); + skb = xennet_get_rx_skb(np, cons + frags); + ref = xennet_get_rx_ref(np, cons + frags); + frags++; + } + + if (unlikely(frags > max)) { + if (net_ratelimit()) + dev_warn(dev, "Too many frags\n"); + err = -E2BIG; + } + + if (unlikely(err)) + np->rx.rsp_cons = cons + frags; + + return err; +} + +static int xennet_set_skb_gso(struct sk_buff *skb, + struct xen_netif_extra_info *gso) +{ + if (!gso->u.gso.size) { + if (net_ratelimit()) + printk(KERN_WARNING "GSO size must not be zero.\n"); + return -EINVAL; + } + + /* Currently only TCPv4 S.O. is supported. */ + if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) { + if (net_ratelimit()) + printk(KERN_WARNING "Bad GSO type %d.\n", gso->u.gso.type); + return -EINVAL; + } + + skb_shinfo(skb)->gso_size = gso->u.gso.size; + skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; + + /* Header must be checked, and gso_segs computed. */ + skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY; + skb_shinfo(skb)->gso_segs = 0; + + return 0; +} + +static RING_IDX xennet_fill_frags(struct netfront_info *np, + struct sk_buff *skb, + struct sk_buff_head *list) +{ + struct skb_shared_info *shinfo = skb_shinfo(skb); + int nr_frags = shinfo->nr_frags; + RING_IDX cons = np->rx.rsp_cons; + skb_frag_t *frag = shinfo->frags + nr_frags; + struct sk_buff *nskb; + + while ((nskb = __skb_dequeue(list))) { + struct xen_netif_rx_response *rx = + RING_GET_RESPONSE(&np->rx, ++cons); + + frag->page = skb_shinfo(nskb)->frags[0].page; + frag->page_offset = rx->offset; + frag->size = rx->status; + + skb->data_len += rx->status; + + skb_shinfo(nskb)->nr_frags = 0; + kfree_skb(nskb); + + frag++; + nr_frags++; + } + + shinfo->nr_frags = nr_frags; + return cons; +} + +static int skb_checksum_setup(struct sk_buff *skb) +{ + struct iphdr *iph; + unsigned char *th; + int err = -EPROTO; + + if (skb->protocol != htons(ETH_P_IP)) + goto out; + + iph = (void *)skb->data; + th = skb->data + 4 * iph->ihl; + if (th >= skb_tail_pointer(skb)) + goto out; + + skb->csum_start = th - skb->head; + switch (iph->protocol) { + case IPPROTO_TCP: + skb->csum_offset = offsetof(struct tcphdr, check); + break; + case IPPROTO_UDP: + skb->csum_offset = offsetof(struct udphdr, check); + break; + default: + if (net_ratelimit()) + printk(KERN_ERR "Attempting to checksum a non-" + "TCP/UDP packet, dropping a protocol" + " %d packet", iph->protocol); + goto out; + } + + if ((th + skb->csum_offset + 2) > skb_tail_pointer(skb)) + goto out; + + err = 0; + +out: + return err; +} + +static int handle_incoming_queue(struct net_device *dev, + struct sk_buff_head *rxq) +{ + struct netfront_info *np = netdev_priv(dev); + int packets_dropped = 0; + struct sk_buff *skb; + + while ((skb = __skb_dequeue(rxq)) != NULL) { + struct page *page = NETFRONT_SKB_CB(skb)->page; + void *vaddr = page_address(page); + unsigned offset = NETFRONT_SKB_CB(skb)->offset; + + memcpy(skb->data, vaddr + offset, + skb_headlen(skb)); + + if (page != skb_shinfo(skb)->frags[0].page) + __free_page(page); + + /* Ethernet work: Delayed to here as it peeks the header. */ + skb->protocol = eth_type_trans(skb, dev); + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + if (skb_checksum_setup(skb)) { + kfree_skb(skb); + packets_dropped++; + np->stats.rx_errors++; + continue; + } + } + + np->stats.rx_packets++; + np->stats.rx_bytes += skb->len; + + /* Pass it up. */ + netif_receive_skb(skb); + dev->last_rx = jiffies; + } + + return packets_dropped; +} + +static int xennet_poll(struct net_device *dev, int *pbudget) +{ + struct netfront_info *np = netdev_priv(dev); + struct sk_buff *skb; + struct netfront_rx_info rinfo; + struct xen_netif_rx_response *rx = &rinfo.rx; + struct xen_netif_extra_info *extras = rinfo.extras; + RING_IDX i, rp; + int work_done, budget, more_to_do = 1; + struct sk_buff_head rxq; + struct sk_buff_head errq; + struct sk_buff_head tmpq; + unsigned long flags; + unsigned int len; + int err; + + spin_lock(&np->rx_lock); + + if (unlikely(!netif_carrier_ok(dev))) { + spin_unlock(&np->rx_lock); + return 0; + } + + skb_queue_head_init(&rxq); + skb_queue_head_init(&errq); + skb_queue_head_init(&tmpq); + + budget = *pbudget; + if (budget > dev->quota) + budget = dev->quota; + rp = np->rx.sring->rsp_prod; + rmb(); /* Ensure we see queued responses up to 'rp'. */ + + i = np->rx.rsp_cons; + work_done = 0; + while ((i != rp) && (work_done < budget)) { + memcpy(rx, RING_GET_RESPONSE(&np->rx, i), sizeof(*rx)); + memset(extras, 0, sizeof(rinfo.extras)); + + err = xennet_get_responses(np, &rinfo, rp, &tmpq); + + if (unlikely(err)) { +err: + while ((skb = __skb_dequeue(&tmpq))) + __skb_queue_tail(&errq, skb); + np->stats.rx_errors++; + i = np->rx.rsp_cons; + continue; + } + + skb = __skb_dequeue(&tmpq); + + if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) { + struct xen_netif_extra_info *gso; + gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1]; + + if (unlikely(xennet_set_skb_gso(skb, gso))) { + __skb_queue_head(&tmpq, skb); + np->rx.rsp_cons += skb_queue_len(&tmpq); + goto err; + } + } + + NETFRONT_SKB_CB(skb)->page = skb_shinfo(skb)->frags[0].page; + NETFRONT_SKB_CB(skb)->offset = rx->offset; + + len = rx->status; + if (len > RX_COPY_THRESHOLD) + len = RX_COPY_THRESHOLD; + skb_put(skb, len); + + if (rx->status > len) { + skb_shinfo(skb)->frags[0].page_offset = + rx->offset + len; + skb_shinfo(skb)->frags[0].size = rx->status - len; + skb->data_len = rx->status - len; + } else { + skb_shinfo(skb)->frags[0].page = NULL; + skb_shinfo(skb)->nr_frags = 0; + } + + i = xennet_fill_frags(np, skb, &tmpq); + + /* + * Truesize approximates the size of true data plus + * any supervisor overheads. Adding hypervisor + * overheads has been shown to significantly reduce + * achievable bandwidth with the default receive + * buffer size. It is therefore not wise to account + * for it here. + * + * After alloc_skb(RX_COPY_THRESHOLD), truesize is set + * to RX_COPY_THRESHOLD + the supervisor + * overheads. Here, we add the size of the data pulled + * in xennet_fill_frags(). + * + * We also adjust for any unused space in the main + * data area by subtracting (RX_COPY_THRESHOLD - + * len). This is especially important with drivers + * which split incoming packets into header and data, + * using only 66 bytes of the main data area (see the + * e1000 driver for example.) On such systems, + * without this last adjustement, our achievable + * receive throughout using the standard receive + * buffer size was cut by 25%(!!!). + */ + skb->truesize += skb->data_len - (RX_COPY_THRESHOLD - len); + skb->len += skb->data_len; + + if (rx->flags & NETRXF_csum_blank) + skb->ip_summed = CHECKSUM_PARTIAL; + else if (rx->flags & NETRXF_data_validated) + skb->ip_summed = CHECKSUM_UNNECESSARY; + + __skb_queue_tail(&rxq, skb); + + np->rx.rsp_cons = ++i; + work_done++; + } + + while ((skb = __skb_dequeue(&errq))) + kfree_skb(skb); + + work_done -= handle_incoming_queue(dev, &rxq); + + /* If we get a callback with very few responses, reduce fill target. */ + /* NB. Note exponential increase, linear decrease. */ + if (((np->rx.req_prod_pvt - np->rx.sring->rsp_prod) > + ((3*np->rx_target) / 4)) && + (--np->rx_target < np->rx_min_target)) + np->rx_target = np->rx_min_target; + + xennet_alloc_rx_buffers(dev); + + *pbudget -= work_done; + dev->quota -= work_done; + + if (work_done < budget) { + local_irq_save(flags); + + RING_FINAL_CHECK_FOR_RESPONSES(&np->rx, more_to_do); + if (!more_to_do) + __netif_rx_complete(dev); + + local_irq_restore(flags); + } + + spin_unlock(&np->rx_lock); + + return more_to_do; +} + +static int xennet_change_mtu(struct net_device *dev, int mtu) +{ + int max = xennet_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN; + + if (mtu > max) + return -EINVAL; + dev->mtu = mtu; + return 0; +} + +static void xennet_release_tx_bufs(struct netfront_info *np) +{ + struct sk_buff *skb; + int i; + + for (i = 0; i < NET_TX_RING_SIZE; i++) { + /* Skip over entries which are actually freelist references */ + if ((unsigned long)np->tx_skbs[i].skb < PAGE_OFFSET) + continue; + + skb = np->tx_skbs[i].skb; + gnttab_end_foreign_access_ref(np->grant_tx_ref[i], + GNTMAP_readonly); + gnttab_release_grant_reference(&np->gref_tx_head, + np->grant_tx_ref[i]); + np->grant_tx_ref[i] = GRANT_INVALID_REF; + add_id_to_freelist(&np->tx_skb_freelist, np->tx_skbs, i); + dev_kfree_skb_irq(skb); + } +} + +static void xennet_release_rx_bufs(struct netfront_info *np) +{ + struct mmu_update *mmu = np->rx_mmu; + struct multicall_entry *mcl = np->rx_mcl; + struct sk_buff_head free_list; + struct sk_buff *skb; + unsigned long mfn; + int xfer = 0, noxfer = 0, unused = 0; + int id, ref; + + dev_warn(&np->netdev->dev, "%s: fix me for copying receiver.\n", + __func__); + return; + + skb_queue_head_init(&free_list); + + spin_lock_bh(&np->rx_lock); + + for (id = 0; id < NET_RX_RING_SIZE; id++) { + ref = np->grant_rx_ref[id]; + if (ref == GRANT_INVALID_REF) { + unused++; + continue; + } + + skb = np->rx_skbs[id]; + mfn = gnttab_end_foreign_transfer_ref(ref); + gnttab_release_grant_reference(&np->gref_rx_head, ref); + np->grant_rx_ref[id] = GRANT_INVALID_REF; + + if (0 == mfn) { + skb_shinfo(skb)->nr_frags = 0; + dev_kfree_skb(skb); + noxfer++; + continue; + } + + if (!xen_feature(XENFEAT_auto_translated_physmap)) { + /* Remap the page. */ + struct page *page = skb_shinfo(skb)->frags[0].page; + unsigned long pfn = page_to_pfn(page); + void *vaddr = page_address(page); + + MULTI_update_va_mapping(mcl, (unsigned long)vaddr, + mfn_pte(mfn, PAGE_KERNEL), + 0); + mcl++; + mmu->ptr = ((u64)mfn << PAGE_SHIFT) + | MMU_MACHPHYS_UPDATE; + mmu->val = pfn; + mmu++; + + set_phys_to_machine(pfn, mfn); + } + __skb_queue_tail(&free_list, skb); + xfer++; + } + + dev_info(&np->netdev->dev, "%s: %d xfer, %d noxfer, %d unused\n", + __func__, xfer, noxfer, unused); + + if (xfer) { + if (!xen_feature(XENFEAT_auto_translated_physmap)) { + /* Do all the remapping work and M2P updates. */ + MULTI_mmu_update(mcl, np->rx_mmu, mmu - np->rx_mmu, + 0, DOMID_SELF); + mcl++; + HYPERVISOR_multicall(np->rx_mcl, mcl - np->rx_mcl); + } + } + + while ((skb = __skb_dequeue(&free_list)) != NULL) + dev_kfree_skb(skb); + + spin_unlock_bh(&np->rx_lock); +} + +static void xennet_uninit(struct net_device *dev) +{ + struct netfront_info *np = netdev_priv(dev); + xennet_release_tx_bufs(np); + xennet_release_rx_bufs(np); + gnttab_free_grant_references(np->gref_tx_head); + gnttab_free_grant_references(np->gref_rx_head); +} + +static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev) +{ + int i, err; + struct net_device *netdev; + struct netfront_info *np; + + netdev = alloc_etherdev(sizeof(struct netfront_info)); + if (!netdev) { + printk(KERN_WARNING "%s> alloc_etherdev failed.\n", + __func__); + return ERR_PTR(-ENOMEM); + } + + np = netdev_priv(netdev); + np->xbdev = dev; + + spin_lock_init(&np->tx_lock); + spin_lock_init(&np->rx_lock); + + skb_queue_head_init(&np->rx_batch); + np->rx_target = RX_DFL_MIN_TARGET; + np->rx_min_target = RX_DFL_MIN_TARGET; + np->rx_max_target = RX_MAX_TARGET; + + init_timer(&np->rx_refill_timer); + np->rx_refill_timer.data = (unsigned long)netdev; + np->rx_refill_timer.function = rx_refill_timeout; + + /* Initialise tx_skbs as a free chain containing every entry. */ + np->tx_skb_freelist = 0; + for (i = 0; i < NET_TX_RING_SIZE; i++) { + np->tx_skbs[i].link = i+1; + np->grant_tx_ref[i] = GRANT_INVALID_REF; + } + + /* Clear out rx_skbs */ + for (i = 0; i < NET_RX_RING_SIZE; i++) { + np->rx_skbs[i] = NULL; + np->grant_rx_ref[i] = GRANT_INVALID_REF; + } + + /* A grant for every tx ring slot */ + if (gnttab_alloc_grant_references(TX_MAX_TARGET, + &np->gref_tx_head) < 0) { + printk(KERN_ALERT "#### netfront can't alloc tx grant refs\n"); + err = -ENOMEM; + goto exit; + } + /* A grant for every rx ring slot */ + if (gnttab_alloc_grant_references(RX_MAX_TARGET, + &np->gref_rx_head) < 0) { + printk(KERN_ALERT "#### netfront can't alloc rx grant refs\n"); + err = -ENOMEM; + goto exit_free_tx; + } + + netdev->open = xennet_open; + netdev->hard_start_xmit = xennet_start_xmit; + netdev->stop = xennet_close; + netdev->get_stats = xennet_get_stats; + netdev->poll = xennet_poll; + netdev->uninit = xennet_uninit; + netdev->change_mtu = xennet_change_mtu; + netdev->weight = 64; + netdev->features = NETIF_F_IP_CSUM; + + SET_ETHTOOL_OPS(netdev, &xennet_ethtool_ops); + SET_MODULE_OWNER(netdev); + SET_NETDEV_DEV(netdev, &dev->dev); + + np->netdev = netdev; + + netif_carrier_off(netdev); + + return netdev; + + exit_free_tx: + gnttab_free_grant_references(np->gref_tx_head); + exit: + free_netdev(netdev); + return ERR_PTR(err); +} + +/** + * Entry point to this code when a new device is created. Allocate the basic + * structures and the ring buffers for communication with the backend, and + * inform the backend of the appropriate details for those. + */ +static int __devinit netfront_probe(struct xenbus_device *dev, + const struct xenbus_device_id *id) +{ + int err; + struct net_device *netdev; + struct netfront_info *info; + + netdev = xennet_create_dev(dev); + if (IS_ERR(netdev)) { + err = PTR_ERR(netdev); + xenbus_dev_fatal(dev, err, "creating netdev"); + return err; + } + + info = netdev_priv(netdev); + dev->dev.driver_data = info; + + err = register_netdev(info->netdev); + if (err) { + printk(KERN_WARNING "%s: register_netdev err=%d\n", + __func__, err); + goto fail; + } + + err = xennet_sysfs_addif(info->netdev); + if (err) { + unregister_netdev(info->netdev); + printk(KERN_WARNING "%s: add sysfs failed err=%d\n", + __func__, err); + goto fail; + } + + return 0; + + fail: + free_netdev(netdev); + dev->dev.driver_data = NULL; + return err; +} + +static void xennet_end_access(int ref, void *page) +{ + /* This frees the page as a side-effect */ + if (ref != GRANT_INVALID_REF) + gnttab_end_foreign_access(ref, 0, (unsigned long)page); +} + +static void xennet_disconnect_backend(struct netfront_info *info) +{ + /* Stop old i/f to prevent errors whilst we rebuild the state. */ + spin_lock_bh(&info->rx_lock); + spin_lock_irq(&info->tx_lock); + netif_carrier_off(info->netdev); + spin_unlock_irq(&info->tx_lock); + spin_unlock_bh(&info->rx_lock); + + if (info->netdev->irq) + unbind_from_irqhandler(info->netdev->irq, info->netdev); + info->evtchn = info->netdev->irq = 0; + + /* End access and free the pages */ + xennet_end_access(info->tx_ring_ref, info->tx.sring); + xennet_end_access(info->rx_ring_ref, info->rx.sring); + + info->tx_ring_ref = GRANT_INVALID_REF; + info->rx_ring_ref = GRANT_INVALID_REF; + info->tx.sring = NULL; + info->rx.sring = NULL; +} + +/** + * We are reconnecting to the backend, due to a suspend/resume, or a backend + * driver restart. We tear down our netif structure and recreate it, but + * leave the device-layer structures intact so that this is transparent to the + * rest of the kernel. + */ +static int netfront_resume(struct xenbus_device *dev) +{ + struct netfront_info *info = dev->dev.driver_data; + + dev_dbg(&dev->dev, "%s\n", dev->nodename); + + xennet_disconnect_backend(info); + return 0; +} + +static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[]) +{ + char *s, *e, *macstr; + int i; + + macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL); + if (IS_ERR(macstr)) + return PTR_ERR(macstr); + + for (i = 0; i < ETH_ALEN; i++) { + mac[i] = simple_strtoul(s, &e, 16); + if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) { + kfree(macstr); + return -ENOENT; + } + s = e+1; + } + + kfree(macstr); + return 0; +} + +static irqreturn_t xennet_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct netfront_info *np = netdev_priv(dev); + unsigned long flags; + + spin_lock_irqsave(&np->tx_lock, flags); + + if (likely(netif_carrier_ok(dev))) { + xennet_tx_buf_gc(dev); + /* Under tx_lock: protects access to rx shared-ring indexes. */ + if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx)) + netif_rx_schedule(dev); + } + + spin_unlock_irqrestore(&np->tx_lock, flags); + + return IRQ_HANDLED; +} + +static int setup_netfront(struct xenbus_device *dev, struct netfront_info *info) +{ + struct xen_netif_tx_sring *txs; + struct xen_netif_rx_sring *rxs; + int err; + struct net_device *netdev = info->netdev; + + info->tx_ring_ref = GRANT_INVALID_REF; + info->rx_ring_ref = GRANT_INVALID_REF; + info->rx.sring = NULL; + info->tx.sring = NULL; + netdev->irq = 0; + + err = xen_net_read_mac(dev, netdev->dev_addr); + if (err) { + xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename); + goto fail; + } + + txs = (struct xen_netif_tx_sring *)get_zeroed_page(GFP_KERNEL); + if (!txs) { + err = -ENOMEM; + xenbus_dev_fatal(dev, err, "allocating tx ring page"); + goto fail; + } + SHARED_RING_INIT(txs); + FRONT_RING_INIT(&info->tx, txs, PAGE_SIZE); + + err = xenbus_grant_ring(dev, virt_to_mfn(txs)); + if (err < 0) { + free_page((unsigned long)txs); + goto fail; + } + + info->tx_ring_ref = err; + rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_KERNEL); + if (!rxs) { + err = -ENOMEM; + xenbus_dev_fatal(dev, err, "allocating rx ring page"); + goto fail; + } + SHARED_RING_INIT(rxs); + FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE); + + err = xenbus_grant_ring(dev, virt_to_mfn(rxs)); + if (err < 0) { + free_page((unsigned long)rxs); + goto fail; + } + info->rx_ring_ref = err; + + err = xenbus_alloc_evtchn(dev, &info->evtchn); + if (err) + goto fail; + + err = bind_evtchn_to_irqhandler(info->evtchn, xennet_interrupt, + IRQF_SAMPLE_RANDOM, netdev->name, + netdev); + if (err < 0) + goto fail; + netdev->irq = err; + return 0; + + fail: + return err; +} + +/* Common code used when first setting up, and when resuming. */ +static int talk_to_backend(struct xenbus_device *dev, + struct netfront_info *info) +{ + const char *message; + struct xenbus_transaction xbt; + int err; + + /* Create shared ring, alloc event channel. */ + err = setup_netfront(dev, info); + if (err) + goto out; + +again: + err = xenbus_transaction_start(&xbt); + if (err) { + xenbus_dev_fatal(dev, err, "starting transaction"); + goto destroy_ring; + } + + err = xenbus_printf(xbt, dev->nodename, "tx-ring-ref", "%u", + info->tx_ring_ref); + if (err) { + message = "writing tx ring-ref"; + goto abort_transaction; + } + err = xenbus_printf(xbt, dev->nodename, "rx-ring-ref", "%u", + info->rx_ring_ref); + if (err) { + message = "writing rx ring-ref"; + goto abort_transaction; + } + err = xenbus_printf(xbt, dev->nodename, + "event-channel", "%u", info->evtchn); + if (err) { + message = "writing event-channel"; + goto abort_transaction; + } + + err = xenbus_printf(xbt, dev->nodename, "request-rx-copy", "%u", + 1); + if (err) { + message = "writing request-rx-copy"; + goto abort_transaction; + } + + err = xenbus_printf(xbt, dev->nodename, "feature-rx-notify", "%d", 1); + if (err) { + message = "writing feature-rx-notify"; + goto abort_transaction; + } + + err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", 1); + if (err) { + message = "writing feature-sg"; + goto abort_transaction; + } + + err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", "%d", 1); + if (err) { + message = "writing feature-gso-tcpv4"; + goto abort_transaction; + } + + err = xenbus_transaction_end(xbt, 0); + if (err) { + if (err == -EAGAIN) + goto again; + xenbus_dev_fatal(dev, err, "completing transaction"); + goto destroy_ring; + } + + return 0; + + abort_transaction: + xenbus_transaction_end(xbt, 1); + xenbus_dev_fatal(dev, err, "%s", message); + destroy_ring: + xennet_disconnect_backend(info); + out: + return err; +} + +static int xennet_set_sg(struct net_device *dev, u32 data) +{ + if (data) { + struct netfront_info *np = netdev_priv(dev); + int val; + + if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, "feature-sg", + "%d", &val) < 0) + val = 0; + if (!val) + return -ENOSYS; + } else if (dev->mtu > ETH_DATA_LEN) + dev->mtu = ETH_DATA_LEN; + + return ethtool_op_set_sg(dev, data); +} + +static int xennet_set_tso(struct net_device *dev, u32 data) +{ + if (data) { + struct netfront_info *np = netdev_priv(dev); + int val; + + if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, + "feature-gso-tcpv4", "%d", &val) < 0) + val = 0; + if (!val) + return -ENOSYS; + } + + return ethtool_op_set_tso(dev, data); +} + +static void xennet_set_features(struct net_device *dev) +{ + /* Turn off all GSO bits except ROBUST. */ + dev->features &= (1 << NETIF_F_GSO_SHIFT) - 1; + dev->features |= NETIF_F_GSO_ROBUST; + xennet_set_sg(dev, 0); + + /* We need checksum offload to enable scatter/gather and TSO. */ + if (!(dev->features & NETIF_F_IP_CSUM)) + return; + + if (!xennet_set_sg(dev, 1)) + xennet_set_tso(dev, 1); +} + +static int xennet_connect(struct net_device *dev) +{ + struct netfront_info *np = netdev_priv(dev); + int i, requeue_idx, err; + struct sk_buff *skb; + grant_ref_t ref; + struct xen_netif_rx_request *req; + unsigned int feature_rx_copy; + + err = xenbus_scanf(XBT_NIL, np->xbdev->otherend, + "feature-rx-copy", "%u", &feature_rx_copy); + if (err != 1) + feature_rx_copy = 0; + + if (!feature_rx_copy) { + dev_info(&dev->dev, + "backend does not support copying recieve path"); + return -ENODEV; + } + + err = talk_to_backend(np->xbdev, np); + if (err) + return err; + + xennet_set_features(dev); + + spin_lock_bh(&np->rx_lock); + spin_lock_irq(&np->tx_lock); + + /* Step 1: Discard all pending TX packet fragments. */ + xennet_release_tx_bufs(np); + + /* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */ + for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) { + if (!np->rx_skbs[i]) + continue; + + skb = np->rx_skbs[requeue_idx] = xennet_get_rx_skb(np, i); + ref = np->grant_rx_ref[requeue_idx] = xennet_get_rx_ref(np, i); + req = RING_GET_REQUEST(&np->rx, requeue_idx); + + gnttab_grant_foreign_access_ref( + ref, np->xbdev->otherend_id, + pfn_to_mfn(page_to_pfn(skb_shinfo(skb)-> + frags->page)), + 0); + req->gref = ref; + req->id = requeue_idx; + + requeue_idx++; + } + + np->rx.req_prod_pvt = requeue_idx; + + /* + * Step 3: All public and private state should now be sane. Get + * ready to start sending and receiving packets and give the driver + * domain a kick because we've probably just requeued some + * packets. + */ + netif_carrier_on(np->netdev); + notify_remote_via_irq(np->netdev->irq); + xennet_tx_buf_gc(dev); + xennet_alloc_rx_buffers(dev); + + spin_unlock_irq(&np->tx_lock); + spin_unlock_bh(&np->rx_lock); + + return 0; +} + +/** + * Callback received when the backend's state changes. + */ +static void backend_changed(struct xenbus_device *dev, + enum xenbus_state backend_state) +{ + struct netfront_info *np = dev->dev.driver_data; + struct net_device *netdev = np->netdev; + + dev_dbg(&dev->dev, "%s\n", xenbus_strstate(backend_state)); + + switch (backend_state) { + case XenbusStateInitialising: + case XenbusStateInitialised: + case XenbusStateConnected: + case XenbusStateUnknown: + case XenbusStateClosed: + break; + + case XenbusStateInitWait: + if (dev->state != XenbusStateInitialising) + break; + if (xennet_connect(netdev) != 0) + break; + xenbus_switch_state(dev, XenbusStateConnected); + break; + + case XenbusStateClosing: + xenbus_frontend_closed(dev); + break; + } +} + +static struct ethtool_ops xennet_ethtool_ops = +{ + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = xennet_set_sg, + .get_tso = ethtool_op_get_tso, + .set_tso = xennet_set_tso, + .get_link = ethtool_op_get_link, +}; + +#ifdef CONFIG_SYSFS +static ssize_t show_rxbuf_min(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct net_device *netdev = to_net_dev(dev); + struct netfront_info *info = netdev_priv(netdev); + + return sprintf(buf, "%u\n", info->rx_min_target); +} + +static ssize_t store_rxbuf_min(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct net_device *netdev = to_net_dev(dev); + struct netfront_info *np = netdev_priv(netdev); + char *endp; + unsigned long target; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + target = simple_strtoul(buf, &endp, 0); + if (endp == buf) + return -EBADMSG; + + if (target < RX_MIN_TARGET) + target = RX_MIN_TARGET; + if (target > RX_MAX_TARGET) + target = RX_MAX_TARGET; + + spin_lock_bh(&np->rx_lock); + if (target > np->rx_max_target) + np->rx_max_target = target; + np->rx_min_target = target; + if (target > np->rx_target) + np->rx_target = target; + + xennet_alloc_rx_buffers(netdev); + + spin_unlock_bh(&np->rx_lock); + return len; +} + +static ssize_t show_rxbuf_max(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct net_device *netdev = to_net_dev(dev); + struct netfront_info *info = netdev_priv(netdev); + + return sprintf(buf, "%u\n", info->rx_max_target); +} + +static ssize_t store_rxbuf_max(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct net_device *netdev = to_net_dev(dev); + struct netfront_info *np = netdev_priv(netdev); + char *endp; + unsigned long target; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + target = simple_strtoul(buf, &endp, 0); + if (endp == buf) + return -EBADMSG; + + if (target < RX_MIN_TARGET) + target = RX_MIN_TARGET; + if (target > RX_MAX_TARGET) + target = RX_MAX_TARGET; + + spin_lock_bh(&np->rx_lock); + if (target < np->rx_min_target) + np->rx_min_target = target; + np->rx_max_target = target; + if (target < np->rx_target) + np->rx_target = target; + + xennet_alloc_rx_buffers(netdev); + + spin_unlock_bh(&np->rx_lock); + return len; +} + +static ssize_t show_rxbuf_cur(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct net_device *netdev = to_net_dev(dev); + struct netfront_info *info = netdev_priv(netdev); + + return sprintf(buf, "%u\n", info->rx_target); +} + +static struct device_attribute xennet_attrs[] = { + __ATTR(rxbuf_min, S_IRUGO|S_IWUSR, show_rxbuf_min, store_rxbuf_min), + __ATTR(rxbuf_max, S_IRUGO|S_IWUSR, show_rxbuf_max, store_rxbuf_max), + __ATTR(rxbuf_cur, S_IRUGO, show_rxbuf_cur, NULL), +}; + +static int xennet_sysfs_addif(struct net_device *netdev) +{ + int i; + int err; + + for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++) { + err = device_create_file(&netdev->dev, + &xennet_attrs[i]); + if (err) + goto fail; + } + return 0; + + fail: + while (--i >= 0) + device_remove_file(&netdev->dev, &xennet_attrs[i]); + return err; +} + +static void xennet_sysfs_delif(struct net_device *netdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++) + device_remove_file(&netdev->dev, &xennet_attrs[i]); +} + +#endif /* CONFIG_SYSFS */ + +static struct xenbus_device_id netfront_ids[] = { + { "vif" }, + { "" } +}; + + +static int __devexit xennet_remove(struct xenbus_device *dev) +{ + struct netfront_info *info = dev->dev.driver_data; + + dev_dbg(&dev->dev, "%s\n", dev->nodename); + + unregister_netdev(info->netdev); + + xennet_disconnect_backend(info); + + del_timer_sync(&info->rx_refill_timer); + + xennet_sysfs_delif(info->netdev); + + free_netdev(info->netdev); + + return 0; +} + +static struct xenbus_driver netfront = { + .name = "vif", + .owner = THIS_MODULE, + .ids = netfront_ids, + .probe = netfront_probe, + .remove = __devexit_p(xennet_remove), + .resume = netfront_resume, + .otherend_changed = backend_changed, +}; + +static int __init netif_init(void) +{ + if (!is_running_on_xen()) + return -ENODEV; + + if (is_initial_xendomain()) + return 0; + + printk(KERN_INFO "Initialising Xen virtual ethernet driver.\n"); + + return xenbus_register_frontend(&netfront); +} +module_init(netif_init); + + +static void __exit netif_exit(void) +{ + if (is_initial_xendomain()) + return; + + return xenbus_unregister_driver(&netfront); +} +module_exit(netif_exit); + +MODULE_DESCRIPTION("Xen virtual network device frontend"); +MODULE_LICENSE("GPL"); diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c index a708c329675e..38cdf9fa36a7 100644 --- a/drivers/parisc/superio.c +++ b/drivers/parisc/superio.c @@ -73,6 +73,7 @@ #include <linux/termios.h> #include <linux/tty.h> #include <linux/serial_core.h> +#include <linux/serial_8250.h> #include <linux/delay.h> #include <asm/io.h> diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index 03baf1c64a2e..ed112ee16012 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -147,7 +147,7 @@ static int pnp_dock_event(int dock, struct pnp_docking_station_info *info) info->location_id, info->serial, info->capabilities); envp[i] = NULL; - value = call_usermodehelper (argv [0], argv, envp, 0); + value = call_usermodehelper (argv [0], argv, envp, UMH_WAIT_EXEC); kfree (buf); kfree (envp); return 0; diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c index a54e4140683a..e821a155b658 100644 --- a/drivers/sbus/char/bbc_envctrl.c +++ b/drivers/sbus/char/bbc_envctrl.c @@ -7,6 +7,7 @@ #include <linux/kthread.h> #include <linux/delay.h> #include <linux/kmod.h> +#include <linux/reboot.h> #include <asm/oplib.h> #include <asm/ebus.h> @@ -170,8 +171,6 @@ static void get_current_temps(struct bbc_cpu_temperature *tp) static void do_envctrl_shutdown(struct bbc_cpu_temperature *tp) { static int shutting_down = 0; - static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; - char *argv[] = { "/sbin/shutdown", "-h", "now", NULL }; char *type = "???"; s8 val = -1; @@ -195,7 +194,7 @@ static void do_envctrl_shutdown(struct bbc_cpu_temperature *tp) printk(KERN_CRIT "kenvctrld: Shutting down the system now.\n"); shutting_down = 1; - if (call_usermodehelper("/sbin/shutdown", argv, envp, 0) < 0) + if (orderly_poweroff(true) < 0) printk(KERN_CRIT "envctrl: shutdown execution failed\n"); } diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index 8328acab47fd..dadabef116b6 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -26,6 +26,7 @@ #include <linux/ioport.h> #include <linux/miscdevice.h> #include <linux/kmod.h> +#include <linux/reboot.h> #include <asm/ebus.h> #include <asm/uaccess.h> @@ -966,10 +967,6 @@ static struct i2c_child_t *envctrl_get_i2c_child(unsigned char mon_type) static void envctrl_do_shutdown(void) { static int inprog = 0; - static char *envp[] = { - "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; - char *argv[] = { - "/sbin/shutdown", "-h", "now", NULL }; int ret; if (inprog != 0) @@ -977,7 +974,7 @@ static void envctrl_do_shutdown(void) inprog = 1; printk(KERN_CRIT "kenvctrld: WARNING: Shutting down the system now.\n"); - ret = call_usermodehelper("/sbin/shutdown", argv, envp, 0); + ret = orderly_poweroff(true); if (ret < 0) { printk(KERN_CRIT "kenvctrld: WARNING: system shutdown failed!\n"); inprog = 0; /* unlikely to succeed, but we could try again */ diff --git a/drivers/serial/8250_hp300.c b/drivers/serial/8250_hp300.c index 53e81a44c1a3..2cf0953fe0ec 100644 --- a/drivers/serial/8250_hp300.c +++ b/drivers/serial/8250_hp300.c @@ -11,6 +11,7 @@ #include <linux/kernel.h> #include <linux/serial.h> #include <linux/serial_core.h> +#include <linux/serial_8250.h> #include <linux/delay.h> #include <linux/dio.h> #include <linux/console.h> diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 7fa413ddccf5..18f629706448 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -486,6 +486,36 @@ config SERIAL_DZ_CONSOLE If unsure, say Y. +config SERIAL_ZS + tristate "DECstation Z85C30 serial support" + depends on MACH_DECSTATION + select SERIAL_CORE + default y + ---help--- + Support for the Zilog 85C350 serial communications controller used + for serial ports in newer DECstation systems. These include the + DECsystem 5900 and all models of the DECstation and DECsystem 5000 + systems except from model 200. + + If unsure, say Y. To compile this driver as a module, choose M here: + the module will be called zs. + +config SERIAL_ZS_CONSOLE + bool "Support for console on a DECstation Z85C30 serial port" + depends on SERIAL_ZS=y + select SERIAL_CORE_CONSOLE + default y + ---help--- + If you say Y here, it will be possible to use a serial port as the + system console (the system console is the device which receives all + kernel messages and warnings and which allows logins in single user + mode). + + Note that the firmware uses ttyS1 as the serial console on the + Maxine and ttyS3 on the others using this driver. + + If unsure, say Y. + config SERIAL_21285 tristate "DC21285 serial port support" depends on ARM && FOOTBRIDGE diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index c48cdd61b736..af6377d480d7 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_V850E_UART) += v850e_uart.o obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o obj-$(CONFIG_SERIAL_DZ) += dz.o +obj-$(CONFIG_SERIAL_ZS) += zs.o obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o obj-$(CONFIG_SERIAL_SGI_L1_CONSOLE) += sn_console.o obj-$(CONFIG_SERIAL_CPM) += cpm_uart/ diff --git a/drivers/serial/zs.c b/drivers/serial/zs.c new file mode 100644 index 000000000000..65f1294fd27b --- /dev/null +++ b/drivers/serial/zs.c @@ -0,0 +1,1287 @@ +/* + * zs.c: Serial port driver for IOASIC DECstations. + * + * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras. + * Derived from drivers/macintosh/macserial.c by Harald Koerfgen. + * + * DECstation changes + * Copyright (C) 1998-2000 Harald Koerfgen + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007 Maciej W. Rozycki + * + * For the rest of the code the original Copyright applies: + * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au) + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * + * + * Note: for IOASIC systems the wiring is as follows: + * + * mouse/keyboard: + * DIN-7 MJ-4 signal SCC + * 2 1 TxD <- A.TxD + * 3 4 RxD -> A.RxD + * + * EIA-232/EIA-423: + * DB-25 MMJ-6 signal SCC + * 2 2 TxD <- B.TxD + * 3 5 RxD -> B.RxD + * 4 RTS <- ~A.RTS + * 5 CTS -> ~B.CTS + * 6 6 DSR -> ~A.SYNC + * 8 CD -> ~B.DCD + * 12 DSRS(DCE) -> ~A.CTS (*) + * 15 TxC -> B.TxC + * 17 RxC -> B.RxC + * 20 1 DTR <- ~A.DTR + * 22 RI -> ~A.DCD + * 23 DSRS(DTE) <- ~B.RTS + * + * (*) EIA-232 defines the signal at this pin to be SCD, while DSRS(DCE) + * is shared with DSRS(DTE) at pin 23. + * + * As you can immediately notice the wiring of the RTS, DTR and DSR signals + * is a bit odd. This makes the handling of port B unnecessarily + * complicated and prevents the use of some automatic modes of operation. + */ + +#if defined(CONFIG_SERIAL_ZS_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include <linux/bug.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/irqflags.h> +#include <linux/kernel.h> +#include <linux/major.h> +#include <linux/serial.h> +#include <linux/serial_core.h> +#include <linux/spinlock.h> +#include <linux/sysrq.h> +#include <linux/tty.h> +#include <linux/types.h> + +#include <asm/atomic.h> +#include <asm/system.h> + +#include <asm/dec/interrupts.h> +#include <asm/dec/ioasic_addrs.h> +#include <asm/dec/system.h> + +#include "zs.h" + + +MODULE_AUTHOR("Maciej W. Rozycki <macro@linux-mips.org>"); +MODULE_DESCRIPTION("DECstation Z85C30 serial driver"); +MODULE_LICENSE("GPL"); + + +static char zs_name[] __initdata = "DECstation Z85C30 serial driver version "; +static char zs_version[] __initdata = "0.10"; + +/* + * It would be nice to dynamically allocate everything that + * depends on ZS_NUM_SCCS, so we could support any number of + * Z85C30s, but for now... + */ +#define ZS_NUM_SCCS 2 /* Max # of ZS chips supported. */ +#define ZS_NUM_CHAN 2 /* 2 channels per chip. */ +#define ZS_CHAN_A 0 /* Index of the channel A. */ +#define ZS_CHAN_B 1 /* Index of the channel B. */ +#define ZS_CHAN_IO_SIZE 8 /* IOMEM space size. */ +#define ZS_CHAN_IO_STRIDE 4 /* Register alignment. */ +#define ZS_CHAN_IO_OFFSET 1 /* The SCC resides on the high byte + of the 16-bit IOBUS. */ +#define ZS_CLOCK 7372800 /* Z85C30 PCLK input clock rate. */ + +#define to_zport(uport) container_of(uport, struct zs_port, port) + +struct zs_parms { + resource_size_t scc[ZS_NUM_SCCS]; + int irq[ZS_NUM_SCCS]; +}; + +static struct zs_scc zs_sccs[ZS_NUM_SCCS]; + +static u8 zs_init_regs[ZS_NUM_REGS] __initdata = { + 0, /* write 0 */ + PAR_SPEC, /* write 1 */ + 0, /* write 2 */ + 0, /* write 3 */ + X16CLK | SB1, /* write 4 */ + 0, /* write 5 */ + 0, 0, 0, /* write 6, 7, 8 */ + MIE | DLC | NV, /* write 9 */ + NRZ, /* write 10 */ + TCBR | RCBR, /* write 11 */ + 0, 0, /* BRG time constant, write 12 + 13 */ + BRSRC | BRENABL, /* write 14 */ + 0, /* write 15 */ +}; + +/* + * Debugging. + */ +#undef ZS_DEBUG_REGS + + +/* + * Reading and writing Z85C30 registers. + */ +static void recovery_delay(void) +{ + udelay(2); +} + +static u8 read_zsreg(struct zs_port *zport, int reg) +{ + void __iomem *control = zport->port.membase + ZS_CHAN_IO_OFFSET; + u8 retval; + + if (reg != 0) { + writeb(reg & 0xf, control); + fast_iob(); + recovery_delay(); + } + retval = readb(control); + recovery_delay(); + return retval; +} + +static void write_zsreg(struct zs_port *zport, int reg, u8 value) +{ + void __iomem *control = zport->port.membase + ZS_CHAN_IO_OFFSET; + + if (reg != 0) { + writeb(reg & 0xf, control); + fast_iob(); recovery_delay(); + } + writeb(value, control); + fast_iob(); + recovery_delay(); + return; +} + +static u8 read_zsdata(struct zs_port *zport) +{ + void __iomem *data = zport->port.membase + + ZS_CHAN_IO_STRIDE + ZS_CHAN_IO_OFFSET; + u8 retval; + + retval = readb(data); + recovery_delay(); + return retval; +} + +static void write_zsdata(struct zs_port *zport, u8 value) +{ + void __iomem *data = zport->port.membase + + ZS_CHAN_IO_STRIDE + ZS_CHAN_IO_OFFSET; + + writeb(value, data); + fast_iob(); + recovery_delay(); + return; +} + +#ifdef ZS_DEBUG_REGS +void zs_dump(void) +{ + struct zs_port *zport; + int i, j; + + for (i = 0; i < ZS_NUM_SCCS * ZS_NUM_CHAN; i++) { + zport = &zs_sccs[i / ZS_NUM_CHAN].zport[i % ZS_NUM_CHAN]; + + if (!zport->scc) + continue; + + for (j = 0; j < 16; j++) + printk("W%-2d = 0x%02x\t", j, zport->regs[j]); + printk("\n"); + for (j = 0; j < 16; j++) + printk("R%-2d = 0x%02x\t", j, read_zsreg(zport, j)); + printk("\n\n"); + } +} +#endif + + +static void zs_spin_lock_cond_irq(spinlock_t *lock, int irq) +{ + if (irq) + spin_lock_irq(lock); + else + spin_lock(lock); +} + +static void zs_spin_unlock_cond_irq(spinlock_t *lock, int irq) +{ + if (irq) + spin_unlock_irq(lock); + else + spin_unlock(lock); +} + +static int zs_receive_drain(struct zs_port *zport) +{ + int loops = 10000; + + while ((read_zsreg(zport, R0) & Rx_CH_AV) && loops--) + read_zsdata(zport); + return loops; +} + +static int zs_transmit_drain(struct zs_port *zport, int irq) +{ + struct zs_scc *scc = zport->scc; + int loops = 10000; + + while (!(read_zsreg(zport, R0) & Tx_BUF_EMP) && loops--) { + zs_spin_unlock_cond_irq(&scc->zlock, irq); + udelay(2); + zs_spin_lock_cond_irq(&scc->zlock, irq); + } + return loops; +} + +static int zs_line_drain(struct zs_port *zport, int irq) +{ + struct zs_scc *scc = zport->scc; + int loops = 10000; + + while (!(read_zsreg(zport, R1) & ALL_SNT) && loops--) { + zs_spin_unlock_cond_irq(&scc->zlock, irq); + udelay(2); + zs_spin_lock_cond_irq(&scc->zlock, irq); + } + return loops; +} + + +static void load_zsregs(struct zs_port *zport, u8 *regs, int irq) +{ + /* Let the current transmission finish. */ + zs_line_drain(zport, irq); + /* Load 'em up. */ + write_zsreg(zport, R3, regs[3] & ~RxENABLE); + write_zsreg(zport, R5, regs[5] & ~TxENAB); + write_zsreg(zport, R4, regs[4]); + write_zsreg(zport, R9, regs[9]); + write_zsreg(zport, R1, regs[1]); + write_zsreg(zport, R2, regs[2]); + write_zsreg(zport, R10, regs[10]); + write_zsreg(zport, R14, regs[14] & ~BRENABL); + write_zsreg(zport, R11, regs[11]); + write_zsreg(zport, R12, regs[12]); + write_zsreg(zport, R13, regs[13]); + write_zsreg(zport, R14, regs[14]); + write_zsreg(zport, R15, regs[15]); + if (regs[3] & RxENABLE) + write_zsreg(zport, R3, regs[3]); + if (regs[5] & TxENAB) + write_zsreg(zport, R5, regs[5]); + return; +} + + +/* + * Status handling routines. + */ + +/* + * zs_tx_empty() -- get the transmitter empty status + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows an RS485 driver to be written in user space. + */ +static unsigned int zs_tx_empty(struct uart_port *uport) +{ + struct zs_port *zport = to_zport(uport); + struct zs_scc *scc = zport->scc; + unsigned long flags; + u8 status; + + spin_lock_irqsave(&scc->zlock, flags); + status = read_zsreg(zport, R1); + spin_unlock_irqrestore(&scc->zlock, flags); + + return status & ALL_SNT ? TIOCSER_TEMT : 0; +} + +static unsigned int zs_raw_get_ab_mctrl(struct zs_port *zport_a, + struct zs_port *zport_b) +{ + u8 status_a, status_b; + unsigned int mctrl; + + status_a = read_zsreg(zport_a, R0); + status_b = read_zsreg(zport_b, R0); + + mctrl = ((status_b & CTS) ? TIOCM_CTS : 0) | + ((status_b & DCD) ? TIOCM_CAR : 0) | + ((status_a & DCD) ? TIOCM_RNG : 0) | + ((status_a & SYNC_HUNT) ? TIOCM_DSR : 0); + + return mctrl; +} + +static unsigned int zs_raw_get_mctrl(struct zs_port *zport) +{ + struct zs_port *zport_a = &zport->scc->zport[ZS_CHAN_A]; + + return zport != zport_a ? zs_raw_get_ab_mctrl(zport_a, zport) : 0; +} + +static unsigned int zs_raw_xor_mctrl(struct zs_port *zport) +{ + struct zs_port *zport_a = &zport->scc->zport[ZS_CHAN_A]; + unsigned int mmask, mctrl, delta; + u8 mask_a, mask_b; + + if (zport == zport_a) + return 0; + + mask_a = zport_a->regs[15]; + mask_b = zport->regs[15]; + + mmask = ((mask_b & CTSIE) ? TIOCM_CTS : 0) | + ((mask_b & DCDIE) ? TIOCM_CAR : 0) | + ((mask_a & DCDIE) ? TIOCM_RNG : 0) | + ((mask_a & SYNCIE) ? TIOCM_DSR : 0); + + mctrl = zport->mctrl; + if (mmask) { + mctrl &= ~mmask; + mctrl |= zs_raw_get_ab_mctrl(zport_a, zport) & mmask; + } + + delta = mctrl ^ zport->mctrl; + if (delta) + zport->mctrl = mctrl; + + return delta; +} + +static unsigned int zs_get_mctrl(struct uart_port *uport) +{ + struct zs_port *zport = to_zport(uport); + struct zs_scc *scc = zport->scc; + unsigned int mctrl; + + spin_lock(&scc->zlock); + mctrl = zs_raw_get_mctrl(zport); + spin_unlock(&scc->zlock); + + return mctrl; +} + +static void zs_set_mctrl(struct uart_port *uport, unsigned int mctrl) +{ + struct zs_port *zport = to_zport(uport); + struct zs_scc *scc = zport->scc; + struct zs_port *zport_a = &scc->zport[ZS_CHAN_A]; + u8 oldloop, newloop; + + spin_lock(&scc->zlock); + if (zport != zport_a) { + if (mctrl & TIOCM_DTR) + zport_a->regs[5] |= DTR; + else + zport_a->regs[5] &= ~DTR; + if (mctrl & TIOCM_RTS) + zport_a->regs[5] |= RTS; + else + zport_a->regs[5] &= ~RTS; + write_zsreg(zport_a, R5, zport_a->regs[5]); + } + + /* Rarely modified, so don't poke at hardware unless necessary. */ + oldloop = zport->regs[14]; + newloop = oldloop; + if (mctrl & TIOCM_LOOP) + newloop |= LOOPBAK; + else + newloop &= ~LOOPBAK; + if (newloop != oldloop) { + zport->regs[14] = newloop; + write_zsreg(zport, R14, zport->regs[14]); + } + spin_unlock(&scc->zlock); +} + +static void zs_raw_stop_tx(struct zs_port *zport) +{ + write_zsreg(zport, R0, RES_Tx_P); + zport->tx_stopped = 1; +} + +static void zs_stop_tx(struct uart_port *uport) +{ + struct zs_port *zport = to_zport(uport); + struct zs_scc *scc = zport->scc; + + spin_lock(&scc->zlock); + zs_raw_stop_tx(zport); + spin_unlock(&scc->zlock); +} + +static void zs_raw_transmit_chars(struct zs_port *); + +static void zs_start_tx(struct uart_port *uport) +{ + struct zs_port *zport = to_zport(uport); + struct zs_scc *scc = zport->scc; + + spin_lock(&scc->zlock); + if (zport->tx_stopped) { + zs_transmit_drain(zport, 0); + zport->tx_stopped = 0; + zs_raw_transmit_chars(zport); + } + spin_unlock(&scc->zlock); +} + +static void zs_stop_rx(struct uart_port *uport) +{ + struct zs_port *zport = to_zport(uport); + struct zs_scc *scc = zport->scc; + struct zs_port *zport_a = &scc->zport[ZS_CHAN_A]; + + spin_lock(&scc->zlock); + zport->regs[15] &= ~BRKIE; + zport->regs[1] &= ~(RxINT_MASK | TxINT_ENAB); + zport->regs[1] |= RxINT_DISAB; + + if (zport != zport_a) { + /* A-side DCD tracks RI and SYNC tracks DSR. */ + zport_a->regs[15] &= ~(DCDIE | SYNCIE); + write_zsreg(zport_a, R15, zport_a->regs[15]); + if (!(zport_a->regs[15] & BRKIE)) { + zport_a->regs[1] &= ~EXT_INT_ENAB; + write_zsreg(zport_a, R1, zport_a->regs[1]); + } + + /* This-side DCD tracks DCD and CTS tracks CTS. */ + zport->regs[15] &= ~(DCDIE | CTSIE); + zport->regs[1] &= ~EXT_INT_ENAB; + } else { + /* DCD tracks RI and SYNC tracks DSR for the B side. */ + if (!(zport->regs[15] & (DCDIE | SYNCIE))) + zport->regs[1] &= ~EXT_INT_ENAB; + } + + write_zsreg(zport, R15, zport->regs[15]); + write_zsreg(zport, R1, zport->regs[1]); + spin_unlock(&scc->zlock); +} + +static void zs_enable_ms(struct uart_port *uport) +{ + struct zs_port *zport = to_zport(uport); + struct zs_scc *scc = zport->scc; + struct zs_port *zport_a = &scc->zport[ZS_CHAN_A]; + + if (zport == zport_a) + return; + + spin_lock(&scc->zlock); + + /* Clear Ext interrupts if not being handled already. */ + if (!(zport_a->regs[1] & EXT_INT_ENAB)) + write_zsreg(zport_a, R0, RES_EXT_INT); + + /* A-side DCD tracks RI and SYNC tracks DSR. */ + zport_a->regs[1] |= EXT_INT_ENAB; + zport_a->regs[15] |= DCDIE | SYNCIE; + + /* This-side DCD tracks DCD and CTS tracks CTS. */ + zport->regs[15] |= DCDIE | CTSIE; + + zs_raw_xor_mctrl(zport); + + write_zsreg(zport_a, R1, zport_a->regs[1]); + write_zsreg(zport_a, R15, zport_a->regs[15]); + write_zsreg(zport, R15, zport->regs[15]); + spin_unlock(&scc->zlock); +} + +static void zs_break_ctl(struct uart_port *uport, int break_state) +{ + struct zs_port *zport = to_zport(uport); + struct zs_scc *scc = zport->scc; + unsigned long flags; + + spin_lock_irqsave(&scc->zlock, flags); + if (break_state == -1) + zport->regs[5] |= SND_BRK; + else + zport->regs[5] &= ~SND_BRK; + write_zsreg(zport, R5, zport->regs[5]); + spin_unlock_irqrestore(&scc->zlock, flags); +} + + +/* + * Interrupt handling routines. + */ +#define Rx_BRK 0x0100 /* BREAK event software flag. */ +#define Rx_SYS 0x0200 /* SysRq event software flag. */ + +static void zs_receive_chars(struct zs_port *zport) +{ + struct uart_port *uport = &zport->port; + struct zs_scc *scc = zport->scc; + struct uart_icount *icount; + unsigned int avail, status, ch, flag; + int count; + + for (count = 16; count; count--) { + spin_lock(&scc->zlock); + avail = read_zsreg(zport, R0) & Rx_CH_AV; + spin_unlock(&scc->zlock); + if (!avail) + break; + + spin_lock(&scc->zlock); + status = read_zsreg(zport, R1) & (Rx_OVR | FRM_ERR | PAR_ERR); + ch = read_zsdata(zport); + spin_unlock(&scc->zlock); + + flag = TTY_NORMAL; + + icount = &uport->icount; + icount->rx++; + + /* Handle the null char got when BREAK is removed. */ + if (!ch) + status |= zport->tty_break; + if (unlikely(status & + (Rx_OVR | FRM_ERR | PAR_ERR | Rx_SYS | Rx_BRK))) { + zport->tty_break = 0; + + /* Reset the error indication. */ + if (status & (Rx_OVR | FRM_ERR | PAR_ERR)) { + spin_lock(&scc->zlock); + write_zsreg(zport, R0, ERR_RES); + spin_unlock(&scc->zlock); + } + + if (status & (Rx_SYS | Rx_BRK)) { + icount->brk++; + /* SysRq discards the null char. */ + if (status & Rx_SYS) + continue; + } else if (status & FRM_ERR) + icount->frame++; + else if (status & PAR_ERR) + icount->parity++; + if (status & Rx_OVR) + icount->overrun++; + + status &= uport->read_status_mask; + if (status & Rx_BRK) + flag = TTY_BREAK; + else if (status & FRM_ERR) + flag = TTY_FRAME; + else if (status & PAR_ERR) + flag = TTY_PARITY; + } + + if (uart_handle_sysrq_char(uport, ch)) + continue; + + uart_insert_char(uport, status, Rx_OVR, ch, flag); + } + + tty_flip_buffer_push(uport->info->tty); +} + +static void zs_raw_transmit_chars(struct zs_port *zport) +{ + struct circ_buf *xmit = &zport->port.info->xmit; + + /* XON/XOFF chars. */ + if (zport->port.x_char) { + write_zsdata(zport, zport->port.x_char); + zport->port.icount.tx++; + zport->port.x_char = 0; + return; + } + + /* If nothing to do or stopped or hardware stopped. */ + if (uart_circ_empty(xmit) || uart_tx_stopped(&zport->port)) { + zs_raw_stop_tx(zport); + return; + } + + /* Send char. */ + write_zsdata(zport, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + zport->port.icount.tx++; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&zport->port); + + /* Are we are done? */ + if (uart_circ_empty(xmit)) + zs_raw_stop_tx(zport); +} + +static void zs_transmit_chars(struct zs_port *zport) +{ + struct zs_scc *scc = zport->scc; + + spin_lock(&scc->zlock); + zs_raw_transmit_chars(zport); + spin_unlock(&scc->zlock); +} + +static void zs_status_handle(struct zs_port *zport, struct zs_port *zport_a) +{ + struct uart_port *uport = &zport->port; + struct zs_scc *scc = zport->scc; + unsigned int delta; + u8 status, brk; + + spin_lock(&scc->zlock); + + /* Get status from Read Register 0. */ + status = read_zsreg(zport, R0); + + if (zport->regs[15] & BRKIE) { + brk = status & BRK_ABRT; + if (brk && !zport->brk) { + spin_unlock(&scc->zlock); + if (uart_handle_break(uport)) + zport->tty_break = Rx_SYS; + else + zport->tty_break = Rx_BRK; + spin_lock(&scc->zlock); + } + zport->brk = brk; + } + + if (zport != zport_a) { + delta = zs_raw_xor_mctrl(zport); + spin_unlock(&scc->zlock); + + if (delta & TIOCM_CTS) + uart_handle_cts_change(uport, + zport->mctrl & TIOCM_CTS); + if (delta & TIOCM_CAR) + uart_handle_dcd_change(uport, + zport->mctrl & TIOCM_CAR); + if (delta & TIOCM_RNG) + uport->icount.dsr++; + if (delta & TIOCM_DSR) + uport->icount.rng++; + + if (delta) + wake_up_interruptible(&uport->info->delta_msr_wait); + + spin_lock(&scc->zlock); + } + + /* Clear the status condition... */ + write_zsreg(zport, R0, RES_EXT_INT); + + spin_unlock(&scc->zlock); +} + +/* + * This is the Z85C30 driver's generic interrupt routine. + */ +static irqreturn_t zs_interrupt(int irq, void *dev_id) +{ + struct zs_scc *scc = dev_id; + struct zs_port *zport_a = &scc->zport[ZS_CHAN_A]; + struct zs_port *zport_b = &scc->zport[ZS_CHAN_B]; + irqreturn_t status = IRQ_NONE; + u8 zs_intreg; + int count; + + /* + * NOTE: The read register 3, which holds the irq status, + * does so for both channels on each chip. Although + * the status value itself must be read from the A + * channel and is only valid when read from channel A. + * Yes... broken hardware... + */ + for (count = 16; count; count--) { + spin_lock(&scc->zlock); + zs_intreg = read_zsreg(zport_a, R3); + spin_unlock(&scc->zlock); + if (!zs_intreg) + break; + + /* + * We do not like losing characters, so we prioritise + * interrupt sources a little bit differently than + * the SCC would, was it allowed to. + */ + if (zs_intreg & CHBRxIP) + zs_receive_chars(zport_b); + if (zs_intreg & CHARxIP) + zs_receive_chars(zport_a); + if (zs_intreg & CHBEXT) + zs_status_handle(zport_b, zport_a); + if (zs_intreg & CHAEXT) + zs_status_handle(zport_a, zport_a); + if (zs_intreg & CHBTxIP) + zs_transmit_chars(zport_b); + if (zs_intreg & CHATxIP) + zs_transmit_chars(zport_a); + + status = IRQ_HANDLED; + } + + return status; +} + + +/* + * Finally, routines used to initialize the serial port. + */ +static int zs_startup(struct uart_port *uport) +{ + struct zs_port *zport = to_zport(uport); + struct zs_scc *scc = zport->scc; + unsigned long flags; + int irq_guard; + int ret; + + irq_guard = atomic_add_return(1, &scc->irq_guard); + if (irq_guard == 1) { + ret = request_irq(zport->port.irq, zs_interrupt, + IRQF_SHARED, "scc", scc); + if (ret) { + atomic_add(-1, &scc->irq_guard); + printk(KERN_ERR "zs: can't get irq %d\n", + zport->port.irq); + return ret; + } + } + + spin_lock_irqsave(&scc->zlock, flags); + + /* Clear the receive FIFO. */ + zs_receive_drain(zport); + + /* Clear the interrupt registers. */ + write_zsreg(zport, R0, ERR_RES); + write_zsreg(zport, R0, RES_Tx_P); + /* But Ext only if not being handled already. */ + if (!(zport->regs[1] & EXT_INT_ENAB)) + write_zsreg(zport, R0, RES_EXT_INT); + + /* Finally, enable sequencing and interrupts. */ + zport->regs[1] &= ~RxINT_MASK; + zport->regs[1] |= RxINT_ALL | TxINT_ENAB | EXT_INT_ENAB; + zport->regs[3] |= RxENABLE; + zport->regs[5] |= TxENAB; + zport->regs[15] |= BRKIE; + write_zsreg(zport, R1, zport->regs[1]); + write_zsreg(zport, R3, zport->regs[3]); + write_zsreg(zport, R5, zport->regs[5]); + write_zsreg(zport, R15, zport->regs[15]); + + /* Record the current state of RR0. */ + zport->mctrl = zs_raw_get_mctrl(zport); + zport->brk = read_zsreg(zport, R0) & BRK_ABRT; + + zport->tx_stopped = 1; + + spin_unlock_irqrestore(&scc->zlock, flags); + + return 0; +} + +static void zs_shutdown(struct uart_port *uport) +{ + struct zs_port *zport = to_zport(uport); + struct zs_scc *scc = zport->scc; + unsigned long flags; + int irq_guard; + + spin_lock_irqsave(&scc->zlock, flags); + + zport->regs[5] &= ~TxENAB; + zport->regs[3] &= ~RxENABLE; + write_zsreg(zport, R5, zport->regs[5]); + write_zsreg(zport, R3, zport->regs[3]); + + spin_unlock_irqrestore(&scc->zlock, flags); + + irq_guard = atomic_add_return(-1, &scc->irq_guard); + if (!irq_guard) + free_irq(zport->port.irq, scc); +} + + +static void zs_reset(struct zs_port *zport) +{ + struct zs_scc *scc = zport->scc; + int irq; + unsigned long flags; + + spin_lock_irqsave(&scc->zlock, flags); + irq = !irqs_disabled_flags(flags); + if (!scc->initialised) { + /* Reset the pointer first, just in case... */ + read_zsreg(zport, R0); + /* And let the current transmission finish. */ + zs_line_drain(zport, irq); + write_zsreg(zport, R9, FHWRES); + udelay(10); + write_zsreg(zport, R9, 0); + scc->initialised = 1; + } + load_zsregs(zport, zport->regs, irq); + spin_unlock_irqrestore(&scc->zlock, flags); +} + +static void zs_set_termios(struct uart_port *uport, struct ktermios *termios, + struct ktermios *old_termios) +{ + struct zs_port *zport = to_zport(uport); + struct zs_scc *scc = zport->scc; + struct zs_port *zport_a = &scc->zport[ZS_CHAN_A]; + int irq; + unsigned int baud, brg; + unsigned long flags; + + spin_lock_irqsave(&scc->zlock, flags); + irq = !irqs_disabled_flags(flags); + + /* Byte size. */ + zport->regs[3] &= ~RxNBITS_MASK; + zport->regs[5] &= ~TxNBITS_MASK; + switch (termios->c_cflag & CSIZE) { + case CS5: + zport->regs[3] |= Rx5; + zport->regs[5] |= Tx5; + break; + case CS6: + zport->regs[3] |= Rx6; + zport->regs[5] |= Tx6; + break; + case CS7: + zport->regs[3] |= Rx7; + zport->regs[5] |= Tx7; + break; + case CS8: + default: + zport->regs[3] |= Rx8; + zport->regs[5] |= Tx8; + break; + } + + /* Parity and stop bits. */ + zport->regs[4] &= ~(XCLK_MASK | SB_MASK | PAR_ENA | PAR_EVEN); + if (termios->c_cflag & CSTOPB) + zport->regs[4] |= SB2; + else + zport->regs[4] |= SB1; + if (termios->c_cflag & PARENB) + zport->regs[4] |= PAR_ENA; + if (!(termios->c_cflag & PARODD)) + zport->regs[4] |= PAR_EVEN; + switch (zport->clk_mode) { + case 64: + zport->regs[4] |= X64CLK; + break; + case 32: + zport->regs[4] |= X32CLK; + break; + case 16: + zport->regs[4] |= X16CLK; + break; + case 1: + zport->regs[4] |= X1CLK; + break; + default: + BUG(); + } + + baud = uart_get_baud_rate(uport, termios, old_termios, 0, + uport->uartclk / zport->clk_mode / 4); + + brg = ZS_BPS_TO_BRG(baud, uport->uartclk / zport->clk_mode); + zport->regs[12] = brg & 0xff; + zport->regs[13] = (brg >> 8) & 0xff; + + uart_update_timeout(uport, termios->c_cflag, baud); + + uport->read_status_mask = Rx_OVR; + if (termios->c_iflag & INPCK) + uport->read_status_mask |= FRM_ERR | PAR_ERR; + if (termios->c_iflag & (BRKINT | PARMRK)) + uport->read_status_mask |= Rx_BRK; + + uport->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + uport->ignore_status_mask |= FRM_ERR | PAR_ERR; + if (termios->c_iflag & IGNBRK) { + uport->ignore_status_mask |= Rx_BRK; + if (termios->c_iflag & IGNPAR) + uport->ignore_status_mask |= Rx_OVR; + } + + if (termios->c_cflag & CREAD) + zport->regs[3] |= RxENABLE; + else + zport->regs[3] &= ~RxENABLE; + + if (zport != zport_a) { + if (!(termios->c_cflag & CLOCAL)) { + zport->regs[15] |= DCDIE; + } else + zport->regs[15] &= ~DCDIE; + if (termios->c_cflag & CRTSCTS) { + zport->regs[15] |= CTSIE; + } else + zport->regs[15] &= ~CTSIE; + zs_raw_xor_mctrl(zport); + } + + /* Load up the new values. */ + load_zsregs(zport, zport->regs, irq); + + spin_unlock_irqrestore(&scc->zlock, flags); +} + + +static const char *zs_type(struct uart_port *uport) +{ + return "Z85C30 SCC"; +} + +static void zs_release_port(struct uart_port *uport) +{ + iounmap(uport->membase); + uport->membase = 0; + release_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE); +} + +static int zs_map_port(struct uart_port *uport) +{ + if (!uport->membase) + uport->membase = ioremap_nocache(uport->mapbase, + ZS_CHAN_IO_SIZE); + if (!uport->membase) { + printk(KERN_ERR "zs: Cannot map MMIO\n"); + return -ENOMEM; + } + return 0; +} + +static int zs_request_port(struct uart_port *uport) +{ + int ret; + + if (!request_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE, "scc")) { + printk(KERN_ERR "zs: Unable to reserve MMIO resource\n"); + return -EBUSY; + } + ret = zs_map_port(uport); + if (ret) { + release_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE); + return ret; + } + return 0; +} + +static void zs_config_port(struct uart_port *uport, int flags) +{ + struct zs_port *zport = to_zport(uport); + + if (flags & UART_CONFIG_TYPE) { + if (zs_request_port(uport)) + return; + + uport->type = PORT_ZS; + + zs_reset(zport); + } +} + +static int zs_verify_port(struct uart_port *uport, struct serial_struct *ser) +{ + struct zs_port *zport = to_zport(uport); + int ret = 0; + + if (ser->type != PORT_UNKNOWN && ser->type != PORT_ZS) + ret = -EINVAL; + if (ser->irq != uport->irq) + ret = -EINVAL; + if (ser->baud_base != uport->uartclk / zport->clk_mode / 4) + ret = -EINVAL; + return ret; +} + + +static struct uart_ops zs_ops = { + .tx_empty = zs_tx_empty, + .set_mctrl = zs_set_mctrl, + .get_mctrl = zs_get_mctrl, + .stop_tx = zs_stop_tx, + .start_tx = zs_start_tx, + .stop_rx = zs_stop_rx, + .enable_ms = zs_enable_ms, + .break_ctl = zs_break_ctl, + .startup = zs_startup, + .shutdown = zs_shutdown, + .set_termios = zs_set_termios, + .type = zs_type, + .release_port = zs_release_port, + .request_port = zs_request_port, + .config_port = zs_config_port, + .verify_port = zs_verify_port, +}; + +/* + * Initialize Z85C30 port structures. + */ +static int __init zs_probe_sccs(void) +{ + static int probed; + struct zs_parms zs_parms; + int chip, side, irq; + int n_chips = 0; + int i; + + if (probed) + return 0; + + irq = dec_interrupt[DEC_IRQ_SCC0]; + if (irq >= 0) { + zs_parms.scc[n_chips] = IOASIC_SCC0; + zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC0]; + n_chips++; + } + irq = dec_interrupt[DEC_IRQ_SCC1]; + if (irq >= 0) { + zs_parms.scc[n_chips] = IOASIC_SCC1; + zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC1]; + n_chips++; + } + if (!n_chips) + return -ENXIO; + + probed = 1; + + for (chip = 0; chip < n_chips; chip++) { + spin_lock_init(&zs_sccs[chip].zlock); + for (side = 0; side < ZS_NUM_CHAN; side++) { + struct zs_port *zport = &zs_sccs[chip].zport[side]; + struct uart_port *uport = &zport->port; + + zport->scc = &zs_sccs[chip]; + zport->clk_mode = 16; + + uport->irq = zs_parms.irq[chip]; + uport->uartclk = ZS_CLOCK; + uport->fifosize = 1; + uport->iotype = UPIO_MEM; + uport->flags = UPF_BOOT_AUTOCONF; + uport->ops = &zs_ops; + uport->line = chip * ZS_NUM_CHAN + side; + uport->mapbase = dec_kn_slot_base + + zs_parms.scc[chip] + + (side ^ ZS_CHAN_B) * ZS_CHAN_IO_SIZE; + + for (i = 0; i < ZS_NUM_REGS; i++) + zport->regs[i] = zs_init_regs[i]; + } + } + + return 0; +} + + +#ifdef CONFIG_SERIAL_ZS_CONSOLE +static void zs_console_putchar(struct uart_port *uport, int ch) +{ + struct zs_port *zport = to_zport(uport); + struct zs_scc *scc = zport->scc; + int irq; + unsigned long flags; + + spin_lock_irqsave(&scc->zlock, flags); + irq = !irqs_disabled_flags(flags); + if (zs_transmit_drain(zport, irq)) + write_zsdata(zport, ch); + spin_unlock_irqrestore(&scc->zlock, flags); +} + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + */ +static void zs_console_write(struct console *co, const char *s, + unsigned int count) +{ + int chip = co->index / ZS_NUM_CHAN, side = co->index % ZS_NUM_CHAN; + struct zs_port *zport = &zs_sccs[chip].zport[side]; + struct zs_scc *scc = zport->scc; + unsigned long flags; + u8 txint, txenb; + int irq; + + /* Disable transmit interrupts and enable the transmitter. */ + spin_lock_irqsave(&scc->zlock, flags); + txint = zport->regs[1]; + txenb = zport->regs[5]; + if (txint & TxINT_ENAB) { + zport->regs[1] = txint & ~TxINT_ENAB; + write_zsreg(zport, R1, zport->regs[1]); + } + if (!(txenb & TxENAB)) { + zport->regs[5] = txenb | TxENAB; + write_zsreg(zport, R5, zport->regs[5]); + } + spin_unlock_irqrestore(&scc->zlock, flags); + + uart_console_write(&zport->port, s, count, zs_console_putchar); + + /* Restore transmit interrupts and the transmitter enable. */ + spin_lock_irqsave(&scc->zlock, flags); + irq = !irqs_disabled_flags(flags); + zs_line_drain(zport, irq); + if (!(txenb & TxENAB)) { + zport->regs[5] &= ~TxENAB; + write_zsreg(zport, R5, zport->regs[5]); + } + if (txint & TxINT_ENAB) { + zport->regs[1] |= TxINT_ENAB; + write_zsreg(zport, R1, zport->regs[1]); + } + spin_unlock_irqrestore(&scc->zlock, flags); +} + +/* + * Setup serial console baud/bits/parity. We do two things here: + * - construct a cflag setting for the first uart_open() + * - initialise the serial port + * Return non-zero if we didn't find a serial port. + */ +static int __init zs_console_setup(struct console *co, char *options) +{ + int chip = co->index / ZS_NUM_CHAN, side = co->index % ZS_NUM_CHAN; + struct zs_port *zport = &zs_sccs[chip].zport[side]; + struct uart_port *uport = &zport->port; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + int ret; + + ret = zs_map_port(uport); + if (ret) + return ret; + + zs_reset(zport); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + return uart_set_options(uport, co, baud, parity, bits, flow); +} + +static struct uart_driver zs_reg; +static struct console zs_console = { + .name = "ttyS", + .write = zs_console_write, + .device = uart_console_device, + .setup = zs_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &zs_reg, +}; + +/* + * Register console. + */ +static int __init zs_serial_console_init(void) +{ + int ret; + + ret = zs_probe_sccs(); + if (ret) + return ret; + register_console(&zs_console); + + return 0; +} + +console_initcall(zs_serial_console_init); + +#define SERIAL_ZS_CONSOLE &zs_console +#else +#define SERIAL_ZS_CONSOLE NULL +#endif /* CONFIG_SERIAL_ZS_CONSOLE */ + +static struct uart_driver zs_reg = { + .owner = THIS_MODULE, + .driver_name = "serial", + .dev_name = "ttyS", + .major = TTY_MAJOR, + .minor = 64, + .nr = ZS_NUM_SCCS * ZS_NUM_CHAN, + .cons = SERIAL_ZS_CONSOLE, +}; + +/* zs_init inits the driver. */ +static int __init zs_init(void) +{ + int i, ret; + + pr_info("%s%s\n", zs_name, zs_version); + + /* Find out how many Z85C30 SCCs we have. */ + ret = zs_probe_sccs(); + if (ret) + return ret; + + ret = uart_register_driver(&zs_reg); + if (ret) + return ret; + + for (i = 0; i < ZS_NUM_SCCS * ZS_NUM_CHAN; i++) { + struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN]; + struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN]; + struct uart_port *uport = &zport->port; + + if (zport->scc) + uart_add_one_port(&zs_reg, uport); + } + + return 0; +} + +static void __exit zs_exit(void) +{ + int i; + + for (i = ZS_NUM_SCCS * ZS_NUM_CHAN - 1; i >= 0; i--) { + struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN]; + struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN]; + struct uart_port *uport = &zport->port; + + if (zport->scc) + uart_remove_one_port(&zs_reg, uport); + } + + uart_unregister_driver(&zs_reg); +} + +module_init(zs_init); +module_exit(zs_exit); diff --git a/drivers/serial/zs.h b/drivers/serial/zs.h new file mode 100644 index 000000000000..aa921b57d827 --- /dev/null +++ b/drivers/serial/zs.h @@ -0,0 +1,284 @@ +/* + * zs.h: Definitions for the DECstation Z85C30 serial driver. + * + * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras. + * Adapted from drivers/macintosh/macserial.h by Harald Koerfgen. + * + * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au) + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 2004, 2005, 2007 Maciej W. Rozycki + */ +#ifndef _SERIAL_ZS_H +#define _SERIAL_ZS_H + +#ifdef __KERNEL__ + +#define ZS_NUM_REGS 16 + +/* + * This is our internal structure for each serial port's state. + */ +struct zs_port { + struct zs_scc *scc; /* Containing SCC. */ + struct uart_port port; /* Underlying UART. */ + + int clk_mode; /* May be 1, 16, 32, or 64. */ + + unsigned int tty_break; /* Set on BREAK condition. */ + int tx_stopped; /* Output is suspended. */ + + unsigned int mctrl; /* State of modem lines. */ + u8 brk; /* BREAK state from RR0. */ + + u8 regs[ZS_NUM_REGS]; /* Channel write registers. */ +}; + +/* + * Per-SCC state for locking and the interrupt handler. + */ +struct zs_scc { + struct zs_port zport[2]; + spinlock_t zlock; + atomic_t irq_guard; + int initialised; +}; + +#endif /* __KERNEL__ */ + +/* + * Conversion routines to/from brg time constants from/to bits per second. + */ +#define ZS_BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2)) +#define ZS_BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2) + +/* + * The Zilog register set. + */ + +/* Write Register 0 (Command) */ +#define R0 0 /* Register selects */ +#define R1 1 +#define R2 2 +#define R3 3 +#define R4 4 +#define R5 5 +#define R6 6 +#define R7 7 +#define R8 8 +#define R9 9 +#define R10 10 +#define R11 11 +#define R12 12 +#define R13 13 +#define R14 14 +#define R15 15 + +#define NULLCODE 0 /* Null Code */ +#define POINT_HIGH 0x8 /* Select upper half of registers */ +#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */ +#define SEND_ABORT 0x18 /* HDLC Abort */ +#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */ +#define RES_Tx_P 0x28 /* Reset TxINT Pending */ +#define ERR_RES 0x30 /* Error Reset */ +#define RES_H_IUS 0x38 /* Reset highest IUS */ + +#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */ +#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */ +#define RES_EOM_L 0xC0 /* Reset EOM latch */ + +/* Write Register 1 (Tx/Rx/Ext Int Enable and WAIT/DMA Commands) */ +#define EXT_INT_ENAB 0x1 /* Ext Int Enable */ +#define TxINT_ENAB 0x2 /* Tx Int Enable */ +#define PAR_SPEC 0x4 /* Parity is special condition */ + +#define RxINT_DISAB 0 /* Rx Int Disable */ +#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */ +#define RxINT_ALL 0x10 /* Int on all Rx Characters or error */ +#define RxINT_ERR 0x18 /* Int on error only */ +#define RxINT_MASK 0x18 + +#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */ +#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */ +#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */ + +/* Write Register 2 (Interrupt Vector) */ + +/* Write Register 3 (Receive Parameters and Control) */ +#define RxENABLE 0x1 /* Rx Enable */ +#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */ +#define ADD_SM 0x4 /* Address Search Mode (SDLC) */ +#define RxCRC_ENAB 0x8 /* Rx CRC Enable */ +#define ENT_HM 0x10 /* Enter Hunt Mode */ +#define AUTO_ENAB 0x20 /* Auto Enables */ +#define Rx5 0x0 /* Rx 5 Bits/Character */ +#define Rx7 0x40 /* Rx 7 Bits/Character */ +#define Rx6 0x80 /* Rx 6 Bits/Character */ +#define Rx8 0xc0 /* Rx 8 Bits/Character */ +#define RxNBITS_MASK 0xc0 + +/* Write Register 4 (Transmit/Receive Miscellaneous Parameters and Modes) */ +#define PAR_ENA 0x1 /* Parity Enable */ +#define PAR_EVEN 0x2 /* Parity Even/Odd* */ + +#define SYNC_ENAB 0 /* Sync Modes Enable */ +#define SB1 0x4 /* 1 stop bit/char */ +#define SB15 0x8 /* 1.5 stop bits/char */ +#define SB2 0xc /* 2 stop bits/char */ +#define SB_MASK 0xc + +#define MONSYNC 0 /* 8 Bit Sync character */ +#define BISYNC 0x10 /* 16 bit sync character */ +#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */ +#define EXTSYNC 0x30 /* External Sync Mode */ + +#define X1CLK 0x0 /* x1 clock mode */ +#define X16CLK 0x40 /* x16 clock mode */ +#define X32CLK 0x80 /* x32 clock mode */ +#define X64CLK 0xc0 /* x64 clock mode */ +#define XCLK_MASK 0xc0 + +/* Write Register 5 (Transmit Parameters and Controls) */ +#define TxCRC_ENAB 0x1 /* Tx CRC Enable */ +#define RTS 0x2 /* RTS */ +#define SDLC_CRC 0x4 /* SDLC/CRC-16 */ +#define TxENAB 0x8 /* Tx Enable */ +#define SND_BRK 0x10 /* Send Break */ +#define Tx5 0x0 /* Tx 5 bits (or less)/character */ +#define Tx7 0x20 /* Tx 7 bits/character */ +#define Tx6 0x40 /* Tx 6 bits/character */ +#define Tx8 0x60 /* Tx 8 bits/character */ +#define TxNBITS_MASK 0x60 +#define DTR 0x80 /* DTR */ + +/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */ + +/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */ + +/* Write Register 8 (Transmit Buffer) */ + +/* Write Register 9 (Master Interrupt Control) */ +#define VIS 1 /* Vector Includes Status */ +#define NV 2 /* No Vector */ +#define DLC 4 /* Disable Lower Chain */ +#define MIE 8 /* Master Interrupt Enable */ +#define STATHI 0x10 /* Status high */ +#define SOFTACK 0x20 /* Software Interrupt Acknowledge */ +#define NORESET 0 /* No reset on write to R9 */ +#define CHRB 0x40 /* Reset channel B */ +#define CHRA 0x80 /* Reset channel A */ +#define FHWRES 0xc0 /* Force hardware reset */ + +/* Write Register 10 (Miscellaneous Transmitter/Receiver Control Bits) */ +#define BIT6 1 /* 6 bit/8bit sync */ +#define LOOPMODE 2 /* SDLC Loop mode */ +#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */ +#define MARKIDLE 8 /* Mark/flag on idle */ +#define GAOP 0x10 /* Go active on poll */ +#define NRZ 0 /* NRZ mode */ +#define NRZI 0x20 /* NRZI mode */ +#define FM1 0x40 /* FM1 (transition = 1) */ +#define FM0 0x60 /* FM0 (transition = 0) */ +#define CRCPS 0x80 /* CRC Preset I/O */ + +/* Write Register 11 (Clock Mode Control) */ +#define TRxCXT 0 /* TRxC = Xtal output */ +#define TRxCTC 1 /* TRxC = Transmit clock */ +#define TRxCBR 2 /* TRxC = BR Generator Output */ +#define TRxCDP 3 /* TRxC = DPLL output */ +#define TRxCOI 4 /* TRxC O/I */ +#define TCRTxCP 0 /* Transmit clock = RTxC pin */ +#define TCTRxCP 8 /* Transmit clock = TRxC pin */ +#define TCBR 0x10 /* Transmit clock = BR Generator output */ +#define TCDPLL 0x18 /* Transmit clock = DPLL output */ +#define RCRTxCP 0 /* Receive clock = RTxC pin */ +#define RCTRxCP 0x20 /* Receive clock = TRxC pin */ +#define RCBR 0x40 /* Receive clock = BR Generator output */ +#define RCDPLL 0x60 /* Receive clock = DPLL output */ +#define RTxCX 0x80 /* RTxC Xtal/No Xtal */ + +/* Write Register 12 (Lower Byte of Baud Rate Generator Time Constant) */ + +/* Write Register 13 (Upper Byte of Baud Rate Generator Time Constant) */ + +/* Write Register 14 (Miscellaneous Control Bits) */ +#define BRENABL 1 /* Baud rate generator enable */ +#define BRSRC 2 /* Baud rate generator source */ +#define DTRREQ 4 /* DTR/Request function */ +#define AUTOECHO 8 /* Auto Echo */ +#define LOOPBAK 0x10 /* Local loopback */ +#define SEARCH 0x20 /* Enter search mode */ +#define RMC 0x40 /* Reset missing clock */ +#define DISDPLL 0x60 /* Disable DPLL */ +#define SSBR 0x80 /* Set DPLL source = BR generator */ +#define SSRTxC 0xa0 /* Set DPLL source = RTxC */ +#define SFMM 0xc0 /* Set FM mode */ +#define SNRZI 0xe0 /* Set NRZI mode */ + +/* Write Register 15 (External/Status Interrupt Control) */ +#define WR7P_EN 1 /* WR7 Prime SDLC Feature Enable */ +#define ZCIE 2 /* Zero count IE */ +#define DCDIE 8 /* DCD IE */ +#define SYNCIE 0x10 /* Sync/hunt IE */ +#define CTSIE 0x20 /* CTS IE */ +#define TxUIE 0x40 /* Tx Underrun/EOM IE */ +#define BRKIE 0x80 /* Break/Abort IE */ + + +/* Read Register 0 (Transmit/Receive Buffer Status and External Status) */ +#define Rx_CH_AV 0x1 /* Rx Character Available */ +#define ZCOUNT 0x2 /* Zero count */ +#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */ +#define DCD 0x8 /* DCD */ +#define SYNC_HUNT 0x10 /* Sync/hunt */ +#define CTS 0x20 /* CTS */ +#define TxEOM 0x40 /* Tx underrun */ +#define BRK_ABRT 0x80 /* Break/Abort */ + +/* Read Register 1 (Special Receive Condition Status) */ +#define ALL_SNT 0x1 /* All sent */ +/* Residue Data for 8 Rx bits/char programmed */ +#define RES3 0x8 /* 0/3 */ +#define RES4 0x4 /* 0/4 */ +#define RES5 0xc /* 0/5 */ +#define RES6 0x2 /* 0/6 */ +#define RES7 0xa /* 0/7 */ +#define RES8 0x6 /* 0/8 */ +#define RES18 0xe /* 1/8 */ +#define RES28 0x0 /* 2/8 */ +/* Special Rx Condition Interrupts */ +#define PAR_ERR 0x10 /* Parity Error */ +#define Rx_OVR 0x20 /* Rx Overrun Error */ +#define FRM_ERR 0x40 /* CRC/Framing Error */ +#define END_FR 0x80 /* End of Frame (SDLC) */ + +/* Read Register 2 (Interrupt Vector (WR2) -- channel A). */ + +/* Read Register 2 (Modified Interrupt Vector -- channel B). */ + +/* Read Register 3 (Interrupt Pending Bits -- channel A only). */ +#define CHBEXT 0x1 /* Channel B Ext/Stat IP */ +#define CHBTxIP 0x2 /* Channel B Tx IP */ +#define CHBRxIP 0x4 /* Channel B Rx IP */ +#define CHAEXT 0x8 /* Channel A Ext/Stat IP */ +#define CHATxIP 0x10 /* Channel A Tx IP */ +#define CHARxIP 0x20 /* Channel A Rx IP */ + +/* Read Register 6 (SDLC FIFO Status and Byte Count LSB) */ + +/* Read Register 7 (SDLC FIFO Status and Byte Count MSB) */ + +/* Read Register 8 (Receive Data) */ + +/* Read Register 10 (Miscellaneous Status Bits) */ +#define ONLOOP 2 /* On loop */ +#define LOOPSEND 0x10 /* Loop sending */ +#define CLK2MIS 0x40 /* Two clocks missing */ +#define CLK1MIS 0x80 /* One clock missing */ + +/* Read Register 12 (Lower Byte of Baud Rate Generator Constant (WR12)) */ + +/* Read Register 13 (Upper Byte of Baud Rate Generator Constant (WR13) */ + +/* Read Register 15 (External/Status Interrupt Control (WR15)) */ + +#endif /* _SERIAL_ZS_H */ diff --git a/drivers/tc/Makefile b/drivers/tc/Makefile index 967342692211..c899246bd362 100644 --- a/drivers/tc/Makefile +++ b/drivers/tc/Makefile @@ -5,7 +5,6 @@ # Object file lists. obj-$(CONFIG_TC) += tc.o tc-driver.o -obj-$(CONFIG_ZS) += zs.o obj-$(CONFIG_VT) += lk201.o lk201-map.o lk201-remap.o $(obj)/lk201-map.o: $(obj)/lk201-map.c diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c deleted file mode 100644 index ed979f13908a..000000000000 --- a/drivers/tc/zs.c +++ /dev/null @@ -1,2203 +0,0 @@ -/* - * decserial.c: Serial port driver for IOASIC DECstations. - * - * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras. - * Derived from drivers/macintosh/macserial.c by Harald Koerfgen. - * - * DECstation changes - * Copyright (C) 1998-2000 Harald Koerfgen - * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Maciej W. Rozycki - * - * For the rest of the code the original Copyright applies: - * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au) - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * - * - * Note: for IOASIC systems the wiring is as follows: - * - * mouse/keyboard: - * DIN-7 MJ-4 signal SCC - * 2 1 TxD <- A.TxD - * 3 4 RxD -> A.RxD - * - * EIA-232/EIA-423: - * DB-25 MMJ-6 signal SCC - * 2 2 TxD <- B.TxD - * 3 5 RxD -> B.RxD - * 4 RTS <- ~A.RTS - * 5 CTS -> ~B.CTS - * 6 6 DSR -> ~A.SYNC - * 8 CD -> ~B.DCD - * 12 DSRS(DCE) -> ~A.CTS (*) - * 15 TxC -> B.TxC - * 17 RxC -> B.RxC - * 20 1 DTR <- ~A.DTR - * 22 RI -> ~A.DCD - * 23 DSRS(DTE) <- ~B.RTS - * - * (*) EIA-232 defines the signal at this pin to be SCD, while DSRS(DCE) - * is shared with DSRS(DTE) at pin 23. - */ - -#include <linux/errno.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/timer.h> -#include <linux/interrupt.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/major.h> -#include <linux/string.h> -#include <linux/fcntl.h> -#include <linux/mm.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/spinlock.h> -#ifdef CONFIG_SERIAL_DEC_CONSOLE -#include <linux/console.h> -#endif - -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/irq.h> -#include <asm/system.h> -#include <asm/bootinfo.h> - -#include <asm/dec/interrupts.h> -#include <asm/dec/ioasic_addrs.h> -#include <asm/dec/machtype.h> -#include <asm/dec/serial.h> -#include <asm/dec/system.h> - -#ifdef CONFIG_KGDB -#include <asm/kgdb.h> -#endif -#ifdef CONFIG_MAGIC_SYSRQ -#include <linux/sysrq.h> -#endif - -#include "zs.h" - -/* - * It would be nice to dynamically allocate everything that - * depends on NUM_SERIAL, so we could support any number of - * Z8530s, but for now... - */ -#define NUM_SERIAL 2 /* Max number of ZS chips supported */ -#define NUM_CHANNELS (NUM_SERIAL * 2) /* 2 channels per chip */ -#define CHANNEL_A_NR (zs_parms->channel_a_offset > zs_parms->channel_b_offset) - /* Number of channel A in the chip */ -#define ZS_CHAN_IO_SIZE 8 -#define ZS_CLOCK 7372800 /* Z8530 RTxC input clock rate */ - -#define RECOVERY_DELAY udelay(2) - -struct zs_parms { - unsigned long scc0; - unsigned long scc1; - int channel_a_offset; - int channel_b_offset; - int irq0; - int irq1; - int clock; -}; - -static struct zs_parms *zs_parms; - -#ifdef CONFIG_MACH_DECSTATION -static struct zs_parms ds_parms = { - scc0 : IOASIC_SCC0, - scc1 : IOASIC_SCC1, - channel_a_offset : 1, - channel_b_offset : 9, - irq0 : -1, - irq1 : -1, - clock : ZS_CLOCK -}; -#endif - -#ifdef CONFIG_MACH_DECSTATION -#define DS_BUS_PRESENT (IOASIC) -#else -#define DS_BUS_PRESENT 0 -#endif - -#define BUS_PRESENT (DS_BUS_PRESENT) - -DEFINE_SPINLOCK(zs_lock); - -struct dec_zschannel zs_channels[NUM_CHANNELS]; -struct dec_serial zs_soft[NUM_CHANNELS]; -int zs_channels_found; -struct dec_serial *zs_chain; /* list of all channels */ - -struct tty_struct zs_ttys[NUM_CHANNELS]; - -#ifdef CONFIG_SERIAL_DEC_CONSOLE -static struct console zs_console; -#endif -#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \ - !defined(MODULE) -static unsigned long break_pressed; /* break, really ... */ -#endif - -static unsigned char zs_init_regs[16] __initdata = { - 0, /* write 0 */ - 0, /* write 1 */ - 0, /* write 2 */ - 0, /* write 3 */ - (X16CLK), /* write 4 */ - 0, /* write 5 */ - 0, 0, 0, /* write 6, 7, 8 */ - (MIE | DLC | NV), /* write 9 */ - (NRZ), /* write 10 */ - (TCBR | RCBR), /* write 11 */ - 0, 0, /* BRG time constant, write 12 + 13 */ - (BRSRC | BRENABL), /* write 14 */ - 0 /* write 15 */ -}; - -static struct tty_driver *serial_driver; - -/* serial subtype definitions */ -#define SERIAL_TYPE_NORMAL 1 - -/* number of characters left in xmit buffer before we ask for more */ -#define WAKEUP_CHARS 256 - -/* - * Debugging. - */ -#undef SERIAL_DEBUG_OPEN -#undef SERIAL_DEBUG_FLOW -#undef SERIAL_DEBUG_THROTTLE -#undef SERIAL_PARANOIA_CHECK - -#undef ZS_DEBUG_REGS - -#ifdef SERIAL_DEBUG_THROTTLE -#define _tty_name(tty,buf) tty_name(tty,buf) -#endif - -#define RS_STROBE_TIME 10 -#define RS_ISR_PASS_LIMIT 256 - -static void probe_sccs(void); -static void change_speed(struct dec_serial *info); -static void rs_wait_until_sent(struct tty_struct *tty, int timeout); - -static inline int serial_paranoia_check(struct dec_serial *info, - char *name, const char *routine) -{ -#ifdef SERIAL_PARANOIA_CHECK - static const char *badmagic = - "Warning: bad magic number for serial struct %s in %s\n"; - static const char *badinfo = - "Warning: null mac_serial for %s in %s\n"; - - if (!info) { - printk(badinfo, name, routine); - return 1; - } - if (info->magic != SERIAL_MAGIC) { - printk(badmagic, name, routine); - return 1; - } -#endif - return 0; -} - -/* - * This is used to figure out the divisor speeds and the timeouts - */ -static int baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 0 }; - -/* - * Reading and writing Z8530 registers. - */ -static inline unsigned char read_zsreg(struct dec_zschannel *channel, - unsigned char reg) -{ - unsigned char retval; - - if (reg != 0) { - *channel->control = reg & 0xf; - fast_iob(); RECOVERY_DELAY; - } - retval = *channel->control; - RECOVERY_DELAY; - return retval; -} - -static inline void write_zsreg(struct dec_zschannel *channel, - unsigned char reg, unsigned char value) -{ - if (reg != 0) { - *channel->control = reg & 0xf; - fast_iob(); RECOVERY_DELAY; - } - *channel->control = value; - fast_iob(); RECOVERY_DELAY; - return; -} - -static inline unsigned char read_zsdata(struct dec_zschannel *channel) -{ - unsigned char retval; - - retval = *channel->data; - RECOVERY_DELAY; - return retval; -} - -static inline void write_zsdata(struct dec_zschannel *channel, - unsigned char value) -{ - *channel->data = value; - fast_iob(); RECOVERY_DELAY; - return; -} - -static inline void load_zsregs(struct dec_zschannel *channel, - unsigned char *regs) -{ -/* ZS_CLEARERR(channel); - ZS_CLEARFIFO(channel); */ - /* Load 'em up */ - write_zsreg(channel, R3, regs[R3] & ~RxENABLE); - write_zsreg(channel, R5, regs[R5] & ~TxENAB); - write_zsreg(channel, R4, regs[R4]); - write_zsreg(channel, R9, regs[R9]); - write_zsreg(channel, R1, regs[R1]); - write_zsreg(channel, R2, regs[R2]); - write_zsreg(channel, R10, regs[R10]); - write_zsreg(channel, R11, regs[R11]); - write_zsreg(channel, R12, regs[R12]); - write_zsreg(channel, R13, regs[R13]); - write_zsreg(channel, R14, regs[R14]); - write_zsreg(channel, R15, regs[R15]); - write_zsreg(channel, R3, regs[R3]); - write_zsreg(channel, R5, regs[R5]); - return; -} - -/* Sets or clears DTR/RTS on the requested line */ -static inline void zs_rtsdtr(struct dec_serial *info, int which, int set) -{ - unsigned long flags; - - spin_lock_irqsave(&zs_lock, flags); - if (info->zs_channel != info->zs_chan_a) { - if (set) { - info->zs_chan_a->curregs[5] |= (which & (RTS | DTR)); - } else { - info->zs_chan_a->curregs[5] &= ~(which & (RTS | DTR)); - } - write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]); - } - spin_unlock_irqrestore(&zs_lock, flags); -} - -/* Utility routines for the Zilog */ -static inline int get_zsbaud(struct dec_serial *ss) -{ - struct dec_zschannel *channel = ss->zs_channel; - int brg; - - /* The baud rate is split up between two 8-bit registers in - * what is termed 'BRG time constant' format in my docs for - * the chip, it is a function of the clk rate the chip is - * receiving which happens to be constant. - */ - brg = (read_zsreg(channel, 13) << 8); - brg |= read_zsreg(channel, 12); - return BRG_TO_BPS(brg, (zs_parms->clock/(ss->clk_divisor))); -} - -/* On receive, this clears errors and the receiver interrupts */ -static inline void rs_recv_clear(struct dec_zschannel *zsc) -{ - write_zsreg(zsc, 0, ERR_RES); - write_zsreg(zsc, 0, RES_H_IUS); /* XXX this is unnecessary */ -} - -/* - * ---------------------------------------------------------------------- - * - * Here starts the interrupt handling routines. All of the following - * subroutines are declared as inline and are folded into - * rs_interrupt(). They were separated out for readability's sake. - * - * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 - * ----------------------------------------------------------------------- - */ - -/* - * This routine is used by the interrupt handler to schedule - * processing in the software interrupt portion of the driver. - */ -static void rs_sched_event(struct dec_serial *info, int event) -{ - info->event |= 1 << event; - tasklet_schedule(&info->tlet); -} - -static void receive_chars(struct dec_serial *info) -{ - struct tty_struct *tty = info->tty; - unsigned char ch, stat, flag; - - while ((read_zsreg(info->zs_channel, R0) & Rx_CH_AV) != 0) { - - stat = read_zsreg(info->zs_channel, R1); - ch = read_zsdata(info->zs_channel); - - if (!tty && (!info->hook || !info->hook->rx_char)) - continue; - - flag = TTY_NORMAL; - if (info->tty_break) { - info->tty_break = 0; - flag = TTY_BREAK; - if (info->flags & ZILOG_SAK) - do_SAK(tty); - /* Ignore the null char got when BREAK is removed. */ - if (ch == 0) - continue; - } else { - if (stat & Rx_OVR) { - flag = TTY_OVERRUN; - } else if (stat & FRM_ERR) { - flag = TTY_FRAME; - } else if (stat & PAR_ERR) { - flag = TTY_PARITY; - } - if (flag != TTY_NORMAL) - /* reset the error indication */ - write_zsreg(info->zs_channel, R0, ERR_RES); - } - -#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \ - !defined(MODULE) - if (break_pressed && info->line == zs_console.index) { - /* Ignore the null char got when BREAK is removed. */ - if (ch == 0) - continue; - if (time_before(jiffies, break_pressed + HZ * 5)) { - handle_sysrq(ch, NULL); - break_pressed = 0; - continue; - } - break_pressed = 0; - } -#endif - - if (info->hook && info->hook->rx_char) { - (*info->hook->rx_char)(ch, flag); - return; - } - - tty_insert_flip_char(tty, ch, flag); - } - if (tty) - tty_flip_buffer_push(tty); -} - -static void transmit_chars(struct dec_serial *info) -{ - if ((read_zsreg(info->zs_channel, R0) & Tx_BUF_EMP) == 0) - return; - info->tx_active = 0; - - if (info->x_char) { - /* Send next char */ - write_zsdata(info->zs_channel, info->x_char); - info->x_char = 0; - info->tx_active = 1; - return; - } - - if ((info->xmit_cnt <= 0) || (info->tty && info->tty->stopped) - || info->tx_stopped) { - write_zsreg(info->zs_channel, R0, RES_Tx_P); - return; - } - /* Send char */ - write_zsdata(info->zs_channel, info->xmit_buf[info->xmit_tail++]); - info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt--; - info->tx_active = 1; - - if (info->xmit_cnt < WAKEUP_CHARS) - rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); -} - -static void status_handle(struct dec_serial *info) -{ - unsigned char stat; - - /* Get status from Read Register 0 */ - stat = read_zsreg(info->zs_channel, R0); - - if ((stat & BRK_ABRT) && !(info->read_reg_zero & BRK_ABRT)) { -#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \ - !defined(MODULE) - if (info->line == zs_console.index) { - if (!break_pressed) - break_pressed = jiffies; - } else -#endif - info->tty_break = 1; - } - - if (info->zs_channel != info->zs_chan_a) { - - /* Check for DCD transitions */ - if (info->tty && !C_CLOCAL(info->tty) && - ((stat ^ info->read_reg_zero) & DCD) != 0 ) { - if (stat & DCD) { - wake_up_interruptible(&info->open_wait); - } else { - tty_hangup(info->tty); - } - } - - /* Check for CTS transitions */ - if (info->tty && C_CRTSCTS(info->tty)) { - if ((stat & CTS) != 0) { - if (info->tx_stopped) { - info->tx_stopped = 0; - if (!info->tx_active) - transmit_chars(info); - } - } else { - info->tx_stopped = 1; - } - } - - } - - /* Clear status condition... */ - write_zsreg(info->zs_channel, R0, RES_EXT_INT); - info->read_reg_zero = stat; -} - -/* - * This is the serial driver's generic interrupt routine - */ -static irqreturn_t rs_interrupt(int irq, void *dev_id) -{ - struct dec_serial *info = (struct dec_serial *) dev_id; - irqreturn_t status = IRQ_NONE; - unsigned char zs_intreg; - int shift; - - /* NOTE: The read register 3, which holds the irq status, - * does so for both channels on each chip. Although - * the status value itself must be read from the A - * channel and is only valid when read from channel A. - * Yes... broken hardware... - */ -#define CHAN_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT) - - if (info->zs_chan_a == info->zs_channel) - shift = 3; /* Channel A */ - else - shift = 0; /* Channel B */ - - for (;;) { - zs_intreg = read_zsreg(info->zs_chan_a, R3) >> shift; - if ((zs_intreg & CHAN_IRQMASK) == 0) - break; - - status = IRQ_HANDLED; - - if (zs_intreg & CHBRxIP) { - receive_chars(info); - } - if (zs_intreg & CHBTxIP) { - transmit_chars(info); - } - if (zs_intreg & CHBEXT) { - status_handle(info); - } - } - - /* Why do we need this ? */ - write_zsreg(info->zs_channel, 0, RES_H_IUS); - - return status; -} - -#ifdef ZS_DEBUG_REGS -void zs_dump (void) { - int i, j; - for (i = 0; i < zs_channels_found; i++) { - struct dec_zschannel *ch = &zs_channels[i]; - if ((long)ch->control == UNI_IO_BASE+UNI_SCC1A_CTRL) { - for (j = 0; j < 15; j++) { - printk("W%d = 0x%x\t", - j, (int)ch->curregs[j]); - } - for (j = 0; j < 15; j++) { - printk("R%d = 0x%x\t", - j, (int)read_zsreg(ch,j)); - } - printk("\n\n"); - } - } -} -#endif - -/* - * ------------------------------------------------------------------- - * Here ends the serial interrupt routines. - * ------------------------------------------------------------------- - */ - -/* - * ------------------------------------------------------------ - * rs_stop() and rs_start() - * - * This routines are called before setting or resetting tty->stopped. - * ------------------------------------------------------------ - */ -static void rs_stop(struct tty_struct *tty) -{ - struct dec_serial *info = (struct dec_serial *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, "rs_stop")) - return; - -#if 1 - spin_lock_irqsave(&zs_lock, flags); - if (info->zs_channel->curregs[5] & TxENAB) { - info->zs_channel->curregs[5] &= ~TxENAB; - write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]); - } - spin_unlock_irqrestore(&zs_lock, flags); -#endif -} - -static void rs_start(struct tty_struct *tty) -{ - struct dec_serial *info = (struct dec_serial *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, "rs_start")) - return; - - spin_lock_irqsave(&zs_lock, flags); -#if 1 - if (info->xmit_cnt && info->xmit_buf && !(info->zs_channel->curregs[5] & TxENAB)) { - info->zs_channel->curregs[5] |= TxENAB; - write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]); - } -#else - if (info->xmit_cnt && info->xmit_buf && !info->tx_active) { - transmit_chars(info); - } -#endif - spin_unlock_irqrestore(&zs_lock, flags); -} - -/* - * This routine is used to handle the "bottom half" processing for the - * serial driver, known also the "software interrupt" processing. - * This processing is done at the kernel interrupt level, after the - * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This - * is where time-consuming activities which can not be done in the - * interrupt driver proper are done; the interrupt driver schedules - * them using rs_sched_event(), and they get done here. - */ - -static void do_softint(unsigned long private_) -{ - struct dec_serial *info = (struct dec_serial *) private_; - struct tty_struct *tty; - - tty = info->tty; - if (!tty) - return; - - if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) - tty_wakeup(tty); -} - -static int zs_startup(struct dec_serial * info) -{ - unsigned long flags; - - if (info->flags & ZILOG_INITIALIZED) - return 0; - - if (!info->xmit_buf) { - info->xmit_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL); - if (!info->xmit_buf) - return -ENOMEM; - } - - spin_lock_irqsave(&zs_lock, flags); - -#ifdef SERIAL_DEBUG_OPEN - printk("starting up ttyS%d (irq %d)...", info->line, info->irq); -#endif - - /* - * Clear the receive FIFO. - */ - ZS_CLEARFIFO(info->zs_channel); - info->xmit_fifo_size = 1; - - /* - * Clear the interrupt registers. - */ - write_zsreg(info->zs_channel, R0, ERR_RES); - write_zsreg(info->zs_channel, R0, RES_H_IUS); - - /* - * Set the speed of the serial port - */ - change_speed(info); - - /* - * Turn on RTS and DTR. - */ - zs_rtsdtr(info, RTS | DTR, 1); - - /* - * Finally, enable sequencing and interrupts - */ - info->zs_channel->curregs[R1] &= ~RxINT_MASK; - info->zs_channel->curregs[R1] |= (RxINT_ALL | TxINT_ENAB | - EXT_INT_ENAB); - info->zs_channel->curregs[R3] |= RxENABLE; - info->zs_channel->curregs[R5] |= TxENAB; - info->zs_channel->curregs[R15] |= (DCDIE | CTSIE | TxUIE | BRKIE); - write_zsreg(info->zs_channel, R1, info->zs_channel->curregs[R1]); - write_zsreg(info->zs_channel, R3, info->zs_channel->curregs[R3]); - write_zsreg(info->zs_channel, R5, info->zs_channel->curregs[R5]); - write_zsreg(info->zs_channel, R15, info->zs_channel->curregs[R15]); - - /* - * And clear the interrupt registers again for luck. - */ - write_zsreg(info->zs_channel, R0, ERR_RES); - write_zsreg(info->zs_channel, R0, RES_H_IUS); - - /* Save the current value of RR0 */ - info->read_reg_zero = read_zsreg(info->zs_channel, R0); - - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - - info->flags |= ZILOG_INITIALIZED; - spin_unlock_irqrestore(&zs_lock, flags); - return 0; -} - -/* - * This routine will shutdown a serial port; interrupts are disabled, and - * DTR is dropped if the hangup on close termio flag is on. - */ -static void shutdown(struct dec_serial * info) -{ - unsigned long flags; - - if (!(info->flags & ZILOG_INITIALIZED)) - return; - -#ifdef SERIAL_DEBUG_OPEN - printk("Shutting down serial port %d (irq %d)....", info->line, - info->irq); -#endif - - spin_lock_irqsave(&zs_lock, flags); - - if (info->xmit_buf) { - free_page((unsigned long) info->xmit_buf); - info->xmit_buf = 0; - } - - info->zs_channel->curregs[1] = 0; - write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]); /* no interrupts */ - - info->zs_channel->curregs[3] &= ~RxENABLE; - write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]); - - info->zs_channel->curregs[5] &= ~TxENAB; - write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]); - if (!info->tty || C_HUPCL(info->tty)) { - zs_rtsdtr(info, RTS | DTR, 0); - } - - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); - - info->flags &= ~ZILOG_INITIALIZED; - spin_unlock_irqrestore(&zs_lock, flags); -} - -/* - * This routine is called to set the UART divisor registers to match - * the specified baud rate for a serial port. - */ -static void change_speed(struct dec_serial *info) -{ - unsigned cflag; - int i; - int brg, bits; - unsigned long flags; - - if (!info->hook) { - if (!info->tty || !info->tty->termios) - return; - cflag = info->tty->termios->c_cflag; - if (!info->port) - return; - } else { - cflag = info->hook->cflags; - } - - i = cflag & CBAUD; - if (i & CBAUDEX) { - i &= ~CBAUDEX; - if (i < 1 || i > 2) { - if (!info->hook) - info->tty->termios->c_cflag &= ~CBAUDEX; - else - info->hook->cflags &= ~CBAUDEX; - } else - i += 15; - } - - spin_lock_irqsave(&zs_lock, flags); - info->zs_baud = baud_table[i]; - if (info->zs_baud) { - brg = BPS_TO_BRG(info->zs_baud, zs_parms->clock/info->clk_divisor); - info->zs_channel->curregs[12] = (brg & 255); - info->zs_channel->curregs[13] = ((brg >> 8) & 255); - zs_rtsdtr(info, DTR, 1); - } else { - zs_rtsdtr(info, RTS | DTR, 0); - return; - } - - /* byte size and parity */ - info->zs_channel->curregs[3] &= ~RxNBITS_MASK; - info->zs_channel->curregs[5] &= ~TxNBITS_MASK; - switch (cflag & CSIZE) { - case CS5: - bits = 7; - info->zs_channel->curregs[3] |= Rx5; - info->zs_channel->curregs[5] |= Tx5; - break; - case CS6: - bits = 8; - info->zs_channel->curregs[3] |= Rx6; - info->zs_channel->curregs[5] |= Tx6; - break; - case CS7: - bits = 9; - info->zs_channel->curregs[3] |= Rx7; - info->zs_channel->curregs[5] |= Tx7; - break; - case CS8: - default: /* defaults to 8 bits */ - bits = 10; - info->zs_channel->curregs[3] |= Rx8; - info->zs_channel->curregs[5] |= Tx8; - break; - } - - info->timeout = ((info->xmit_fifo_size*HZ*bits) / info->zs_baud); - info->timeout += HZ/50; /* Add .02 seconds of slop */ - - info->zs_channel->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN); - if (cflag & CSTOPB) { - info->zs_channel->curregs[4] |= SB2; - } else { - info->zs_channel->curregs[4] |= SB1; - } - if (cflag & PARENB) { - info->zs_channel->curregs[4] |= PAR_ENA; - } - if (!(cflag & PARODD)) { - info->zs_channel->curregs[4] |= PAR_EVEN; - } - - if (!(cflag & CLOCAL)) { - if (!(info->zs_channel->curregs[15] & DCDIE)) - info->read_reg_zero = read_zsreg(info->zs_channel, 0); - info->zs_channel->curregs[15] |= DCDIE; - } else - info->zs_channel->curregs[15] &= ~DCDIE; - if (cflag & CRTSCTS) { - info->zs_channel->curregs[15] |= CTSIE; - if ((read_zsreg(info->zs_channel, 0) & CTS) == 0) - info->tx_stopped = 1; - } else { - info->zs_channel->curregs[15] &= ~CTSIE; - info->tx_stopped = 0; - } - - /* Load up the new values */ - load_zsregs(info->zs_channel, info->zs_channel->curregs); - - spin_unlock_irqrestore(&zs_lock, flags); -} - -static void rs_flush_chars(struct tty_struct *tty) -{ - struct dec_serial *info = (struct dec_serial *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, "rs_flush_chars")) - return; - - if (info->xmit_cnt <= 0 || tty->stopped || info->tx_stopped || - !info->xmit_buf) - return; - - /* Enable transmitter */ - spin_lock_irqsave(&zs_lock, flags); - transmit_chars(info); - spin_unlock_irqrestore(&zs_lock, flags); -} - -static int rs_write(struct tty_struct * tty, - const unsigned char *buf, int count) -{ - int c, total = 0; - struct dec_serial *info = (struct dec_serial *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, "rs_write")) - return 0; - - if (!tty || !info->xmit_buf) - return 0; - - while (1) { - spin_lock_irqsave(&zs_lock, flags); - c = min(count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); - if (c <= 0) - break; - - memcpy(info->xmit_buf + info->xmit_head, buf, c); - info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt += c; - spin_unlock_irqrestore(&zs_lock, flags); - buf += c; - count -= c; - total += c; - } - - if (info->xmit_cnt && !tty->stopped && !info->tx_stopped - && !info->tx_active) - transmit_chars(info); - spin_unlock_irqrestore(&zs_lock, flags); - return total; -} - -static int rs_write_room(struct tty_struct *tty) -{ - struct dec_serial *info = (struct dec_serial *)tty->driver_data; - int ret; - - if (serial_paranoia_check(info, tty->name, "rs_write_room")) - return 0; - ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; - if (ret < 0) - ret = 0; - return ret; -} - -static int rs_chars_in_buffer(struct tty_struct *tty) -{ - struct dec_serial *info = (struct dec_serial *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer")) - return 0; - return info->xmit_cnt; -} - -static void rs_flush_buffer(struct tty_struct *tty) -{ - struct dec_serial *info = (struct dec_serial *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "rs_flush_buffer")) - return; - spin_lock_irq(&zs_lock); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - spin_unlock_irq(&zs_lock); - tty_wakeup(tty); -} - -/* - * ------------------------------------------------------------ - * rs_throttle() - * - * This routine is called by the upper-layer tty layer to signal that - * incoming characters should be throttled. - * ------------------------------------------------------------ - */ -static void rs_throttle(struct tty_struct * tty) -{ - struct dec_serial *info = (struct dec_serial *)tty->driver_data; - unsigned long flags; - -#ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("throttle %s: %d....\n", _tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty)); -#endif - - if (serial_paranoia_check(info, tty->name, "rs_throttle")) - return; - - if (I_IXOFF(tty)) { - spin_lock_irqsave(&zs_lock, flags); - info->x_char = STOP_CHAR(tty); - if (!info->tx_active) - transmit_chars(info); - spin_unlock_irqrestore(&zs_lock, flags); - } - - if (C_CRTSCTS(tty)) { - zs_rtsdtr(info, RTS, 0); - } -} - -static void rs_unthrottle(struct tty_struct * tty) -{ - struct dec_serial *info = (struct dec_serial *)tty->driver_data; - unsigned long flags; - -#ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("unthrottle %s: %d....\n", _tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty)); -#endif - - if (serial_paranoia_check(info, tty->name, "rs_unthrottle")) - return; - - if (I_IXOFF(tty)) { - spin_lock_irqsave(&zs_lock, flags); - if (info->x_char) - info->x_char = 0; - else { - info->x_char = START_CHAR(tty); - if (!info->tx_active) - transmit_chars(info); - } - spin_unlock_irqrestore(&zs_lock, flags); - } - - if (C_CRTSCTS(tty)) { - zs_rtsdtr(info, RTS, 1); - } -} - -/* - * ------------------------------------------------------------ - * rs_ioctl() and friends - * ------------------------------------------------------------ - */ - -static int get_serial_info(struct dec_serial * info, - struct serial_struct * retinfo) -{ - struct serial_struct tmp; - - if (!retinfo) - return -EFAULT; - memset(&tmp, 0, sizeof(tmp)); - tmp.type = info->type; - tmp.line = info->line; - tmp.port = info->port; - tmp.irq = info->irq; - tmp.flags = info->flags; - tmp.baud_base = info->baud_base; - tmp.close_delay = info->close_delay; - tmp.closing_wait = info->closing_wait; - tmp.custom_divisor = info->custom_divisor; - return copy_to_user(retinfo,&tmp,sizeof(*retinfo)) ? -EFAULT : 0; -} - -static int set_serial_info(struct dec_serial * info, - struct serial_struct * new_info) -{ - struct serial_struct new_serial; - struct dec_serial old_info; - int retval = 0; - - if (!new_info) - return -EFAULT; - copy_from_user(&new_serial,new_info,sizeof(new_serial)); - old_info = *info; - - if (!capable(CAP_SYS_ADMIN)) { - if ((new_serial.baud_base != info->baud_base) || - (new_serial.type != info->type) || - (new_serial.close_delay != info->close_delay) || - ((new_serial.flags & ~ZILOG_USR_MASK) != - (info->flags & ~ZILOG_USR_MASK))) - return -EPERM; - info->flags = ((info->flags & ~ZILOG_USR_MASK) | - (new_serial.flags & ZILOG_USR_MASK)); - info->custom_divisor = new_serial.custom_divisor; - goto check_and_exit; - } - - if (info->count > 1) - return -EBUSY; - - /* - * OK, past this point, all the error checking has been done. - * At this point, we start making changes..... - */ - - info->baud_base = new_serial.baud_base; - info->flags = ((info->flags & ~ZILOG_FLAGS) | - (new_serial.flags & ZILOG_FLAGS)); - info->type = new_serial.type; - info->close_delay = new_serial.close_delay; - info->closing_wait = new_serial.closing_wait; - -check_and_exit: - retval = zs_startup(info); - return retval; -} - -/* - * get_lsr_info - get line status register info - * - * Purpose: Let user call ioctl() to get info when the UART physically - * is emptied. On bus types like RS485, the transmitter must - * release the bus after transmitting. This must be done when - * the transmit shift register is empty, not be done when the - * transmit holding register is empty. This functionality - * allows an RS485 driver to be written in user space. - */ -static int get_lsr_info(struct dec_serial * info, unsigned int *value) -{ - unsigned char status; - - spin_lock(&zs_lock); - status = read_zsreg(info->zs_channel, 0); - spin_unlock_irq(&zs_lock); - put_user(status,value); - return 0; -} - -static int rs_tiocmget(struct tty_struct *tty, struct file *file) -{ - struct dec_serial * info = (struct dec_serial *)tty->driver_data; - unsigned char control, status_a, status_b; - unsigned int result; - - if (info->hook) - return -ENODEV; - - if (serial_paranoia_check(info, tty->name, __FUNCTION__)) - return -ENODEV; - - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - - if (info->zs_channel == info->zs_chan_a) - result = 0; - else { - spin_lock(&zs_lock); - control = info->zs_chan_a->curregs[5]; - status_a = read_zsreg(info->zs_chan_a, 0); - status_b = read_zsreg(info->zs_channel, 0); - spin_unlock_irq(&zs_lock); - result = ((control & RTS) ? TIOCM_RTS: 0) - | ((control & DTR) ? TIOCM_DTR: 0) - | ((status_b & DCD) ? TIOCM_CAR: 0) - | ((status_a & DCD) ? TIOCM_RNG: 0) - | ((status_a & SYNC_HUNT) ? TIOCM_DSR: 0) - | ((status_b & CTS) ? TIOCM_CTS: 0); - } - return result; -} - -static int rs_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear) -{ - struct dec_serial * info = (struct dec_serial *)tty->driver_data; - - if (info->hook) - return -ENODEV; - - if (serial_paranoia_check(info, tty->name, __FUNCTION__)) - return -ENODEV; - - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - - if (info->zs_channel == info->zs_chan_a) - return 0; - - spin_lock(&zs_lock); - if (set & TIOCM_RTS) - info->zs_chan_a->curregs[5] |= RTS; - if (set & TIOCM_DTR) - info->zs_chan_a->curregs[5] |= DTR; - if (clear & TIOCM_RTS) - info->zs_chan_a->curregs[5] &= ~RTS; - if (clear & TIOCM_DTR) - info->zs_chan_a->curregs[5] &= ~DTR; - write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]); - spin_unlock_irq(&zs_lock); - return 0; -} - -/* - * rs_break - turn transmit break condition on/off - */ -static void rs_break(struct tty_struct *tty, int break_state) -{ - struct dec_serial *info = (struct dec_serial *) tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, "rs_break")) - return; - if (!info->port) - return; - - spin_lock_irqsave(&zs_lock, flags); - if (break_state == -1) - info->zs_channel->curregs[5] |= SND_BRK; - else - info->zs_channel->curregs[5] &= ~SND_BRK; - write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]); - spin_unlock_irqrestore(&zs_lock, flags); -} - -static int rs_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) -{ - struct dec_serial * info = (struct dec_serial *)tty->driver_data; - - if (info->hook) - return -ENODEV; - - if (serial_paranoia_check(info, tty->name, "rs_ioctl")) - return -ENODEV; - - if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && - (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - } - - switch (cmd) { - case TIOCGSERIAL: - if (!access_ok(VERIFY_WRITE, (void *)arg, - sizeof(struct serial_struct))) - return -EFAULT; - return get_serial_info(info, (struct serial_struct *)arg); - - case TIOCSSERIAL: - return set_serial_info(info, (struct serial_struct *)arg); - - case TIOCSERGETLSR: /* Get line status register */ - if (!access_ok(VERIFY_WRITE, (void *)arg, - sizeof(unsigned int))) - return -EFAULT; - return get_lsr_info(info, (unsigned int *)arg); - - case TIOCSERGSTRUCT: - if (!access_ok(VERIFY_WRITE, (void *)arg, - sizeof(struct dec_serial))) - return -EFAULT; - copy_from_user((struct dec_serial *)arg, info, - sizeof(struct dec_serial)); - return 0; - - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) -{ - struct dec_serial *info = (struct dec_serial *)tty->driver_data; - int was_stopped; - - if (tty->termios->c_cflag == old_termios->c_cflag) - return; - was_stopped = info->tx_stopped; - - change_speed(info); - - if (was_stopped && !info->tx_stopped) - rs_start(tty); -} - -/* - * ------------------------------------------------------------ - * rs_close() - * - * This routine is called when the serial port gets closed. - * Wait for the last remaining data to be sent. - * ------------------------------------------------------------ - */ -static void rs_close(struct tty_struct *tty, struct file * filp) -{ - struct dec_serial * info = (struct dec_serial *)tty->driver_data; - unsigned long flags; - - if (!info || serial_paranoia_check(info, tty->name, "rs_close")) - return; - - spin_lock_irqsave(&zs_lock, flags); - - if (tty_hung_up_p(filp)) { - spin_unlock_irqrestore(&zs_lock, flags); - return; - } - -#ifdef SERIAL_DEBUG_OPEN - printk("rs_close ttyS%d, count = %d\n", info->line, info->count); -#endif - if ((tty->count == 1) && (info->count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. Info->count should always - * be one in these conditions. If it's greater than - * one, we've got real problems, since it means the - * serial port won't be shutdown. - */ - printk("rs_close: bad serial port count; tty->count is 1, " - "info->count is %d\n", info->count); - info->count = 1; - } - if (--info->count < 0) { - printk("rs_close: bad serial port count for ttyS%d: %d\n", - info->line, info->count); - info->count = 0; - } - if (info->count) { - spin_unlock_irqrestore(&zs_lock, flags); - return; - } - info->flags |= ZILOG_CLOSING; - /* - * Now we wait for the transmit buffer to clear; and we notify - * the line discipline to only process XON/XOFF characters. - */ - tty->closing = 1; - if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, info->closing_wait); - /* - * At this point we stop accepting input. To do this, we - * disable the receiver and receive interrupts. - */ - info->zs_channel->curregs[3] &= ~RxENABLE; - write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]); - info->zs_channel->curregs[1] = 0; /* disable any rx ints */ - write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]); - ZS_CLEARFIFO(info->zs_channel); - if (info->flags & ZILOG_INITIALIZED) { - /* - * Before we drop DTR, make sure the SCC transmitter - * has completely drained. - */ - rs_wait_until_sent(tty, info->timeout); - } - - shutdown(info); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); - tty_ldisc_flush(tty); - tty->closing = 0; - info->event = 0; - info->tty = 0; - if (info->blocked_open) { - if (info->close_delay) { - msleep_interruptible(jiffies_to_msecs(info->close_delay)); - } - wake_up_interruptible(&info->open_wait); - } - info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CLOSING); - wake_up_interruptible(&info->close_wait); - spin_unlock_irqrestore(&zs_lock, flags); -} - -/* - * rs_wait_until_sent() --- wait until the transmitter is empty - */ -static void rs_wait_until_sent(struct tty_struct *tty, int timeout) -{ - struct dec_serial *info = (struct dec_serial *) tty->driver_data; - unsigned long orig_jiffies; - int char_time; - - if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent")) - return; - - orig_jiffies = jiffies; - /* - * Set the check interval to be 1/5 of the estimated time to - * send a single character, and make it at least 1. The check - * interval should also be less than the timeout. - */ - char_time = (info->timeout - HZ/50) / info->xmit_fifo_size; - char_time = char_time / 5; - if (char_time == 0) - char_time = 1; - if (timeout) - char_time = min(char_time, timeout); - while ((read_zsreg(info->zs_channel, 1) & Tx_BUF_EMP) == 0) { - msleep_interruptible(jiffies_to_msecs(char_time)); - if (signal_pending(current)) - break; - if (timeout && time_after(jiffies, orig_jiffies + timeout)) - break; - } - current->state = TASK_RUNNING; -} - -/* - * rs_hangup() --- called by tty_hangup() when a hangup is signaled. - */ -static void rs_hangup(struct tty_struct *tty) -{ - struct dec_serial * info = (struct dec_serial *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "rs_hangup")) - return; - - rs_flush_buffer(tty); - shutdown(info); - info->event = 0; - info->count = 0; - info->flags &= ~ZILOG_NORMAL_ACTIVE; - info->tty = 0; - wake_up_interruptible(&info->open_wait); -} - -/* - * ------------------------------------------------------------ - * rs_open() and friends - * ------------------------------------------------------------ - */ -static int block_til_ready(struct tty_struct *tty, struct file * filp, - struct dec_serial *info) -{ - DECLARE_WAITQUEUE(wait, current); - int retval; - int do_clocal = 0; - - /* - * If the device is in the middle of being closed, then block - * until it's done, and then try again. - */ - if (info->flags & ZILOG_CLOSING) { - interruptible_sleep_on(&info->close_wait); -#ifdef SERIAL_DO_RESTART - return ((info->flags & ZILOG_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); -#else - return -EAGAIN; -#endif - } - - /* - * If non-blocking mode is set, or the port is not enabled, - * then make the check up front and then exit. - */ - if ((filp->f_flags & O_NONBLOCK) || - (tty->flags & (1 << TTY_IO_ERROR))) { - info->flags |= ZILOG_NORMAL_ACTIVE; - return 0; - } - - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - - /* - * Block waiting for the carrier detect and the line to become - * free (i.e., not in use by the callout). While we are in - * this loop, info->count is dropped by one, so that - * rs_close() knows when to free things. We restore it upon - * exit, either normal or abnormal. - */ - retval = 0; - add_wait_queue(&info->open_wait, &wait); -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready before block: ttyS%d, count = %d\n", - info->line, info->count); -#endif - spin_lock(&zs_lock); - if (!tty_hung_up_p(filp)) - info->count--; - spin_unlock_irq(&zs_lock); - info->blocked_open++; - while (1) { - spin_lock(&zs_lock); - if (tty->termios->c_cflag & CBAUD) - zs_rtsdtr(info, RTS | DTR, 1); - spin_unlock_irq(&zs_lock); - set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || - !(info->flags & ZILOG_INITIALIZED)) { -#ifdef SERIAL_DO_RESTART - if (info->flags & ZILOG_HUP_NOTIFY) - retval = -EAGAIN; - else - retval = -ERESTARTSYS; -#else - retval = -EAGAIN; -#endif - break; - } - if (!(info->flags & ZILOG_CLOSING) && - (do_clocal || (read_zsreg(info->zs_channel, 0) & DCD))) - break; - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready blocking: ttyS%d, count = %d\n", - info->line, info->count); -#endif - schedule(); - } - current->state = TASK_RUNNING; - remove_wait_queue(&info->open_wait, &wait); - if (!tty_hung_up_p(filp)) - info->count++; - info->blocked_open--; -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready after blocking: ttyS%d, count = %d\n", - info->line, info->count); -#endif - if (retval) - return retval; - info->flags |= ZILOG_NORMAL_ACTIVE; - return 0; -} - -/* - * This routine is called whenever a serial port is opened. It - * enables interrupts for a serial port, linking in its ZILOG structure into - * the IRQ chain. It also performs the serial-specific - * initialization for the tty structure. - */ -static int rs_open(struct tty_struct *tty, struct file * filp) -{ - struct dec_serial *info; - int retval, line; - - line = tty->index; - if ((line < 0) || (line >= zs_channels_found)) - return -ENODEV; - info = zs_soft + line; - - if (info->hook) - return -ENODEV; - - if (serial_paranoia_check(info, tty->name, "rs_open")) - return -ENODEV; -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open %s, count = %d\n", tty->name, info->count); -#endif - - info->count++; - tty->driver_data = info; - info->tty = tty; - - /* - * If the port is the middle of closing, bail out now - */ - if (tty_hung_up_p(filp) || - (info->flags & ZILOG_CLOSING)) { - if (info->flags & ZILOG_CLOSING) - interruptible_sleep_on(&info->close_wait); -#ifdef SERIAL_DO_RESTART - return ((info->flags & ZILOG_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); -#else - return -EAGAIN; -#endif - } - - /* - * Start up serial port - */ - retval = zs_startup(info); - if (retval) - return retval; - - retval = block_til_ready(tty, filp, info); - if (retval) { -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open returning after block_til_ready with %d\n", - retval); -#endif - return retval; - } - -#ifdef CONFIG_SERIAL_DEC_CONSOLE - if (zs_console.cflag && zs_console.index == line) { - tty->termios->c_cflag = zs_console.cflag; - zs_console.cflag = 0; - change_speed(info); - } -#endif - -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open %s successful...", tty->name); -#endif -/* tty->low_latency = 1; */ - return 0; -} - -/* Finally, routines used to initialize the serial driver. */ - -static void __init show_serial_version(void) -{ - printk("DECstation Z8530 serial driver version 0.09\n"); -} - -/* Initialize Z8530s zs_channels - */ - -static void __init probe_sccs(void) -{ - struct dec_serial **pp; - int i, n, n_chips = 0, n_channels, chip, channel; - unsigned long flags; - - /* - * did we get here by accident? - */ - if(!BUS_PRESENT) { - printk("Not on JUNKIO machine, skipping probe_sccs\n"); - return; - } - - switch(mips_machtype) { -#ifdef CONFIG_MACH_DECSTATION - case MACH_DS5000_2X0: - case MACH_DS5900: - n_chips = 2; - zs_parms = &ds_parms; - zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0]; - zs_parms->irq1 = dec_interrupt[DEC_IRQ_SCC1]; - break; - case MACH_DS5000_1XX: - n_chips = 2; - zs_parms = &ds_parms; - zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0]; - zs_parms->irq1 = dec_interrupt[DEC_IRQ_SCC1]; - break; - case MACH_DS5000_XX: - n_chips = 1; - zs_parms = &ds_parms; - zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0]; - break; -#endif - default: - panic("zs: unsupported bus"); - } - if (!zs_parms) - panic("zs: uninitialized parms"); - - pp = &zs_chain; - - n_channels = 0; - - for (chip = 0; chip < n_chips; chip++) { - for (channel = 0; channel <= 1; channel++) { - /* - * The sccs reside on the high byte of the 16 bit IOBUS - */ - zs_channels[n_channels].control = - (volatile void *)CKSEG1ADDR(dec_kn_slot_base + - (0 == chip ? zs_parms->scc0 : zs_parms->scc1) + - (0 == channel ? zs_parms->channel_a_offset : - zs_parms->channel_b_offset)); - zs_channels[n_channels].data = - zs_channels[n_channels].control + 4; - -#ifndef CONFIG_SERIAL_DEC_CONSOLE - /* - * We're called early and memory managment isn't up, yet. - * Thus request_region would fail. - */ - if (!request_region((unsigned long) - zs_channels[n_channels].control, - ZS_CHAN_IO_SIZE, "SCC")) - panic("SCC I/O region is not free"); -#endif - zs_soft[n_channels].zs_channel = &zs_channels[n_channels]; - /* HACK alert! */ - if (!(chip & 1)) - zs_soft[n_channels].irq = zs_parms->irq0; - else - zs_soft[n_channels].irq = zs_parms->irq1; - - /* - * Identification of channel A. Location of channel A - * inside chip depends on mapping of internal address - * the chip decodes channels by. - * CHANNEL_A_NR returns either 0 (in case of - * DECstations) or 1 (in case of Baget). - */ - if (CHANNEL_A_NR == channel) - zs_soft[n_channels].zs_chan_a = - &zs_channels[n_channels+1-2*CHANNEL_A_NR]; - else - zs_soft[n_channels].zs_chan_a = - &zs_channels[n_channels]; - - *pp = &zs_soft[n_channels]; - pp = &zs_soft[n_channels].zs_next; - n_channels++; - } - } - - *pp = 0; - zs_channels_found = n_channels; - - for (n = 0; n < zs_channels_found; n++) { - for (i = 0; i < 16; i++) { - zs_soft[n].zs_channel->curregs[i] = zs_init_regs[i]; - } - } - - spin_lock_irqsave(&zs_lock, flags); - for (n = 0; n < zs_channels_found; n++) { - if (n % 2 == 0) { - write_zsreg(zs_soft[n].zs_chan_a, R9, FHWRES); - udelay(10); - write_zsreg(zs_soft[n].zs_chan_a, R9, 0); - } - load_zsregs(zs_soft[n].zs_channel, - zs_soft[n].zs_channel->curregs); - } - spin_unlock_irqrestore(&zs_lock, flags); -} - -static const struct tty_operations serial_ops = { - .open = rs_open, - .close = rs_close, - .write = rs_write, - .flush_chars = rs_flush_chars, - .write_room = rs_write_room, - .chars_in_buffer = rs_chars_in_buffer, - .flush_buffer = rs_flush_buffer, - .ioctl = rs_ioctl, - .throttle = rs_throttle, - .unthrottle = rs_unthrottle, - .set_termios = rs_set_termios, - .stop = rs_stop, - .start = rs_start, - .hangup = rs_hangup, - .break_ctl = rs_break, - .wait_until_sent = rs_wait_until_sent, - .tiocmget = rs_tiocmget, - .tiocmset = rs_tiocmset, -}; - -/* zs_init inits the driver */ -int __init zs_init(void) -{ - int channel, i; - struct dec_serial *info; - - if(!BUS_PRESENT) - return -ENODEV; - - /* Find out how many Z8530 SCCs we have */ - if (zs_chain == 0) - probe_sccs(); - serial_driver = alloc_tty_driver(zs_channels_found); - if (!serial_driver) - return -ENOMEM; - - show_serial_version(); - - /* Initialize the tty_driver structure */ - /* Not all of this is exactly right for us. */ - - serial_driver->owner = THIS_MODULE; - serial_driver->name = "ttyS"; - serial_driver->major = TTY_MAJOR; - serial_driver->minor_start = 64; - serial_driver->type = TTY_DRIVER_TYPE_SERIAL; - serial_driver->subtype = SERIAL_TYPE_NORMAL; - serial_driver->init_termios = tty_std_termios; - serial_driver->init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - tty_set_operations(serial_driver, &serial_ops); - - if (tty_register_driver(serial_driver)) - panic("Couldn't register serial driver"); - - for (info = zs_chain, i = 0; info; info = info->zs_next, i++) { - - /* Needed before interrupts are enabled. */ - info->tty = 0; - info->x_char = 0; - - if (info->hook && info->hook->init_info) { - (*info->hook->init_info)(info); - continue; - } - - info->magic = SERIAL_MAGIC; - info->port = (int) info->zs_channel->control; - info->line = i; - info->custom_divisor = 16; - info->close_delay = 50; - info->closing_wait = 3000; - info->event = 0; - info->count = 0; - info->blocked_open = 0; - tasklet_init(&info->tlet, do_softint, (unsigned long)info); - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); - printk("ttyS%02d at 0x%08x (irq = %d) is a Z85C30 SCC\n", - info->line, info->port, info->irq); - tty_register_device(serial_driver, info->line, NULL); - - } - - for (channel = 0; channel < zs_channels_found; ++channel) { - zs_soft[channel].clk_divisor = 16; - zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]); - - if (request_irq(zs_soft[channel].irq, rs_interrupt, IRQF_SHARED, - "scc", &zs_soft[channel])) - printk(KERN_ERR "decserial: can't get irq %d\n", - zs_soft[channel].irq); - - if (zs_soft[channel].hook) { - zs_startup(&zs_soft[channel]); - if (zs_soft[channel].hook->init_channel) - (*zs_soft[channel].hook->init_channel) - (&zs_soft[channel]); - } - } - - return 0; -} - -/* - * polling I/O routines - */ -static int zs_poll_tx_char(void *handle, unsigned char ch) -{ - struct dec_serial *info = handle; - struct dec_zschannel *chan = info->zs_channel; - int ret; - - if(chan) { - int loops = 10000; - - while (loops && !(read_zsreg(chan, 0) & Tx_BUF_EMP)) - loops--; - - if (loops) { - write_zsdata(chan, ch); - ret = 0; - } else - ret = -EAGAIN; - - return ret; - } else - return -ENODEV; -} - -static int zs_poll_rx_char(void *handle) -{ - struct dec_serial *info = handle; - struct dec_zschannel *chan = info->zs_channel; - int ret; - - if(chan) { - int loops = 10000; - - while (loops && !(read_zsreg(chan, 0) & Rx_CH_AV)) - loops--; - - if (loops) - ret = read_zsdata(chan); - else - ret = -EAGAIN; - - return ret; - } else - return -ENODEV; -} - -int register_zs_hook(unsigned int channel, struct dec_serial_hook *hook) -{ - struct dec_serial *info = &zs_soft[channel]; - - if (info->hook) { - printk("%s: line %d has already a hook registered\n", - __FUNCTION__, channel); - - return 0; - } else { - hook->poll_rx_char = zs_poll_rx_char; - hook->poll_tx_char = zs_poll_tx_char; - info->hook = hook; - - return 1; - } -} - -int unregister_zs_hook(unsigned int channel) -{ - struct dec_serial *info = &zs_soft[channel]; - - if (info->hook) { - info->hook = NULL; - return 1; - } else { - printk("%s: trying to unregister hook on line %d," - " but none is registered\n", __FUNCTION__, channel); - return 0; - } -} - -/* - * ------------------------------------------------------------ - * Serial console driver - * ------------------------------------------------------------ - */ -#ifdef CONFIG_SERIAL_DEC_CONSOLE - - -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - */ -static void serial_console_write(struct console *co, const char *s, - unsigned count) -{ - struct dec_serial *info; - int i; - - info = zs_soft + co->index; - - for (i = 0; i < count; i++, s++) { - if(*s == '\n') - zs_poll_tx_char(info, '\r'); - zs_poll_tx_char(info, *s); - } -} - -static struct tty_driver *serial_console_device(struct console *c, int *index) -{ - *index = c->index; - return serial_driver; -} - -/* - * Setup initial baud/bits/parity. We do two things here: - * - construct a cflag setting for the first rs_open() - * - initialize the serial port - * Return non-zero if we didn't find a serial port. - */ -static int __init serial_console_setup(struct console *co, char *options) -{ - struct dec_serial *info; - int baud = 9600; - int bits = 8; - int parity = 'n'; - int cflag = CREAD | HUPCL | CLOCAL; - int clk_divisor = 16; - int brg; - char *s; - unsigned long flags; - - if(!BUS_PRESENT) - return -ENODEV; - - info = zs_soft + co->index; - - if (zs_chain == 0) - probe_sccs(); - - info->is_cons = 1; - - if (options) { - baud = simple_strtoul(options, NULL, 10); - s = options; - while(*s >= '0' && *s <= '9') - s++; - if (*s) - parity = *s++; - if (*s) - bits = *s - '0'; - } - - /* - * Now construct a cflag setting. - */ - switch(baud) { - case 1200: - cflag |= B1200; - break; - case 2400: - cflag |= B2400; - break; - case 4800: - cflag |= B4800; - break; - case 19200: - cflag |= B19200; - break; - case 38400: - cflag |= B38400; - break; - case 57600: - cflag |= B57600; - break; - case 115200: - cflag |= B115200; - break; - case 9600: - default: - cflag |= B9600; - /* - * Set this to a sane value to prevent a divide error. - */ - baud = 9600; - break; - } - switch(bits) { - case 7: - cflag |= CS7; - break; - default: - case 8: - cflag |= CS8; - break; - } - switch(parity) { - case 'o': case 'O': - cflag |= PARODD; - break; - case 'e': case 'E': - cflag |= PARENB; - break; - } - co->cflag = cflag; - - spin_lock_irqsave(&zs_lock, flags); - - /* - * Set up the baud rate generator. - */ - brg = BPS_TO_BRG(baud, zs_parms->clock / clk_divisor); - info->zs_channel->curregs[R12] = (brg & 255); - info->zs_channel->curregs[R13] = ((brg >> 8) & 255); - - /* - * Set byte size and parity. - */ - if (bits == 7) { - info->zs_channel->curregs[R3] |= Rx7; - info->zs_channel->curregs[R5] |= Tx7; - } else { - info->zs_channel->curregs[R3] |= Rx8; - info->zs_channel->curregs[R5] |= Tx8; - } - if (cflag & PARENB) { - info->zs_channel->curregs[R4] |= PAR_ENA; - } - if (!(cflag & PARODD)) { - info->zs_channel->curregs[R4] |= PAR_EVEN; - } - info->zs_channel->curregs[R4] |= SB1; - - /* - * Turn on RTS and DTR. - */ - zs_rtsdtr(info, RTS | DTR, 1); - - /* - * Finally, enable sequencing. - */ - info->zs_channel->curregs[R3] |= RxENABLE; - info->zs_channel->curregs[R5] |= TxENAB; - - /* - * Clear the interrupt registers. - */ - write_zsreg(info->zs_channel, R0, ERR_RES); - write_zsreg(info->zs_channel, R0, RES_H_IUS); - - /* - * Load up the new values. - */ - load_zsregs(info->zs_channel, info->zs_channel->curregs); - - /* Save the current value of RR0 */ - info->read_reg_zero = read_zsreg(info->zs_channel, R0); - - zs_soft[co->index].clk_divisor = clk_divisor; - zs_soft[co->index].zs_baud = get_zsbaud(&zs_soft[co->index]); - - spin_unlock_irqrestore(&zs_lock, flags); - - return 0; -} - -static struct console zs_console = { - .name = "ttyS", - .write = serial_console_write, - .device = serial_console_device, - .setup = serial_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - -/* - * Register console. - */ -void __init zs_serial_console_init(void) -{ - register_console(&zs_console); -} -#endif /* ifdef CONFIG_SERIAL_DEC_CONSOLE */ - -#ifdef CONFIG_KGDB -struct dec_zschannel *zs_kgdbchan; -static unsigned char scc_inittab[] = { - 9, 0x80, /* reset A side (CHRA) */ - 13, 0, /* set baud rate divisor */ - 12, 1, - 14, 1, /* baud rate gen enable, src=rtxc (BRENABL) */ - 11, 0x50, /* clocks = br gen (RCBR | TCBR) */ - 5, 0x6a, /* tx 8 bits, assert RTS (Tx8 | TxENAB | RTS) */ - 4, 0x44, /* x16 clock, 1 stop (SB1 | X16CLK)*/ - 3, 0xc1, /* rx enable, 8 bits (RxENABLE | Rx8)*/ -}; - -/* These are for receiving and sending characters under the kgdb - * source level kernel debugger. - */ -void putDebugChar(char kgdb_char) -{ - struct dec_zschannel *chan = zs_kgdbchan; - while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0) - RECOVERY_DELAY; - write_zsdata(chan, kgdb_char); -} -char getDebugChar(void) -{ - struct dec_zschannel *chan = zs_kgdbchan; - while((read_zsreg(chan, 0) & Rx_CH_AV) == 0) - eieio(); /*barrier();*/ - return read_zsdata(chan); -} -void kgdb_interruptible(int yes) -{ - struct dec_zschannel *chan = zs_kgdbchan; - int one, nine; - nine = read_zsreg(chan, 9); - if (yes == 1) { - one = EXT_INT_ENAB|RxINT_ALL; - nine |= MIE; - printk("turning serial ints on\n"); - } else { - one = RxINT_DISAB; - nine &= ~MIE; - printk("turning serial ints off\n"); - } - write_zsreg(chan, 1, one); - write_zsreg(chan, 9, nine); -} - -static int kgdbhook_init_channel(void *handle) -{ - return 0; -} - -static void kgdbhook_init_info(void *handle) -{ -} - -static void kgdbhook_rx_char(void *handle, unsigned char ch, unsigned char fl) -{ - struct dec_serial *info = handle; - - if (fl != TTY_NORMAL) - return; - if (ch == 0x03 || ch == '$') - breakpoint(); -} - -/* This sets up the serial port we're using, and turns on - * interrupts for that channel, so kgdb is usable once we're done. - */ -static inline void kgdb_chaninit(struct dec_zschannel *ms, int intson, int bps) -{ - int brg; - int i, x; - volatile char *sccc = ms->control; - brg = BPS_TO_BRG(bps, zs_parms->clock/16); - printk("setting bps on kgdb line to %d [brg=%x]\n", bps, brg); - for (i = 20000; i != 0; --i) { - x = *sccc; eieio(); - } - for (i = 0; i < sizeof(scc_inittab); ++i) { - write_zsreg(ms, scc_inittab[i], scc_inittab[i+1]); - i++; - } -} -/* This is called at boot time to prime the kgdb serial debugging - * serial line. The 'tty_num' argument is 0 for /dev/ttya and 1 - * for /dev/ttyb which is determined in setup_arch() from the - * boot command line flags. - */ -struct dec_serial_hook zs_kgdbhook = { - .init_channel = kgdbhook_init_channel, - .init_info = kgdbhook_init_info, - .rx_char = kgdbhook_rx_char, - .cflags = B38400 | CS8 | CLOCAL, -}; - -void __init zs_kgdb_hook(int tty_num) -{ - /* Find out how many Z8530 SCCs we have */ - if (zs_chain == 0) - probe_sccs(); - zs_soft[tty_num].zs_channel = &zs_channels[tty_num]; - zs_kgdbchan = zs_soft[tty_num].zs_channel; - zs_soft[tty_num].change_needed = 0; - zs_soft[tty_num].clk_divisor = 16; - zs_soft[tty_num].zs_baud = 38400; - zs_soft[tty_num].hook = &zs_kgdbhook; /* This runs kgdb */ - /* Turn on transmitter/receiver at 8-bits/char */ - kgdb_chaninit(zs_soft[tty_num].zs_channel, 1, 38400); - printk("KGDB: on channel %d initialized\n", tty_num); - set_debug_traps(); /* init stub */ -} -#endif /* ifdef CONFIG_KGDB */ diff --git a/drivers/tc/zs.h b/drivers/tc/zs.h deleted file mode 100644 index 13512200ceba..000000000000 --- a/drivers/tc/zs.h +++ /dev/null @@ -1,404 +0,0 @@ -/* - * drivers/tc/zs.h: Definitions for the DECstation Z85C30 serial driver. - * - * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras. - * Adapted from drivers/macintosh/macserial.h by Harald Koerfgen. - * - * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au) - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 2004, 2005 Maciej W. Rozycki - */ -#ifndef _DECSERIAL_H -#define _DECSERIAL_H - -#include <asm/dec/serial.h> - -#define NUM_ZSREGS 16 - -struct serial_struct { - int type; - int line; - int port; - int irq; - int flags; - int xmit_fifo_size; - int custom_divisor; - int baud_base; - unsigned short close_delay; - char reserved_char[2]; - int hub6; - unsigned short closing_wait; /* time to wait before closing */ - unsigned short closing_wait2; /* no longer used... */ - int reserved[4]; -}; - -/* - * For the close wait times, 0 means wait forever for serial port to - * flush its output. 65535 means don't wait at all. - */ -#define ZILOG_CLOSING_WAIT_INF 0 -#define ZILOG_CLOSING_WAIT_NONE 65535 - -/* - * Definitions for ZILOG_struct (and serial_struct) flags field - */ -#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes - on the callout port */ -#define ZILOG_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */ -#define ZILOG_SAK 0x0004 /* Secure Attention Key (Orange book) */ -#define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */ - -#define ZILOG_SPD_MASK 0x0030 -#define ZILOG_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */ - -#define ZILOG_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */ -#define ZILOG_SPD_CUST 0x0030 /* Use user-specified divisor */ - -#define ZILOG_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */ -#define ZILOG_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */ -#define ZILOG_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */ -#define ZILOG_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */ -#define ZILOG_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */ - -#define ZILOG_FLAGS 0x0FFF /* Possible legal ZILOG flags */ -#define ZILOG_USR_MASK 0x0430 /* Legal flags that non-privileged - * users can set or reset */ - -/* Internal flags used only by kernel/chr_drv/serial.c */ -#define ZILOG_INITIALIZED 0x80000000 /* Serial port was initialized */ -#define ZILOG_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */ -#define ZILOG_NORMAL_ACTIVE 0x20000000 /* Normal device is active */ -#define ZILOG_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */ -#define ZILOG_CLOSING 0x08000000 /* Serial port is closing */ -#define ZILOG_CTS_FLOW 0x04000000 /* Do CTS flow control */ -#define ZILOG_CHECK_CD 0x02000000 /* i.e., CLOCAL */ - -/* Software state per channel */ - -#ifdef __KERNEL__ -/* - * This is our internal structure for each serial port's state. - * - * Many fields are paralleled by the structure used by the serial_struct - * structure. - * - * For definitions of the flags field, see tty.h - */ - -struct dec_zschannel { - volatile unsigned char *control; - volatile unsigned char *data; - - /* Current write register values */ - unsigned char curregs[NUM_ZSREGS]; -}; - -struct dec_serial { - struct dec_serial *zs_next; /* For IRQ servicing chain. */ - struct dec_zschannel *zs_channel; /* Channel registers. */ - struct dec_zschannel *zs_chan_a; /* A side registers. */ - unsigned char read_reg_zero; - - struct dec_serial_hook *hook; /* Hook on this channel. */ - int tty_break; /* Set on BREAK condition. */ - int is_cons; /* Is this our console. */ - int tx_active; /* Char is being xmitted. */ - int tx_stopped; /* Output is suspended. */ - - /* - * We need to know the current clock divisor - * to read the bps rate the chip has currently loaded. - */ - int clk_divisor; /* May be 1, 16, 32, or 64. */ - int zs_baud; - - char change_needed; - - int magic; - int baud_base; - int port; - int irq; - int flags; /* Defined in tty.h. */ - int type; /* UART type. */ - struct tty_struct *tty; - int read_status_mask; - int ignore_status_mask; - int timeout; - int xmit_fifo_size; - int custom_divisor; - int x_char; /* XON/XOFF character. */ - int close_delay; - unsigned short closing_wait; - unsigned short closing_wait2; - unsigned long event; - unsigned long last_active; - int line; - int count; /* # of fds on device. */ - int blocked_open; /* # of blocked opens. */ - unsigned char *xmit_buf; - int xmit_head; - int xmit_tail; - int xmit_cnt; - struct tasklet_struct tlet; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; -}; - - -#define SERIAL_MAGIC 0x5301 - -/* - * The size of the serial xmit buffer is 1 page, or 4096 bytes - */ -#define SERIAL_XMIT_SIZE 4096 - -/* - * Events are used to schedule things to happen at timer-interrupt - * time, instead of at rs interrupt time. - */ -#define RS_EVENT_WRITE_WAKEUP 0 - -#endif /* __KERNEL__ */ - -/* Conversion routines to/from brg time constants from/to bits - * per second. - */ -#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2)) -#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2) - -/* The Zilog register set */ - -#define FLAG 0x7e - -/* Write Register 0 */ -#define R0 0 /* Register selects */ -#define R1 1 -#define R2 2 -#define R3 3 -#define R4 4 -#define R5 5 -#define R6 6 -#define R7 7 -#define R8 8 -#define R9 9 -#define R10 10 -#define R11 11 -#define R12 12 -#define R13 13 -#define R14 14 -#define R15 15 - -#define NULLCODE 0 /* Null Code */ -#define POINT_HIGH 0x8 /* Select upper half of registers */ -#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */ -#define SEND_ABORT 0x18 /* HDLC Abort */ -#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */ -#define RES_Tx_P 0x28 /* Reset TxINT Pending */ -#define ERR_RES 0x30 /* Error Reset */ -#define RES_H_IUS 0x38 /* Reset highest IUS */ - -#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */ -#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */ -#define RES_EOM_L 0xC0 /* Reset EOM latch */ - -/* Write Register 1 */ - -#define EXT_INT_ENAB 0x1 /* Ext Int Enable */ -#define TxINT_ENAB 0x2 /* Tx Int Enable */ -#define PAR_SPEC 0x4 /* Parity is special condition */ - -#define RxINT_DISAB 0 /* Rx Int Disable */ -#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */ -#define RxINT_ALL 0x10 /* Int on all Rx Characters or error */ -#define RxINT_ERR 0x18 /* Int on error only */ -#define RxINT_MASK 0x18 - -#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */ -#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */ -#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */ - -/* Write Register #2 (Interrupt Vector) */ - -/* Write Register 3 */ - -#define RxENABLE 0x1 /* Rx Enable */ -#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */ -#define ADD_SM 0x4 /* Address Search Mode (SDLC) */ -#define RxCRC_ENAB 0x8 /* Rx CRC Enable */ -#define ENT_HM 0x10 /* Enter Hunt Mode */ -#define AUTO_ENAB 0x20 /* Auto Enables */ -#define Rx5 0x0 /* Rx 5 Bits/Character */ -#define Rx7 0x40 /* Rx 7 Bits/Character */ -#define Rx6 0x80 /* Rx 6 Bits/Character */ -#define Rx8 0xc0 /* Rx 8 Bits/Character */ -#define RxNBITS_MASK 0xc0 - -/* Write Register 4 */ - -#define PAR_ENA 0x1 /* Parity Enable */ -#define PAR_EVEN 0x2 /* Parity Even/Odd* */ - -#define SYNC_ENAB 0 /* Sync Modes Enable */ -#define SB1 0x4 /* 1 stop bit/char */ -#define SB15 0x8 /* 1.5 stop bits/char */ -#define SB2 0xc /* 2 stop bits/char */ -#define SB_MASK 0xc - -#define MONSYNC 0 /* 8 Bit Sync character */ -#define BISYNC 0x10 /* 16 bit sync character */ -#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */ -#define EXTSYNC 0x30 /* External Sync Mode */ - -#define X1CLK 0x0 /* x1 clock mode */ -#define X16CLK 0x40 /* x16 clock mode */ -#define X32CLK 0x80 /* x32 clock mode */ -#define X64CLK 0xC0 /* x64 clock mode */ -#define XCLK_MASK 0xC0 - -/* Write Register 5 */ - -#define TxCRC_ENAB 0x1 /* Tx CRC Enable */ -#define RTS 0x2 /* RTS */ -#define SDLC_CRC 0x4 /* SDLC/CRC-16 */ -#define TxENAB 0x8 /* Tx Enable */ -#define SND_BRK 0x10 /* Send Break */ -#define Tx5 0x0 /* Tx 5 bits (or less)/character */ -#define Tx7 0x20 /* Tx 7 bits/character */ -#define Tx6 0x40 /* Tx 6 bits/character */ -#define Tx8 0x60 /* Tx 8 bits/character */ -#define TxNBITS_MASK 0x60 -#define DTR 0x80 /* DTR */ - -/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */ - -/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */ - -/* Write Register 8 (transmit buffer) */ - -/* Write Register 9 (Master interrupt control) */ -#define VIS 1 /* Vector Includes Status */ -#define NV 2 /* No Vector */ -#define DLC 4 /* Disable Lower Chain */ -#define MIE 8 /* Master Interrupt Enable */ -#define STATHI 0x10 /* Status high */ -#define SOFTACK 0x20 /* Software Interrupt Acknowledge */ -#define NORESET 0 /* No reset on write to R9 */ -#define CHRB 0x40 /* Reset channel B */ -#define CHRA 0x80 /* Reset channel A */ -#define FHWRES 0xc0 /* Force hardware reset */ - -/* Write Register 10 (misc control bits) */ -#define BIT6 1 /* 6 bit/8bit sync */ -#define LOOPMODE 2 /* SDLC Loop mode */ -#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */ -#define MARKIDLE 8 /* Mark/flag on idle */ -#define GAOP 0x10 /* Go active on poll */ -#define NRZ 0 /* NRZ mode */ -#define NRZI 0x20 /* NRZI mode */ -#define FM1 0x40 /* FM1 (transition = 1) */ -#define FM0 0x60 /* FM0 (transition = 0) */ -#define CRCPS 0x80 /* CRC Preset I/O */ - -/* Write Register 11 (Clock Mode control) */ -#define TRxCXT 0 /* TRxC = Xtal output */ -#define TRxCTC 1 /* TRxC = Transmit clock */ -#define TRxCBR 2 /* TRxC = BR Generator Output */ -#define TRxCDP 3 /* TRxC = DPLL output */ -#define TRxCOI 4 /* TRxC O/I */ -#define TCRTxCP 0 /* Transmit clock = RTxC pin */ -#define TCTRxCP 8 /* Transmit clock = TRxC pin */ -#define TCBR 0x10 /* Transmit clock = BR Generator output */ -#define TCDPLL 0x18 /* Transmit clock = DPLL output */ -#define RCRTxCP 0 /* Receive clock = RTxC pin */ -#define RCTRxCP 0x20 /* Receive clock = TRxC pin */ -#define RCBR 0x40 /* Receive clock = BR Generator output */ -#define RCDPLL 0x60 /* Receive clock = DPLL output */ -#define RTxCX 0x80 /* RTxC Xtal/No Xtal */ - -/* Write Register 12 (lower byte of baud rate generator time constant) */ - -/* Write Register 13 (upper byte of baud rate generator time constant) */ - -/* Write Register 14 (Misc control bits) */ -#define BRENABL 1 /* Baud rate generator enable */ -#define BRSRC 2 /* Baud rate generator source */ -#define DTRREQ 4 /* DTR/Request function */ -#define AUTOECHO 8 /* Auto Echo */ -#define LOOPBAK 0x10 /* Local loopback */ -#define SEARCH 0x20 /* Enter search mode */ -#define RMC 0x40 /* Reset missing clock */ -#define DISDPLL 0x60 /* Disable DPLL */ -#define SSBR 0x80 /* Set DPLL source = BR generator */ -#define SSRTxC 0xa0 /* Set DPLL source = RTxC */ -#define SFMM 0xc0 /* Set FM mode */ -#define SNRZI 0xe0 /* Set NRZI mode */ - -/* Write Register 15 (external/status interrupt control) */ -#define ZCIE 2 /* Zero count IE */ -#define DCDIE 8 /* DCD IE */ -#define SYNCIE 0x10 /* Sync/hunt IE */ -#define CTSIE 0x20 /* CTS IE */ -#define TxUIE 0x40 /* Tx Underrun/EOM IE */ -#define BRKIE 0x80 /* Break/Abort IE */ - - -/* Read Register 0 */ -#define Rx_CH_AV 0x1 /* Rx Character Available */ -#define ZCOUNT 0x2 /* Zero count */ -#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */ -#define DCD 0x8 /* DCD */ -#define SYNC_HUNT 0x10 /* Sync/hunt */ -#define CTS 0x20 /* CTS */ -#define TxEOM 0x40 /* Tx underrun */ -#define BRK_ABRT 0x80 /* Break/Abort */ - -/* Read Register 1 */ -#define ALL_SNT 0x1 /* All sent */ -/* Residue Data for 8 Rx bits/char programmed */ -#define RES3 0x8 /* 0/3 */ -#define RES4 0x4 /* 0/4 */ -#define RES5 0xc /* 0/5 */ -#define RES6 0x2 /* 0/6 */ -#define RES7 0xa /* 0/7 */ -#define RES8 0x6 /* 0/8 */ -#define RES18 0xe /* 1/8 */ -#define RES28 0x0 /* 2/8 */ -/* Special Rx Condition Interrupts */ -#define PAR_ERR 0x10 /* Parity error */ -#define Rx_OVR 0x20 /* Rx Overrun Error */ -#define FRM_ERR 0x40 /* CRC/Framing Error */ -#define END_FR 0x80 /* End of Frame (SDLC) */ - -/* Read Register 2 (channel b only) - Interrupt vector */ - -/* Read Register 3 (interrupt pending register) ch a only */ -#define CHBEXT 0x1 /* Channel B Ext/Stat IP */ -#define CHBTxIP 0x2 /* Channel B Tx IP */ -#define CHBRxIP 0x4 /* Channel B Rx IP */ -#define CHAEXT 0x8 /* Channel A Ext/Stat IP */ -#define CHATxIP 0x10 /* Channel A Tx IP */ -#define CHARxIP 0x20 /* Channel A Rx IP */ - -/* Read Register 8 (receive data register) */ - -/* Read Register 10 (misc status bits) */ -#define ONLOOP 2 /* On loop */ -#define LOOPSEND 0x10 /* Loop sending */ -#define CLK2MIS 0x40 /* Two clocks missing */ -#define CLK1MIS 0x80 /* One clock missing */ - -/* Read Register 12 (lower byte of baud rate generator constant) */ - -/* Read Register 13 (upper byte of baud rate generator constant) */ - -/* Read Register 15 (value of WR 15) */ - -/* Misc macros */ -#define ZS_CLEARERR(channel) (write_zsreg(channel, 0, ERR_RES)) -#define ZS_CLEARFIFO(channel) do { volatile unsigned char garbage; \ - garbage = read_zsdata(channel); \ - garbage = read_zsdata(channel); \ - garbage = read_zsdata(channel); \ - } while(0) - -#endif /* !(_DECSERIAL_H) */ diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig index da219c043c99..9de1c114f809 100644 --- a/drivers/video/logo/Kconfig +++ b/drivers/video/logo/Kconfig @@ -12,7 +12,7 @@ if LOGO config FB_LOGO_EXTRA bool - depends on FB + depends on FB=y default y if SPU_BASE config LOGO_LINUX_MONO diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile new file mode 100644 index 000000000000..56592f0d6cef --- /dev/null +++ b/drivers/xen/Makefile @@ -0,0 +1,2 @@ +obj-y += grant-table.o +obj-y += xenbus/ diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c new file mode 100644 index 000000000000..ea94dbabf9a9 --- /dev/null +++ b/drivers/xen/grant-table.c @@ -0,0 +1,582 @@ +/****************************************************************************** + * grant_table.c + * + * Granting foreign access to our memory reservation. + * + * Copyright (c) 2005-2006, Christopher Clark + * Copyright (c) 2004-2005, K A Fraser + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/vmalloc.h> +#include <linux/uaccess.h> + +#include <xen/interface/xen.h> +#include <xen/page.h> +#include <xen/grant_table.h> + +#include <asm/pgtable.h> +#include <asm/sync_bitops.h> + + +/* External tools reserve first few grant table entries. */ +#define NR_RESERVED_ENTRIES 8 +#define GNTTAB_LIST_END 0xffffffff +#define GREFS_PER_GRANT_FRAME (PAGE_SIZE / sizeof(struct grant_entry)) + +static grant_ref_t **gnttab_list; +static unsigned int nr_grant_frames; +static unsigned int boot_max_nr_grant_frames; +static int gnttab_free_count; +static grant_ref_t gnttab_free_head; +static DEFINE_SPINLOCK(gnttab_list_lock); + +static struct grant_entry *shared; + +static struct gnttab_free_callback *gnttab_free_callback_list; + +static int gnttab_expand(unsigned int req_entries); + +#define RPP (PAGE_SIZE / sizeof(grant_ref_t)) + +static inline grant_ref_t *__gnttab_entry(grant_ref_t entry) +{ + return &gnttab_list[(entry) / RPP][(entry) % RPP]; +} +/* This can be used as an l-value */ +#define gnttab_entry(entry) (*__gnttab_entry(entry)) + +static int get_free_entries(unsigned count) +{ + unsigned long flags; + int ref, rc; + grant_ref_t head; + + spin_lock_irqsave(&gnttab_list_lock, flags); + + if ((gnttab_free_count < count) && + ((rc = gnttab_expand(count - gnttab_free_count)) < 0)) { + spin_unlock_irqrestore(&gnttab_list_lock, flags); + return rc; + } + + ref = head = gnttab_free_head; + gnttab_free_count -= count; + while (count-- > 1) + head = gnttab_entry(head); + gnttab_free_head = gnttab_entry(head); + gnttab_entry(head) = GNTTAB_LIST_END; + + spin_unlock_irqrestore(&gnttab_list_lock, flags); + + return ref; +} + +static void do_free_callbacks(void) +{ + struct gnttab_free_callback *callback, *next; + + callback = gnttab_free_callback_list; + gnttab_free_callback_list = NULL; + + while (callback != NULL) { + next = callback->next; + if (gnttab_free_count >= callback->count) { + callback->next = NULL; + callback->fn(callback->arg); + } else { + callback->next = gnttab_free_callback_list; + gnttab_free_callback_list = callback; + } + callback = next; + } +} + +static inline void check_free_callbacks(void) +{ + if (unlikely(gnttab_free_callback_list)) + do_free_callbacks(); +} + +static void put_free_entry(grant_ref_t ref) +{ + unsigned long flags; + spin_lock_irqsave(&gnttab_list_lock, flags); + gnttab_entry(ref) = gnttab_free_head; + gnttab_free_head = ref; + gnttab_free_count++; + check_free_callbacks(); + spin_unlock_irqrestore(&gnttab_list_lock, flags); +} + +static void update_grant_entry(grant_ref_t ref, domid_t domid, + unsigned long frame, unsigned flags) +{ + /* + * Introducing a valid entry into the grant table: + * 1. Write ent->domid. + * 2. Write ent->frame: + * GTF_permit_access: Frame to which access is permitted. + * GTF_accept_transfer: Pseudo-phys frame slot being filled by new + * frame, or zero if none. + * 3. Write memory barrier (WMB). + * 4. Write ent->flags, inc. valid type. + */ + shared[ref].frame = frame; + shared[ref].domid = domid; + wmb(); + shared[ref].flags = flags; +} + +/* + * Public grant-issuing interface functions + */ +void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid, + unsigned long frame, int readonly) +{ + update_grant_entry(ref, domid, frame, + GTF_permit_access | (readonly ? GTF_readonly : 0)); +} +EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref); + +int gnttab_grant_foreign_access(domid_t domid, unsigned long frame, + int readonly) +{ + int ref; + + ref = get_free_entries(1); + if (unlikely(ref < 0)) + return -ENOSPC; + + gnttab_grant_foreign_access_ref(ref, domid, frame, readonly); + + return ref; +} +EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access); + +int gnttab_query_foreign_access(grant_ref_t ref) +{ + u16 nflags; + + nflags = shared[ref].flags; + + return (nflags & (GTF_reading|GTF_writing)); +} +EXPORT_SYMBOL_GPL(gnttab_query_foreign_access); + +int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly) +{ + u16 flags, nflags; + + nflags = shared[ref].flags; + do { + flags = nflags; + if (flags & (GTF_reading|GTF_writing)) { + printk(KERN_ALERT "WARNING: g.e. still in use!\n"); + return 0; + } + } while ((nflags = sync_cmpxchg(&shared[ref].flags, flags, 0)) != flags); + + return 1; +} +EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref); + +void gnttab_end_foreign_access(grant_ref_t ref, int readonly, + unsigned long page) +{ + if (gnttab_end_foreign_access_ref(ref, readonly)) { + put_free_entry(ref); + if (page != 0) + free_page(page); + } else { + /* XXX This needs to be fixed so that the ref and page are + placed on a list to be freed up later. */ + printk(KERN_WARNING + "WARNING: leaking g.e. and page still in use!\n"); + } +} +EXPORT_SYMBOL_GPL(gnttab_end_foreign_access); + +int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn) +{ + int ref; + + ref = get_free_entries(1); + if (unlikely(ref < 0)) + return -ENOSPC; + gnttab_grant_foreign_transfer_ref(ref, domid, pfn); + + return ref; +} +EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer); + +void gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid, + unsigned long pfn) +{ + update_grant_entry(ref, domid, pfn, GTF_accept_transfer); +} +EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref); + +unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref) +{ + unsigned long frame; + u16 flags; + + /* + * If a transfer is not even yet started, try to reclaim the grant + * reference and return failure (== 0). + */ + while (!((flags = shared[ref].flags) & GTF_transfer_committed)) { + if (sync_cmpxchg(&shared[ref].flags, flags, 0) == flags) + return 0; + cpu_relax(); + } + + /* If a transfer is in progress then wait until it is completed. */ + while (!(flags & GTF_transfer_completed)) { + flags = shared[ref].flags; + cpu_relax(); + } + + rmb(); /* Read the frame number /after/ reading completion status. */ + frame = shared[ref].frame; + BUG_ON(frame == 0); + + return frame; +} +EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref); + +unsigned long gnttab_end_foreign_transfer(grant_ref_t ref) +{ + unsigned long frame = gnttab_end_foreign_transfer_ref(ref); + put_free_entry(ref); + return frame; +} +EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer); + +void gnttab_free_grant_reference(grant_ref_t ref) +{ + put_free_entry(ref); +} +EXPORT_SYMBOL_GPL(gnttab_free_grant_reference); + +void gnttab_free_grant_references(grant_ref_t head) +{ + grant_ref_t ref; + unsigned long flags; + int count = 1; + if (head == GNTTAB_LIST_END) + return; + spin_lock_irqsave(&gnttab_list_lock, flags); + ref = head; + while (gnttab_entry(ref) != GNTTAB_LIST_END) { + ref = gnttab_entry(ref); + count++; + } + gnttab_entry(ref) = gnttab_free_head; + gnttab_free_head = head; + gnttab_free_count += count; + check_free_callbacks(); + spin_unlock_irqrestore(&gnttab_list_lock, flags); +} +EXPORT_SYMBOL_GPL(gnttab_free_grant_references); + +int gnttab_alloc_grant_references(u16 count, grant_ref_t *head) +{ + int h = get_free_entries(count); + + if (h < 0) + return -ENOSPC; + + *head = h; + + return 0; +} +EXPORT_SYMBOL_GPL(gnttab_alloc_grant_references); + +int gnttab_empty_grant_references(const grant_ref_t *private_head) +{ + return (*private_head == GNTTAB_LIST_END); +} +EXPORT_SYMBOL_GPL(gnttab_empty_grant_references); + +int gnttab_claim_grant_reference(grant_ref_t *private_head) +{ + grant_ref_t g = *private_head; + if (unlikely(g == GNTTAB_LIST_END)) + return -ENOSPC; + *private_head = gnttab_entry(g); + return g; +} +EXPORT_SYMBOL_GPL(gnttab_claim_grant_reference); + +void gnttab_release_grant_reference(grant_ref_t *private_head, + grant_ref_t release) +{ + gnttab_entry(release) = *private_head; + *private_head = release; +} +EXPORT_SYMBOL_GPL(gnttab_release_grant_reference); + +void gnttab_request_free_callback(struct gnttab_free_callback *callback, + void (*fn)(void *), void *arg, u16 count) +{ + unsigned long flags; + spin_lock_irqsave(&gnttab_list_lock, flags); + if (callback->next) + goto out; + callback->fn = fn; + callback->arg = arg; + callback->count = count; + callback->next = gnttab_free_callback_list; + gnttab_free_callback_list = callback; + check_free_callbacks(); +out: + spin_unlock_irqrestore(&gnttab_list_lock, flags); +} +EXPORT_SYMBOL_GPL(gnttab_request_free_callback); + +void gnttab_cancel_free_callback(struct gnttab_free_callback *callback) +{ + struct gnttab_free_callback **pcb; + unsigned long flags; + + spin_lock_irqsave(&gnttab_list_lock, flags); + for (pcb = &gnttab_free_callback_list; *pcb; pcb = &(*pcb)->next) { + if (*pcb == callback) { + *pcb = callback->next; + break; + } + } + spin_unlock_irqrestore(&gnttab_list_lock, flags); +} +EXPORT_SYMBOL_GPL(gnttab_cancel_free_callback); + +static int grow_gnttab_list(unsigned int more_frames) +{ + unsigned int new_nr_grant_frames, extra_entries, i; + + new_nr_grant_frames = nr_grant_frames + more_frames; + extra_entries = more_frames * GREFS_PER_GRANT_FRAME; + + for (i = nr_grant_frames; i < new_nr_grant_frames; i++) { + gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_ATOMIC); + if (!gnttab_list[i]) + goto grow_nomem; + } + + + for (i = GREFS_PER_GRANT_FRAME * nr_grant_frames; + i < GREFS_PER_GRANT_FRAME * new_nr_grant_frames - 1; i++) + gnttab_entry(i) = i + 1; + + gnttab_entry(i) = gnttab_free_head; + gnttab_free_head = GREFS_PER_GRANT_FRAME * nr_grant_frames; + gnttab_free_count += extra_entries; + + nr_grant_frames = new_nr_grant_frames; + + check_free_callbacks(); + + return 0; + +grow_nomem: + for ( ; i >= nr_grant_frames; i--) + free_page((unsigned long) gnttab_list[i]); + return -ENOMEM; +} + +static unsigned int __max_nr_grant_frames(void) +{ + struct gnttab_query_size query; + int rc; + + query.dom = DOMID_SELF; + + rc = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &query, 1); + if ((rc < 0) || (query.status != GNTST_okay)) + return 4; /* Legacy max supported number of frames */ + + return query.max_nr_frames; +} + +static inline unsigned int max_nr_grant_frames(void) +{ + unsigned int xen_max = __max_nr_grant_frames(); + + if (xen_max > boot_max_nr_grant_frames) + return boot_max_nr_grant_frames; + return xen_max; +} + +static int map_pte_fn(pte_t *pte, struct page *pmd_page, + unsigned long addr, void *data) +{ + unsigned long **frames = (unsigned long **)data; + + set_pte_at(&init_mm, addr, pte, mfn_pte((*frames)[0], PAGE_KERNEL)); + (*frames)++; + return 0; +} + +static int unmap_pte_fn(pte_t *pte, struct page *pmd_page, + unsigned long addr, void *data) +{ + + set_pte_at(&init_mm, addr, pte, __pte(0)); + return 0; +} + +static int gnttab_map(unsigned int start_idx, unsigned int end_idx) +{ + struct gnttab_setup_table setup; + unsigned long *frames; + unsigned int nr_gframes = end_idx + 1; + int rc; + + frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC); + if (!frames) + return -ENOMEM; + + setup.dom = DOMID_SELF; + setup.nr_frames = nr_gframes; + setup.frame_list = frames; + + rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1); + if (rc == -ENOSYS) { + kfree(frames); + return -ENOSYS; + } + + BUG_ON(rc || setup.status); + + if (shared == NULL) { + struct vm_struct *area; + area = alloc_vm_area(PAGE_SIZE * max_nr_grant_frames()); + BUG_ON(area == NULL); + shared = area->addr; + } + rc = apply_to_page_range(&init_mm, (unsigned long)shared, + PAGE_SIZE * nr_gframes, + map_pte_fn, &frames); + BUG_ON(rc); + frames -= nr_gframes; /* adjust after map_pte_fn() */ + + kfree(frames); + + return 0; +} + +static int gnttab_resume(void) +{ + if (max_nr_grant_frames() < nr_grant_frames) + return -ENOSYS; + return gnttab_map(0, nr_grant_frames - 1); +} + +static int gnttab_suspend(void) +{ + apply_to_page_range(&init_mm, (unsigned long)shared, + PAGE_SIZE * nr_grant_frames, + unmap_pte_fn, NULL); + + return 0; +} + +static int gnttab_expand(unsigned int req_entries) +{ + int rc; + unsigned int cur, extra; + + cur = nr_grant_frames; + extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) / + GREFS_PER_GRANT_FRAME); + if (cur + extra > max_nr_grant_frames()) + return -ENOSPC; + + rc = gnttab_map(cur, cur + extra - 1); + if (rc == 0) + rc = grow_gnttab_list(extra); + + return rc; +} + +static int __devinit gnttab_init(void) +{ + int i; + unsigned int max_nr_glist_frames; + unsigned int nr_init_grefs; + + if (!is_running_on_xen()) + return -ENODEV; + + nr_grant_frames = 1; + boot_max_nr_grant_frames = __max_nr_grant_frames(); + + /* Determine the maximum number of frames required for the + * grant reference free list on the current hypervisor. + */ + max_nr_glist_frames = (boot_max_nr_grant_frames * + GREFS_PER_GRANT_FRAME / + (PAGE_SIZE / sizeof(grant_ref_t))); + + gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *), + GFP_KERNEL); + if (gnttab_list == NULL) + return -ENOMEM; + + for (i = 0; i < nr_grant_frames; i++) { + gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_KERNEL); + if (gnttab_list[i] == NULL) + goto ini_nomem; + } + + if (gnttab_resume() < 0) + return -ENODEV; + + nr_init_grefs = nr_grant_frames * GREFS_PER_GRANT_FRAME; + + for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++) + gnttab_entry(i) = i + 1; + + gnttab_entry(nr_init_grefs - 1) = GNTTAB_LIST_END; + gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES; + gnttab_free_head = NR_RESERVED_ENTRIES; + + printk("Grant table initialized\n"); + return 0; + + ini_nomem: + for (i--; i >= 0; i--) + free_page((unsigned long)gnttab_list[i]); + kfree(gnttab_list); + return -ENOMEM; +} + +core_initcall(gnttab_init); diff --git a/drivers/xen/xenbus/Makefile b/drivers/xen/xenbus/Makefile new file mode 100644 index 000000000000..5571f5b84223 --- /dev/null +++ b/drivers/xen/xenbus/Makefile @@ -0,0 +1,7 @@ +obj-y += xenbus.o + +xenbus-objs = +xenbus-objs += xenbus_client.o +xenbus-objs += xenbus_comms.o +xenbus-objs += xenbus_xs.o +xenbus-objs += xenbus_probe.o diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c new file mode 100644 index 000000000000..9fd2f70ab46d --- /dev/null +++ b/drivers/xen/xenbus/xenbus_client.c @@ -0,0 +1,569 @@ +/****************************************************************************** + * Client-facing interface for the Xenbus driver. In other words, the + * interface between the Xenbus and the device-specific code, be it the + * frontend or the backend of that driver. + * + * Copyright (C) 2005 XenSource Ltd + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include <linux/types.h> +#include <linux/vmalloc.h> +#include <asm/xen/hypervisor.h> +#include <xen/interface/xen.h> +#include <xen/interface/event_channel.h> +#include <xen/events.h> +#include <xen/grant_table.h> +#include <xen/xenbus.h> + +const char *xenbus_strstate(enum xenbus_state state) +{ + static const char *const name[] = { + [ XenbusStateUnknown ] = "Unknown", + [ XenbusStateInitialising ] = "Initialising", + [ XenbusStateInitWait ] = "InitWait", + [ XenbusStateInitialised ] = "Initialised", + [ XenbusStateConnected ] = "Connected", + [ XenbusStateClosing ] = "Closing", + [ XenbusStateClosed ] = "Closed", + }; + return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID"; +} +EXPORT_SYMBOL_GPL(xenbus_strstate); + +/** + * xenbus_watch_path - register a watch + * @dev: xenbus device + * @path: path to watch + * @watch: watch to register + * @callback: callback to register + * + * Register a @watch on the given path, using the given xenbus_watch structure + * for storage, and the given @callback function as the callback. Return 0 on + * success, or -errno on error. On success, the given @path will be saved as + * @watch->node, and remains the caller's to free. On error, @watch->node will + * be NULL, the device will switch to %XenbusStateClosing, and the error will + * be saved in the store. + */ +int xenbus_watch_path(struct xenbus_device *dev, const char *path, + struct xenbus_watch *watch, + void (*callback)(struct xenbus_watch *, + const char **, unsigned int)) +{ + int err; + + watch->node = path; + watch->callback = callback; + + err = register_xenbus_watch(watch); + + if (err) { + watch->node = NULL; + watch->callback = NULL; + xenbus_dev_fatal(dev, err, "adding watch on %s", path); + } + + return err; +} +EXPORT_SYMBOL_GPL(xenbus_watch_path); + + +/** + * xenbus_watch_pathfmt - register a watch on a sprintf-formatted path + * @dev: xenbus device + * @watch: watch to register + * @callback: callback to register + * @pathfmt: format of path to watch + * + * Register a watch on the given @path, using the given xenbus_watch + * structure for storage, and the given @callback function as the callback. + * Return 0 on success, or -errno on error. On success, the watched path + * (@path/@path2) will be saved as @watch->node, and becomes the caller's to + * kfree(). On error, watch->node will be NULL, so the caller has nothing to + * free, the device will switch to %XenbusStateClosing, and the error will be + * saved in the store. + */ +int xenbus_watch_pathfmt(struct xenbus_device *dev, + struct xenbus_watch *watch, + void (*callback)(struct xenbus_watch *, + const char **, unsigned int), + const char *pathfmt, ...) +{ + int err; + va_list ap; + char *path; + + va_start(ap, pathfmt); + path = kvasprintf(GFP_KERNEL, pathfmt, ap); + va_end(ap); + + if (!path) { + xenbus_dev_fatal(dev, -ENOMEM, "allocating path for watch"); + return -ENOMEM; + } + err = xenbus_watch_path(dev, path, watch, callback); + + if (err) + kfree(path); + return err; +} +EXPORT_SYMBOL_GPL(xenbus_watch_pathfmt); + + +/** + * xenbus_switch_state + * @dev: xenbus device + * @xbt: transaction handle + * @state: new state + * + * Advertise in the store a change of the given driver to the given new_state. + * Return 0 on success, or -errno on error. On error, the device will switch + * to XenbusStateClosing, and the error will be saved in the store. + */ +int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state state) +{ + /* We check whether the state is currently set to the given value, and + if not, then the state is set. We don't want to unconditionally + write the given state, because we don't want to fire watches + unnecessarily. Furthermore, if the node has gone, we don't write + to it, as the device will be tearing down, and we don't want to + resurrect that directory. + + Note that, because of this cached value of our state, this function + will not work inside a Xenstore transaction (something it was + trying to in the past) because dev->state would not get reset if + the transaction was aborted. + + */ + + int current_state; + int err; + + if (state == dev->state) + return 0; + + err = xenbus_scanf(XBT_NIL, dev->nodename, "state", "%d", + ¤t_state); + if (err != 1) + return 0; + + err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%d", state); + if (err) { + if (state != XenbusStateClosing) /* Avoid looping */ + xenbus_dev_fatal(dev, err, "writing new state"); + return err; + } + + dev->state = state; + + return 0; +} +EXPORT_SYMBOL_GPL(xenbus_switch_state); + +int xenbus_frontend_closed(struct xenbus_device *dev) +{ + xenbus_switch_state(dev, XenbusStateClosed); + complete(&dev->down); + return 0; +} +EXPORT_SYMBOL_GPL(xenbus_frontend_closed); + +/** + * Return the path to the error node for the given device, or NULL on failure. + * If the value returned is non-NULL, then it is the caller's to kfree. + */ +static char *error_path(struct xenbus_device *dev) +{ + return kasprintf(GFP_KERNEL, "error/%s", dev->nodename); +} + + +static void xenbus_va_dev_error(struct xenbus_device *dev, int err, + const char *fmt, va_list ap) +{ + int ret; + unsigned int len; + char *printf_buffer = NULL; + char *path_buffer = NULL; + +#define PRINTF_BUFFER_SIZE 4096 + printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL); + if (printf_buffer == NULL) + goto fail; + + len = sprintf(printf_buffer, "%i ", -err); + ret = vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap); + + BUG_ON(len + ret > PRINTF_BUFFER_SIZE-1); + + dev_err(&dev->dev, "%s\n", printf_buffer); + + path_buffer = error_path(dev); + + if (path_buffer == NULL) { + dev_err(&dev->dev, "failed to write error node for %s (%s)\n", + dev->nodename, printf_buffer); + goto fail; + } + + if (xenbus_write(XBT_NIL, path_buffer, "error", printf_buffer) != 0) { + dev_err(&dev->dev, "failed to write error node for %s (%s)\n", + dev->nodename, printf_buffer); + goto fail; + } + +fail: + kfree(printf_buffer); + kfree(path_buffer); +} + + +/** + * xenbus_dev_error + * @dev: xenbus device + * @err: error to report + * @fmt: error message format + * + * Report the given negative errno into the store, along with the given + * formatted message. + */ +void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + xenbus_va_dev_error(dev, err, fmt, ap); + va_end(ap); +} +EXPORT_SYMBOL_GPL(xenbus_dev_error); + +/** + * xenbus_dev_fatal + * @dev: xenbus device + * @err: error to report + * @fmt: error message format + * + * Equivalent to xenbus_dev_error(dev, err, fmt, args), followed by + * xenbus_switch_state(dev, NULL, XenbusStateClosing) to schedule an orderly + * closedown of this driver and its peer. + */ + +void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + xenbus_va_dev_error(dev, err, fmt, ap); + va_end(ap); + + xenbus_switch_state(dev, XenbusStateClosing); +} +EXPORT_SYMBOL_GPL(xenbus_dev_fatal); + +/** + * xenbus_grant_ring + * @dev: xenbus device + * @ring_mfn: mfn of ring to grant + + * Grant access to the given @ring_mfn to the peer of the given device. Return + * 0 on success, or -errno on error. On error, the device will switch to + * XenbusStateClosing, and the error will be saved in the store. + */ +int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn) +{ + int err = gnttab_grant_foreign_access(dev->otherend_id, ring_mfn, 0); + if (err < 0) + xenbus_dev_fatal(dev, err, "granting access to ring page"); + return err; +} +EXPORT_SYMBOL_GPL(xenbus_grant_ring); + + +/** + * Allocate an event channel for the given xenbus_device, assigning the newly + * created local port to *port. Return 0 on success, or -errno on error. On + * error, the device will switch to XenbusStateClosing, and the error will be + * saved in the store. + */ +int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port) +{ + struct evtchn_alloc_unbound alloc_unbound; + int err; + + alloc_unbound.dom = DOMID_SELF; + alloc_unbound.remote_dom = dev->otherend_id; + + err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, + &alloc_unbound); + if (err) + xenbus_dev_fatal(dev, err, "allocating event channel"); + else + *port = alloc_unbound.port; + + return err; +} +EXPORT_SYMBOL_GPL(xenbus_alloc_evtchn); + + +/** + * Bind to an existing interdomain event channel in another domain. Returns 0 + * on success and stores the local port in *port. On error, returns -errno, + * switches the device to XenbusStateClosing, and saves the error in XenStore. + */ +int xenbus_bind_evtchn(struct xenbus_device *dev, int remote_port, int *port) +{ + struct evtchn_bind_interdomain bind_interdomain; + int err; + + bind_interdomain.remote_dom = dev->otherend_id; + bind_interdomain.remote_port = remote_port; + + err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain, + &bind_interdomain); + if (err) + xenbus_dev_fatal(dev, err, + "binding to event channel %d from domain %d", + remote_port, dev->otherend_id); + else + *port = bind_interdomain.local_port; + + return err; +} +EXPORT_SYMBOL_GPL(xenbus_bind_evtchn); + + +/** + * Free an existing event channel. Returns 0 on success or -errno on error. + */ +int xenbus_free_evtchn(struct xenbus_device *dev, int port) +{ + struct evtchn_close close; + int err; + + close.port = port; + + err = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close); + if (err) + xenbus_dev_error(dev, err, "freeing event channel %d", port); + + return err; +} +EXPORT_SYMBOL_GPL(xenbus_free_evtchn); + + +/** + * xenbus_map_ring_valloc + * @dev: xenbus device + * @gnt_ref: grant reference + * @vaddr: pointer to address to be filled out by mapping + * + * Based on Rusty Russell's skeleton driver's map_page. + * Map a page of memory into this domain from another domain's grant table. + * xenbus_map_ring_valloc allocates a page of virtual address space, maps the + * page to that address, and sets *vaddr to that address. + * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h) + * or -ENOMEM on error. If an error is returned, device will switch to + * XenbusStateClosing and the error message will be saved in XenStore. + */ +int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr) +{ + struct gnttab_map_grant_ref op = { + .flags = GNTMAP_host_map, + .ref = gnt_ref, + .dom = dev->otherend_id, + }; + struct vm_struct *area; + + *vaddr = NULL; + + area = alloc_vm_area(PAGE_SIZE); + if (!area) + return -ENOMEM; + + op.host_addr = (unsigned long)area->addr; + + if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) + BUG(); + + if (op.status != GNTST_okay) { + free_vm_area(area); + xenbus_dev_fatal(dev, op.status, + "mapping in shared page %d from domain %d", + gnt_ref, dev->otherend_id); + return op.status; + } + + /* Stuff the handle in an unused field */ + area->phys_addr = (unsigned long)op.handle; + + *vaddr = area->addr; + return 0; +} +EXPORT_SYMBOL_GPL(xenbus_map_ring_valloc); + + +/** + * xenbus_map_ring + * @dev: xenbus device + * @gnt_ref: grant reference + * @handle: pointer to grant handle to be filled + * @vaddr: address to be mapped to + * + * Map a page of memory into this domain from another domain's grant table. + * xenbus_map_ring does not allocate the virtual address space (you must do + * this yourself!). It only maps in the page to the specified address. + * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h) + * or -ENOMEM on error. If an error is returned, device will switch to + * XenbusStateClosing and the error message will be saved in XenStore. + */ +int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref, + grant_handle_t *handle, void *vaddr) +{ + struct gnttab_map_grant_ref op = { + .host_addr = (unsigned long)vaddr, + .flags = GNTMAP_host_map, + .ref = gnt_ref, + .dom = dev->otherend_id, + }; + + if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) + BUG(); + + if (op.status != GNTST_okay) { + xenbus_dev_fatal(dev, op.status, + "mapping in shared page %d from domain %d", + gnt_ref, dev->otherend_id); + } else + *handle = op.handle; + + return op.status; +} +EXPORT_SYMBOL_GPL(xenbus_map_ring); + + +/** + * xenbus_unmap_ring_vfree + * @dev: xenbus device + * @vaddr: addr to unmap + * + * Based on Rusty Russell's skeleton driver's unmap_page. + * Unmap a page of memory in this domain that was imported from another domain. + * Use xenbus_unmap_ring_vfree if you mapped in your memory with + * xenbus_map_ring_valloc (it will free the virtual address space). + * Returns 0 on success and returns GNTST_* on error + * (see xen/include/interface/grant_table.h). + */ +int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr) +{ + struct vm_struct *area; + struct gnttab_unmap_grant_ref op = { + .host_addr = (unsigned long)vaddr, + }; + + /* It'd be nice if linux/vmalloc.h provided a find_vm_area(void *addr) + * method so that we don't have to muck with vmalloc internals here. + * We could force the user to hang on to their struct vm_struct from + * xenbus_map_ring_valloc, but these 6 lines considerably simplify + * this API. + */ + read_lock(&vmlist_lock); + for (area = vmlist; area != NULL; area = area->next) { + if (area->addr == vaddr) + break; + } + read_unlock(&vmlist_lock); + + if (!area) { + xenbus_dev_error(dev, -ENOENT, + "can't find mapped virtual address %p", vaddr); + return GNTST_bad_virt_addr; + } + + op.handle = (grant_handle_t)area->phys_addr; + + if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) + BUG(); + + if (op.status == GNTST_okay) + free_vm_area(area); + else + xenbus_dev_error(dev, op.status, + "unmapping page at handle %d error %d", + (int16_t)area->phys_addr, op.status); + + return op.status; +} +EXPORT_SYMBOL_GPL(xenbus_unmap_ring_vfree); + + +/** + * xenbus_unmap_ring + * @dev: xenbus device + * @handle: grant handle + * @vaddr: addr to unmap + * + * Unmap a page of memory in this domain that was imported from another domain. + * Returns 0 on success and returns GNTST_* on error + * (see xen/include/interface/grant_table.h). + */ +int xenbus_unmap_ring(struct xenbus_device *dev, + grant_handle_t handle, void *vaddr) +{ + struct gnttab_unmap_grant_ref op = { + .host_addr = (unsigned long)vaddr, + .handle = handle, + }; + + if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) + BUG(); + + if (op.status != GNTST_okay) + xenbus_dev_error(dev, op.status, + "unmapping page at handle %d error %d", + handle, op.status); + + return op.status; +} +EXPORT_SYMBOL_GPL(xenbus_unmap_ring); + + +/** + * xenbus_read_driver_state + * @path: path for driver + * + * Return the state of the driver rooted at the given store path, or + * XenbusStateUnknown if no state can be read. + */ +enum xenbus_state xenbus_read_driver_state(const char *path) +{ + enum xenbus_state result; + int err = xenbus_gather(XBT_NIL, path, "state", "%d", &result, NULL); + if (err) + result = XenbusStateUnknown; + + return result; +} +EXPORT_SYMBOL_GPL(xenbus_read_driver_state); diff --git a/drivers/xen/xenbus/xenbus_comms.c b/drivers/xen/xenbus/xenbus_comms.c new file mode 100644 index 000000000000..6efbe3f29ca5 --- /dev/null +++ b/drivers/xen/xenbus/xenbus_comms.c @@ -0,0 +1,233 @@ +/****************************************************************************** + * xenbus_comms.c + * + * Low level code to talks to Xen Store: ringbuffer and event channel. + * + * Copyright (C) 2005 Rusty Russell, IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include <linux/wait.h> +#include <linux/interrupt.h> +#include <linux/sched.h> +#include <linux/err.h> +#include <xen/xenbus.h> +#include <asm/xen/hypervisor.h> +#include <xen/events.h> +#include <xen/page.h> +#include "xenbus_comms.h" + +static int xenbus_irq; + +static DECLARE_WORK(probe_work, xenbus_probe); + +static DECLARE_WAIT_QUEUE_HEAD(xb_waitq); + +static irqreturn_t wake_waiting(int irq, void *unused) +{ + if (unlikely(xenstored_ready == 0)) { + xenstored_ready = 1; + schedule_work(&probe_work); + } + + wake_up(&xb_waitq); + return IRQ_HANDLED; +} + +static int check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod) +{ + return ((prod - cons) <= XENSTORE_RING_SIZE); +} + +static void *get_output_chunk(XENSTORE_RING_IDX cons, + XENSTORE_RING_IDX prod, + char *buf, uint32_t *len) +{ + *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod); + if ((XENSTORE_RING_SIZE - (prod - cons)) < *len) + *len = XENSTORE_RING_SIZE - (prod - cons); + return buf + MASK_XENSTORE_IDX(prod); +} + +static const void *get_input_chunk(XENSTORE_RING_IDX cons, + XENSTORE_RING_IDX prod, + const char *buf, uint32_t *len) +{ + *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons); + if ((prod - cons) < *len) + *len = prod - cons; + return buf + MASK_XENSTORE_IDX(cons); +} + +/** + * xb_write - low level write + * @data: buffer to send + * @len: length of buffer + * + * Returns 0 on success, error otherwise. + */ +int xb_write(const void *data, unsigned len) +{ + struct xenstore_domain_interface *intf = xen_store_interface; + XENSTORE_RING_IDX cons, prod; + int rc; + + while (len != 0) { + void *dst; + unsigned int avail; + + rc = wait_event_interruptible( + xb_waitq, + (intf->req_prod - intf->req_cons) != + XENSTORE_RING_SIZE); + if (rc < 0) + return rc; + + /* Read indexes, then verify. */ + cons = intf->req_cons; + prod = intf->req_prod; + if (!check_indexes(cons, prod)) { + intf->req_cons = intf->req_prod = 0; + return -EIO; + } + + dst = get_output_chunk(cons, prod, intf->req, &avail); + if (avail == 0) + continue; + if (avail > len) + avail = len; + + /* Must write data /after/ reading the consumer index. */ + mb(); + + memcpy(dst, data, avail); + data += avail; + len -= avail; + + /* Other side must not see new producer until data is there. */ + wmb(); + intf->req_prod += avail; + + /* Implies mb(): other side will see the updated producer. */ + notify_remote_via_evtchn(xen_store_evtchn); + } + + return 0; +} + +int xb_data_to_read(void) +{ + struct xenstore_domain_interface *intf = xen_store_interface; + return (intf->rsp_cons != intf->rsp_prod); +} + +int xb_wait_for_data_to_read(void) +{ + return wait_event_interruptible(xb_waitq, xb_data_to_read()); +} + +int xb_read(void *data, unsigned len) +{ + struct xenstore_domain_interface *intf = xen_store_interface; + XENSTORE_RING_IDX cons, prod; + int rc; + + while (len != 0) { + unsigned int avail; + const char *src; + + rc = xb_wait_for_data_to_read(); + if (rc < 0) + return rc; + + /* Read indexes, then verify. */ + cons = intf->rsp_cons; + prod = intf->rsp_prod; + if (!check_indexes(cons, prod)) { + intf->rsp_cons = intf->rsp_prod = 0; + return -EIO; + } + + src = get_input_chunk(cons, prod, intf->rsp, &avail); + if (avail == 0) + continue; + if (avail > len) + avail = len; + + /* Must read data /after/ reading the producer index. */ + rmb(); + + memcpy(data, src, avail); + data += avail; + len -= avail; + + /* Other side must not see free space until we've copied out */ + mb(); + intf->rsp_cons += avail; + + pr_debug("Finished read of %i bytes (%i to go)\n", avail, len); + + /* Implies mb(): other side will see the updated consumer. */ + notify_remote_via_evtchn(xen_store_evtchn); + } + + return 0; +} + +/** + * xb_init_comms - Set up interrupt handler off store event channel. + */ +int xb_init_comms(void) +{ + struct xenstore_domain_interface *intf = xen_store_interface; + int err; + + if (intf->req_prod != intf->req_cons) + printk(KERN_ERR "XENBUS request ring is not quiescent " + "(%08x:%08x)!\n", intf->req_cons, intf->req_prod); + + if (intf->rsp_prod != intf->rsp_cons) { + printk(KERN_WARNING "XENBUS response ring is not quiescent " + "(%08x:%08x): fixing up\n", + intf->rsp_cons, intf->rsp_prod); + intf->rsp_cons = intf->rsp_prod; + } + + if (xenbus_irq) + unbind_from_irqhandler(xenbus_irq, &xb_waitq); + + err = bind_evtchn_to_irqhandler( + xen_store_evtchn, wake_waiting, + 0, "xenbus", &xb_waitq); + if (err <= 0) { + printk(KERN_ERR "XENBUS request irq failed %i\n", err); + return err; + } + + xenbus_irq = err; + + return 0; +} diff --git a/drivers/xen/xenbus/xenbus_comms.h b/drivers/xen/xenbus/xenbus_comms.h new file mode 100644 index 000000000000..c21db7513736 --- /dev/null +++ b/drivers/xen/xenbus/xenbus_comms.h @@ -0,0 +1,46 @@ +/* + * Private include for xenbus communications. + * + * Copyright (C) 2005 Rusty Russell, IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef _XENBUS_COMMS_H +#define _XENBUS_COMMS_H + +int xs_init(void); +int xb_init_comms(void); + +/* Low level routines. */ +int xb_write(const void *data, unsigned len); +int xb_read(void *data, unsigned len); +int xb_data_to_read(void); +int xb_wait_for_data_to_read(void); +int xs_input_avail(void); +extern struct xenstore_domain_interface *xen_store_interface; +extern int xen_store_evtchn; + +#endif /* _XENBUS_COMMS_H */ diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c new file mode 100644 index 000000000000..0b769f7c4a48 --- /dev/null +++ b/drivers/xen/xenbus/xenbus_probe.c @@ -0,0 +1,935 @@ +/****************************************************************************** + * Talks to Xen Store to figure out what devices we have. + * + * Copyright (C) 2005 Rusty Russell, IBM Corporation + * Copyright (C) 2005 Mike Wray, Hewlett-Packard + * Copyright (C) 2005, 2006 XenSource Ltd + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#define DPRINTK(fmt, args...) \ + pr_debug("xenbus_probe (%s:%d) " fmt ".\n", \ + __func__, __LINE__, ##args) + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/string.h> +#include <linux/ctype.h> +#include <linux/fcntl.h> +#include <linux/mm.h> +#include <linux/notifier.h> +#include <linux/kthread.h> +#include <linux/mutex.h> +#include <linux/io.h> + +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/xen/hypervisor.h> +#include <xen/xenbus.h> +#include <xen/events.h> +#include <xen/page.h> + +#include "xenbus_comms.h" +#include "xenbus_probe.h" + +int xen_store_evtchn; +struct xenstore_domain_interface *xen_store_interface; +static unsigned long xen_store_mfn; + +static BLOCKING_NOTIFIER_HEAD(xenstore_chain); + +static void wait_for_devices(struct xenbus_driver *xendrv); + +static int xenbus_probe_frontend(const char *type, const char *name); + +static void xenbus_dev_shutdown(struct device *_dev); + +/* If something in array of ids matches this device, return it. */ +static const struct xenbus_device_id * +match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev) +{ + for (; *arr->devicetype != '\0'; arr++) { + if (!strcmp(arr->devicetype, dev->devicetype)) + return arr; + } + return NULL; +} + +int xenbus_match(struct device *_dev, struct device_driver *_drv) +{ + struct xenbus_driver *drv = to_xenbus_driver(_drv); + + if (!drv->ids) + return 0; + + return match_device(drv->ids, to_xenbus_device(_dev)) != NULL; +} + +/* device/<type>/<id> => <type>-<id> */ +static int frontend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename) +{ + nodename = strchr(nodename, '/'); + if (!nodename || strlen(nodename + 1) >= BUS_ID_SIZE) { + printk(KERN_WARNING "XENBUS: bad frontend %s\n", nodename); + return -EINVAL; + } + + strlcpy(bus_id, nodename + 1, BUS_ID_SIZE); + if (!strchr(bus_id, '/')) { + printk(KERN_WARNING "XENBUS: bus_id %s no slash\n", bus_id); + return -EINVAL; + } + *strchr(bus_id, '/') = '-'; + return 0; +} + + +static void free_otherend_details(struct xenbus_device *dev) +{ + kfree(dev->otherend); + dev->otherend = NULL; +} + + +static void free_otherend_watch(struct xenbus_device *dev) +{ + if (dev->otherend_watch.node) { + unregister_xenbus_watch(&dev->otherend_watch); + kfree(dev->otherend_watch.node); + dev->otherend_watch.node = NULL; + } +} + + +int read_otherend_details(struct xenbus_device *xendev, + char *id_node, char *path_node) +{ + int err = xenbus_gather(XBT_NIL, xendev->nodename, + id_node, "%i", &xendev->otherend_id, + path_node, NULL, &xendev->otherend, + NULL); + if (err) { + xenbus_dev_fatal(xendev, err, + "reading other end details from %s", + xendev->nodename); + return err; + } + if (strlen(xendev->otherend) == 0 || + !xenbus_exists(XBT_NIL, xendev->otherend, "")) { + xenbus_dev_fatal(xendev, -ENOENT, + "unable to read other end from %s. " + "missing or inaccessible.", + xendev->nodename); + free_otherend_details(xendev); + return -ENOENT; + } + + return 0; +} + + +static int read_backend_details(struct xenbus_device *xendev) +{ + return read_otherend_details(xendev, "backend-id", "backend"); +} + + +/* Bus type for frontend drivers. */ +static struct xen_bus_type xenbus_frontend = { + .root = "device", + .levels = 2, /* device/type/<id> */ + .get_bus_id = frontend_bus_id, + .probe = xenbus_probe_frontend, + .bus = { + .name = "xen", + .match = xenbus_match, + .probe = xenbus_dev_probe, + .remove = xenbus_dev_remove, + .shutdown = xenbus_dev_shutdown, + }, +}; + +static void otherend_changed(struct xenbus_watch *watch, + const char **vec, unsigned int len) +{ + struct xenbus_device *dev = + container_of(watch, struct xenbus_device, otherend_watch); + struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver); + enum xenbus_state state; + + /* Protect us against watches firing on old details when the otherend + details change, say immediately after a resume. */ + if (!dev->otherend || + strncmp(dev->otherend, vec[XS_WATCH_PATH], + strlen(dev->otherend))) { + dev_dbg(&dev->dev, "Ignoring watch at %s", vec[XS_WATCH_PATH]); + return; + } + + state = xenbus_read_driver_state(dev->otherend); + + dev_dbg(&dev->dev, "state is %d, (%s), %s, %s", + state, xenbus_strstate(state), dev->otherend_watch.node, + vec[XS_WATCH_PATH]); + + /* + * Ignore xenbus transitions during shutdown. This prevents us doing + * work that can fail e.g., when the rootfs is gone. + */ + if (system_state > SYSTEM_RUNNING) { + struct xen_bus_type *bus = bus; + bus = container_of(dev->dev.bus, struct xen_bus_type, bus); + /* If we're frontend, drive the state machine to Closed. */ + /* This should cause the backend to release our resources. */ + if ((bus == &xenbus_frontend) && (state == XenbusStateClosing)) + xenbus_frontend_closed(dev); + return; + } + + if (drv->otherend_changed) + drv->otherend_changed(dev, state); +} + + +static int talk_to_otherend(struct xenbus_device *dev) +{ + struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver); + + free_otherend_watch(dev); + free_otherend_details(dev); + + return drv->read_otherend_details(dev); +} + + +static int watch_otherend(struct xenbus_device *dev) +{ + return xenbus_watch_pathfmt(dev, &dev->otherend_watch, otherend_changed, + "%s/%s", dev->otherend, "state"); +} + + +int xenbus_dev_probe(struct device *_dev) +{ + struct xenbus_device *dev = to_xenbus_device(_dev); + struct xenbus_driver *drv = to_xenbus_driver(_dev->driver); + const struct xenbus_device_id *id; + int err; + + DPRINTK("%s", dev->nodename); + + if (!drv->probe) { + err = -ENODEV; + goto fail; + } + + id = match_device(drv->ids, dev); + if (!id) { + err = -ENODEV; + goto fail; + } + + err = talk_to_otherend(dev); + if (err) { + dev_warn(&dev->dev, "talk_to_otherend on %s failed.\n", + dev->nodename); + return err; + } + + err = drv->probe(dev, id); + if (err) + goto fail; + + err = watch_otherend(dev); + if (err) { + dev_warn(&dev->dev, "watch_otherend on %s failed.\n", + dev->nodename); + return err; + } + + return 0; +fail: + xenbus_dev_error(dev, err, "xenbus_dev_probe on %s", dev->nodename); + xenbus_switch_state(dev, XenbusStateClosed); + return -ENODEV; +} + +int xenbus_dev_remove(struct device *_dev) +{ + struct xenbus_device *dev = to_xenbus_device(_dev); + struct xenbus_driver *drv = to_xenbus_driver(_dev->driver); + + DPRINTK("%s", dev->nodename); + + free_otherend_watch(dev); + free_otherend_details(dev); + + if (drv->remove) + drv->remove(dev); + + xenbus_switch_state(dev, XenbusStateClosed); + return 0; +} + +static void xenbus_dev_shutdown(struct device *_dev) +{ + struct xenbus_device *dev = to_xenbus_device(_dev); + unsigned long timeout = 5*HZ; + + DPRINTK("%s", dev->nodename); + + get_device(&dev->dev); + if (dev->state != XenbusStateConnected) { + printk(KERN_INFO "%s: %s: %s != Connected, skipping\n", __func__, + dev->nodename, xenbus_strstate(dev->state)); + goto out; + } + xenbus_switch_state(dev, XenbusStateClosing); + timeout = wait_for_completion_timeout(&dev->down, timeout); + if (!timeout) + printk(KERN_INFO "%s: %s timeout closing device\n", + __func__, dev->nodename); + out: + put_device(&dev->dev); +} + +int xenbus_register_driver_common(struct xenbus_driver *drv, + struct xen_bus_type *bus, + struct module *owner, + const char *mod_name) +{ + drv->driver.name = drv->name; + drv->driver.bus = &bus->bus; + drv->driver.owner = owner; + drv->driver.mod_name = mod_name; + + return driver_register(&drv->driver); +} + +int __xenbus_register_frontend(struct xenbus_driver *drv, + struct module *owner, const char *mod_name) +{ + int ret; + + drv->read_otherend_details = read_backend_details; + + ret = xenbus_register_driver_common(drv, &xenbus_frontend, + owner, mod_name); + if (ret) + return ret; + + /* If this driver is loaded as a module wait for devices to attach. */ + wait_for_devices(drv); + + return 0; +} +EXPORT_SYMBOL_GPL(__xenbus_register_frontend); + +void xenbus_unregister_driver(struct xenbus_driver *drv) +{ + driver_unregister(&drv->driver); +} +EXPORT_SYMBOL_GPL(xenbus_unregister_driver); + +struct xb_find_info +{ + struct xenbus_device *dev; + const char *nodename; +}; + +static int cmp_dev(struct device *dev, void *data) +{ + struct xenbus_device *xendev = to_xenbus_device(dev); + struct xb_find_info *info = data; + + if (!strcmp(xendev->nodename, info->nodename)) { + info->dev = xendev; + get_device(dev); + return 1; + } + return 0; +} + +struct xenbus_device *xenbus_device_find(const char *nodename, + struct bus_type *bus) +{ + struct xb_find_info info = { .dev = NULL, .nodename = nodename }; + + bus_for_each_dev(bus, NULL, &info, cmp_dev); + return info.dev; +} + +static int cleanup_dev(struct device *dev, void *data) +{ + struct xenbus_device *xendev = to_xenbus_device(dev); + struct xb_find_info *info = data; + int len = strlen(info->nodename); + + DPRINTK("%s", info->nodename); + + /* Match the info->nodename path, or any subdirectory of that path. */ + if (strncmp(xendev->nodename, info->nodename, len)) + return 0; + + /* If the node name is longer, ensure it really is a subdirectory. */ + if ((strlen(xendev->nodename) > len) && (xendev->nodename[len] != '/')) + return 0; + + info->dev = xendev; + get_device(dev); + return 1; +} + +static void xenbus_cleanup_devices(const char *path, struct bus_type *bus) +{ + struct xb_find_info info = { .nodename = path }; + + do { + info.dev = NULL; + bus_for_each_dev(bus, NULL, &info, cleanup_dev); + if (info.dev) { + device_unregister(&info.dev->dev); + put_device(&info.dev->dev); + } + } while (info.dev); +} + +static void xenbus_dev_release(struct device *dev) +{ + if (dev) + kfree(to_xenbus_device(dev)); +} + +static ssize_t xendev_show_nodename(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", to_xenbus_device(dev)->nodename); +} +DEVICE_ATTR(nodename, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_nodename, NULL); + +static ssize_t xendev_show_devtype(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", to_xenbus_device(dev)->devicetype); +} +DEVICE_ATTR(devtype, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_devtype, NULL); + + +int xenbus_probe_node(struct xen_bus_type *bus, + const char *type, + const char *nodename) +{ + int err; + struct xenbus_device *xendev; + size_t stringlen; + char *tmpstring; + + enum xenbus_state state = xenbus_read_driver_state(nodename); + + if (state != XenbusStateInitialising) { + /* Device is not new, so ignore it. This can happen if a + device is going away after switching to Closed. */ + return 0; + } + + stringlen = strlen(nodename) + 1 + strlen(type) + 1; + xendev = kzalloc(sizeof(*xendev) + stringlen, GFP_KERNEL); + if (!xendev) + return -ENOMEM; + + xendev->state = XenbusStateInitialising; + + /* Copy the strings into the extra space. */ + + tmpstring = (char *)(xendev + 1); + strcpy(tmpstring, nodename); + xendev->nodename = tmpstring; + + tmpstring += strlen(tmpstring) + 1; + strcpy(tmpstring, type); + xendev->devicetype = tmpstring; + init_completion(&xendev->down); + + xendev->dev.bus = &bus->bus; + xendev->dev.release = xenbus_dev_release; + + err = bus->get_bus_id(xendev->dev.bus_id, xendev->nodename); + if (err) + goto fail; + + /* Register with generic device framework. */ + err = device_register(&xendev->dev); + if (err) + goto fail; + + err = device_create_file(&xendev->dev, &dev_attr_nodename); + if (err) + goto fail_unregister; + + err = device_create_file(&xendev->dev, &dev_attr_devtype); + if (err) + goto fail_remove_file; + + return 0; +fail_remove_file: + device_remove_file(&xendev->dev, &dev_attr_nodename); +fail_unregister: + device_unregister(&xendev->dev); +fail: + kfree(xendev); + return err; +} + +/* device/<typename>/<name> */ +static int xenbus_probe_frontend(const char *type, const char *name) +{ + char *nodename; + int err; + + nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", + xenbus_frontend.root, type, name); + if (!nodename) + return -ENOMEM; + + DPRINTK("%s", nodename); + + err = xenbus_probe_node(&xenbus_frontend, type, nodename); + kfree(nodename); + return err; +} + +static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type) +{ + int err = 0; + char **dir; + unsigned int dir_n = 0; + int i; + + dir = xenbus_directory(XBT_NIL, bus->root, type, &dir_n); + if (IS_ERR(dir)) + return PTR_ERR(dir); + + for (i = 0; i < dir_n; i++) { + err = bus->probe(type, dir[i]); + if (err) + break; + } + kfree(dir); + return err; +} + +int xenbus_probe_devices(struct xen_bus_type *bus) +{ + int err = 0; + char **dir; + unsigned int i, dir_n; + + dir = xenbus_directory(XBT_NIL, bus->root, "", &dir_n); + if (IS_ERR(dir)) + return PTR_ERR(dir); + + for (i = 0; i < dir_n; i++) { + err = xenbus_probe_device_type(bus, dir[i]); + if (err) + break; + } + kfree(dir); + return err; +} + +static unsigned int char_count(const char *str, char c) +{ + unsigned int i, ret = 0; + + for (i = 0; str[i]; i++) + if (str[i] == c) + ret++; + return ret; +} + +static int strsep_len(const char *str, char c, unsigned int len) +{ + unsigned int i; + + for (i = 0; str[i]; i++) + if (str[i] == c) { + if (len == 0) + return i; + len--; + } + return (len == 0) ? i : -ERANGE; +} + +void xenbus_dev_changed(const char *node, struct xen_bus_type *bus) +{ + int exists, rootlen; + struct xenbus_device *dev; + char type[BUS_ID_SIZE]; + const char *p, *root; + + if (char_count(node, '/') < 2) + return; + + exists = xenbus_exists(XBT_NIL, node, ""); + if (!exists) { + xenbus_cleanup_devices(node, &bus->bus); + return; + } + + /* backend/<type>/... or device/<type>/... */ + p = strchr(node, '/') + 1; + snprintf(type, BUS_ID_SIZE, "%.*s", (int)strcspn(p, "/"), p); + type[BUS_ID_SIZE-1] = '\0'; + + rootlen = strsep_len(node, '/', bus->levels); + if (rootlen < 0) + return; + root = kasprintf(GFP_KERNEL, "%.*s", rootlen, node); + if (!root) + return; + + dev = xenbus_device_find(root, &bus->bus); + if (!dev) + xenbus_probe_node(bus, type, root); + else + put_device(&dev->dev); + + kfree(root); +} + +static void frontend_changed(struct xenbus_watch *watch, + const char **vec, unsigned int len) +{ + DPRINTK(""); + + xenbus_dev_changed(vec[XS_WATCH_PATH], &xenbus_frontend); +} + +/* We watch for devices appearing and vanishing. */ +static struct xenbus_watch fe_watch = { + .node = "device", + .callback = frontend_changed, +}; + +static int suspend_dev(struct device *dev, void *data) +{ + int err = 0; + struct xenbus_driver *drv; + struct xenbus_device *xdev; + + DPRINTK(""); + + if (dev->driver == NULL) + return 0; + drv = to_xenbus_driver(dev->driver); + xdev = container_of(dev, struct xenbus_device, dev); + if (drv->suspend) + err = drv->suspend(xdev); + if (err) + printk(KERN_WARNING + "xenbus: suspend %s failed: %i\n", dev->bus_id, err); + return 0; +} + +static int suspend_cancel_dev(struct device *dev, void *data) +{ + int err = 0; + struct xenbus_driver *drv; + struct xenbus_device *xdev; + + DPRINTK(""); + + if (dev->driver == NULL) + return 0; + drv = to_xenbus_driver(dev->driver); + xdev = container_of(dev, struct xenbus_device, dev); + if (drv->suspend_cancel) + err = drv->suspend_cancel(xdev); + if (err) + printk(KERN_WARNING + "xenbus: suspend_cancel %s failed: %i\n", + dev->bus_id, err); + return 0; +} + +static int resume_dev(struct device *dev, void *data) +{ + int err; + struct xenbus_driver *drv; + struct xenbus_device *xdev; + + DPRINTK(""); + + if (dev->driver == NULL) + return 0; + + drv = to_xenbus_driver(dev->driver); + xdev = container_of(dev, struct xenbus_device, dev); + + err = talk_to_otherend(xdev); + if (err) { + printk(KERN_WARNING + "xenbus: resume (talk_to_otherend) %s failed: %i\n", + dev->bus_id, err); + return err; + } + + xdev->state = XenbusStateInitialising; + + if (drv->resume) { + err = drv->resume(xdev); + if (err) { + printk(KERN_WARNING + "xenbus: resume %s failed: %i\n", + dev->bus_id, err); + return err; + } + } + + err = watch_otherend(xdev); + if (err) { + printk(KERN_WARNING + "xenbus_probe: resume (watch_otherend) %s failed: " + "%d.\n", dev->bus_id, err); + return err; + } + + return 0; +} + +void xenbus_suspend(void) +{ + DPRINTK(""); + + bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev); + xenbus_backend_suspend(suspend_dev); + xs_suspend(); +} +EXPORT_SYMBOL_GPL(xenbus_suspend); + +void xenbus_resume(void) +{ + xb_init_comms(); + xs_resume(); + bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev); + xenbus_backend_resume(resume_dev); +} +EXPORT_SYMBOL_GPL(xenbus_resume); + +void xenbus_suspend_cancel(void) +{ + xs_suspend_cancel(); + bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_cancel_dev); + xenbus_backend_resume(suspend_cancel_dev); +} +EXPORT_SYMBOL_GPL(xenbus_suspend_cancel); + +/* A flag to determine if xenstored is 'ready' (i.e. has started) */ +int xenstored_ready = 0; + + +int register_xenstore_notifier(struct notifier_block *nb) +{ + int ret = 0; + + if (xenstored_ready > 0) + ret = nb->notifier_call(nb, 0, NULL); + else + blocking_notifier_chain_register(&xenstore_chain, nb); + + return ret; +} +EXPORT_SYMBOL_GPL(register_xenstore_notifier); + +void unregister_xenstore_notifier(struct notifier_block *nb) +{ + blocking_notifier_chain_unregister(&xenstore_chain, nb); +} +EXPORT_SYMBOL_GPL(unregister_xenstore_notifier); + +void xenbus_probe(struct work_struct *unused) +{ + BUG_ON((xenstored_ready <= 0)); + + /* Enumerate devices in xenstore and watch for changes. */ + xenbus_probe_devices(&xenbus_frontend); + register_xenbus_watch(&fe_watch); + xenbus_backend_probe_and_watch(); + + /* Notify others that xenstore is up */ + blocking_notifier_call_chain(&xenstore_chain, 0, NULL); +} + +static int __init xenbus_probe_init(void) +{ + int err = 0; + + DPRINTK(""); + + err = -ENODEV; + if (!is_running_on_xen()) + goto out_error; + + /* Register ourselves with the kernel bus subsystem */ + err = bus_register(&xenbus_frontend.bus); + if (err) + goto out_error; + + err = xenbus_backend_bus_register(); + if (err) + goto out_unreg_front; + + /* + * Domain0 doesn't have a store_evtchn or store_mfn yet. + */ + if (is_initial_xendomain()) { + /* dom0 not yet supported */ + } else { + xenstored_ready = 1; + xen_store_evtchn = xen_start_info->store_evtchn; + xen_store_mfn = xen_start_info->store_mfn; + } + xen_store_interface = mfn_to_virt(xen_store_mfn); + + /* Initialize the interface to xenstore. */ + err = xs_init(); + if (err) { + printk(KERN_WARNING + "XENBUS: Error initializing xenstore comms: %i\n", err); + goto out_unreg_back; + } + + if (!is_initial_xendomain()) + xenbus_probe(NULL); + + return 0; + + out_unreg_back: + xenbus_backend_bus_unregister(); + + out_unreg_front: + bus_unregister(&xenbus_frontend.bus); + + out_error: + return err; +} + +postcore_initcall(xenbus_probe_init); + +MODULE_LICENSE("GPL"); + +static int is_disconnected_device(struct device *dev, void *data) +{ + struct xenbus_device *xendev = to_xenbus_device(dev); + struct device_driver *drv = data; + + /* + * A device with no driver will never connect. We care only about + * devices which should currently be in the process of connecting. + */ + if (!dev->driver) + return 0; + + /* Is this search limited to a particular driver? */ + if (drv && (dev->driver != drv)) + return 0; + + return (xendev->state != XenbusStateConnected); +} + +static int exists_disconnected_device(struct device_driver *drv) +{ + return bus_for_each_dev(&xenbus_frontend.bus, NULL, drv, + is_disconnected_device); +} + +static int print_device_status(struct device *dev, void *data) +{ + struct xenbus_device *xendev = to_xenbus_device(dev); + struct device_driver *drv = data; + + /* Is this operation limited to a particular driver? */ + if (drv && (dev->driver != drv)) + return 0; + + if (!dev->driver) { + /* Information only: is this too noisy? */ + printk(KERN_INFO "XENBUS: Device with no driver: %s\n", + xendev->nodename); + } else if (xendev->state != XenbusStateConnected) { + printk(KERN_WARNING "XENBUS: Timeout connecting " + "to device: %s (state %d)\n", + xendev->nodename, xendev->state); + } + + return 0; +} + +/* We only wait for device setup after most initcalls have run. */ +static int ready_to_wait_for_devices; + +/* + * On a 10 second timeout, wait for all devices currently configured. We need + * to do this to guarantee that the filesystems and / or network devices + * needed for boot are available, before we can allow the boot to proceed. + * + * This needs to be on a late_initcall, to happen after the frontend device + * drivers have been initialised, but before the root fs is mounted. + * + * A possible improvement here would be to have the tools add a per-device + * flag to the store entry, indicating whether it is needed at boot time. + * This would allow people who knew what they were doing to accelerate their + * boot slightly, but of course needs tools or manual intervention to set up + * those flags correctly. + */ +static void wait_for_devices(struct xenbus_driver *xendrv) +{ + unsigned long timeout = jiffies + 10*HZ; + struct device_driver *drv = xendrv ? &xendrv->driver : NULL; + + if (!ready_to_wait_for_devices || !is_running_on_xen()) + return; + + while (exists_disconnected_device(drv)) { + if (time_after(jiffies, timeout)) + break; + schedule_timeout_interruptible(HZ/10); + } + + bus_for_each_dev(&xenbus_frontend.bus, NULL, drv, + print_device_status); +} + +#ifndef MODULE +static int __init boot_wait_for_devices(void) +{ + ready_to_wait_for_devices = 1; + wait_for_devices(NULL); + return 0; +} + +late_initcall(boot_wait_for_devices); +#endif diff --git a/drivers/xen/xenbus/xenbus_probe.h b/drivers/xen/xenbus/xenbus_probe.h new file mode 100644 index 000000000000..e09b19415a40 --- /dev/null +++ b/drivers/xen/xenbus/xenbus_probe.h @@ -0,0 +1,74 @@ +/****************************************************************************** + * xenbus_probe.h + * + * Talks to Xen Store to figure out what devices we have. + * + * Copyright (C) 2005 Rusty Russell, IBM Corporation + * Copyright (C) 2005 XenSource Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef _XENBUS_PROBE_H +#define _XENBUS_PROBE_H + +#ifdef CONFIG_XEN_BACKEND +extern void xenbus_backend_suspend(int (*fn)(struct device *, void *)); +extern void xenbus_backend_resume(int (*fn)(struct device *, void *)); +extern void xenbus_backend_probe_and_watch(void); +extern int xenbus_backend_bus_register(void); +extern void xenbus_backend_bus_unregister(void); +#else +static inline void xenbus_backend_suspend(int (*fn)(struct device *, void *)) {} +static inline void xenbus_backend_resume(int (*fn)(struct device *, void *)) {} +static inline void xenbus_backend_probe_and_watch(void) {} +static inline int xenbus_backend_bus_register(void) { return 0; } +static inline void xenbus_backend_bus_unregister(void) {} +#endif + +struct xen_bus_type +{ + char *root; + unsigned int levels; + int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename); + int (*probe)(const char *type, const char *dir); + struct bus_type bus; +}; + +extern int xenbus_match(struct device *_dev, struct device_driver *_drv); +extern int xenbus_dev_probe(struct device *_dev); +extern int xenbus_dev_remove(struct device *_dev); +extern int xenbus_register_driver_common(struct xenbus_driver *drv, + struct xen_bus_type *bus, + struct module *owner, + const char *mod_name); +extern int xenbus_probe_node(struct xen_bus_type *bus, + const char *type, + const char *nodename); +extern int xenbus_probe_devices(struct xen_bus_type *bus); + +extern void xenbus_dev_changed(const char *node, struct xen_bus_type *bus); + +#endif diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c new file mode 100644 index 000000000000..9e943fbce81b --- /dev/null +++ b/drivers/xen/xenbus/xenbus_xs.c @@ -0,0 +1,861 @@ +/****************************************************************************** + * xenbus_xs.c + * + * This is the kernel equivalent of the "xs" library. We don't need everything + * and we use xenbus_comms for communication. + * + * Copyright (C) 2005 Rusty Russell, IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include <linux/unistd.h> +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/uio.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/fcntl.h> +#include <linux/kthread.h> +#include <linux/rwsem.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <xen/xenbus.h> +#include "xenbus_comms.h" + +struct xs_stored_msg { + struct list_head list; + + struct xsd_sockmsg hdr; + + union { + /* Queued replies. */ + struct { + char *body; + } reply; + + /* Queued watch events. */ + struct { + struct xenbus_watch *handle; + char **vec; + unsigned int vec_size; + } watch; + } u; +}; + +struct xs_handle { + /* A list of replies. Currently only one will ever be outstanding. */ + struct list_head reply_list; + spinlock_t reply_lock; + wait_queue_head_t reply_waitq; + + /* + * Mutex ordering: transaction_mutex -> watch_mutex -> request_mutex. + * response_mutex is never taken simultaneously with the other three. + */ + + /* One request at a time. */ + struct mutex request_mutex; + + /* Protect xenbus reader thread against save/restore. */ + struct mutex response_mutex; + + /* Protect transactions against save/restore. */ + struct rw_semaphore transaction_mutex; + + /* Protect watch (de)register against save/restore. */ + struct rw_semaphore watch_mutex; +}; + +static struct xs_handle xs_state; + +/* List of registered watches, and a lock to protect it. */ +static LIST_HEAD(watches); +static DEFINE_SPINLOCK(watches_lock); + +/* List of pending watch callback events, and a lock to protect it. */ +static LIST_HEAD(watch_events); +static DEFINE_SPINLOCK(watch_events_lock); + +/* + * Details of the xenwatch callback kernel thread. The thread waits on the + * watch_events_waitq for work to do (queued on watch_events list). When it + * wakes up it acquires the xenwatch_mutex before reading the list and + * carrying out work. + */ +static pid_t xenwatch_pid; +static DEFINE_MUTEX(xenwatch_mutex); +static DECLARE_WAIT_QUEUE_HEAD(watch_events_waitq); + +static int get_error(const char *errorstring) +{ + unsigned int i; + + for (i = 0; strcmp(errorstring, xsd_errors[i].errstring) != 0; i++) { + if (i == ARRAY_SIZE(xsd_errors) - 1) { + printk(KERN_WARNING + "XENBUS xen store gave: unknown error %s", + errorstring); + return EINVAL; + } + } + return xsd_errors[i].errnum; +} + +static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len) +{ + struct xs_stored_msg *msg; + char *body; + + spin_lock(&xs_state.reply_lock); + + while (list_empty(&xs_state.reply_list)) { + spin_unlock(&xs_state.reply_lock); + /* XXX FIXME: Avoid synchronous wait for response here. */ + wait_event(xs_state.reply_waitq, + !list_empty(&xs_state.reply_list)); + spin_lock(&xs_state.reply_lock); + } + + msg = list_entry(xs_state.reply_list.next, + struct xs_stored_msg, list); + list_del(&msg->list); + + spin_unlock(&xs_state.reply_lock); + + *type = msg->hdr.type; + if (len) + *len = msg->hdr.len; + body = msg->u.reply.body; + + kfree(msg); + + return body; +} + +void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg) +{ + void *ret; + struct xsd_sockmsg req_msg = *msg; + int err; + + if (req_msg.type == XS_TRANSACTION_START) + down_read(&xs_state.transaction_mutex); + + mutex_lock(&xs_state.request_mutex); + + err = xb_write(msg, sizeof(*msg) + msg->len); + if (err) { + msg->type = XS_ERROR; + ret = ERR_PTR(err); + } else + ret = read_reply(&msg->type, &msg->len); + + mutex_unlock(&xs_state.request_mutex); + + if ((msg->type == XS_TRANSACTION_END) || + ((req_msg.type == XS_TRANSACTION_START) && + (msg->type == XS_ERROR))) + up_read(&xs_state.transaction_mutex); + + return ret; +} + +/* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */ +static void *xs_talkv(struct xenbus_transaction t, + enum xsd_sockmsg_type type, + const struct kvec *iovec, + unsigned int num_vecs, + unsigned int *len) +{ + struct xsd_sockmsg msg; + void *ret = NULL; + unsigned int i; + int err; + + msg.tx_id = t.id; + msg.req_id = 0; + msg.type = type; + msg.len = 0; + for (i = 0; i < num_vecs; i++) + msg.len += iovec[i].iov_len; + + mutex_lock(&xs_state.request_mutex); + + err = xb_write(&msg, sizeof(msg)); + if (err) { + mutex_unlock(&xs_state.request_mutex); + return ERR_PTR(err); + } + + for (i = 0; i < num_vecs; i++) { + err = xb_write(iovec[i].iov_base, iovec[i].iov_len); + if (err) { + mutex_unlock(&xs_state.request_mutex); + return ERR_PTR(err); + } + } + + ret = read_reply(&msg.type, len); + + mutex_unlock(&xs_state.request_mutex); + + if (IS_ERR(ret)) + return ret; + + if (msg.type == XS_ERROR) { + err = get_error(ret); + kfree(ret); + return ERR_PTR(-err); + } + + if (msg.type != type) { + if (printk_ratelimit()) + printk(KERN_WARNING + "XENBUS unexpected type [%d], expected [%d]\n", + msg.type, type); + kfree(ret); + return ERR_PTR(-EINVAL); + } + return ret; +} + +/* Simplified version of xs_talkv: single message. */ +static void *xs_single(struct xenbus_transaction t, + enum xsd_sockmsg_type type, + const char *string, + unsigned int *len) +{ + struct kvec iovec; + + iovec.iov_base = (void *)string; + iovec.iov_len = strlen(string) + 1; + return xs_talkv(t, type, &iovec, 1, len); +} + +/* Many commands only need an ack, don't care what it says. */ +static int xs_error(char *reply) +{ + if (IS_ERR(reply)) + return PTR_ERR(reply); + kfree(reply); + return 0; +} + +static unsigned int count_strings(const char *strings, unsigned int len) +{ + unsigned int num; + const char *p; + + for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1) + num++; + + return num; +} + +/* Return the path to dir with /name appended. Buffer must be kfree()'ed. */ +static char *join(const char *dir, const char *name) +{ + char *buffer; + + if (strlen(name) == 0) + buffer = kasprintf(GFP_KERNEL, "%s", dir); + else + buffer = kasprintf(GFP_KERNEL, "%s/%s", dir, name); + return (!buffer) ? ERR_PTR(-ENOMEM) : buffer; +} + +static char **split(char *strings, unsigned int len, unsigned int *num) +{ + char *p, **ret; + + /* Count the strings. */ + *num = count_strings(strings, len); + + /* Transfer to one big alloc for easy freeing. */ + ret = kmalloc(*num * sizeof(char *) + len, GFP_KERNEL); + if (!ret) { + kfree(strings); + return ERR_PTR(-ENOMEM); + } + memcpy(&ret[*num], strings, len); + kfree(strings); + + strings = (char *)&ret[*num]; + for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1) + ret[(*num)++] = p; + + return ret; +} + +char **xenbus_directory(struct xenbus_transaction t, + const char *dir, const char *node, unsigned int *num) +{ + char *strings, *path; + unsigned int len; + + path = join(dir, node); + if (IS_ERR(path)) + return (char **)path; + + strings = xs_single(t, XS_DIRECTORY, path, &len); + kfree(path); + if (IS_ERR(strings)) + return (char **)strings; + + return split(strings, len, num); +} +EXPORT_SYMBOL_GPL(xenbus_directory); + +/* Check if a path exists. Return 1 if it does. */ +int xenbus_exists(struct xenbus_transaction t, + const char *dir, const char *node) +{ + char **d; + int dir_n; + + d = xenbus_directory(t, dir, node, &dir_n); + if (IS_ERR(d)) + return 0; + kfree(d); + return 1; +} +EXPORT_SYMBOL_GPL(xenbus_exists); + +/* Get the value of a single file. + * Returns a kmalloced value: call free() on it after use. + * len indicates length in bytes. + */ +void *xenbus_read(struct xenbus_transaction t, + const char *dir, const char *node, unsigned int *len) +{ + char *path; + void *ret; + + path = join(dir, node); + if (IS_ERR(path)) + return (void *)path; + + ret = xs_single(t, XS_READ, path, len); + kfree(path); + return ret; +} +EXPORT_SYMBOL_GPL(xenbus_read); + +/* Write the value of a single file. + * Returns -err on failure. + */ +int xenbus_write(struct xenbus_transaction t, + const char *dir, const char *node, const char *string) +{ + const char *path; + struct kvec iovec[2]; + int ret; + + path = join(dir, node); + if (IS_ERR(path)) + return PTR_ERR(path); + + iovec[0].iov_base = (void *)path; + iovec[0].iov_len = strlen(path) + 1; + iovec[1].iov_base = (void *)string; + iovec[1].iov_len = strlen(string); + + ret = xs_error(xs_talkv(t, XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL)); + kfree(path); + return ret; +} +EXPORT_SYMBOL_GPL(xenbus_write); + +/* Create a new directory. */ +int xenbus_mkdir(struct xenbus_transaction t, + const char *dir, const char *node) +{ + char *path; + int ret; + + path = join(dir, node); + if (IS_ERR(path)) + return PTR_ERR(path); + + ret = xs_error(xs_single(t, XS_MKDIR, path, NULL)); + kfree(path); + return ret; +} +EXPORT_SYMBOL_GPL(xenbus_mkdir); + +/* Destroy a file or directory (directories must be empty). */ +int xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node) +{ + char *path; + int ret; + + path = join(dir, node); + if (IS_ERR(path)) + return PTR_ERR(path); + + ret = xs_error(xs_single(t, XS_RM, path, NULL)); + kfree(path); + return ret; +} +EXPORT_SYMBOL_GPL(xenbus_rm); + +/* Start a transaction: changes by others will not be seen during this + * transaction, and changes will not be visible to others until end. + */ +int xenbus_transaction_start(struct xenbus_transaction *t) +{ + char *id_str; + + down_read(&xs_state.transaction_mutex); + + id_str = xs_single(XBT_NIL, XS_TRANSACTION_START, "", NULL); + if (IS_ERR(id_str)) { + up_read(&xs_state.transaction_mutex); + return PTR_ERR(id_str); + } + + t->id = simple_strtoul(id_str, NULL, 0); + kfree(id_str); + return 0; +} +EXPORT_SYMBOL_GPL(xenbus_transaction_start); + +/* End a transaction. + * If abandon is true, transaction is discarded instead of committed. + */ +int xenbus_transaction_end(struct xenbus_transaction t, int abort) +{ + char abortstr[2]; + int err; + + if (abort) + strcpy(abortstr, "F"); + else + strcpy(abortstr, "T"); + + err = xs_error(xs_single(t, XS_TRANSACTION_END, abortstr, NULL)); + + up_read(&xs_state.transaction_mutex); + + return err; +} +EXPORT_SYMBOL_GPL(xenbus_transaction_end); + +/* Single read and scanf: returns -errno or num scanned. */ +int xenbus_scanf(struct xenbus_transaction t, + const char *dir, const char *node, const char *fmt, ...) +{ + va_list ap; + int ret; + char *val; + + val = xenbus_read(t, dir, node, NULL); + if (IS_ERR(val)) + return PTR_ERR(val); + + va_start(ap, fmt); + ret = vsscanf(val, fmt, ap); + va_end(ap); + kfree(val); + /* Distinctive errno. */ + if (ret == 0) + return -ERANGE; + return ret; +} +EXPORT_SYMBOL_GPL(xenbus_scanf); + +/* Single printf and write: returns -errno or 0. */ +int xenbus_printf(struct xenbus_transaction t, + const char *dir, const char *node, const char *fmt, ...) +{ + va_list ap; + int ret; +#define PRINTF_BUFFER_SIZE 4096 + char *printf_buffer; + + printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL); + if (printf_buffer == NULL) + return -ENOMEM; + + va_start(ap, fmt); + ret = vsnprintf(printf_buffer, PRINTF_BUFFER_SIZE, fmt, ap); + va_end(ap); + + BUG_ON(ret > PRINTF_BUFFER_SIZE-1); + ret = xenbus_write(t, dir, node, printf_buffer); + + kfree(printf_buffer); + + return ret; +} +EXPORT_SYMBOL_GPL(xenbus_printf); + +/* Takes tuples of names, scanf-style args, and void **, NULL terminated. */ +int xenbus_gather(struct xenbus_transaction t, const char *dir, ...) +{ + va_list ap; + const char *name; + int ret = 0; + + va_start(ap, dir); + while (ret == 0 && (name = va_arg(ap, char *)) != NULL) { + const char *fmt = va_arg(ap, char *); + void *result = va_arg(ap, void *); + char *p; + + p = xenbus_read(t, dir, name, NULL); + if (IS_ERR(p)) { + ret = PTR_ERR(p); + break; + } + if (fmt) { + if (sscanf(p, fmt, result) == 0) + ret = -EINVAL; + kfree(p); + } else + *(char **)result = p; + } + va_end(ap); + return ret; +} +EXPORT_SYMBOL_GPL(xenbus_gather); + +static int xs_watch(const char *path, const char *token) +{ + struct kvec iov[2]; + + iov[0].iov_base = (void *)path; + iov[0].iov_len = strlen(path) + 1; + iov[1].iov_base = (void *)token; + iov[1].iov_len = strlen(token) + 1; + + return xs_error(xs_talkv(XBT_NIL, XS_WATCH, iov, + ARRAY_SIZE(iov), NULL)); +} + +static int xs_unwatch(const char *path, const char *token) +{ + struct kvec iov[2]; + + iov[0].iov_base = (char *)path; + iov[0].iov_len = strlen(path) + 1; + iov[1].iov_base = (char *)token; + iov[1].iov_len = strlen(token) + 1; + + return xs_error(xs_talkv(XBT_NIL, XS_UNWATCH, iov, + ARRAY_SIZE(iov), NULL)); +} + +static struct xenbus_watch *find_watch(const char *token) +{ + struct xenbus_watch *i, *cmp; + + cmp = (void *)simple_strtoul(token, NULL, 16); + + list_for_each_entry(i, &watches, list) + if (i == cmp) + return i; + + return NULL; +} + +/* Register callback to watch this node. */ +int register_xenbus_watch(struct xenbus_watch *watch) +{ + /* Pointer in ascii is the token. */ + char token[sizeof(watch) * 2 + 1]; + int err; + + sprintf(token, "%lX", (long)watch); + + down_read(&xs_state.watch_mutex); + + spin_lock(&watches_lock); + BUG_ON(find_watch(token)); + list_add(&watch->list, &watches); + spin_unlock(&watches_lock); + + err = xs_watch(watch->node, token); + + /* Ignore errors due to multiple registration. */ + if ((err != 0) && (err != -EEXIST)) { + spin_lock(&watches_lock); + list_del(&watch->list); + spin_unlock(&watches_lock); + } + + up_read(&xs_state.watch_mutex); + + return err; +} +EXPORT_SYMBOL_GPL(register_xenbus_watch); + +void unregister_xenbus_watch(struct xenbus_watch *watch) +{ + struct xs_stored_msg *msg, *tmp; + char token[sizeof(watch) * 2 + 1]; + int err; + + sprintf(token, "%lX", (long)watch); + + down_read(&xs_state.watch_mutex); + + spin_lock(&watches_lock); + BUG_ON(!find_watch(token)); + list_del(&watch->list); + spin_unlock(&watches_lock); + + err = xs_unwatch(watch->node, token); + if (err) + printk(KERN_WARNING + "XENBUS Failed to release watch %s: %i\n", + watch->node, err); + + up_read(&xs_state.watch_mutex); + + /* Make sure there are no callbacks running currently (unless + its us) */ + if (current->pid != xenwatch_pid) + mutex_lock(&xenwatch_mutex); + + /* Cancel pending watch events. */ + spin_lock(&watch_events_lock); + list_for_each_entry_safe(msg, tmp, &watch_events, list) { + if (msg->u.watch.handle != watch) + continue; + list_del(&msg->list); + kfree(msg->u.watch.vec); + kfree(msg); + } + spin_unlock(&watch_events_lock); + + if (current->pid != xenwatch_pid) + mutex_unlock(&xenwatch_mutex); +} +EXPORT_SYMBOL_GPL(unregister_xenbus_watch); + +void xs_suspend(void) +{ + down_write(&xs_state.transaction_mutex); + down_write(&xs_state.watch_mutex); + mutex_lock(&xs_state.request_mutex); + mutex_lock(&xs_state.response_mutex); +} + +void xs_resume(void) +{ + struct xenbus_watch *watch; + char token[sizeof(watch) * 2 + 1]; + + mutex_unlock(&xs_state.response_mutex); + mutex_unlock(&xs_state.request_mutex); + up_write(&xs_state.transaction_mutex); + + /* No need for watches_lock: the watch_mutex is sufficient. */ + list_for_each_entry(watch, &watches, list) { + sprintf(token, "%lX", (long)watch); + xs_watch(watch->node, token); + } + + up_write(&xs_state.watch_mutex); +} + +void xs_suspend_cancel(void) +{ + mutex_unlock(&xs_state.response_mutex); + mutex_unlock(&xs_state.request_mutex); + up_write(&xs_state.watch_mutex); + up_write(&xs_state.transaction_mutex); +} + +static int xenwatch_thread(void *unused) +{ + struct list_head *ent; + struct xs_stored_msg *msg; + + for (;;) { + wait_event_interruptible(watch_events_waitq, + !list_empty(&watch_events)); + + if (kthread_should_stop()) + break; + + mutex_lock(&xenwatch_mutex); + + spin_lock(&watch_events_lock); + ent = watch_events.next; + if (ent != &watch_events) + list_del(ent); + spin_unlock(&watch_events_lock); + + if (ent != &watch_events) { + msg = list_entry(ent, struct xs_stored_msg, list); + msg->u.watch.handle->callback( + msg->u.watch.handle, + (const char **)msg->u.watch.vec, + msg->u.watch.vec_size); + kfree(msg->u.watch.vec); + kfree(msg); + } + + mutex_unlock(&xenwatch_mutex); + } + + return 0; +} + +static int process_msg(void) +{ + struct xs_stored_msg *msg; + char *body; + int err; + + /* + * We must disallow save/restore while reading a xenstore message. + * A partial read across s/r leaves us out of sync with xenstored. + */ + for (;;) { + err = xb_wait_for_data_to_read(); + if (err) + return err; + mutex_lock(&xs_state.response_mutex); + if (xb_data_to_read()) + break; + /* We raced with save/restore: pending data 'disappeared'. */ + mutex_unlock(&xs_state.response_mutex); + } + + + msg = kmalloc(sizeof(*msg), GFP_KERNEL); + if (msg == NULL) { + err = -ENOMEM; + goto out; + } + + err = xb_read(&msg->hdr, sizeof(msg->hdr)); + if (err) { + kfree(msg); + goto out; + } + + body = kmalloc(msg->hdr.len + 1, GFP_KERNEL); + if (body == NULL) { + kfree(msg); + err = -ENOMEM; + goto out; + } + + err = xb_read(body, msg->hdr.len); + if (err) { + kfree(body); + kfree(msg); + goto out; + } + body[msg->hdr.len] = '\0'; + + if (msg->hdr.type == XS_WATCH_EVENT) { + msg->u.watch.vec = split(body, msg->hdr.len, + &msg->u.watch.vec_size); + if (IS_ERR(msg->u.watch.vec)) { + kfree(msg); + err = PTR_ERR(msg->u.watch.vec); + goto out; + } + + spin_lock(&watches_lock); + msg->u.watch.handle = find_watch( + msg->u.watch.vec[XS_WATCH_TOKEN]); + if (msg->u.watch.handle != NULL) { + spin_lock(&watch_events_lock); + list_add_tail(&msg->list, &watch_events); + wake_up(&watch_events_waitq); + spin_unlock(&watch_events_lock); + } else { + kfree(msg->u.watch.vec); + kfree(msg); + } + spin_unlock(&watches_lock); + } else { + msg->u.reply.body = body; + spin_lock(&xs_state.reply_lock); + list_add_tail(&msg->list, &xs_state.reply_list); + spin_unlock(&xs_state.reply_lock); + wake_up(&xs_state.reply_waitq); + } + + out: + mutex_unlock(&xs_state.response_mutex); + return err; +} + +static int xenbus_thread(void *unused) +{ + int err; + + for (;;) { + err = process_msg(); + if (err) + printk(KERN_WARNING "XENBUS error %d while reading " + "message\n", err); + if (kthread_should_stop()) + break; + } + + return 0; +} + +int xs_init(void) +{ + int err; + struct task_struct *task; + + INIT_LIST_HEAD(&xs_state.reply_list); + spin_lock_init(&xs_state.reply_lock); + init_waitqueue_head(&xs_state.reply_waitq); + + mutex_init(&xs_state.request_mutex); + mutex_init(&xs_state.response_mutex); + init_rwsem(&xs_state.transaction_mutex); + init_rwsem(&xs_state.watch_mutex); + + /* Initialize the shared memory rings to talk to xenstored */ + err = xb_init_comms(); + if (err) + return err; + + task = kthread_run(xenwatch_thread, NULL, "xenwatch"); + if (IS_ERR(task)) + return PTR_ERR(task); + xenwatch_pid = task->pid; + + task = kthread_run(xenbus_thread, NULL, "xenbus"); + if (IS_ERR(task)) + return PTR_ERR(task); + + return 0; +} |