aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/Makefile2
-rw-r--r--drivers/base/cpu.c2
-rw-r--r--drivers/base/dmapool.c481
-rw-r--r--drivers/block/ataflop.c16
-rw-r--r--drivers/block/cciss.c10
-rw-r--r--drivers/block/loop.c8
-rw-r--r--drivers/block/paride/pt.c2
-rw-r--r--drivers/block/pktcdvd.c4
-rw-r--r--drivers/block/rd.c3
-rw-r--r--drivers/cdrom/cdrom.c17
-rw-r--r--drivers/char/Kconfig4
-rw-r--r--drivers/char/hvc_console.c2
-rw-r--r--drivers/char/hvcs.c2
-rw-r--r--drivers/char/hw_random/via-rng.c14
-rw-r--r--drivers/char/i8k.c7
-rw-r--r--drivers/char/ip27-rtc.c9
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c6
-rw-r--r--drivers/char/lp.c10
-rw-r--r--drivers/char/mxser.c1
-rw-r--r--drivers/char/mxser_new.c1
-rw-r--r--drivers/char/n_tty.c27
-rw-r--r--drivers/char/pcmcia/synclink_cs.c3
-rw-r--r--drivers/char/random.c1
-rw-r--r--drivers/char/riscom8.c147
-rw-r--r--drivers/char/ser_a2232.c2
-rw-r--r--drivers/char/synclink.c3
-rw-r--r--drivers/char/synclink_gt.c71
-rw-r--r--drivers/char/synclinkmp.c3
-rw-r--r--drivers/char/tpm/tpm.c44
-rw-r--r--drivers/char/tpm/tpm.h2
-rw-r--r--drivers/char/tpm/tpm_infineon.c6
-rw-r--r--drivers/char/tty_io.c25
-rw-r--r--drivers/char/vt.c8
-rw-r--r--drivers/firmware/dcdbas.c3
-rw-r--r--drivers/firmware/dmi-id.c1
-rw-r--r--drivers/gpio/Kconfig11
-rw-r--r--drivers/gpio/Makefile2
-rw-r--r--drivers/gpio/pca9539.c271
-rw-r--r--drivers/gpio/pca953x.c308
-rw-r--r--drivers/ide/Kconfig9
-rw-r--r--drivers/ide/arm/Makefile1
-rw-r--r--drivers/ide/arm/icside.c2
-rw-r--r--drivers/ide/arm/palm_bk3710.c395
-rw-r--r--drivers/ide/cris/ide-cris.c33
-rw-r--r--drivers/ide/ide-acpi.c2
-rw-r--r--drivers/ide/ide-cd.c9
-rw-r--r--drivers/ide/ide-dma.c3
-rw-r--r--drivers/ide/ide-floppy.c6
-rw-r--r--drivers/ide/ide-generic.c10
-rw-r--r--drivers/ide/ide-io.c14
-rw-r--r--drivers/ide/ide-iops.c45
-rw-r--r--drivers/ide/ide-lib.c2
-rw-r--r--drivers/ide/ide-probe.c53
-rw-r--r--drivers/ide/ide-proc.c1
-rw-r--r--drivers/ide/ide-tape.c2400
-rw-r--r--drivers/ide/ide-taskfile.c35
-rw-r--r--drivers/ide/ide.c54
-rw-r--r--drivers/ide/legacy/buddha.c72
-rw-r--r--drivers/ide/legacy/falconide.c42
-rw-r--r--drivers/ide/legacy/gayle.c39
-rw-r--r--drivers/ide/legacy/hd.c9
-rw-r--r--drivers/ide/legacy/macide.c57
-rw-r--r--drivers/ide/legacy/q40ide.c9
-rw-r--r--drivers/ide/pci/Makefile3
-rw-r--r--drivers/ide/pci/generic.c13
-rw-r--r--drivers/ide/pci/siimage.c3
-rw-r--r--drivers/input/touchscreen/h3600_ts_input.c4
-rw-r--r--drivers/isdn/act2000/module.c22
-rw-r--r--drivers/isdn/gigaset/asyncdata.c8
-rw-r--r--drivers/isdn/gigaset/bas-gigaset.c423
-rw-r--r--drivers/isdn/gigaset/common.c135
-rw-r--r--drivers/isdn/gigaset/ev-layer.c106
-rw-r--r--drivers/isdn/gigaset/gigaset.h45
-rw-r--r--drivers/isdn/gigaset/interface.c19
-rw-r--r--drivers/isdn/gigaset/isocdata.c51
-rw-r--r--drivers/isdn/gigaset/ser-gigaset.c20
-rw-r--r--drivers/isdn/gigaset/usb-gigaset.c206
-rw-r--r--drivers/isdn/hardware/eicon/debug.c2
-rw-r--r--drivers/isdn/hardware/eicon/diva.c5
-rw-r--r--drivers/isdn/hardware/eicon/message.c2
-rw-r--r--drivers/isdn/hisax/avm_pci.c8
-rw-r--r--drivers/isdn/i4l/isdn_tty.c1
-rw-r--r--drivers/isdn/i4l/isdn_ttyfax.c2
-rw-r--r--drivers/isdn/icn/icn.c22
-rw-r--r--drivers/isdn/isdnloop/isdnloop.c16
-rw-r--r--drivers/macintosh/mediabay.c46
-rw-r--r--drivers/md/bitmap.c39
-rw-r--r--drivers/md/faulty.c2
-rw-r--r--drivers/md/linear.c2
-rw-r--r--drivers/md/md.c395
-rw-r--r--drivers/md/mktables.c187
-rw-r--r--drivers/md/multipath.c2
-rw-r--r--drivers/md/raid0.c8
-rw-r--r--drivers/md/raid1.c5
-rw-r--r--drivers/md/raid10.c7
-rw-r--r--drivers/md/raid5.c48
-rw-r--r--drivers/md/raid6test/test.c117
-rw-r--r--drivers/media/video/Makefile1
-rw-r--r--drivers/media/video/tvmixer.c336
-rw-r--r--drivers/misc/asus-laptop.c1
-rw-r--r--drivers/misc/fujitsu-laptop.c1
-rw-r--r--drivers/misc/lkdtm.c24
-rw-r--r--drivers/misc/msi-laptop.c1
-rw-r--r--drivers/misc/phantom.c7
-rw-r--r--drivers/mtd/devices/block2mtd.c4
-rw-r--r--drivers/mtd/devices/phram.c4
-rw-r--r--drivers/mtd/maps/mtx-1_flash.c2
-rw-r--r--drivers/parport/parport_pc.c50
-rw-r--r--drivers/parport/parport_serial.c4
-rw-r--r--drivers/pci/dmar.c1
-rw-r--r--drivers/pci/intel-iommu.c4
-rw-r--r--drivers/pci/intel-iommu.h14
-rw-r--r--drivers/pci/iova.c8
-rw-r--r--drivers/pci/iova.h16
-rw-r--r--drivers/pnp/driver.c12
-rw-r--r--drivers/pnp/interface.c13
-rw-r--r--drivers/pnp/manager.c27
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c44
-rw-r--r--drivers/pnp/pnpbios/core.c2
-rw-r--r--drivers/pnp/pnpbios/rsparser.c33
-rw-r--r--drivers/pnp/quirks.c43
-rw-r--r--drivers/ps3/ps3av.c97
-rw-r--r--drivers/rtc/Kconfig126
-rw-r--r--drivers/rtc/Makefile4
-rw-r--r--drivers/rtc/rtc-at91sam9.c520
-rw-r--r--drivers/rtc/rtc-bfin.c351
-rw-r--r--drivers/rtc/rtc-cmos.c221
-rw-r--r--drivers/rtc/rtc-dev.c9
-rw-r--r--drivers/rtc/rtc-ds1302.c262
-rw-r--r--drivers/rtc/rtc-ds1307.c27
-rw-r--r--drivers/rtc/rtc-ds1511.c656
-rw-r--r--drivers/rtc/rtc-pcf8583.c24
-rw-r--r--drivers/rtc/rtc-r9701.c178
-rw-r--r--drivers/rtc/rtc-s3c.c5
-rw-r--r--drivers/rtc/rtc-sa1100.c16
-rw-r--r--drivers/rtc/rtc-sysfs.c19
-rw-r--r--drivers/s390/sysinfo.c2
-rw-r--r--drivers/scsi/a2091.c3
-rw-r--r--drivers/scsi/a3000.c3
-rw-r--r--drivers/scsi/aic7xxx_old.c2
-rw-r--r--drivers/scsi/gvp11.c3
-rw-r--r--drivers/scsi/ibmvscsi/ibmvstgt.c4
-rw-r--r--drivers/scsi/ide-scsi.c4
-rw-r--r--drivers/serial/Kconfig23
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_core.c2
-rw-r--r--drivers/serial/dz.c2
-rw-r--r--drivers/serial/imx.c4
-rw-r--r--drivers/serial/sc26xx.c755
-rw-r--r--drivers/serial/uartlite.c2
-rw-r--r--drivers/spi/Kconfig13
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/atmel_spi.c173
-rw-r--r--drivers/spi/omap2_mcspi.c37
-rw-r--r--drivers/spi/pxa2xx_spi.c17
-rw-r--r--drivers/spi/spi.c35
-rw-r--r--drivers/spi/spi_bfin5xx.c131
-rw-r--r--drivers/spi/spi_imx.c11
-rw-r--r--drivers/spi/spi_s3c24xx.c12
-rw-r--r--drivers/spi/spi_s3c24xx_gpio.c12
-rw-r--r--drivers/spi/spi_sh_sci.c205
-rw-r--r--drivers/uio/uio.c14
-rw-r--r--drivers/video/atmel_lcdfb.c135
-rw-r--r--drivers/video/backlight/Kconfig13
-rw-r--r--drivers/video/bf54x-lq043fb.c3
-rw-r--r--drivers/video/console/bitblit.c4
-rw-r--r--drivers/video/console/fbcon.c29
-rw-r--r--drivers/video/console/fbcon.h47
-rw-r--r--drivers/video/console/fbcon_ccw.c4
-rw-r--r--drivers/video/console/fbcon_cw.c4
-rw-r--r--drivers/video/console/fbcon_ud.c4
-rw-r--r--drivers/video/console/fonts.c4
-rw-r--r--drivers/video/console/tileblit.c4
-rw-r--r--drivers/video/console/vgacon.c2
-rw-r--r--drivers/video/fb_defio.c17
-rw-r--r--drivers/video/fb_draw.h1
-rw-r--r--drivers/video/fbmon.c118
-rw-r--r--drivers/video/geode/lxfb_core.c2
-rw-r--r--drivers/video/hpfb.c3
-rw-r--r--drivers/video/i810/i810_main.c2
-rw-r--r--drivers/video/igafb.c5
-rw-r--r--drivers/video/intelfb/intelfbhw.c2
-rw-r--r--drivers/video/neofb.c27
-rw-r--r--drivers/video/nvidia/nvidia.c22
-rw-r--r--drivers/video/pm2fb.c13
-rw-r--r--drivers/video/pm3fb.c2
-rw-r--r--drivers/video/pmag-aa-fb.c2
-rw-r--r--drivers/video/ps3fb.c451
-rw-r--r--drivers/video/s3c2410fb.c88
-rw-r--r--drivers/video/s3c2410fb.h7
-rw-r--r--drivers/video/sis/sis_main.c4
-rw-r--r--drivers/video/sm501fb.c64
-rw-r--r--drivers/video/tdfxfb.c2
-rw-r--r--drivers/video/uvesafb.c8
-rw-r--r--drivers/video/vermilion/vermilion.c5
-rw-r--r--drivers/virtio/virtio_balloon.c1
-rw-r--r--drivers/w1/masters/Kconfig10
-rw-r--r--drivers/w1/masters/Makefile1
-rw-r--r--drivers/w1/masters/w1-gpio.c124
-rw-r--r--drivers/w1/slaves/w1_therm.c3
-rw-r--r--drivers/w1/w1.c4
201 files changed, 8004 insertions, 4690 deletions
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 63e09c015ca..c66637392bb 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -5,7 +5,7 @@ obj-y := core.o sys.o bus.o dd.o \
cpu.o firmware.o init.o map.o devres.o \
attribute_container.o transport_class.o
obj-y += power/
-obj-$(CONFIG_HAS_DMA) += dma-mapping.o dmapool.o
+obj-$(CONFIG_HAS_DMA) += dma-mapping.o
obj-$(CONFIG_ISA) += isa.o
obj-$(CONFIG_FW_LOADER) += firmware_class.o
obj-$(CONFIG_NUMA) += node.o
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index c5885f5ce0a..499b003f927 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -110,7 +110,7 @@ static SYSDEV_ATTR(crash_notes, 0400, show_crash_notes, NULL);
*
* Initialize and register the CPU device.
*/
-int __devinit register_cpu(struct cpu *cpu, int num)
+int __cpuinit register_cpu(struct cpu *cpu, int num)
{
int error;
cpu->node_id = cpu_to_node(num);
diff --git a/drivers/base/dmapool.c b/drivers/base/dmapool.c
deleted file mode 100644
index b5034dc72a0..00000000000
--- a/drivers/base/dmapool.c
+++ /dev/null
@@ -1,481 +0,0 @@
-
-#include <linux/device.h>
-#include <linux/mm.h>
-#include <asm/io.h> /* Needed for i386 to build */
-#include <linux/dma-mapping.h>
-#include <linux/dmapool.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/poison.h>
-#include <linux/sched.h>
-
-/*
- * Pool allocator ... wraps the dma_alloc_coherent page allocator, so
- * small blocks are easily used by drivers for bus mastering controllers.
- * This should probably be sharing the guts of the slab allocator.
- */
-
-struct dma_pool { /* the pool */
- struct list_head page_list;
- spinlock_t lock;
- size_t blocks_per_page;
- size_t size;
- struct device *dev;
- size_t allocation;
- char name [32];
- wait_queue_head_t waitq;
- struct list_head pools;
-};
-
-struct dma_page { /* cacheable header for 'allocation' bytes */
- struct list_head page_list;
- void *vaddr;
- dma_addr_t dma;
- unsigned in_use;
- unsigned long bitmap [0];
-};
-
-#define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000)
-
-static DEFINE_MUTEX (pools_lock);
-
-static ssize_t
-show_pools (struct device *dev, struct device_attribute *attr, char *buf)
-{
- unsigned temp;
- unsigned size;
- char *next;
- struct dma_page *page;
- struct dma_pool *pool;
-
- next = buf;
- size = PAGE_SIZE;
-
- temp = scnprintf(next, size, "poolinfo - 0.1\n");
- size -= temp;
- next += temp;
-
- mutex_lock(&pools_lock);
- list_for_each_entry(pool, &dev->dma_pools, pools) {
- unsigned pages = 0;
- unsigned blocks = 0;
-
- list_for_each_entry(page, &pool->page_list, page_list) {
- pages++;
- blocks += page->in_use;
- }
-
- /* per-pool info, no real statistics yet */
- temp = scnprintf(next, size, "%-16s %4u %4Zu %4Zu %2u\n",
- pool->name,
- blocks, pages * pool->blocks_per_page,
- pool->size, pages);
- size -= temp;
- next += temp;
- }
- mutex_unlock(&pools_lock);
-
- return PAGE_SIZE - size;
-}
-static DEVICE_ATTR (pools, S_IRUGO, show_pools, NULL);
-
-/**
- * dma_pool_create - Creates a pool of consistent memory blocks, for dma.
- * @name: name of pool, for diagnostics
- * @dev: device that will be doing the DMA
- * @size: size of the blocks in this pool.
- * @align: alignment requirement for blocks; must be a power of two
- * @allocation: returned blocks won't cross this boundary (or zero)
- * Context: !in_interrupt()
- *
- * Returns a dma allocation pool with the requested characteristics, or
- * null if one can't be created. Given one of these pools, dma_pool_alloc()
- * may be used to allocate memory. Such memory will all have "consistent"
- * DMA mappings, accessible by the device and its driver without using
- * cache flushing primitives. The actual size of blocks allocated may be
- * larger than requested because of alignment.
- *
- * If allocation is nonzero, objects returned from dma_pool_alloc() won't
- * cross that size boundary. This is useful for devices which have
- * addressing restrictions on individual DMA transfers, such as not crossing
- * boundaries of 4KBytes.
- */
-struct dma_pool *
-dma_pool_create (const char *name, struct device *dev,
- size_t size, size_t align, size_t allocation)
-{
- struct dma_pool *retval;
-
- if (align == 0)
- align = 1;
- if (size == 0)
- return NULL;
- else if (size < align)
- size = align;
- else if ((size % align) != 0) {
- size += align + 1;
- size &= ~(align - 1);
- }
-
- if (allocation == 0) {
- if (PAGE_SIZE < size)
- allocation = size;
- else
- allocation = PAGE_SIZE;
- // FIXME: round up for less fragmentation
- } else if (allocation < size)
- return NULL;
-
- if (!(retval = kmalloc_node (sizeof *retval, GFP_KERNEL, dev_to_node(dev))))
- return retval;
-
- strlcpy (retval->name, name, sizeof retval->name);
-
- retval->dev = dev;
-
- INIT_LIST_HEAD (&retval->page_list);
- spin_lock_init (&retval->lock);
- retval->size = size;
- retval->allocation = allocation;
- retval->blocks_per_page = allocation / size;
- init_waitqueue_head (&retval->waitq);
-
- if (dev) {
- int ret;
-
- mutex_lock(&pools_lock);
- if (list_empty (&dev->dma_pools))
- ret = device_create_file (dev, &dev_attr_pools);
- else
- ret = 0;
- /* note: not currently insisting "name" be unique */
- if (!ret)
- list_add (&retval->pools, &dev->dma_pools);
- else {
- kfree(retval);
- retval = NULL;
- }
- mutex_unlock(&pools_lock);
- } else
- INIT_LIST_HEAD (&retval->pools);
-
- return retval;
-}
-
-
-static struct dma_page *
-pool_alloc_page (struct dma_pool *pool, gfp_t mem_flags)
-{
- struct dma_page *page;
- int mapsize;
-
- mapsize = pool->blocks_per_page;
- mapsize = (mapsize + BITS_PER_LONG - 1) / BITS_PER_LONG;
- mapsize *= sizeof (long);
-
- page = kmalloc(mapsize + sizeof *page, mem_flags);
- if (!page)
- return NULL;
- page->vaddr = dma_alloc_coherent (pool->dev,
- pool->allocation,
- &page->dma,
- mem_flags);
- if (page->vaddr) {
- memset (page->bitmap, 0xff, mapsize); // bit set == free
-#ifdef CONFIG_DEBUG_SLAB
- memset (page->vaddr, POOL_POISON_FREED, pool->allocation);
-#endif
- list_add (&page->page_list, &pool->page_list);
- page->in_use = 0;
- } else {
- kfree (page);
- page = NULL;
- }
- return page;
-}
-
-
-static inline int
-is_page_busy (int blocks, unsigned long *bitmap)
-{
- while (blocks > 0) {
- if (*bitmap++ != ~0UL)
- return 1;
- blocks -= BITS_PER_LONG;
- }
- return 0;
-}
-
-static void
-pool_free_page (struct dma_pool *pool, struct dma_page *page)
-{
- dma_addr_t dma = page->dma;
-
-#ifdef CONFIG_DEBUG_SLAB
- memset (page->vaddr, POOL_POISON_FREED, pool->allocation);
-#endif
- dma_free_coherent (pool->dev, pool->allocation, page->vaddr, dma);
- list_del (&page->page_list);
- kfree (page);
-}
-
-
-/**
- * dma_pool_destroy - destroys a pool of dma memory blocks.
- * @pool: dma pool that will be destroyed
- * Context: !in_interrupt()
- *
- * Caller guarantees that no more memory from the pool is in use,
- * and that nothing will try to use the pool after this call.
- */
-void
-dma_pool_destroy (struct dma_pool *pool)
-{
- mutex_lock(&pools_lock);
- list_del (&pool->pools);
- if (pool->dev && list_empty (&pool->dev->dma_pools))
- device_remove_file (pool->dev, &dev_attr_pools);
- mutex_unlock(&pools_lock);
-
- while (!list_empty (&pool->page_list)) {
- struct dma_page *page;
- page = list_entry (pool->page_list.next,
- struct dma_page, page_list);
- if (is_page_busy (pool->blocks_per_page, page->bitmap)) {
- if (pool->dev)
- dev_err(pool->dev, "dma_pool_destroy %s, %p busy\n",
- pool->name, page->vaddr);
- else
- printk (KERN_ERR "dma_pool_destroy %s, %p busy\n",
- pool->name, page->vaddr);
- /* leak the still-in-use consistent memory */
- list_del (&page->page_list);
- kfree (page);
- } else
- pool_free_page (pool, page);
- }
-
- kfree (pool);
-}
-
-
-/**
- * dma_pool_alloc - get a block of consistent memory
- * @pool: dma pool that will produce the block
- * @mem_flags: GFP_* bitmask
- * @handle: pointer to dma address of block
- *
- * This returns the kernel virtual address of a currently unused block,
- * and reports its dma address through the handle.
- * If such a memory block can't be allocated, null is returned.
- */
-void *
-dma_pool_alloc (struct dma_pool *pool, gfp_t mem_flags, dma_addr_t *handle)
-{
- unsigned long flags;
- struct dma_page *page;
- int map, block;
- size_t offset;
- void *retval;
-
-restart:
- spin_lock_irqsave (&pool->lock, flags);
- list_for_each_entry(page, &pool->page_list, page_list) {
- int i;
- /* only cachable accesses here ... */
- for (map = 0, i = 0;
- i < pool->blocks_per_page;
- i += BITS_PER_LONG, map++) {
- if (page->bitmap [map] == 0)
- continue;
- block = ffz (~ page->bitmap [map]);
- if ((i + block) < pool->blocks_per_page) {
- clear_bit (block, &page->bitmap [map]);
- offset = (BITS_PER_LONG * map) + block;
- offset *= pool->size;
- goto ready;
- }
- }
- }
- if (!(page = pool_alloc_page (pool, GFP_ATOMIC))) {
- if (mem_flags & __GFP_WAIT) {
- DECLARE_WAITQUEUE (wait, current);
-
- __set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue (&pool->waitq, &wait);
- spin_unlock_irqrestore (&pool->lock, flags);
-
- schedule_timeout (POOL_TIMEOUT_JIFFIES);
-
- remove_wait_queue (&pool->waitq, &wait);
- goto restart;
- }
- retval = NULL;
- goto done;
- }
-
- clear_bit (0, &page->bitmap [0]);
- offset = 0;
-ready:
- page->in_use++;
- retval = offset + page->vaddr;
- *handle = offset + page->dma;
-#ifdef CONFIG_DEBUG_SLAB
- memset (retval, POOL_POISON_ALLOCATED, pool->size);
-#endif
-done:
- spin_unlock_irqrestore (&pool->lock, flags);
- return retval;
-}
-
-
-static struct dma_page *
-pool_find_page (struct dma_pool *pool, dma_addr_t dma)
-{
- unsigned long flags;
- struct dma_page *page;
-
- spin_lock_irqsave (&pool->lock, flags);
- list_for_each_entry(page, &pool->page_list, page_list) {
- if (dma < page->dma)
- continue;
- if (dma < (page->dma + pool->allocation))
- goto done;
- }
- page = NULL;
-done:
- spin_unlock_irqrestore (&pool->lock, flags);
- return page;
-}
-
-
-/**
- * dma_pool_free - put block back into dma pool
- * @pool: the dma pool holding the block
- * @vaddr: virtual address of block
- * @dma: dma address of block
- *
- * Caller promises neither device nor driver will again touch this block
- * unless it is first re-allocated.
- */
-void
-dma_pool_free (struct dma_pool *pool, void *vaddr, dma_addr_t dma)
-{
- struct dma_page *page;
- unsigned long flags;
- int map, block;
-
- if ((page = pool_find_page(pool, dma)) == NULL) {
- if (pool->dev)
- dev_err(pool->dev, "dma_pool_free %s, %p/%lx (bad dma)\n",
- pool->name, vaddr, (unsigned long) dma);
- else
- printk (KERN_ERR "dma_pool_free %s, %p/%lx (bad dma)\n",
- pool->name, vaddr, (unsigned long) dma);
- return;
- }
-
- block = dma - page->dma;
- block /= pool->size;
- map = block / BITS_PER_LONG;
- block %= BITS_PER_LONG;
-
-#ifdef CONFIG_DEBUG_SLAB
- if (((dma - page->dma) + (void *)page->vaddr) != vaddr) {
- if (pool->dev)
- dev_err(pool->dev, "dma_pool_free %s, %p (bad vaddr)/%Lx\n",
- pool->name, vaddr, (unsigned long long) dma);
- else
- printk (KERN_ERR "dma_pool_free %s, %p (bad vaddr)/%Lx\n",
- pool->name, vaddr, (unsigned long long) dma);
- return;
- }
- if (page->bitmap [map] & (1UL << block)) {
- if (pool->dev)
- dev_err(pool->dev, "dma_pool_free %s, dma %Lx already free\n",
- pool->name, (unsigned long long)dma);
- else
- printk (KERN_ERR "dma_pool_free %s, dma %Lx already free\n",
- pool->name, (unsigned long long)dma);
- return;
- }
- memset (vaddr, POOL_POISON_FREED, pool->size);
-#endif
-
- spin_lock_irqsave (&pool->lock, flags);
- page->in_use--;
- set_bit (block, &page->bitmap [map]);
- if (waitqueue_active (&pool->waitq))
- wake_up (&pool->waitq);
- /*
- * Resist a temptation to do
- * if (!is_page_busy(bpp, page->bitmap)) pool_free_page(pool, page);
- * Better have a few empty pages hang around.
- */
- spin_unlock_irqrestore (&pool->lock, flags);
-}
-
-/*
- * Managed DMA pool
- */
-static void dmam_pool_release(struct device *dev, void *res)
-{
- struct dma_pool *pool = *(struct dma_pool **)res;
-
- dma_pool_destroy(pool);
-}
-
-static int dmam_pool_match(struct device *dev, void *res, void *match_data)
-{
- return *(struct dma_pool **)res == match_data;
-}
-
-/**
- * dmam_pool_create - Managed dma_pool_create()
- * @name: name of pool, for diagnostics
- * @dev: device that will be doing the DMA
- * @size: size of the blocks in this pool.
- * @align: alignment requirement for blocks; must be a power of two
- * @allocation: returned blocks won't cross this boundary (or zero)
- *
- * Managed dma_pool_create(). DMA pool created with this function is
- * automatically destroyed on driver detach.
- */
-struct dma_pool *dmam_pool_create(const char *name, struct device *dev,
- size_t size, size_t align, size_t allocation)
-{
- struct dma_pool **ptr, *pool;
-
- ptr = devres_alloc(dmam_pool_release, sizeof(*ptr), GFP_KERNEL);
- if (!ptr)
- return NULL;
-
- pool = *ptr = dma_pool_create(name, dev, size, align, allocation);
- if (pool)
- devres_add(dev, ptr);
- else
- devres_free(ptr);
-
- return pool;
-}
-
-/**
- * dmam_pool_destroy - Managed dma_pool_destroy()
- * @pool: dma pool that will be destroyed
- *
- * Managed dma_pool_destroy().
- */
-void dmam_pool_destroy(struct dma_pool *pool)
-{
- struct device *dev = pool->dev;
-
- dma_pool_destroy(pool);
- WARN_ON(devres_destroy(dev, dmam_pool_release, dmam_pool_match, pool));
-}
-
-EXPORT_SYMBOL (dma_pool_create);
-EXPORT_SYMBOL (dma_pool_destroy);
-EXPORT_SYMBOL (dma_pool_alloc);
-EXPORT_SYMBOL (dma_pool_free);
-EXPORT_SYMBOL (dmam_pool_create);
-EXPORT_SYMBOL (dmam_pool_destroy);
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index 94268c75d04..424995073c6 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -90,7 +90,7 @@ static struct atari_disk_type {
unsigned blocks; /* total number of blocks */
unsigned fdc_speed; /* fdc_speed setting */
unsigned stretch; /* track doubling ? */
-} disk_type[] = {
+} atari_disk_type[] = {
{ "d360", 9, 720, 0, 0}, /* 0: 360kB diskette */
{ "D360", 9, 720, 0, 1}, /* 1: 360kb in 720k or 1.2MB drive */
{ "D720", 9,1440, 0, 0}, /* 2: 720kb in 720k or 1.2MB drive */
@@ -658,7 +658,7 @@ static int do_format(int drive, int type, struct atari_format_descr *desc)
return -EINVAL;
}
type = minor2disktype[type].index;
- UDT = &disk_type[type];
+ UDT = &atari_disk_type[type];
}
if (!UDT || desc->track >= UDT->blocks/UDT->spt/2 || desc->head >= 2) {
@@ -1064,7 +1064,7 @@ static void fd_rwsec_done1(int status)
searched for a non-existent sector! */
!(read_track && FDC_READ(FDCREG_SECTOR) > SUDT->spt)) {
if (Probing) {
- if (SUDT > disk_type) {
+ if (SUDT > atari_disk_type) {
if (SUDT[-1].blocks > ReqBlock) {
/* try another disk type */
SUDT--;
@@ -1082,7 +1082,7 @@ static void fd_rwsec_done1(int status)
} else {
/* record not found, but not probing. Maybe stretch wrong ? Restart probing */
if (SUD.autoprobe) {
- SUDT = disk_type + StartDiskType[DriveType];
+ SUDT = atari_disk_type + StartDiskType[DriveType];
set_capacity(unit[SelectedDrive].disk,
SUDT->blocks);
Probing = 1;
@@ -1421,7 +1421,7 @@ repeat:
if (type == 0) {
if (!UDT) {
Probing = 1;
- UDT = disk_type + StartDiskType[DriveType];
+ UDT = atari_disk_type + StartDiskType[DriveType];
set_capacity(floppy->disk, UDT->blocks);
UD.autoprobe = 1;
}
@@ -1439,7 +1439,7 @@ repeat:
goto repeat;
}
type = minor2disktype[type].index;
- UDT = &disk_type[type];
+ UDT = &atari_disk_type[type];
set_capacity(floppy->disk, UDT->blocks);
UD.autoprobe = 0;
}
@@ -1505,7 +1505,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp,
if (minor2disktype[type].drive_types > DriveType)
return -ENODEV;
type = minor2disktype[type].index;
- dtp = &disk_type[type];
+ dtp = &atari_disk_type[type];
if (UD.flags & FTD_MSG)
printk (KERN_ERR "floppy%d: found dtp %p name %s!\n",
drive, dtp, dtp->name);
@@ -1576,7 +1576,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp,
continue;
}
setidx = minor2disktype[settype].index;
- dtp = &disk_type[setidx];
+ dtp = &atari_disk_type[setidx];
/* found matching entry ?? */
if ( dtp->blocks == setprm.size
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 855ce8e5efb..9715be3f248 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -2630,12 +2630,14 @@ static void do_cciss_request(struct request_queue *q)
c->Request.CDB[8] = creq->nr_sectors & 0xff;
c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
} else {
+ u32 upper32 = upper_32_bits(start_blk);
+
c->Request.CDBLen = 16;
c->Request.CDB[1]= 0;
- c->Request.CDB[2]= (start_blk >> 56) & 0xff; //MSB
- c->Request.CDB[3]= (start_blk >> 48) & 0xff;
- c->Request.CDB[4]= (start_blk >> 40) & 0xff;
- c->Request.CDB[5]= (start_blk >> 32) & 0xff;
+ c->Request.CDB[2]= (upper32 >> 24) & 0xff; //MSB
+ c->Request.CDB[3]= (upper32 >> 16) & 0xff;
+ c->Request.CDB[4]= (upper32 >> 8) & 0xff;
+ c->Request.CDB[5]= upper32 & 0xff;
c->Request.CDB[6]= (start_blk >> 24) & 0xff;
c->Request.CDB[7]= (start_blk >> 16) & 0xff;
c->Request.CDB[8]= (start_blk >> 8) & 0xff;
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index b8af22e610d..91ebb007416 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -973,6 +973,10 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
lo->transfer = xfer->transfer;
lo->ioctl = xfer->ioctl;
+ if ((lo->lo_flags & LO_FLAGS_AUTOCLEAR) !=
+ (info->lo_flags & LO_FLAGS_AUTOCLEAR))
+ lo->lo_flags ^= LO_FLAGS_AUTOCLEAR;
+
lo->lo_encrypt_key_size = info->lo_encrypt_key_size;
lo->lo_init[0] = info->lo_init[0];
lo->lo_init[1] = info->lo_init[1];
@@ -1331,6 +1335,10 @@ static int lo_release(struct inode *inode, struct file *file)
mutex_lock(&lo->lo_ctl_mutex);
--lo->lo_refcnt;
+
+ if ((lo->lo_flags & LO_FLAGS_AUTOCLEAR) && !lo->lo_refcnt)
+ loop_clr_fd(lo, inode->i_bdev);
+
mutex_unlock(&lo->lo_ctl_mutex);
return 0;
diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c
index 76096cad798..8b9549ab4a4 100644
--- a/drivers/block/paride/pt.c
+++ b/drivers/block/paride/pt.c
@@ -660,7 +660,7 @@ static int pt_open(struct inode *inode, struct file *file)
pt_identify(tape);
err = -ENODEV;
- if (!tape->flags & PT_MEDIA)
+ if (!(tape->flags & PT_MEDIA))
goto out;
err = -EROFS;
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index e9de1712e5a..674cd66dcab 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -2212,11 +2212,11 @@ static int pkt_media_speed(struct pktcdvd_device *pd, unsigned *speed)
return ret;
}
- if (!buf[6] & 0x40) {
+ if (!(buf[6] & 0x40)) {
printk(DRIVER_NAME": Disc type is not CD-RW\n");
return 1;
}
- if (!buf[6] & 0x4) {
+ if (!(buf[6] & 0x4)) {
printk(DRIVER_NAME": A1 values on media are not valid, maybe not CDRW?\n");
return 1;
}
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index 82f4eecc869..06e23be7090 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -56,6 +56,7 @@
#include <linux/backing-dev.h>
#include <linux/blkpg.h>
#include <linux/writeback.h>
+#include <linux/log2.h>
#include <asm/uaccess.h>
@@ -450,7 +451,7 @@ static int __init rd_init(void)
err = -ENOMEM;
if (rd_blocksize > PAGE_SIZE || rd_blocksize < 512 ||
- (rd_blocksize & (rd_blocksize-1))) {
+ !is_power_of_2(rd_blocksize)) {
printk("RAMDISK: wrong blocksize %d, reverting to defaults\n",
rd_blocksize);
rd_blocksize = BLOCK_SIZE;
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 47e5b40510c..db259e60289 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -1206,25 +1206,26 @@ int check_for_audio_disc(struct cdrom_device_info * cdi,
return 0;
}
-/* Admittedly, the logic below could be performed in a nicer way. */
int cdrom_release(struct cdrom_device_info *cdi, struct file *fp)
{
struct cdrom_device_ops *cdo = cdi->ops;
int opened_for_data;
- cdinfo(CD_CLOSE, "entering cdrom_release\n");
+ cdinfo(CD_CLOSE, "entering cdrom_release\n");
if (cdi->use_count > 0)
cdi->use_count--;
- if (cdi->use_count == 0)
+
+ if (cdi->use_count == 0) {
cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name);
- if (cdi->use_count == 0)
cdrom_dvd_rw_close_write(cdi);
- if (cdi->use_count == 0 &&
- (cdo->capability & CDC_LOCK) && !keeplocked) {
- cdinfo(CD_CLOSE, "Unlocking door!\n");
- cdo->lock_door(cdi, 0);
+
+ if ((cdo->capability & CDC_LOCK) && !keeplocked) {
+ cdinfo(CD_CLOSE, "Unlocking door!\n");
+ cdo->lock_door(cdi, 0);
+ }
}
+
opened_for_data = !(cdi->options & CDO_USE_FFLAGS) ||
!(fp && fp->f_flags & O_NONBLOCK);
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 46662959477..85bf9b2aa74 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -276,7 +276,7 @@ config N_HDLC
config RISCOM8
tristate "SDL RISCom/8 card support"
- depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP
+ depends on SERIAL_NONSTANDARD
help
This is a driver for the SDL Communications RISCom/8 multiport card,
which gives you many serial ports. You would need something like
@@ -765,7 +765,7 @@ config JS_RTC
config SGI_DS1286
tristate "SGI DS1286 RTC support"
- depends on SGI_IP22
+ depends on SGI_HAS_DS1286
help
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index 480fae29c9b..44160d5ebca 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -93,7 +93,7 @@ struct hvc_struct {
};
/* dynamic list of hvc_struct instances */
-static struct list_head hvc_structs = LIST_HEAD_INIT(hvc_structs);
+static LIST_HEAD(hvc_structs);
/*
* Protect the list of hvc_struct instances from inserts and removals during
diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c
index 3402def2200..786d518e947 100644
--- a/drivers/char/hvcs.c
+++ b/drivers/char/hvcs.c
@@ -306,7 +306,7 @@ struct hvcs_struct {
/* Required to back map a kref to its containing object */
#define from_kref(k) container_of(k, struct hvcs_struct, kref)
-static struct list_head hvcs_structs = LIST_HEAD_INIT(hvcs_structs);
+static LIST_HEAD(hvcs_structs);
static DEFINE_SPINLOCK(hvcs_structs_lock);
static void hvcs_unthrottle(struct tty_struct *tty);
diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c
index 868e39fd42e..f7feae4ebb5 100644
--- a/drivers/char/hw_random/via-rng.c
+++ b/drivers/char/hw_random/via-rng.c
@@ -42,6 +42,8 @@ enum {
VIA_STRFILT_ENABLE = (1 << 14),
VIA_RAWBITS_ENABLE = (1 << 13),
VIA_RNG_ENABLE = (1 << 6),
+ VIA_NOISESRC1 = (1 << 8),
+ VIA_NOISESRC2 = (1 << 9),
VIA_XSTORE_CNT_MASK = 0x0F,
VIA_RNG_CHUNK_8 = 0x00, /* 64 rand bits, 64 stored bits */
@@ -119,6 +121,7 @@ static int via_rng_data_read(struct hwrng *rng, u32 *data)
static int via_rng_init(struct hwrng *rng)
{
+ struct cpuinfo_x86 *c = &cpu_data(0);
u32 lo, hi, old_lo;
/* Control the RNG via MSR. Tread lightly and pay very close
@@ -134,6 +137,17 @@ static int via_rng_init(struct hwrng *rng)
lo &= ~VIA_XSTORE_CNT_MASK;
lo &= ~(VIA_STRFILT_ENABLE | VIA_STRFILT_FAIL | VIA_RAWBITS_ENABLE);
lo |= VIA_RNG_ENABLE;
+ lo |= VIA_NOISESRC1;
+
+ /* Enable secondary noise source on CPUs where it is present. */
+
+ /* Nehemiah stepping 8 and higher */
+ if ((c->x86_model == 9) && (c->x86_mask > 7))
+ lo |= VIA_NOISESRC2;
+
+ /* Esther */
+ if (c->x86_model >= 10)
+ lo |= VIA_NOISESRC2;
if (lo != old_lo)
wrmsr(MSR_VIA_RNG, lo, hi);
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index 30e56451642..179223a1741 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -439,6 +439,13 @@ static struct dmi_system_id __initdata i8k_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"),
},
},
+ { /* UK Inspiron 6400 */
+ .ident = "Dell Inspiron 3",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MM061"),
+ },
+ },
{ }
};
diff --git a/drivers/char/ip27-rtc.c b/drivers/char/ip27-rtc.c
index 932264a657d..86e6538a77b 100644
--- a/drivers/char/ip27-rtc.c
+++ b/drivers/char/ip27-rtc.c
@@ -46,8 +46,8 @@
#include <asm/sn/sn0/hub.h>
#include <asm/sn/sn_private.h>
-static int rtc_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg);
+static long rtc_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg);
static int rtc_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data);
@@ -75,8 +75,7 @@ static unsigned long epoch = 1970; /* year corresponding to 0x00 */
static const unsigned char days_in_mo[] =
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
+static long rtc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct rtc_time wtime;
@@ -197,7 +196,7 @@ static int rtc_release(struct inode *inode, struct file *file)
static const struct file_operations rtc_fops = {
.owner = THIS_MODULE,
- .ioctl = rtc_ioctl,
+ .unlocked_ioctl = rtc_ioctl,
.open = rtc_open,
.release = rtc_release,
};
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 5dc1265ce1d..32b2b22996d 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -365,12 +365,12 @@ static struct device_driver ipmidriver = {
};
static DEFINE_MUTEX(ipmidriver_mutex);
-static struct list_head ipmi_interfaces = LIST_HEAD_INIT(ipmi_interfaces);
+static LIST_HEAD(ipmi_interfaces);
static DEFINE_MUTEX(ipmi_interfaces_mutex);
/* List of watchers that want to know when smi's are added and
deleted. */
-static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers);
+static LIST_HEAD(smi_watchers);
static DEFINE_MUTEX(smi_watchers_mutex);
@@ -441,7 +441,7 @@ struct watcher_entry {
int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
{
ipmi_smi_t intf;
- struct list_head to_deliver = LIST_HEAD_INIT(to_deliver);
+ LIST_HEAD(to_deliver);
struct watcher_entry *e, *e2;
mutex_lock(&smi_watchers_mutex);
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index 81674d7c56c..60ac642752b 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -312,7 +312,7 @@ static ssize_t lp_write(struct file * file, const char __user * buf,
if (copy_size > LP_BUFFER_SIZE)
copy_size = LP_BUFFER_SIZE;
- if (down_interruptible (&lp_table[minor].port_mutex))
+ if (mutex_lock_interruptible(&lp_table[minor].port_mutex))
return -EINTR;
if (copy_from_user (kbuf, buf, copy_size)) {
@@ -399,7 +399,7 @@ static ssize_t lp_write(struct file * file, const char __user * buf,
lp_release_parport (&lp_table[minor]);
}
out_unlock:
- up (&lp_table[minor].port_mutex);
+ mutex_unlock(&lp_table[minor].port_mutex);
return retv;
}
@@ -421,7 +421,7 @@ static ssize_t lp_read(struct file * file, char __user * buf,
if (count > LP_BUFFER_SIZE)
count = LP_BUFFER_SIZE;
- if (down_interruptible (&lp_table[minor].port_mutex))
+ if (mutex_lock_interruptible(&lp_table[minor].port_mutex))
return -EINTR;
lp_claim_parport_or_block (&lp_table[minor]);
@@ -479,7 +479,7 @@ static ssize_t lp_read(struct file * file, char __user * buf,
if (retval > 0 && copy_to_user (buf, kbuf, retval))
retval = -EFAULT;
- up (&lp_table[minor].port_mutex);
+ mutex_unlock(&lp_table[minor].port_mutex);
return retval;
}
@@ -888,7 +888,7 @@ static int __init lp_init (void)
lp_table[i].last_error = 0;
init_waitqueue_head (&lp_table[i].waitq);
init_waitqueue_head (&lp_table[i].dataq);
- init_MUTEX (&lp_table[i].port_mutex);
+ mutex_init(&lp_table[i].port_mutex);
lp_table[i].timeout = 10 * HZ;
}
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index fd0abef7ee0..47420787a01 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -37,7 +37,6 @@
#include <linux/module.h>
-#include <linux/autoconf.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
diff --git a/drivers/char/mxser_new.c b/drivers/char/mxser_new.c
index 081c84c7b54..bf1bee4e1f5 100644
--- a/drivers/char/mxser_new.c
+++ b/drivers/char/mxser_new.c
@@ -20,7 +20,6 @@
*/
#include <linux/module.h>
-#include <linux/autoconf.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 596c7173997..90c3969012a 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -695,17 +695,16 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
return;
}
- if (tty->stopped && !tty->flow_stopped &&
- I_IXON(tty) && I_IXANY(tty)) {
- start_tty(tty);
- return;
- }
-
if (I_ISTRIP(tty))
c &= 0x7f;
if (I_IUCLC(tty) && L_IEXTEN(tty))
c=tolower(c);
+ if (tty->stopped && !tty->flow_stopped && I_IXON(tty) &&
+ ((I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty)) ||
+ c == INTR_CHAR(tty) || c == QUIT_CHAR(tty)))
+ start_tty(tty);
+
if (tty->closing) {
if (I_IXON(tty)) {
if (c == START_CHAR(tty))
@@ -769,7 +768,21 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
signal = SIGTSTP;
if (c == SUSP_CHAR(tty)) {
send_signal:
- isig(signal, tty, 0);
+ /*
+ * Echo character, and then send the signal.
+ * Note that we do not use isig() here because we want
+ * the order to be:
+ * 1) flush, 2) echo, 3) signal
+ */
+ if (!L_NOFLSH(tty)) {
+ n_tty_flush_buffer(tty);
+ if (tty->driver->flush_buffer)
+ tty->driver->flush_buffer(tty);
+ }
+ if (L_ECHO(tty))
+ echo_char(c, tty);
+ if (tty->pgrp)
+ kill_pgrp(tty->pgrp, signal, 1);
return;
}
}
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 8caff0ca80f..279ff5005ce 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -57,6 +57,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/ioctl.h>
+#include <linux/synclink.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -87,8 +88,6 @@
#include <asm/uaccess.h>
-#include "linux/synclink.h"
-
static MGSL_PARAMS default_params = {
MGSL_MODE_HDLC, /* unsigned long mode */
0, /* unsigned char loopback; */
diff --git a/drivers/char/random.c b/drivers/char/random.c
index c511a831f0c..f43c89f7c44 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1039,6 +1039,7 @@ write_pool(struct entropy_store *r, const char __user *buffer, size_t count)
p += bytes;
add_entropy_words(r, buf, (bytes + 3) / 4);
+ cond_resched();
}
return 0;
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index 102ece4c4e0..d130b87d8ed 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -47,6 +47,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/tty_flip.h>
+#include <linux/spinlock.h>
#include <asm/uaccess.h>
@@ -81,6 +82,8 @@
static struct tty_driver *riscom_driver;
+static DEFINE_SPINLOCK(riscom_lock);
+
static struct riscom_board rc_board[RC_NBOARD] = {
{
.base = RC_IOBASE1,
@@ -217,13 +220,14 @@ static void __init rc_init_CD180(struct riscom_board const * bp)
{
unsigned long flags;
- save_flags(flags); cli();
+ spin_lock_irqsave(&riscom_lock, flags);
+
rc_out(bp, RC_CTOUT, 0); /* Clear timeout */
rc_wait_CCR(bp); /* Wait for CCR ready */
rc_out(bp, CD180_CCR, CCR_HARDRESET); /* Reset CD180 chip */
- sti();
+ spin_unlock_irqrestore(&riscom_lock, flags);
msleep(50); /* Delay 0.05 sec */
- cli();
+ spin_lock_irqsave(&riscom_lock, flags);
rc_out(bp, CD180_GIVR, RC_ID); /* Set ID for this chip */
rc_out(bp, CD180_GICR, 0); /* Clear all bits */
rc_out(bp, CD180_PILR1, RC_ACK_MINT); /* Prio for modem intr */
@@ -234,7 +238,7 @@ static void __init rc_init_CD180(struct riscom_board const * bp)
rc_out(bp, CD180_PPRH, (RC_OSCFREQ/(1000000/RISCOM_TPS)) >> 8);
rc_out(bp, CD180_PPRL, (RC_OSCFREQ/(1000000/RISCOM_TPS)) & 0xff);
- restore_flags(flags);
+ spin_unlock_irqrestore(&riscom_lock, flags);
}
/* Main probing routine, also sets irq. */
@@ -812,9 +816,9 @@ static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port)
}
port->xmit_buf = (unsigned char *) tmp;
}
-
- save_flags(flags); cli();
-
+
+ spin_lock_irqsave(&riscom_lock, flags);
+
if (port->tty)
clear_bit(TTY_IO_ERROR, &port->tty->flags);
@@ -825,7 +829,7 @@ static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port)
rc_change_speed(bp, port);
port->flags |= ASYNC_INITIALIZED;
- restore_flags(flags);
+ spin_unlock_irqrestore(&riscom_lock, flags);
return 0;
}
@@ -901,6 +905,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
int retval;
int do_clocal = 0;
int CD;
+ unsigned long flags;
/*
* If the device is in the middle of being closed, then block
@@ -936,19 +941,26 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
*/
retval = 0;
add_wait_queue(&port->open_wait, &wait);
- cli();
+
+ spin_lock_irqsave(&riscom_lock, flags);
+
if (!tty_hung_up_p(filp))
port->count--;
- sti();
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
+
port->blocked_open++;
while (1) {
- cli();
+ spin_lock_irqsave(&riscom_lock, flags);
+
rc_out(bp, CD180_CAR, port_No(port));
CD = rc_in(bp, CD180_MSVR) & MSVR_CD;
rc_out(bp, CD180_MSVR, MSVR_RTS);
bp->DTR &= ~(1u << port_No(port));
rc_out(bp, RC_DTR, bp->DTR);
- sti();
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
+
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
!(port->flags & ASYNC_INITIALIZED)) {
@@ -1020,8 +1032,9 @@ static void rc_close(struct tty_struct * tty, struct file * filp)
if (!port || rc_paranoia_check(port, tty->name, "close"))
return;
-
- save_flags(flags); cli();
+
+ spin_lock_irqsave(&riscom_lock, flags);
+
if (tty_hung_up_p(filp))
goto out;
@@ -1088,7 +1101,9 @@ static void rc_close(struct tty_struct * tty, struct file * filp)
}
port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
wake_up_interruptible(&port->close_wait);
-out: restore_flags(flags);
+
+out:
+ spin_unlock_irqrestore(&riscom_lock, flags);
}
static int rc_write(struct tty_struct * tty,
@@ -1107,34 +1122,33 @@ static int rc_write(struct tty_struct * tty,
if (!tty || !port->xmit_buf)
return 0;
- save_flags(flags);
while (1) {
- cli();
+ spin_lock_irqsave(&riscom_lock, flags);
+
c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
SERIAL_XMIT_SIZE - port->xmit_head));
- if (c <= 0) {
- restore_flags(flags);
- break;
- }
+ if (c <= 0)
+ break; /* lock continues to be held */
memcpy(port->xmit_buf + port->xmit_head, buf, c);
port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
port->xmit_cnt += c;
- restore_flags(flags);
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
buf += c;
count -= c;
total += c;
}
- cli();
if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
!(port->IER & IER_TXRDY)) {
port->IER |= IER_TXRDY;
rc_out(bp, CD180_CAR, port_No(port));
rc_out(bp, CD180_IER, port->IER);
}
- restore_flags(flags);
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
return total;
}
@@ -1150,7 +1164,7 @@ static void rc_put_char(struct tty_struct * tty, unsigned char ch)
if (!tty || !port->xmit_buf)
return;
- save_flags(flags); cli();
+ spin_lock_irqsave(&riscom_lock, flags);
if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
goto out;
@@ -1158,7 +1172,9 @@ static void rc_put_char(struct tty_struct * tty, unsigned char ch)
port->xmit_buf[port->xmit_head++] = ch;
port->xmit_head &= SERIAL_XMIT_SIZE - 1;
port->xmit_cnt++;
-out: restore_flags(flags);
+
+out:
+ spin_unlock_irqrestore(&riscom_lock, flags);
}
static void rc_flush_chars(struct tty_struct * tty)
@@ -1173,11 +1189,13 @@ static void rc_flush_chars(struct tty_struct * tty)
!port->xmit_buf)
return;
- save_flags(flags); cli();
+ spin_lock_irqsave(&riscom_lock, flags);
+
port->IER |= IER_TXRDY;
rc_out(port_Board(port), CD180_CAR, port_No(port));
rc_out(port_Board(port), CD180_IER, port->IER);
- restore_flags(flags);
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
}
static int rc_write_room(struct tty_struct * tty)
@@ -1212,9 +1230,11 @@ static void rc_flush_buffer(struct tty_struct *tty)
if (rc_paranoia_check(port, tty->name, "rc_flush_buffer"))
return;
- save_flags(flags); cli();
+ spin_lock_irqsave(&riscom_lock, flags);
+
port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
- restore_flags(flags);
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
tty_wakeup(tty);
}
@@ -1231,11 +1251,15 @@ static int rc_tiocmget(struct tty_struct *tty, struct file *file)
return -ENODEV;
bp = port_Board(port);
- save_flags(flags); cli();
+
+ spin_lock_irqsave(&riscom_lock, flags);
+
rc_out(bp, CD180_CAR, port_No(port));
status = rc_in(bp, CD180_MSVR);
result = rc_in(bp, RC_RI) & (1u << port_No(port)) ? 0 : TIOCM_RNG;
- restore_flags(flags);
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
+
result |= ((status & MSVR_RTS) ? TIOCM_RTS : 0)
| ((status & MSVR_DTR) ? TIOCM_DTR : 0)
| ((status & MSVR_CD) ? TIOCM_CAR : 0)
@@ -1256,7 +1280,8 @@ static int rc_tiocmset(struct tty_struct *tty, struct file *file,
bp = port_Board(port);
- save_flags(flags); cli();
+ spin_lock_irqsave(&riscom_lock, flags);
+
if (set & TIOCM_RTS)
port->MSVR |= MSVR_RTS;
if (set & TIOCM_DTR)
@@ -1270,7 +1295,9 @@ static int rc_tiocmset(struct tty_struct *tty, struct file *file,
rc_out(bp, CD180_CAR, port_No(port));
rc_out(bp, CD180_MSVR, port->MSVR);
rc_out(bp, RC_DTR, bp->DTR);
- restore_flags(flags);
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
+
return 0;
}
@@ -1279,7 +1306,8 @@ static inline void rc_send_break(struct riscom_port * port, unsigned long length
struct riscom_board *bp = port_Board(port);
unsigned long flags;
- save_flags(flags); cli();
+ spin_lock_irqsave(&riscom_lock, flags);
+
port->break_length = RISCOM_TPS / HZ * length;
port->COR2 |= COR2_ETC;
port->IER |= IER_TXRDY;
@@ -1289,7 +1317,8 @@ static inline void rc_send_break(struct riscom_port * port, unsigned long length
rc_wait_CCR(bp);
rc_out(bp, CD180_CCR, CCR_CORCHG2);
rc_wait_CCR(bp);
- restore_flags(flags);
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
}
static inline int rc_set_serial_info(struct riscom_port * port,
@@ -1298,7 +1327,6 @@ static inline int rc_set_serial_info(struct riscom_port * port,
struct serial_struct tmp;
struct riscom_board *bp = port_Board(port);
int change_speed;
- unsigned long flags;
if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
return -EFAULT;
@@ -1332,9 +1360,11 @@ static inline int rc_set_serial_info(struct riscom_port * port,
port->closing_wait = tmp.closing_wait;
}
if (change_speed) {
- save_flags(flags); cli();
+ unsigned long flags;
+
+ spin_lock_irqsave(&riscom_lock, flags);
rc_change_speed(bp, port);
- restore_flags(flags);
+ spin_unlock_irqrestore(&riscom_lock, flags);
}
return 0;
}
@@ -1414,17 +1444,19 @@ static void rc_throttle(struct tty_struct * tty)
return;
bp = port_Board(port);
-
- save_flags(flags); cli();
+
+ spin_lock_irqsave(&riscom_lock, flags);
+
port->MSVR &= ~MSVR_RTS;
rc_out(bp, CD180_CAR, port_No(port));
- if (I_IXOFF(tty)) {
+ if (I_IXOFF(tty)) {
rc_wait_CCR(bp);
rc_out(bp, CD180_CCR, CCR_SSCH2);
rc_wait_CCR(bp);
}
rc_out(bp, CD180_MSVR, port->MSVR);
- restore_flags(flags);
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
}
static void rc_unthrottle(struct tty_struct * tty)
@@ -1438,7 +1470,8 @@ static void rc_unthrottle(struct tty_struct * tty)
bp = port_Board(port);
- save_flags(flags); cli();
+ spin_lock_irqsave(&riscom_lock, flags);
+
port->MSVR |= MSVR_RTS;
rc_out(bp, CD180_CAR, port_No(port));
if (I_IXOFF(tty)) {
@@ -1447,7 +1480,8 @@ static void rc_unthrottle(struct tty_struct * tty)
rc_wait_CCR(bp);
}
rc_out(bp, CD180_MSVR, port->MSVR);
- restore_flags(flags);
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
}
static void rc_stop(struct tty_struct * tty)
@@ -1461,11 +1495,13 @@ static void rc_stop(struct tty_struct * tty)
bp = port_Board(port);
- save_flags(flags); cli();
+ spin_lock_irqsave(&riscom_lock, flags);
+
port->IER &= ~IER_TXRDY;
rc_out(bp, CD180_CAR, port_No(port));
rc_out(bp, CD180_IER, port->IER);
- restore_flags(flags);
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
}
static void rc_start(struct tty_struct * tty)
@@ -1479,13 +1515,15 @@ static void rc_start(struct tty_struct * tty)
bp = port_Board(port);
- save_flags(flags); cli();
+ spin_lock_irqsave(&riscom_lock, flags);
+
if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) {
port->IER |= IER_TXRDY;
rc_out(bp, CD180_CAR, port_No(port));
rc_out(bp, CD180_IER, port->IER);
}
- restore_flags(flags);
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
}
/*
@@ -1537,9 +1575,9 @@ static void rc_set_termios(struct tty_struct * tty, struct ktermios * old_termio
tty->termios->c_iflag == old_termios->c_iflag)
return;
- save_flags(flags); cli();
+ spin_lock_irqsave(&riscom_lock, flags);
rc_change_speed(port_Board(port), port);
- restore_flags(flags);
+ spin_unlock_irqrestore(&riscom_lock, flags);
if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios->c_cflag & CRTSCTS)) {
@@ -1627,11 +1665,12 @@ static void rc_release_drivers(void)
{
unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&riscom_lock, flags);
+
tty_unregister_driver(riscom_driver);
put_tty_driver(riscom_driver);
- restore_flags(flags);
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
}
#ifndef MODULE
diff --git a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c
index 3c869145bfd..4ba3aec9e1c 100644
--- a/drivers/char/ser_a2232.c
+++ b/drivers/char/ser_a2232.c
@@ -653,7 +653,7 @@ static void a2232_init_portstructs(void)
port->gs.closing_wait = 30 * HZ;
port->gs.rd = &a2232_real_driver;
#ifdef NEW_WRITE_LOCKING
- init_MUTEX(&(port->gs.port_write_mutex));
+ mutex_init(&(port->gs.port_write_mutex));
#endif
init_waitqueue_head(&port->gs.open_wait);
init_waitqueue_head(&port->gs.close_wait);
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index d010ed95ed3..ddc74d1f4f1 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -85,6 +85,7 @@
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/ioctl.h>
+#include <linux/synclink.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -110,8 +111,6 @@
#include <asm/uaccess.h>
-#include "linux/synclink.h"
-
#define RCLRVALUE 0xffff
static MGSL_PARAMS default_params = {
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 64e835f6243..1f954acf2ba 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -73,6 +73,7 @@
#include <linux/bitops.h>
#include <linux/workqueue.h>
#include <linux/hdlc.h>
+#include <linux/synclink.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -81,8 +82,6 @@
#include <asm/types.h>
#include <asm/uaccess.h>
-#include "linux/synclink.h"
-
#if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_GT_MODULE))
#define SYNCLINK_GENERIC_HDLC 1
#else
@@ -2040,37 +2039,41 @@ static void bh_transmit(struct slgt_info *info)
tty_wakeup(tty);
}
-static void dsr_change(struct slgt_info *info)
+static void dsr_change(struct slgt_info *info, unsigned short status)
{
- get_signals(info);
+ if (status & BIT3) {
+ info->signals |= SerialSignal_DSR;
+ info->input_signal_events.dsr_up++;
+ } else {
+ info->signals &= ~SerialSignal_DSR;
+ info->input_signal_events.dsr_down++;
+ }
DBGISR(("dsr_change %s signals=%04X\n", info->device_name, info->signals));
if ((info->dsr_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
slgt_irq_off(info, IRQ_DSR);
return;
}
info->icount.dsr++;
- if (info->signals & SerialSignal_DSR)
- info->input_signal_events.dsr_up++;
- else
- info->input_signal_events.dsr_down++;
wake_up_interruptible(&info->status_event_wait_q);
wake_up_interruptible(&info->event_wait_q);
info->pending_bh |= BH_STATUS;
}
-static void cts_change(struct slgt_info *info)
+static void cts_change(struct slgt_info *info, unsigned short status)
{
- get_signals(info);
+ if (status & BIT2) {
+ info->signals |= SerialSignal_CTS;
+ info->input_signal_events.cts_up++;
+ } else {
+ info->signals &= ~SerialSignal_CTS;
+ info->input_signal_events.cts_down++;
+ }
DBGISR(("cts_change %s signals=%04X\n", info->device_name, info->signals));
if ((info->cts_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
slgt_irq_off(info, IRQ_CTS);
return;
}
info->icount.cts++;
- if (info->signals & SerialSignal_CTS)
- info->input_signal_events.cts_up++;
- else
- info->input_signal_events.cts_down++;
wake_up_interruptible(&info->status_event_wait_q);
wake_up_interruptible(&info->event_wait_q);
info->pending_bh |= BH_STATUS;
@@ -2091,20 +2094,21 @@ static void cts_change(struct slgt_info *info)
}
}
-static void dcd_change(struct slgt_info *info)
+static void dcd_change(struct slgt_info *info, unsigned short status)
{
- get_signals(info);
+ if (status & BIT1) {
+ info->signals |= SerialSignal_DCD;
+ info->input_signal_events.dcd_up++;
+ } else {
+ info->signals &= ~SerialSignal_DCD;
+ info->input_signal_events.dcd_down++;
+ }
DBGISR(("dcd_change %s signals=%04X\n", info->device_name, info->signals));
if ((info->dcd_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
slgt_irq_off(info, IRQ_DCD);
return;
}
info->icount.dcd++;
- if (info->signals & SerialSignal_DCD) {
- info->input_signal_events.dcd_up++;
- } else {
- info->input_signal_events.dcd_down++;
- }
#if SYNCLINK_GENERIC_HDLC
if (info->netcount) {
if (info->signals & SerialSignal_DCD)
@@ -2127,20 +2131,21 @@ static void dcd_change(struct slgt_info *info)
}
}
-static void ri_change(struct slgt_info *info)
+static void ri_change(struct slgt_info *info, unsigned short status)
{
- get_signals(info);
+ if (status & BIT0) {
+ info->signals |= SerialSignal_RI;
+ info->input_signal_events.ri_up++;
+ } else {
+ info->signals &= ~SerialSignal_RI;
+ info->input_signal_events.ri_down++;
+ }
DBGISR(("ri_change %s signals=%04X\n", info->device_name, info->signals));
if ((info->ri_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
slgt_irq_off(info, IRQ_RI);
return;
}
- info->icount.dcd++;
- if (info->signals & SerialSignal_RI) {
- info->input_signal_events.ri_up++;
- } else {
- info->input_signal_events.ri_down++;
- }
+ info->icount.rng++;
wake_up_interruptible(&info->status_event_wait_q);
wake_up_interruptible(&info->event_wait_q);
info->pending_bh |= BH_STATUS;
@@ -2191,13 +2196,13 @@ static void isr_serial(struct slgt_info *info)
}
if (status & IRQ_DSR)
- dsr_change(info);
+ dsr_change(info, status);
if (status & IRQ_CTS)
- cts_change(info);
+ cts_change(info, status);
if (status & IRQ_DCD)
- dcd_change(info);
+ dcd_change(info, status);
if (status & IRQ_RI)
- ri_change(info);
+ ri_change(info, status);
}
static void isr_rdma(struct slgt_info *info)
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index c63013b2fc3..f3e7807f78d 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -66,6 +66,7 @@
#include <linux/termios.h>
#include <linux/workqueue.h>
#include <linux/hdlc.h>
+#include <linux/synclink.h>
#if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINKMP_MODULE))
#define SYNCLINK_GENERIC_HDLC 1
@@ -80,8 +81,6 @@
#include <asm/uaccess.h>
-#include "linux/synclink.h"
-
static MGSL_PARAMS default_params = {
MGSL_MODE_HDLC, /* unsigned long mode */
0, /* unsigned char loopback; */
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index c88424a0c89..a5d8bcb4000 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -1031,18 +1031,13 @@ void tpm_remove_hardware(struct device *dev)
spin_unlock(&driver_lock);
- dev_set_drvdata(dev, NULL);
misc_deregister(&chip->vendor.miscdev);
- kfree(chip->vendor.miscdev.name);
sysfs_remove_group(&dev->kobj, chip->vendor.attr_group);
tpm_bios_log_teardown(chip->bios_dir);
- clear_bit(chip->dev_num, dev_mask);
-
- kfree(chip);
-
- put_device(dev);
+ /* write it this way to be explicit (chip->dev == dev) */
+ put_device(chip->dev);
}
EXPORT_SYMBOL_GPL(tpm_remove_hardware);
@@ -1083,6 +1078,26 @@ int tpm_pm_resume(struct device *dev)
EXPORT_SYMBOL_GPL(tpm_pm_resume);
/*
+ * Once all references to platform device are down to 0,
+ * release all allocated structures.
+ * In case vendor provided release function,
+ * call it too.
+ */
+static void tpm_dev_release(struct device *dev)
+{
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+
+ if (chip->vendor.release)
+ chip->vendor.release(dev);
+
+ chip->release(dev);
+
+ clear_bit(chip->dev_num, dev_mask);
+ kfree(chip->vendor.miscdev.name);
+ kfree(chip);
+}
+
+/*
* Called from tpm_<specific>.c probe function only for devices
* the driver has determined it should claim. Prior to calling
* this function the specific probe function has called pci_enable_device
@@ -1136,23 +1151,21 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend
chip->vendor.miscdev.parent = dev;
chip->dev = get_device(dev);
+ chip->release = dev->release;
+ dev->release = tpm_dev_release;
+ dev_set_drvdata(dev, chip);
if (misc_register(&chip->vendor.miscdev)) {
dev_err(chip->dev,
"unable to misc_register %s, minor %d\n",
chip->vendor.miscdev.name,
chip->vendor.miscdev.minor);
- put_device(dev);
- clear_bit(chip->dev_num, dev_mask);
- kfree(chip);
- kfree(devname);
+ put_device(chip->dev);
return NULL;
}
spin_lock(&driver_lock);
- dev_set_drvdata(dev, chip);
-
list_add(&chip->list, &tpm_chip_list);
spin_unlock(&driver_lock);
@@ -1160,10 +1173,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend
if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) {
list_del(&chip->list);
misc_deregister(&chip->vendor.miscdev);
- put_device(dev);
- clear_bit(chip->dev_num, dev_mask);
- kfree(chip);
- kfree(devname);
+ put_device(chip->dev);
return NULL;
}
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index d15ccddc92e..e885148b4cf 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -74,6 +74,7 @@ struct tpm_vendor_specific {
int (*send) (struct tpm_chip *, u8 *, size_t);
void (*cancel) (struct tpm_chip *);
u8 (*status) (struct tpm_chip *);
+ void (*release) (struct device *);
struct miscdevice miscdev;
struct attribute_group *attr_group;
struct list_head list;
@@ -106,6 +107,7 @@ struct tpm_chip {
struct dentry **bios_dir;
struct list_head list;
+ void (*release) (struct device *);
};
#define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor)
diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c
index 967002a5a1e..726ee8a0277 100644
--- a/drivers/char/tpm/tpm_infineon.c
+++ b/drivers/char/tpm/tpm_infineon.c
@@ -611,7 +611,7 @@ static __devexit void tpm_inf_pnp_remove(struct pnp_dev *dev)
}
}
-static struct pnp_driver tpm_inf_pnp = {
+static struct pnp_driver tpm_inf_pnp_driver = {
.name = "tpm_inf_pnp",
.driver = {
.owner = THIS_MODULE,
@@ -625,12 +625,12 @@ static struct pnp_driver tpm_inf_pnp = {
static int __init init_inf(void)
{
- return pnp_register_driver(&tpm_inf_pnp);
+ return pnp_register_driver(&tpm_inf_pnp_driver);
}
static void __exit cleanup_inf(void)
{
- pnp_unregister_driver(&tpm_inf_pnp);
+ pnp_unregister_driver(&tpm_inf_pnp_driver);
}
module_init(init_inf);
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index f36fecd3fd2..79c86c47947 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -138,7 +138,7 @@ EXPORT_SYMBOL(tty_mutex);
extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */
extern int pty_limit; /* Config limit on Unix98 ptys */
static DEFINE_IDR(allocated_ptys);
-static DECLARE_MUTEX(allocated_ptys_lock);
+static DEFINE_MUTEX(allocated_ptys_lock);
static int ptmx_open(struct inode *, struct file *);
#endif
@@ -2571,9 +2571,9 @@ static void release_dev(struct file * filp)
#ifdef CONFIG_UNIX98_PTYS
/* Make this pty number available for reallocation */
if (devpts) {
- down(&allocated_ptys_lock);
+ mutex_lock(&allocated_ptys_lock);
idr_remove(&allocated_ptys, idx);
- up(&allocated_ptys_lock);
+ mutex_unlock(&allocated_ptys_lock);
}
#endif
@@ -2737,24 +2737,24 @@ static int ptmx_open(struct inode * inode, struct file * filp)
nonseekable_open(inode, filp);
/* find a device that is not in use. */
- down(&allocated_ptys_lock);
+ mutex_lock(&allocated_ptys_lock);
if (!idr_pre_get(&allocated_ptys, GFP_KERNEL)) {
- up(&allocated_ptys_lock);
+ mutex_unlock(&allocated_ptys_lock);
return -ENOMEM;
}
idr_ret = idr_get_new(&allocated_ptys, NULL, &index);
if (idr_ret < 0) {
- up(&allocated_ptys_lock);
+ mutex_unlock(&allocated_ptys_lock);
if (idr_ret == -EAGAIN)
return -ENOMEM;
return -EIO;
}
if (index >= pty_limit) {
idr_remove(&allocated_ptys, index);
- up(&allocated_ptys_lock);
+ mutex_unlock(&allocated_ptys_lock);
return -EIO;
}
- up(&allocated_ptys_lock);
+ mutex_unlock(&allocated_ptys_lock);
mutex_lock(&tty_mutex);
retval = init_dev(ptm_driver, index, &tty);
@@ -2781,9 +2781,9 @@ out1:
release_dev(filp);
return retval;
out:
- down(&allocated_ptys_lock);
+ mutex_lock(&allocated_ptys_lock);
idr_remove(&allocated_ptys, index);
- up(&allocated_ptys_lock);
+ mutex_unlock(&allocated_ptys_lock);
return retval;
}
#endif
@@ -3721,7 +3721,6 @@ static void initialize_tty_struct(struct tty_struct *tty)
tty->buf.head = tty->buf.tail = NULL;
tty_buffer_init(tty);
INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc);
- init_MUTEX(&tty->buf.pty_sem);
mutex_init(&tty->termios_mutex);
init_waitqueue_head(&tty->write_wait);
init_waitqueue_head(&tty->read_wait);
@@ -4048,10 +4047,6 @@ void __init console_init(void)
}
}
-#ifdef CONFIG_VT
-extern int vty_init(void);
-#endif
-
static int __init tty_class_init(void)
{
tty_class = class_create(THIS_MODULE, "tty");
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 7a5badfb7d8..367be917506 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -2400,13 +2400,15 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
{
struct vc_data *vc = vc_cons[fg_console].d;
unsigned char c;
- static unsigned long printing;
+ static DEFINE_SPINLOCK(printing_lock);
const ushort *start;
ushort cnt = 0;
ushort myx;
/* console busy or not yet initialized */
- if (!printable || test_and_set_bit(0, &printing))
+ if (!printable)
+ return;
+ if (!spin_trylock(&printing_lock))
return;
if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1))
@@ -2481,7 +2483,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
notify_update(vc);
quit:
- clear_bit(0, &printing);
+ spin_unlock(&printing_lock);
}
static struct tty_driver *vt_console_device(struct console *c, int *index)
diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c
index 18cdcb3ae1c..1636806ec55 100644
--- a/drivers/firmware/dcdbas.c
+++ b/drivers/firmware/dcdbas.c
@@ -658,4 +658,5 @@ MODULE_DESCRIPTION(DRIVER_DESCRIPTION " (version " DRIVER_VERSION ")");
MODULE_VERSION(DRIVER_VERSION);
MODULE_AUTHOR("Dell Inc.");
MODULE_LICENSE("GPL");
-
+/* Any System or BIOS claiming to be by Dell */
+MODULE_ALIAS("dmi:*:[bs]vnD[Ee][Ll][Ll]*:*");
diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c
index 313c99cbdc6..e880d6c8d89 100644
--- a/drivers/firmware/dmi-id.c
+++ b/drivers/firmware/dmi-id.c
@@ -11,7 +11,6 @@
#include <linux/init.h>
#include <linux/dmi.h>
#include <linux/device.h>
-#include <linux/autoconf.h>
struct dmi_device_attribute{
struct device_attribute dev_attr;
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 74fac0f5c34..bbd28342e77 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -27,15 +27,16 @@ config DEBUG_GPIO
comment "I2C GPIO expanders:"
-config GPIO_PCA9539
- tristate "PCA9539 16-bit I/O port"
+config GPIO_PCA953X
+ tristate "PCA953x I/O ports"
depends on I2C
help
- Say yes here to support the PCA9539 16-bit I/O port. These
- parts are made by NXP and TI.
+ Say yes here to support the PCA9534 (8-bit), PCA9535 (16-bit),
+ PCA9536 (4-bit), PCA9537 (4-bit), PCA9538 (8-bit), and PCA9539
+ (16-bit) I/O ports. These parts are made by NXP and TI.
This driver can also be built as a module. If so, the module
- will be called pca9539.
+ will be called pca953x.
config GPIO_PCF857X
tristate "PCF857x, PCA857x, and PCA967x I2C GPIO expanders"
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 470ecd6aa77..fdde9923cf3 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -5,5 +5,5 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG
obj-$(CONFIG_HAVE_GPIO_LIB) += gpiolib.o
obj-$(CONFIG_GPIO_MCP23S08) += mcp23s08.o
-obj-$(CONFIG_GPIO_PCA9539) += pca9539.o
+obj-$(CONFIG_GPIO_PCA953X) += pca953x.o
obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o
diff --git a/drivers/gpio/pca9539.c b/drivers/gpio/pca9539.c
deleted file mode 100644
index 3e85c92a7d5..00000000000
--- a/drivers/gpio/pca9539.c
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * pca9539.c - 16-bit I/O port with interrupt and reset
- *
- * Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>
- * Copyright (C) 2007 Marvell International Ltd.
- *
- * Derived from drivers/i2c/chips/pca9539.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/i2c/pca9539.h>
-
-#include <asm/gpio.h>
-
-
-#define NR_PCA9539_GPIOS 16
-
-#define PCA9539_INPUT 0
-#define PCA9539_OUTPUT 2
-#define PCA9539_INVERT 4
-#define PCA9539_DIRECTION 6
-
-struct pca9539_chip {
- unsigned gpio_start;
- uint16_t reg_output;
- uint16_t reg_direction;
-
- struct i2c_client *client;
- struct gpio_chip gpio_chip;
-};
-
-/* NOTE: we can't currently rely on fault codes to come from SMBus
- * calls, so we map all errors to EIO here and return zero otherwise.
- */
-static int pca9539_write_reg(struct pca9539_chip *chip, int reg, uint16_t val)
-{
- if (i2c_smbus_write_word_data(chip->client, reg, val) < 0)
- return -EIO;
- else
- return 0;
-}
-
-static int pca9539_read_reg(struct pca9539_chip *chip, int reg, uint16_t *val)
-{
- int ret;
-
- ret = i2c_smbus_read_word_data(chip->client, reg);
- if (ret < 0) {
- dev_err(&chip->client->dev, "failed reading register\n");
- return -EIO;
- }
-
- *val = (uint16_t)ret;
- return 0;
-}
-
-static int pca9539_gpio_direction_input(struct gpio_chip *gc, unsigned off)
-{
- struct pca9539_chip *chip;
- uint16_t reg_val;
- int ret;
-
- chip = container_of(gc, struct pca9539_chip, gpio_chip);
-
- reg_val = chip->reg_direction | (1u << off);
- ret = pca9539_write_reg(chip, PCA9539_DIRECTION, reg_val);
- if (ret)
- return ret;
-
- chip->reg_direction = reg_val;
- return 0;
-}
-
-static int pca9539_gpio_direction_output(struct gpio_chip *gc,
- unsigned off, int val)
-{
- struct pca9539_chip *chip;
- uint16_t reg_val;
- int ret;
-
- chip = container_of(gc, struct pca9539_chip, gpio_chip);
-
- /* set output level */
- if (val)
- reg_val = chip->reg_output | (1u << off);
- else
- reg_val = chip->reg_output & ~(1u << off);
-
- ret = pca9539_write_reg(chip, PCA9539_OUTPUT, reg_val);
- if (ret)
- return ret;
-
- chip->reg_output = reg_val;
-
- /* then direction */
- reg_val = chip->reg_direction & ~(1u << off);
- ret = pca9539_write_reg(chip, PCA9539_DIRECTION, reg_val);
- if (ret)
- return ret;
-
- chip->reg_direction = reg_val;
- return 0;
-}
-
-static int pca9539_gpio_get_value(struct gpio_chip *gc, unsigned off)
-{
- struct pca9539_chip *chip;
- uint16_t reg_val;
- int ret;
-
- chip = container_of(gc, struct pca9539_chip, gpio_chip);
-
- ret = pca9539_read_reg(chip, PCA9539_INPUT, &reg_val);
- if (ret < 0) {
- /* NOTE: diagnostic already emitted; that's all we should
- * do unless gpio_*_value_cansleep() calls become different
- * from their nonsleeping siblings (and report faults).
- */
- return 0;
- }
-
- return (reg_val & (1u << off)) ? 1 : 0;
-}
-
-static void pca9539_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
-{
- struct pca9539_chip *chip;
- uint16_t reg_val;
- int ret;
-
- chip = container_of(gc, struct pca9539_chip, gpio_chip);
-
- if (val)
- reg_val = chip->reg_output | (1u << off);
- else
- reg_val = chip->reg_output & ~(1u << off);
-
- ret = pca9539_write_reg(chip, PCA9539_OUTPUT, reg_val);
- if (ret)
- return;
-
- chip->reg_output = reg_val;
-}
-
-static int pca9539_init_gpio(struct pca9539_chip *chip)
-{
- struct gpio_chip *gc;
-
- gc = &chip->gpio_chip;
-
- gc->direction_input = pca9539_gpio_direction_input;
- gc->direction_output = pca9539_gpio_direction_output;
- gc->get = pca9539_gpio_get_value;
- gc->set = pca9539_gpio_set_value;
-
- gc->base = chip->gpio_start;
- gc->ngpio = NR_PCA9539_GPIOS;
- gc->label = "pca9539";
-
- return gpiochip_add(gc);
-}
-
-static int __devinit pca9539_probe(struct i2c_client *client)
-{
- struct pca9539_platform_data *pdata;
- struct pca9539_chip *chip;
- int ret;
-
- pdata = client->dev.platform_data;
- if (pdata == NULL)
- return -ENODEV;
-
- chip = kzalloc(sizeof(struct pca9539_chip), GFP_KERNEL);
- if (chip == NULL)
- return -ENOMEM;
-
- chip->client = client;
-
- chip->gpio_start = pdata->gpio_base;
-
- /* initialize cached registers from their original values.
- * we can't share this chip with another i2c master.
- */
- ret = pca9539_read_reg(chip, PCA9539_OUTPUT, &chip->reg_output);
- if (ret)
- goto out_failed;
-
- ret = pca9539_read_reg(chip, PCA9539_DIRECTION, &chip->reg_direction);
- if (ret)
- goto out_failed;
-
- /* set platform specific polarity inversion */
- ret = pca9539_write_reg(chip, PCA9539_INVERT, pdata->invert);
- if (ret)
- goto out_failed;
-
- ret = pca9539_init_gpio(chip);
- if (ret)
- goto out_failed;
-
- if (pdata->setup) {
- ret = pdata->setup(client, chip->gpio_chip.base,
- chip->gpio_chip.ngpio, pdata->context);
- if (ret < 0)
- dev_warn(&client->dev, "setup failed, %d\n", ret);
- }
-
- i2c_set_clientdata(client, chip);
- return 0;
-
-out_failed:
- kfree(chip);
- return ret;
-}
-
-static int pca9539_remove(struct i2c_client *client)
-{
- struct pca9539_platform_data *pdata = client->dev.platform_data;
- struct pca9539_chip *chip = i2c_get_clientdata(client);
- int ret = 0;
-
- if (pdata->teardown) {
- ret = pdata->teardown(client, chip->gpio_chip.base,
- chip->gpio_chip.ngpio, pdata->context);
- if (ret < 0) {
- dev_err(&client->dev, "%s failed, %d\n",
- "teardown", ret);
- return ret;
- }
- }
-
- ret = gpiochip_remove(&chip->gpio_chip);
- if (ret) {
- dev_err(&client->dev, "%s failed, %d\n",
- "gpiochip_remove()", ret);
- return ret;
- }
-
- kfree(chip);
- return 0;
-}
-
-static struct i2c_driver pca9539_driver = {
- .driver = {
- .name = "pca9539",
- },
- .probe = pca9539_probe,
- .remove = pca9539_remove,
-};
-
-static int __init pca9539_init(void)
-{
- return i2c_add_driver(&pca9539_driver);
-}
-module_init(pca9539_init);
-
-static void __exit pca9539_exit(void)
-{
- i2c_del_driver(&pca9539_driver);
-}
-module_exit(pca9539_exit);
-
-MODULE_AUTHOR("eric miao <eric.miao@marvell.com>");
-MODULE_DESCRIPTION("GPIO expander driver for PCA9539");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
new file mode 100644
index 00000000000..92583cd4bff
--- /dev/null
+++ b/drivers/gpio/pca953x.c
@@ -0,0 +1,308 @@
+/*
+ * pca953x.c - 4/8/16 bit I/O ports
+ *
+ * Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>
+ * Copyright (C) 2007 Marvell International Ltd.
+ *
+ * Derived from drivers/i2c/chips/pca9539.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c/pca953x.h>
+
+#include <asm/gpio.h>
+
+#define PCA953X_INPUT 0
+#define PCA953X_OUTPUT 1
+#define PCA953X_INVERT 2
+#define PCA953X_DIRECTION 3
+
+/* This is temporary - in 2.6.26 i2c_driver_data should replace it. */
+struct pca953x_desc {
+ char name[I2C_NAME_SIZE];
+ unsigned long driver_data;
+};
+
+static const struct pca953x_desc pca953x_descs[] = {
+ { "pca9534", 8, },
+ { "pca9535", 16, },
+ { "pca9536", 4, },
+ { "pca9537", 4, },
+ { "pca9538", 8, },
+ { "pca9539", 16, },
+ /* REVISIT several pca955x parts should work here too */
+};
+
+struct pca953x_chip {
+ unsigned gpio_start;
+ uint16_t reg_output;
+ uint16_t reg_direction;
+
+ struct i2c_client *client;
+ struct gpio_chip gpio_chip;
+};
+
+/* NOTE: we can't currently rely on fault codes to come from SMBus
+ * calls, so we map all errors to EIO here and return zero otherwise.
+ */
+static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val)
+{
+ int ret;
+
+ if (chip->gpio_chip.ngpio <= 8)
+ ret = i2c_smbus_write_byte_data(chip->client, reg, val);
+ else
+ ret = i2c_smbus_write_word_data(chip->client, reg << 1, val);
+
+ if (ret < 0) {
+ dev_err(&chip->client->dev, "failed writing register\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int pca953x_read_reg(struct pca953x_chip *chip, int reg, uint16_t *val)
+{
+ int ret;
+
+ if (chip->gpio_chip.ngpio <= 8)
+ ret = i2c_smbus_read_byte_data(chip->client, reg);
+ else
+ ret = i2c_smbus_read_word_data(chip->client, reg << 1);
+
+ if (ret < 0) {
+ dev_err(&chip->client->dev, "failed reading register\n");
+ return -EIO;
+ }
+
+ *val = (uint16_t)ret;
+ return 0;
+}
+
+static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
+{
+ struct pca953x_chip *chip;
+ uint16_t reg_val;
+ int ret;
+
+ chip = container_of(gc, struct pca953x_chip, gpio_chip);
+
+ reg_val = chip->reg_direction | (1u << off);
+ ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val);
+ if (ret)
+ return ret;
+
+ chip->reg_direction = reg_val;
+ return 0;
+}
+
+static int pca953x_gpio_direction_output(struct gpio_chip *gc,
+ unsigned off, int val)
+{
+ struct pca953x_chip *chip;
+ uint16_t reg_val;
+ int ret;
+
+ chip = container_of(gc, struct pca953x_chip, gpio_chip);
+
+ /* set output level */
+ if (val)
+ reg_val = chip->reg_output | (1u << off);
+ else
+ reg_val = chip->reg_output & ~(1u << off);
+
+ ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val);
+ if (ret)
+ return ret;
+
+ chip->reg_output = reg_val;
+
+ /* then direction */
+ reg_val = chip->reg_direction & ~(1u << off);
+ ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val);
+ if (ret)
+ return ret;
+
+ chip->reg_direction = reg_val;
+ return 0;
+}
+
+static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
+{
+ struct pca953x_chip *chip;
+ uint16_t reg_val;
+ int ret;
+
+ chip = container_of(gc, struct pca953x_chip, gpio_chip);
+
+ ret = pca953x_read_reg(chip, PCA953X_INPUT, &reg_val);
+ if (ret < 0) {
+ /* NOTE: diagnostic already emitted; that's all we should
+ * do unless gpio_*_value_cansleep() calls become different
+ * from their nonsleeping siblings (and report faults).
+ */
+ return 0;
+ }
+
+ return (reg_val & (1u << off)) ? 1 : 0;
+}
+
+static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
+{
+ struct pca953x_chip *chip;
+ uint16_t reg_val;
+ int ret;
+
+ chip = container_of(gc, struct pca953x_chip, gpio_chip);
+
+ if (val)
+ reg_val = chip->reg_output | (1u << off);
+ else
+ reg_val = chip->reg_output & ~(1u << off);
+
+ ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val);
+ if (ret)
+ return;
+
+ chip->reg_output = reg_val;
+}
+
+static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
+{
+ struct gpio_chip *gc;
+
+ gc = &chip->gpio_chip;
+
+ gc->direction_input = pca953x_gpio_direction_input;
+ gc->direction_output = pca953x_gpio_direction_output;
+ gc->get = pca953x_gpio_get_value;
+ gc->set = pca953x_gpio_set_value;
+
+ gc->base = chip->gpio_start;
+ gc->ngpio = gpios;
+ gc->label = chip->client->name;
+}
+
+static int __devinit pca953x_probe(struct i2c_client *client)
+{
+ struct pca953x_platform_data *pdata;
+ struct pca953x_chip *chip;
+ int ret, i;
+ const struct pca953x_desc *id = NULL;
+
+ pdata = client->dev.platform_data;
+ if (pdata == NULL)
+ return -ENODEV;
+
+ /* this loop vanishes when we get i2c_device_id */
+ for (i = 0; i < ARRAY_SIZE(pca953x_descs); i++)
+ if (!strcmp(pca953x_descs[i].name, client->name)) {
+ id = pca953x_descs + i;
+ break;
+ }
+ if (!id)
+ return -ENODEV;
+
+ chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL);
+ if (chip == NULL)
+ return -ENOMEM;
+
+ chip->client = client;
+
+ chip->gpio_start = pdata->gpio_base;
+
+ /* initialize cached registers from their original values.
+ * we can't share this chip with another i2c master.
+ */
+ pca953x_setup_gpio(chip, id->driver_data);
+
+ ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output);
+ if (ret)
+ goto out_failed;
+
+ ret = pca953x_read_reg(chip, PCA953X_DIRECTION, &chip->reg_direction);
+ if (ret)
+ goto out_failed;
+
+ /* set platform specific polarity inversion */
+ ret = pca953x_write_reg(chip, PCA953X_INVERT, pdata->invert);
+ if (ret)
+ goto out_failed;
+
+
+ ret = gpiochip_add(&chip->gpio_chip);
+ if (ret)
+ goto out_failed;
+
+ if (pdata->setup) {
+ ret = pdata->setup(client, chip->gpio_chip.base,
+ chip->gpio_chip.ngpio, pdata->context);
+ if (ret < 0)
+ dev_warn(&client->dev, "setup failed, %d\n", ret);
+ }
+
+ i2c_set_clientdata(client, chip);
+ return 0;
+
+out_failed:
+ kfree(chip);
+ return ret;
+}
+
+static int pca953x_remove(struct i2c_client *client)
+{
+ struct pca953x_platform_data *pdata = client->dev.platform_data;
+ struct pca953x_chip *chip = i2c_get_clientdata(client);
+ int ret = 0;
+
+ if (pdata->teardown) {
+ ret = pdata->teardown(client, chip->gpio_chip.base,
+ chip->gpio_chip.ngpio, pdata->context);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s failed, %d\n",
+ "teardown", ret);
+ return ret;
+ }
+ }
+
+ ret = gpiochip_remove(&chip->gpio_chip);
+ if (ret) {
+ dev_err(&client->dev, "%s failed, %d\n",
+ "gpiochip_remove()", ret);
+ return ret;
+ }
+
+ kfree(chip);
+ return 0;
+}
+
+static struct i2c_driver pca953x_driver = {
+ .driver = {
+ .name = "pca953x",
+ },
+ .probe = pca953x_probe,
+ .remove = pca953x_remove,
+};
+
+static int __init pca953x_init(void)
+{
+ return i2c_add_driver(&pca953x_driver);
+}
+module_init(pca953x_init);
+
+static void __exit pca953x_exit(void)
+{
+ i2c_del_driver(&pca953x_driver);
+}
+module_exit(pca953x_exit);
+
+MODULE_AUTHOR("eric miao <eric.miao@marvell.com>");
+MODULE_DESCRIPTION("GPIO expander driver for PCA953x");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 45b26ed351c..ab8fb257528 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -1009,6 +1009,15 @@ config BLK_DEV_Q40IDE
normally be on; disable it only if you are running a custom hard
drive subsystem through an expansion card.
+config BLK_DEV_PALMCHIP_BK3710
+ tristate "Palmchip bk3710 IDE controller support"
+ depends on ARCH_DAVINCI
+ select BLK_DEV_IDEDMA_PCI
+ help
+ Say Y here if you want to support the onchip IDE controller on the
+ TI DaVinci SoC
+
+
config BLK_DEV_MPC8xx_IDE
tristate "MPC8xx IDE support"
depends on 8xx && (LWMON || IVMS8 || IVML24 || TQM8xxL) && IDE=y && BLK_DEV_IDE=y && !PPC_MERGE
diff --git a/drivers/ide/arm/Makefile b/drivers/ide/arm/Makefile
index 5f63ad21686..936e7b0237f 100644
--- a/drivers/ide/arm/Makefile
+++ b/drivers/ide/arm/Makefile
@@ -2,6 +2,7 @@
obj-$(CONFIG_BLK_DEV_IDE_ICSIDE) += icside.o
obj-$(CONFIG_BLK_DEV_IDE_RAPIDE) += rapide.o
obj-$(CONFIG_BLK_DEV_IDE_BAST) += bast-ide.o
+obj-$(CONFIG_BLK_DEV_PALMCHIP_BK3710) += palm_bk3710.o
ifeq ($(CONFIG_IDE_ARM), m)
obj-m += ide_arm.o
diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c
index fb00f3827ec..e816b0ffcfe 100644
--- a/drivers/ide/arm/icside.c
+++ b/drivers/ide/arm/icside.c
@@ -365,7 +365,7 @@ static void icside_dma_timeout(ide_drive_t *drive)
if (icside_dma_test_irq(drive))
return;
- ide_dump_status(drive, "DMA timeout", HWIF(drive)->INB(IDE_STATUS_REG));
+ ide_dump_status(drive, "DMA timeout", ide_read_status(drive));
icside_dma_end(drive);
}
diff --git a/drivers/ide/arm/palm_bk3710.c b/drivers/ide/arm/palm_bk3710.c
new file mode 100644
index 00000000000..c3069970a01
--- /dev/null
+++ b/drivers/ide/arm/palm_bk3710.c
@@ -0,0 +1,395 @@
+/*
+ * Palmchip bk3710 IDE controller
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2007 MontaVista Software, Inc., <source@mvista.com>
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+/* Offset of the primary interface registers */
+#define IDE_PALM_ATA_PRI_REG_OFFSET 0x1F0
+
+/* Primary Control Offset */
+#define IDE_PALM_ATA_PRI_CTL_OFFSET 0x3F6
+
+/*
+ * PalmChip 3710 IDE Controller UDMA timing structure Definition
+ */
+struct palm_bk3710_udmatiming {
+ unsigned int rptime; /* Ready to pause time */
+ unsigned int cycletime; /* Cycle Time */
+};
+
+#define BK3710_BMICP 0x00
+#define BK3710_BMISP 0x02
+#define BK3710_BMIDTP 0x04
+#define BK3710_BMICS 0x08
+#define BK3710_BMISS 0x0A
+#define BK3710_BMIDTS 0x0C
+#define BK3710_IDETIMP 0x40
+#define BK3710_IDETIMS 0x42
+#define BK3710_SIDETIM 0x44
+#define BK3710_SLEWCTL 0x45
+#define BK3710_IDESTATUS 0x47
+#define BK3710_UDMACTL 0x48
+#define BK3710_UDMATIM 0x4A
+#define BK3710_MISCCTL 0x50
+#define BK3710_REGSTB 0x54
+#define BK3710_REGRCVR 0x58
+#define BK3710_DATSTB 0x5C
+#define BK3710_DATRCVR 0x60
+#define BK3710_DMASTB 0x64
+#define BK3710_DMARCVR 0x68
+#define BK3710_UDMASTB 0x6C
+#define BK3710_UDMATRP 0x70
+#define BK3710_UDMAENV 0x74
+#define BK3710_IORDYTMP 0x78
+#define BK3710_IORDYTMS 0x7C
+
+#include "../ide-timing.h"
+
+static long ide_palm_clk;
+
+static const struct palm_bk3710_udmatiming palm_bk3710_udmatimings[6] = {
+ {160, 240}, /* UDMA Mode 0 */
+ {125, 160}, /* UDMA Mode 1 */
+ {100, 120}, /* UDMA Mode 2 */
+ {100, 90}, /* UDMA Mode 3 */
+ {85, 60}, /* UDMA Mode 4 */
+};
+
+static struct clk *ideclkp;
+
+static void palm_bk3710_setudmamode(void __iomem *base, unsigned int dev,
+ unsigned int mode)
+{
+ u8 tenv, trp, t0;
+ u32 val32;
+ u16 val16;
+
+ /* DMA Data Setup */
+ t0 = (palm_bk3710_udmatimings[mode].cycletime + ide_palm_clk - 1)
+ / ide_palm_clk - 1;
+ tenv = (20 + ide_palm_clk - 1) / ide_palm_clk - 1;
+ trp = (palm_bk3710_udmatimings[mode].rptime + ide_palm_clk - 1)
+ / ide_palm_clk - 1;
+
+ /* udmatim Register */
+ val16 = readw(base + BK3710_UDMATIM) & (dev ? 0xFF0F : 0xFFF0);
+ val16 |= (mode << (dev ? 4 : 0));
+ writew(val16, base + BK3710_UDMATIM);
+
+ /* udmastb Ultra DMA Access Strobe Width */
+ val32 = readl(base + BK3710_UDMASTB) & (0xFF << (dev ? 0 : 8));
+ val32 |= (t0 << (dev ? 8 : 0));
+ writel(val32, base + BK3710_UDMASTB);
+
+ /* udmatrp Ultra DMA Ready to Pause Time */
+ val32 = readl(base + BK3710_UDMATRP) & (0xFF << (dev ? 0 : 8));
+ val32 |= (trp << (dev ? 8 : 0));
+ writel(val32, base + BK3710_UDMATRP);
+
+ /* udmaenv Ultra DMA envelop Time */
+ val32 = readl(base + BK3710_UDMAENV) & (0xFF << (dev ? 0 : 8));
+ val32 |= (tenv << (dev ? 8 : 0));
+ writel(val32, base + BK3710_UDMAENV);
+
+ /* Enable UDMA for Device */
+ val16 = readw(base + BK3710_UDMACTL) | (1 << dev);
+ writew(val16, base + BK3710_UDMACTL);
+}
+
+static void palm_bk3710_setdmamode(void __iomem *base, unsigned int dev,
+ unsigned short min_cycle,
+ unsigned int mode)
+{
+ u8 td, tkw, t0;
+ u32 val32;
+ u16 val16;
+ struct ide_timing *t;
+ int cycletime;
+
+ t = ide_timing_find_mode(mode);
+ cycletime = max_t(int, t->cycle, min_cycle);
+
+ /* DMA Data Setup */
+ t0 = (cycletime + ide_palm_clk - 1) / ide_palm_clk;
+ td = (t->active + ide_palm_clk - 1) / ide_palm_clk;
+ tkw = t0 - td - 1;
+ td -= 1;
+
+ val32 = readl(base + BK3710_DMASTB) & (0xFF << (dev ? 0 : 8));
+ val32 |= (td << (dev ? 8 : 0));
+ writel(val32, base + BK3710_DMASTB);
+
+ val32 = readl(base + BK3710_DMARCVR) & (0xFF << (dev ? 0 : 8));
+ val32 |= (tkw << (dev ? 8 : 0));
+ writel(val32, base + BK3710_DMARCVR);
+
+ /* Disable UDMA for Device */
+ val16 = readw(base + BK3710_UDMACTL) & ~(1 << dev);
+ writew(val16, base + BK3710_UDMACTL);
+}
+
+static void palm_bk3710_setpiomode(void __iomem *base, ide_drive_t *mate,
+ unsigned int dev, unsigned int cycletime,
+ unsigned int mode)
+{
+ u8 t2, t2i, t0;
+ u32 val32;
+ struct ide_timing *t;
+
+ /* PIO Data Setup */
+ t0 = (cycletime + ide_palm_clk - 1) / ide_palm_clk;
+ t2 = (ide_timing_find_mode(XFER_PIO_0 + mode)->active +
+ ide_palm_clk - 1) / ide_palm_clk;
+
+ t2i = t0 - t2 - 1;
+ t2 -= 1;
+
+ val32 = readl(base + BK3710_DATSTB) & (0xFF << (dev ? 0 : 8));
+ val32 |= (t2 << (dev ? 8 : 0));
+ writel(val32, base + BK3710_DATSTB);
+
+ val32 = readl(base + BK3710_DATRCVR) & (0xFF << (dev ? 0 : 8));
+ val32 |= (t2i << (dev ? 8 : 0));
+ writel(val32, base + BK3710_DATRCVR);
+
+ if (mate && mate->present) {
+ u8 mode2 = ide_get_best_pio_mode(mate, 255, 4);
+
+ if (mode2 < mode)
+ mode = mode2;
+ }
+
+ /* TASKFILE Setup */
+ t = ide_timing_find_mode(XFER_PIO_0 + mode);
+ t0 = (t->cyc8b + ide_palm_clk - 1) / ide_palm_clk;
+ t2 = (t->act8b + ide_palm_clk - 1) / ide_palm_clk;
+
+ t2i = t0 - t2 - 1;
+ t2 -= 1;
+
+ val32 = readl(base + BK3710_REGSTB) & (0xFF << (dev ? 0 : 8));
+ val32 |= (t2 << (dev ? 8 : 0));
+ writel(val32, base + BK3710_REGSTB);
+
+ val32 = readl(base + BK3710_REGRCVR) & (0xFF << (dev ? 0 : 8));
+ val32 |= (t2i << (dev ? 8 : 0));
+ writel(val32, base + BK3710_REGRCVR);
+}
+
+static void palm_bk3710_set_dma_mode(ide_drive_t *drive, u8 xferspeed)
+{
+ int is_slave = drive->dn & 1;
+ void __iomem *base = (void *)drive->hwif->dma_base;
+
+ if (xferspeed >= XFER_UDMA_0) {
+ palm_bk3710_setudmamode(base, is_slave,
+ xferspeed - XFER_UDMA_0);
+ } else {
+ palm_bk3710_setdmamode(base, is_slave, drive->id->eide_dma_min,
+ xferspeed);
+ }
+}
+
+static void palm_bk3710_set_pio_mode(ide_drive_t *drive, u8 pio)
+{
+ unsigned int cycle_time;
+ int is_slave = drive->dn & 1;
+ ide_drive_t *mate;
+ void __iomem *base = (void *)drive->hwif->dma_base;
+
+ /*
+ * Obtain the drive PIO data for tuning the Palm Chip registers
+ */
+ cycle_time = ide_pio_cycle_time(drive, pio);
+ mate = ide_get_paired_drive(drive);
+ palm_bk3710_setpiomode(base, mate, is_slave, cycle_time, pio);
+}
+
+static void __devinit palm_bk3710_chipinit(void __iomem *base)
+{
+ /*
+ * enable the reset_en of ATA controller so that when ata signals
+ * are brought out, by writing into device config. at that
+ * time por_n signal should not be 'Z' and have a stable value.
+ */
+ writel(0x0300, base + BK3710_MISCCTL);
+
+ /* wait for some time and deassert the reset of ATA Device. */
+ mdelay(100);
+
+ /* Deassert the Reset */
+ writel(0x0200, base + BK3710_MISCCTL);
+
+ /*
+ * Program the IDETIMP Register Value based on the following assumptions
+ *
+ * (ATA_IDETIMP_IDEEN , ENABLE ) |
+ * (ATA_IDETIMP_SLVTIMEN , DISABLE) |
+ * (ATA_IDETIMP_RDYSMPL , 70NS) |
+ * (ATA_IDETIMP_RDYRCVRY , 50NS) |
+ * (ATA_IDETIMP_DMAFTIM1 , PIOCOMP) |
+ * (ATA_IDETIMP_PREPOST1 , DISABLE) |
+ * (ATA_IDETIMP_RDYSEN1 , DISABLE) |
+ * (ATA_IDETIMP_PIOFTIM1 , DISABLE) |
+ * (ATA_IDETIMP_DMAFTIM0 , PIOCOMP) |
+ * (ATA_IDETIMP_PREPOST0 , DISABLE) |
+ * (ATA_IDETIMP_RDYSEN0 , DISABLE) |
+ * (ATA_IDETIMP_PIOFTIM0 , DISABLE)
+ */
+ writew(0xB388, base + BK3710_IDETIMP);
+
+ /*
+ * Configure SIDETIM Register
+ * (ATA_SIDETIM_RDYSMPS1 ,120NS ) |
+ * (ATA_SIDETIM_RDYRCYS1 ,120NS )
+ */
+ writeb(0, base + BK3710_SIDETIM);
+
+ /*
+ * UDMACTL Ultra-ATA DMA Control
+ * (ATA_UDMACTL_UDMAP1 , 0 ) |
+ * (ATA_UDMACTL_UDMAP0 , 0 )
+ *
+ */
+ writew(0, base + BK3710_UDMACTL);
+
+ /*
+ * MISCCTL Miscellaneous Conrol Register
+ * (ATA_MISCCTL_RSTMODEP , 1) |
+ * (ATA_MISCCTL_RESETP , 0) |
+ * (ATA_MISCCTL_TIMORIDE , 1)
+ */
+ writel(0x201, base + BK3710_MISCCTL);
+
+ /*
+ * IORDYTMP IORDY Timer for Primary Register
+ * (ATA_IORDYTMP_IORDYTMP , 0xffff )
+ */
+ writel(0xFFFF, base + BK3710_IORDYTMP);
+
+ /*
+ * Configure BMISP Register
+ * (ATA_BMISP_DMAEN1 , DISABLE ) |
+ * (ATA_BMISP_DMAEN0 , DISABLE ) |
+ * (ATA_BMISP_IORDYINT , CLEAR) |
+ * (ATA_BMISP_INTRSTAT , CLEAR) |
+ * (ATA_BMISP_DMAERROR , CLEAR)
+ */
+ writew(0, base + BK3710_BMISP);
+
+ palm_bk3710_setpiomode(base, NULL, 0, 600, 0);
+ palm_bk3710_setpiomode(base, NULL, 1, 600, 0);
+}
+static int __devinit palm_bk3710_probe(struct platform_device *pdev)
+{
+ hw_regs_t ide_ctlr_info;
+ int index = 0;
+ int pribase;
+ struct clk *clkp;
+ struct resource *mem, *irq;
+ ide_hwif_t *hwif;
+ void __iomem *base;
+
+ clkp = clk_get(NULL, "IDECLK");
+ if (IS_ERR(clkp))
+ return -ENODEV;
+
+ ideclkp = clkp;
+ clk_enable(ideclkp);
+ ide_palm_clk = clk_get_rate(ideclkp)/100000;
+ ide_palm_clk = (10000/ide_palm_clk) + 1;
+ /* Register the IDE interface with Linux ATA Interface */
+ memset(&ide_ctlr_info, 0, sizeof(ide_ctlr_info));
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (mem == NULL) {
+ printk(KERN_ERR "failed to get memory region resource\n");
+ return -ENODEV;
+ }
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (irq == NULL) {
+ printk(KERN_ERR "failed to get IRQ resource\n");
+ return -ENODEV;
+ }
+
+ base = (void *)mem->start;
+
+ /* Configure the Palm Chip controller */
+ palm_bk3710_chipinit(base);
+
+ pribase = mem->start + IDE_PALM_ATA_PRI_REG_OFFSET;
+ for (index = 0; index < IDE_NR_PORTS - 2; index++)
+ ide_ctlr_info.io_ports[index] = pribase + index;
+ ide_ctlr_info.io_ports[IDE_CONTROL_OFFSET] = mem->start +
+ IDE_PALM_ATA_PRI_CTL_OFFSET;
+ ide_ctlr_info.irq = irq->start;
+ ide_ctlr_info.chipset = ide_palm3710;
+
+ if (ide_register_hw(&ide_ctlr_info, NULL, &hwif) < 0) {
+ printk(KERN_WARNING "Palm Chip BK3710 IDE Register Fail\n");
+ return -ENODEV;
+ }
+
+ hwif->set_pio_mode = &palm_bk3710_set_pio_mode;
+ hwif->set_dma_mode = &palm_bk3710_set_dma_mode;
+ hwif->mmio = 1;
+ default_hwif_mmiops(hwif);
+ hwif->cbl = ATA_CBL_PATA80;
+ hwif->ultra_mask = 0x1f; /* Ultra DMA Mode 4 Max
+ (input clk 99MHz) */
+ hwif->mwdma_mask = 0x7;
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+
+ ide_setup_dma(hwif, mem->start);
+
+ return 0;
+}
+
+static struct platform_driver platform_bk_driver = {
+ .driver = {
+ .name = "palm_bk3710",
+ },
+ .probe = palm_bk3710_probe,
+ .remove = NULL,
+};
+
+static int __init palm_bk3710_init(void)
+{
+ return platform_driver_register(&platform_bk_driver);
+}
+
+module_init(palm_bk3710_init);
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c
index 00587a8c2ba..e79bf8f9b7d 100644
--- a/drivers/ide/cris/ide-cris.c
+++ b/drivers/ide/cris/ide-cris.c
@@ -753,6 +753,25 @@ static void cris_set_dma_mode(ide_drive_t *drive, const u8 speed)
cris_ide_set_speed(TYPE_DMA, 0, strobe, hold);
}
+static void __init cris_setup_ports(hw_regs_t *hw, unsigned long base)
+{
+ int i;
+
+ memset(hw, 0, sizeof(*hw));
+
+ for (i = 0; i <= 7; i++)
+ hw->io_ports[i] = base + cris_ide_reg_addr(i, 0, 1);
+
+ /*
+ * the IDE control register is at ATA address 6,
+ * with CS1 active instead of CS0
+ */
+ hw->io_ports[IDE_CONTROL_OFFSET] = base + cris_ide_reg_addr(6, 1, 0);
+
+ hw->irq = ide_default_irq(0);
+ hw->ack_intr = cris_ide_ack_intr;
+}
+
static const struct ide_port_info cris_port_info __initdata = {
.chipset = ide_etrax100,
.host_flags = IDE_HFLAG_NO_ATAPI_DMA |
@@ -765,24 +784,16 @@ static const struct ide_port_info cris_port_info __initdata = {
static int __init init_e100_ide(void)
{
hw_regs_t hw;
- int ide_offsets[IDE_NR_PORTS], h, i;
+ int h;
u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
printk("ide: ETRAX FS built-in ATA DMA controller\n");
- for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
- ide_offsets[i] = cris_ide_reg_addr(i, 0, 1);
-
- /* the IDE control register is at ATA address 6, with CS1 active instead of CS0 */
- ide_offsets[IDE_CONTROL_OFFSET] = cris_ide_reg_addr(6, 1, 0);
-
for (h = 0; h < 4; h++) {
ide_hwif_t *hwif = NULL;
- ide_setup_ports(&hw, cris_ide_base_address(h),
- ide_offsets,
- 0, 0, cris_ide_ack_intr,
- ide_default_irq(0));
+ cris_setup_ports(&hw, cris_ide_base_address(h));
+
hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
if (hwif == NULL)
continue;
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
index 25aaeae1e83..e07b189f3ec 100644
--- a/drivers/ide/ide-acpi.c
+++ b/drivers/ide/ide-acpi.c
@@ -171,7 +171,7 @@ err:
static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif)
{
struct device *dev = hwif->gendev.parent;
- acpi_handle dev_handle;
+ acpi_handle uninitialized_var(dev_handle);
acpi_integer pcidevfn;
acpi_handle chan_handle;
int err;
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index ee4d458e2bb..5e42c19a03e 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -295,7 +295,8 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
int stat, err, sense_key;
/* Check for errors. */
- stat = HWIF(drive)->INB(IDE_STATUS_REG);
+ stat = ide_read_status(drive);
+
if (stat_ret)
*stat_ret = stat;
@@ -303,7 +304,7 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
return 0;
/* Get the IDE error register. */
- err = HWIF(drive)->INB(IDE_ERROR_REG);
+ err = ide_read_error(drive);
sense_key = err >> 4;
if (rq == NULL) {
@@ -692,7 +693,7 @@ int ide_cd_check_ireason(ide_drive_t *drive, int len, int ireason, int rw)
/* Some drives (ASUS) seem to tell us that status
* info is available. just get it and ignore.
*/
- (void) HWIF(drive)->INB(IDE_STATUS_REG);
+ (void)ide_read_status(drive);
return 0;
} else {
/* Drive wants a command packet, or invalid ireason... */
@@ -1326,7 +1327,7 @@ ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block)
if (blk_fs_request(rq)) {
if (info->cd_flags & IDE_CD_FLAG_SEEKING) {
unsigned long elapsed = jiffies - info->start_seek;
- int stat = HWIF(drive)->INB(IDE_STATUS_REG);
+ int stat = ide_read_status(drive);
if ((stat & SEEK_STAT) != SEEK_STAT) {
if (elapsed < IDECD_SEEK_TIMEOUT) {
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index 3cf59f2c392..a4bb32883c6 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -147,7 +147,8 @@ ide_startstop_t ide_dma_intr (ide_drive_t *drive)
u8 stat = 0, dma_stat = 0;
dma_stat = HWIF(drive)->ide_dma_end(drive);
- stat = HWIF(drive)->INB(IDE_STATUS_REG); /* get drive status */
+ stat = ide_read_status(drive);
+
if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
if (!dma_stat) {
struct request *rq = HWGROUP(drive)->rq;
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index f8fe6ee128f..faf22d716f8 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -465,7 +465,7 @@ static void idefloppy_retry_pc(ide_drive_t *drive)
idefloppy_pc_t *pc;
struct request *rq;
- (void)drive->hwif->INB(IDE_ERROR_REG);
+ (void)ide_read_error(drive);
pc = idefloppy_next_pc_storage(drive);
rq = idefloppy_next_rq_storage(drive);
idefloppy_create_request_sense_cmd(pc);
@@ -501,7 +501,7 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
}
/* Clear the interrupt */
- stat = drive->hwif->INB(IDE_STATUS_REG);
+ stat = ide_read_status(drive);
/* No more interrupts */
if ((stat & DRQ_STAT) == 0) {
@@ -1246,7 +1246,7 @@ static int idefloppy_get_format_progress(ide_drive_t *drive, int __user *arg)
u8 stat;
local_irq_save(flags);
- stat = drive->hwif->INB(IDE_STATUS_REG);
+ stat = ide_read_status(drive);
local_irq_restore(flags);
progress_indication = ((stat & SEEK_STAT) == 0) ? 0 : 0x10000;
diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c
index be469dbbe8f..709b9e4d287 100644
--- a/drivers/ide/ide-generic.c
+++ b/drivers/ide/ide-generic.c
@@ -20,8 +20,14 @@ static int __init ide_generic_init(void)
if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
ide_get_lock(NULL, NULL); /* for atari only */
- for (i = 0; i < MAX_HWIFS; i++)
- idx[i] = ide_hwifs[i].present ? 0xff : i;
+ for (i = 0; i < MAX_HWIFS; i++) {
+ ide_hwif_t *hwif = &ide_hwifs[i];
+
+ if (hwif->io_ports[IDE_DATA_OFFSET] && !hwif->present)
+ idx[i] = i;
+ else
+ idx[i] = 0xff;
+ }
ide_device_add_all(idx, NULL);
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 4bddef0c0b9..3addbe478d2 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -466,7 +466,7 @@ static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq, u8
return ide_stopped;
}
- if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))
+ if (ide_read_status(drive) & (BUSY_STAT | DRQ_STAT))
rq->errors |= ERROR_RESET;
if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
@@ -493,7 +493,7 @@ static ide_startstop_t ide_atapi_error(ide_drive_t *drive, struct request *rq, u
/* add decoding error stuff */
}
- if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))
+ if (ide_read_status(drive) & (BUSY_STAT | DRQ_STAT))
/* force an abort */
hwif->OUTB(WIN_IDLEIMMEDIATE, IDE_COMMAND_REG);
@@ -821,9 +821,8 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
#ifdef DEBUG
printk("%s: DRIVE_CMD (null)\n", drive->name);
#endif
- ide_end_drive_cmd(drive,
- hwif->INB(IDE_STATUS_REG),
- hwif->INB(IDE_ERROR_REG));
+ ide_end_drive_cmd(drive, ide_read_status(drive), ide_read_error(drive));
+
return ide_stopped;
}
@@ -1231,7 +1230,7 @@ static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
printk(KERN_WARNING "%s: DMA timeout error\n", drive->name);
(void)HWIF(drive)->ide_dma_end(drive);
ret = ide_error(drive, "dma timeout error",
- hwif->INB(IDE_STATUS_REG));
+ ide_read_status(drive));
} else {
printk(KERN_WARNING "%s: DMA timeout retry\n", drive->name);
hwif->dma_timeout(drive);
@@ -1355,7 +1354,8 @@ void ide_timer_expiry (unsigned long data)
startstop = ide_dma_timeout_retry(drive, wait);
} else
startstop =
- ide_error(drive, "irq timeout", hwif->INB(IDE_STATUS_REG));
+ ide_error(drive, "irq timeout",
+ ide_read_status(drive));
}
drive->service_time = jiffies - drive->service_start;
spin_lock_irq(&ide_lock);
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index a95178f5e1b..c32e759df20 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -430,10 +430,10 @@ int drive_is_ready (ide_drive_t *drive)
* about possible isa-pnp and pci-pnp issues yet.
*/
if (IDE_CONTROL_REG)
- stat = hwif->INB(IDE_ALTSTATUS_REG);
+ stat = ide_read_altstatus(drive);
else
/* Note: this may clear a pending IRQ!! */
- stat = hwif->INB(IDE_STATUS_REG);
+ stat = ide_read_status(drive);
if (stat & BUSY_STAT)
/* drive busy: definitely not interrupting */
@@ -458,23 +458,24 @@ EXPORT_SYMBOL(drive_is_ready);
*/
static int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout, u8 *rstat)
{
- ide_hwif_t *hwif = drive->hwif;
unsigned long flags;
int i;
u8 stat;
udelay(1); /* spec allows drive 400ns to assert "BUSY" */
- if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+ stat = ide_read_status(drive);
+
+ if (stat & BUSY_STAT) {
local_irq_set(flags);
timeout += jiffies;
- while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+ while ((stat = ide_read_status(drive)) & BUSY_STAT) {
if (time_after(jiffies, timeout)) {
/*
* One last read after the timeout in case
* heavy interrupt load made us not make any
* progress during the timeout..
*/
- stat = hwif->INB(IDE_STATUS_REG);
+ stat = ide_read_status(drive);
if (!(stat & BUSY_STAT))
break;
@@ -494,7 +495,9 @@ static int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad, unsigned long ti
*/
for (i = 0; i < 10; i++) {
udelay(1);
- if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), good, bad)) {
+ stat = ide_read_status(drive);
+
+ if (OK_STAT(stat, good, bad)) {
*rstat = stat;
return 0;
}
@@ -617,6 +620,7 @@ int ide_driveid_update(ide_drive_t *drive)
ide_hwif_t *hwif = drive->hwif;
struct hd_driveid *id;
unsigned long timeout, flags;
+ u8 stat;
/*
* Re-read drive->id for possible DMA mode
@@ -633,10 +637,15 @@ int ide_driveid_update(ide_drive_t *drive)
SELECT_MASK(drive, 0);
return 0; /* drive timed-out */
}
+
msleep(50); /* give drive a breather */
- } while (hwif->INB(IDE_ALTSTATUS_REG) & BUSY_STAT);
+ stat = ide_read_altstatus(drive);
+ } while (stat & BUSY_STAT);
+
msleep(50); /* wait for IRQ and DRQ_STAT */
- if (!OK_STAT(hwif->INB(IDE_STATUS_REG),DRQ_STAT,BAD_R_STAT)) {
+ stat = ide_read_status(drive);
+
+ if (!OK_STAT(stat, DRQ_STAT, BAD_R_STAT)) {
SELECT_MASK(drive, 0);
printk("%s: CHECK for good STATUS\n", drive->name);
return 0;
@@ -649,7 +658,7 @@ int ide_driveid_update(ide_drive_t *drive)
return 0;
}
ata_input_data(drive, id, SECTOR_WORDS);
- (void) hwif->INB(IDE_STATUS_REG); /* clear drive IRQ */
+ (void)ide_read_status(drive); /* clear drive IRQ */
local_irq_enable();
local_irq_restore(flags);
ide_fix_driveid(id);
@@ -850,17 +859,16 @@ static ide_startstop_t do_reset1 (ide_drive_t *, int);
static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
{
ide_hwgroup_t *hwgroup = HWGROUP(drive);
- ide_hwif_t *hwif = HWIF(drive);
u8 stat;
SELECT_DRIVE(drive);
udelay (10);
+ stat = ide_read_status(drive);
- if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG), 0, BUSY_STAT)) {
+ if (OK_STAT(stat, 0, BUSY_STAT))
printk("%s: ATAPI reset complete\n", drive->name);
- } else {
+ else {
if (time_before(jiffies, hwgroup->poll_timeout)) {
- BUG_ON(HWGROUP(drive)->handler != NULL);
ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
/* continue polling */
return ide_started;
@@ -898,9 +906,10 @@ static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
}
}
- if (!OK_STAT(tmp = hwif->INB(IDE_STATUS_REG), 0, BUSY_STAT)) {
+ tmp = ide_read_status(drive);
+
+ if (!OK_STAT(tmp, 0, BUSY_STAT)) {
if (time_before(jiffies, hwgroup->poll_timeout)) {
- BUG_ON(HWGROUP(drive)->handler != NULL);
ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
/* continue polling */
return ide_started;
@@ -909,7 +918,9 @@ static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
drive->failures++;
} else {
printk("%s: reset: ", hwif->name);
- if ((tmp = hwif->INB(IDE_ERROR_REG)) == 1) {
+ tmp = ide_read_error(drive);
+
+ if (tmp == 1) {
printk("success\n");
drive->failures = 0;
} else {
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
index b42940d8bf7..1ff676cc647 100644
--- a/drivers/ide/ide-lib.c
+++ b/drivers/ide/ide-lib.c
@@ -578,7 +578,7 @@ u8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat)
}
printk("}\n");
if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
- err = drive->hwif->INB(IDE_ERROR_REG);
+ err = ide_read_error(drive);
printk("%s: %s: error=0x%02x ", drive->name, msg, err);
if (drive->media == ide_disk)
ide_dump_ata_error(drive, err);
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 9c07bdb68d1..6daea896c5d 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -264,8 +264,7 @@ err_misc:
static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
{
ide_hwif_t *hwif = HWIF(drive);
- int rc;
- unsigned long hd_status;
+ int use_altstatus = 0, rc;
unsigned long timeout;
u8 s = 0, a = 0;
@@ -273,19 +272,17 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
msleep(50);
if (IDE_CONTROL_REG) {
- a = hwif->INB(IDE_ALTSTATUS_REG);
- s = hwif->INB(IDE_STATUS_REG);
- if ((a ^ s) & ~INDEX_STAT) {
- printk(KERN_INFO "%s: probing with STATUS(0x%02x) instead of "
- "ALTSTATUS(0x%02x)\n", drive->name, s, a);
+ a = ide_read_altstatus(drive);
+ s = ide_read_status(drive);
+ if ((a ^ s) & ~INDEX_STAT)
/* ancient Seagate drives, broken interfaces */
- hd_status = IDE_STATUS_REG;
- } else {
+ printk(KERN_INFO "%s: probing with STATUS(0x%02x) "
+ "instead of ALTSTATUS(0x%02x)\n",
+ drive->name, s, a);
+ else
/* use non-intrusive polling */
- hd_status = IDE_ALTSTATUS_REG;
- }
- } else
- hd_status = IDE_STATUS_REG;
+ use_altstatus = 1;
+ }
/* set features register for atapi
* identify command to be sure of reply
@@ -306,11 +303,15 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
}
/* give drive a breather */
msleep(50);
- } while ((hwif->INB(hd_status)) & BUSY_STAT);
+ s = use_altstatus ? ide_read_altstatus(drive)
+ : ide_read_status(drive);
+ } while (s & BUSY_STAT);
/* wait for IRQ and DRQ_STAT */
msleep(50);
- if (OK_STAT((hwif->INB(IDE_STATUS_REG)), DRQ_STAT, BAD_R_STAT)) {
+ s = ide_read_status(drive);
+
+ if (OK_STAT(s, DRQ_STAT, BAD_R_STAT)) {
unsigned long flags;
/* local CPU only; some systems need this */
@@ -320,7 +321,7 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
/* drive responded with ID */
rc = 0;
/* clear drive IRQ */
- (void) hwif->INB(IDE_STATUS_REG);
+ (void)ide_read_status(drive);
local_irq_restore(flags);
} else {
/* drive refused ID */
@@ -367,7 +368,7 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd)
ide_set_irq(drive, 0);
/* clear drive IRQ */
- (void) hwif->INB(IDE_STATUS_REG);
+ (void)ide_read_status(drive);
udelay(5);
irq = probe_irq_off(cookie);
if (!hwif->irq) {
@@ -455,7 +456,9 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
return 3;
}
- if (OK_STAT((hwif->INB(IDE_STATUS_REG)), READY_STAT, BUSY_STAT) ||
+ stat = ide_read_status(drive);
+
+ if (OK_STAT(stat, READY_STAT, BUSY_STAT) ||
drive->present || cmd == WIN_PIDENTIFY) {
/* send cmd and wait */
if ((rc = try_to_identify(drive, cmd))) {
@@ -463,7 +466,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
rc = try_to_identify(drive,cmd);
}
- stat = hwif->INB(IDE_STATUS_REG);
+ stat = ide_read_status(drive);
if (stat == (BUSY_STAT | READY_STAT))
return 4;
@@ -482,7 +485,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
}
/* ensure drive IRQ is clear */
- stat = hwif->INB(IDE_STATUS_REG);
+ stat = ide_read_status(drive);
if (rc == 1)
printk(KERN_ERR "%s: no response (status = 0x%02x)\n",
@@ -496,7 +499,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
SELECT_DRIVE(&hwif->drives[0]);
msleep(50);
/* ensure drive irq is clear */
- (void) hwif->INB(IDE_STATUS_REG);
+ (void)ide_read_status(drive);
}
return rc;
}
@@ -521,7 +524,7 @@ static void enable_nest (ide_drive_t *drive)
msleep(50);
- stat = hwif->INB(IDE_STATUS_REG);
+ stat = ide_read_status(drive);
if (!OK_STAT(stat, 0, BAD_STAT))
printk(KERN_CONT "failed (status = 0x%02x)\n", stat);
@@ -1046,7 +1049,7 @@ static int init_irq (ide_hwif_t *hwif)
*/
if (!match || match->irq != hwif->irq) {
int sa = 0;
-#if defined(__mc68000__) || defined(CONFIG_APUS)
+#if defined(__mc68000__)
sa = IRQF_SHARED;
#endif /* __mc68000__ || CONFIG_APUS */
@@ -1069,7 +1072,7 @@ static int init_irq (ide_hwif_t *hwif)
hwif->rqsize = 65536;
}
-#if !defined(__mc68000__) && !defined(CONFIG_APUS)
+#if !defined(__mc68000__)
printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name,
hwif->io_ports[IDE_DATA_OFFSET],
hwif->io_ports[IDE_DATA_OFFSET]+7,
@@ -1077,7 +1080,7 @@ static int init_irq (ide_hwif_t *hwif)
#else
printk("%s at 0x%08lx on irq %d", hwif->name,
hwif->io_ports[IDE_DATA_OFFSET], hwif->irq);
-#endif /* __mc68000__ && CONFIG_APUS */
+#endif /* __mc68000__ */
if (match)
printk(" (%sed with %s)",
hwif->sharing_irq ? "shar" : "serializ", match->name);
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index 975c0ff0f43..bab88ca7f7e 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -65,6 +65,7 @@ static int proc_ide_read_imodel
case ide_4drives: name = "4drives"; break;
case ide_pmac: name = "mac-io"; break;
case ide_au1xxx: name = "au1xxx"; break;
+ case ide_palm3710: name = "palm3710"; break;
case ide_etrax100: name = "etrax100"; break;
case ide_acorn: name = "acorn"; break;
default: name = "(unknown)"; break;
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index bf40d8c824a..49dd2e7bae7 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -15,7 +15,7 @@
* Documentation/ide/ChangeLog.ide-tape.1995-2002
*/
-#define IDETAPE_VERSION "1.19"
+#define IDETAPE_VERSION "1.20"
#include <linux/module.h>
#include <linux/types.h>
@@ -39,63 +39,70 @@
#include <scsi/scsi.h>
#include <asm/byteorder.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
+#include <linux/irq.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
#include <asm/unaligned.h>
#include <linux/mtio.h>
+enum {
+ /* output errors only */
+ DBG_ERR = (1 << 0),
+ /* output all sense key/asc */
+ DBG_SENSE = (1 << 1),
+ /* info regarding all chrdev-related procedures */
+ DBG_CHRDEV = (1 << 2),
+ /* all remaining procedures */
+ DBG_PROCS = (1 << 3),
+ /* buffer alloc info (pc_stack & rq_stack) */
+ DBG_PCRQ_STACK = (1 << 4),
+};
+
+/* define to see debug info */
+#define IDETAPE_DEBUG_LOG 0
+
+#if IDETAPE_DEBUG_LOG
+#define debug_log(lvl, fmt, args...) \
+{ \
+ if (tape->debug_mask & lvl) \
+ printk(KERN_INFO "ide-tape: " fmt, ## args); \
+}
+#else
+#define debug_log(lvl, fmt, args...) do {} while (0)
+#endif
+
/**************************** Tunable parameters *****************************/
/*
- * Pipelined mode parameters.
+ * Pipelined mode parameters.
*
- * We try to use the minimum number of stages which is enough to
- * keep the tape constantly streaming. To accomplish that, we implement
- * a feedback loop around the maximum number of stages:
+ * We try to use the minimum number of stages which is enough to keep the tape
+ * constantly streaming. To accomplish that, we implement a feedback loop around
+ * the maximum number of stages:
*
- * We start from MIN maximum stages (we will not even use MIN stages
- * if we don't need them), increment it by RATE*(MAX-MIN)
- * whenever we sense that the pipeline is empty, until we reach
- * the optimum value or until we reach MAX.
+ * We start from MIN maximum stages (we will not even use MIN stages if we don't
+ * need them), increment it by RATE*(MAX-MIN) whenever we sense that the
+ * pipeline is empty, until we reach the optimum value or until we reach MAX.
*
- * Setting the following parameter to 0 is illegal: the pipelined mode
- * cannot be disabled (calculate_speeds() divides by tape->max_stages.)
+ * Setting the following parameter to 0 is illegal: the pipelined mode cannot be
+ * disabled (idetape_calculate_speeds() divides by tape->max_stages.)
*/
#define IDETAPE_MIN_PIPELINE_STAGES 1
#define IDETAPE_MAX_PIPELINE_STAGES 400
#define IDETAPE_INCREASE_STAGES_RATE 20
/*
- * The following are used to debug the driver:
- *
- * Setting IDETAPE_DEBUG_LOG to 1 will log driver flow control.
+ * After each failed packet command we issue a request sense command and retry
+ * the packet command IDETAPE_MAX_PC_RETRIES times.
*
- * Setting them to 0 will restore normal operation mode:
- *
- * 1. Disable logging normal successful operations.
- * 2. Disable self-sanity checks.
- * 3. Errors will still be logged, of course.
- *
- * All the #if DEBUG code will be removed some day, when the driver
- * is verified to be stable enough. This will make it much more
- * esthetic.
- */
-#define IDETAPE_DEBUG_LOG 0
-
-/*
- * After each failed packet command we issue a request sense command
- * and retry the packet command IDETAPE_MAX_PC_RETRIES times.
- *
- * Setting IDETAPE_MAX_PC_RETRIES to 0 will disable retries.
+ * Setting IDETAPE_MAX_PC_RETRIES to 0 will disable retries.
*/
#define IDETAPE_MAX_PC_RETRIES 3
/*
- * With each packet command, we allocate a buffer of
- * IDETAPE_PC_BUFFER_SIZE bytes. This is used for several packet
- * commands (Not for READ/WRITE commands).
+ * With each packet command, we allocate a buffer of IDETAPE_PC_BUFFER_SIZE
+ * bytes. This is used for several packet commands (Not for READ/WRITE commands)
*/
#define IDETAPE_PC_BUFFER_SIZE 256
@@ -114,48 +121,39 @@
#define IDETAPE_WAIT_CMD (900*HZ)
/*
- * The following parameter is used to select the point in the internal
- * tape fifo in which we will start to refill the buffer. Decreasing
- * the following parameter will improve the system's latency and
- * interactive response, while using a high value might improve system
- * throughput.
+ * The following parameter is used to select the point in the internal tape fifo
+ * in which we will start to refill the buffer. Decreasing the following
+ * parameter will improve the system's latency and interactive response, while
+ * using a high value might improve system throughput.
*/
-#define IDETAPE_FIFO_THRESHOLD 2
+#define IDETAPE_FIFO_THRESHOLD 2
/*
- * DSC polling parameters.
- *
- * Polling for DSC (a single bit in the status register) is a very
- * important function in ide-tape. There are two cases in which we
- * poll for DSC:
+ * DSC polling parameters.
*
- * 1. Before a read/write packet command, to ensure that we
- * can transfer data from/to the tape's data buffers, without
- * causing an actual media access. In case the tape is not
- * ready yet, we take out our request from the device
- * request queue, so that ide.c will service requests from
- * the other device on the same interface meanwhile.
+ * Polling for DSC (a single bit in the status register) is a very important
+ * function in ide-tape. There are two cases in which we poll for DSC:
*
- * 2. After the successful initialization of a "media access
- * packet command", which is a command which can take a long
- * time to complete (it can be several seconds or even an hour).
+ * 1. Before a read/write packet command, to ensure that we can transfer data
+ * from/to the tape's data buffers, without causing an actual media access.
+ * In case the tape is not ready yet, we take out our request from the device
+ * request queue, so that ide.c could service requests from the other device
+ * on the same interface in the meantime.
*
- * Again, we postpone our request in the middle to free the bus
- * for the other device. The polling frequency here should be
- * lower than the read/write frequency since those media access
- * commands are slow. We start from a "fast" frequency -
- * IDETAPE_DSC_MA_FAST (one second), and if we don't receive DSC
- * after IDETAPE_DSC_MA_THRESHOLD (5 minutes), we switch it to a
- * lower frequency - IDETAPE_DSC_MA_SLOW (1 minute).
+ * 2. After the successful initialization of a "media access packet command",
+ * which is a command that can take a long time to complete (the interval can
+ * range from several seconds to even an hour). Again, we postpone our request
+ * in the middle to free the bus for the other device. The polling frequency
+ * here should be lower than the read/write frequency since those media access
+ * commands are slow. We start from a "fast" frequency - IDETAPE_DSC_MA_FAST
+ * (1 second), and if we don't receive DSC after IDETAPE_DSC_MA_THRESHOLD
+ * (5 min), we switch it to a lower frequency - IDETAPE_DSC_MA_SLOW (1 min).
*
- * We also set a timeout for the timer, in case something goes wrong.
- * The timeout should be longer then the maximum execution time of a
- * tape operation.
- */
-
-/*
- * DSC timings.
+ * We also set a timeout for the timer, in case something goes wrong. The
+ * timeout should be longer then the maximum execution time of a tape operation.
*/
+
+/* DSC timings. */
#define IDETAPE_DSC_RW_MIN 5*HZ/100 /* 50 msec */
#define IDETAPE_DSC_RW_MAX 40*HZ/100 /* 400 msec */
#define IDETAPE_DSC_RW_TIMEOUT 2*60*HZ /* 2 minutes */
@@ -166,19 +164,15 @@
/*************************** End of tunable parameters ***********************/
-/*
- * Read/Write error simulation
- */
+/* Read/Write error simulation */
#define SIMULATE_ERRORS 0
-/*
- * For general magnetic tape device compatibility.
- */
-typedef enum {
- idetape_direction_none,
- idetape_direction_read,
- idetape_direction_write
-} idetape_chrdev_direction_t;
+/* tape directions */
+enum {
+ IDETAPE_DIR_NONE = (1 << 0),
+ IDETAPE_DIR_READ = (1 << 1),
+ IDETAPE_DIR_WRITE = (1 << 2),
+};
struct idetape_bh {
u32 b_size;
@@ -187,24 +181,32 @@ struct idetape_bh {
char *b_data;
};
-/*
- * Our view of a packet command.
- */
typedef struct idetape_packet_command_s {
- u8 c[12]; /* Actual packet bytes */
- int retries; /* On each retry, we increment retries */
- int error; /* Error code */
- int request_transfer; /* Bytes to transfer */
- int actually_transferred; /* Bytes actually transferred */
- int buffer_size; /* Size of our data buffer */
+ /* Actual packet bytes */
+ u8 c[12];
+ /* On each retry, we increment retries */
+ int retries;
+ /* Error code */
+ int error;
+ /* Bytes to transfer */
+ int request_transfer;
+ /* Bytes actually transferred */
+ int actually_transferred;
+ /* Size of our data buffer */
+ int buffer_size;
struct idetape_bh *bh;
char *b_data;
int b_count;
- u8 *buffer; /* Data buffer */
- u8 *current_position; /* Pointer into the above buffer */
- ide_startstop_t (*callback) (ide_drive_t *); /* Called when this packet command is completed */
- u8 pc_buffer[IDETAPE_PC_BUFFER_SIZE]; /* Temporary buffer */
- unsigned long flags; /* Status/Action bit flags: long for set_bit */
+ /* Data buffer */
+ u8 *buffer;
+ /* Pointer into the above buffer */
+ u8 *current_position;
+ /* Called when this packet command is completed */
+ ide_startstop_t (*callback) (ide_drive_t *);
+ /* Temporary buffer */
+ u8 pc_buffer[IDETAPE_PC_BUFFER_SIZE];
+ /* Status/Action bit flags: long for set_bit */
+ unsigned long flags;
} idetape_pc_t;
/*
@@ -223,9 +225,7 @@ typedef struct idetape_packet_command_s {
/* Data direction */
#define PC_WRITING 5
-/*
- * A pipeline stage.
- */
+/* A pipeline stage. */
typedef struct idetape_stage_s {
struct request rq; /* The corresponding request */
struct idetape_bh *bh; /* The data buffers */
@@ -233,9 +233,8 @@ typedef struct idetape_stage_s {
} idetape_stage_t;
/*
- * Most of our global data which we need to save even as we leave the
- * driver due to an interrupt or a timer event is stored in a variable
- * of type idetape_tape_t, defined below.
+ * Most of our global data which we need to save even as we leave the driver due
+ * to an interrupt or a timer event is stored in the struct defined below.
*/
typedef struct ide_tape_obj {
ide_drive_t *drive;
@@ -271,15 +270,14 @@ typedef struct ide_tape_obj {
int rq_stack_index;
/*
- * DSC polling variables.
+ * DSC polling variables.
*
- * While polling for DSC we use postponed_rq to postpone the
- * current request so that ide.c will be able to service
- * pending requests on the other device. Note that at most
- * we will have only one DSC (usually data transfer) request
- * in the device request queue. Additional requests can be
- * queued in our internal pipeline, but they will be visible
- * to ide.c only one at a time.
+ * While polling for DSC we use postponed_rq to postpone the current
+ * request so that ide.c will be able to service pending requests on the
+ * other device. Note that at most we will have only one DSC (usually
+ * data transfer) request in the device request queue. Additional
+ * requests can be queued in our internal pipeline, but they will be
+ * visible to ide.c only one at a time.
*/
struct request *postponed_rq;
/* The time in which we started polling for DSC */
@@ -287,73 +285,57 @@ typedef struct ide_tape_obj {
/* Timer used to poll for dsc */
struct timer_list dsc_timer;
/* Read/Write dsc polling frequency */
- unsigned long best_dsc_rw_frequency;
- /* The current polling frequency */
- unsigned long dsc_polling_frequency;
- /* Maximum waiting time */
+ unsigned long best_dsc_rw_freq;
+ unsigned long dsc_poll_freq;
unsigned long dsc_timeout;
- /*
- * Read position information
- */
+ /* Read position information */
u8 partition;
/* Current block */
- unsigned int first_frame_position;
- unsigned int last_frame_position;
- unsigned int blocks_in_buffer;
+ unsigned int first_frame;
- /*
- * Last error information
- */
+ /* Last error information */
u8 sense_key, asc, ascq;
- /*
- * Character device operation
- */
+ /* Character device operation */
unsigned int minor;
/* device name */
char name[4];
/* Current character device data transfer direction */
- idetape_chrdev_direction_t chrdev_direction;
+ u8 chrdev_dir;
- /*
- * Device information
- */
- /* Usually 512 or 1024 bytes */
- unsigned short tape_block_size;
+ /* tape block size, usually 512 or 1024 bytes */
+ unsigned short blk_size;
int user_bs_factor;
/* Copy of the tape's Capabilities and Mechanical Page */
u8 caps[20];
/*
- * Active data transfer request parameters.
- *
- * At most, there is only one ide-tape originated data transfer
- * request in the device request queue. This allows ide.c to
- * easily service requests from the other device when we
- * postpone our active request. In the pipelined operation
- * mode, we use our internal pipeline structure to hold
- * more data requests.
+ * Active data transfer request parameters.
*
- * The data buffer size is chosen based on the tape's
- * recommendation.
+ * At most, there is only one ide-tape originated data transfer request
+ * in the device request queue. This allows ide.c to easily service
+ * requests from the other device when we postpone our active request.
+ * In the pipelined operation mode, we use our internal pipeline
+ * structure to hold more data requests. The data buffer size is chosen
+ * based on the tape's recommendation.
*/
- /* Pointer to the request which is waiting in the device request queue */
- struct request *active_data_request;
- /* Data buffer size (chosen based on the tape's recommendation */
+ /* ptr to the request which is waiting in the device request queue */
+ struct request *active_data_rq;
+ /* Data buffer size chosen based on the tape's recommendation */
int stage_size;
idetape_stage_t *merge_stage;
int merge_stage_size;
struct idetape_bh *bh;
char *b_data;
int b_count;
-
+
/*
- * Pipeline parameters.
+ * Pipeline parameters.
*
- * To accomplish non-pipelined mode, we simply set the following
- * variables to zero (or NULL, where appropriate).
+ * To accomplish non-pipelined mode, we simply set the following
+ * variables to zero (or NULL, where appropriate).
*/
/* Number of currently used stages */
int nr_stages;
@@ -378,20 +360,13 @@ typedef struct ide_tape_obj {
/* Status/Action flags: long for set_bit */
unsigned long flags;
/* protects the ide-tape queue */
- spinlock_t spinlock;
+ spinlock_t lock;
- /*
- * Measures average tape speed
- */
+ /* Measures average tape speed */
unsigned long avg_time;
int avg_size;
int avg_speed;
- char vendor_id[10];
- char product_id[18];
- char firmware_revision[6];
- int firmware_revision_num;
-
/* the door is currently locked */
int door_locked;
/* the tape hardware is write protected */
@@ -400,11 +375,9 @@ typedef struct ide_tape_obj {
char write_prot;
/*
- * Limit the number of times a request can
- * be postponed, to avoid an infinite postpone
- * deadlock.
+ * Limit the number of times a request can be postponed, to avoid an
+ * infinite postpone deadlock.
*/
- /* request postpone count limit */
int postpone_cnt;
/*
@@ -419,30 +392,19 @@ typedef struct ide_tape_obj {
int tape_head;
int last_tape_head;
- /*
- * Speed control at the tape buffers input/output
- */
+ /* Speed control at the tape buffers input/output */
unsigned long insert_time;
int insert_size;
int insert_speed;
int max_insert_speed;
int measure_insert_time;
- /*
- * Measure tape still time, in milliseconds
- */
- unsigned long tape_still_time_begin;
- int tape_still_time;
-
- /*
- * Speed regulation negative feedback loop
- */
+ /* Speed regulation negative feedback loop */
int speed_control;
int pipeline_head_speed;
int controlled_pipeline_head_speed;
int uncontrolled_pipeline_head_speed;
int controlled_last_pipeline_head;
- int uncontrolled_last_pipeline_head;
unsigned long uncontrolled_pipeline_head_time;
unsigned long controlled_pipeline_head_time;
int controlled_previous_pipeline_head;
@@ -451,18 +413,7 @@ typedef struct ide_tape_obj {
unsigned long uncontrolled_previous_head_time;
int restart_speed_control_req;
- /*
- * Debug_level determines amount of debugging output;
- * can be changed using /proc/ide/hdx/settings
- * 0 : almost no debugging output
- * 1 : 0+output errors only
- * 2 : 1+output all sensekey/asc
- * 3 : 2+follow all chrdev related procedures
- * 4 : 3+follow all procedures
- * 5 : 4+include pc_stack rq_stack info
- * 6 : 5+USE_COUNT updates
- */
- int debug_level;
+ u32 debug_mask;
} idetape_tape_t;
static DEFINE_MUTEX(idetape_ref_mutex);
@@ -495,9 +446,7 @@ static void ide_tape_put(struct ide_tape_obj *tape)
mutex_unlock(&idetape_ref_mutex);
}
-/*
- * Tape door status
- */
+/* Tape door status */
#define DOOR_UNLOCKED 0
#define DOOR_LOCKED 1
#define DOOR_EXPLICITLY_LOCKED 2
@@ -517,30 +466,23 @@ static void ide_tape_put(struct ide_tape_obj *tape)
/* 0 = no tape is loaded, so we don't rewind after ejecting */
#define IDETAPE_MEDIUM_PRESENT 9
-/*
- * Some defines for the READ BUFFER command
- */
+/* A define for the READ BUFFER command */
#define IDETAPE_RETRIEVE_FAULTY_BLOCK 6
-/*
- * Some defines for the SPACE command
- */
+/* Some defines for the SPACE command */
#define IDETAPE_SPACE_OVER_FILEMARK 1
#define IDETAPE_SPACE_TO_EOD 3
-/*
- * Some defines for the LOAD UNLOAD command
- */
+/* Some defines for the LOAD UNLOAD command */
#define IDETAPE_LU_LOAD_MASK 1
#define IDETAPE_LU_RETENSION_MASK 2
#define IDETAPE_LU_EOT_MASK 4
/*
- * Special requests for our block device strategy routine.
+ * Special requests for our block device strategy routine.
*
- * In order to service a character device command, we add special
- * requests to the tail of our block device request queue and wait
- * for their completion.
+ * In order to service a character device command, we add special requests to
+ * the tail of our block device request queue and wait for their completion.
*/
enum {
@@ -551,55 +493,20 @@ enum {
REQ_IDETAPE_READ_BUFFER = (1 << 4),
};
-/*
- * Error codes which are returned in rq->errors to the higher part
- * of the driver.
- */
+/* Error codes returned in rq->errors to the higher part of the driver. */
#define IDETAPE_ERROR_GENERAL 101
#define IDETAPE_ERROR_FILEMARK 102
#define IDETAPE_ERROR_EOD 103
-/*
- * The following is used to format the general configuration word of
- * the ATAPI IDENTIFY DEVICE command.
- */
-struct idetape_id_gcw {
- unsigned packet_size :2; /* Packet Size */
- unsigned reserved234 :3; /* Reserved */
- unsigned drq_type :2; /* Command packet DRQ type */
- unsigned removable :1; /* Removable media */
- unsigned device_type :5; /* Device type */
- unsigned reserved13 :1; /* Reserved */
- unsigned protocol :2; /* Protocol type */
-};
-
-/*
- * READ POSITION packet command - Data Format (From Table 6-57)
- */
-typedef struct {
- unsigned reserved0_10 :2; /* Reserved */
- unsigned bpu :1; /* Block Position Unknown */
- unsigned reserved0_543 :3; /* Reserved */
- unsigned eop :1; /* End Of Partition */
- unsigned bop :1; /* Beginning Of Partition */
- u8 partition; /* Partition Number */
- u8 reserved2, reserved3; /* Reserved */
- u32 first_block; /* First Block Location */
- u32 last_block; /* Last Block Location (Optional) */
- u8 reserved12; /* Reserved */
- u8 blocks_in_buffer[3]; /* Blocks In Buffer - (Optional) */
- u32 bytes_in_buffer; /* Bytes In Buffer (Optional) */
-} idetape_read_position_result_t;
-
/* Structures related to the SELECT SENSE / MODE SENSE packet commands. */
#define IDETAPE_BLOCK_DESCRIPTOR 0
#define IDETAPE_CAPABILITIES_PAGE 0x2a
/*
- * The variables below are used for the character device interface.
- * Additional state variables are defined in our ide_drive_t structure.
+ * The variables below are used for the character device interface. Additional
+ * state variables are defined in our ide_drive_t structure.
*/
-static struct ide_tape_obj * idetape_devs[MAX_HWIFS * MAX_DRIVES];
+static struct ide_tape_obj *idetape_devs[MAX_HWIFS * MAX_DRIVES];
#define ide_tape_f(file) ((file)->private_data)
@@ -616,23 +523,17 @@ static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i)
}
/*
- * Function declarations
- *
- */
-static int idetape_chrdev_release (struct inode *inode, struct file *filp);
-static void idetape_write_release (ide_drive_t *drive, unsigned int minor);
-
-/*
* Too bad. The drive wants to send us data which we are not ready to accept.
* Just throw it away.
*/
-static void idetape_discard_data (ide_drive_t *drive, unsigned int bcount)
+static void idetape_discard_data(ide_drive_t *drive, unsigned int bcount)
{
while (bcount--)
(void) HWIF(drive)->INB(IDE_DATA_REG);
}
-static void idetape_input_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount)
+static void idetape_input_buffers(ide_drive_t *drive, idetape_pc_t *pc,
+ unsigned int bcount)
{
struct idetape_bh *bh = pc->bh;
int count;
@@ -644,8 +545,11 @@ static void idetape_input_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigne
idetape_discard_data(drive, bcount);
return;
}
- count = min((unsigned int)(bh->b_size - atomic_read(&bh->b_count)), bcount);
- HWIF(drive)->atapi_input_bytes(drive, bh->b_data + atomic_read(&bh->b_count), count);
+ count = min(
+ (unsigned int)(bh->b_size - atomic_read(&bh->b_count)),
+ bcount);
+ HWIF(drive)->atapi_input_bytes(drive, bh->b_data +
+ atomic_read(&bh->b_count), count);
bcount -= count;
atomic_add(count, &bh->b_count);
if (atomic_read(&bh->b_count) == bh->b_size) {
@@ -657,15 +561,16 @@ static void idetape_input_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigne
pc->bh = bh;
}
-static void idetape_output_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount)
+static void idetape_output_buffers(ide_drive_t *drive, idetape_pc_t *pc,
+ unsigned int bcount)
{
struct idetape_bh *bh = pc->bh;
int count;
while (bcount) {
if (bh == NULL) {
- printk(KERN_ERR "ide-tape: bh == NULL in "
- "idetape_output_buffers\n");
+ printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+ __func__);
return;
}
count = min((unsigned int)pc->b_count, (unsigned int)bcount);
@@ -674,7 +579,8 @@ static void idetape_output_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsign
pc->b_data += count;
pc->b_count -= count;
if (!pc->b_count) {
- pc->bh = bh = bh->b_reqnext;
+ bh = bh->b_reqnext;
+ pc->bh = bh;
if (bh) {
pc->b_data = bh->b_data;
pc->b_count = atomic_read(&bh->b_count);
@@ -683,7 +589,7 @@ static void idetape_output_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsign
}
}
-static void idetape_update_buffers (idetape_pc_t *pc)
+static void idetape_update_buffers(idetape_pc_t *pc)
{
struct idetape_bh *bh = pc->bh;
int count;
@@ -693,8 +599,8 @@ static void idetape_update_buffers (idetape_pc_t *pc)
return;
while (bcount) {
if (bh == NULL) {
- printk(KERN_ERR "ide-tape: bh == NULL in "
- "idetape_update_buffers\n");
+ printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+ __func__);
return;
}
count = min((unsigned int)bh->b_size, (unsigned int)bcount);
@@ -712,17 +618,14 @@ static void idetape_update_buffers (idetape_pc_t *pc)
* driver. A storage space for a maximum of IDETAPE_PC_STACK packet
* commands is allocated at initialization time.
*/
-static idetape_pc_t *idetape_next_pc_storage (ide_drive_t *drive)
+static idetape_pc_t *idetape_next_pc_storage(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 5)
- printk(KERN_INFO "ide-tape: pc_stack_index=%d\n",
- tape->pc_stack_index);
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_PCRQ_STACK, "pc_stack_index=%d\n", tape->pc_stack_index);
+
if (tape->pc_stack_index == IDETAPE_PC_STACK)
- tape->pc_stack_index=0;
+ tape->pc_stack_index = 0;
return (&tape->pc_stack[tape->pc_stack_index++]);
}
@@ -731,32 +634,26 @@ static idetape_pc_t *idetape_next_pc_storage (ide_drive_t *drive)
* Since we queue packet commands in the request queue, we need to
* allocate a request, along with the allocation of a packet command.
*/
-
+
/**************************************************************
* *
* This should get fixed to use kmalloc(.., GFP_ATOMIC) *
* followed later on by kfree(). -ml *
* *
**************************************************************/
-
-static struct request *idetape_next_rq_storage (ide_drive_t *drive)
+
+static struct request *idetape_next_rq_storage(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 5)
- printk(KERN_INFO "ide-tape: rq_stack_index=%d\n",
- tape->rq_stack_index);
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_PCRQ_STACK, "rq_stack_index=%d\n", tape->rq_stack_index);
+
if (tape->rq_stack_index == IDETAPE_PC_STACK)
- tape->rq_stack_index=0;
+ tape->rq_stack_index = 0;
return (&tape->rq_stack[tape->rq_stack_index++]);
}
-/*
- * idetape_init_pc initializes a packet command.
- */
-static void idetape_init_pc (idetape_pc_t *pc)
+static void idetape_init_pc(idetape_pc_t *pc)
{
memset(pc->c, 0, 12);
pc->retries = 0;
@@ -780,22 +677,14 @@ static void idetape_analyze_error(ide_drive_t *drive, u8 *sense)
tape->sense_key = sense[2] & 0xF;
tape->asc = sense[12];
tape->ascq = sense[13];
-#if IDETAPE_DEBUG_LOG
- /*
- * Without debugging, we only log an error if we decided to give up
- * retrying.
- */
- if (tape->debug_level >= 1)
- printk(KERN_INFO "ide-tape: pc = %x, sense key = %x, "
- "asc = %x, ascq = %x\n",
- pc->c[0], tape->sense_key,
- tape->asc, tape->ascq);
-#endif /* IDETAPE_DEBUG_LOG */
+
+ debug_log(DBG_ERR, "pc = %x, sense key = %x, asc = %x, ascq = %x\n",
+ pc->c[0], tape->sense_key, tape->asc, tape->ascq);
/* Correct pc->actually_transferred by asking the tape. */
if (test_bit(PC_DMA_ERROR, &pc->flags)) {
pc->actually_transferred = pc->request_transfer -
- tape->tape_block_size *
+ tape->blk_size *
be32_to_cpu(get_unaligned((u32 *)&sense[3]));
idetape_update_buffers(pc);
}
@@ -843,50 +732,24 @@ static void idetape_activate_next_stage(ide_drive_t *drive)
idetape_stage_t *stage = tape->next_stage;
struct request *rq = &stage->rq;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: Reached idetape_active_next_stage\n");
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
+
if (stage == NULL) {
- printk(KERN_ERR "ide-tape: bug: Trying to activate a non existing stage\n");
+ printk(KERN_ERR "ide-tape: bug: Trying to activate a non"
+ " existing stage\n");
return;
}
rq->rq_disk = tape->disk;
rq->buffer = NULL;
rq->special = (void *)stage->bh;
- tape->active_data_request = rq;
+ tape->active_data_rq = rq;
tape->active_stage = stage;
tape->next_stage = stage->next;
}
-/*
- * idetape_increase_max_pipeline_stages is a part of the feedback
- * loop which tries to find the optimum number of stages. In the
- * feedback loop, we are starting from a minimum maximum number of
- * stages, and if we sense that the pipeline is empty, we try to
- * increase it, until we reach the user compile time memory limit.
- */
-static void idetape_increase_max_pipeline_stages (ide_drive_t *drive)
-{
- idetape_tape_t *tape = drive->driver_data;
- int increase = (tape->max_pipeline - tape->min_pipeline) / 10;
-
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk (KERN_INFO "ide-tape: Reached idetape_increase_max_pipeline_stages\n");
-#endif /* IDETAPE_DEBUG_LOG */
-
- tape->max_stages += max(increase, 1);
- tape->max_stages = max(tape->max_stages, tape->min_pipeline);
- tape->max_stages = min(tape->max_stages, tape->max_pipeline);
-}
-
-/*
- * idetape_kfree_stage calls kfree to completely free a stage, along with
- * its related buffers.
- */
-static void __idetape_kfree_stage (idetape_stage_t *stage)
+/* Free a stage along with its related buffers completely. */
+static void __idetape_kfree_stage(idetape_stage_t *stage)
{
struct idetape_bh *prev_bh, *bh = stage->bh;
int size;
@@ -907,30 +770,29 @@ static void __idetape_kfree_stage (idetape_stage_t *stage)
kfree(stage);
}
-static void idetape_kfree_stage (idetape_tape_t *tape, idetape_stage_t *stage)
+static void idetape_kfree_stage(idetape_tape_t *tape, idetape_stage_t *stage)
{
__idetape_kfree_stage(stage);
}
/*
- * idetape_remove_stage_head removes tape->first_stage from the pipeline.
- * The caller should avoid race conditions.
+ * Remove tape->first_stage from the pipeline. The caller should avoid race
+ * conditions.
*/
-static void idetape_remove_stage_head (ide_drive_t *drive)
+static void idetape_remove_stage_head(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
idetape_stage_t *stage;
-
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: Reached idetape_remove_stage_head\n");
-#endif /* IDETAPE_DEBUG_LOG */
+
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
+
if (tape->first_stage == NULL) {
printk(KERN_ERR "ide-tape: bug: tape->first_stage is NULL\n");
return;
}
if (tape->active_stage == tape->first_stage) {
- printk(KERN_ERR "ide-tape: bug: Trying to free our active pipeline stage\n");
+ printk(KERN_ERR "ide-tape: bug: Trying to free our active "
+ "pipeline stage\n");
return;
}
stage = tape->first_stage;
@@ -940,9 +802,11 @@ static void idetape_remove_stage_head (ide_drive_t *drive)
if (tape->first_stage == NULL) {
tape->last_stage = NULL;
if (tape->next_stage != NULL)
- printk(KERN_ERR "ide-tape: bug: tape->next_stage != NULL\n");
+ printk(KERN_ERR "ide-tape: bug: tape->next_stage !="
+ " NULL\n");
if (tape->nr_stages)
- printk(KERN_ERR "ide-tape: bug: nr_stages should be 0 now\n");
+ printk(KERN_ERR "ide-tape: bug: nr_stages should be 0 "
+ "now\n");
}
}
@@ -957,10 +821,8 @@ static void idetape_abort_pipeline(ide_drive_t *drive,
idetape_stage_t *stage = new_last_stage->next;
idetape_stage_t *nstage;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: %s: idetape_abort_pipeline called\n", tape->name);
-#endif
+ debug_log(DBG_PROCS, "%s: Enter %s\n", tape->name, __func__);
+
while (stage) {
nstage = stage->next;
idetape_kfree_stage(tape, stage);
@@ -975,8 +837,8 @@ static void idetape_abort_pipeline(ide_drive_t *drive,
}
/*
- * idetape_end_request is used to finish servicing a request, and to
- * insert a pending pipeline request into the main device queue.
+ * Finish servicing a request and insert a pending pipeline request into the
+ * main device queue.
*/
static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects)
{
@@ -987,15 +849,12 @@ static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects)
int remove_stage = 0;
idetape_stage_t *active_stage;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: Reached idetape_end_request\n");
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
switch (uptodate) {
- case 0: error = IDETAPE_ERROR_GENERAL; break;
- case 1: error = 0; break;
- default: error = uptodate;
+ case 0: error = IDETAPE_ERROR_GENERAL; break;
+ case 1: error = 0; break;
+ default: error = uptodate;
}
rq->errors = error;
if (error)
@@ -1006,20 +865,21 @@ static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects)
return 0;
}
- spin_lock_irqsave(&tape->spinlock, flags);
+ spin_lock_irqsave(&tape->lock, flags);
/* The request was a pipelined data transfer request */
- if (tape->active_data_request == rq) {
+ if (tape->active_data_rq == rq) {
active_stage = tape->active_stage;
tape->active_stage = NULL;
- tape->active_data_request = NULL;
+ tape->active_data_rq = NULL;
tape->nr_pending_stages--;
if (rq->cmd[0] & REQ_IDETAPE_WRITE) {
remove_stage = 1;
if (error) {
set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
if (error == IDETAPE_ERROR_EOD)
- idetape_abort_pipeline(drive, active_stage);
+ idetape_abort_pipeline(drive,
+ active_stage);
}
} else if (rq->cmd[0] & REQ_IDETAPE_READ) {
if (error == IDETAPE_ERROR_EOD) {
@@ -1030,48 +890,57 @@ static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects)
if (tape->next_stage != NULL) {
idetape_activate_next_stage(drive);
+ /* Insert the next request into the request queue. */
+ (void)ide_do_drive_cmd(drive, tape->active_data_rq,
+ ide_end);
+ } else if (!error) {
/*
- * Insert the next request into the request queue.
+ * This is a part of the feedback loop which tries to
+ * find the optimum number of stages. We are starting
+ * from a minimum maximum number of stages, and if we
+ * sense that the pipeline is empty, we try to increase
+ * it, until we reach the user compile time memory
+ * limit.
*/
- (void) ide_do_drive_cmd(drive, tape->active_data_request, ide_end);
- } else if (!error) {
- idetape_increase_max_pipeline_stages(drive);
+ int i = (tape->max_pipeline - tape->min_pipeline) / 10;
+
+ tape->max_stages += max(i, 1);
+ tape->max_stages = max(tape->max_stages,
+ tape->min_pipeline);
+ tape->max_stages = min(tape->max_stages,
+ tape->max_pipeline);
}
}
ide_end_drive_cmd(drive, 0, 0);
-// blkdev_dequeue_request(rq);
-// drive->rq = NULL;
-// end_that_request_last(rq);
if (remove_stage)
idetape_remove_stage_head(drive);
- if (tape->active_data_request == NULL)
+ if (tape->active_data_rq == NULL)
clear_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);
- spin_unlock_irqrestore(&tape->spinlock, flags);
+ spin_unlock_irqrestore(&tape->lock, flags);
return 0;
}
-static ide_startstop_t idetape_request_sense_callback (ide_drive_t *drive)
+static ide_startstop_t idetape_request_sense_callback(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: Reached idetape_request_sense_callback\n");
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
+
if (!tape->pc->error) {
idetape_analyze_error(drive, tape->pc->buffer);
idetape_end_request(drive, 1, 0);
} else {
- printk(KERN_ERR "ide-tape: Error in REQUEST SENSE itself - Aborting request!\n");
+ printk(KERN_ERR "ide-tape: Error in REQUEST SENSE itself - "
+ "Aborting request!\n");
idetape_end_request(drive, 0, 0);
}
return ide_stopped;
}
-static void idetape_create_request_sense_cmd (idetape_pc_t *pc)
+static void idetape_create_request_sense_cmd(idetape_pc_t *pc)
{
- idetape_init_pc(pc);
+ idetape_init_pc(pc);
pc->c[0] = REQUEST_SENSE;
pc->c[4] = 20;
pc->request_transfer = 20;
@@ -1086,25 +955,22 @@ static void idetape_init_rq(struct request *rq, u8 cmd)
}
/*
- * idetape_queue_pc_head generates a new packet command request in front
- * of the request queue, before the current request, so that it will be
- * processed immediately, on the next pass through the driver.
- *
- * idetape_queue_pc_head is called from the request handling part of
- * the driver (the "bottom" part). Safe storage for the request should
- * be allocated with idetape_next_pc_storage and idetape_next_rq_storage
- * before calling idetape_queue_pc_head.
+ * Generate a new packet command request in front of the request queue, before
+ * the current request, so that it will be processed immediately, on the next
+ * pass through the driver. The function below is called from the request
+ * handling part of the driver (the "bottom" part). Safe storage for the request
+ * should be allocated with ide_tape_next_{pc,rq}_storage() prior to that.
*
- * Memory for those requests is pre-allocated at initialization time, and
- * is limited to IDETAPE_PC_STACK requests. We assume that we have enough
- * space for the maximum possible number of inter-dependent packet commands.
+ * Memory for those requests is pre-allocated at initialization time, and is
+ * limited to IDETAPE_PC_STACK requests. We assume that we have enough space for
+ * the maximum possible number of inter-dependent packet commands.
*
- * The higher level of the driver - The ioctl handler and the character
- * device handling functions should queue request to the lower level part
- * and wait for their completion using idetape_queue_pc_tail or
- * idetape_queue_rw_tail.
+ * The higher level of the driver - The ioctl handler and the character device
+ * handling functions should queue request to the lower level part and wait for
+ * their completion using idetape_queue_pc_tail or idetape_queue_rw_tail.
*/
-static void idetape_queue_pc_head (ide_drive_t *drive, idetape_pc_t *pc,struct request *rq)
+static void idetape_queue_pc_head(ide_drive_t *drive, idetape_pc_t *pc,
+ struct request *rq)
{
struct ide_tape_obj *tape = drive->driver_data;
@@ -1125,7 +991,7 @@ static ide_startstop_t idetape_retry_pc (ide_drive_t *drive)
idetape_pc_t *pc;
struct request *rq;
- (void)drive->hwif->INB(IDE_ERROR_REG);
+ (void)ide_read_error(drive);
pc = idetape_next_pc_storage(drive);
rq = idetape_next_rq_storage(drive);
idetape_create_request_sense_cmd(pc);
@@ -1135,50 +1001,46 @@ static ide_startstop_t idetape_retry_pc (ide_drive_t *drive)
}
/*
- * idetape_postpone_request postpones the current request so that
- * ide.c will be able to service requests from another device on
- * the same hwgroup while we are polling for DSC.
+ * Postpone the current request so that ide.c will be able to service requests
+ * from another device on the same hwgroup while we are polling for DSC.
*/
-static void idetape_postpone_request (ide_drive_t *drive)
+static void idetape_postpone_request(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: idetape_postpone_request\n");
-#endif
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
+
tape->postponed_rq = HWGROUP(drive)->rq;
- ide_stall_queue(drive, tape->dsc_polling_frequency);
+ ide_stall_queue(drive, tape->dsc_poll_freq);
}
+typedef void idetape_io_buf(ide_drive_t *, idetape_pc_t *, unsigned int);
+
/*
- * idetape_pc_intr is the usual interrupt handler which will be called
- * during a packet command. We will transfer some of the data (as
- * requested by the drive) and will re-point interrupt handler to us.
- * When data transfer is finished, we will act according to the
- * algorithm described before idetape_issue_packet_command.
- *
+ * This is the usual interrupt handler which will be called during a packet
+ * command. We will transfer some of the data (as requested by the drive) and
+ * will re-point interrupt handler to us. When data transfer is finished, we
+ * will act according to the algorithm described before
+ * idetape_issue_pc.
*/
-static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
+static ide_startstop_t idetape_pc_intr(ide_drive_t *drive)
{
ide_hwif_t *hwif = drive->hwif;
idetape_tape_t *tape = drive->driver_data;
idetape_pc_t *pc = tape->pc;
+ xfer_func_t *xferfunc;
+ idetape_io_buf *iobuf;
unsigned int temp;
#if SIMULATE_ERRORS
- static int error_sim_count = 0;
+ static int error_sim_count;
#endif
u16 bcount;
u8 stat, ireason;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: Reached idetape_pc_intr "
- "interrupt handler\n");
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_PROCS, "Enter %s - interrupt handler\n", __func__);
/* Clear the interrupt */
- stat = hwif->INB(IDE_STATUS_REG);
+ stat = ide_read_status(drive);
if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
if (hwif->ide_dma_end(drive) || (stat & ERR_STAT)) {
@@ -1208,20 +1070,16 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
pc->actually_transferred = pc->request_transfer;
idetape_update_buffers(pc);
}
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: DMA finished\n");
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_PROCS, "DMA finished\n");
+
}
/* No more interrupts */
if ((stat & DRQ_STAT) == 0) {
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: Packet command completed, %d bytes transferred\n", pc->actually_transferred);
-#endif /* IDETAPE_DEBUG_LOG */
- clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+ debug_log(DBG_SENSE, "Packet command completed, %d bytes"
+ " transferred\n", pc->actually_transferred);
+ clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
local_irq_enable();
#if SIMULATE_ERRORS
@@ -1236,19 +1094,16 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
stat &= ~ERR_STAT;
if ((stat & ERR_STAT) || test_bit(PC_DMA_ERROR, &pc->flags)) {
/* Error detected */
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 1)
- printk(KERN_INFO "ide-tape: %s: I/O error\n",
- tape->name);
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_ERR, "%s: I/O error\n", tape->name);
+
if (pc->c[0] == REQUEST_SENSE) {
- printk(KERN_ERR "ide-tape: I/O error in request sense command\n");
+ printk(KERN_ERR "ide-tape: I/O error in request"
+ " sense command\n");
return ide_do_reset(drive);
}
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 1)
- printk(KERN_INFO "ide-tape: [cmd %x]: check condition\n", pc->c[0]);
-#endif
+ debug_log(DBG_ERR, "[cmd %x]: check condition\n",
+ pc->c[0]);
+
/* Retry operation */
return idetape_retry_pc(drive);
}
@@ -1257,7 +1112,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
(stat & SEEK_STAT) == 0) {
/* Media access command */
tape->dsc_polling_start = jiffies;
- tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST;
+ tape->dsc_poll_freq = IDETAPE_DSC_MA_FAST;
tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT;
/* Allow ide.c to handle other requests */
idetape_postpone_request(drive);
@@ -1282,7 +1137,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
ireason = hwif->INB(IDE_IREASON_REG);
if (ireason & CD) {
- printk(KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n");
+ printk(KERN_ERR "ide-tape: CoD != 0 in %s\n", __func__);
return ide_do_reset(drive);
}
if (((ireason & IO) == IO) == test_bit(PC_WRITING, &pc->flags)) {
@@ -1298,86 +1153,76 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
temp = pc->actually_transferred + bcount;
if (temp > pc->request_transfer) {
if (temp > pc->buffer_size) {
- printk(KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
+ printk(KERN_ERR "ide-tape: The tape wants to "
+ "send us more data than expected "
+ "- discarding data\n");
idetape_discard_data(drive, bcount);
- ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
+ ide_set_handler(drive, &idetape_pc_intr,
+ IDETAPE_WAIT_CMD, NULL);
return ide_started;
}
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 2)
- printk(KERN_NOTICE "ide-tape: The tape wants to send us more data than expected - allowing transfer\n");
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_SENSE, "The tape wants to send us more "
+ "data than expected - allowing transfer\n");
}
- }
- if (test_bit(PC_WRITING, &pc->flags)) {
- if (pc->bh != NULL)
- idetape_output_buffers(drive, pc, bcount);
- else
- /* Write the current buffer */
- hwif->atapi_output_bytes(drive, pc->current_position,
- bcount);
+ iobuf = &idetape_input_buffers;
+ xferfunc = hwif->atapi_input_bytes;
} else {
- if (pc->bh != NULL)
- idetape_input_buffers(drive, pc, bcount);
- else
- /* Read the current buffer */
- hwif->atapi_input_bytes(drive, pc->current_position,
- bcount);
+ iobuf = &idetape_output_buffers;
+ xferfunc = hwif->atapi_output_bytes;
}
+
+ if (pc->bh)
+ iobuf(drive, pc, bcount);
+ else
+ xferfunc(drive, pc->current_position, bcount);
+
/* Update the current position */
pc->actually_transferred += bcount;
pc->current_position += bcount;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes "
- "on that interrupt\n", pc->c[0], bcount);
-#endif
+
+ debug_log(DBG_SENSE, "[cmd %x] transferred %d bytes on that intr.\n",
+ pc->c[0], bcount);
+
/* And set the interrupt handler again */
ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
return ide_started;
}
/*
- * Packet Command Interface
- *
- * The current Packet Command is available in tape->pc, and will not
- * change until we finish handling it. Each packet command is associated
- * with a callback function that will be called when the command is
- * finished.
+ * Packet Command Interface
*
- * The handling will be done in three stages:
+ * The current Packet Command is available in tape->pc, and will not change
+ * until we finish handling it. Each packet command is associated with a
+ * callback function that will be called when the command is finished.
*
- * 1. idetape_issue_packet_command will send the packet command to the
- * drive, and will set the interrupt handler to idetape_pc_intr.
+ * The handling will be done in three stages:
*
- * 2. On each interrupt, idetape_pc_intr will be called. This step
- * will be repeated until the device signals us that no more
- * interrupts will be issued.
+ * 1. idetape_issue_pc will send the packet command to the drive, and will set
+ * the interrupt handler to idetape_pc_intr.
*
- * 3. ATAPI Tape media access commands have immediate status with a
- * delayed process. In case of a successful initiation of a
- * media access packet command, the DSC bit will be set when the
- * actual execution of the command is finished.
- * Since the tape drive will not issue an interrupt, we have to
- * poll for this event. In this case, we define the request as
- * "low priority request" by setting rq_status to
- * IDETAPE_RQ_POSTPONED, set a timer to poll for DSC and exit
- * the driver.
+ * 2. On each interrupt, idetape_pc_intr will be called. This step will be
+ * repeated until the device signals us that no more interrupts will be issued.
*
- * ide.c will then give higher priority to requests which
- * originate from the other device, until will change rq_status
- * to RQ_ACTIVE.
+ * 3. ATAPI Tape media access commands have immediate status with a delayed
+ * process. In case of a successful initiation of a media access packet command,
+ * the DSC bit will be set when the actual execution of the command is finished.
+ * Since the tape drive will not issue an interrupt, we have to poll for this
+ * event. In this case, we define the request as "low priority request" by
+ * setting rq_status to IDETAPE_RQ_POSTPONED, set a timer to poll for DSC and
+ * exit the driver.
*
- * 4. When the packet command is finished, it will be checked for errors.
+ * ide.c will then give higher priority to requests which originate from the
+ * other device, until will change rq_status to RQ_ACTIVE.
*
- * 5. In case an error was found, we queue a request sense packet
- * command in front of the request queue and retry the operation
- * up to IDETAPE_MAX_PC_RETRIES times.
+ * 4. When the packet command is finished, it will be checked for errors.
*
- * 6. In case no error was found, or we decided to give up and not
- * to retry again, the callback function will be called and then
- * we will handle the next request.
+ * 5. In case an error was found, we queue a request sense packet command in
+ * front of the request queue and retry the operation up to
+ * IDETAPE_MAX_PC_RETRIES times.
*
+ * 6. In case no error was found, or we decided to give up and not to retry
+ * again, the callback function will be called and then we will handle the next
+ * request.
*/
static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
{
@@ -1388,8 +1233,9 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
ide_startstop_t startstop;
u8 ireason;
- if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
- printk(KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
+ if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) {
+ printk(KERN_ERR "ide-tape: Strange, packet command initiated "
+ "yet DRQ isn't asserted\n");
return startstop;
}
ireason = hwif->INB(IDE_IREASON_REG);
@@ -1422,7 +1268,7 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
return ide_started;
}
-static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
+static ide_startstop_t idetape_issue_pc(ide_drive_t *drive, idetape_pc_t *pc)
{
ide_hwif_t *hwif = drive->hwif;
idetape_tape_t *tape = drive->driver_data;
@@ -1443,9 +1289,9 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
if (pc->retries > IDETAPE_MAX_PC_RETRIES ||
test_bit(PC_ABORT, &pc->flags)) {
/*
- * We will "abort" retrying a packet command in case
- * a legitimate error code was received (crossing a
- * filemark, or end of the media, for example).
+ * We will "abort" retrying a packet command in case legitimate
+ * error code was received (crossing a filemark, or end of the
+ * media, for example).
*/
if (!test_bit(PC_ABORT, &pc->flags)) {
if (!(pc->c[0] == TEST_UNIT_READY &&
@@ -1464,10 +1310,7 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
tape->failed_pc = NULL;
return pc->callback(drive);
}
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: Retry number - %d, cmd = %02X\n", pc->retries, pc->c[0]);
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_SENSE, "Retry #%d, cmd = %02X\n", pc->retries, pc->c[0]);
pc->retries++;
/* We haven't transferred any data yet */
@@ -1499,31 +1342,24 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
}
}
-/*
- * General packet command callback function.
- */
-static ide_startstop_t idetape_pc_callback (ide_drive_t *drive)
+static ide_startstop_t idetape_pc_callback(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
-
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: Reached idetape_pc_callback\n");
-#endif /* IDETAPE_DEBUG_LOG */
+
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
idetape_end_request(drive, tape->pc->error ? 0 : 1, 0);
return ide_stopped;
}
-/*
- * A mode sense command is used to "sense" tape parameters.
- */
-static void idetape_create_mode_sense_cmd (idetape_pc_t *pc, u8 page_code)
+/* A mode sense command is used to "sense" tape parameters. */
+static void idetape_create_mode_sense_cmd(idetape_pc_t *pc, u8 page_code)
{
idetape_init_pc(pc);
pc->c[0] = MODE_SENSE;
if (page_code != IDETAPE_BLOCK_DESCRIPTOR)
- pc->c[1] = 8; /* DBD = 1 - Don't return block descriptors */
+ /* DBD = 1 - Don't return block descriptors */
+ pc->c[1] = 8;
pc->c[2] = page_code;
/*
* Changed pc->c[3] to 0 (255 will at best return unused info).
@@ -1533,7 +1369,8 @@ static void idetape_create_mode_sense_cmd (idetape_pc_t *pc, u8 page_code)
* and return an error when 255 is used.
*/
pc->c[3] = 0;
- pc->c[4] = 255; /* (We will just discard data in that case) */
+ /* We will just discard data in that case */
+ pc->c[4] = 255;
if (page_code == IDETAPE_BLOCK_DESCRIPTOR)
pc->request_transfer = 12;
else if (page_code == IDETAPE_CAPABILITIES_PAGE)
@@ -1543,62 +1380,77 @@ static void idetape_create_mode_sense_cmd (idetape_pc_t *pc, u8 page_code)
pc->callback = &idetape_pc_callback;
}
-static void calculate_speeds(ide_drive_t *drive)
+static void idetape_calculate_speeds(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
- int full = 125, empty = 75;
- if (time_after(jiffies, tape->controlled_pipeline_head_time + 120 * HZ)) {
- tape->controlled_previous_pipeline_head = tape->controlled_last_pipeline_head;
- tape->controlled_previous_head_time = tape->controlled_pipeline_head_time;
+ if (time_after(jiffies,
+ tape->controlled_pipeline_head_time + 120 * HZ)) {
+ tape->controlled_previous_pipeline_head =
+ tape->controlled_last_pipeline_head;
+ tape->controlled_previous_head_time =
+ tape->controlled_pipeline_head_time;
tape->controlled_last_pipeline_head = tape->pipeline_head;
tape->controlled_pipeline_head_time = jiffies;
}
if (time_after(jiffies, tape->controlled_pipeline_head_time + 60 * HZ))
- tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_last_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_pipeline_head_time);
+ tape->controlled_pipeline_head_speed = (tape->pipeline_head -
+ tape->controlled_last_pipeline_head) * 32 * HZ /
+ (jiffies - tape->controlled_pipeline_head_time);
else if (time_after(jiffies, tape->controlled_previous_head_time))
- tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_previous_head_time);
+ tape->controlled_pipeline_head_speed = (tape->pipeline_head -
+ tape->controlled_previous_pipeline_head) * 32 *
+ HZ / (jiffies - tape->controlled_previous_head_time);
- if (tape->nr_pending_stages < tape->max_stages /*- 1 */) {
+ if (tape->nr_pending_stages < tape->max_stages/*- 1 */) {
/* -1 for read mode error recovery */
- if (time_after(jiffies, tape->uncontrolled_previous_head_time + 10 * HZ)) {
+ if (time_after(jiffies, tape->uncontrolled_previous_head_time +
+ 10 * HZ)) {
tape->uncontrolled_pipeline_head_time = jiffies;
- tape->uncontrolled_pipeline_head_speed = (tape->pipeline_head - tape->uncontrolled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->uncontrolled_previous_head_time);
+ tape->uncontrolled_pipeline_head_speed =
+ (tape->pipeline_head -
+ tape->uncontrolled_previous_pipeline_head) *
+ 32 * HZ / (jiffies -
+ tape->uncontrolled_previous_head_time);
}
} else {
tape->uncontrolled_previous_head_time = jiffies;
tape->uncontrolled_previous_pipeline_head = tape->pipeline_head;
- if (time_after(jiffies, tape->uncontrolled_pipeline_head_time + 30 * HZ)) {
+ if (time_after(jiffies, tape->uncontrolled_pipeline_head_time +
+ 30 * HZ))
tape->uncontrolled_pipeline_head_time = jiffies;
- }
+
}
- tape->pipeline_head_speed = max(tape->uncontrolled_pipeline_head_speed, tape->controlled_pipeline_head_speed);
- if (tape->speed_control == 0) {
- tape->max_insert_speed = 5000;
- } else if (tape->speed_control == 1) {
+ tape->pipeline_head_speed = max(tape->uncontrolled_pipeline_head_speed,
+ tape->controlled_pipeline_head_speed);
+
+ if (tape->speed_control == 1) {
if (tape->nr_pending_stages >= tape->max_stages / 2)
tape->max_insert_speed = tape->pipeline_head_speed +
- (1100 - tape->pipeline_head_speed) * 2 * (tape->nr_pending_stages - tape->max_stages / 2) / tape->max_stages;
+ (1100 - tape->pipeline_head_speed) * 2 *
+ (tape->nr_pending_stages - tape->max_stages / 2)
+ / tape->max_stages;
else
tape->max_insert_speed = 500 +
- (tape->pipeline_head_speed - 500) * 2 * tape->nr_pending_stages / tape->max_stages;
+ (tape->pipeline_head_speed - 500) * 2 *
+ tape->nr_pending_stages / tape->max_stages;
+
if (tape->nr_pending_stages >= tape->max_stages * 99 / 100)
tape->max_insert_speed = 5000;
- } else if (tape->speed_control == 2) {
- tape->max_insert_speed = tape->pipeline_head_speed * empty / 100 +
- (tape->pipeline_head_speed * full / 100 - tape->pipeline_head_speed * empty / 100) * tape->nr_pending_stages / tape->max_stages;
} else
tape->max_insert_speed = tape->speed_control;
+
tape->max_insert_speed = max(tape->max_insert_speed, 500);
}
-static ide_startstop_t idetape_media_access_finished (ide_drive_t *drive)
+static ide_startstop_t idetape_media_access_finished(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
idetape_pc_t *pc = tape->pc;
u8 stat;
- stat = drive->hwif->INB(IDE_STATUS_REG);
+ stat = ide_read_status(drive);
+
if (stat & SEEK_STAT) {
if (stat & ERR_STAT) {
/* Error detected */
@@ -1618,14 +1470,14 @@ static ide_startstop_t idetape_media_access_finished (ide_drive_t *drive)
return pc->callback(drive);
}
-static ide_startstop_t idetape_rw_callback (ide_drive_t *drive)
+static ide_startstop_t idetape_rw_callback(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
struct request *rq = HWGROUP(drive)->rq;
- int blocks = tape->pc->actually_transferred / tape->tape_block_size;
+ int blocks = tape->pc->actually_transferred / tape->blk_size;
- tape->avg_size += blocks * tape->tape_block_size;
- tape->insert_size += blocks * tape->tape_block_size;
+ tape->avg_size += blocks * tape->blk_size;
+ tape->insert_size += blocks * tape->blk_size;
if (tape->insert_size > 1024 * 1024)
tape->measure_insert_time = 1;
if (tape->measure_insert_time) {
@@ -1634,19 +1486,17 @@ static ide_startstop_t idetape_rw_callback (ide_drive_t *drive)
tape->insert_size = 0;
}
if (time_after(jiffies, tape->insert_time))
- tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
+ tape->insert_speed = tape->insert_size / 1024 * HZ /
+ (jiffies - tape->insert_time);
if (time_after_eq(jiffies, tape->avg_time + HZ)) {
- tape->avg_speed = tape->avg_size * HZ / (jiffies - tape->avg_time) / 1024;
+ tape->avg_speed = tape->avg_size * HZ /
+ (jiffies - tape->avg_time) / 1024;
tape->avg_size = 0;
tape->avg_time = jiffies;
}
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: Reached idetape_rw_callback\n");
-#endif /* IDETAPE_DEBUG_LOG */
-
- tape->first_frame_position += blocks;
+ tape->first_frame += blocks;
rq->current_nr_sectors -= blocks;
if (!tape->pc->error)
@@ -1656,7 +1506,8 @@ static ide_startstop_t idetape_rw_callback (ide_drive_t *drive)
return ide_stopped;
}
-static void idetape_create_read_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct idetape_bh *bh)
+static void idetape_create_read_cmd(idetape_tape_t *tape, idetape_pc_t *pc,
+ unsigned int length, struct idetape_bh *bh)
{
idetape_init_pc(pc);
pc->c[0] = READ_6;
@@ -1666,12 +1517,14 @@ static void idetape_create_read_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsi
pc->bh = bh;
atomic_set(&bh->b_count, 0);
pc->buffer = NULL;
- pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
+ pc->buffer_size = length * tape->blk_size;
+ pc->request_transfer = pc->buffer_size;
if (pc->request_transfer == tape->stage_size)
set_bit(PC_DMA_RECOMMENDED, &pc->flags);
}
-static void idetape_create_read_buffer_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct idetape_bh *bh)
+static void idetape_create_read_buffer_cmd(idetape_tape_t *tape,
+ idetape_pc_t *pc, struct idetape_bh *bh)
{
int size = 32768;
struct idetape_bh *p = bh;
@@ -1689,10 +1542,12 @@ static void idetape_create_read_buffer_cmd(idetape_tape_t *tape, idetape_pc_t *p
atomic_set(&p->b_count, 0);
p = p->b_reqnext;
}
- pc->request_transfer = pc->buffer_size = size;
+ pc->request_transfer = size;
+ pc->buffer_size = size;
}
-static void idetape_create_write_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct idetape_bh *bh)
+static void idetape_create_write_cmd(idetape_tape_t *tape, idetape_pc_t *pc,
+ unsigned int length, struct idetape_bh *bh)
{
idetape_init_pc(pc);
pc->c[0] = WRITE_6;
@@ -1704,14 +1559,12 @@ static void idetape_create_write_cmd(idetape_tape_t *tape, idetape_pc_t *pc, uns
pc->b_data = bh->b_data;
pc->b_count = atomic_read(&bh->b_count);
pc->buffer = NULL;
- pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
+ pc->buffer_size = length * tape->blk_size;
+ pc->request_transfer = pc->buffer_size;
if (pc->request_transfer == tape->stage_size)
set_bit(PC_DMA_RECOMMENDED, &pc->flags);
}
-/*
- * idetape_do_request is our request handling function.
- */
static ide_startstop_t idetape_do_request(ide_drive_t *drive,
struct request *rq, sector_t block)
{
@@ -1720,30 +1573,22 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
struct request *postponed_rq = tape->postponed_rq;
u8 stat;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: sector: %ld, "
- "nr_sectors: %ld, current_nr_sectors: %d\n",
+ debug_log(DBG_SENSE, "sector: %ld, nr_sectors: %ld,"
+ " current_nr_sectors: %d\n",
rq->sector, rq->nr_sectors, rq->current_nr_sectors);
-#endif /* IDETAPE_DEBUG_LOG */
if (!blk_special_request(rq)) {
- /*
- * We do not support buffer cache originated requests.
- */
+ /* We do not support buffer cache originated requests. */
printk(KERN_NOTICE "ide-tape: %s: Unsupported request in "
"request queue (%d)\n", drive->name, rq->cmd_type);
ide_end_request(drive, 0, 0);
return ide_stopped;
}
- /*
- * Retry a failed packet command
- */
- if (tape->failed_pc != NULL &&
- tape->pc->c[0] == REQUEST_SENSE) {
- return idetape_issue_packet_command(drive, tape->failed_pc);
- }
+ /* Retry a failed packet command */
+ if (tape->failed_pc && tape->pc->c[0] == REQUEST_SENSE)
+ return idetape_issue_pc(drive, tape->failed_pc);
+
if (postponed_rq != NULL)
if (rq != postponed_rq) {
printk(KERN_ERR "ide-tape: ide-tape.c bug - "
@@ -1758,7 +1603,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
* If the tape is still busy, postpone our request and service
* the other device meanwhile.
*/
- stat = drive->hwif->INB(IDE_STATUS_REG);
+ stat = ide_read_status(drive);
if (!drive->dsc_overlap && !(rq->cmd[0] & REQ_IDETAPE_PC2))
set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
@@ -1768,16 +1613,15 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
drive->post_reset = 0;
}
- if (tape->tape_still_time > 100 && tape->tape_still_time < 200)
- tape->measure_insert_time = 1;
if (time_after(jiffies, tape->insert_time))
- tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
- calculate_speeds(drive);
+ tape->insert_speed = tape->insert_size / 1024 * HZ /
+ (jiffies - tape->insert_time);
+ idetape_calculate_speeds(drive);
if (!test_and_clear_bit(IDETAPE_IGNORE_DSC, &tape->flags) &&
(stat & SEEK_STAT) == 0) {
if (postponed_rq == NULL) {
tape->dsc_polling_start = jiffies;
- tape->dsc_polling_frequency = tape->best_dsc_rw_frequency;
+ tape->dsc_poll_freq = tape->best_dsc_rw_freq;
tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT;
} else if (time_after(jiffies, tape->dsc_timeout)) {
printk(KERN_ERR "ide-tape: %s: DSC timeout\n",
@@ -1788,8 +1632,10 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
} else {
return ide_do_reset(drive);
}
- } else if (time_after(jiffies, tape->dsc_polling_start + IDETAPE_DSC_MA_THRESHOLD))
- tape->dsc_polling_frequency = IDETAPE_DSC_MA_SLOW;
+ } else if (time_after(jiffies,
+ tape->dsc_polling_start +
+ IDETAPE_DSC_MA_THRESHOLD))
+ tape->dsc_poll_freq = IDETAPE_DSC_MA_SLOW;
idetape_postpone_request(drive);
return ide_stopped;
}
@@ -1797,20 +1643,23 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
tape->buffer_head++;
tape->postpone_cnt = 0;
pc = idetape_next_pc_storage(drive);
- idetape_create_read_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
+ idetape_create_read_cmd(tape, pc, rq->current_nr_sectors,
+ (struct idetape_bh *)rq->special);
goto out;
}
if (rq->cmd[0] & REQ_IDETAPE_WRITE) {
tape->buffer_head++;
tape->postpone_cnt = 0;
pc = idetape_next_pc_storage(drive);
- idetape_create_write_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
+ idetape_create_write_cmd(tape, pc, rq->current_nr_sectors,
+ (struct idetape_bh *)rq->special);
goto out;
}
if (rq->cmd[0] & REQ_IDETAPE_READ_BUFFER) {
tape->postpone_cnt = 0;
pc = idetape_next_pc_storage(drive);
- idetape_create_read_buffer_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
+ idetape_create_read_buffer_cmd(tape, pc,
+ (struct idetape_bh *)rq->special);
goto out;
}
if (rq->cmd[0] & REQ_IDETAPE_PC1) {
@@ -1825,49 +1674,51 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
}
BUG();
out:
- return idetape_issue_packet_command(drive, pc);
+ return idetape_issue_pc(drive, pc);
}
-/*
- * Pipeline related functions
- */
-static inline int idetape_pipeline_active (idetape_tape_t *tape)
+/* Pipeline related functions */
+static inline int idetape_pipeline_active(idetape_tape_t *tape)
{
int rc1, rc2;
rc1 = test_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);
- rc2 = (tape->active_data_request != NULL);
+ rc2 = (tape->active_data_rq != NULL);
return rc1;
}
/*
- * idetape_kmalloc_stage uses __get_free_page to allocate a pipeline
- * stage, along with all the necessary small buffers which together make
- * a buffer of size tape->stage_size (or a bit more). We attempt to
- * combine sequential pages as much as possible.
+ * The function below uses __get_free_page to allocate a pipeline stage, along
+ * with all the necessary small buffers which together make a buffer of size
+ * tape->stage_size (or a bit more). We attempt to combine sequential pages as
+ * much as possible.
*
- * Returns a pointer to the new allocated stage, or NULL if we
- * can't (or don't want to) allocate a stage.
+ * It returns a pointer to the new allocated stage, or NULL if we can't (or
+ * don't want to) allocate a stage.
*
- * Pipeline stages are optional and are used to increase performance.
- * If we can't allocate them, we'll manage without them.
+ * Pipeline stages are optional and are used to increase performance. If we
+ * can't allocate them, we'll manage without them.
*/
-static idetape_stage_t *__idetape_kmalloc_stage (idetape_tape_t *tape, int full, int clear)
+static idetape_stage_t *__idetape_kmalloc_stage(idetape_tape_t *tape, int full,
+ int clear)
{
idetape_stage_t *stage;
struct idetape_bh *prev_bh, *bh;
int pages = tape->pages_per_stage;
char *b_data = NULL;
- if ((stage = kmalloc(sizeof (idetape_stage_t),GFP_KERNEL)) == NULL)
+ stage = kmalloc(sizeof(idetape_stage_t), GFP_KERNEL);
+ if (!stage)
return NULL;
stage->next = NULL;
- bh = stage->bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL);
+ stage->bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL);
+ bh = stage->bh;
if (bh == NULL)
goto abort;
bh->b_reqnext = NULL;
- if ((bh->b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL)
+ bh->b_data = (char *) __get_free_page(GFP_KERNEL);
+ if (!bh->b_data)
goto abort;
if (clear)
memset(bh->b_data, 0, PAGE_SIZE);
@@ -1875,7 +1726,8 @@ static idetape_stage_t *__idetape_kmalloc_stage (idetape_tape_t *tape, int full,
atomic_set(&bh->b_count, full ? bh->b_size : 0);
while (--pages) {
- if ((b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL)
+ b_data = (char *) __get_free_page(GFP_KERNEL);
+ if (!b_data)
goto abort;
if (clear)
memset(b_data, 0, PAGE_SIZE);
@@ -1893,7 +1745,8 @@ static idetape_stage_t *__idetape_kmalloc_stage (idetape_tape_t *tape, int full,
continue;
}
prev_bh = bh;
- if ((bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL)) == NULL) {
+ bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL);
+ if (!bh) {
free_page((unsigned long) b_data);
goto abort;
}
@@ -1912,14 +1765,11 @@ abort:
return NULL;
}
-static idetape_stage_t *idetape_kmalloc_stage (idetape_tape_t *tape)
+static idetape_stage_t *idetape_kmalloc_stage(idetape_tape_t *tape)
{
idetape_stage_t *cache_stage = tape->cache_stage;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: Reached idetape_kmalloc_stage\n");
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
if (tape->nr_stages >= tape->max_stages)
return NULL;
@@ -1930,7 +1780,8 @@ static idetape_stage_t *idetape_kmalloc_stage (idetape_tape_t *tape)
return __idetape_kmalloc_stage(tape, 0, 0);
}
-static int idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char __user *buf, int n)
+static int idetape_copy_stage_from_user(idetape_tape_t *tape,
+ idetape_stage_t *stage, const char __user *buf, int n)
{
struct idetape_bh *bh = tape->bh;
int count;
@@ -1938,12 +1789,15 @@ static int idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *
while (n) {
if (bh == NULL) {
- printk(KERN_ERR "ide-tape: bh == NULL in "
- "idetape_copy_stage_from_user\n");
+ printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+ __func__);
return 1;
}
- count = min((unsigned int)(bh->b_size - atomic_read(&bh->b_count)), (unsigned int)n);
- if (copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, count))
+ count = min((unsigned int)
+ (bh->b_size - atomic_read(&bh->b_count)),
+ (unsigned int)n);
+ if (copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf,
+ count))
ret = 1;
n -= count;
atomic_add(count, &bh->b_count);
@@ -1958,7 +1812,8 @@ static int idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *
return ret;
}
-static int idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, idetape_stage_t *stage, int n)
+static int idetape_copy_stage_to_user(idetape_tape_t *tape, char __user *buf,
+ idetape_stage_t *stage, int n)
{
struct idetape_bh *bh = tape->bh;
int count;
@@ -1966,8 +1821,8 @@ static int idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, i
while (n) {
if (bh == NULL) {
- printk(KERN_ERR "ide-tape: bh == NULL in "
- "idetape_copy_stage_to_user\n");
+ printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+ __func__);
return 1;
}
count = min(tape->b_count, n);
@@ -1978,7 +1833,8 @@ static int idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, i
tape->b_count -= count;
buf += count;
if (!tape->b_count) {
- tape->bh = bh = bh->b_reqnext;
+ bh = bh->b_reqnext;
+ tape->bh = bh;
if (bh) {
tape->b_data = bh->b_data;
tape->b_count = atomic_read(&bh->b_count);
@@ -1988,12 +1844,12 @@ static int idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, i
return ret;
}
-static void idetape_init_merge_stage (idetape_tape_t *tape)
+static void idetape_init_merge_stage(idetape_tape_t *tape)
{
struct idetape_bh *bh = tape->merge_stage->bh;
-
+
tape->bh = bh;
- if (tape->chrdev_direction == idetape_direction_write)
+ if (tape->chrdev_dir == IDETAPE_DIR_WRITE)
atomic_set(&bh->b_count, 0);
else {
tape->b_data = bh->b_data;
@@ -2001,7 +1857,7 @@ static void idetape_init_merge_stage (idetape_tape_t *tape)
}
}
-static void idetape_switch_buffers (idetape_tape_t *tape, idetape_stage_t *stage)
+static void idetape_switch_buffers(idetape_tape_t *tape, idetape_stage_t *stage)
{
struct idetape_bh *tmp;
@@ -2011,87 +1867,76 @@ static void idetape_switch_buffers (idetape_tape_t *tape, idetape_stage_t *stage
idetape_init_merge_stage(tape);
}
-/*
- * idetape_add_stage_tail adds a new stage at the end of the pipeline.
- */
-static void idetape_add_stage_tail (ide_drive_t *drive,idetape_stage_t *stage)
+/* Add a new stage at the end of the pipeline. */
+static void idetape_add_stage_tail(ide_drive_t *drive, idetape_stage_t *stage)
{
idetape_tape_t *tape = drive->driver_data;
unsigned long flags;
-
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk (KERN_INFO "ide-tape: Reached idetape_add_stage_tail\n");
-#endif /* IDETAPE_DEBUG_LOG */
- spin_lock_irqsave(&tape->spinlock, flags);
+
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
+
+ spin_lock_irqsave(&tape->lock, flags);
stage->next = NULL;
if (tape->last_stage != NULL)
- tape->last_stage->next=stage;
+ tape->last_stage->next = stage;
else
- tape->first_stage = tape->next_stage=stage;
+ tape->first_stage = stage;
+ tape->next_stage = stage;
tape->last_stage = stage;
if (tape->next_stage == NULL)
tape->next_stage = tape->last_stage;
tape->nr_stages++;
tape->nr_pending_stages++;
- spin_unlock_irqrestore(&tape->spinlock, flags);
+ spin_unlock_irqrestore(&tape->lock, flags);
}
-/*
- * idetape_wait_for_request installs a completion in a pending request
- * and sleeps until it is serviced.
- *
- * The caller should ensure that the request will not be serviced
- * before we install the completion (usually by disabling interrupts).
+/* Install a completion in a pending request and sleep until it is serviced. The
+ * caller should ensure that the request will not be serviced before we install
+ * the completion (usually by disabling interrupts).
*/
-static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq)
+static void idetape_wait_for_request(ide_drive_t *drive, struct request *rq)
{
DECLARE_COMPLETION_ONSTACK(wait);
idetape_tape_t *tape = drive->driver_data;
if (rq == NULL || !blk_special_request(rq)) {
- printk (KERN_ERR "ide-tape: bug: Trying to sleep on non-valid request\n");
+ printk(KERN_ERR "ide-tape: bug: Trying to sleep on non-valid"
+ " request\n");
return;
}
rq->end_io_data = &wait;
rq->end_io = blk_end_sync_rq;
- spin_unlock_irq(&tape->spinlock);
+ spin_unlock_irq(&tape->lock);
wait_for_completion(&wait);
/* The stage and its struct request have been deallocated */
- spin_lock_irq(&tape->spinlock);
+ spin_lock_irq(&tape->lock);
}
-static ide_startstop_t idetape_read_position_callback (ide_drive_t *drive)
+static ide_startstop_t idetape_read_position_callback(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
- idetape_read_position_result_t *result;
-
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: Reached idetape_read_position_callback\n");
-#endif /* IDETAPE_DEBUG_LOG */
+ u8 *readpos = tape->pc->buffer;
+
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
if (!tape->pc->error) {
- result = (idetape_read_position_result_t *) tape->pc->buffer;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: BOP - %s\n",result->bop ? "Yes":"No");
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: EOP - %s\n",result->eop ? "Yes":"No");
-#endif /* IDETAPE_DEBUG_LOG */
- if (result->bpu) {
- printk(KERN_INFO "ide-tape: Block location is unknown to the tape\n");
+ debug_log(DBG_SENSE, "BOP - %s\n",
+ (readpos[0] & 0x80) ? "Yes" : "No");
+ debug_log(DBG_SENSE, "EOP - %s\n",
+ (readpos[0] & 0x40) ? "Yes" : "No");
+
+ if (readpos[0] & 0x4) {
+ printk(KERN_INFO "ide-tape: Block location is unknown"
+ "to the tape\n");
clear_bit(IDETAPE_ADDRESS_VALID, &tape->flags);
idetape_end_request(drive, 0, 0);
} else {
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: Block Location - %u\n", ntohl(result->first_block));
-#endif /* IDETAPE_DEBUG_LOG */
- tape->partition = result->partition;
- tape->first_frame_position = ntohl(result->first_block);
- tape->last_frame_position = ntohl(result->last_block);
- tape->blocks_in_buffer = result->blocks_in_buffer[2];
+ debug_log(DBG_SENSE, "Block Location - %u\n",
+ be32_to_cpu(*(u32 *)&readpos[4]));
+
+ tape->partition = readpos[1];
+ tape->first_frame =
+ be32_to_cpu(*(u32 *)&readpos[4]);
set_bit(IDETAPE_ADDRESS_VALID, &tape->flags);
idetape_end_request(drive, 1, 0);
}
@@ -2102,14 +1947,11 @@ static ide_startstop_t idetape_read_position_callback (ide_drive_t *drive)
}
/*
- * idetape_create_write_filemark_cmd will:
- *
- * 1. Write a filemark if write_filemark=1.
- * 2. Flush the device buffers without writing a filemark
- * if write_filemark=0.
- *
+ * Write a filemark if write_filemark=1. Flush the device buffers without
+ * writing a filemark otherwise.
*/
-static void idetape_create_write_filemark_cmd (ide_drive_t *drive, idetape_pc_t *pc,int write_filemark)
+static void idetape_create_write_filemark_cmd(ide_drive_t *drive,
+ idetape_pc_t *pc, int write_filemark)
{
idetape_init_pc(pc);
pc->c[0] = WRITE_FILEMARKS;
@@ -2126,26 +1968,19 @@ static void idetape_create_test_unit_ready_cmd(idetape_pc_t *pc)
}
/*
- * idetape_queue_pc_tail is based on the following functions:
- *
- * ide_do_drive_cmd from ide.c
- * cdrom_queue_request and cdrom_queue_packet_command from ide-cd.c
+ * We add a special packet command request to the tail of the request queue, and
+ * wait for it to be serviced. This is not to be called from within the request
+ * handling part of the driver! We allocate here data on the stack and it is
+ * valid until the request is finished. This is not the case for the bottom part
+ * of the driver, where we are always leaving the functions to wait for an
+ * interrupt or a timer event.
*
- * We add a special packet command request to the tail of the request
- * queue, and wait for it to be serviced.
- *
- * This is not to be called from within the request handling part
- * of the driver ! We allocate here data in the stack, and it is valid
- * until the request is finished. This is not the case for the bottom
- * part of the driver, where we are always leaving the functions to wait
- * for an interrupt or a timer event.
- *
- * From the bottom part of the driver, we should allocate safe memory
- * using idetape_next_pc_storage and idetape_next_rq_storage, and add
- * the request to the request list without waiting for it to be serviced !
- * In that case, we usually use idetape_queue_pc_head.
+ * From the bottom part of the driver, we should allocate safe memory using
+ * idetape_next_pc_storage() and ide_tape_next_rq_storage(), and add the request
+ * to the request list without waiting for it to be serviced! In that case, we
+ * usually use idetape_queue_pc_head().
*/
-static int __idetape_queue_pc_tail (ide_drive_t *drive, idetape_pc_t *pc)
+static int __idetape_queue_pc_tail(ide_drive_t *drive, idetape_pc_t *pc)
{
struct ide_tape_obj *tape = drive->driver_data;
struct request rq;
@@ -2156,7 +1991,8 @@ static int __idetape_queue_pc_tail (ide_drive_t *drive, idetape_pc_t *pc)
return ide_do_drive_cmd(drive, &rq, ide_wait);
}
-static void idetape_create_load_unload_cmd (ide_drive_t *drive, idetape_pc_t *pc,int cmd)
+static void idetape_create_load_unload_cmd(ide_drive_t *drive, idetape_pc_t *pc,
+ int cmd)
{
idetape_init_pc(pc);
pc->c[0] = START_STOP;
@@ -2171,9 +2007,7 @@ static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout)
idetape_pc_t pc;
int load_attempted = 0;
- /*
- * Wait for the tape to become ready
- */
+ /* Wait for the tape to become ready */
set_bit(IDETAPE_MEDIUM_PRESENT, &tape->flags);
timeout += jiffies;
while (time_before(jiffies, timeout)) {
@@ -2181,10 +2015,12 @@ static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout)
if (!__idetape_queue_pc_tail(drive, &pc))
return 0;
if ((tape->sense_key == 2 && tape->asc == 4 && tape->ascq == 2)
- || (tape->asc == 0x3A)) { /* no media */
+ || (tape->asc == 0x3A)) {
+ /* no media */
if (load_attempted)
return -ENOMEDIUM;
- idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_LOAD_MASK);
+ idetape_create_load_unload_cmd(drive, &pc,
+ IDETAPE_LU_LOAD_MASK);
__idetape_queue_pc_tail(drive, &pc);
load_attempted = 1;
/* not about to be ready */
@@ -2196,24 +2032,25 @@ static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout)
return -EIO;
}
-static int idetape_queue_pc_tail (ide_drive_t *drive,idetape_pc_t *pc)
+static int idetape_queue_pc_tail(ide_drive_t *drive, idetape_pc_t *pc)
{
return __idetape_queue_pc_tail(drive, pc);
}
-static int idetape_flush_tape_buffers (ide_drive_t *drive)
+static int idetape_flush_tape_buffers(ide_drive_t *drive)
{
idetape_pc_t pc;
int rc;
idetape_create_write_filemark_cmd(drive, &pc, 0);
- if ((rc = idetape_queue_pc_tail(drive, &pc)))
+ rc = idetape_queue_pc_tail(drive, &pc);
+ if (rc)
return rc;
idetape_wait_ready(drive, 60 * 5 * HZ);
return 0;
}
-static void idetape_create_read_position_cmd (idetape_pc_t *pc)
+static void idetape_create_read_position_cmd(idetape_pc_t *pc)
{
idetape_init_pc(pc);
pc->c[0] = READ_POSITION;
@@ -2221,25 +2058,23 @@ static void idetape_create_read_position_cmd (idetape_pc_t *pc)
pc->callback = &idetape_read_position_callback;
}
-static int idetape_read_position (ide_drive_t *drive)
+static int idetape_read_position(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
idetape_pc_t pc;
int position;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: Reached idetape_read_position\n");
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
idetape_create_read_position_cmd(&pc);
if (idetape_queue_pc_tail(drive, &pc))
return -1;
- position = tape->first_frame_position;
+ position = tape->first_frame;
return position;
}
-static void idetape_create_locate_cmd (ide_drive_t *drive, idetape_pc_t *pc, unsigned int block, u8 partition, int skip)
+static void idetape_create_locate_cmd(ide_drive_t *drive, idetape_pc_t *pc,
+ unsigned int block, u8 partition, int skip)
{
idetape_init_pc(pc);
pc->c[0] = POSITION_TO_ELEMENT;
@@ -2250,7 +2085,8 @@ static void idetape_create_locate_cmd (ide_drive_t *drive, idetape_pc_t *pc, uns
pc->callback = &idetape_pc_callback;
}
-static int idetape_create_prevent_cmd (ide_drive_t *drive, idetape_pc_t *pc, int prevent)
+static int idetape_create_prevent_cmd(ide_drive_t *drive, idetape_pc_t *pc,
+ int prevent)
{
idetape_tape_t *tape = drive->driver_data;
@@ -2265,17 +2101,17 @@ static int idetape_create_prevent_cmd (ide_drive_t *drive, idetape_pc_t *pc, int
return 1;
}
-static int __idetape_discard_read_pipeline (ide_drive_t *drive)
+static int __idetape_discard_read_pipeline(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
unsigned long flags;
int cnt;
- if (tape->chrdev_direction != idetape_direction_read)
+ if (tape->chrdev_dir != IDETAPE_DIR_READ)
return 0;
/* Remove merge stage. */
- cnt = tape->merge_stage_size / tape->tape_block_size;
+ cnt = tape->merge_stage_size / tape->blk_size;
if (test_and_clear_bit(IDETAPE_FILEMARK, &tape->flags))
++cnt; /* Filemarks count as 1 sector */
tape->merge_stage_size = 0;
@@ -2286,22 +2122,22 @@ static int __idetape_discard_read_pipeline (ide_drive_t *drive)
/* Clear pipeline flags. */
clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
- tape->chrdev_direction = idetape_direction_none;
+ tape->chrdev_dir = IDETAPE_DIR_NONE;
/* Remove pipeline stages. */
if (tape->first_stage == NULL)
return 0;
- spin_lock_irqsave(&tape->spinlock, flags);
+ spin_lock_irqsave(&tape->lock, flags);
tape->next_stage = NULL;
if (idetape_pipeline_active(tape))
- idetape_wait_for_request(drive, tape->active_data_request);
- spin_unlock_irqrestore(&tape->spinlock, flags);
+ idetape_wait_for_request(drive, tape->active_data_rq);
+ spin_unlock_irqrestore(&tape->lock, flags);
while (tape->first_stage != NULL) {
struct request *rq_ptr = &tape->first_stage->rq;
- cnt += rq_ptr->nr_sectors - rq_ptr->current_nr_sectors;
+ cnt += rq_ptr->nr_sectors - rq_ptr->current_nr_sectors;
if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK)
++cnt;
idetape_remove_stage_head(drive);
@@ -2312,21 +2148,19 @@ static int __idetape_discard_read_pipeline (ide_drive_t *drive)
}
/*
- * idetape_position_tape positions the tape to the requested block
- * using the LOCATE packet command. A READ POSITION command is then
- * issued to check where we are positioned.
- *
- * Like all higher level operations, we queue the commands at the tail
- * of the request queue and wait for their completion.
- *
+ * Position the tape to the requested block using the LOCATE packet command.
+ * A READ POSITION command is then issued to check where we are positioned. Like
+ * all higher level operations, we queue the commands at the tail of the request
+ * queue and wait for their completion.
*/
-static int idetape_position_tape (ide_drive_t *drive, unsigned int block, u8 partition, int skip)
+static int idetape_position_tape(ide_drive_t *drive, unsigned int block,
+ u8 partition, int skip)
{
idetape_tape_t *tape = drive->driver_data;
int retval;
idetape_pc_t pc;
- if (tape->chrdev_direction == idetape_direction_read)
+ if (tape->chrdev_dir == IDETAPE_DIR_READ)
__idetape_discard_read_pipeline(drive);
idetape_wait_ready(drive, 60 * 5 * HZ);
idetape_create_locate_cmd(drive, &pc, block, partition, skip);
@@ -2338,7 +2172,8 @@ static int idetape_position_tape (ide_drive_t *drive, unsigned int block, u8 par
return (idetape_queue_pc_tail(drive, &pc));
}
-static void idetape_discard_read_pipeline (ide_drive_t *drive, int restore_position)
+static void idetape_discard_read_pipeline(ide_drive_t *drive,
+ int restore_position)
{
idetape_tape_t *tape = drive->driver_data;
int cnt;
@@ -2349,35 +2184,37 @@ static void idetape_discard_read_pipeline (ide_drive_t *drive, int restore_posit
position = idetape_read_position(drive);
seek = position > cnt ? position - cnt : 0;
if (idetape_position_tape(drive, seek, 0, 0)) {
- printk(KERN_INFO "ide-tape: %s: position_tape failed in discard_pipeline()\n", tape->name);
+ printk(KERN_INFO "ide-tape: %s: position_tape failed in"
+ " discard_pipeline()\n", tape->name);
return;
}
}
}
/*
- * idetape_queue_rw_tail generates a read/write request for the block
- * device interface and wait for it to be serviced.
+ * Generate a read/write request for the block device interface and wait for it
+ * to be serviced.
*/
-static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks, struct idetape_bh *bh)
+static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks,
+ struct idetape_bh *bh)
{
idetape_tape_t *tape = drive->driver_data;
struct request rq;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: idetape_queue_rw_tail: cmd=%d\n",cmd);
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_SENSE, "%s: cmd=%d\n", __func__, cmd);
+
if (idetape_pipeline_active(tape)) {
- printk(KERN_ERR "ide-tape: bug: the pipeline is active in idetape_queue_rw_tail\n");
+ printk(KERN_ERR "ide-tape: bug: the pipeline is active in %s\n",
+ __func__);
return (0);
}
idetape_init_rq(&rq, cmd);
rq.rq_disk = tape->disk;
rq.special = (void *)bh;
- rq.sector = tape->first_frame_position;
- rq.nr_sectors = rq.current_nr_sectors = blocks;
+ rq.sector = tape->first_frame;
+ rq.nr_sectors = blocks;
+ rq.current_nr_sectors = blocks;
(void) ide_do_drive_cmd(drive, &rq, ide_wait);
if ((cmd & (REQ_IDETAPE_READ | REQ_IDETAPE_WRITE)) == 0)
@@ -2387,14 +2224,11 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks, struct
idetape_init_merge_stage(tape);
if (rq.errors == IDETAPE_ERROR_GENERAL)
return -EIO;
- return (tape->tape_block_size * (blocks-rq.current_nr_sectors));
+ return (tape->blk_size * (blocks-rq.current_nr_sectors));
}
-/*
- * idetape_insert_pipeline_into_queue is used to start servicing the
- * pipeline stages, starting from tape->next_stage.
- */
-static void idetape_insert_pipeline_into_queue (ide_drive_t *drive)
+/* start servicing the pipeline stages, starting from tape->next_stage. */
+static void idetape_plug_pipeline(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
@@ -2403,19 +2237,20 @@ static void idetape_insert_pipeline_into_queue (ide_drive_t *drive)
if (!idetape_pipeline_active(tape)) {
set_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);
idetape_activate_next_stage(drive);
- (void) ide_do_drive_cmd(drive, tape->active_data_request, ide_end);
+ (void) ide_do_drive_cmd(drive, tape->active_data_rq, ide_end);
}
}
-static void idetape_create_inquiry_cmd (idetape_pc_t *pc)
+static void idetape_create_inquiry_cmd(idetape_pc_t *pc)
{
idetape_init_pc(pc);
pc->c[0] = INQUIRY;
- pc->c[4] = pc->request_transfer = 254;
+ pc->c[4] = 254;
+ pc->request_transfer = 254;
pc->callback = &idetape_pc_callback;
}
-static void idetape_create_rewind_cmd (ide_drive_t *drive, idetape_pc_t *pc)
+static void idetape_create_rewind_cmd(ide_drive_t *drive, idetape_pc_t *pc)
{
idetape_init_pc(pc);
pc->c[0] = REZERO_UNIT;
@@ -2423,7 +2258,7 @@ static void idetape_create_rewind_cmd (ide_drive_t *drive, idetape_pc_t *pc)
pc->callback = &idetape_pc_callback;
}
-static void idetape_create_erase_cmd (idetape_pc_t *pc)
+static void idetape_create_erase_cmd(idetape_pc_t *pc)
{
idetape_init_pc(pc);
pc->c[0] = ERASE;
@@ -2432,7 +2267,7 @@ static void idetape_create_erase_cmd (idetape_pc_t *pc)
pc->callback = &idetape_pc_callback;
}
-static void idetape_create_space_cmd (idetape_pc_t *pc,int count, u8 cmd)
+static void idetape_create_space_cmd(idetape_pc_t *pc, int count, u8 cmd)
{
idetape_init_pc(pc);
pc->c[0] = SPACE;
@@ -2442,89 +2277,87 @@ static void idetape_create_space_cmd (idetape_pc_t *pc,int count, u8 cmd)
pc->callback = &idetape_pc_callback;
}
-static void idetape_wait_first_stage (ide_drive_t *drive)
+static void idetape_wait_first_stage(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
unsigned long flags;
if (tape->first_stage == NULL)
return;
- spin_lock_irqsave(&tape->spinlock, flags);
+ spin_lock_irqsave(&tape->lock, flags);
if (tape->active_stage == tape->first_stage)
- idetape_wait_for_request(drive, tape->active_data_request);
- spin_unlock_irqrestore(&tape->spinlock, flags);
+ idetape_wait_for_request(drive, tape->active_data_rq);
+ spin_unlock_irqrestore(&tape->lock, flags);
}
/*
- * idetape_add_chrdev_write_request tries to add a character device
- * originated write request to our pipeline. In case we don't succeed,
- * we revert to non-pipelined operation mode for this request.
+ * Try to add a character device originated write request to our pipeline. In
+ * case we don't succeed, we revert to non-pipelined operation mode for this
+ * request. In order to accomplish that, we
*
- * 1. Try to allocate a new pipeline stage.
- * 2. If we can't, wait for more and more requests to be serviced
- * and try again each time.
- * 3. If we still can't allocate a stage, fallback to
- * non-pipelined operation mode for this request.
+ * 1. Try to allocate a new pipeline stage.
+ * 2. If we can't, wait for more and more requests to be serviced and try again
+ * each time.
+ * 3. If we still can't allocate a stage, fallback to non-pipelined operation
+ * mode for this request.
*/
-static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks)
+static int idetape_add_chrdev_write_request(ide_drive_t *drive, int blocks)
{
idetape_tape_t *tape = drive->driver_data;
idetape_stage_t *new_stage;
unsigned long flags;
struct request *rq;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 3)
- printk(KERN_INFO "ide-tape: Reached idetape_add_chrdev_write_request\n");
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_CHRDEV, "Enter %s\n", __func__);
- /*
- * Attempt to allocate a new stage.
- * Pay special attention to possible race conditions.
- */
+ /* Attempt to allocate a new stage. Beware possible race conditions. */
while ((new_stage = idetape_kmalloc_stage(tape)) == NULL) {
- spin_lock_irqsave(&tape->spinlock, flags);
+ spin_lock_irqsave(&tape->lock, flags);
if (idetape_pipeline_active(tape)) {
- idetape_wait_for_request(drive, tape->active_data_request);
- spin_unlock_irqrestore(&tape->spinlock, flags);
+ idetape_wait_for_request(drive, tape->active_data_rq);
+ spin_unlock_irqrestore(&tape->lock, flags);
} else {
- spin_unlock_irqrestore(&tape->spinlock, flags);
- idetape_insert_pipeline_into_queue(drive);
+ spin_unlock_irqrestore(&tape->lock, flags);
+ idetape_plug_pipeline(drive);
if (idetape_pipeline_active(tape))
continue;
/*
- * Linux is short on memory. Fallback to
- * non-pipelined operation mode for this request.
+ * The machine is short on memory. Fallback to non-
+ * pipelined operation mode for this request.
*/
- return idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, blocks, tape->merge_stage->bh);
+ return idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE,
+ blocks, tape->merge_stage->bh);
}
}
rq = &new_stage->rq;
idetape_init_rq(rq, REQ_IDETAPE_WRITE);
/* Doesn't actually matter - We always assume sequential access */
- rq->sector = tape->first_frame_position;
- rq->nr_sectors = rq->current_nr_sectors = blocks;
+ rq->sector = tape->first_frame;
+ rq->current_nr_sectors = blocks;
+ rq->nr_sectors = blocks;
idetape_switch_buffers(tape, new_stage);
idetape_add_stage_tail(drive, new_stage);
tape->pipeline_head++;
- calculate_speeds(drive);
+ idetape_calculate_speeds(drive);
/*
- * Estimate whether the tape has stopped writing by checking
- * if our write pipeline is currently empty. If we are not
- * writing anymore, wait for the pipeline to be full enough
- * (90%) before starting to service requests, so that we will
- * be able to keep up with the higher speeds of the tape.
+ * Estimate whether the tape has stopped writing by checking if our
+ * write pipeline is currently empty. If we are not writing anymore,
+ * wait for the pipeline to be almost completely full (90%) before
+ * starting to service requests, so that we will be able to keep up with
+ * the higher speeds of the tape.
*/
if (!idetape_pipeline_active(tape)) {
if (tape->nr_stages >= tape->max_stages * 9 / 10 ||
- tape->nr_stages >= tape->max_stages - tape->uncontrolled_pipeline_head_speed * 3 * 1024 / tape->tape_block_size) {
+ tape->nr_stages >= tape->max_stages -
+ tape->uncontrolled_pipeline_head_speed * 3 * 1024 /
+ tape->blk_size) {
tape->measure_insert_time = 1;
tape->insert_time = jiffies;
tape->insert_size = 0;
tape->insert_speed = 0;
- idetape_insert_pipeline_into_queue(drive);
+ idetape_plug_pipeline(drive);
}
}
if (test_and_clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags))
@@ -2534,31 +2367,32 @@ static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks)
}
/*
- * idetape_wait_for_pipeline will wait until all pending pipeline
- * requests are serviced. Typically called on device close.
+ * Wait until all pending pipeline requests are serviced. Typically called on
+ * device close.
*/
-static void idetape_wait_for_pipeline (ide_drive_t *drive)
+static void idetape_wait_for_pipeline(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
unsigned long flags;
while (tape->next_stage || idetape_pipeline_active(tape)) {
- idetape_insert_pipeline_into_queue(drive);
- spin_lock_irqsave(&tape->spinlock, flags);
+ idetape_plug_pipeline(drive);
+ spin_lock_irqsave(&tape->lock, flags);
if (idetape_pipeline_active(tape))
- idetape_wait_for_request(drive, tape->active_data_request);
- spin_unlock_irqrestore(&tape->spinlock, flags);
+ idetape_wait_for_request(drive, tape->active_data_rq);
+ spin_unlock_irqrestore(&tape->lock, flags);
}
}
-static void idetape_empty_write_pipeline (ide_drive_t *drive)
+static void idetape_empty_write_pipeline(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
int blocks, min;
struct idetape_bh *bh;
- if (tape->chrdev_direction != idetape_direction_write) {
- printk(KERN_ERR "ide-tape: bug: Trying to empty write pipeline, but we are not writing.\n");
+ if (tape->chrdev_dir != IDETAPE_DIR_WRITE) {
+ printk(KERN_ERR "ide-tape: bug: Trying to empty write pipeline,"
+ " but we are not writing.\n");
return;
}
if (tape->merge_stage_size > tape->stage_size) {
@@ -2566,12 +2400,13 @@ static void idetape_empty_write_pipeline (ide_drive_t *drive)
tape->merge_stage_size = tape->stage_size;
}
if (tape->merge_stage_size) {
- blocks = tape->merge_stage_size / tape->tape_block_size;
- if (tape->merge_stage_size % tape->tape_block_size) {
+ blocks = tape->merge_stage_size / tape->blk_size;
+ if (tape->merge_stage_size % tape->blk_size) {
unsigned int i;
blocks++;
- i = tape->tape_block_size - tape->merge_stage_size % tape->tape_block_size;
+ i = tape->blk_size - tape->merge_stage_size %
+ tape->blk_size;
bh = tape->bh->b_reqnext;
while (bh) {
atomic_set(&bh->b_count, 0);
@@ -2580,12 +2415,14 @@ static void idetape_empty_write_pipeline (ide_drive_t *drive)
bh = tape->bh;
while (i) {
if (bh == NULL) {
-
- printk(KERN_INFO "ide-tape: bug, bh NULL\n");
+ printk(KERN_INFO "ide-tape: bug,"
+ " bh NULL\n");
break;
}
- min = min(i, (unsigned int)(bh->b_size - atomic_read(&bh->b_count)));
- memset(bh->b_data + atomic_read(&bh->b_count), 0, min);
+ min = min(i, (unsigned int)(bh->b_size -
+ atomic_read(&bh->b_count)));
+ memset(bh->b_data + atomic_read(&bh->b_count),
+ 0, min);
atomic_add(min, &bh->b_count);
i -= min;
bh = bh->b_reqnext;
@@ -2600,13 +2437,13 @@ static void idetape_empty_write_pipeline (ide_drive_t *drive)
tape->merge_stage = NULL;
}
clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
- tape->chrdev_direction = idetape_direction_none;
+ tape->chrdev_dir = IDETAPE_DIR_NONE;
/*
- * On the next backup, perform the feedback loop again.
- * (I don't want to keep sense information between backups,
- * as some systems are constantly on, and the system load
- * can be totally different on the next backup).
+ * On the next backup, perform the feedback loop again. (I don't want to
+ * keep sense information between backups, as some systems are
+ * constantly on, and the system load can be totally different on the
+ * next backup).
*/
tape->max_stages = tape->min_pipeline;
if (tape->first_stage != NULL ||
@@ -2621,21 +2458,25 @@ static void idetape_empty_write_pipeline (ide_drive_t *drive)
}
}
-static void idetape_restart_speed_control (ide_drive_t *drive)
+static void idetape_restart_speed_control(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
tape->restart_speed_control_req = 0;
tape->pipeline_head = 0;
- tape->controlled_last_pipeline_head = tape->uncontrolled_last_pipeline_head = 0;
- tape->controlled_previous_pipeline_head = tape->uncontrolled_previous_pipeline_head = 0;
- tape->pipeline_head_speed = tape->controlled_pipeline_head_speed = 5000;
+ tape->controlled_last_pipeline_head = 0;
+ tape->controlled_previous_pipeline_head = 0;
+ tape->uncontrolled_previous_pipeline_head = 0;
+ tape->controlled_pipeline_head_speed = 5000;
+ tape->pipeline_head_speed = 5000;
tape->uncontrolled_pipeline_head_speed = 0;
- tape->controlled_pipeline_head_time = tape->uncontrolled_pipeline_head_time = jiffies;
- tape->controlled_previous_head_time = tape->uncontrolled_previous_head_time = jiffies;
+ tape->controlled_pipeline_head_time =
+ tape->uncontrolled_pipeline_head_time = jiffies;
+ tape->controlled_previous_head_time =
+ tape->uncontrolled_previous_head_time = jiffies;
}
-static int idetape_initiate_read (ide_drive_t *drive, int max_stages)
+static int idetape_init_read(ide_drive_t *drive, int max_stages)
{
idetape_tape_t *tape = drive->driver_data;
idetape_stage_t *new_stage;
@@ -2644,32 +2485,35 @@ static int idetape_initiate_read (ide_drive_t *drive, int max_stages)
u16 blocks = *(u16 *)&tape->caps[12];
/* Initialize read operation */
- if (tape->chrdev_direction != idetape_direction_read) {
- if (tape->chrdev_direction == idetape_direction_write) {
+ if (tape->chrdev_dir != IDETAPE_DIR_READ) {
+ if (tape->chrdev_dir == IDETAPE_DIR_WRITE) {
idetape_empty_write_pipeline(drive);
idetape_flush_tape_buffers(drive);
}
if (tape->merge_stage || tape->merge_stage_size) {
- printk (KERN_ERR "ide-tape: merge_stage_size should be 0 now\n");
+ printk(KERN_ERR "ide-tape: merge_stage_size should be"
+ " 0 now\n");
tape->merge_stage_size = 0;
}
- if ((tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0)) == NULL)
+ tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0);
+ if (!tape->merge_stage)
return -ENOMEM;
- tape->chrdev_direction = idetape_direction_read;
+ tape->chrdev_dir = IDETAPE_DIR_READ;
/*
- * Issue a read 0 command to ensure that DSC handshake
- * is switched from completion mode to buffer available
- * mode.
- * No point in issuing this if DSC overlap isn't supported,
- * some drives (Seagate STT3401A) will return an error.
+ * Issue a read 0 command to ensure that DSC handshake is
+ * switched from completion mode to buffer available mode.
+ * No point in issuing this if DSC overlap isn't supported, some
+ * drives (Seagate STT3401A) will return an error.
*/
if (drive->dsc_overlap) {
- bytes_read = idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, 0, tape->merge_stage->bh);
+ bytes_read = idetape_queue_rw_tail(drive,
+ REQ_IDETAPE_READ, 0,
+ tape->merge_stage->bh);
if (bytes_read < 0) {
__idetape_kfree_stage(tape->merge_stage);
tape->merge_stage = NULL;
- tape->chrdev_direction = idetape_direction_none;
+ tape->chrdev_dir = IDETAPE_DIR_NONE;
return bytes_read;
}
}
@@ -2677,8 +2521,9 @@ static int idetape_initiate_read (ide_drive_t *drive, int max_stages)
if (tape->restart_speed_control_req)
idetape_restart_speed_control(drive);
idetape_init_rq(&rq, REQ_IDETAPE_READ);
- rq.sector = tape->first_frame_position;
- rq.nr_sectors = rq.current_nr_sectors = blocks;
+ rq.sector = tape->first_frame;
+ rq.nr_sectors = blocks;
+ rq.current_nr_sectors = blocks;
if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) &&
tape->nr_stages < max_stages) {
new_stage = idetape_kmalloc_stage(tape);
@@ -2696,50 +2541,43 @@ static int idetape_initiate_read (ide_drive_t *drive, int max_stages)
tape->insert_time = jiffies;
tape->insert_size = 0;
tape->insert_speed = 0;
- idetape_insert_pipeline_into_queue(drive);
+ idetape_plug_pipeline(drive);
}
}
return 0;
}
/*
- * idetape_add_chrdev_read_request is called from idetape_chrdev_read
- * to service a character device read request and add read-ahead
- * requests to our pipeline.
+ * Called from idetape_chrdev_read() to service a character device read request
+ * and add read-ahead requests to our pipeline.
*/
-static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
+static int idetape_add_chrdev_read_request(ide_drive_t *drive, int blocks)
{
idetape_tape_t *tape = drive->driver_data;
unsigned long flags;
struct request *rq_ptr;
int bytes_read;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: Reached idetape_add_chrdev_read_request, %d blocks\n", blocks);
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_PROCS, "Enter %s, %d blocks\n", __func__, blocks);
- /*
- * If we are at a filemark, return a read length of 0
- */
+ /* If we are at a filemark, return a read length of 0 */
if (test_bit(IDETAPE_FILEMARK, &tape->flags))
return 0;
- /*
- * Wait for the next block to be available at the head
- * of the pipeline
- */
- idetape_initiate_read(drive, tape->max_stages);
+ /* Wait for the next block to reach the head of the pipeline. */
+ idetape_init_read(drive, tape->max_stages);
if (tape->first_stage == NULL) {
if (test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags))
return 0;
- return idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, blocks, tape->merge_stage->bh);
+ return idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, blocks,
+ tape->merge_stage->bh);
}
idetape_wait_first_stage(drive);
rq_ptr = &tape->first_stage->rq;
- bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors);
- rq_ptr->nr_sectors = rq_ptr->current_nr_sectors = 0;
-
+ bytes_read = tape->blk_size * (rq_ptr->nr_sectors -
+ rq_ptr->current_nr_sectors);
+ rq_ptr->nr_sectors = 0;
+ rq_ptr->current_nr_sectors = 0;
if (rq_ptr->errors == IDETAPE_ERROR_EOD)
return 0;
@@ -2747,43 +2585,46 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
idetape_switch_buffers(tape, tape->first_stage);
if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK)
set_bit(IDETAPE_FILEMARK, &tape->flags);
- spin_lock_irqsave(&tape->spinlock, flags);
+ spin_lock_irqsave(&tape->lock, flags);
idetape_remove_stage_head(drive);
- spin_unlock_irqrestore(&tape->spinlock, flags);
+ spin_unlock_irqrestore(&tape->lock, flags);
tape->pipeline_head++;
- calculate_speeds(drive);
+ idetape_calculate_speeds(drive);
}
- if (bytes_read > blocks * tape->tape_block_size) {
- printk(KERN_ERR "ide-tape: bug: trying to return more bytes than requested\n");
- bytes_read = blocks * tape->tape_block_size;
+ if (bytes_read > blocks * tape->blk_size) {
+ printk(KERN_ERR "ide-tape: bug: trying to return more bytes"
+ " than requested\n");
+ bytes_read = blocks * tape->blk_size;
}
return (bytes_read);
}
-static void idetape_pad_zeros (ide_drive_t *drive, int bcount)
+static void idetape_pad_zeros(ide_drive_t *drive, int bcount)
{
idetape_tape_t *tape = drive->driver_data;
struct idetape_bh *bh;
int blocks;
-
+
while (bcount) {
unsigned int count;
bh = tape->merge_stage->bh;
count = min(tape->stage_size, bcount);
bcount -= count;
- blocks = count / tape->tape_block_size;
+ blocks = count / tape->blk_size;
while (count) {
- atomic_set(&bh->b_count, min(count, (unsigned int)bh->b_size));
+ atomic_set(&bh->b_count,
+ min(count, (unsigned int)bh->b_size));
memset(bh->b_data, 0, atomic_read(&bh->b_count));
count -= atomic_read(&bh->b_count);
bh = bh->b_reqnext;
}
- idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, blocks, tape->merge_stage->bh);
+ idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, blocks,
+ tape->merge_stage->bh);
}
}
-static int idetape_pipeline_size (ide_drive_t *drive)
+static int idetape_pipeline_size(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
idetape_stage_t *stage;
@@ -2794,9 +2635,10 @@ static int idetape_pipeline_size (ide_drive_t *drive)
stage = tape->first_stage;
while (stage != NULL) {
rq = &stage->rq;
- size += tape->tape_block_size * (rq->nr_sectors-rq->current_nr_sectors);
+ size += tape->blk_size * (rq->nr_sectors -
+ rq->current_nr_sectors);
if (rq->errors == IDETAPE_ERROR_FILEMARK)
- size += tape->tape_block_size;
+ size += tape->blk_size;
stage = stage->next;
}
size += tape->merge_stage_size;
@@ -2804,20 +2646,18 @@ static int idetape_pipeline_size (ide_drive_t *drive)
}
/*
- * Rewinds the tape to the Beginning Of the current Partition (BOP).
- *
- * We currently support only one partition.
- */
-static int idetape_rewind_tape (ide_drive_t *drive)
+ * Rewinds the tape to the Beginning Of the current Partition (BOP). We
+ * currently support only one partition.
+ */
+static int idetape_rewind_tape(ide_drive_t *drive)
{
int retval;
idetape_pc_t pc;
-#if IDETAPE_DEBUG_LOG
- idetape_tape_t *tape = drive->driver_data;
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: Reached idetape_rewind_tape\n");
-#endif /* IDETAPE_DEBUG_LOG */
-
+ idetape_tape_t *tape;
+ tape = drive->driver_data;
+
+ debug_log(DBG_SENSE, "Enter %s\n", __func__);
+
idetape_create_rewind_cmd(drive, &pc);
retval = idetape_queue_pc_tail(drive, &pc);
if (retval)
@@ -2830,14 +2670,9 @@ static int idetape_rewind_tape (ide_drive_t *drive)
return 0;
}
-/*
- * Our special ide-tape ioctl's.
- *
- * Currently there aren't any ioctl's.
- * mtio.h compatible commands should be issued to the character device
- * interface.
- */
-static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd, unsigned long arg)
+/* mtio.h compatible commands should be issued to the chrdev interface. */
+static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd,
+ unsigned long arg)
{
idetape_tape_t *tape = drive->driver_data;
void __user *argp = (void __user *)arg;
@@ -2848,44 +2683,41 @@ static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd, unsigned l
int nr_stages;
} config;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: Reached idetape_blkdev_ioctl\n");
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
+
switch (cmd) {
- case 0x0340:
- if (copy_from_user(&config, argp, sizeof(config)))
- return -EFAULT;
- tape->best_dsc_rw_frequency = config.dsc_rw_frequency;
- tape->max_stages = config.nr_stages;
- break;
- case 0x0350:
- config.dsc_rw_frequency = (int) tape->best_dsc_rw_frequency;
- config.nr_stages = tape->max_stages;
- if (copy_to_user(argp, &config, sizeof(config)))
- return -EFAULT;
- break;
- default:
- return -EIO;
+ case 0x0340:
+ if (copy_from_user(&config, argp, sizeof(config)))
+ return -EFAULT;
+ tape->best_dsc_rw_freq = config.dsc_rw_frequency;
+ tape->max_stages = config.nr_stages;
+ break;
+ case 0x0350:
+ config.dsc_rw_frequency = (int) tape->best_dsc_rw_freq;
+ config.nr_stages = tape->max_stages;
+ if (copy_to_user(argp, &config, sizeof(config)))
+ return -EFAULT;
+ break;
+ default:
+ return -EIO;
}
return 0;
}
/*
- * idetape_space_over_filemarks is now a bit more complicated than just
- * passing the command to the tape since we may have crossed some
- * filemarks during our pipelined read-ahead mode.
- *
- * As a minor side effect, the pipeline enables us to support MTFSFM when
- * the filemark is in our internal pipeline even if the tape doesn't
- * support spacing over filemarks in the reverse direction.
+ * The function below is now a bit more complicated than just passing the
+ * command to the tape since we may have crossed some filemarks during our
+ * pipelined read-ahead mode. As a minor side effect, the pipeline enables us to
+ * support MTFSFM when the filemark is in our internal pipeline even if the tape
+ * doesn't support spacing over filemarks in the reverse direction.
*/
-static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_count)
+static int idetape_space_over_filemarks(ide_drive_t *drive, short mt_op,
+ int mt_count)
{
idetape_tape_t *tape = drive->driver_data;
idetape_pc_t pc;
unsigned long flags;
- int retval,count=0;
+ int retval, count = 0;
int sprev = !!(tape->caps[4] & 0x20);
if (mt_count == 0)
@@ -2893,14 +2725,11 @@ static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_c
if (MTBSF == mt_op || MTBSFM == mt_op) {
if (!sprev)
return -EIO;
- mt_count = - mt_count;
+ mt_count = -mt_count;
}
- if (tape->chrdev_direction == idetape_direction_read) {
- /*
- * We have a read-ahead buffer. Scan it for crossed
- * filemarks.
- */
+ if (tape->chrdev_dir == IDETAPE_DIR_READ) {
+ /* its a read-ahead buffer, scan it for crossed filemarks. */
tape->merge_stage_size = 0;
if (test_and_clear_bit(IDETAPE_FILEMARK, &tape->flags))
++count;
@@ -2910,24 +2739,27 @@ static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_c
set_bit(IDETAPE_FILEMARK, &tape->flags);
return 0;
}
- spin_lock_irqsave(&tape->spinlock, flags);
+ spin_lock_irqsave(&tape->lock, flags);
if (tape->first_stage == tape->active_stage) {
/*
- * We have reached the active stage in the read pipeline.
- * There is no point in allowing the drive to continue
- * reading any farther, so we stop the pipeline.
+ * We have reached the active stage in the read
+ * pipeline. There is no point in allowing the
+ * drive to continue reading any farther, so we
+ * stop the pipeline.
*
- * This section should be moved to a separate subroutine,
- * because a similar function is performed in
- * __idetape_discard_read_pipeline(), for example.
+ * This section should be moved to a separate
+ * subroutine because similar operations are
+ * done in __idetape_discard_read_pipeline(),
+ * for example.
*/
tape->next_stage = NULL;
- spin_unlock_irqrestore(&tape->spinlock, flags);
+ spin_unlock_irqrestore(&tape->lock, flags);
idetape_wait_first_stage(drive);
tape->next_stage = tape->first_stage->next;
} else
- spin_unlock_irqrestore(&tape->spinlock, flags);
- if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK)
+ spin_unlock_irqrestore(&tape->lock, flags);
+ if (tape->first_stage->rq.errors ==
+ IDETAPE_ERROR_FILEMARK)
++count;
idetape_remove_stage_head(drive);
}
@@ -2935,73 +2767,74 @@ static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_c
}
/*
- * The filemark was not found in our internal pipeline.
- * Now we can issue the space command.
+ * The filemark was not found in our internal pipeline; now we can issue
+ * the space command.
*/
switch (mt_op) {
- case MTFSF:
- case MTBSF:
- idetape_create_space_cmd(&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK);
- return (idetape_queue_pc_tail(drive, &pc));
- case MTFSFM:
- case MTBSFM:
- if (!sprev)
- return (-EIO);
- retval = idetape_space_over_filemarks(drive, MTFSF, mt_count-count);
- if (retval) return (retval);
- count = (MTBSFM == mt_op ? 1 : -1);
- return (idetape_space_over_filemarks(drive, MTFSF, count));
- default:
- printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op);
- return (-EIO);
+ case MTFSF:
+ case MTBSF:
+ idetape_create_space_cmd(&pc, mt_count - count,
+ IDETAPE_SPACE_OVER_FILEMARK);
+ return idetape_queue_pc_tail(drive, &pc);
+ case MTFSFM:
+ case MTBSFM:
+ if (!sprev)
+ return -EIO;
+ retval = idetape_space_over_filemarks(drive, MTFSF,
+ mt_count - count);
+ if (retval)
+ return retval;
+ count = (MTBSFM == mt_op ? 1 : -1);
+ return idetape_space_over_filemarks(drive, MTFSF, count);
+ default:
+ printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",
+ mt_op);
+ return -EIO;
}
}
-
/*
- * Our character device read / write functions.
+ * Our character device read / write functions.
*
- * The tape is optimized to maximize throughput when it is transferring
- * an integral number of the "continuous transfer limit", which is
- * a parameter of the specific tape (26 KB on my particular tape).
- * (32 kB for Onstream)
+ * The tape is optimized to maximize throughput when it is transferring an
+ * integral number of the "continuous transfer limit", which is a parameter of
+ * the specific tape (26kB on my particular tape, 32kB for Onstream).
*
- * As of version 1.3 of the driver, the character device provides an
- * abstract continuous view of the media - any mix of block sizes (even 1
- * byte) on the same backup/restore procedure is supported. The driver
- * will internally convert the requests to the recommended transfer unit,
- * so that an unmatch between the user's block size to the recommended
- * size will only result in a (slightly) increased driver overhead, but
- * will no longer hit performance.
- * This is not applicable to Onstream.
+ * As of version 1.3 of the driver, the character device provides an abstract
+ * continuous view of the media - any mix of block sizes (even 1 byte) on the
+ * same backup/restore procedure is supported. The driver will internally
+ * convert the requests to the recommended transfer unit, so that an unmatch
+ * between the user's block size to the recommended size will only result in a
+ * (slightly) increased driver overhead, but will no longer hit performance.
+ * This is not applicable to Onstream.
*/
-static ssize_t idetape_chrdev_read (struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
+static ssize_t idetape_chrdev_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
{
struct ide_tape_obj *tape = ide_tape_f(file);
ide_drive_t *drive = tape->drive;
- ssize_t bytes_read,temp, actually_read = 0, rc;
+ ssize_t bytes_read, temp, actually_read = 0, rc;
ssize_t ret = 0;
u16 ctl = *(u16 *)&tape->caps[12];
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 3)
- printk(KERN_INFO "ide-tape: Reached idetape_chrdev_read, count %Zd\n", count);
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_CHRDEV, "Enter %s, count %Zd\n", __func__, count);
- if (tape->chrdev_direction != idetape_direction_read) {
+ if (tape->chrdev_dir != IDETAPE_DIR_READ) {
if (test_bit(IDETAPE_DETECT_BS, &tape->flags))
- if (count > tape->tape_block_size &&
- (count % tape->tape_block_size) == 0)
- tape->user_bs_factor = count / tape->tape_block_size;
+ if (count > tape->blk_size &&
+ (count % tape->blk_size) == 0)
+ tape->user_bs_factor = count / tape->blk_size;
}
- if ((rc = idetape_initiate_read(drive, tape->max_stages)) < 0)
+ rc = idetape_init_read(drive, tape->max_stages);
+ if (rc < 0)
return rc;
if (count == 0)
return (0);
if (tape->merge_stage_size) {
- actually_read = min((unsigned int)(tape->merge_stage_size), (unsigned int)count);
- if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, actually_read))
+ actually_read = min((unsigned int)(tape->merge_stage_size),
+ (unsigned int)count);
+ if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage,
+ actually_read))
ret = -EFAULT;
buf += actually_read;
tape->merge_stage_size -= actually_read;
@@ -3011,7 +2844,8 @@ static ssize_t idetape_chrdev_read (struct file *file, char __user *buf,
bytes_read = idetape_add_chrdev_read_request(drive, ctl);
if (bytes_read <= 0)
goto finish;
- if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, bytes_read))
+ if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage,
+ bytes_read))
ret = -EFAULT;
buf += bytes_read;
count -= bytes_read;
@@ -3022,25 +2856,24 @@ static ssize_t idetape_chrdev_read (struct file *file, char __user *buf,
if (bytes_read <= 0)
goto finish;
temp = min((unsigned long)count, (unsigned long)bytes_read);
- if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, temp))
+ if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage,
+ temp))
ret = -EFAULT;
actually_read += temp;
tape->merge_stage_size = bytes_read-temp;
}
finish:
if (!actually_read && test_bit(IDETAPE_FILEMARK, &tape->flags)) {
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: %s: spacing over filemark\n", tape->name);
-#endif
+ debug_log(DBG_SENSE, "%s: spacing over filemark\n", tape->name);
+
idetape_space_over_filemarks(drive, MTFSF, 1);
return 0;
}
- return (ret) ? ret : actually_read;
+ return ret ? ret : actually_read;
}
-static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
+static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
struct ide_tape_obj *tape = ide_tape_f(file);
@@ -3053,39 +2886,37 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
if (tape->write_prot)
return -EACCES;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 3)
- printk(KERN_INFO "ide-tape: Reached idetape_chrdev_write, "
- "count %Zd\n", count);
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_CHRDEV, "Enter %s, count %Zd\n", __func__, count);
/* Initialize write operation */
- if (tape->chrdev_direction != idetape_direction_write) {
- if (tape->chrdev_direction == idetape_direction_read)
+ if (tape->chrdev_dir != IDETAPE_DIR_WRITE) {
+ if (tape->chrdev_dir == IDETAPE_DIR_READ)
idetape_discard_read_pipeline(drive, 1);
if (tape->merge_stage || tape->merge_stage_size) {
printk(KERN_ERR "ide-tape: merge_stage_size "
"should be 0 now\n");
tape->merge_stage_size = 0;
}
- if ((tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0)) == NULL)
+ tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0);
+ if (!tape->merge_stage)
return -ENOMEM;
- tape->chrdev_direction = idetape_direction_write;
+ tape->chrdev_dir = IDETAPE_DIR_WRITE;
idetape_init_merge_stage(tape);
/*
- * Issue a write 0 command to ensure that DSC handshake
- * is switched from completion mode to buffer available
- * mode.
- * No point in issuing this if DSC overlap isn't supported,
- * some drives (Seagate STT3401A) will return an error.
+ * Issue a write 0 command to ensure that DSC handshake is
+ * switched from completion mode to buffer available mode. No
+ * point in issuing this if DSC overlap isn't supported, some
+ * drives (Seagate STT3401A) will return an error.
*/
if (drive->dsc_overlap) {
- ssize_t retval = idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, 0, tape->merge_stage->bh);
+ ssize_t retval = idetape_queue_rw_tail(drive,
+ REQ_IDETAPE_WRITE, 0,
+ tape->merge_stage->bh);
if (retval < 0) {
__idetape_kfree_stage(tape->merge_stage);
tape->merge_stage = NULL;
- tape->chrdev_direction = idetape_direction_none;
+ tape->chrdev_dir = IDETAPE_DIR_NONE;
return retval;
}
}
@@ -3096,11 +2927,14 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
idetape_restart_speed_control(drive);
if (tape->merge_stage_size) {
if (tape->merge_stage_size >= tape->stage_size) {
- printk(KERN_ERR "ide-tape: bug: merge buffer too big\n");
+ printk(KERN_ERR "ide-tape: bug: merge buf too big\n");
tape->merge_stage_size = 0;
}
- actually_written = min((unsigned int)(tape->stage_size - tape->merge_stage_size), (unsigned int)count);
- if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, actually_written))
+ actually_written = min((unsigned int)
+ (tape->stage_size - tape->merge_stage_size),
+ (unsigned int)count);
+ if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf,
+ actually_written))
ret = -EFAULT;
buf += actually_written;
tape->merge_stage_size += actually_written;
@@ -3116,7 +2950,8 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
}
while (count >= tape->stage_size) {
ssize_t retval;
- if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, tape->stage_size))
+ if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf,
+ tape->stage_size))
ret = -EFAULT;
buf += tape->stage_size;
count -= tape->stage_size;
@@ -3127,14 +2962,15 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
}
if (count) {
actually_written += count;
- if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, count))
+ if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf,
+ count))
ret = -EFAULT;
tape->merge_stage_size += count;
}
- return (ret) ? ret : actually_written;
+ return ret ? ret : actually_written;
}
-static int idetape_write_filemark (ide_drive_t *drive)
+static int idetape_write_filemark(ide_drive_t *drive)
{
idetape_pc_t pc;
@@ -3165,113 +3001,117 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count)
{
idetape_tape_t *tape = drive->driver_data;
idetape_pc_t pc;
- int i,retval;
+ int i, retval;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 1)
- printk(KERN_INFO "ide-tape: Handling MTIOCTOP ioctl: "
- "mt_op=%d, mt_count=%d\n", mt_op, mt_count);
-#endif /* IDETAPE_DEBUG_LOG */
- /*
- * Commands which need our pipelined read-ahead stages.
- */
+ debug_log(DBG_ERR, "Handling MTIOCTOP ioctl: mt_op=%d, mt_count=%d\n",
+ mt_op, mt_count);
+
+ /* Commands which need our pipelined read-ahead stages. */
switch (mt_op) {
- case MTFSF:
- case MTFSFM:
- case MTBSF:
- case MTBSFM:
- if (!mt_count)
- return (0);
- return (idetape_space_over_filemarks(drive,mt_op,mt_count));
- default:
- break;
+ case MTFSF:
+ case MTFSFM:
+ case MTBSF:
+ case MTBSFM:
+ if (!mt_count)
+ return 0;
+ return idetape_space_over_filemarks(drive, mt_op, mt_count);
+ default:
+ break;
}
+
switch (mt_op) {
- case MTWEOF:
- if (tape->write_prot)
- return -EACCES;
- idetape_discard_read_pipeline(drive, 1);
- for (i = 0; i < mt_count; i++) {
- retval = idetape_write_filemark(drive);
- if (retval)
- return retval;
- }
- return (0);
- case MTREW:
- idetape_discard_read_pipeline(drive, 0);
- if (idetape_rewind_tape(drive))
+ case MTWEOF:
+ if (tape->write_prot)
+ return -EACCES;
+ idetape_discard_read_pipeline(drive, 1);
+ for (i = 0; i < mt_count; i++) {
+ retval = idetape_write_filemark(drive);
+ if (retval)
+ return retval;
+ }
+ return 0;
+ case MTREW:
+ idetape_discard_read_pipeline(drive, 0);
+ if (idetape_rewind_tape(drive))
+ return -EIO;
+ return 0;
+ case MTLOAD:
+ idetape_discard_read_pipeline(drive, 0);
+ idetape_create_load_unload_cmd(drive, &pc,
+ IDETAPE_LU_LOAD_MASK);
+ return idetape_queue_pc_tail(drive, &pc);
+ case MTUNLOAD:
+ case MTOFFL:
+ /*
+ * If door is locked, attempt to unlock before
+ * attempting to eject.
+ */
+ if (tape->door_locked) {
+ if (idetape_create_prevent_cmd(drive, &pc, 0))
+ if (!idetape_queue_pc_tail(drive, &pc))
+ tape->door_locked = DOOR_UNLOCKED;
+ }
+ idetape_discard_read_pipeline(drive, 0);
+ idetape_create_load_unload_cmd(drive, &pc,
+ !IDETAPE_LU_LOAD_MASK);
+ retval = idetape_queue_pc_tail(drive, &pc);
+ if (!retval)
+ clear_bit(IDETAPE_MEDIUM_PRESENT, &tape->flags);
+ return retval;
+ case MTNOP:
+ idetape_discard_read_pipeline(drive, 0);
+ return idetape_flush_tape_buffers(drive);
+ case MTRETEN:
+ idetape_discard_read_pipeline(drive, 0);
+ idetape_create_load_unload_cmd(drive, &pc,
+ IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
+ return idetape_queue_pc_tail(drive, &pc);
+ case MTEOM:
+ idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD);
+ return idetape_queue_pc_tail(drive, &pc);
+ case MTERASE:
+ (void)idetape_rewind_tape(drive);
+ idetape_create_erase_cmd(&pc);
+ return idetape_queue_pc_tail(drive, &pc);
+ case MTSETBLK:
+ if (mt_count) {
+ if (mt_count < tape->blk_size ||
+ mt_count % tape->blk_size)
return -EIO;
+ tape->user_bs_factor = mt_count / tape->blk_size;
+ clear_bit(IDETAPE_DETECT_BS, &tape->flags);
+ } else
+ set_bit(IDETAPE_DETECT_BS, &tape->flags);
+ return 0;
+ case MTSEEK:
+ idetape_discard_read_pipeline(drive, 0);
+ return idetape_position_tape(drive,
+ mt_count * tape->user_bs_factor, tape->partition, 0);
+ case MTSETPART:
+ idetape_discard_read_pipeline(drive, 0);
+ return idetape_position_tape(drive, 0, mt_count, 0);
+ case MTFSR:
+ case MTBSR:
+ case MTLOCK:
+ if (!idetape_create_prevent_cmd(drive, &pc, 1))
return 0;
- case MTLOAD:
- idetape_discard_read_pipeline(drive, 0);
- idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_LOAD_MASK);
- return (idetape_queue_pc_tail(drive, &pc));
- case MTUNLOAD:
- case MTOFFL:
- /*
- * If door is locked, attempt to unlock before
- * attempting to eject.
- */
- if (tape->door_locked) {
- if (idetape_create_prevent_cmd(drive, &pc, 0))
- if (!idetape_queue_pc_tail(drive, &pc))
- tape->door_locked = DOOR_UNLOCKED;
- }
- idetape_discard_read_pipeline(drive, 0);
- idetape_create_load_unload_cmd(drive, &pc,!IDETAPE_LU_LOAD_MASK);
- retval = idetape_queue_pc_tail(drive, &pc);
- if (!retval)
- clear_bit(IDETAPE_MEDIUM_PRESENT, &tape->flags);
+ retval = idetape_queue_pc_tail(drive, &pc);
+ if (retval)
return retval;
- case MTNOP:
- idetape_discard_read_pipeline(drive, 0);
- return (idetape_flush_tape_buffers(drive));
- case MTRETEN:
- idetape_discard_read_pipeline(drive, 0);
- idetape_create_load_unload_cmd(drive, &pc,IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
- return (idetape_queue_pc_tail(drive, &pc));
- case MTEOM:
- idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD);
- return (idetape_queue_pc_tail(drive, &pc));
- case MTERASE:
- (void) idetape_rewind_tape(drive);
- idetape_create_erase_cmd(&pc);
- return (idetape_queue_pc_tail(drive, &pc));
- case MTSETBLK:
- if (mt_count) {
- if (mt_count < tape->tape_block_size || mt_count % tape->tape_block_size)
- return -EIO;
- tape->user_bs_factor = mt_count / tape->tape_block_size;
- clear_bit(IDETAPE_DETECT_BS, &tape->flags);
- } else
- set_bit(IDETAPE_DETECT_BS, &tape->flags);
- return 0;
- case MTSEEK:
- idetape_discard_read_pipeline(drive, 0);
- return idetape_position_tape(drive, mt_count * tape->user_bs_factor, tape->partition, 0);
- case MTSETPART:
- idetape_discard_read_pipeline(drive, 0);
- return (idetape_position_tape(drive, 0, mt_count, 0));
- case MTFSR:
- case MTBSR:
- case MTLOCK:
- if (!idetape_create_prevent_cmd(drive, &pc, 1))
- return 0;
- retval = idetape_queue_pc_tail(drive, &pc);
- if (retval) return retval;
- tape->door_locked = DOOR_EXPLICITLY_LOCKED;
- return 0;
- case MTUNLOCK:
- if (!idetape_create_prevent_cmd(drive, &pc, 0))
- return 0;
- retval = idetape_queue_pc_tail(drive, &pc);
- if (retval) return retval;
- tape->door_locked = DOOR_UNLOCKED;
+ tape->door_locked = DOOR_EXPLICITLY_LOCKED;
+ return 0;
+ case MTUNLOCK:
+ if (!idetape_create_prevent_cmd(drive, &pc, 0))
return 0;
- default:
- printk(KERN_ERR "ide-tape: MTIO operation %d not "
- "supported\n", mt_op);
- return (-EIO);
+ retval = idetape_queue_pc_tail(drive, &pc);
+ if (retval)
+ return retval;
+ tape->door_locked = DOOR_UNLOCKED;
+ return 0;
+ default:
+ printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",
+ mt_op);
+ return -EIO;
}
}
@@ -3288,50 +3128,51 @@ static int idetape_chrdev_ioctl(struct inode *inode, struct file *file,
struct mtop mtop;
struct mtget mtget;
struct mtpos mtpos;
- int block_offset = 0, position = tape->first_frame_position;
+ int block_offset = 0, position = tape->first_frame;
void __user *argp = (void __user *)arg;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 3)
- printk(KERN_INFO "ide-tape: Reached idetape_chrdev_ioctl, "
- "cmd=%u\n", cmd);
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_CHRDEV, "Enter %s, cmd=%u\n", __func__, cmd);
tape->restart_speed_control_req = 1;
- if (tape->chrdev_direction == idetape_direction_write) {
+ if (tape->chrdev_dir == IDETAPE_DIR_WRITE) {
idetape_empty_write_pipeline(drive);
idetape_flush_tape_buffers(drive);
}
if (cmd == MTIOCGET || cmd == MTIOCPOS) {
- block_offset = idetape_pipeline_size(drive) / (tape->tape_block_size * tape->user_bs_factor);
- if ((position = idetape_read_position(drive)) < 0)
+ block_offset = idetape_pipeline_size(drive) /
+ (tape->blk_size * tape->user_bs_factor);
+ position = idetape_read_position(drive);
+ if (position < 0)
return -EIO;
}
switch (cmd) {
- case MTIOCTOP:
- if (copy_from_user(&mtop, argp, sizeof (struct mtop)))
- return -EFAULT;
- return (idetape_mtioctop(drive,mtop.mt_op,mtop.mt_count));
- case MTIOCGET:
- memset(&mtget, 0, sizeof (struct mtget));
- mtget.mt_type = MT_ISSCSI2;
- mtget.mt_blkno = position / tape->user_bs_factor - block_offset;
- mtget.mt_dsreg = ((tape->tape_block_size * tape->user_bs_factor) << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK;
- if (tape->drv_write_prot) {
- mtget.mt_gstat |= GMT_WR_PROT(0xffffffff);
- }
- if (copy_to_user(argp, &mtget, sizeof(struct mtget)))
- return -EFAULT;
- return 0;
- case MTIOCPOS:
- mtpos.mt_blkno = position / tape->user_bs_factor - block_offset;
- if (copy_to_user(argp, &mtpos, sizeof(struct mtpos)))
- return -EFAULT;
- return 0;
- default:
- if (tape->chrdev_direction == idetape_direction_read)
- idetape_discard_read_pipeline(drive, 1);
- return idetape_blkdev_ioctl(drive, cmd, arg);
+ case MTIOCTOP:
+ if (copy_from_user(&mtop, argp, sizeof(struct mtop)))
+ return -EFAULT;
+ return idetape_mtioctop(drive, mtop.mt_op, mtop.mt_count);
+ case MTIOCGET:
+ memset(&mtget, 0, sizeof(struct mtget));
+ mtget.mt_type = MT_ISSCSI2;
+ mtget.mt_blkno = position / tape->user_bs_factor - block_offset;
+ mtget.mt_dsreg =
+ ((tape->blk_size * tape->user_bs_factor)
+ << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK;
+
+ if (tape->drv_write_prot)
+ mtget.mt_gstat |= GMT_WR_PROT(0xffffffff);
+
+ if (copy_to_user(argp, &mtget, sizeof(struct mtget)))
+ return -EFAULT;
+ return 0;
+ case MTIOCPOS:
+ mtpos.mt_blkno = position / tape->user_bs_factor - block_offset;
+ if (copy_to_user(argp, &mtpos, sizeof(struct mtpos)))
+ return -EFAULT;
+ return 0;
+ default:
+ if (tape->chrdev_dir == IDETAPE_DIR_READ)
+ idetape_discard_read_pipeline(drive, 1);
+ return idetape_blkdev_ioctl(drive, cmd, arg);
}
}
@@ -3347,23 +3188,20 @@ static void ide_tape_get_bsize_from_bdesc(ide_drive_t *drive)
idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_DESCRIPTOR);
if (idetape_queue_pc_tail(drive, &pc)) {
printk(KERN_ERR "ide-tape: Can't get block descriptor\n");
- if (tape->tape_block_size == 0) {
+ if (tape->blk_size == 0) {
printk(KERN_WARNING "ide-tape: Cannot deal with zero "
"block size, assuming 32k\n");
- tape->tape_block_size = 32768;
+ tape->blk_size = 32768;
}
return;
}
- tape->tape_block_size = (pc.buffer[4 + 5] << 16) +
+ tape->blk_size = (pc.buffer[4 + 5] << 16) +
(pc.buffer[4 + 6] << 8) +
pc.buffer[4 + 7];
tape->drv_write_prot = (pc.buffer[2] & 0x80) >> 7;
}
-/*
- * Our character device open function.
- */
-static int idetape_chrdev_open (struct inode *inode, struct file *filp)
+static int idetape_chrdev_open(struct inode *inode, struct file *filp)
{
unsigned int minor = iminor(inode), i = minor & ~0xc0;
ide_drive_t *drive;
@@ -3371,6 +3209,15 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp)
idetape_pc_t pc;
int retval;
+ if (i >= MAX_HWIFS * MAX_DRIVES)
+ return -ENXIO;
+
+ tape = ide_tape_chrdev_get(i);
+ if (!tape)
+ return -ENXIO;
+
+ debug_log(DBG_CHRDEV, "Enter %s\n", __func__);
+
/*
* We really want to do nonseekable_open(inode, filp); here, but some
* versions of tar incorrectly call lseek on tapes and bail out if that
@@ -3378,16 +3225,6 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp)
*/
filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
-#if IDETAPE_DEBUG_LOG
- printk(KERN_INFO "ide-tape: Reached idetape_chrdev_open\n");
-#endif /* IDETAPE_DEBUG_LOG */
-
- if (i >= MAX_HWIFS * MAX_DRIVES)
- return -ENXIO;
-
- if (!(tape = ide_tape_chrdev_get(i)))
- return -ENXIO;
-
drive = tape->drive;
filp->private_data = tape;
@@ -3408,7 +3245,7 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp)
if (!test_bit(IDETAPE_ADDRESS_VALID, &tape->flags))
(void)idetape_rewind_tape(drive);
- if (tape->chrdev_direction != idetape_direction_read)
+ if (tape->chrdev_dir != IDETAPE_DIR_READ)
clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
/* Read block size and write protect status from drive. */
@@ -3430,10 +3267,8 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp)
}
}
- /*
- * Lock the tape drive door so user can't eject.
- */
- if (tape->chrdev_direction == idetape_direction_none) {
+ /* Lock the tape drive door so user can't eject. */
+ if (tape->chrdev_dir == IDETAPE_DIR_NONE) {
if (idetape_create_prevent_cmd(drive, &pc, 1)) {
if (!idetape_queue_pc_tail(drive, &pc)) {
if (tape->door_locked != DOOR_EXPLICITLY_LOCKED)
@@ -3450,14 +3285,15 @@ out_put_tape:
return retval;
}
-static void idetape_write_release (ide_drive_t *drive, unsigned int minor)
+static void idetape_write_release(ide_drive_t *drive, unsigned int minor)
{
idetape_tape_t *tape = drive->driver_data;
idetape_empty_write_pipeline(drive);
tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0);
if (tape->merge_stage != NULL) {
- idetape_pad_zeros(drive, tape->tape_block_size * (tape->user_bs_factor - 1));
+ idetape_pad_zeros(drive, tape->blk_size *
+ (tape->user_bs_factor - 1));
__idetape_kfree_stage(tape->merge_stage);
tape->merge_stage = NULL;
}
@@ -3466,10 +3302,7 @@ static void idetape_write_release (ide_drive_t *drive, unsigned int minor)
idetape_flush_tape_buffers(drive);
}
-/*
- * Our character device release function.
- */
-static int idetape_chrdev_release (struct inode *inode, struct file *filp)
+static int idetape_chrdev_release(struct inode *inode, struct file *filp)
{
struct ide_tape_obj *tape = ide_tape_f(filp);
ide_drive_t *drive = tape->drive;
@@ -3478,14 +3311,12 @@ static int idetape_chrdev_release (struct inode *inode, struct file *filp)
lock_kernel();
tape = drive->driver_data;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 3)
- printk(KERN_INFO "ide-tape: Reached idetape_chrdev_release\n");
-#endif /* IDETAPE_DEBUG_LOG */
- if (tape->chrdev_direction == idetape_direction_write)
+ debug_log(DBG_CHRDEV, "Enter %s\n", __func__);
+
+ if (tape->chrdev_dir == IDETAPE_DIR_WRITE)
idetape_write_release(drive, minor);
- if (tape->chrdev_direction == idetape_direction_read) {
+ if (tape->chrdev_dir == IDETAPE_DIR_READ) {
if (minor < 128)
idetape_discard_read_pipeline(drive, 1);
else
@@ -3497,7 +3328,7 @@ static int idetape_chrdev_release (struct inode *inode, struct file *filp)
}
if (minor < 128 && test_bit(IDETAPE_MEDIUM_PRESENT, &tape->flags))
(void) idetape_rewind_tape(drive);
- if (tape->chrdev_direction == idetape_direction_none) {
+ if (tape->chrdev_dir == IDETAPE_DIR_NONE) {
if (tape->door_locked == DOOR_LOCKED) {
if (idetape_create_prevent_cmd(drive, &pc, 0)) {
if (!idetape_queue_pc_tail(drive, &pc))
@@ -3512,37 +3343,39 @@ static int idetape_chrdev_release (struct inode *inode, struct file *filp)
}
/*
- * idetape_identify_device is called to check the contents of the
- * ATAPI IDENTIFY command results. We return:
+ * check the contents of the ATAPI IDENTIFY command results. We return:
*
- * 1 If the tape can be supported by us, based on the information
- * we have so far.
+ * 1 - If the tape can be supported by us, based on the information we have so
+ * far.
*
- * 0 If this tape driver is not currently supported by us.
+ * 0 - If this tape driver is not currently supported by us.
*/
-static int idetape_identify_device (ide_drive_t *drive)
+static int idetape_identify_device(ide_drive_t *drive)
{
- struct idetape_id_gcw gcw;
- struct hd_driveid *id = drive->id;
+ u8 gcw[2], protocol, device_type, removable, packet_size;
if (drive->id_read == 0)
return 1;
- *((unsigned short *) &gcw) = id->config;
+ *((unsigned short *) &gcw) = drive->id->config;
+
+ protocol = (gcw[1] & 0xC0) >> 6;
+ device_type = gcw[1] & 0x1F;
+ removable = !!(gcw[0] & 0x80);
+ packet_size = gcw[0] & 0x3;
/* Check that we can support this device */
-
- if (gcw.protocol != 2)
+ if (protocol != 2)
printk(KERN_ERR "ide-tape: Protocol (0x%02x) is not ATAPI\n",
- gcw.protocol);
- else if (gcw.device_type != 1)
+ protocol);
+ else if (device_type != 1)
printk(KERN_ERR "ide-tape: Device type (0x%02x) is not set "
- "to tape\n", gcw.device_type);
- else if (!gcw.removable)
+ "to tape\n", device_type);
+ else if (!removable)
printk(KERN_ERR "ide-tape: The removable flag is not set\n");
- else if (gcw.packet_size != 0) {
- printk(KERN_ERR "ide-tape: Packet size (0x%02x) is not 12 "
- "bytes long\n", gcw.packet_size);
+ else if (packet_size != 0) {
+ printk(KERN_ERR "ide-tape: Packet size (0x%02x) is not 12"
+ " bytes\n", packet_size);
} else
return 1;
return 0;
@@ -3550,9 +3383,9 @@ static int idetape_identify_device (ide_drive_t *drive)
static void idetape_get_inquiry_results(ide_drive_t *drive)
{
- char *r;
idetape_tape_t *tape = drive->driver_data;
idetape_pc_t pc;
+ char fw_rev[6], vendor_id[10], product_id[18];
idetape_create_inquiry_cmd(&pc);
if (idetape_queue_pc_tail(drive, &pc)) {
@@ -3560,27 +3393,23 @@ static void idetape_get_inquiry_results(ide_drive_t *drive)
tape->name);
return;
}
- memcpy(tape->vendor_id, &pc.buffer[8], 8);
- memcpy(tape->product_id, &pc.buffer[16], 16);
- memcpy(tape->firmware_revision, &pc.buffer[32], 4);
-
- ide_fixstring(tape->vendor_id, 10, 0);
- ide_fixstring(tape->product_id, 18, 0);
- ide_fixstring(tape->firmware_revision, 6, 0);
- r = tape->firmware_revision;
- if (*(r + 1) == '.')
- tape->firmware_revision_num = (*r - '0') * 100 +
- (*(r + 2) - '0') * 10 + *(r + 3) - '0';
+ memcpy(vendor_id, &pc.buffer[8], 8);
+ memcpy(product_id, &pc.buffer[16], 16);
+ memcpy(fw_rev, &pc.buffer[32], 4);
+
+ ide_fixstring(vendor_id, 10, 0);
+ ide_fixstring(product_id, 18, 0);
+ ide_fixstring(fw_rev, 6, 0);
+
printk(KERN_INFO "ide-tape: %s <-> %s: %s %s rev %s\n",
- drive->name, tape->name, tape->vendor_id,
- tape->product_id, tape->firmware_revision);
+ drive->name, tape->name, vendor_id, product_id, fw_rev);
}
/*
* Ask the tape about its various parameters. In particular, we will adjust our
* data transfer buffer size to the recommended value as returned by the tape.
*/
-static void idetape_get_mode_sense_results (ide_drive_t *drive)
+static void idetape_get_mode_sense_results(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
idetape_pc_t pc;
@@ -3591,7 +3420,7 @@ static void idetape_get_mode_sense_results (ide_drive_t *drive)
if (idetape_queue_pc_tail(drive, &pc)) {
printk(KERN_ERR "ide-tape: Can't get tape parameters - assuming"
" some default values\n");
- tape->tape_block_size = 512;
+ tape->blk_size = 512;
put_unaligned(52, (u16 *)&tape->caps[12]);
put_unaligned(540, (u16 *)&tape->caps[14]);
put_unaligned(6*52, (u16 *)&tape->caps[16]);
@@ -3621,62 +3450,75 @@ static void idetape_get_mode_sense_results (ide_drive_t *drive)
memcpy(&tape->caps, caps, 20);
if (caps[7] & 0x02)
- tape->tape_block_size = 512;
+ tape->blk_size = 512;
else if (caps[7] & 0x04)
- tape->tape_block_size = 1024;
+ tape->blk_size = 1024;
}
#ifdef CONFIG_IDE_PROC_FS
-static void idetape_add_settings (ide_drive_t *drive)
+static void idetape_add_settings(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
-/*
- * drive setting name read/write data type min max mul_factor div_factor data pointer set function
- */
ide_add_setting(drive, "buffer", SETTING_READ, TYPE_SHORT, 0, 0xffff,
1, 2, (u16 *)&tape->caps[16], NULL);
- ide_add_setting(drive, "pipeline_min", SETTING_RW, TYPE_INT, 1, 0xffff, tape->stage_size / 1024, 1, &tape->min_pipeline, NULL);
- ide_add_setting(drive, "pipeline", SETTING_RW, TYPE_INT, 1, 0xffff, tape->stage_size / 1024, 1, &tape->max_stages, NULL);
- ide_add_setting(drive, "pipeline_max", SETTING_RW, TYPE_INT, 1, 0xffff, tape->stage_size / 1024, 1, &tape->max_pipeline, NULL);
- ide_add_setting(drive, "pipeline_used", SETTING_READ, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->nr_stages, NULL);
- ide_add_setting(drive, "pipeline_pending", SETTING_READ, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->nr_pending_stages, NULL);
+ ide_add_setting(drive, "pipeline_min", SETTING_RW, TYPE_INT, 1, 0xffff,
+ tape->stage_size / 1024, 1, &tape->min_pipeline, NULL);
+ ide_add_setting(drive, "pipeline", SETTING_RW, TYPE_INT, 1, 0xffff,
+ tape->stage_size / 1024, 1, &tape->max_stages, NULL);
+ ide_add_setting(drive, "pipeline_max", SETTING_RW, TYPE_INT, 1, 0xffff,
+ tape->stage_size / 1024, 1, &tape->max_pipeline, NULL);
+ ide_add_setting(drive, "pipeline_used", SETTING_READ, TYPE_INT, 0,
+ 0xffff, tape->stage_size / 1024, 1, &tape->nr_stages,
+ NULL);
+ ide_add_setting(drive, "pipeline_pending", SETTING_READ, TYPE_INT, 0,
+ 0xffff, tape->stage_size / 1024, 1,
+ &tape->nr_pending_stages, NULL);
ide_add_setting(drive, "speed", SETTING_READ, TYPE_SHORT, 0, 0xffff,
1, 1, (u16 *)&tape->caps[14], NULL);
- ide_add_setting(drive, "stage", SETTING_READ, TYPE_INT, 0, 0xffff, 1, 1024, &tape->stage_size, NULL);
- ide_add_setting(drive, "tdsc", SETTING_RW, TYPE_INT, IDETAPE_DSC_RW_MIN, IDETAPE_DSC_RW_MAX, 1000, HZ, &tape->best_dsc_rw_frequency, NULL);
- ide_add_setting(drive, "dsc_overlap", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->dsc_overlap, NULL);
- ide_add_setting(drive, "pipeline_head_speed_c",SETTING_READ, TYPE_INT, 0, 0xffff, 1, 1, &tape->controlled_pipeline_head_speed, NULL);
- ide_add_setting(drive, "pipeline_head_speed_u",SETTING_READ, TYPE_INT, 0, 0xffff, 1, 1, &tape->uncontrolled_pipeline_head_speed,NULL);
- ide_add_setting(drive, "avg_speed", SETTING_READ, TYPE_INT, 0, 0xffff, 1, 1, &tape->avg_speed, NULL);
- ide_add_setting(drive, "debug_level", SETTING_RW, TYPE_INT, 0, 0xffff, 1, 1, &tape->debug_level, NULL);
+ ide_add_setting(drive, "stage", SETTING_READ, TYPE_INT, 0, 0xffff, 1,
+ 1024, &tape->stage_size, NULL);
+ ide_add_setting(drive, "tdsc", SETTING_RW, TYPE_INT, IDETAPE_DSC_RW_MIN,
+ IDETAPE_DSC_RW_MAX, 1000, HZ, &tape->best_dsc_rw_freq,
+ NULL);
+ ide_add_setting(drive, "dsc_overlap", SETTING_RW, TYPE_BYTE, 0, 1, 1,
+ 1, &drive->dsc_overlap, NULL);
+ ide_add_setting(drive, "pipeline_head_speed_c", SETTING_READ, TYPE_INT,
+ 0, 0xffff, 1, 1, &tape->controlled_pipeline_head_speed,
+ NULL);
+ ide_add_setting(drive, "pipeline_head_speed_u", SETTING_READ, TYPE_INT,
+ 0, 0xffff, 1, 1,
+ &tape->uncontrolled_pipeline_head_speed, NULL);
+ ide_add_setting(drive, "avg_speed", SETTING_READ, TYPE_INT, 0, 0xffff,
+ 1, 1, &tape->avg_speed, NULL);
+ ide_add_setting(drive, "debug_mask", SETTING_RW, TYPE_INT, 0, 0xffff, 1,
+ 1, &tape->debug_mask, NULL);
}
#else
static inline void idetape_add_settings(ide_drive_t *drive) { ; }
#endif
/*
- * ide_setup is called to:
+ * The function below is called to:
*
- * 1. Initialize our various state variables.
- * 2. Ask the tape for its capabilities.
- * 3. Allocate a buffer which will be used for data
- * transfer. The buffer size is chosen based on
- * the recommendation which we received in step (2).
+ * 1. Initialize our various state variables.
+ * 2. Ask the tape for its capabilities.
+ * 3. Allocate a buffer which will be used for data transfer. The buffer size
+ * is chosen based on the recommendation which we received in step 2.
*
- * Note that at this point ide.c already assigned us an irq, so that
- * we can queue requests here and wait for their completion.
+ * Note that at this point ide.c already assigned us an irq, so that we can
+ * queue requests here and wait for their completion.
*/
-static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
+static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor)
{
unsigned long t1, tmid, tn, t;
int speed;
- struct idetape_id_gcw gcw;
int stage_size;
+ u8 gcw[2];
struct sysinfo si;
u16 *ctl = (u16 *)&tape->caps[12];
- spin_lock_init(&tape->spinlock);
+ spin_lock_init(&tape->lock);
drive->dsc_overlap = 1;
if (drive->hwif->host_flags & IDE_HFLAG_NO_DSC) {
printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n",
@@ -3690,25 +3532,29 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
tape->name[0] = 'h';
tape->name[1] = 't';
tape->name[2] = '0' + minor;
- tape->chrdev_direction = idetape_direction_none;
+ tape->chrdev_dir = IDETAPE_DIR_NONE;
tape->pc = tape->pc_stack;
tape->max_insert_speed = 10000;
tape->speed_control = 1;
*((unsigned short *) &gcw) = drive->id->config;
- if (gcw.drq_type == 1)
+
+ /* Command packet DRQ type */
+ if (((gcw[0] & 0x60) >> 5) == 1)
set_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags);
- tape->min_pipeline = tape->max_pipeline = tape->max_stages = 10;
-
+ tape->min_pipeline = 10;
+ tape->max_pipeline = 10;
+ tape->max_stages = 10;
+
idetape_get_inquiry_results(drive);
idetape_get_mode_sense_results(drive);
ide_tape_get_bsize_from_bdesc(drive);
tape->user_bs_factor = 1;
- tape->stage_size = *ctl * tape->tape_block_size;
+ tape->stage_size = *ctl * tape->blk_size;
while (tape->stage_size > 0xffff) {
printk(KERN_NOTICE "ide-tape: decreasing stage size\n");
*ctl /= 2;
- tape->stage_size = *ctl * tape->tape_block_size;
+ tape->stage_size = *ctl * tape->blk_size;
}
stage_size = tape->stage_size;
tape->pages_per_stage = stage_size / PAGE_SIZE;
@@ -3722,17 +3568,22 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
tape->max_stages = speed * 1000 * 10 / tape->stage_size;
- /*
- * Limit memory use for pipeline to 10% of physical memory
- */
+ /* Limit memory use for pipeline to 10% of physical memory */
si_meminfo(&si);
- if (tape->max_stages * tape->stage_size > si.totalram * si.mem_unit / 10)
- tape->max_stages = si.totalram * si.mem_unit / (10 * tape->stage_size);
+ if (tape->max_stages * tape->stage_size >
+ si.totalram * si.mem_unit / 10)
+ tape->max_stages =
+ si.totalram * si.mem_unit / (10 * tape->stage_size);
+
tape->max_stages = min(tape->max_stages, IDETAPE_MAX_PIPELINE_STAGES);
tape->min_pipeline = min(tape->max_stages, IDETAPE_MIN_PIPELINE_STAGES);
- tape->max_pipeline = min(tape->max_stages * 2, IDETAPE_MAX_PIPELINE_STAGES);
- if (tape->max_stages == 0)
- tape->max_stages = tape->min_pipeline = tape->max_pipeline = 1;
+ tape->max_pipeline =
+ min(tape->max_stages * 2, IDETAPE_MAX_PIPELINE_STAGES);
+ if (tape->max_stages == 0) {
+ tape->max_stages = 1;
+ tape->min_pipeline = 1;
+ tape->max_pipeline = 1;
+ }
t1 = (tape->stage_size * HZ) / (speed * 1000);
tmid = (*(u16 *)&tape->caps[16] * 32 * HZ) / (speed * 125);
@@ -3744,17 +3595,19 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
t = t1;
/*
- * Ensure that the number we got makes sense; limit
- * it within IDETAPE_DSC_RW_MIN and IDETAPE_DSC_RW_MAX.
+ * Ensure that the number we got makes sense; limit it within
+ * IDETAPE_DSC_RW_MIN and IDETAPE_DSC_RW_MAX.
*/
- tape->best_dsc_rw_frequency = max_t(unsigned long, min_t(unsigned long, t, IDETAPE_DSC_RW_MAX), IDETAPE_DSC_RW_MIN);
+ tape->best_dsc_rw_freq = max_t(unsigned long,
+ min_t(unsigned long, t, IDETAPE_DSC_RW_MAX),
+ IDETAPE_DSC_RW_MIN);
printk(KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, "
"%dkB pipeline, %lums tDSC%s\n",
drive->name, tape->name, *(u16 *)&tape->caps[14],
(*(u16 *)&tape->caps[16] * 512) / tape->stage_size,
tape->stage_size / 1024,
tape->max_stages * tape->stage_size / 1024,
- tape->best_dsc_rw_frequency * 1000 / HZ,
+ tape->best_dsc_rw_freq * 1000 / HZ,
drive->using_dma ? ", DMA":"");
idetape_add_settings(drive);
@@ -3782,7 +3635,8 @@ static void ide_tape_release(struct kref *kref)
drive->dsc_overlap = 0;
drive->driver_data = NULL;
device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor));
- device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor + 128));
+ device_destroy(idetape_sysfs_class,
+ MKDEV(IDETAPE_MAJOR, tape->minor + 128));
idetape_devs[tape->minor] = NULL;
g->private_data = NULL;
put_disk(g);
@@ -3831,9 +3685,7 @@ static ide_driver_t idetape_driver = {
#endif
};
-/*
- * Our character device supporting functions, passed to register_chrdev.
- */
+/* Our character device supporting functions, passed to register_chrdev. */
static const struct file_operations idetape_fops = {
.owner = THIS_MODULE,
.read = idetape_chrdev_read,
@@ -3848,7 +3700,8 @@ static int idetape_open(struct inode *inode, struct file *filp)
struct gendisk *disk = inode->i_bdev->bd_disk;
struct ide_tape_obj *tape;
- if (!(tape = ide_tape_get(disk)))
+ tape = ide_tape_get(disk);
+ if (!tape)
return -ENXIO;
return 0;
@@ -3895,21 +3748,20 @@ static int ide_tape_probe(ide_drive_t *drive)
goto failed;
if (drive->media != ide_tape)
goto failed;
- if (!idetape_identify_device (drive)) {
- printk(KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name);
+ if (!idetape_identify_device(drive)) {
+ printk(KERN_ERR "ide-tape: %s: not supported by this version of"
+ " the driver\n", drive->name);
goto failed;
}
if (drive->scsi) {
- printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name);
+ printk(KERN_INFO "ide-tape: passing drive %s to ide-scsi"
+ " emulation.\n", drive->name);
goto failed;
}
- if (strstr(drive->id->model, "OnStream DI-")) {
- printk(KERN_WARNING "ide-tape: Use drive %s with ide-scsi emulation and osst.\n", drive->name);
- printk(KERN_WARNING "ide-tape: OnStream support will be removed soon from ide-tape!\n");
- }
- tape = kzalloc(sizeof (idetape_tape_t), GFP_KERNEL);
+ tape = kzalloc(sizeof(idetape_tape_t), GFP_KERNEL);
if (tape == NULL) {
- printk(KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
+ printk(KERN_ERR "ide-tape: %s: Can't allocate a tape struct\n",
+ drive->name);
goto failed;
}
@@ -3955,10 +3807,7 @@ failed:
return -ENODEV;
}
-MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
-MODULE_LICENSE("GPL");
-
-static void __exit idetape_exit (void)
+static void __exit idetape_exit(void)
{
driver_unregister(&idetape_driver.gen_driver);
class_destroy(idetape_sysfs_class);
@@ -3977,7 +3826,8 @@ static int __init idetape_init(void)
}
if (register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops)) {
- printk(KERN_ERR "ide-tape: Failed to register character device interface\n");
+ printk(KERN_ERR "ide-tape: Failed to register chrdev"
+ " interface\n");
error = -EBUSY;
goto out_free_class;
}
@@ -4000,3 +3850,5 @@ MODULE_ALIAS("ide:*m-tape*");
module_init(idetape_init);
module_exit(idetape_exit);
MODULE_ALIAS_CHARDEV_MAJOR(IDETAPE_MAJOR);
+MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 4e1da1c78cb..0518a2e948c 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -189,12 +189,11 @@ EXPORT_SYMBOL_GPL(do_rw_taskfile);
*/
static ide_startstop_t set_multmode_intr(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- u8 stat;
+ u8 stat = ide_read_status(drive);
- if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) {
+ if (OK_STAT(stat, READY_STAT, BAD_STAT))
drive->mult_count = drive->mult_req;
- } else {
+ else {
drive->mult_req = drive->mult_count = 0;
drive->special.b.recalibrate = 1;
(void) ide_dump_status(drive, "set_multmode", stat);
@@ -207,11 +206,10 @@ static ide_startstop_t set_multmode_intr(ide_drive_t *drive)
*/
static ide_startstop_t set_geometry_intr(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
int retries = 5;
u8 stat;
- while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
+ while (((stat = ide_read_status(drive)) & BUSY_STAT) && retries--)
udelay(10);
if (OK_STAT(stat, READY_STAT, BAD_STAT))
@@ -230,10 +228,9 @@ static ide_startstop_t set_geometry_intr(ide_drive_t *drive)
*/
static ide_startstop_t recal_intr(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- u8 stat;
+ u8 stat = ide_read_status(drive);
- if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), READY_STAT, BAD_STAT))
+ if (!OK_STAT(stat, READY_STAT, BAD_STAT))
return ide_error(drive, "recal_intr", stat);
return ide_stopped;
}
@@ -244,23 +241,23 @@ static ide_startstop_t recal_intr(ide_drive_t *drive)
static ide_startstop_t task_no_data_intr(ide_drive_t *drive)
{
ide_task_t *args = HWGROUP(drive)->rq->special;
- ide_hwif_t *hwif = HWIF(drive);
u8 stat;
local_irq_enable_in_hardirq();
- if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) {
+ stat = ide_read_status(drive);
+
+ if (!OK_STAT(stat, READY_STAT, BAD_STAT))
return ide_error(drive, "task_no_data_intr", stat);
/* calls ide_end_drive_cmd */
- }
+
if (args)
- ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
+ ide_end_drive_cmd(drive, stat, ide_read_error(drive));
return ide_stopped;
}
static u8 wait_drive_not_busy(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
int retries;
u8 stat;
@@ -269,7 +266,9 @@ static u8 wait_drive_not_busy(ide_drive_t *drive)
* This can take up to 10 usec, but we will wait max 1 ms.
*/
for (retries = 0; retries < 100; retries++) {
- if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT)
+ stat = ide_read_status(drive);
+
+ if (stat & BUSY_STAT)
udelay(10);
else
break;
@@ -408,7 +407,7 @@ static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
{
if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
- u8 err = drive->hwif->INB(IDE_ERROR_REG);
+ u8 err = ide_read_error(drive);
ide_end_drive_cmd(drive, stat, err);
return;
@@ -430,7 +429,7 @@ static ide_startstop_t task_in_intr(ide_drive_t *drive)
{
ide_hwif_t *hwif = drive->hwif;
struct request *rq = HWGROUP(drive)->rq;
- u8 stat = hwif->INB(IDE_STATUS_REG);
+ u8 stat = ide_read_status(drive);
/* new way for dealing with premature shared PCI interrupts */
if (!OK_STAT(stat, DRQ_STAT, BAD_R_STAT)) {
@@ -465,7 +464,7 @@ static ide_startstop_t task_out_intr (ide_drive_t *drive)
{
ide_hwif_t *hwif = drive->hwif;
struct request *rq = HWGROUP(drive)->rq;
- u8 stat = hwif->INB(IDE_STATUS_REG);
+ u8 stat = ide_read_status(drive);
if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat))
return task_error(drive, rq, __FUNCTION__, stat);
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index ac613600161..ad0e9955f73 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -618,60 +618,6 @@ abort:
EXPORT_SYMBOL(ide_unregister);
-
-/**
- * ide_setup_ports - set up IDE interface ports
- * @hw: register descriptions
- * @base: base register
- * @offsets: table of register offsets
- * @ctrl: control register
- * @ack_irq: IRQ ack
- * @irq: interrupt lie
- *
- * Setup hw_regs_t structure described by parameters. You
- * may set up the hw structure yourself OR use this routine to
- * do it for you. This is basically a helper
- *
- */
-
-void ide_setup_ports ( hw_regs_t *hw,
- unsigned long base, int *offsets,
- unsigned long ctrl, unsigned long intr,
- ide_ack_intr_t *ack_intr,
-/*
- * ide_io_ops_t *iops,
- */
- int irq)
-{
- int i;
-
- memset(hw, 0, sizeof(hw_regs_t));
- for (i = 0; i < IDE_NR_PORTS; i++) {
- if (offsets[i] == -1) {
- switch(i) {
- case IDE_CONTROL_OFFSET:
- hw->io_ports[i] = ctrl;
- break;
-#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
- case IDE_IRQ_OFFSET:
- hw->io_ports[i] = intr;
- break;
-#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
- default:
- hw->io_ports[i] = 0;
- break;
- }
- } else {
- hw->io_ports[i] = base + offsets[i];
- }
- }
- hw->irq = irq;
- hw->ack_intr = ack_intr;
-/*
- * hw->iops = iops;
- */
-}
-
void ide_init_port_hw(ide_hwif_t *hwif, hw_regs_t *hw)
{
memcpy(hwif->io_ports, hw->io_ports, sizeof(hwif->io_ports));
diff --git a/drivers/ide/legacy/buddha.c b/drivers/ide/legacy/buddha.c
index 8bdb79da17e..50ffa871d5e 100644
--- a/drivers/ide/legacy/buddha.c
+++ b/drivers/ide/legacy/buddha.c
@@ -56,31 +56,11 @@ static u_int xsurf_bases[XSURF_NUM_HWIFS] __initdata = {
XSURF_BASE1, XSURF_BASE2
};
-
/*
* Offsets from one of the above bases
*/
-#define BUDDHA_DATA 0x00
-#define BUDDHA_ERROR 0x06 /* see err-bits */
-#define BUDDHA_NSECTOR 0x0a /* nr of sectors to read/write */
-#define BUDDHA_SECTOR 0x0e /* starting sector */
-#define BUDDHA_LCYL 0x12 /* starting cylinder */
-#define BUDDHA_HCYL 0x16 /* high byte of starting cyl */
-#define BUDDHA_SELECT 0x1a /* 101dhhhh , d=drive, hhhh=head */
-#define BUDDHA_STATUS 0x1e /* see status-bits */
#define BUDDHA_CONTROL 0x11a
-#define XSURF_CONTROL -1 /* X-Surf has no CS1* (Control/AltStat) */
-
-static int buddha_offsets[IDE_NR_PORTS] __initdata = {
- BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
- BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, BUDDHA_CONTROL, -1
-};
-
-static int xsurf_offsets[IDE_NR_PORTS] __initdata = {
- BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
- BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, XSURF_CONTROL, -1
-};
/*
* Other registers
@@ -140,6 +120,26 @@ static int xsurf_ack_intr(ide_hwif_t *hwif)
return 1;
}
+static void __init buddha_setup_ports(hw_regs_t *hw, unsigned long base,
+ unsigned long ctl, unsigned long irq_port,
+ ide_ack_intr_t *ack_intr)
+{
+ int i;
+
+ memset(hw, 0, sizeof(*hw));
+
+ hw->io_ports[IDE_DATA_OFFSET] = base;
+
+ for (i = 1; i < 8; i++)
+ hw->io_ports[i] = base + 2 + i * 4;
+
+ hw->io_ports[IDE_CONTROL_OFFSET] = ctl;
+ hw->io_ports[IDE_IRQ_OFFSET] = irq_port;
+
+ hw->irq = IRQ_AMIGA_PORTS;
+ hw->ack_intr = ack_intr;
+}
+
/*
* Probe for a Buddha or Catweasel IDE interface
*/
@@ -202,22 +202,24 @@ fail_base2:
printk(KERN_INFO "ide: %s IDE controller\n",
buddha_board_name[type]);
- for(i=0;i<buddha_num_hwifs;i++) {
- if(type != BOARD_XSURF) {
- ide_setup_ports(&hw, (buddha_board+buddha_bases[i]),
- buddha_offsets, 0,
- (buddha_board+buddha_irqports[i]),
- buddha_ack_intr,
-// budda_iops,
- IRQ_AMIGA_PORTS);
+ for (i = 0; i < buddha_num_hwifs; i++) {
+ unsigned long base, ctl, irq_port;
+ ide_ack_intr_t *ack_intr;
+
+ if (type != BOARD_XSURF) {
+ base = buddha_board + buddha_bases[i];
+ ctl = base + BUDDHA_CONTROL;
+ irq_port = buddha_board + buddha_irqports[i];
+ ack_intr = buddha_ack_intr;
} else {
- ide_setup_ports(&hw, (buddha_board+xsurf_bases[i]),
- xsurf_offsets, 0,
- (buddha_board+xsurf_irqports[i]),
- xsurf_ack_intr,
-// xsurf_iops,
- IRQ_AMIGA_PORTS);
- }
+ base = buddha_board + xsurf_bases[i];
+ /* X-Surf has no CS1* (Control/AltStat) */
+ ctl = 0;
+ irq_port = buddha_board + xsurf_irqports[i];
+ ack_intr = xsurf_ack_intr;
+ }
+
+ buddha_setup_ports(&hw, base, ctl, irq_port, ack_intr);
hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
if (hwif) {
diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c
index 85b69a82825..f044048903b 100644
--- a/drivers/ide/legacy/falconide.c
+++ b/drivers/ide/legacy/falconide.c
@@ -33,22 +33,8 @@
* Offsets from the above base
*/
-#define ATA_HD_DATA 0x00
-#define ATA_HD_ERROR 0x05 /* see err-bits */
-#define ATA_HD_NSECTOR 0x09 /* nr of sectors to read/write */
-#define ATA_HD_SECTOR 0x0d /* starting sector */
-#define ATA_HD_LCYL 0x11 /* starting cylinder */
-#define ATA_HD_HCYL 0x15 /* high byte of starting cyl */
-#define ATA_HD_SELECT 0x19 /* 101dhhhh , d=drive, hhhh=head */
-#define ATA_HD_STATUS 0x1d /* see status-bits */
#define ATA_HD_CONTROL 0x39
-static int falconide_offsets[IDE_NR_PORTS] __initdata = {
- ATA_HD_DATA, ATA_HD_ERROR, ATA_HD_NSECTOR, ATA_HD_SECTOR, ATA_HD_LCYL,
- ATA_HD_HCYL, ATA_HD_SELECT, ATA_HD_STATUS, ATA_HD_CONTROL, -1
-};
-
-
/*
* falconide_intr_lock is used to obtain access to the IDE interrupt,
* which is shared between several drivers.
@@ -57,6 +43,22 @@ static int falconide_offsets[IDE_NR_PORTS] __initdata = {
int falconide_intr_lock;
EXPORT_SYMBOL(falconide_intr_lock);
+static void __init falconide_setup_ports(hw_regs_t *hw)
+{
+ int i;
+
+ memset(hw, 0, sizeof(*hw));
+
+ hw->io_ports[IDE_DATA_OFFSET] = ATA_HD_BASE;
+
+ for (i = 1; i < 8; i++)
+ hw->io_ports[i] = ATA_HD_BASE + 1 + i * 4;
+
+ hw->io_ports[IDE_CONTROL_OFFSET] = ATA_HD_CONTROL;
+
+ hw->irq = IRQ_MFP_IDE;
+ hw->ack_intr = NULL;
+}
/*
* Probe for a Falcon IDE interface
@@ -64,16 +66,15 @@ EXPORT_SYMBOL(falconide_intr_lock);
static int __init falconide_init(void)
{
- if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) {
hw_regs_t hw;
ide_hwif_t *hwif;
+ if (!MACH_IS_ATARI || !ATARIHW_PRESENT(IDE))
+ return 0;
+
printk(KERN_INFO "ide: Falcon IDE controller\n");
- ide_setup_ports(&hw, ATA_HD_BASE, falconide_offsets,
- 0, 0, NULL,
-// falconide_iops,
- IRQ_MFP_IDE);
+ falconide_setup_ports(&hw);
hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
if (hwif) {
@@ -85,9 +86,8 @@ static int __init falconide_init(void)
ide_device_add(idx, NULL);
}
- }
- return 0;
+ return 0;
}
module_init(falconide_init);
diff --git a/drivers/ide/legacy/gayle.c b/drivers/ide/legacy/gayle.c
index fc29ce75aff..9d3851d2767 100644
--- a/drivers/ide/legacy/gayle.c
+++ b/drivers/ide/legacy/gayle.c
@@ -34,22 +34,8 @@
* Offsets from one of the above bases
*/
-#define GAYLE_DATA 0x00
-#define GAYLE_ERROR 0x06 /* see err-bits */
-#define GAYLE_NSECTOR 0x0a /* nr of sectors to read/write */
-#define GAYLE_SECTOR 0x0e /* starting sector */
-#define GAYLE_LCYL 0x12 /* starting cylinder */
-#define GAYLE_HCYL 0x16 /* high byte of starting cyl */
-#define GAYLE_SELECT 0x1a /* 101dhhhh , d=drive, hhhh=head */
-#define GAYLE_STATUS 0x1e /* see status-bits */
#define GAYLE_CONTROL 0x101a
-static int gayle_offsets[IDE_NR_PORTS] __initdata = {
- GAYLE_DATA, GAYLE_ERROR, GAYLE_NSECTOR, GAYLE_SECTOR, GAYLE_LCYL,
- GAYLE_HCYL, GAYLE_SELECT, GAYLE_STATUS, -1, -1
-};
-
-
/*
* These are at different offsets from the base
*/
@@ -106,6 +92,26 @@ static int gayle_ack_intr_a1200(ide_hwif_t *hwif)
return 1;
}
+static void __init gayle_setup_ports(hw_regs_t *hw, unsigned long base,
+ unsigned long ctl, unsigned long irq_port,
+ ide_ack_intr_t *ack_intr);
+{
+ int i;
+
+ memset(hw, 0, sizeof(*hw));
+
+ hw->io_ports[IDE_DATA_OFFSET] = base;
+
+ for (i = 1; i < 8; i++)
+ hw->io_ports[i] = base + 2 + i * 4;
+
+ hw->io_ports[IDE_CONTROL_OFFSET] = ctl;
+ hw->io_ports[IDE_IRQ_OFFSET] = irq_port;
+
+ hw->irq = IRQ_AMIGA_PORTS;
+ hw->ack_intr = ack_intr;
+}
+
/*
* Probe for a Gayle IDE interface (and optionally for an IDE doubler)
*/
@@ -167,10 +173,7 @@ found:
base = (unsigned long)ZTWO_VADDR(phys_base);
ctrlport = GAYLE_HAS_CONTROL_REG ? (base + GAYLE_CONTROL) : 0;
- ide_setup_ports(&hw, base, gayle_offsets,
- ctrlport, irqport, ack_intr,
-// &gayle_iops,
- IRQ_AMIGA_PORTS);
+ gayle_setup_ports(&hw, base, ctrlport, irqport, ack_intr);
hwif = ide_find_port(base);
if (hwif) {
diff --git a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c
index 8e05d88e81b..0b0d8673192 100644
--- a/drivers/ide/legacy/hd.c
+++ b/drivers/ide/legacy/hd.c
@@ -421,11 +421,14 @@ static void bad_rw_intr(void)
static inline int wait_DRQ(void)
{
- int retries = 100000, stat;
+ int retries;
+ int stat;
- while (--retries > 0)
- if ((stat = inb_p(HD_STATUS)) & DRQ_STAT)
+ for (retries = 0; retries < 100000; retries++) {
+ stat = inb_p(HD_STATUS);
+ if (stat & DRQ_STAT)
return 0;
+ }
dump_status("wait_DRQ", stat);
return -1;
}
diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c
index 06df8df857a..a61e60737dc 100644
--- a/drivers/ide/legacy/macide.c
+++ b/drivers/ide/legacy/macide.c
@@ -31,14 +31,6 @@
* These match MkLinux so they should be correct.
*/
-#define IDE_DATA 0x00
-#define IDE_ERROR 0x04 /* see err-bits */
-#define IDE_NSECTOR 0x08 /* nr of sectors to read/write */
-#define IDE_SECTOR 0x0c /* starting sector */
-#define IDE_LCYL 0x10 /* starting cylinder */
-#define IDE_HCYL 0x14 /* high byte of starting cyl */
-#define IDE_SELECT 0x18 /* 101dhhhh , d=drive, hhhh=head */
-#define IDE_STATUS 0x1c /* see status-bits */
#define IDE_CONTROL 0x38 /* control/altstatus */
/*
@@ -63,11 +55,6 @@
volatile unsigned char *ide_ifr = (unsigned char *) (IDE_BASE + IDE_IFR);
-static int macide_offsets[IDE_NR_PORTS] = {
- IDE_DATA, IDE_ERROR, IDE_NSECTOR, IDE_SECTOR, IDE_LCYL,
- IDE_HCYL, IDE_SELECT, IDE_STATUS, IDE_CONTROL
-};
-
int macide_ack_intr(ide_hwif_t* hwif)
{
if (*ide_ifr & 0x20) {
@@ -77,6 +64,22 @@ int macide_ack_intr(ide_hwif_t* hwif)
return 0;
}
+static void __init macide_setup_ports(hw_regs_t *hw, unsigned long base,
+ int irq, ide_ack_intr_t *ack_intr)
+{
+ int i;
+
+ memset(hw, 0, sizeof(*hw));
+
+ for (i = 0; i < 8; i++)
+ hw->io_ports[i] = base + i * 4;
+
+ hw->io_ports[IDE_CONTROL_OFFSET] = IDE_CONTROL;
+
+ hw->irq = irq;
+ hw->ack_intr = ack_intr;
+}
+
static const char *mac_ide_name[] =
{ "Quadra", "Powerbook", "Powerbook Baboon" };
@@ -86,27 +89,27 @@ static const char *mac_ide_name[] =
static int __init macide_init(void)
{
- hw_regs_t hw;
ide_hwif_t *hwif;
+ ide_ack_intr_t *ack_intr;
+ unsigned long base;
+ int irq;
+ hw_regs_t hw;
switch (macintosh_config->ide_type) {
case MAC_IDE_QUADRA:
- ide_setup_ports(&hw, IDE_BASE, macide_offsets,
- 0, 0, macide_ack_intr,
-// quadra_ide_iops,
- IRQ_NUBUS_F);
+ base = IDE_BASE;
+ ack_intr = macide_ack_intr;
+ irq = IRQ_NUBUS_F;
break;
case MAC_IDE_PB:
- ide_setup_ports(&hw, IDE_BASE, macide_offsets,
- 0, 0, macide_ack_intr,
-// macide_pb_iops,
- IRQ_NUBUS_C);
+ base = IDE_BASE;
+ ack_intr = macide_ack_intr;
+ irq = IRQ_NUBUS_C;
break;
case MAC_IDE_BABOON:
- ide_setup_ports(&hw, BABOON_BASE, macide_offsets,
- 0, 0, NULL,
-// macide_baboon_iops,
- IRQ_BABOON_1);
+ base = BABOON_BASE;
+ ack_intr = NULL;
+ irq = IRQ_BABOON_1;
break;
default:
return -ENODEV;
@@ -115,6 +118,8 @@ static int __init macide_init(void)
printk(KERN_INFO "ide: Macintosh %s IDE controller\n",
mac_ide_name[macintosh_config->ide_type - 1]);
+ macide_setup_ports(&hw, base, irq, ack_intr);
+
hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
if (hwif) {
u8 index = hwif->index;
diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c
index 2f0b34d892a..1381b91bc31 100644
--- a/drivers/ide/legacy/q40ide.c
+++ b/drivers/ide/legacy/q40ide.c
@@ -66,16 +66,12 @@ static int q40ide_default_irq(unsigned long base)
/*
- * This is very similar to ide_setup_ports except that addresses
- * are pretranslated for q40 ISA access
+ * Addresses are pretranslated for Q40 ISA access.
*/
void q40_ide_setup_ports ( hw_regs_t *hw,
unsigned long base, int *offsets,
unsigned long ctrl, unsigned long intr,
ide_ack_intr_t *ack_intr,
-/*
- * ide_io_ops_t *iops,
- */
int irq)
{
int i;
@@ -92,9 +88,6 @@ void q40_ide_setup_ports ( hw_regs_t *hw,
hw->irq = irq;
hw->ack_intr = ack_intr;
-/*
- * hw->iops = iops;
- */
}
diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile
index 94803253e8a..02e6ee7d751 100644
--- a/drivers/ide/pci/Makefile
+++ b/drivers/ide/pci/Makefile
@@ -34,7 +34,8 @@ obj-$(CONFIG_BLK_DEV_TRM290) += trm290.o
obj-$(CONFIG_BLK_DEV_VIA82CXXX) += via82cxxx.o
# Must appear at the end of the block
-obj-$(CONFIG_BLK_DEV_GENERIC) += generic.o
+obj-$(CONFIG_BLK_DEV_GENERIC) += ide-pci-generic.o
+ide-pci-generic-y += generic.o
ifeq ($(CONFIG_BLK_DEV_CMD640), m)
obj-m += cmd640.o
diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c
index 9262a9174b4..7fd83a9d4de 100644
--- a/drivers/ide/pci/generic.c
+++ b/drivers/ide/pci/generic.c
@@ -29,19 +29,6 @@
static int ide_generic_all; /* Set to claim all devices */
-/*
- * the module_param_named() was added for the modular case
- * the __setup() is left as compatibility for existing setups
- */
-#ifndef MODULE
-static int __init ide_generic_all_on(char *unused)
-{
- ide_generic_all = 1;
- printk(KERN_INFO "IDE generic will claim all unknown PCI IDE storage controllers.\n");
- return 1;
-}
-const __setup("all-generic-ide", ide_generic_all_on);
-#endif
module_param_named(all_generic_ide, ide_generic_all, bool, 0444);
MODULE_PARM_DESC(all_generic_ide, "IDE generic will claim all unknown PCI IDE storage controllers.");
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
index ef5b39fa042..cc4be9621bc 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/pci/siimage.c
@@ -704,9 +704,6 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
hwif->sata_scr[SATA_STATUS_OFFSET] = base + 0x104;
hwif->sata_scr[SATA_ERROR_OFFSET] = base + 0x108;
hwif->sata_scr[SATA_CONTROL_OFFSET] = base + 0x100;
- hwif->sata_misc[SATA_MISC_OFFSET] = base + 0x140;
- hwif->sata_misc[SATA_PHY_OFFSET] = base + 0x144;
- hwif->sata_misc[SATA_IEN_OFFSET] = base + 0x148;
}
memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c
index 2ae6c6016a8..28ae15ed12c 100644
--- a/drivers/input/touchscreen/h3600_ts_input.c
+++ b/drivers/input/touchscreen/h3600_ts_input.c
@@ -109,7 +109,7 @@ struct h3600_dev {
static irqreturn_t action_button_handler(int irq, void *dev_id)
{
int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
- struct input_dev *dev = (struct input_dev *) dev_id;
+ struct input_dev *dev = dev_id;
input_report_key(dev, KEY_ENTER, down);
input_sync(dev);
@@ -120,7 +120,7 @@ static irqreturn_t action_button_handler(int irq, void *dev_id)
static irqreturn_t npower_button_handler(int irq, void *dev_id)
{
int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
- struct input_dev *dev = (struct input_dev *) dev_id;
+ struct input_dev *dev = dev_id;
/*
* This interrupt is only called when we release the key. So we have
diff --git a/drivers/isdn/act2000/module.c b/drivers/isdn/act2000/module.c
index ee2b0b9f8f4..8325022e2be 100644
--- a/drivers/isdn/act2000/module.c
+++ b/drivers/isdn/act2000/module.c
@@ -310,7 +310,7 @@ act2000_command(act2000_card * card, isdn_ctrl * c)
}
break;
case ISDN_CMD_DIAL:
- if (!card->flags & ACT2000_FLAGS_RUNNING)
+ if (!(card->flags & ACT2000_FLAGS_RUNNING))
return -ENODEV;
if (!(chan = find_channel(card, c->arg & 0x0f)))
break;
@@ -339,7 +339,7 @@ act2000_command(act2000_card * card, isdn_ctrl * c)
}
return ret;
case ISDN_CMD_ACCEPTD:
- if (!card->flags & ACT2000_FLAGS_RUNNING)
+ if (!(card->flags & ACT2000_FLAGS_RUNNING))
return -ENODEV;
if (!(chan = find_channel(card, c->arg & 0x0f)))
break;
@@ -347,11 +347,11 @@ act2000_command(act2000_card * card, isdn_ctrl * c)
actcapi_select_b2_protocol_req(card, chan);
return 0;
case ISDN_CMD_ACCEPTB:
- if (!card->flags & ACT2000_FLAGS_RUNNING)
+ if (!(card->flags & ACT2000_FLAGS_RUNNING))
return -ENODEV;
return 0;
case ISDN_CMD_HANGUP:
- if (!card->flags & ACT2000_FLAGS_RUNNING)
+ if (!(card->flags & ACT2000_FLAGS_RUNNING))
return -ENODEV;
if (!(chan = find_channel(card, c->arg & 0x0f)))
break;
@@ -366,7 +366,7 @@ act2000_command(act2000_card * card, isdn_ctrl * c)
}
return 0;
case ISDN_CMD_SETEAZ:
- if (!card->flags & ACT2000_FLAGS_RUNNING)
+ if (!(card->flags & ACT2000_FLAGS_RUNNING))
return -ENODEV;
if (!(chan = find_channel(card, c->arg & 0x0f)))
break;
@@ -386,7 +386,7 @@ act2000_command(act2000_card * card, isdn_ctrl * c)
actcapi_listen_req(card);
return 0;
case ISDN_CMD_CLREAZ:
- if (!card->flags & ACT2000_FLAGS_RUNNING)
+ if (!(card->flags & ACT2000_FLAGS_RUNNING))
return -ENODEV;
if (!(chan = find_channel(card, c->arg & 0x0f)))
break;
@@ -394,14 +394,14 @@ act2000_command(act2000_card * card, isdn_ctrl * c)
actcapi_listen_req(card);
return 0;
case ISDN_CMD_SETL2:
- if (!card->flags & ACT2000_FLAGS_RUNNING)
+ if (!(card->flags & ACT2000_FLAGS_RUNNING))
return -ENODEV;
if (!(chan = find_channel(card, c->arg & 0x0f)))
break;
chan->l2prot = (c->arg >> 8);
return 0;
case ISDN_CMD_SETL3:
- if (!card->flags & ACT2000_FLAGS_RUNNING)
+ if (!(card->flags & ACT2000_FLAGS_RUNNING))
return -ENODEV;
if ((c->arg >> 8) != ISDN_PROTO_L3_TRANS) {
printk(KERN_WARNING "L3 protocol unknown\n");
@@ -524,7 +524,7 @@ if_writecmd(const u_char __user *buf, int len, int id, int channel)
act2000_card *card = act2000_findcard(id);
if (card) {
- if (!card->flags & ACT2000_FLAGS_RUNNING)
+ if (!(card->flags & ACT2000_FLAGS_RUNNING))
return -ENODEV;
return (len);
}
@@ -539,7 +539,7 @@ if_readstatus(u_char __user * buf, int len, int id, int channel)
act2000_card *card = act2000_findcard(id);
if (card) {
- if (!card->flags & ACT2000_FLAGS_RUNNING)
+ if (!(card->flags & ACT2000_FLAGS_RUNNING))
return -ENODEV;
return (act2000_readstatus(buf, len, card));
}
@@ -554,7 +554,7 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
act2000_card *card = act2000_findcard(id);
if (card) {
- if (!card->flags & ACT2000_FLAGS_RUNNING)
+ if (!(card->flags & ACT2000_FLAGS_RUNNING))
return -ENODEV;
return (act2000_sendbuf(card, channel, ack, skb));
}
diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c
index 00a3be5b862..091deb9d1c4 100644
--- a/drivers/isdn/gigaset/asyncdata.c
+++ b/drivers/isdn/gigaset/asyncdata.c
@@ -350,8 +350,8 @@ void gigaset_m10x_input(struct inbuf_t *inbuf)
unsigned char *src, c;
int procbytes;
- head = atomic_read(&inbuf->head);
- tail = atomic_read(&inbuf->tail);
+ head = inbuf->head;
+ tail = inbuf->tail;
gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
if (head != tail) {
@@ -361,7 +361,7 @@ void gigaset_m10x_input(struct inbuf_t *inbuf)
gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes);
while (numbytes) {
- if (atomic_read(&cs->mstate) == MS_LOCKED) {
+ if (cs->mstate == MS_LOCKED) {
procbytes = lock_loop(src, numbytes, inbuf);
src += procbytes;
numbytes -= procbytes;
@@ -436,7 +436,7 @@ nextbyte:
}
gig_dbg(DEBUG_INTR, "setting head to %u", head);
- atomic_set(&inbuf->head, head);
+ inbuf->head = head;
}
}
EXPORT_SYMBOL_GPL(gigaset_m10x_input);
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index af7648274b3..5255b5e20e1 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -73,6 +73,14 @@ static int gigaset_probe(struct usb_interface *interface,
/* Function will be called if the device is unplugged */
static void gigaset_disconnect(struct usb_interface *interface);
+/* functions called before/after suspend */
+static int gigaset_suspend(struct usb_interface *intf, pm_message_t message);
+static int gigaset_resume(struct usb_interface *intf);
+
+/* functions called before/after device reset */
+static int gigaset_pre_reset(struct usb_interface *intf);
+static int gigaset_post_reset(struct usb_interface *intf);
+
static int atread_submit(struct cardstate *, int);
static void stopurbs(struct bas_bc_state *);
static int req_submit(struct bc_state *, int, int, int);
@@ -105,8 +113,9 @@ struct bas_cardstate {
unsigned char int_in_buf[3];
spinlock_t lock; /* locks all following */
- atomic_t basstate; /* bitmap (BS_*) */
+ int basstate; /* bitmap (BS_*) */
int pending; /* uncompleted base request */
+ wait_queue_head_t waitqueue;
int rcvbuf_size; /* size of AT receive buffer */
/* 0: no receive in progress */
int retry_cmd_in; /* receive req retry count */
@@ -121,10 +130,10 @@ struct bas_cardstate {
#define BS_ATTIMER 0x020 /* waiting for HD_READY_SEND_ATDATA */
#define BS_ATRDPEND 0x040 /* urb_cmd_in in use */
#define BS_ATWRPEND 0x080 /* urb_cmd_out in use */
+#define BS_SUSPEND 0x100 /* USB port suspended */
static struct gigaset_driver *driver = NULL;
-static struct cardstate *cardstate = NULL;
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver gigaset_usb_driver = {
@@ -132,6 +141,11 @@ static struct usb_driver gigaset_usb_driver = {
.probe = gigaset_probe,
.disconnect = gigaset_disconnect,
.id_table = gigaset_table,
+ .suspend = gigaset_suspend,
+ .resume = gigaset_resume,
+ .reset_resume = gigaset_post_reset,
+ .pre_reset = gigaset_pre_reset,
+ .post_reset = gigaset_post_reset,
};
/* get message text for usb_submit_urb return code
@@ -248,12 +262,12 @@ static inline void dump_urb(enum debuglevel level, const char *tag,
if (urb) {
gig_dbg(level,
" dev=0x%08lx, pipe=%s:EP%d/DV%d:%s, "
- "status=%d, hcpriv=0x%08lx, transfer_flags=0x%x,",
+ "hcpriv=0x%08lx, transfer_flags=0x%x,",
(unsigned long) urb->dev,
usb_pipetype_str(urb->pipe),
usb_pipeendpoint(urb->pipe), usb_pipedevice(urb->pipe),
usb_pipein(urb->pipe) ? "in" : "out",
- urb->status, (unsigned long) urb->hcpriv,
+ (unsigned long) urb->hcpriv,
urb->transfer_flags);
gig_dbg(level,
" transfer_buffer=0x%08lx[%d], actual_length=%d, "
@@ -355,27 +369,27 @@ static void check_pending(struct bas_cardstate *ucs)
case 0:
break;
case HD_OPEN_ATCHANNEL:
- if (atomic_read(&ucs->basstate) & BS_ATOPEN)
+ if (ucs->basstate & BS_ATOPEN)
ucs->pending = 0;
break;
case HD_OPEN_B1CHANNEL:
- if (atomic_read(&ucs->basstate) & BS_B1OPEN)
+ if (ucs->basstate & BS_B1OPEN)
ucs->pending = 0;
break;
case HD_OPEN_B2CHANNEL:
- if (atomic_read(&ucs->basstate) & BS_B2OPEN)
+ if (ucs->basstate & BS_B2OPEN)
ucs->pending = 0;
break;
case HD_CLOSE_ATCHANNEL:
- if (!(atomic_read(&ucs->basstate) & BS_ATOPEN))
+ if (!(ucs->basstate & BS_ATOPEN))
ucs->pending = 0;
break;
case HD_CLOSE_B1CHANNEL:
- if (!(atomic_read(&ucs->basstate) & BS_B1OPEN))
+ if (!(ucs->basstate & BS_B1OPEN))
ucs->pending = 0;
break;
case HD_CLOSE_B2CHANNEL:
- if (!(atomic_read(&ucs->basstate) & BS_B2OPEN))
+ if (!(ucs->basstate & BS_B2OPEN))
ucs->pending = 0;
break;
case HD_DEVICE_INIT_ACK: /* no reply expected */
@@ -441,8 +455,8 @@ inline static int update_basstate(struct bas_cardstate *ucs,
int state;
spin_lock_irqsave(&ucs->lock, flags);
- state = atomic_read(&ucs->basstate);
- atomic_set(&ucs->basstate, (state & ~clear) | set);
+ state = ucs->basstate;
+ ucs->basstate = (state & ~clear) | set;
spin_unlock_irqrestore(&ucs->lock, flags);
return state;
}
@@ -459,11 +473,13 @@ static void read_ctrl_callback(struct urb *urb)
struct inbuf_t *inbuf = urb->context;
struct cardstate *cs = inbuf->cs;
struct bas_cardstate *ucs = cs->hw.bas;
+ int status = urb->status;
int have_data = 0;
unsigned numbytes;
int rc;
update_basstate(ucs, 0, BS_ATRDPEND);
+ wake_up(&ucs->waitqueue);
if (!ucs->rcvbuf_size) {
dev_warn(cs->dev, "%s: no receive in progress\n", __func__);
@@ -472,7 +488,7 @@ static void read_ctrl_callback(struct urb *urb)
del_timer(&ucs->timer_cmd_in);
- switch (urb->status) {
+ switch (status) {
case 0: /* normal completion */
numbytes = urb->actual_length;
if (unlikely(numbytes != ucs->rcvbuf_size)) {
@@ -506,12 +522,12 @@ static void read_ctrl_callback(struct urb *urb)
case -ESHUTDOWN: /* device shut down */
/* no action necessary */
gig_dbg(DEBUG_USBREQ, "%s: %s",
- __func__, get_usb_statmsg(urb->status));
+ __func__, get_usb_statmsg(status));
break;
default: /* severe trouble */
dev_warn(cs->dev, "control read: %s\n",
- get_usb_statmsg(urb->status));
+ get_usb_statmsg(status));
if (ucs->retry_cmd_in++ < BAS_RETRY) {
dev_notice(cs->dev, "control read: retry %d\n",
ucs->retry_cmd_in);
@@ -550,17 +566,28 @@ static void read_ctrl_callback(struct urb *urb)
static int atread_submit(struct cardstate *cs, int timeout)
{
struct bas_cardstate *ucs = cs->hw.bas;
+ int basstate;
int ret;
gig_dbg(DEBUG_USBREQ, "-------> HD_READ_ATMESSAGE (%d)",
ucs->rcvbuf_size);
- if (update_basstate(ucs, BS_ATRDPEND, 0) & BS_ATRDPEND) {
+ basstate = update_basstate(ucs, BS_ATRDPEND, 0);
+ if (basstate & BS_ATRDPEND) {
dev_err(cs->dev,
"could not submit HD_READ_ATMESSAGE: URB busy\n");
return -EBUSY;
}
+ if (basstate & BS_SUSPEND) {
+ dev_notice(cs->dev,
+ "HD_READ_ATMESSAGE not submitted, "
+ "suspend in progress\n");
+ update_basstate(ucs, 0, BS_ATRDPEND);
+ /* treat like disconnect */
+ return -ENODEV;
+ }
+
ucs->dr_cmd_in.bRequestType = IN_VENDOR_REQ;
ucs->dr_cmd_in.bRequest = HD_READ_ATMESSAGE;
ucs->dr_cmd_in.wValue = 0;
@@ -601,12 +628,13 @@ static void read_int_callback(struct urb *urb)
struct cardstate *cs = urb->context;
struct bas_cardstate *ucs = cs->hw.bas;
struct bc_state *bcs;
+ int status = urb->status;
unsigned long flags;
int rc;
unsigned l;
int channel;
- switch (urb->status) {
+ switch (status) {
case 0: /* success */
break;
case -ENOENT: /* cancelled */
@@ -614,7 +642,7 @@ static void read_int_callback(struct urb *urb)
case -EINPROGRESS: /* pending */
/* ignore silently */
gig_dbg(DEBUG_USBREQ, "%s: %s",
- __func__, get_usb_statmsg(urb->status));
+ __func__, get_usb_statmsg(status));
return;
case -ENODEV: /* device removed */
case -ESHUTDOWN: /* device shut down */
@@ -623,7 +651,7 @@ static void read_int_callback(struct urb *urb)
return;
default: /* severe trouble */
dev_warn(cs->dev, "interrupt read: %s\n",
- get_usb_statmsg(urb->status));
+ get_usb_statmsg(status));
//FIXME corrective action? resubmission always ok?
goto resubmit;
}
@@ -745,6 +773,7 @@ static void read_int_callback(struct urb *urb)
}
check_pending(ucs);
+ wake_up(&ucs->waitqueue);
resubmit:
rc = usb_submit_urb(urb, GFP_ATOMIC);
@@ -766,17 +795,18 @@ static void read_iso_callback(struct urb *urb)
{
struct bc_state *bcs;
struct bas_bc_state *ubc;
+ int status = urb->status;
unsigned long flags;
int i, rc;
/* status codes not worth bothering the tasklet with */
- if (unlikely(urb->status == -ENOENT ||
- urb->status == -ECONNRESET ||
- urb->status == -EINPROGRESS ||
- urb->status == -ENODEV ||
- urb->status == -ESHUTDOWN)) {
+ if (unlikely(status == -ENOENT ||
+ status == -ECONNRESET ||
+ status == -EINPROGRESS ||
+ status == -ENODEV ||
+ status == -ESHUTDOWN)) {
gig_dbg(DEBUG_ISO, "%s: %s",
- __func__, get_usb_statmsg(urb->status));
+ __func__, get_usb_statmsg(status));
return;
}
@@ -787,10 +817,11 @@ static void read_iso_callback(struct urb *urb)
if (likely(ubc->isoindone == NULL)) {
/* pass URB to tasklet */
ubc->isoindone = urb;
+ ubc->isoinstatus = status;
tasklet_schedule(&ubc->rcvd_tasklet);
} else {
/* tasklet still busy, drop data and resubmit URB */
- ubc->loststatus = urb->status;
+ ubc->loststatus = status;
for (i = 0; i < BAS_NUMFRAMES; i++) {
ubc->isoinlost += urb->iso_frame_desc[i].actual_length;
if (unlikely(urb->iso_frame_desc[i].status != 0 &&
@@ -800,7 +831,7 @@ static void read_iso_callback(struct urb *urb)
urb->iso_frame_desc[i].status = 0;
urb->iso_frame_desc[i].actual_length = 0;
}
- if (likely(atomic_read(&ubc->running))) {
+ if (likely(ubc->running)) {
/* urb->dev is clobbered by USB subsystem */
urb->dev = bcs->cs->hw.bas->udev;
urb->transfer_flags = URB_ISO_ASAP;
@@ -831,22 +862,24 @@ static void write_iso_callback(struct urb *urb)
{
struct isow_urbctx_t *ucx;
struct bas_bc_state *ubc;
+ int status = urb->status;
unsigned long flags;
/* status codes not worth bothering the tasklet with */
- if (unlikely(urb->status == -ENOENT ||
- urb->status == -ECONNRESET ||
- urb->status == -EINPROGRESS ||
- urb->status == -ENODEV ||
- urb->status == -ESHUTDOWN)) {
+ if (unlikely(status == -ENOENT ||
+ status == -ECONNRESET ||
+ status == -EINPROGRESS ||
+ status == -ENODEV ||
+ status == -ESHUTDOWN)) {
gig_dbg(DEBUG_ISO, "%s: %s",
- __func__, get_usb_statmsg(urb->status));
+ __func__, get_usb_statmsg(status));
return;
}
/* pass URB context to tasklet */
ucx = urb->context;
ubc = ucx->bcs->hw.bas;
+ ucx->status = status;
spin_lock_irqsave(&ubc->isooutlock, flags);
ubc->isooutovfl = ubc->isooutdone;
@@ -875,7 +908,7 @@ static int starturbs(struct bc_state *bcs)
bcs->inputstate |= INS_flag_hunt;
/* submit all isochronous input URBs */
- atomic_set(&ubc->running, 1);
+ ubc->running = 1;
for (k = 0; k < BAS_INURBS; k++) {
urb = ubc->isoinurbs[k];
if (!urb) {
@@ -932,15 +965,15 @@ static int starturbs(struct bc_state *bcs)
ubc->isoouturbs[k].limit = -1;
}
- /* submit two URBs, keep third one */
- for (k = 0; k < 2; ++k) {
+ /* keep one URB free, submit the others */
+ for (k = 0; k < BAS_OUTURBS-1; ++k) {
dump_urb(DEBUG_ISO, "Initial isoc write", urb);
rc = usb_submit_urb(ubc->isoouturbs[k].urb, GFP_ATOMIC);
if (rc != 0)
goto error;
}
dump_urb(DEBUG_ISO, "Initial isoc write (free)", urb);
- ubc->isooutfree = &ubc->isoouturbs[2];
+ ubc->isooutfree = &ubc->isoouturbs[BAS_OUTURBS-1];
ubc->isooutdone = ubc->isooutovfl = NULL;
return 0;
error:
@@ -958,7 +991,7 @@ static void stopurbs(struct bas_bc_state *ubc)
{
int k, rc;
- atomic_set(&ubc->running, 0);
+ ubc->running = 0;
for (k = 0; k < BAS_INURBS; ++k) {
rc = usb_unlink_urb(ubc->isoinurbs[k]);
@@ -1034,7 +1067,7 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx)
}
break;
}
- ucx->limit = atomic_read(&ubc->isooutbuf->nextread);
+ ucx->limit = ubc->isooutbuf->nextread;
ifd->status = 0;
ifd->actual_length = 0;
}
@@ -1070,6 +1103,7 @@ static void write_iso_tasklet(unsigned long data)
struct cardstate *cs = bcs->cs;
struct isow_urbctx_t *done, *next, *ovfl;
struct urb *urb;
+ int status;
struct usb_iso_packet_descriptor *ifd;
int offset;
unsigned long flags;
@@ -1080,7 +1114,7 @@ static void write_iso_tasklet(unsigned long data)
/* loop while completed URBs arrive in time */
for (;;) {
- if (unlikely(!(atomic_read(&ubc->running)))) {
+ if (unlikely(!(ubc->running))) {
gig_dbg(DEBUG_ISO, "%s: not running", __func__);
return;
}
@@ -1126,7 +1160,8 @@ static void write_iso_tasklet(unsigned long data)
/* process completed URB */
urb = done->urb;
- switch (urb->status) {
+ status = done->status;
+ switch (status) {
case -EXDEV: /* partial completion */
gig_dbg(DEBUG_ISO, "%s: URB partially completed",
__func__);
@@ -1179,12 +1214,12 @@ static void write_iso_tasklet(unsigned long data)
break;
default: /* severe trouble */
dev_warn(cs->dev, "isochronous write: %s\n",
- get_usb_statmsg(urb->status));
+ get_usb_statmsg(status));
}
/* mark the write buffer area covered by this URB as free */
if (done->limit >= 0)
- atomic_set(&ubc->isooutbuf->read, done->limit);
+ ubc->isooutbuf->read = done->limit;
/* mark URB as free */
spin_lock_irqsave(&ubc->isooutlock, flags);
@@ -1233,6 +1268,7 @@ static void read_iso_tasklet(unsigned long data)
struct bas_bc_state *ubc = bcs->hw.bas;
struct cardstate *cs = bcs->cs;
struct urb *urb;
+ int status;
char *rcvbuf;
unsigned long flags;
int totleft, numbytes, offset, frame, rc;
@@ -1245,6 +1281,7 @@ static void read_iso_tasklet(unsigned long data)
spin_unlock_irqrestore(&ubc->isoinlock, flags);
return;
}
+ status = ubc->isoinstatus;
ubc->isoindone = NULL;
if (unlikely(ubc->loststatus != -EINPROGRESS)) {
dev_warn(cs->dev,
@@ -1256,15 +1293,15 @@ static void read_iso_tasklet(unsigned long data)
}
spin_unlock_irqrestore(&ubc->isoinlock, flags);
- if (unlikely(!(atomic_read(&ubc->running)))) {
+ if (unlikely(!(ubc->running))) {
gig_dbg(DEBUG_ISO,
"%s: channel not running, "
"dropped URB with status: %s",
- __func__, get_usb_statmsg(urb->status));
+ __func__, get_usb_statmsg(status));
return;
}
- switch (urb->status) {
+ switch (status) {
case 0: /* normal completion */
break;
case -EXDEV: /* inspect individual frames
@@ -1276,7 +1313,7 @@ static void read_iso_tasklet(unsigned long data)
case -ECONNRESET:
case -EINPROGRESS:
gig_dbg(DEBUG_ISO, "%s: %s",
- __func__, get_usb_statmsg(urb->status));
+ __func__, get_usb_statmsg(status));
continue; /* -> skip */
case -EPIPE:
dev_err(cs->dev, "isochronous read stalled\n");
@@ -1284,7 +1321,7 @@ static void read_iso_tasklet(unsigned long data)
continue; /* -> skip */
default: /* severe trouble */
dev_warn(cs->dev, "isochronous read: %s\n",
- get_usb_statmsg(urb->status));
+ get_usb_statmsg(status));
goto error;
}
@@ -1406,6 +1443,8 @@ static void req_timeout(unsigned long data)
dev_warn(bcs->cs->dev, "request 0x%02x timed out, clearing\n",
pending);
}
+
+ wake_up(&ucs->waitqueue);
}
/* write_ctrl_callback
@@ -1418,11 +1457,12 @@ static void req_timeout(unsigned long data)
static void write_ctrl_callback(struct urb *urb)
{
struct bas_cardstate *ucs = urb->context;
+ int status = urb->status;
int rc;
unsigned long flags;
/* check status */
- switch (urb->status) {
+ switch (status) {
case 0: /* normal completion */
spin_lock_irqsave(&ucs->lock, flags);
switch (ucs->pending) {
@@ -1441,20 +1481,22 @@ static void write_ctrl_callback(struct urb *urb)
case -ESHUTDOWN: /* device shut down */
/* ignore silently */
gig_dbg(DEBUG_USBREQ, "%s: %s",
- __func__, get_usb_statmsg(urb->status));
+ __func__, get_usb_statmsg(status));
break;
default: /* any failure */
- if (++ucs->retry_ctrl > BAS_RETRY) {
+ /* don't retry if suspend requested */
+ if (++ucs->retry_ctrl > BAS_RETRY ||
+ (ucs->basstate & BS_SUSPEND)) {
dev_err(&ucs->interface->dev,
"control request 0x%02x failed: %s\n",
ucs->dr_ctrl.bRequest,
- get_usb_statmsg(urb->status));
+ get_usb_statmsg(status));
break; /* give up */
}
dev_notice(&ucs->interface->dev,
"control request 0x%02x: %s, retry %d\n",
- ucs->dr_ctrl.bRequest, get_usb_statmsg(urb->status),
+ ucs->dr_ctrl.bRequest, get_usb_statmsg(status),
ucs->retry_ctrl);
/* urb->dev is clobbered by USB subsystem */
urb->dev = ucs->udev;
@@ -1474,6 +1516,7 @@ static void write_ctrl_callback(struct urb *urb)
del_timer(&ucs->timer_ctrl);
ucs->pending = 0;
spin_unlock_irqrestore(&ucs->lock, flags);
+ wake_up(&ucs->waitqueue);
}
/* req_submit
@@ -1548,37 +1591,46 @@ static int req_submit(struct bc_state *bcs, int req, int val, int timeout)
*/
static int gigaset_init_bchannel(struct bc_state *bcs)
{
+ struct cardstate *cs = bcs->cs;
int req, ret;
unsigned long flags;
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (unlikely(!bcs->cs->connected)) {
+ spin_lock_irqsave(&cs->lock, flags);
+ if (unlikely(!cs->connected)) {
gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
+ spin_unlock_irqrestore(&cs->lock, flags);
return -ENODEV;
}
+ if (cs->hw.bas->basstate & BS_SUSPEND) {
+ dev_notice(cs->dev,
+ "not starting isochronous I/O, "
+ "suspend in progress\n");
+ spin_unlock_irqrestore(&cs->lock, flags);
+ return -EHOSTUNREACH;
+ }
+
if ((ret = starturbs(bcs)) < 0) {
- dev_err(bcs->cs->dev,
+ dev_err(cs->dev,
"could not start isochronous I/O for channel B%d: %s\n",
bcs->channel + 1,
ret == -EFAULT ? "null URB" : get_usb_rcmsg(ret));
if (ret != -ENODEV)
error_hangup(bcs);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
+ spin_unlock_irqrestore(&cs->lock, flags);
return ret;
}
req = bcs->channel ? HD_OPEN_B2CHANNEL : HD_OPEN_B1CHANNEL;
if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0) {
- dev_err(bcs->cs->dev, "could not open channel B%d\n",
+ dev_err(cs->dev, "could not open channel B%d\n",
bcs->channel + 1);
stopurbs(bcs->hw.bas);
if (ret != -ENODEV)
error_hangup(bcs);
}
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
+ spin_unlock_irqrestore(&cs->lock, flags);
return ret;
}
@@ -1594,20 +1646,20 @@ static int gigaset_init_bchannel(struct bc_state *bcs)
*/
static int gigaset_close_bchannel(struct bc_state *bcs)
{
+ struct cardstate *cs = bcs->cs;
int req, ret;
unsigned long flags;
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (unlikely(!bcs->cs->connected)) {
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
+ spin_lock_irqsave(&cs->lock, flags);
+ if (unlikely(!cs->connected)) {
+ spin_unlock_irqrestore(&cs->lock, flags);
gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__);
return -ENODEV;
}
- if (!(atomic_read(&bcs->cs->hw.bas->basstate) &
- (bcs->channel ? BS_B2OPEN : BS_B1OPEN))) {
+ if (!(cs->hw.bas->basstate & (bcs->channel ? BS_B2OPEN : BS_B1OPEN))) {
/* channel not running: just signal common.c */
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
+ spin_unlock_irqrestore(&cs->lock, flags);
gigaset_bchannel_down(bcs);
return 0;
}
@@ -1615,10 +1667,10 @@ static int gigaset_close_bchannel(struct bc_state *bcs)
/* channel running: tell device to close it */
req = bcs->channel ? HD_CLOSE_B2CHANNEL : HD_CLOSE_B1CHANNEL;
if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0)
- dev_err(bcs->cs->dev, "closing channel B%d failed\n",
+ dev_err(cs->dev, "closing channel B%d failed\n",
bcs->channel + 1);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
+ spin_unlock_irqrestore(&cs->lock, flags);
return ret;
}
@@ -1665,12 +1717,14 @@ static void write_command_callback(struct urb *urb)
{
struct cardstate *cs = urb->context;
struct bas_cardstate *ucs = cs->hw.bas;
+ int status = urb->status;
unsigned long flags;
update_basstate(ucs, 0, BS_ATWRPEND);
+ wake_up(&ucs->waitqueue);
/* check status */
- switch (urb->status) {
+ switch (status) {
case 0: /* normal completion */
break;
case -ENOENT: /* cancelled */
@@ -1680,26 +1734,33 @@ static void write_command_callback(struct urb *urb)
case -ESHUTDOWN: /* device shut down */
/* ignore silently */
gig_dbg(DEBUG_USBREQ, "%s: %s",
- __func__, get_usb_statmsg(urb->status));
+ __func__, get_usb_statmsg(status));
return;
default: /* any failure */
if (++ucs->retry_cmd_out > BAS_RETRY) {
dev_warn(cs->dev,
"command write: %s, "
"giving up after %d retries\n",
- get_usb_statmsg(urb->status),
+ get_usb_statmsg(status),
ucs->retry_cmd_out);
break;
}
+ if (ucs->basstate & BS_SUSPEND) {
+ dev_warn(cs->dev,
+ "command write: %s, "
+ "won't retry - suspend requested\n",
+ get_usb_statmsg(status));
+ break;
+ }
if (cs->cmdbuf == NULL) {
dev_warn(cs->dev,
"command write: %s, "
"cannot retry - cmdbuf gone\n",
- get_usb_statmsg(urb->status));
+ get_usb_statmsg(status));
break;
}
dev_notice(cs->dev, "command write: %s, retry %d\n",
- get_usb_statmsg(urb->status), ucs->retry_cmd_out);
+ get_usb_statmsg(status), ucs->retry_cmd_out);
if (atwrite_submit(cs, cs->cmdbuf->buf, cs->cmdbuf->len) >= 0)
/* resubmitted - bypass regular exit block */
return;
@@ -1799,8 +1860,14 @@ static int start_cbsend(struct cardstate *cs)
int rc;
int retval = 0;
+ /* check if suspend requested */
+ if (ucs->basstate & BS_SUSPEND) {
+ gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD, "suspending");
+ return -EHOSTUNREACH;
+ }
+
/* check if AT channel is open */
- if (!(atomic_read(&ucs->basstate) & BS_ATOPEN)) {
+ if (!(ucs->basstate & BS_ATOPEN)) {
gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD, "AT channel not open");
rc = req_submit(cs->bcs, HD_OPEN_ATCHANNEL, 0, BAS_TIMEOUT);
if (rc < 0) {
@@ -1816,8 +1883,7 @@ static int start_cbsend(struct cardstate *cs)
/* try to send first command in queue */
spin_lock_irqsave(&cs->cmdlock, flags);
- while ((cb = cs->cmdbuf) != NULL &&
- atomic_read(&ucs->basstate) & BS_ATREADY) {
+ while ((cb = cs->cmdbuf) != NULL && (ucs->basstate & BS_ATREADY)) {
ucs->retry_cmd_out = 0;
rc = atwrite_submit(cs, cb->buf, cb->len);
if (unlikely(rc)) {
@@ -1855,7 +1921,7 @@ static int gigaset_write_cmd(struct cardstate *cs,
unsigned long flags;
int rc;
- gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ?
+ gigaset_dbg_buffer(cs->mstate != MS_LOCKED ?
DEBUG_TRANSCMD : DEBUG_LOCKCMD,
"CMD Transmit", len, buf);
@@ -1970,7 +2036,7 @@ static int gigaset_freebcshw(struct bc_state *bcs)
return 0;
/* kill URBs and tasklets before freeing - better safe than sorry */
- atomic_set(&ubc->running, 0);
+ ubc->running = 0;
gig_dbg(DEBUG_INIT, "%s: killing iso URBs", __func__);
for (i = 0; i < BAS_OUTURBS; ++i) {
usb_kill_urb(ubc->isoouturbs[i].urb);
@@ -2005,7 +2071,7 @@ static int gigaset_initbcshw(struct bc_state *bcs)
return 0;
}
- atomic_set(&ubc->running, 0);
+ ubc->running = 0;
atomic_set(&ubc->corrbytes, 0);
spin_lock_init(&ubc->isooutlock);
for (i = 0; i < BAS_OUTURBS; ++i) {
@@ -2050,7 +2116,7 @@ static void gigaset_reinitbcshw(struct bc_state *bcs)
{
struct bas_bc_state *ubc = bcs->hw.bas;
- atomic_set(&bcs->hw.bas->running, 0);
+ bcs->hw.bas->running = 0;
atomic_set(&bcs->hw.bas->corrbytes, 0);
bcs->hw.bas->numsub = 0;
spin_lock_init(&ubc->isooutlock);
@@ -2081,10 +2147,11 @@ static int gigaset_initcshw(struct cardstate *cs)
spin_lock_init(&ucs->lock);
ucs->pending = 0;
- atomic_set(&ucs->basstate, 0);
+ ucs->basstate = 0;
init_timer(&ucs->timer_ctrl);
init_timer(&ucs->timer_atrdy);
init_timer(&ucs->timer_cmd_in);
+ init_waitqueue_head(&ucs->waitqueue);
return 1;
}
@@ -2102,7 +2169,7 @@ static void freeurbs(struct cardstate *cs)
int i, j;
gig_dbg(DEBUG_INIT, "%s: killing URBs", __func__);
- for (j = 0; j < 2; ++j) {
+ for (j = 0; j < BAS_CHANNELS; ++j) {
ubc = cs->bcs[j].hw.bas;
for (i = 0; i < BAS_OUTURBS; ++i) {
usb_kill_urb(ubc->isoouturbs[i].urb);
@@ -2179,11 +2246,11 @@ static int gigaset_probe(struct usb_interface *interface,
__func__, le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));
- cs = gigaset_getunassignedcs(driver);
- if (!cs) {
- dev_err(&udev->dev, "no free cardstate\n");
+ /* allocate memory for our device state and intialize it */
+ cs = gigaset_initcs(driver, BAS_CHANNELS, 0, 0, cidmode,
+ GIGASET_MODULENAME);
+ if (!cs)
return -ENODEV;
- }
ucs = cs->hw.bas;
/* save off device structure ptrs for later use */
@@ -2203,7 +2270,7 @@ static int gigaset_probe(struct usb_interface *interface,
!(ucs->urb_ctrl = usb_alloc_urb(0, GFP_KERNEL)))
goto allocerr;
- for (j = 0; j < 2; ++j) {
+ for (j = 0; j < BAS_CHANNELS; ++j) {
ubc = cs->bcs[j].hw.bas;
for (i = 0; i < BAS_OUTURBS; ++i)
if (!(ubc->isoouturbs[i].urb =
@@ -2237,7 +2304,7 @@ static int gigaset_probe(struct usb_interface *interface,
/* tell common part that the device is ready */
if (startmode == SM_LOCKED)
- atomic_set(&cs->mstate, MS_LOCKED);
+ cs->mstate = MS_LOCKED;
/* save address of controller structure */
usb_set_intfdata(interface, cs);
@@ -2252,7 +2319,7 @@ allocerr:
error:
freeurbs(cs);
usb_set_intfdata(interface, NULL);
- gigaset_unassign(cs);
+ gigaset_freecs(cs);
return -ENODEV;
}
@@ -2272,11 +2339,10 @@ static void gigaset_disconnect(struct usb_interface *interface)
dev_info(cs->dev, "disconnecting Gigaset base\n");
/* mark base as not ready, all channels disconnected */
- atomic_set(&ucs->basstate, 0);
+ ucs->basstate = 0;
/* tell LL all channels are down */
- //FIXME shouldn't gigaset_stop() do this?
- for (j = 0; j < 2; ++j)
+ for (j = 0; j < BAS_CHANNELS; ++j)
gigaset_bchannel_down(cs->bcs + j);
/* stop driver (common part) */
@@ -2295,9 +2361,113 @@ static void gigaset_disconnect(struct usb_interface *interface)
ucs->interface = NULL;
ucs->udev = NULL;
cs->dev = NULL;
- gigaset_unassign(cs);
+ gigaset_freecs(cs);
}
+/* gigaset_suspend
+ * This function is called before the USB connection is suspended.
+ */
+static int gigaset_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct cardstate *cs = usb_get_intfdata(intf);
+ struct bas_cardstate *ucs = cs->hw.bas;
+ int rc;
+
+ /* set suspend flag; this stops AT command/response traffic */
+ if (update_basstate(ucs, BS_SUSPEND, 0) & BS_SUSPEND) {
+ gig_dbg(DEBUG_SUSPEND, "already suspended");
+ return 0;
+ }
+
+ /* wait a bit for blocking conditions to go away */
+ rc = wait_event_timeout(ucs->waitqueue,
+ !(ucs->basstate &
+ (BS_B1OPEN|BS_B2OPEN|BS_ATRDPEND|BS_ATWRPEND)),
+ BAS_TIMEOUT*HZ/10);
+ gig_dbg(DEBUG_SUSPEND, "wait_event_timeout() -> %d", rc);
+
+ /* check for conditions preventing suspend */
+ if (ucs->basstate & (BS_B1OPEN|BS_B2OPEN|BS_ATRDPEND|BS_ATWRPEND)) {
+ dev_warn(cs->dev, "cannot suspend:\n");
+ if (ucs->basstate & BS_B1OPEN)
+ dev_warn(cs->dev, " B channel 1 open\n");
+ if (ucs->basstate & BS_B2OPEN)
+ dev_warn(cs->dev, " B channel 2 open\n");
+ if (ucs->basstate & BS_ATRDPEND)
+ dev_warn(cs->dev, " receiving AT reply\n");
+ if (ucs->basstate & BS_ATWRPEND)
+ dev_warn(cs->dev, " sending AT command\n");
+ update_basstate(ucs, 0, BS_SUSPEND);
+ return -EBUSY;
+ }
+
+ /* close AT channel if open */
+ if (ucs->basstate & BS_ATOPEN) {
+ gig_dbg(DEBUG_SUSPEND, "closing AT channel");
+ rc = req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, 0);
+ if (rc) {
+ update_basstate(ucs, 0, BS_SUSPEND);
+ return rc;
+ }
+ wait_event_timeout(ucs->waitqueue, !ucs->pending,
+ BAS_TIMEOUT*HZ/10);
+ /* in case of timeout, proceed anyway */
+ }
+
+ /* kill all URBs and timers that might still be pending */
+ usb_kill_urb(ucs->urb_ctrl);
+ usb_kill_urb(ucs->urb_int_in);
+ del_timer_sync(&ucs->timer_ctrl);
+
+ gig_dbg(DEBUG_SUSPEND, "suspend complete");
+ return 0;
+}
+
+/* gigaset_resume
+ * This function is called after the USB connection has been resumed.
+ */
+static int gigaset_resume(struct usb_interface *intf)
+{
+ struct cardstate *cs = usb_get_intfdata(intf);
+ struct bas_cardstate *ucs = cs->hw.bas;
+ int rc;
+
+ /* resubmit interrupt URB for spontaneous messages from base */
+ rc = usb_submit_urb(ucs->urb_int_in, GFP_KERNEL);
+ if (rc) {
+ dev_err(cs->dev, "could not resubmit interrupt URB: %s\n",
+ get_usb_rcmsg(rc));
+ return rc;
+ }
+
+ /* clear suspend flag to reallow activity */
+ update_basstate(ucs, 0, BS_SUSPEND);
+
+ gig_dbg(DEBUG_SUSPEND, "resume complete");
+ return 0;
+}
+
+/* gigaset_pre_reset
+ * This function is called before the USB connection is reset.
+ */
+static int gigaset_pre_reset(struct usb_interface *intf)
+{
+ /* handle just like suspend */
+ return gigaset_suspend(intf, PMSG_ON);
+}
+
+/* gigaset_post_reset
+ * This function is called after the USB connection has been reset.
+ */
+static int gigaset_post_reset(struct usb_interface *intf)
+{
+ /* FIXME: send HD_DEVICE_INIT_ACK? */
+
+ /* resume operations */
+ return gigaset_resume(intf);
+}
+
+
static const struct gigaset_ops gigops = {
gigaset_write_cmd,
gigaset_write_room,
@@ -2330,12 +2500,6 @@ static int __init bas_gigaset_init(void)
&gigops, THIS_MODULE)) == NULL)
goto error;
- /* allocate memory for our device state and intialize it */
- cardstate = gigaset_initcs(driver, 2, 0, 0, cidmode,
- GIGASET_MODULENAME);
- if (!cardstate)
- goto error;
-
/* register this driver with the USB subsystem */
result = usb_register(&gigaset_usb_driver);
if (result < 0) {
@@ -2347,9 +2511,7 @@ static int __init bas_gigaset_init(void)
info(DRIVER_DESC);
return 0;
-error: if (cardstate)
- gigaset_freecs(cardstate);
- cardstate = NULL;
+error:
if (driver)
gigaset_freedriver(driver);
driver = NULL;
@@ -2361,43 +2523,50 @@ error: if (cardstate)
*/
static void __exit bas_gigaset_exit(void)
{
- struct bas_cardstate *ucs = cardstate->hw.bas;
+ struct bas_cardstate *ucs;
+ int i;
gigaset_blockdriver(driver); /* => probe will fail
* => no gigaset_start any more
*/
- gigaset_shutdown(cardstate);
- /* from now on, no isdn callback should be possible */
-
- /* close all still open channels */
- if (atomic_read(&ucs->basstate) & BS_B1OPEN) {
- gig_dbg(DEBUG_INIT, "closing B1 channel");
- usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0),
- HD_CLOSE_B1CHANNEL, OUT_VENDOR_REQ, 0, 0,
- NULL, 0, BAS_TIMEOUT);
- }
- if (atomic_read(&ucs->basstate) & BS_B2OPEN) {
- gig_dbg(DEBUG_INIT, "closing B2 channel");
- usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0),
- HD_CLOSE_B2CHANNEL, OUT_VENDOR_REQ, 0, 0,
- NULL, 0, BAS_TIMEOUT);
- }
- if (atomic_read(&ucs->basstate) & BS_ATOPEN) {
- gig_dbg(DEBUG_INIT, "closing AT channel");
- usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0),
- HD_CLOSE_ATCHANNEL, OUT_VENDOR_REQ, 0, 0,
- NULL, 0, BAS_TIMEOUT);
+ /* stop all connected devices */
+ for (i = 0; i < driver->minors; i++) {
+ if (gigaset_shutdown(driver->cs + i) < 0)
+ continue; /* no device */
+ /* from now on, no isdn callback should be possible */
+
+ /* close all still open channels */
+ ucs = driver->cs[i].hw.bas;
+ if (ucs->basstate & BS_B1OPEN) {
+ gig_dbg(DEBUG_INIT, "closing B1 channel");
+ usb_control_msg(ucs->udev,
+ usb_sndctrlpipe(ucs->udev, 0),
+ HD_CLOSE_B1CHANNEL, OUT_VENDOR_REQ,
+ 0, 0, NULL, 0, BAS_TIMEOUT);
+ }
+ if (ucs->basstate & BS_B2OPEN) {
+ gig_dbg(DEBUG_INIT, "closing B2 channel");
+ usb_control_msg(ucs->udev,
+ usb_sndctrlpipe(ucs->udev, 0),
+ HD_CLOSE_B2CHANNEL, OUT_VENDOR_REQ,
+ 0, 0, NULL, 0, BAS_TIMEOUT);
+ }
+ if (ucs->basstate & BS_ATOPEN) {
+ gig_dbg(DEBUG_INIT, "closing AT channel");
+ usb_control_msg(ucs->udev,
+ usb_sndctrlpipe(ucs->udev, 0),
+ HD_CLOSE_ATCHANNEL, OUT_VENDOR_REQ,
+ 0, 0, NULL, 0, BAS_TIMEOUT);
+ }
+ ucs->basstate = 0;
}
- atomic_set(&ucs->basstate, 0);
/* deregister this driver with the USB subsystem */
usb_deregister(&gigaset_usb_driver);
/* this will call the disconnect-callback */
/* from now on, no disconnect/probe callback should be running */
- gigaset_freecs(cardstate);
- cardstate = NULL;
gigaset_freedriver(driver);
driver = NULL;
}
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c
index acd417197d0..aacedec4986 100644
--- a/drivers/isdn/gigaset/common.c
+++ b/drivers/isdn/gigaset/common.c
@@ -31,7 +31,6 @@ MODULE_PARM_DESC(debug, "debug level");
/* driver state flags */
#define VALID_MINOR 0x01
#define VALID_ID 0x02
-#define ASSIGNED 0x04
void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
size_t len, const unsigned char *buf)
@@ -178,7 +177,7 @@ int gigaset_get_channel(struct bc_state *bcs)
unsigned long flags;
spin_lock_irqsave(&bcs->cs->lock, flags);
- if (bcs->use_count) {
+ if (bcs->use_count || !try_module_get(bcs->cs->driver->owner)) {
gig_dbg(DEBUG_ANY, "could not allocate channel %d",
bcs->channel);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
@@ -203,6 +202,7 @@ void gigaset_free_channel(struct bc_state *bcs)
}
--bcs->use_count;
bcs->busy = 0;
+ module_put(bcs->cs->driver->owner);
gig_dbg(DEBUG_ANY, "freed channel %d", bcs->channel);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
}
@@ -356,31 +356,28 @@ static struct cardstate *alloc_cs(struct gigaset_driver *drv)
{
unsigned long flags;
unsigned i;
+ struct cardstate *cs;
struct cardstate *ret = NULL;
spin_lock_irqsave(&drv->lock, flags);
+ if (drv->blocked)
+ goto exit;
for (i = 0; i < drv->minors; ++i) {
- if (!(drv->flags[i] & VALID_MINOR)) {
- if (try_module_get(drv->owner)) {
- drv->flags[i] = VALID_MINOR;
- ret = drv->cs + i;
- }
+ cs = drv->cs + i;
+ if (!(cs->flags & VALID_MINOR)) {
+ cs->flags = VALID_MINOR;
+ ret = cs;
break;
}
}
+exit:
spin_unlock_irqrestore(&drv->lock, flags);
return ret;
}
static void free_cs(struct cardstate *cs)
{
- unsigned long flags;
- struct gigaset_driver *drv = cs->driver;
- spin_lock_irqsave(&drv->lock, flags);
- if (drv->flags[cs->minor_index] & VALID_MINOR)
- module_put(drv->owner);
- drv->flags[cs->minor_index] = 0;
- spin_unlock_irqrestore(&drv->lock, flags);
+ cs->flags = 0;
}
static void make_valid(struct cardstate *cs, unsigned mask)
@@ -388,7 +385,7 @@ static void make_valid(struct cardstate *cs, unsigned mask)
unsigned long flags;
struct gigaset_driver *drv = cs->driver;
spin_lock_irqsave(&drv->lock, flags);
- drv->flags[cs->minor_index] |= mask;
+ cs->flags |= mask;
spin_unlock_irqrestore(&drv->lock, flags);
}
@@ -397,7 +394,7 @@ static void make_invalid(struct cardstate *cs, unsigned mask)
unsigned long flags;
struct gigaset_driver *drv = cs->driver;
spin_lock_irqsave(&drv->lock, flags);
- drv->flags[cs->minor_index] &= ~mask;
+ cs->flags &= ~mask;
spin_unlock_irqrestore(&drv->lock, flags);
}
@@ -501,11 +498,11 @@ static void gigaset_inbuf_init(struct inbuf_t *inbuf, struct bc_state *bcs,
struct cardstate *cs, int inputstate)
/* inbuf->read must be allocated before! */
{
- atomic_set(&inbuf->head, 0);
- atomic_set(&inbuf->tail, 0);
+ inbuf->head = 0;
+ inbuf->tail = 0;
inbuf->cs = cs;
inbuf->bcs = bcs; /*base driver: NULL*/
- inbuf->rcvbuf = NULL; //FIXME
+ inbuf->rcvbuf = NULL;
inbuf->inputstate = inputstate;
}
@@ -521,8 +518,8 @@ int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src,
return 0;
bytesleft = numbytes;
- tail = atomic_read(&inbuf->tail);
- head = atomic_read(&inbuf->head);
+ tail = inbuf->tail;
+ head = inbuf->head;
gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
while (bytesleft) {
@@ -546,7 +543,7 @@ int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src,
src += n;
}
gig_dbg(DEBUG_INTR, "setting tail to %u", tail);
- atomic_set(&inbuf->tail, tail);
+ inbuf->tail = tail;
return numbytes != bytesleft;
}
EXPORT_SYMBOL_GPL(gigaset_fill_inbuf);
@@ -668,7 +665,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
tasklet_init(&cs->event_tasklet, &gigaset_handle_event,
(unsigned long) cs);
- atomic_set(&cs->commands_pending, 0);
+ cs->commands_pending = 0;
cs->cur_at_seq = 0;
cs->gotfwver = -1;
cs->open_count = 0;
@@ -688,8 +685,8 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
init_waitqueue_head(&cs->waitqueue);
cs->waiting = 0;
- atomic_set(&cs->mode, M_UNKNOWN);
- atomic_set(&cs->mstate, MS_UNINITIALIZED);
+ cs->mode = M_UNKNOWN;
+ cs->mstate = MS_UNINITIALIZED;
for (i = 0; i < channels; ++i) {
gig_dbg(DEBUG_INIT, "setting up bcs[%d].read", i);
@@ -806,8 +803,8 @@ static void cleanup_cs(struct cardstate *cs)
spin_lock_irqsave(&cs->lock, flags);
- atomic_set(&cs->mode, M_UNKNOWN);
- atomic_set(&cs->mstate, MS_UNINITIALIZED);
+ cs->mode = M_UNKNOWN;
+ cs->mstate = MS_UNINITIALIZED;
clear_at_state(&cs->at_state);
dealloc_at_states(cs);
@@ -817,8 +814,8 @@ static void cleanup_cs(struct cardstate *cs)
kfree(cs->inbuf->rcvbuf);
cs->inbuf->rcvbuf = NULL;
cs->inbuf->inputstate = INS_command;
- atomic_set(&cs->inbuf->head, 0);
- atomic_set(&cs->inbuf->tail, 0);
+ cs->inbuf->head = 0;
+ cs->inbuf->tail = 0;
cb = cs->cmdbuf;
while (cb) {
@@ -832,7 +829,7 @@ static void cleanup_cs(struct cardstate *cs)
cs->gotfwver = -1;
cs->dle = 0;
cs->cur_at_seq = 0;
- atomic_set(&cs->commands_pending, 0);
+ cs->commands_pending = 0;
cs->cbytes = 0;
spin_unlock_irqrestore(&cs->lock, flags);
@@ -862,7 +859,7 @@ int gigaset_start(struct cardstate *cs)
cs->connected = 1;
spin_unlock_irqrestore(&cs->lock, flags);
- if (atomic_read(&cs->mstate) != MS_LOCKED) {
+ if (cs->mstate != MS_LOCKED) {
cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS);
cs->ops->baud_rate(cs, B115200);
cs->ops->set_line_ctrl(cs, CS8);
@@ -893,10 +890,17 @@ error:
}
EXPORT_SYMBOL_GPL(gigaset_start);
-void gigaset_shutdown(struct cardstate *cs)
+/* gigaset_shutdown
+ * check if a device is associated to the cardstate structure and stop it
+ * return value: 0 if ok, -1 if no device was associated
+ */
+int gigaset_shutdown(struct cardstate *cs)
{
mutex_lock(&cs->mutex);
+ if (!(cs->flags & VALID_MINOR))
+ return -1;
+
cs->waiting = 1;
if (!gigaset_add_event(cs, &cs->at_state, EV_SHUTDOWN, NULL, 0, NULL)) {
@@ -913,6 +917,7 @@ void gigaset_shutdown(struct cardstate *cs)
exit:
mutex_unlock(&cs->mutex);
+ return 0;
}
EXPORT_SYMBOL_GPL(gigaset_shutdown);
@@ -954,13 +959,11 @@ struct cardstate *gigaset_get_cs_by_id(int id)
list_for_each_entry(drv, &drivers, list) {
spin_lock(&drv->lock);
for (i = 0; i < drv->minors; ++i) {
- if (drv->flags[i] & VALID_ID) {
- cs = drv->cs + i;
- if (cs->myid == id)
- ret = cs;
- }
- if (ret)
+ cs = drv->cs + i;
+ if ((cs->flags & VALID_ID) && cs->myid == id) {
+ ret = cs;
break;
+ }
}
spin_unlock(&drv->lock);
if (ret)
@@ -983,10 +986,9 @@ void gigaset_debugdrivers(void)
spin_lock(&drv->lock);
for (i = 0; i < drv->minors; ++i) {
gig_dbg(DEBUG_DRIVER, " index %u", i);
- gig_dbg(DEBUG_DRIVER, " flags 0x%02x",
- drv->flags[i]);
cs = drv->cs + i;
gig_dbg(DEBUG_DRIVER, " cardstate %p", cs);
+ gig_dbg(DEBUG_DRIVER, " flags 0x%02x", cs->flags);
gig_dbg(DEBUG_DRIVER, " minor_index %u",
cs->minor_index);
gig_dbg(DEBUG_DRIVER, " driver %p", cs->driver);
@@ -1010,7 +1012,7 @@ static struct cardstate *gigaset_get_cs_by_minor(unsigned minor)
continue;
index = minor - drv->minor;
spin_lock(&drv->lock);
- if (drv->flags[index] & VALID_MINOR)
+ if (drv->cs[index].flags & VALID_MINOR)
ret = drv->cs + index;
spin_unlock(&drv->lock);
if (ret)
@@ -1038,7 +1040,6 @@ void gigaset_freedriver(struct gigaset_driver *drv)
gigaset_if_freedriver(drv);
kfree(drv->cs);
- kfree(drv->flags);
kfree(drv);
}
EXPORT_SYMBOL_GPL(gigaset_freedriver);
@@ -1080,12 +1081,8 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
if (!drv->cs)
goto error;
- drv->flags = kmalloc(minors * sizeof *drv->flags, GFP_KERNEL);
- if (!drv->flags)
- goto error;
-
for (i = 0; i < minors; ++i) {
- drv->flags[i] = 0;
+ drv->cs[i].flags = 0;
drv->cs[i].driver = drv;
drv->cs[i].ops = drv->ops;
drv->cs[i].minor_index = i;
@@ -1106,53 +1103,9 @@ error:
}
EXPORT_SYMBOL_GPL(gigaset_initdriver);
-/* For drivers without fixed assignment device<->cardstate (usb) */
-struct cardstate *gigaset_getunassignedcs(struct gigaset_driver *drv)
-{
- unsigned long flags;
- struct cardstate *cs = NULL;
- unsigned i;
-
- spin_lock_irqsave(&drv->lock, flags);
- if (drv->blocked)
- goto exit;
- for (i = 0; i < drv->minors; ++i) {
- if ((drv->flags[i] & VALID_MINOR) &&
- !(drv->flags[i] & ASSIGNED)) {
- drv->flags[i] |= ASSIGNED;
- cs = drv->cs + i;
- break;
- }
- }
-exit:
- spin_unlock_irqrestore(&drv->lock, flags);
- return cs;
-}
-EXPORT_SYMBOL_GPL(gigaset_getunassignedcs);
-
-void gigaset_unassign(struct cardstate *cs)
-{
- unsigned long flags;
- unsigned *minor_flags;
- struct gigaset_driver *drv;
-
- if (!cs)
- return;
- drv = cs->driver;
- spin_lock_irqsave(&drv->lock, flags);
- minor_flags = drv->flags + cs->minor_index;
- if (*minor_flags & VALID_MINOR)
- *minor_flags &= ~ASSIGNED;
- spin_unlock_irqrestore(&drv->lock, flags);
-}
-EXPORT_SYMBOL_GPL(gigaset_unassign);
-
void gigaset_blockdriver(struct gigaset_driver *drv)
{
- unsigned long flags;
- spin_lock_irqsave(&drv->lock, flags);
drv->blocked = 1;
- spin_unlock_irqrestore(&drv->lock, flags);
}
EXPORT_SYMBOL_GPL(gigaset_blockdriver);
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c
index cec1ef342fc..5cbf64d850e 100644
--- a/drivers/isdn/gigaset/ev-layer.c
+++ b/drivers/isdn/gigaset/ev-layer.c
@@ -735,7 +735,7 @@ static void disconnect(struct at_state_t **at_state_p)
/* revert to selected idle mode */
if (!cs->cidmode) {
cs->at_state.pending_commands |= PC_UMMODE;
- atomic_set(&cs->commands_pending, 1); //FIXME
+ cs->commands_pending = 1;
gig_dbg(DEBUG_CMD, "Scheduling PC_UMMODE");
}
spin_unlock_irqrestore(&cs->lock, flags);
@@ -793,15 +793,15 @@ static void init_failed(struct cardstate *cs, int mode)
struct at_state_t *at_state;
cs->at_state.pending_commands &= ~PC_INIT;
- atomic_set(&cs->mode, mode);
- atomic_set(&cs->mstate, MS_UNINITIALIZED);
+ cs->mode = mode;
+ cs->mstate = MS_UNINITIALIZED;
gigaset_free_channels(cs);
for (i = 0; i < cs->channels; ++i) {
at_state = &cs->bcs[i].at_state;
if (at_state->pending_commands & PC_CID) {
at_state->pending_commands &= ~PC_CID;
at_state->pending_commands |= PC_NOCID;
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
}
}
}
@@ -812,11 +812,11 @@ static void schedule_init(struct cardstate *cs, int state)
gig_dbg(DEBUG_CMD, "not scheduling PC_INIT again");
return;
}
- atomic_set(&cs->mstate, state);
- atomic_set(&cs->mode, M_UNKNOWN);
+ cs->mstate = state;
+ cs->mode = M_UNKNOWN;
gigaset_block_channels(cs);
cs->at_state.pending_commands |= PC_INIT;
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
gig_dbg(DEBUG_CMD, "Scheduling PC_INIT");
}
@@ -953,13 +953,13 @@ static void start_dial(struct at_state_t *at_state, void *data, unsigned seq_ind
at_state->pending_commands |= PC_CID;
gig_dbg(DEBUG_CMD, "Scheduling PC_CID");
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
return;
error:
at_state->pending_commands |= PC_NOCID;
gig_dbg(DEBUG_CMD, "Scheduling PC_NOCID");
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
return;
}
@@ -973,12 +973,12 @@ static void start_accept(struct at_state_t *at_state)
if (retval == 0) {
at_state->pending_commands |= PC_ACCEPT;
gig_dbg(DEBUG_CMD, "Scheduling PC_ACCEPT");
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
} else {
- //FIXME
+ /* error reset */
at_state->pending_commands |= PC_HUP;
gig_dbg(DEBUG_CMD, "Scheduling PC_HUP");
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
}
}
@@ -986,7 +986,7 @@ static void do_start(struct cardstate *cs)
{
gigaset_free_channels(cs);
- if (atomic_read(&cs->mstate) != MS_LOCKED)
+ if (cs->mstate != MS_LOCKED)
schedule_init(cs, MS_INIT);
cs->isdn_up = 1;
@@ -1000,9 +1000,9 @@ static void do_start(struct cardstate *cs)
static void finish_shutdown(struct cardstate *cs)
{
- if (atomic_read(&cs->mstate) != MS_LOCKED) {
- atomic_set(&cs->mstate, MS_UNINITIALIZED);
- atomic_set(&cs->mode, M_UNKNOWN);
+ if (cs->mstate != MS_LOCKED) {
+ cs->mstate = MS_UNINITIALIZED;
+ cs->mode = M_UNKNOWN;
}
/* Tell the LL that the device is not available .. */
@@ -1022,10 +1022,10 @@ static void do_shutdown(struct cardstate *cs)
{
gigaset_block_channels(cs);
- if (atomic_read(&cs->mstate) == MS_READY) {
- atomic_set(&cs->mstate, MS_SHUTDOWN);
+ if (cs->mstate == MS_READY) {
+ cs->mstate = MS_SHUTDOWN;
cs->at_state.pending_commands |= PC_SHUTDOWN;
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
gig_dbg(DEBUG_CMD, "Scheduling PC_SHUTDOWN");
} else
finish_shutdown(cs);
@@ -1120,7 +1120,7 @@ static void handle_icall(struct cardstate *cs, struct bc_state *bcs,
* In fact it doesn't.
*/
at_state->pending_commands |= PC_HUP;
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
break;
}
}
@@ -1130,7 +1130,7 @@ static int do_lock(struct cardstate *cs)
int mode;
int i;
- switch (atomic_read(&cs->mstate)) {
+ switch (cs->mstate) {
case MS_UNINITIALIZED:
case MS_READY:
if (cs->cur_at_seq || !list_empty(&cs->temp_at_states) ||
@@ -1152,20 +1152,20 @@ static int do_lock(struct cardstate *cs)
return -EBUSY;
}
- mode = atomic_read(&cs->mode);
- atomic_set(&cs->mstate, MS_LOCKED);
- atomic_set(&cs->mode, M_UNKNOWN);
+ mode = cs->mode;
+ cs->mstate = MS_LOCKED;
+ cs->mode = M_UNKNOWN;
return mode;
}
static int do_unlock(struct cardstate *cs)
{
- if (atomic_read(&cs->mstate) != MS_LOCKED)
+ if (cs->mstate != MS_LOCKED)
return -EINVAL;
- atomic_set(&cs->mstate, MS_UNINITIALIZED);
- atomic_set(&cs->mode, M_UNKNOWN);
+ cs->mstate = MS_UNINITIALIZED;
+ cs->mode = M_UNKNOWN;
gigaset_free_channels(cs);
if (cs->connected)
schedule_init(cs, MS_INIT);
@@ -1198,17 +1198,17 @@ static void do_action(int action, struct cardstate *cs,
case ACT_INIT:
cs->at_state.pending_commands &= ~PC_INIT;
cs->cur_at_seq = SEQ_NONE;
- atomic_set(&cs->mode, M_UNIMODEM);
+ cs->mode = M_UNIMODEM;
spin_lock_irqsave(&cs->lock, flags);
if (!cs->cidmode) {
spin_unlock_irqrestore(&cs->lock, flags);
gigaset_free_channels(cs);
- atomic_set(&cs->mstate, MS_READY);
+ cs->mstate = MS_READY;
break;
}
spin_unlock_irqrestore(&cs->lock, flags);
cs->at_state.pending_commands |= PC_CIDMODE;
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
break;
case ACT_FAILINIT:
@@ -1234,22 +1234,20 @@ static void do_action(int action, struct cardstate *cs,
| INS_command;
break;
case ACT_CMODESET:
- if (atomic_read(&cs->mstate) == MS_INIT ||
- atomic_read(&cs->mstate) == MS_RECOVER) {
+ if (cs->mstate == MS_INIT || cs->mstate == MS_RECOVER) {
gigaset_free_channels(cs);
- atomic_set(&cs->mstate, MS_READY);
+ cs->mstate = MS_READY;
}
- atomic_set(&cs->mode, M_CID);
+ cs->mode = M_CID;
cs->cur_at_seq = SEQ_NONE;
break;
case ACT_UMODESET:
- atomic_set(&cs->mode, M_UNIMODEM);
+ cs->mode = M_UNIMODEM;
cs->cur_at_seq = SEQ_NONE;
break;
case ACT_FAILCMODE:
cs->cur_at_seq = SEQ_NONE;
- if (atomic_read(&cs->mstate) == MS_INIT ||
- atomic_read(&cs->mstate) == MS_RECOVER) {
+ if (cs->mstate == MS_INIT || cs->mstate == MS_RECOVER) {
init_failed(cs, M_UNKNOWN);
break;
}
@@ -1307,7 +1305,7 @@ static void do_action(int action, struct cardstate *cs,
case ACT_CONNECT:
if (cs->onechannel) {
at_state->pending_commands |= PC_DLE1;
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
break;
}
bcs->chstate |= CHS_D_UP;
@@ -1333,7 +1331,7 @@ static void do_action(int action, struct cardstate *cs,
* DLE only used for M10x with one B channel.
*/
at_state->pending_commands |= PC_DLE0;
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
} else
disconnect(p_at_state);
break;
@@ -1369,7 +1367,7 @@ static void do_action(int action, struct cardstate *cs,
"Could not enter DLE mode. Trying to hang up.\n");
channel = cs->curchannel;
cs->bcs[channel].at_state.pending_commands |= PC_HUP;
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
break;
case ACT_CID: /* got cid; start dialing */
@@ -1379,7 +1377,7 @@ static void do_action(int action, struct cardstate *cs,
cs->bcs[channel].at_state.cid = ev->parameter;
cs->bcs[channel].at_state.pending_commands |=
PC_DIAL;
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
break;
}
/* fall through */
@@ -1411,14 +1409,14 @@ static void do_action(int action, struct cardstate *cs,
case ACT_ABORTDIAL: /* error/timeout during dial preparation */
cs->cur_at_seq = SEQ_NONE;
at_state->pending_commands |= PC_HUP;
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
break;
case ACT_REMOTEREJECT: /* DISCONNECT_IND after dialling */
case ACT_CONNTIMEOUT: /* timeout waiting for ZSAU=ACTIVE */
case ACT_REMOTEHUP: /* DISCONNECT_IND with established connection */
at_state->pending_commands |= PC_HUP;
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
break;
case ACT_GETSTRING: /* warning: RING, ZDLE, ...
are not handled properly anymore */
@@ -1515,7 +1513,7 @@ static void do_action(int action, struct cardstate *cs,
break;
case ACT_HUP:
at_state->pending_commands |= PC_HUP;
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
gig_dbg(DEBUG_CMD, "Scheduling PC_HUP");
break;
@@ -1558,7 +1556,7 @@ static void do_action(int action, struct cardstate *cs,
cs->at_state.pending_commands |= PC_UMMODE;
gig_dbg(DEBUG_CMD, "Scheduling PC_UMMODE");
}
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
}
spin_unlock_irqrestore(&cs->lock, flags);
cs->waiting = 0;
@@ -1741,7 +1739,7 @@ static void process_command_flags(struct cardstate *cs)
int sequence;
unsigned long flags;
- atomic_set(&cs->commands_pending, 0);
+ cs->commands_pending = 0;
if (cs->cur_at_seq) {
gig_dbg(DEBUG_CMD, "not searching scheduled commands: busy");
@@ -1779,7 +1777,7 @@ static void process_command_flags(struct cardstate *cs)
~(PC_DLE1 | PC_ACCEPT | PC_DIAL);
if (at_state->cid > 0)
at_state->pending_commands |= PC_HUP;
- if (atomic_read(&cs->mstate) == MS_RECOVER) {
+ if (cs->mstate == MS_RECOVER) {
if (at_state->pending_commands & PC_CID) {
at_state->pending_commands |= PC_NOCID;
at_state->pending_commands &= ~PC_CID;
@@ -1793,7 +1791,7 @@ static void process_command_flags(struct cardstate *cs)
if (cs->at_state.pending_commands == PC_UMMODE
&& !cs->cidmode
&& list_empty(&cs->temp_at_states)
- && atomic_read(&cs->mode) == M_CID) {
+ && cs->mode == M_CID) {
sequence = SEQ_UMMODE;
at_state = &cs->at_state;
for (i = 0; i < cs->channels; ++i) {
@@ -1860,7 +1858,7 @@ static void process_command_flags(struct cardstate *cs)
}
if (cs->at_state.pending_commands & PC_CIDMODE) {
cs->at_state.pending_commands &= ~PC_CIDMODE;
- if (atomic_read(&cs->mode) == M_UNIMODEM) {
+ if (cs->mode == M_UNIMODEM) {
cs->retry_count = 1;
schedule_sequence(cs, &cs->at_state, SEQ_CIDMODE);
return;
@@ -1886,11 +1884,11 @@ static void process_command_flags(struct cardstate *cs)
return;
}
if (bcs->at_state.pending_commands & PC_CID) {
- switch (atomic_read(&cs->mode)) {
+ switch (cs->mode) {
case M_UNIMODEM:
cs->at_state.pending_commands |= PC_CIDMODE;
gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
return;
#ifdef GIG_MAYINITONDIAL
case M_UNKNOWN:
@@ -1926,7 +1924,7 @@ static void process_events(struct cardstate *cs)
for (i = 0; i < 2 * MAX_EVENTS; ++i) {
tail = cs->ev_tail;
if (tail == head) {
- if (!check_flags && !atomic_read(&cs->commands_pending))
+ if (!check_flags && !cs->commands_pending)
break;
check_flags = 0;
spin_unlock_irqrestore(&cs->ev_lock, flags);
@@ -1934,7 +1932,7 @@ static void process_events(struct cardstate *cs)
spin_lock_irqsave(&cs->ev_lock, flags);
tail = cs->ev_tail;
if (tail == head) {
- if (!atomic_read(&cs->commands_pending))
+ if (!cs->commands_pending)
break;
continue;
}
@@ -1971,7 +1969,7 @@ void gigaset_handle_event(unsigned long data)
struct cardstate *cs = (struct cardstate *) data;
/* handle incoming data on control/common channel */
- if (atomic_read(&cs->inbuf->head) != atomic_read(&cs->inbuf->tail)) {
+ if (cs->inbuf->head != cs->inbuf->tail) {
gig_dbg(DEBUG_INTR, "processing new data");
cs->ops->handle_input(cs->inbuf);
}
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h
index 02bdaf22d7e..f365993161f 100644
--- a/drivers/isdn/gigaset/gigaset.h
+++ b/drivers/isdn/gigaset/gigaset.h
@@ -70,22 +70,13 @@
extern int gigaset_debuglevel; /* "needs" cast to (enum debuglevel) */
-/* any combination of these can be given with the 'debug=' parameter to insmod,
- * e.g. 'insmod usb_gigaset.o debug=0x2c' will set DEBUG_OPEN, DEBUG_CMD and
- * DEBUG_INTR.
- */
+/* debug flags, combine by adding/bitwise OR */
enum debuglevel {
- DEBUG_REG = 0x0002, /* serial port I/O register operations */
- DEBUG_OPEN = 0x0004, /* open/close serial port */
- DEBUG_INTR = 0x0008, /* interrupt processing */
- DEBUG_INTR_DUMP = 0x0010, /* Activating hexdump debug output on
- interrupt requests, not available as
- run-time option */
+ DEBUG_INTR = 0x00008, /* interrupt processing */
DEBUG_CMD = 0x00020, /* sent/received LL commands */
DEBUG_STREAM = 0x00040, /* application data stream I/O events */
DEBUG_STREAM_DUMP = 0x00080, /* application data stream content */
DEBUG_LLDATA = 0x00100, /* sent/received LL data */
- DEBUG_INTR_0 = 0x00200, /* serial port interrupt processing */
DEBUG_DRIVER = 0x00400, /* driver structure */
DEBUG_HDLC = 0x00800, /* M10x HDLC processing */
DEBUG_WRITE = 0x01000, /* M105 data write */
@@ -93,7 +84,7 @@ enum debuglevel {
DEBUG_MCMD = 0x04000, /* COMMANDS THAT ARE SENT VERY OFTEN */
DEBUG_INIT = 0x08000, /* (de)allocation+initialization of data
structures */
- DEBUG_LOCK = 0x10000, /* semaphore operations */
+ DEBUG_SUSPEND = 0x10000, /* suspend/resume processing */
DEBUG_OUTPUT = 0x20000, /* output to device */
DEBUG_ISO = 0x40000, /* isochronous transfers */
DEBUG_IF = 0x80000, /* character device operations */
@@ -191,6 +182,9 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
#define HD_OPEN_ATCHANNEL (0x28) // 3070
#define HD_CLOSE_ATCHANNEL (0x29) // 3070
+/* number of B channels supported by base driver */
+#define BAS_CHANNELS 2
+
/* USB frames for isochronous transfer */
#define BAS_FRAMETIME 1 /* number of milliseconds between frames */
#define BAS_NUMFRAMES 8 /* number of frames per URB */
@@ -313,7 +307,7 @@ struct inbuf_t {
struct bc_state *bcs;
struct cardstate *cs;
int inputstate;
- atomic_t head, tail;
+ int head, tail;
unsigned char data[RBUFSIZE];
};
@@ -335,9 +329,9 @@ struct inbuf_t {
* are also filled with that value
*/
struct isowbuf_t {
- atomic_t read;
- atomic_t nextread;
- atomic_t write;
+ int read;
+ int nextread;
+ int write;
atomic_t writesem;
int wbits;
unsigned char data[BAS_OUTBUFSIZE + BAS_OUTBUFPAD];
@@ -350,11 +344,13 @@ struct isowbuf_t {
* - urb: pointer to the URB itself
* - bcs: pointer to the B Channel control structure
* - limit: end of write buffer area covered by this URB
+ * - status: URB completion status
*/
struct isow_urbctx_t {
struct urb *urb;
struct bc_state *bcs;
int limit;
+ int status;
};
/* AT state structure
@@ -439,14 +435,15 @@ struct cardstate {
unsigned minor_index;
struct device *dev;
struct device *tty_dev;
+ unsigned flags;
const struct gigaset_ops *ops;
/* Stuff to handle communication */
wait_queue_head_t waitqueue;
int waiting;
- atomic_t mode; /* see M_XXXX */
- atomic_t mstate; /* Modem state: see MS_XXXX */
+ int mode; /* see M_XXXX */
+ int mstate; /* Modem state: see MS_XXXX */
/* only changed by the event layer */
int cmd_result;
@@ -503,7 +500,7 @@ struct cardstate {
processed */
int curchannel; /* channel those commands are meant
for */
- atomic_t commands_pending; /* flag(s) in xxx.commands_pending have
+ int commands_pending; /* flag(s) in xxx.commands_pending have
been set */
struct tasklet_struct event_tasklet;
/* tasklet for serializing AT commands.
@@ -543,7 +540,6 @@ struct gigaset_driver {
unsigned minor;
unsigned minors;
struct cardstate *cs;
- unsigned *flags;
int blocked;
const struct gigaset_ops *ops;
@@ -559,7 +555,7 @@ struct cmdbuf_t {
struct bas_bc_state {
/* isochronous output state */
- atomic_t running;
+ int running;
atomic_t corrbytes;
spinlock_t isooutlock;
struct isow_urbctx_t isoouturbs[BAS_OUTURBS];
@@ -574,6 +570,7 @@ struct bas_bc_state {
struct urb *isoinurbs[BAS_INURBS];
unsigned char isoinbuf[BAS_INBUFSIZE * BAS_INURBS];
struct urb *isoindone; /* completed isoc read URB */
+ int isoinstatus; /* status of completed URB */
int loststatus; /* status of dropped URB */
unsigned isoinlost; /* number of bytes lost */
/* state of bit unstuffing algorithm
@@ -770,10 +767,6 @@ void gigaset_freedriver(struct gigaset_driver *drv);
void gigaset_debugdrivers(void);
struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty);
struct cardstate *gigaset_get_cs_by_id(int id);
-
-/* For drivers without fixed assignment device<->cardstate (usb) */
-struct cardstate *gigaset_getunassignedcs(struct gigaset_driver *drv);
-void gigaset_unassign(struct cardstate *cs);
void gigaset_blockdriver(struct gigaset_driver *drv);
/* Allocate and initialize card state. Calls hardware dependent
@@ -792,7 +785,7 @@ int gigaset_start(struct cardstate *cs);
void gigaset_stop(struct cardstate *cs);
/* Tell common.c that the driver is being unloaded. */
-void gigaset_shutdown(struct cardstate *cs);
+int gigaset_shutdown(struct cardstate *cs);
/* Tell common.c that an skb has been sent. */
void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb);
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c
index eb50f3dab5f..af195b07c19 100644
--- a/drivers/isdn/gigaset/interface.c
+++ b/drivers/isdn/gigaset/interface.c
@@ -28,12 +28,11 @@ static int if_lock(struct cardstate *cs, int *arg)
return -EINVAL;
if (cmd < 0) {
- *arg = atomic_read(&cs->mstate) == MS_LOCKED; //FIXME remove?
+ *arg = cs->mstate == MS_LOCKED;
return 0;
}
- if (!cmd && atomic_read(&cs->mstate) == MS_LOCKED
- && cs->connected) {
+ if (!cmd && cs->mstate == MS_LOCKED && cs->connected) {
cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS);
cs->ops->baud_rate(cs, B115200);
cs->ops->set_line_ctrl(cs, CS8);
@@ -104,7 +103,7 @@ static int if_config(struct cardstate *cs, int *arg)
if (*arg != 1)
return -EINVAL;
- if (atomic_read(&cs->mstate) != MS_LOCKED)
+ if (cs->mstate != MS_LOCKED)
return -EBUSY;
if (!cs->connected) {
@@ -162,7 +161,7 @@ static int if_open(struct tty_struct *tty, struct file *filp)
tty->driver_data = NULL;
cs = gigaset_get_cs_by_tty(tty);
- if (!cs)
+ if (!cs || !try_module_get(cs->driver->owner))
return -ENODEV;
if (mutex_lock_interruptible(&cs->mutex))
@@ -208,6 +207,8 @@ static void if_close(struct tty_struct *tty, struct file *filp)
}
mutex_unlock(&cs->mutex);
+
+ module_put(cs->driver->owner);
}
static int if_ioctl(struct tty_struct *tty, struct file *file,
@@ -364,7 +365,7 @@ static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
if (!cs->open_count)
warn("%s: device not opened", __func__);
- else if (atomic_read(&cs->mstate) != MS_LOCKED) {
+ else if (cs->mstate != MS_LOCKED) {
warn("can't write to unlocked device");
retval = -EBUSY;
} else if (!cs->connected) {
@@ -398,9 +399,9 @@ static int if_write_room(struct tty_struct *tty)
if (!cs->open_count)
warn("%s: device not opened", __func__);
- else if (atomic_read(&cs->mstate) != MS_LOCKED) {
+ else if (cs->mstate != MS_LOCKED) {
warn("can't write to unlocked device");
- retval = -EBUSY; //FIXME
+ retval = -EBUSY;
} else if (!cs->connected) {
gig_dbg(DEBUG_ANY, "can't write to unplugged device");
retval = -EBUSY; //FIXME
@@ -430,7 +431,7 @@ static int if_chars_in_buffer(struct tty_struct *tty)
if (!cs->open_count)
warn("%s: device not opened", __func__);
- else if (atomic_read(&cs->mstate) != MS_LOCKED) {
+ else if (cs->mstate != MS_LOCKED) {
warn("can't write to unlocked device");
retval = -EBUSY;
} else if (!cs->connected) {
diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c
index e0505f23880..e30a7773f93 100644
--- a/drivers/isdn/gigaset/isocdata.c
+++ b/drivers/isdn/gigaset/isocdata.c
@@ -23,9 +23,9 @@
*/
void gigaset_isowbuf_init(struct isowbuf_t *iwb, unsigned char idle)
{
- atomic_set(&iwb->read, 0);
- atomic_set(&iwb->nextread, 0);
- atomic_set(&iwb->write, 0);
+ iwb->read = 0;
+ iwb->nextread = 0;
+ iwb->write = 0;
atomic_set(&iwb->writesem, 1);
iwb->wbits = 0;
iwb->idle = idle;
@@ -39,8 +39,8 @@ static inline int isowbuf_freebytes(struct isowbuf_t *iwb)
{
int read, write, freebytes;
- read = atomic_read(&iwb->read);
- write = atomic_read(&iwb->write);
+ read = iwb->read;
+ write = iwb->write;
if ((freebytes = read - write) > 0) {
/* no wraparound: need padding space within regular area */
return freebytes - BAS_OUTBUFPAD;
@@ -62,7 +62,7 @@ static inline int isowbuf_poscmp(struct isowbuf_t *iwb, int a, int b)
int read;
if (a == b)
return 0;
- read = atomic_read(&iwb->read);
+ read = iwb->read;
if (a < b) {
if (a < read && read <= b)
return +1;
@@ -91,18 +91,18 @@ static inline int isowbuf_startwrite(struct isowbuf_t *iwb)
#ifdef CONFIG_GIGASET_DEBUG
gig_dbg(DEBUG_ISO,
"%s: acquired iso write semaphore, data[write]=%02x, nbits=%d",
- __func__, iwb->data[atomic_read(&iwb->write)], iwb->wbits);
+ __func__, iwb->data[iwb->write], iwb->wbits);
#endif
return 1;
}
/* finish writing
- * release the write semaphore and update the maximum buffer fill level
+ * release the write semaphore
* returns the current write position
*/
static inline int isowbuf_donewrite(struct isowbuf_t *iwb)
{
- int write = atomic_read(&iwb->write);
+ int write = iwb->write;
atomic_inc(&iwb->writesem);
return write;
}
@@ -116,7 +116,7 @@ static inline int isowbuf_donewrite(struct isowbuf_t *iwb)
*/
static inline void isowbuf_putbits(struct isowbuf_t *iwb, u32 data, int nbits)
{
- int write = atomic_read(&iwb->write);
+ int write = iwb->write;
data <<= iwb->wbits;
data |= iwb->data[write];
nbits += iwb->wbits;
@@ -128,7 +128,7 @@ static inline void isowbuf_putbits(struct isowbuf_t *iwb, u32 data, int nbits)
}
iwb->wbits = nbits;
iwb->data[write] = data & 0xff;
- atomic_set(&iwb->write, write);
+ iwb->write = write;
}
/* put final flag on HDLC bitstream
@@ -142,7 +142,7 @@ static inline void isowbuf_putflag(struct isowbuf_t *iwb)
/* add two flags, thus reliably covering one byte */
isowbuf_putbits(iwb, 0x7e7e, 8);
/* recover the idle flag byte */
- write = atomic_read(&iwb->write);
+ write = iwb->write;
iwb->idle = iwb->data[write];
gig_dbg(DEBUG_ISO, "idle fill byte %02x", iwb->idle);
/* mask extraneous bits in buffer */
@@ -160,8 +160,8 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size)
int read, write, limit, src, dst;
unsigned char pbyte;
- read = atomic_read(&iwb->nextread);
- write = atomic_read(&iwb->write);
+ read = iwb->nextread;
+ write = iwb->write;
if (likely(read == write)) {
/* return idle frame */
return read < BAS_OUTBUFPAD ?
@@ -176,7 +176,7 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size)
err("invalid size %d", size);
return -EINVAL;
}
- src = atomic_read(&iwb->read);
+ src = iwb->read;
if (unlikely(limit > BAS_OUTBUFSIZE + BAS_OUTBUFPAD ||
(read < src && limit >= src))) {
err("isoc write buffer frame reservation violated");
@@ -191,7 +191,8 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size)
if (!isowbuf_startwrite(iwb))
return -EBUSY;
/* write position could have changed */
- if (limit >= (write = atomic_read(&iwb->write))) {
+ write = iwb->write;
+ if (limit >= write) {
pbyte = iwb->data[write]; /* save
partial byte */
limit = write + BAS_OUTBUFPAD;
@@ -213,7 +214,7 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size)
__func__, pbyte, limit);
iwb->data[limit] = pbyte; /* restore
partial byte */
- atomic_set(&iwb->write, limit);
+ iwb->write = limit;
}
isowbuf_donewrite(iwb);
}
@@ -233,7 +234,7 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size)
limit = src;
}
}
- atomic_set(&iwb->nextread, limit);
+ iwb->nextread = limit;
return read;
}
@@ -477,7 +478,7 @@ static inline int trans_buildframe(struct isowbuf_t *iwb,
unsigned char c;
if (unlikely(count <= 0))
- return atomic_read(&iwb->write); /* better ideas? */
+ return iwb->write;
if (isowbuf_freebytes(iwb) < count ||
!isowbuf_startwrite(iwb)) {
@@ -486,13 +487,13 @@ static inline int trans_buildframe(struct isowbuf_t *iwb,
}
gig_dbg(DEBUG_STREAM, "put %d bytes", count);
- write = atomic_read(&iwb->write);
+ write = iwb->write;
do {
c = bitrev8(*in++);
iwb->data[write++] = c;
write %= BAS_OUTBUFSIZE;
} while (--count > 0);
- atomic_set(&iwb->write, write);
+ iwb->write = write;
iwb->idle = c;
return isowbuf_donewrite(iwb);
@@ -947,8 +948,8 @@ void gigaset_isoc_input(struct inbuf_t *inbuf)
unsigned tail, head, numbytes;
unsigned char *src;
- head = atomic_read(&inbuf->head);
- while (head != (tail = atomic_read(&inbuf->tail))) {
+ head = inbuf->head;
+ while (head != (tail = inbuf->tail)) {
gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
if (head > tail)
tail = RBUFSIZE;
@@ -956,7 +957,7 @@ void gigaset_isoc_input(struct inbuf_t *inbuf)
numbytes = tail - head;
gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes);
- if (atomic_read(&cs->mstate) == MS_LOCKED) {
+ if (cs->mstate == MS_LOCKED) {
gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response",
numbytes, src);
gigaset_if_receive(inbuf->cs, src, numbytes);
@@ -970,7 +971,7 @@ void gigaset_isoc_input(struct inbuf_t *inbuf)
if (head == RBUFSIZE)
head = 0;
gig_dbg(DEBUG_INTR, "setting head to %u", head);
- atomic_set(&inbuf->head, head);
+ inbuf->head = head;
}
}
diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c
index ea44302e6e7..fceeb1d5768 100644
--- a/drivers/isdn/gigaset/ser-gigaset.c
+++ b/drivers/isdn/gigaset/ser-gigaset.c
@@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/tty.h>
#include <linux/poll.h>
+#include <linux/completion.h>
/* Version Information */
#define DRIVER_AUTHOR "Tilman Schmidt"
@@ -48,7 +49,7 @@ struct ser_cardstate {
struct platform_device dev;
struct tty_struct *tty;
atomic_t refcnt;
- struct mutex dead_mutex;
+ struct completion dead_cmp;
};
static struct platform_driver device_driver = {
@@ -240,7 +241,7 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
struct cmdbuf_t *cb;
unsigned long flags;
- gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ?
+ gigaset_dbg_buffer(cs->mstate != MS_LOCKED ?
DEBUG_TRANSCMD : DEBUG_LOCKCMD,
"CMD Transmit", len, buf);
@@ -498,7 +499,7 @@ static struct cardstate *cs_get(struct tty_struct *tty)
static void cs_put(struct cardstate *cs)
{
if (atomic_dec_and_test(&cs->hw.ser->refcnt))
- mutex_unlock(&cs->hw.ser->dead_mutex);
+ complete(&cs->hw.ser->dead_cmp);
}
/*
@@ -527,8 +528,8 @@ gigaset_tty_open(struct tty_struct *tty)
cs->dev = &cs->hw.ser->dev.dev;
cs->hw.ser->tty = tty;
- mutex_init(&cs->hw.ser->dead_mutex);
atomic_set(&cs->hw.ser->refcnt, 1);
+ init_completion(&cs->hw.ser->dead_cmp);
tty->disc_data = cs;
@@ -536,14 +537,13 @@ gigaset_tty_open(struct tty_struct *tty)
* startup system and notify the LL that we are ready to run
*/
if (startmode == SM_LOCKED)
- atomic_set(&cs->mstate, MS_LOCKED);
+ cs->mstate = MS_LOCKED;
if (!gigaset_start(cs)) {
tasklet_kill(&cs->write_tasklet);
goto error;
}
gig_dbg(DEBUG_INIT, "Startup of HLL done");
- mutex_lock(&cs->hw.ser->dead_mutex);
return 0;
error:
@@ -577,7 +577,7 @@ gigaset_tty_close(struct tty_struct *tty)
else {
/* wait for running methods to finish */
if (!atomic_dec_and_test(&cs->hw.ser->refcnt))
- mutex_lock(&cs->hw.ser->dead_mutex);
+ wait_for_completion(&cs->hw.ser->dead_cmp);
}
/* stop operations */
@@ -714,8 +714,8 @@ gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
return;
}
- tail = atomic_read(&inbuf->tail);
- head = atomic_read(&inbuf->head);
+ tail = inbuf->tail;
+ head = inbuf->head;
gig_dbg(DEBUG_INTR, "buffer state: %u -> %u, receive %u bytes",
head, tail, count);
@@ -742,7 +742,7 @@ gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
}
gig_dbg(DEBUG_INTR, "setting tail to %u", tail);
- atomic_set(&inbuf->tail, tail);
+ inbuf->tail = tail;
/* Everything was received .. Push data into handler */
gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c
index ca4bee173cf..77d20ab0cd4 100644
--- a/drivers/isdn/gigaset/usb-gigaset.c
+++ b/drivers/isdn/gigaset/usb-gigaset.c
@@ -104,12 +104,17 @@ MODULE_DEVICE_TABLE(usb, gigaset_table);
* flags per packet.
*/
+/* functions called if a device of this driver is connected/disconnected */
static int gigaset_probe(struct usb_interface *interface,
const struct usb_device_id *id);
static void gigaset_disconnect(struct usb_interface *interface);
+/* functions called before/after suspend */
+static int gigaset_suspend(struct usb_interface *intf, pm_message_t message);
+static int gigaset_resume(struct usb_interface *intf);
+static int gigaset_pre_reset(struct usb_interface *intf);
+
static struct gigaset_driver *driver = NULL;
-static struct cardstate *cardstate = NULL;
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver gigaset_usb_driver = {
@@ -117,12 +122,17 @@ static struct usb_driver gigaset_usb_driver = {
.probe = gigaset_probe,
.disconnect = gigaset_disconnect,
.id_table = gigaset_table,
+ .suspend = gigaset_suspend,
+ .resume = gigaset_resume,
+ .reset_resume = gigaset_resume,
+ .pre_reset = gigaset_pre_reset,
+ .post_reset = gigaset_resume,
};
struct usb_cardstate {
struct usb_device *udev; /* usb device pointer */
struct usb_interface *interface; /* interface for this device */
- atomic_t busy; /* bulk output in progress */
+ int busy; /* bulk output in progress */
/* Output buffer */
unsigned char *bulk_out_buffer;
@@ -314,7 +324,7 @@ static void gigaset_modem_fill(unsigned long data)
gig_dbg(DEBUG_OUTPUT, "modem_fill");
- if (atomic_read(&cs->hw.usb->busy)) {
+ if (cs->hw.usb->busy) {
gig_dbg(DEBUG_OUTPUT, "modem_fill: busy");
return;
}
@@ -361,18 +371,13 @@ static void gigaset_read_int_callback(struct urb *urb)
{
struct inbuf_t *inbuf = urb->context;
struct cardstate *cs = inbuf->cs;
- int resubmit = 0;
+ int status = urb->status;
int r;
unsigned numbytes;
unsigned char *src;
unsigned long flags;
- if (!urb->status) {
- if (!cs->connected) {
- err("%s: disconnected", __func__); /* should never happen */
- return;
- }
-
+ if (!status) {
numbytes = urb->actual_length;
if (numbytes) {
@@ -389,28 +394,26 @@ static void gigaset_read_int_callback(struct urb *urb)
}
} else
gig_dbg(DEBUG_INTR, "Received zero block length");
- resubmit = 1;
} else {
/* The urb might have been killed. */
- gig_dbg(DEBUG_ANY, "%s - nonzero read bulk status received: %d",
- __func__, urb->status);
- if (urb->status != -ENOENT) { /* not killed */
- if (!cs->connected) {
- err("%s: disconnected", __func__); /* should never happen */
- return;
- }
- resubmit = 1;
- }
+ gig_dbg(DEBUG_ANY, "%s - nonzero status received: %d",
+ __func__, status);
+ if (status == -ENOENT || status == -ESHUTDOWN)
+ /* killed or endpoint shutdown: don't resubmit */
+ return;
}
- if (resubmit) {
- spin_lock_irqsave(&cs->lock, flags);
- r = cs->connected ? usb_submit_urb(urb, GFP_ATOMIC) : -ENODEV;
+ /* resubmit URB */
+ spin_lock_irqsave(&cs->lock, flags);
+ if (!cs->connected) {
spin_unlock_irqrestore(&cs->lock, flags);
- if (r)
- dev_err(cs->dev, "error %d when resubmitting urb.\n",
- -r);
+ err("%s: disconnected", __func__);
+ return;
}
+ r = usb_submit_urb(urb, GFP_ATOMIC);
+ spin_unlock_irqrestore(&cs->lock, flags);
+ if (r)
+ dev_err(cs->dev, "error %d resubmitting URB\n", -r);
}
@@ -418,19 +421,28 @@ static void gigaset_read_int_callback(struct urb *urb)
static void gigaset_write_bulk_callback(struct urb *urb)
{
struct cardstate *cs = urb->context;
+ int status = urb->status;
unsigned long flags;
- if (urb->status)
+ switch (status) {
+ case 0: /* normal completion */
+ break;
+ case -ENOENT: /* killed */
+ gig_dbg(DEBUG_ANY, "%s: killed", __func__);
+ cs->hw.usb->busy = 0;
+ return;
+ default:
dev_err(cs->dev, "bulk transfer failed (status %d)\n",
- -urb->status);
+ -status);
/* That's all we can do. Communication problems
are handled by timeouts or network protocols. */
+ }
spin_lock_irqsave(&cs->lock, flags);
if (!cs->connected) {
err("%s: not connected", __func__);
} else {
- atomic_set(&cs->hw.usb->busy, 0);
+ cs->hw.usb->busy = 0;
tasklet_schedule(&cs->write_tasklet);
}
spin_unlock_irqrestore(&cs->lock, flags);
@@ -478,14 +490,14 @@ static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb)
cb->offset += count;
cb->len -= count;
- atomic_set(&ucs->busy, 1);
+ ucs->busy = 1;
spin_lock_irqsave(&cs->lock, flags);
status = cs->connected ? usb_submit_urb(ucs->bulk_out_urb, GFP_ATOMIC) : -ENODEV;
spin_unlock_irqrestore(&cs->lock, flags);
if (status) {
- atomic_set(&ucs->busy, 0);
+ ucs->busy = 0;
err("could not submit urb (error %d)\n",
-status);
cb->len = 0; /* skip urb => remove cb+wakeup
@@ -504,7 +516,7 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
struct cmdbuf_t *cb;
unsigned long flags;
- gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ?
+ gigaset_dbg_buffer(cs->mstate != MS_LOCKED ?
DEBUG_TRANSCMD : DEBUG_LOCKCMD,
"CMD Transmit", len, buf);
@@ -641,7 +653,7 @@ static int write_modem(struct cardstate *cs)
count = min(bcs->tx_skb->len, (unsigned) ucs->bulk_out_size);
skb_copy_from_linear_data(bcs->tx_skb, ucs->bulk_out_buffer, count);
skb_pull(bcs->tx_skb, count);
- atomic_set(&ucs->busy, 1);
+ ucs->busy = 1;
gig_dbg(DEBUG_OUTPUT, "write_modem: send %d bytes", count);
spin_lock_irqsave(&cs->lock, flags);
@@ -659,7 +671,7 @@ static int write_modem(struct cardstate *cs)
if (ret) {
err("could not submit urb (error %d)\n", -ret);
- atomic_set(&ucs->busy, 0);
+ ucs->busy = 0;
}
if (!bcs->tx_skb->len) {
@@ -680,53 +692,44 @@ static int gigaset_probe(struct usb_interface *interface,
{
int retval;
struct usb_device *udev = interface_to_usbdev(interface);
- unsigned int ifnum;
- struct usb_host_interface *hostif;
+ struct usb_host_interface *hostif = interface->cur_altsetting;
struct cardstate *cs = NULL;
struct usb_cardstate *ucs = NULL;
struct usb_endpoint_descriptor *endpoint;
int buffer_size;
- int alt;
- gig_dbg(DEBUG_ANY,
- "%s: Check if device matches .. (Vendor: 0x%x, Product: 0x%x)",
- __func__, le16_to_cpu(udev->descriptor.idVendor),
- le16_to_cpu(udev->descriptor.idProduct));
-
- retval = -ENODEV; //FIXME
+ gig_dbg(DEBUG_ANY, "%s: Check if device matches ...", __func__);
/* See if the device offered us matches what we can accept */
if ((le16_to_cpu(udev->descriptor.idVendor) != USB_M105_VENDOR_ID) ||
- (le16_to_cpu(udev->descriptor.idProduct) != USB_M105_PRODUCT_ID))
+ (le16_to_cpu(udev->descriptor.idProduct) != USB_M105_PRODUCT_ID)) {
+ gig_dbg(DEBUG_ANY, "device ID (0x%x, 0x%x) not for me - skip",
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct));
return -ENODEV;
-
- /* this starts to become ascii art... */
- hostif = interface->cur_altsetting;
- alt = hostif->desc.bAlternateSetting;
- ifnum = hostif->desc.bInterfaceNumber; // FIXME ?
-
- if (alt != 0 || ifnum != 0) {
- dev_warn(&udev->dev, "ifnum %d, alt %d\n", ifnum, alt);
+ }
+ if (hostif->desc.bInterfaceNumber != 0) {
+ gig_dbg(DEBUG_ANY, "interface %d not for me - skip",
+ hostif->desc.bInterfaceNumber);
+ return -ENODEV;
+ }
+ if (hostif->desc.bAlternateSetting != 0) {
+ dev_notice(&udev->dev, "unsupported altsetting %d - skip",
+ hostif->desc.bAlternateSetting);
return -ENODEV;
}
-
- /* Reject application specific intefaces
- *
- */
if (hostif->desc.bInterfaceClass != 255) {
- dev_info(&udev->dev,
- "%s: Device matched but iface_desc[%d]->bInterfaceClass==%d!\n",
- __func__, ifnum, hostif->desc.bInterfaceClass);
+ dev_notice(&udev->dev, "unsupported interface class %d - skip",
+ hostif->desc.bInterfaceClass);
return -ENODEV;
}
dev_info(&udev->dev, "%s: Device matched ... !\n", __func__);
- cs = gigaset_getunassignedcs(driver);
- if (!cs) {
- dev_warn(&udev->dev, "no free cardstate\n");
+ /* allocate memory for our device state and intialize it */
+ cs = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME);
+ if (!cs)
return -ENODEV;
- }
ucs = cs->hw.usb;
/* save off device structure ptrs for later use */
@@ -759,7 +762,7 @@ static int gigaset_probe(struct usb_interface *interface,
endpoint = &hostif->endpoint[1].desc;
- atomic_set(&ucs->busy, 0);
+ ucs->busy = 0;
ucs->read_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!ucs->read_urb) {
@@ -792,7 +795,7 @@ static int gigaset_probe(struct usb_interface *interface,
/* tell common part that the device is ready */
if (startmode == SM_LOCKED)
- atomic_set(&cs->mstate, MS_LOCKED);
+ cs->mstate = MS_LOCKED;
if (!gigaset_start(cs)) {
tasklet_kill(&cs->write_tasklet);
@@ -813,7 +816,7 @@ error:
usb_put_dev(ucs->udev);
ucs->udev = NULL;
ucs->interface = NULL;
- gigaset_unassign(cs);
+ gigaset_freecs(cs);
return retval;
}
@@ -824,6 +827,9 @@ static void gigaset_disconnect(struct usb_interface *interface)
cs = usb_get_intfdata(interface);
ucs = cs->hw.usb;
+
+ dev_info(cs->dev, "disconnecting Gigaset USB adapter\n");
+
usb_kill_urb(ucs->read_urb);
gigaset_stop(cs);
@@ -831,7 +837,7 @@ static void gigaset_disconnect(struct usb_interface *interface)
usb_set_intfdata(interface, NULL);
tasklet_kill(&cs->write_tasklet);
- usb_kill_urb(ucs->bulk_out_urb); /* FIXME: only if active? */
+ usb_kill_urb(ucs->bulk_out_urb);
kfree(ucs->bulk_out_buffer);
usb_free_urb(ucs->bulk_out_urb);
@@ -844,7 +850,53 @@ static void gigaset_disconnect(struct usb_interface *interface)
ucs->interface = NULL;
ucs->udev = NULL;
cs->dev = NULL;
- gigaset_unassign(cs);
+ gigaset_freecs(cs);
+}
+
+/* gigaset_suspend
+ * This function is called before the USB connection is suspended or reset.
+ */
+static int gigaset_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct cardstate *cs = usb_get_intfdata(intf);
+
+ /* stop activity */
+ cs->connected = 0; /* prevent rescheduling */
+ usb_kill_urb(cs->hw.usb->read_urb);
+ tasklet_kill(&cs->write_tasklet);
+ usb_kill_urb(cs->hw.usb->bulk_out_urb);
+
+ gig_dbg(DEBUG_SUSPEND, "suspend complete");
+ return 0;
+}
+
+/* gigaset_resume
+ * This function is called after the USB connection has been resumed or reset.
+ */
+static int gigaset_resume(struct usb_interface *intf)
+{
+ struct cardstate *cs = usb_get_intfdata(intf);
+ int rc;
+
+ /* resubmit interrupt URB */
+ cs->connected = 1;
+ rc = usb_submit_urb(cs->hw.usb->read_urb, GFP_KERNEL);
+ if (rc) {
+ dev_err(cs->dev, "Could not submit read URB (error %d)\n", -rc);
+ return rc;
+ }
+
+ gig_dbg(DEBUG_SUSPEND, "resume complete");
+ return 0;
+}
+
+/* gigaset_pre_reset
+ * This function is called before the USB connection is reset.
+ */
+static int gigaset_pre_reset(struct usb_interface *intf)
+{
+ /* same as suspend */
+ return gigaset_suspend(intf, PMSG_ON);
}
static const struct gigaset_ops ops = {
@@ -880,11 +932,6 @@ static int __init usb_gigaset_init(void)
&ops, THIS_MODULE)) == NULL)
goto error;
- /* allocate memory for our device state and intialize it */
- cardstate = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME);
- if (!cardstate)
- goto error;
-
/* register this driver with the USB subsystem */
result = usb_register(&gigaset_usb_driver);
if (result < 0) {
@@ -897,9 +944,7 @@ static int __init usb_gigaset_init(void)
info(DRIVER_DESC);
return 0;
-error: if (cardstate)
- gigaset_freecs(cardstate);
- cardstate = NULL;
+error:
if (driver)
gigaset_freedriver(driver);
driver = NULL;
@@ -913,11 +958,16 @@ error: if (cardstate)
*/
static void __exit usb_gigaset_exit(void)
{
+ int i;
+
gigaset_blockdriver(driver); /* => probe will fail
* => no gigaset_start any more
*/
- gigaset_shutdown(cardstate);
+ /* stop all connected devices */
+ for (i = 0; i < driver->minors; i++)
+ gigaset_shutdown(driver->cs + i);
+
/* from now on, no isdn callback should be possible */
/* deregister this driver with the USB subsystem */
@@ -925,8 +975,6 @@ static void __exit usb_gigaset_exit(void)
/* this will call the disconnect-callback */
/* from now on, no disconnect/probe callback should be running */
- gigaset_freecs(cardstate);
- cardstate = NULL;
gigaset_freedriver(driver);
driver = NULL;
}
diff --git a/drivers/isdn/hardware/eicon/debug.c b/drivers/isdn/hardware/eicon/debug.c
index 0db9cc661e2..84318ec8d13 100644
--- a/drivers/isdn/hardware/eicon/debug.c
+++ b/drivers/isdn/hardware/eicon/debug.c
@@ -1188,7 +1188,7 @@ int SuperTraceASSIGN (void* AdapterHandle, byte* data) {
if ((features[0] & DIVA_XDI_EXTENDED_FEATURES_VALID) &&
(features[0] & DIVA_XDI_EXTENDED_FEATURE_MANAGEMENT_DMA)) {
- dword rx_dma_magic;
+ dword uninitialized_var(rx_dma_magic);
if ((pC->dma_handle = diva_get_dma_descriptor (pC->request, &rx_dma_magic)) >= 0) {
pC->xbuffer[0] = LLI;
pC->xbuffer[1] = 8;
diff --git a/drivers/isdn/hardware/eicon/diva.c b/drivers/isdn/hardware/eicon/diva.c
index ffa2afa77c2..1403a5458e6 100644
--- a/drivers/isdn/hardware/eicon/diva.c
+++ b/drivers/isdn/hardware/eicon/diva.c
@@ -515,12 +515,11 @@ diva_xdi_read(void *adapter, void *os_handle, void __user *dst,
irqreturn_t diva_os_irq_wrapper(int irq, void *context)
{
- diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) context;
+ diva_os_xdi_adapter_t *a = context;
diva_xdi_clear_interrupts_proc_t clear_int_proc;
- if (!a || !a->xdi_adapter.diva_isr_handler) {
+ if (!a || !a->xdi_adapter.diva_isr_handler)
return IRQ_NONE;
- }
if ((clear_int_proc = a->clear_interrupts_proc)) {
(*clear_int_proc) (a);
diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c
index b9177ca4369..1ff98e7eb79 100644
--- a/drivers/isdn/hardware/eicon/message.c
+++ b/drivers/isdn/hardware/eicon/message.c
@@ -9027,7 +9027,7 @@ static byte AddInfo(byte **add_i,
/* facility is a nested structure */
/* FTY can be more than once */
- if(esc_chi[0] && !(esc_chi[esc_chi[0]])&0x7f )
+ if (esc_chi[0] && !(esc_chi[esc_chi[0]] & 0x7f))
{
add_i[0] = (byte *)"\x02\x02\x00"; /* use neither b nor d channel */
}
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
index 035d158779d..0f1db1f669b 100644
--- a/drivers/isdn/hisax/avm_pci.c
+++ b/drivers/isdn/hisax/avm_pci.c
@@ -263,11 +263,7 @@ hdlc_empty_fifo(struct BCState *bcs, int count)
outl(idx, cs->hw.avm.cfg_reg + 4);
while (cnt < count) {
#ifdef __powerpc__
-#ifdef CONFIG_APUS
- *ptr++ = in_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE));
-#else
*ptr++ = in_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE));
-#endif /* CONFIG_APUS */
#else
*ptr++ = inl(cs->hw.avm.isac);
#endif /* __powerpc__ */
@@ -328,11 +324,7 @@ hdlc_fill_fifo(struct BCState *bcs)
if (cs->subtyp == AVM_FRITZ_PCI) {
while (cnt<count) {
#ifdef __powerpc__
-#ifdef CONFIG_APUS
- out_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE), *ptr++);
-#else
out_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE), *ptr++);
-#endif /* CONFIG_APUS */
#else
outl(*ptr++, cs->hw.avm.isac);
#endif /* __powerpc__ */
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 9cb6e5021ad..133eb18e65c 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -1917,7 +1917,6 @@ isdn_tty_modem_init(void)
info->owner = THIS_MODULE;
#endif
spin_lock_init(&info->readlock);
- init_MUTEX(&info->write_sem);
sprintf(info->last_cause, "0000");
sprintf(info->last_num, "none");
info->last_dir = 0;
diff --git a/drivers/isdn/i4l/isdn_ttyfax.c b/drivers/isdn/i4l/isdn_ttyfax.c
index a943d078bac..f93de4a3035 100644
--- a/drivers/isdn/i4l/isdn_ttyfax.c
+++ b/drivers/isdn/i4l/isdn_ttyfax.c
@@ -834,7 +834,7 @@ isdn_tty_cmd_FCLASS2(char **p, modem_info * info)
char *rp = &f->resolution;
p[0] += 2;
- if (!info->faxonline & 1) /* not outgoing connection */
+ if (!(info->faxonline & 1)) /* not outgoing connection */
PARSE_ERROR1;
for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 4); i++) {
diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c
index 82d957bde29..bf7997abc4a 100644
--- a/drivers/isdn/icn/icn.c
+++ b/drivers/isdn/icn/icn.c
@@ -1302,7 +1302,7 @@ icn_command(isdn_ctrl * c, icn_card * card)
}
break;
case ISDN_CMD_DIAL:
- if (!card->flags & ICN_FLAGS_RUNNING)
+ if (!(card->flags & ICN_FLAGS_RUNNING))
return -ENODEV;
if (card->leased)
break;
@@ -1328,7 +1328,7 @@ icn_command(isdn_ctrl * c, icn_card * card)
}
break;
case ISDN_CMD_ACCEPTD:
- if (!card->flags & ICN_FLAGS_RUNNING)
+ if (!(card->flags & ICN_FLAGS_RUNNING))
return -ENODEV;
if (c->arg < ICN_BCH) {
a = c->arg + 1;
@@ -1348,7 +1348,7 @@ icn_command(isdn_ctrl * c, icn_card * card)
}
break;
case ISDN_CMD_ACCEPTB:
- if (!card->flags & ICN_FLAGS_RUNNING)
+ if (!(card->flags & ICN_FLAGS_RUNNING))
return -ENODEV;
if (c->arg < ICN_BCH) {
a = c->arg + 1;
@@ -1366,7 +1366,7 @@ icn_command(isdn_ctrl * c, icn_card * card)
}
break;
case ISDN_CMD_HANGUP:
- if (!card->flags & ICN_FLAGS_RUNNING)
+ if (!(card->flags & ICN_FLAGS_RUNNING))
return -ENODEV;
if (c->arg < ICN_BCH) {
a = c->arg + 1;
@@ -1375,7 +1375,7 @@ icn_command(isdn_ctrl * c, icn_card * card)
}
break;
case ISDN_CMD_SETEAZ:
- if (!card->flags & ICN_FLAGS_RUNNING)
+ if (!(card->flags & ICN_FLAGS_RUNNING))
return -ENODEV;
if (card->leased)
break;
@@ -1391,7 +1391,7 @@ icn_command(isdn_ctrl * c, icn_card * card)
}
break;
case ISDN_CMD_CLREAZ:
- if (!card->flags & ICN_FLAGS_RUNNING)
+ if (!(card->flags & ICN_FLAGS_RUNNING))
return -ENODEV;
if (card->leased)
break;
@@ -1405,7 +1405,7 @@ icn_command(isdn_ctrl * c, icn_card * card)
}
break;
case ISDN_CMD_SETL2:
- if (!card->flags & ICN_FLAGS_RUNNING)
+ if (!(card->flags & ICN_FLAGS_RUNNING))
return -ENODEV;
if ((c->arg & 255) < ICN_BCH) {
a = c->arg;
@@ -1424,7 +1424,7 @@ icn_command(isdn_ctrl * c, icn_card * card)
}
break;
case ISDN_CMD_SETL3:
- if (!card->flags & ICN_FLAGS_RUNNING)
+ if (!(card->flags & ICN_FLAGS_RUNNING))
return -ENODEV;
return 0;
default:
@@ -1471,7 +1471,7 @@ if_writecmd(const u_char __user *buf, int len, int id, int channel)
icn_card *card = icn_findcard(id);
if (card) {
- if (!card->flags & ICN_FLAGS_RUNNING)
+ if (!(card->flags & ICN_FLAGS_RUNNING))
return -ENODEV;
return (icn_writecmd(buf, len, 1, card));
}
@@ -1486,7 +1486,7 @@ if_readstatus(u_char __user *buf, int len, int id, int channel)
icn_card *card = icn_findcard(id);
if (card) {
- if (!card->flags & ICN_FLAGS_RUNNING)
+ if (!(card->flags & ICN_FLAGS_RUNNING))
return -ENODEV;
return (icn_readstatus(buf, len, card));
}
@@ -1501,7 +1501,7 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
icn_card *card = icn_findcard(id);
if (card) {
- if (!card->flags & ICN_FLAGS_RUNNING)
+ if (!(card->flags & ICN_FLAGS_RUNNING))
return -ENODEV;
return (icn_sendbuf(channel, ack, skb, card));
}
diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c
index bb92e3cd933..655ef9a3f4d 100644
--- a/drivers/isdn/isdnloop/isdnloop.c
+++ b/drivers/isdn/isdnloop/isdnloop.c
@@ -1184,7 +1184,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card)
}
break;
case ISDN_CMD_DIAL:
- if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
return -ENODEV;
if (card->leased)
break;
@@ -1210,7 +1210,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card)
}
break;
case ISDN_CMD_ACCEPTD:
- if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
return -ENODEV;
if (c->arg < ISDNLOOP_BCH) {
a = c->arg + 1;
@@ -1238,7 +1238,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card)
}
break;
case ISDN_CMD_ACCEPTB:
- if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
return -ENODEV;
if (c->arg < ISDNLOOP_BCH) {
a = c->arg + 1;
@@ -1264,7 +1264,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card)
i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
break;
case ISDN_CMD_HANGUP:
- if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
return -ENODEV;
if (c->arg < ISDNLOOP_BCH) {
a = c->arg + 1;
@@ -1273,7 +1273,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card)
}
break;
case ISDN_CMD_SETEAZ:
- if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
return -ENODEV;
if (card->leased)
break;
@@ -1303,7 +1303,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card)
}
break;
case ISDN_CMD_SETL2:
- if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
return -ENODEV;
if ((c->arg & 255) < ISDNLOOP_BCH) {
a = c->arg;
@@ -1395,7 +1395,7 @@ if_readstatus(u_char __user *buf, int len, int id, int channel)
isdnloop_card *card = isdnloop_findcard(id);
if (card) {
- if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
return -ENODEV;
return (isdnloop_readstatus(buf, len, card));
}
@@ -1410,7 +1410,7 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
isdnloop_card *card = isdnloop_findcard(id);
if (card) {
- if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
return -ENODEV;
/* ack request stored in skb scratch area */
*(skb->head) = ack;
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
index de9ebbfbf12..936788272a5 100644
--- a/drivers/macintosh/mediabay.c
+++ b/drivers/macintosh/mediabay.c
@@ -78,12 +78,14 @@ struct media_bay_info {
int cached_gpio;
int sleeping;
struct semaphore lock;
-#ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
void __iomem *cd_base;
- int cd_index;
int cd_irq;
int cd_retry;
#endif
+#if defined(CONFIG_BLK_DEV_IDE_PMAC) || defined(CONFIG_MAC_FLOPPY)
+ int cd_index;
+#endif
};
#define MAX_BAYS 2
@@ -91,7 +93,7 @@ struct media_bay_info {
static struct media_bay_info media_bays[MAX_BAYS];
int media_bay_count = 0;
-#ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
/* check the busy bit in the media-bay ide interface
(assumes the media-bay contains an ide device) */
#define MB_IDE_READY(i) ((readb(media_bays[i].cd_base + 0x70) & 0x80) == 0)
@@ -401,7 +403,7 @@ static void poll_media_bay(struct media_bay_info* bay)
set_mb_power(bay, id != MB_NO);
bay->content_id = id;
if (id == MB_NO) {
-#ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
bay->cd_retry = 0;
#endif
printk(KERN_INFO "media bay %d is empty\n", bay->index);
@@ -414,9 +416,9 @@ static void poll_media_bay(struct media_bay_info* bay)
}
}
+#ifdef CONFIG_MAC_FLOPPY
int check_media_bay(struct device_node *which_bay, int what)
{
-#ifdef CONFIG_BLK_DEV_IDE
int i;
for (i=0; i<media_bay_count; i++)
@@ -426,14 +428,14 @@ int check_media_bay(struct device_node *which_bay, int what)
media_bays[i].cd_index = -1;
return -EINVAL;
}
-#endif /* CONFIG_BLK_DEV_IDE */
return -ENODEV;
}
EXPORT_SYMBOL(check_media_bay);
+#endif /* CONFIG_MAC_FLOPPY */
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
int check_media_bay_by_base(unsigned long base, int what)
{
-#ifdef CONFIG_BLK_DEV_IDE
int i;
for (i=0; i<media_bay_count; i++)
@@ -443,15 +445,13 @@ int check_media_bay_by_base(unsigned long base, int what)
media_bays[i].cd_index = -1;
return -EINVAL;
}
-#endif
-
+
return -ENODEV;
}
int media_bay_set_ide_infos(struct device_node* which_bay, unsigned long base,
- int irq, int index)
+ int irq, int index)
{
-#ifdef CONFIG_BLK_DEV_IDE
int i;
for (i=0; i<media_bay_count; i++) {
@@ -483,10 +483,10 @@ int media_bay_set_ide_infos(struct device_node* which_bay, unsigned long base,
return -ENODEV;
}
}
-#endif /* CONFIG_BLK_DEV_IDE */
-
+
return -ENODEV;
}
+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
static void media_bay_step(int i)
{
@@ -521,14 +521,13 @@ static void media_bay_step(int i)
bay->state = mb_resetting;
MBDBG("mediabay%d: waiting reset (kind:%d)\n", i, bay->content_id);
break;
-
case mb_resetting:
if (bay->content_id != MB_CD) {
MBDBG("mediabay%d: bay is up (kind:%d)\n", i, bay->content_id);
bay->state = mb_up;
break;
}
-#ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
MBDBG("mediabay%d: waiting IDE reset (kind:%d)\n", i, bay->content_id);
bay->ops->un_reset_ide(bay);
bay->timer = msecs_to_jiffies(MB_IDE_WAIT);
@@ -536,16 +535,14 @@ static void media_bay_step(int i)
#else
printk(KERN_DEBUG "media-bay %d is ide (not compiled in kernel)\n", i);
set_mb_power(bay, 0);
-#endif /* CONFIG_BLK_DEV_IDE */
+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
break;
-
-#ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
case mb_ide_resetting:
bay->timer = msecs_to_jiffies(MB_IDE_TIMEOUT);
bay->state = mb_ide_waiting;
MBDBG("mediabay%d: waiting IDE ready (kind:%d)\n", i, bay->content_id);
break;
-
case mb_ide_waiting:
if (bay->cd_base == NULL) {
bay->timer = 0;
@@ -587,11 +584,10 @@ static void media_bay_step(int i)
bay->timer = 0;
}
break;
-#endif /* CONFIG_BLK_DEV_IDE */
-
+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
case mb_powering_down:
bay->state = mb_empty;
-#ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
if (bay->cd_index >= 0) {
printk(KERN_DEBUG "Unregistering mb %d ide, index:%d\n", i,
bay->cd_index);
@@ -607,7 +603,7 @@ static void media_bay_step(int i)
bay->content_id = MB_NO;
}
}
-#endif /* CONFIG_BLK_DEV_IDE */
+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
MBDBG("mediabay%d: end of power down\n", i);
break;
}
@@ -739,7 +735,7 @@ static int media_bay_resume(struct macio_dev *mdev)
bay->last_value = bay->content_id;
bay->value_count = msecs_to_jiffies(MB_STABLE_DELAY);
bay->timer = msecs_to_jiffies(MB_POWER_DELAY);
-#ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
bay->cd_retry = 0;
#endif
do {
@@ -829,7 +825,7 @@ static int __init media_bay_init(void)
for (i=0; i<MAX_BAYS; i++) {
memset((char *)&media_bays[i], 0, sizeof(struct media_bay_info));
media_bays[i].content_id = -1;
-#ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
media_bays[i].cd_index = -1;
#endif
}
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 1b1ef3130e6..a0585fb6da9 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -237,7 +237,7 @@ static struct page *read_sb_page(mddev_t *mddev, long offset, unsigned long inde
if (!page)
return ERR_PTR(-ENOMEM);
- ITERATE_RDEV(mddev, rdev, tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
if (! test_bit(In_sync, &rdev->flags)
|| test_bit(Faulty, &rdev->flags))
continue;
@@ -261,7 +261,7 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
struct list_head *tmp;
mddev_t *mddev = bitmap->mddev;
- ITERATE_RDEV(mddev, rdev, tmp)
+ rdev_for_each(rdev, tmp, mddev)
if (test_bit(In_sync, &rdev->flags)
&& !test_bit(Faulty, &rdev->flags)) {
int size = PAGE_SIZE;
@@ -1348,14 +1348,38 @@ void bitmap_close_sync(struct bitmap *bitmap)
*/
sector_t sector = 0;
int blocks;
- if (!bitmap) return;
+ if (!bitmap)
+ return;
while (sector < bitmap->mddev->resync_max_sectors) {
bitmap_end_sync(bitmap, sector, &blocks, 0);
-/*
- if (sector < 500) printk("bitmap_close_sync: sec %llu blks %d\n",
- (unsigned long long)sector, blocks);
-*/ sector += blocks;
+ sector += blocks;
+ }
+}
+
+void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector)
+{
+ sector_t s = 0;
+ int blocks;
+
+ if (!bitmap)
+ return;
+ if (sector == 0) {
+ bitmap->last_end_sync = jiffies;
+ return;
+ }
+ if (time_before(jiffies, (bitmap->last_end_sync
+ + bitmap->daemon_sleep * HZ)))
+ return;
+ wait_event(bitmap->mddev->recovery_wait,
+ atomic_read(&bitmap->mddev->recovery_active) == 0);
+
+ sector &= ~((1ULL << CHUNK_BLOCK_SHIFT(bitmap)) - 1);
+ s = 0;
+ while (s < sector && s < bitmap->mddev->resync_max_sectors) {
+ bitmap_end_sync(bitmap, s, &blocks, 0);
+ s += blocks;
}
+ bitmap->last_end_sync = jiffies;
}
static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int needed)
@@ -1565,3 +1589,4 @@ EXPORT_SYMBOL(bitmap_start_sync);
EXPORT_SYMBOL(bitmap_end_sync);
EXPORT_SYMBOL(bitmap_unplug);
EXPORT_SYMBOL(bitmap_close_sync);
+EXPORT_SYMBOL(bitmap_cond_end_sync);
diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c
index cf2ddce3411..d107ddceefc 100644
--- a/drivers/md/faulty.c
+++ b/drivers/md/faulty.c
@@ -294,7 +294,7 @@ static int run(mddev_t *mddev)
}
conf->nfaults = 0;
- ITERATE_RDEV(mddev, rdev, tmp)
+ rdev_for_each(rdev, tmp, mddev)
conf->rdev = rdev;
mddev->array_size = mddev->size;
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index 3dac1cfb818..0b8511776b3 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -122,7 +122,7 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks)
cnt = 0;
conf->array_size = 0;
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
int j = rdev->raid_disk;
dev_info_t *disk = conf->disks + j;
diff --git a/drivers/md/md.c b/drivers/md/md.c
index c28a120b416..5fc326d3970 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -195,7 +195,7 @@ static DEFINE_SPINLOCK(all_mddevs_lock);
* Any code which breaks out of this loop while own
* a reference to the current mddev and must mddev_put it.
*/
-#define ITERATE_MDDEV(mddev,tmp) \
+#define for_each_mddev(mddev,tmp) \
\
for (({ spin_lock(&all_mddevs_lock); \
tmp = all_mddevs.next; \
@@ -275,6 +275,7 @@ static mddev_t * mddev_find(dev_t unit)
spin_lock_init(&new->write_lock);
init_waitqueue_head(&new->sb_wait);
new->reshape_position = MaxSector;
+ new->resync_max = MaxSector;
new->queue = blk_alloc_queue(GFP_KERNEL);
if (!new->queue) {
@@ -310,7 +311,7 @@ static mdk_rdev_t * find_rdev_nr(mddev_t *mddev, int nr)
mdk_rdev_t * rdev;
struct list_head *tmp;
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
if (rdev->desc_nr == nr)
return rdev;
}
@@ -322,7 +323,7 @@ static mdk_rdev_t * find_rdev(mddev_t * mddev, dev_t dev)
struct list_head *tmp;
mdk_rdev_t *rdev;
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
if (rdev->bdev->bd_dev == dev)
return rdev;
}
@@ -773,12 +774,16 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev)
__u64 ev1 = md_event(sb);
rdev->raid_disk = -1;
- rdev->flags = 0;
+ clear_bit(Faulty, &rdev->flags);
+ clear_bit(In_sync, &rdev->flags);
+ clear_bit(WriteMostly, &rdev->flags);
+ clear_bit(BarriersNotsupp, &rdev->flags);
+
if (mddev->raid_disks == 0) {
mddev->major_version = 0;
mddev->minor_version = sb->minor_version;
mddev->patch_version = sb->patch_version;
- mddev->persistent = ! sb->not_persistent;
+ mddev->external = 0;
mddev->chunk_size = sb->chunk_size;
mddev->ctime = sb->ctime;
mddev->utime = sb->utime;
@@ -904,7 +909,7 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
sb->size = mddev->size;
sb->raid_disks = mddev->raid_disks;
sb->md_minor = mddev->md_minor;
- sb->not_persistent = !mddev->persistent;
+ sb->not_persistent = 0;
sb->utime = mddev->utime;
sb->state = 0;
sb->events_hi = (mddev->events>>32);
@@ -938,7 +943,7 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
sb->state |= (1<<MD_SB_BITMAP_PRESENT);
sb->disks[0].state = (1<<MD_DISK_REMOVED);
- ITERATE_RDEV(mddev,rdev2,tmp) {
+ rdev_for_each(rdev2, tmp, mddev) {
mdp_disk_t *d;
int desc_nr;
if (rdev2->raid_disk >= 0 && test_bit(In_sync, &rdev2->flags)
@@ -1153,11 +1158,15 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
__u64 ev1 = le64_to_cpu(sb->events);
rdev->raid_disk = -1;
- rdev->flags = 0;
+ clear_bit(Faulty, &rdev->flags);
+ clear_bit(In_sync, &rdev->flags);
+ clear_bit(WriteMostly, &rdev->flags);
+ clear_bit(BarriersNotsupp, &rdev->flags);
+
if (mddev->raid_disks == 0) {
mddev->major_version = 1;
mddev->patch_version = 0;
- mddev->persistent = 1;
+ mddev->external = 0;
mddev->chunk_size = le32_to_cpu(sb->chunksize) << 9;
mddev->ctime = le64_to_cpu(sb->ctime) & ((1ULL << 32)-1);
mddev->utime = le64_to_cpu(sb->utime) & ((1ULL << 32)-1);
@@ -1286,7 +1295,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
}
max_dev = 0;
- ITERATE_RDEV(mddev,rdev2,tmp)
+ rdev_for_each(rdev2, tmp, mddev)
if (rdev2->desc_nr+1 > max_dev)
max_dev = rdev2->desc_nr+1;
@@ -1295,7 +1304,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
for (i=0; i<max_dev;i++)
sb->dev_roles[i] = cpu_to_le16(0xfffe);
- ITERATE_RDEV(mddev,rdev2,tmp) {
+ rdev_for_each(rdev2, tmp, mddev) {
i = rdev2->desc_nr;
if (test_bit(Faulty, &rdev2->flags))
sb->dev_roles[i] = cpu_to_le16(0xfffe);
@@ -1333,8 +1342,8 @@ static int match_mddev_units(mddev_t *mddev1, mddev_t *mddev2)
struct list_head *tmp, *tmp2;
mdk_rdev_t *rdev, *rdev2;
- ITERATE_RDEV(mddev1,rdev,tmp)
- ITERATE_RDEV(mddev2, rdev2, tmp2)
+ rdev_for_each(rdev, tmp, mddev1)
+ rdev_for_each(rdev2, tmp2, mddev2)
if (rdev->bdev->bd_contains ==
rdev2->bdev->bd_contains)
return 1;
@@ -1401,7 +1410,7 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
goto fail;
}
list_add(&rdev->same_set, &mddev->disks);
- bd_claim_by_disk(rdev->bdev, rdev, mddev->gendisk);
+ bd_claim_by_disk(rdev->bdev, rdev->bdev->bd_holder, mddev->gendisk);
return 0;
fail:
@@ -1410,10 +1419,11 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
return err;
}
-static void delayed_delete(struct work_struct *ws)
+static void md_delayed_delete(struct work_struct *ws)
{
mdk_rdev_t *rdev = container_of(ws, mdk_rdev_t, del_work);
kobject_del(&rdev->kobj);
+ kobject_put(&rdev->kobj);
}
static void unbind_rdev_from_array(mdk_rdev_t * rdev)
@@ -1432,7 +1442,8 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev)
/* We need to delay this, otherwise we can deadlock when
* writing to 'remove' to "dev/state"
*/
- INIT_WORK(&rdev->del_work, delayed_delete);
+ INIT_WORK(&rdev->del_work, md_delayed_delete);
+ kobject_get(&rdev->kobj);
schedule_work(&rdev->del_work);
}
@@ -1441,7 +1452,7 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev)
* otherwise reused by a RAID array (or any other kernel
* subsystem), by bd_claiming the device.
*/
-static int lock_rdev(mdk_rdev_t *rdev, dev_t dev)
+static int lock_rdev(mdk_rdev_t *rdev, dev_t dev, int shared)
{
int err = 0;
struct block_device *bdev;
@@ -1453,13 +1464,15 @@ static int lock_rdev(mdk_rdev_t *rdev, dev_t dev)
__bdevname(dev, b));
return PTR_ERR(bdev);
}
- err = bd_claim(bdev, rdev);
+ err = bd_claim(bdev, shared ? (mdk_rdev_t *)lock_rdev : rdev);
if (err) {
printk(KERN_ERR "md: could not bd_claim %s.\n",
bdevname(bdev, b));
blkdev_put(bdev);
return err;
}
+ if (!shared)
+ set_bit(AllReserved, &rdev->flags);
rdev->bdev = bdev;
return err;
}
@@ -1503,7 +1516,7 @@ static void export_array(mddev_t *mddev)
struct list_head *tmp;
mdk_rdev_t *rdev;
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
if (!rdev->mddev) {
MD_BUG();
continue;
@@ -1581,17 +1594,17 @@ static void md_print_devices(void)
printk("md: **********************************\n");
printk("md: * <COMPLETE RAID STATE PRINTOUT> *\n");
printk("md: **********************************\n");
- ITERATE_MDDEV(mddev,tmp) {
+ for_each_mddev(mddev, tmp) {
if (mddev->bitmap)
bitmap_print_sb(mddev->bitmap);
else
printk("%s: ", mdname(mddev));
- ITERATE_RDEV(mddev,rdev,tmp2)
+ rdev_for_each(rdev, tmp2, mddev)
printk("<%s>", bdevname(rdev->bdev,b));
printk("\n");
- ITERATE_RDEV(mddev,rdev,tmp2)
+ rdev_for_each(rdev, tmp2, mddev)
print_rdev(rdev);
}
printk("md: **********************************\n");
@@ -1610,7 +1623,7 @@ static void sync_sbs(mddev_t * mddev, int nospares)
mdk_rdev_t *rdev;
struct list_head *tmp;
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
if (rdev->sb_events == mddev->events ||
(nospares &&
rdev->raid_disk < 0 &&
@@ -1696,18 +1709,20 @@ repeat:
MD_BUG();
mddev->events --;
}
- sync_sbs(mddev, nospares);
/*
* do not write anything to disk if using
* nonpersistent superblocks
*/
if (!mddev->persistent) {
- clear_bit(MD_CHANGE_PENDING, &mddev->flags);
+ if (!mddev->external)
+ clear_bit(MD_CHANGE_PENDING, &mddev->flags);
+
spin_unlock_irq(&mddev->write_lock);
wake_up(&mddev->sb_wait);
return;
}
+ sync_sbs(mddev, nospares);
spin_unlock_irq(&mddev->write_lock);
dprintk(KERN_INFO
@@ -1715,7 +1730,7 @@ repeat:
mdname(mddev),mddev->in_sync);
bitmap_update_sb(mddev->bitmap);
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
char b[BDEVNAME_SIZE];
dprintk(KERN_INFO "md: ");
if (rdev->sb_loaded != 1)
@@ -1785,7 +1800,7 @@ static ssize_t
state_show(mdk_rdev_t *rdev, char *page)
{
char *sep = "";
- int len=0;
+ size_t len = 0;
if (test_bit(Faulty, &rdev->flags)) {
len+= sprintf(page+len, "%sfaulty",sep);
@@ -1887,20 +1902,45 @@ static ssize_t
slot_store(mdk_rdev_t *rdev, const char *buf, size_t len)
{
char *e;
+ int err;
+ char nm[20];
int slot = simple_strtoul(buf, &e, 10);
if (strncmp(buf, "none", 4)==0)
slot = -1;
else if (e==buf || (*e && *e!= '\n'))
return -EINVAL;
- if (rdev->mddev->pers)
- /* Cannot set slot in active array (yet) */
- return -EBUSY;
- if (slot >= rdev->mddev->raid_disks)
- return -ENOSPC;
- rdev->raid_disk = slot;
- /* assume it is working */
- rdev->flags = 0;
- set_bit(In_sync, &rdev->flags);
+ if (rdev->mddev->pers) {
+ /* Setting 'slot' on an active array requires also
+ * updating the 'rd%d' link, and communicating
+ * with the personality with ->hot_*_disk.
+ * For now we only support removing
+ * failed/spare devices. This normally happens automatically,
+ * but not when the metadata is externally managed.
+ */
+ if (slot != -1)
+ return -EBUSY;
+ if (rdev->raid_disk == -1)
+ return -EEXIST;
+ /* personality does all needed checks */
+ if (rdev->mddev->pers->hot_add_disk == NULL)
+ return -EINVAL;
+ err = rdev->mddev->pers->
+ hot_remove_disk(rdev->mddev, rdev->raid_disk);
+ if (err)
+ return err;
+ sprintf(nm, "rd%d", rdev->raid_disk);
+ sysfs_remove_link(&rdev->mddev->kobj, nm);
+ set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery);
+ md_wakeup_thread(rdev->mddev->thread);
+ } else {
+ if (slot >= rdev->mddev->raid_disks)
+ return -ENOSPC;
+ rdev->raid_disk = slot;
+ /* assume it is working */
+ clear_bit(Faulty, &rdev->flags);
+ clear_bit(WriteMostly, &rdev->flags);
+ set_bit(In_sync, &rdev->flags);
+ }
return len;
}
@@ -1923,6 +1963,10 @@ offset_store(mdk_rdev_t *rdev, const char *buf, size_t len)
return -EINVAL;
if (rdev->mddev->pers)
return -EBUSY;
+ if (rdev->size && rdev->mddev->external)
+ /* Must set offset before size, so overlap checks
+ * can be sane */
+ return -EBUSY;
rdev->data_offset = offset;
return len;
}
@@ -1936,16 +1980,69 @@ rdev_size_show(mdk_rdev_t *rdev, char *page)
return sprintf(page, "%llu\n", (unsigned long long)rdev->size);
}
+static int overlaps(sector_t s1, sector_t l1, sector_t s2, sector_t l2)
+{
+ /* check if two start/length pairs overlap */
+ if (s1+l1 <= s2)
+ return 0;
+ if (s2+l2 <= s1)
+ return 0;
+ return 1;
+}
+
static ssize_t
rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len)
{
char *e;
unsigned long long size = simple_strtoull(buf, &e, 10);
+ unsigned long long oldsize = rdev->size;
if (e==buf || (*e && *e != '\n'))
return -EINVAL;
if (rdev->mddev->pers)
return -EBUSY;
rdev->size = size;
+ if (size > oldsize && rdev->mddev->external) {
+ /* need to check that all other rdevs with the same ->bdev
+ * do not overlap. We need to unlock the mddev to avoid
+ * a deadlock. We have already changed rdev->size, and if
+ * we have to change it back, we will have the lock again.
+ */
+ mddev_t *mddev;
+ int overlap = 0;
+ struct list_head *tmp, *tmp2;
+
+ mddev_unlock(rdev->mddev);
+ for_each_mddev(mddev, tmp) {
+ mdk_rdev_t *rdev2;
+
+ mddev_lock(mddev);
+ rdev_for_each(rdev2, tmp2, mddev)
+ if (test_bit(AllReserved, &rdev2->flags) ||
+ (rdev->bdev == rdev2->bdev &&
+ rdev != rdev2 &&
+ overlaps(rdev->data_offset, rdev->size,
+ rdev2->data_offset, rdev2->size))) {
+ overlap = 1;
+ break;
+ }
+ mddev_unlock(mddev);
+ if (overlap) {
+ mddev_put(mddev);
+ break;
+ }
+ }
+ mddev_lock(rdev->mddev);
+ if (overlap) {
+ /* Someone else could have slipped in a size
+ * change here, but doing so is just silly.
+ * We put oldsize back because we *know* it is
+ * safe, and trust userspace not to race with
+ * itself
+ */
+ rdev->size = oldsize;
+ return -EBUSY;
+ }
+ }
if (size < rdev->mddev->size || rdev->mddev->size == 0)
rdev->mddev->size = size;
return len;
@@ -1980,12 +2077,18 @@ rdev_attr_store(struct kobject *kobj, struct attribute *attr,
{
struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr);
mdk_rdev_t *rdev = container_of(kobj, mdk_rdev_t, kobj);
+ int rv;
if (!entry->store)
return -EIO;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- return entry->store(rdev, page, length);
+ rv = mddev_lock(rdev->mddev);
+ if (!rv) {
+ rv = entry->store(rdev, page, length);
+ mddev_unlock(rdev->mddev);
+ }
+ return rv;
}
static void rdev_free(struct kobject *ko)
@@ -2029,7 +2132,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
if ((err = alloc_disk_sb(rdev)))
goto abort_free;
- err = lock_rdev(rdev, newdev);
+ err = lock_rdev(rdev, newdev, super_format == -2);
if (err)
goto abort_free;
@@ -2099,7 +2202,7 @@ static void analyze_sbs(mddev_t * mddev)
char b[BDEVNAME_SIZE];
freshest = NULL;
- ITERATE_RDEV(mddev,rdev,tmp)
+ rdev_for_each(rdev, tmp, mddev)
switch (super_types[mddev->major_version].
load_super(rdev, freshest, mddev->minor_version)) {
case 1:
@@ -2120,7 +2223,7 @@ static void analyze_sbs(mddev_t * mddev)
validate_super(mddev, freshest);
i = 0;
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
if (rdev != freshest)
if (super_types[mddev->major_version].
validate_super(mddev, rdev)) {
@@ -2215,7 +2318,7 @@ level_show(mddev_t *mddev, char *page)
static ssize_t
level_store(mddev_t *mddev, const char *buf, size_t len)
{
- int rv = len;
+ ssize_t rv = len;
if (mddev->pers)
return -EBUSY;
if (len == 0)
@@ -2425,6 +2528,8 @@ array_state_show(mddev_t *mddev, char *page)
case 0:
if (mddev->in_sync)
st = clean;
+ else if (test_bit(MD_CHANGE_CLEAN, &mddev->flags))
+ st = write_pending;
else if (mddev->safemode)
st = active_idle;
else
@@ -2455,11 +2560,9 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len)
break;
case clear:
/* stopping an active array */
- if (mddev->pers) {
- if (atomic_read(&mddev->active) > 1)
- return -EBUSY;
- err = do_md_stop(mddev, 0);
- }
+ if (atomic_read(&mddev->active) > 1)
+ return -EBUSY;
+ err = do_md_stop(mddev, 0);
break;
case inactive:
/* stopping an active array */
@@ -2467,7 +2570,8 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len)
if (atomic_read(&mddev->active) > 1)
return -EBUSY;
err = do_md_stop(mddev, 2);
- }
+ } else
+ err = 0; /* already inactive */
break;
case suspended:
break; /* not supported yet */
@@ -2495,9 +2599,15 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len)
restart_array(mddev);
spin_lock_irq(&mddev->write_lock);
if (atomic_read(&mddev->writes_pending) == 0) {
- mddev->in_sync = 1;
- set_bit(MD_CHANGE_CLEAN, &mddev->flags);
- }
+ if (mddev->in_sync == 0) {
+ mddev->in_sync = 1;
+ if (mddev->persistent)
+ set_bit(MD_CHANGE_CLEAN,
+ &mddev->flags);
+ }
+ err = 0;
+ } else
+ err = -EBUSY;
spin_unlock_irq(&mddev->write_lock);
} else {
mddev->ro = 0;
@@ -2508,7 +2618,8 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len)
case active:
if (mddev->pers) {
restart_array(mddev);
- clear_bit(MD_CHANGE_CLEAN, &mddev->flags);
+ if (mddev->external)
+ clear_bit(MD_CHANGE_CLEAN, &mddev->flags);
wake_up(&mddev->sb_wait);
err = 0;
} else {
@@ -2574,7 +2685,9 @@ new_dev_store(mddev_t *mddev, const char *buf, size_t len)
if (err < 0)
goto out;
}
- } else
+ } else if (mddev->external)
+ rdev = md_import_device(dev, -2, -1);
+ else
rdev = md_import_device(dev, -1, -1);
if (IS_ERR(rdev))
@@ -2659,7 +2772,9 @@ __ATTR(component_size, S_IRUGO|S_IWUSR, size_show, size_store);
/* Metdata version.
- * This is either 'none' for arrays with externally managed metadata,
+ * This is one of
+ * 'none' for arrays with no metadata (good luck...)
+ * 'external' for arrays with externally managed metadata,
* or N.M for internally known formats
*/
static ssize_t
@@ -2668,6 +2783,8 @@ metadata_show(mddev_t *mddev, char *page)
if (mddev->persistent)
return sprintf(page, "%d.%d\n",
mddev->major_version, mddev->minor_version);
+ else if (mddev->external)
+ return sprintf(page, "external:%s\n", mddev->metadata_type);
else
return sprintf(page, "none\n");
}
@@ -2682,6 +2799,21 @@ metadata_store(mddev_t *mddev, const char *buf, size_t len)
if (cmd_match(buf, "none")) {
mddev->persistent = 0;
+ mddev->external = 0;
+ mddev->major_version = 0;
+ mddev->minor_version = 90;
+ return len;
+ }
+ if (strncmp(buf, "external:", 9) == 0) {
+ size_t namelen = len-9;
+ if (namelen >= sizeof(mddev->metadata_type))
+ namelen = sizeof(mddev->metadata_type)-1;
+ strncpy(mddev->metadata_type, buf+9, namelen);
+ mddev->metadata_type[namelen] = 0;
+ if (namelen && mddev->metadata_type[namelen-1] == '\n')
+ mddev->metadata_type[--namelen] = 0;
+ mddev->persistent = 0;
+ mddev->external = 1;
mddev->major_version = 0;
mddev->minor_version = 90;
return len;
@@ -2698,6 +2830,7 @@ metadata_store(mddev_t *mddev, const char *buf, size_t len)
mddev->major_version = major;
mddev->minor_version = minor;
mddev->persistent = 1;
+ mddev->external = 0;
return len;
}
@@ -2865,6 +2998,43 @@ sync_completed_show(mddev_t *mddev, char *page)
static struct md_sysfs_entry md_sync_completed = __ATTR_RO(sync_completed);
static ssize_t
+max_sync_show(mddev_t *mddev, char *page)
+{
+ if (mddev->resync_max == MaxSector)
+ return sprintf(page, "max\n");
+ else
+ return sprintf(page, "%llu\n",
+ (unsigned long long)mddev->resync_max);
+}
+static ssize_t
+max_sync_store(mddev_t *mddev, const char *buf, size_t len)
+{
+ if (strncmp(buf, "max", 3) == 0)
+ mddev->resync_max = MaxSector;
+ else {
+ char *ep;
+ unsigned long long max = simple_strtoull(buf, &ep, 10);
+ if (ep == buf || (*ep != 0 && *ep != '\n'))
+ return -EINVAL;
+ if (max < mddev->resync_max &&
+ test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
+ return -EBUSY;
+
+ /* Must be a multiple of chunk_size */
+ if (mddev->chunk_size) {
+ if (max & (sector_t)((mddev->chunk_size>>9)-1))
+ return -EINVAL;
+ }
+ mddev->resync_max = max;
+ }
+ wake_up(&mddev->recovery_wait);
+ return len;
+}
+
+static struct md_sysfs_entry md_max_sync =
+__ATTR(sync_max, S_IRUGO|S_IWUSR, max_sync_show, max_sync_store);
+
+static ssize_t
suspend_lo_show(mddev_t *mddev, char *page)
{
return sprintf(page, "%llu\n", (unsigned long long)mddev->suspend_lo);
@@ -2974,6 +3144,7 @@ static struct attribute *md_redundancy_attrs[] = {
&md_sync_max.attr,
&md_sync_speed.attr,
&md_sync_completed.attr,
+ &md_max_sync.attr,
&md_suspend_lo.attr,
&md_suspend_hi.attr,
&md_bitmap.attr,
@@ -3118,8 +3289,11 @@ static int do_md_run(mddev_t * mddev)
/*
* Analyze all RAID superblock(s)
*/
- if (!mddev->raid_disks)
+ if (!mddev->raid_disks) {
+ if (!mddev->persistent)
+ return -EINVAL;
analyze_sbs(mddev);
+ }
chunk_size = mddev->chunk_size;
@@ -3143,7 +3317,7 @@ static int do_md_run(mddev_t * mddev)
}
/* devices must have minimum size of one chunk */
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
if (test_bit(Faulty, &rdev->flags))
continue;
if (rdev->size < chunk_size / 1024) {
@@ -3170,7 +3344,7 @@ static int do_md_run(mddev_t * mddev)
* the only valid external interface is through the md
* device.
*/
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
if (test_bit(Faulty, &rdev->flags))
continue;
sync_blockdev(rdev->bdev);
@@ -3236,8 +3410,8 @@ static int do_md_run(mddev_t * mddev)
mdk_rdev_t *rdev2;
struct list_head *tmp2;
int warned = 0;
- ITERATE_RDEV(mddev, rdev, tmp) {
- ITERATE_RDEV(mddev, rdev2, tmp2) {
+ rdev_for_each(rdev, tmp, mddev) {
+ rdev_for_each(rdev2, tmp2, mddev) {
if (rdev < rdev2 &&
rdev->bdev->bd_contains ==
rdev2->bdev->bd_contains) {
@@ -3297,7 +3471,7 @@ static int do_md_run(mddev_t * mddev)
mddev->safemode_delay = (200 * HZ)/1000 +1; /* 200 msec delay */
mddev->in_sync = 1;
- ITERATE_RDEV(mddev,rdev,tmp)
+ rdev_for_each(rdev, tmp, mddev)
if (rdev->raid_disk >= 0) {
char nm[20];
sprintf(nm, "rd%d", rdev->raid_disk);
@@ -3330,7 +3504,7 @@ static int do_md_run(mddev_t * mddev)
if (mddev->degraded && !mddev->sync_thread) {
struct list_head *rtmp;
int spares = 0;
- ITERATE_RDEV(mddev,rdev,rtmp)
+ rdev_for_each(rdev, rtmp, mddev)
if (rdev->raid_disk >= 0 &&
!test_bit(In_sync, &rdev->flags) &&
!test_bit(Faulty, &rdev->flags))
@@ -3507,14 +3681,14 @@ static int do_md_stop(mddev_t * mddev, int mode)
}
mddev->bitmap_offset = 0;
- ITERATE_RDEV(mddev,rdev,tmp)
+ rdev_for_each(rdev, tmp, mddev)
if (rdev->raid_disk >= 0) {
char nm[20];
sprintf(nm, "rd%d", rdev->raid_disk);
sysfs_remove_link(&mddev->kobj, nm);
}
- /* make sure all delayed_delete calls have finished */
+ /* make sure all md_delayed_delete calls have finished */
flush_scheduled_work();
export_array(mddev);
@@ -3523,7 +3697,10 @@ static int do_md_stop(mddev_t * mddev, int mode)
mddev->size = 0;
mddev->raid_disks = 0;
mddev->recovery_cp = 0;
+ mddev->resync_max = MaxSector;
mddev->reshape_position = MaxSector;
+ mddev->external = 0;
+ mddev->persistent = 0;
} else if (mddev->pers)
printk(KERN_INFO "md: %s switched to read-only mode.\n",
@@ -3546,7 +3723,7 @@ static void autorun_array(mddev_t *mddev)
printk(KERN_INFO "md: running: ");
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
char b[BDEVNAME_SIZE];
printk("<%s>", bdevname(rdev->bdev,b));
}
@@ -3589,7 +3766,7 @@ static void autorun_devices(int part)
printk(KERN_INFO "md: considering %s ...\n",
bdevname(rdev0->bdev,b));
INIT_LIST_HEAD(&candidates);
- ITERATE_RDEV_PENDING(rdev,tmp)
+ rdev_for_each_list(rdev, tmp, pending_raid_disks)
if (super_90_load(rdev, rdev0, 0) >= 0) {
printk(KERN_INFO "md: adding %s ...\n",
bdevname(rdev->bdev,b));
@@ -3632,7 +3809,8 @@ static void autorun_devices(int part)
mddev_unlock(mddev);
} else {
printk(KERN_INFO "md: created %s\n", mdname(mddev));
- ITERATE_RDEV_GENERIC(candidates,rdev,tmp) {
+ mddev->persistent = 1;
+ rdev_for_each_list(rdev, tmp, candidates) {
list_del_init(&rdev->same_set);
if (bind_rdev_to_array(rdev, mddev))
export_rdev(rdev);
@@ -3643,7 +3821,7 @@ static void autorun_devices(int part)
/* on success, candidates will be empty, on error
* it won't...
*/
- ITERATE_RDEV_GENERIC(candidates,rdev,tmp)
+ rdev_for_each_list(rdev, tmp, candidates)
export_rdev(rdev);
mddev_put(mddev);
}
@@ -3673,7 +3851,7 @@ static int get_array_info(mddev_t * mddev, void __user * arg)
struct list_head *tmp;
nr=working=active=failed=spare=0;
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
nr++;
if (test_bit(Faulty, &rdev->flags))
failed++;
@@ -3919,8 +4097,6 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
else
rdev->raid_disk = -1;
- rdev->flags = 0;
-
if (rdev->raid_disk < mddev->raid_disks)
if (info->state & (1<<MD_DISK_SYNC))
set_bit(In_sync, &rdev->flags);
@@ -4165,13 +4341,15 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info)
else
mddev->recovery_cp = 0;
mddev->persistent = ! info->not_persistent;
+ mddev->external = 0;
mddev->layout = info->layout;
mddev->chunk_size = info->chunk_size;
mddev->max_disks = MD_SB_DISKS;
- mddev->flags = 0;
+ if (mddev->persistent)
+ mddev->flags = 0;
set_bit(MD_CHANGE_DEVS, &mddev->flags);
mddev->default_bitmap_offset = MD_SB_BYTES >> 9;
@@ -4213,7 +4391,7 @@ static int update_size(mddev_t *mddev, unsigned long size)
*/
if (mddev->sync_thread)
return -EBUSY;
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
sector_t avail;
avail = rdev->size * 2;
@@ -4471,9 +4649,10 @@ static int md_ioctl(struct inode *inode, struct file *file,
*/
/* if we are not initialised yet, only ADD_NEW_DISK, STOP_ARRAY,
* RUN_ARRAY, and GET_ and SET_BITMAP_FILE are allowed */
- if (!mddev->raid_disks && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY
- && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE
- && cmd != GET_BITMAP_FILE) {
+ if ((!mddev->raid_disks && !mddev->external)
+ && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY
+ && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE
+ && cmd != GET_BITMAP_FILE) {
err = -ENODEV;
goto abort_unlock;
}
@@ -4757,7 +4936,7 @@ static void status_unused(struct seq_file *seq)
seq_printf(seq, "unused devices: ");
- ITERATE_RDEV_PENDING(rdev,tmp) {
+ rdev_for_each_list(rdev, tmp, pending_raid_disks) {
char b[BDEVNAME_SIZE];
i++;
seq_printf(seq, "%s ",
@@ -4953,7 +5132,7 @@ static int md_seq_show(struct seq_file *seq, void *v)
}
size = 0;
- ITERATE_RDEV(mddev,rdev,tmp2) {
+ rdev_for_each(rdev, tmp2, mddev) {
char b[BDEVNAME_SIZE];
seq_printf(seq, " %s[%d]",
bdevname(rdev->bdev,b), rdev->desc_nr);
@@ -4982,7 +5161,10 @@ static int md_seq_show(struct seq_file *seq, void *v)
mddev->major_version,
mddev->minor_version);
}
- } else
+ } else if (mddev->external)
+ seq_printf(seq, " super external:%s",
+ mddev->metadata_type);
+ else
seq_printf(seq, " super non-persistent");
if (mddev->pers) {
@@ -5106,7 +5288,7 @@ static int is_mddev_idle(mddev_t *mddev)
long curr_events;
idle = 1;
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
struct gendisk *disk = rdev->bdev->bd_contains->bd_disk;
curr_events = disk_stat_read(disk, sectors[0]) +
disk_stat_read(disk, sectors[1]) -
@@ -5283,7 +5465,7 @@ void md_do_sync(mddev_t *mddev)
set_bit(MD_RECOVERY_INTR, &mddev->recovery);
goto skip;
}
- ITERATE_MDDEV(mddev2,tmp) {
+ for_each_mddev(mddev2, tmp) {
if (mddev2 == mddev)
continue;
if (mddev2->curr_resync &&
@@ -5333,7 +5515,7 @@ void md_do_sync(mddev_t *mddev)
/* recovery follows the physical size of devices */
max_sectors = mddev->size << 1;
j = MaxSector;
- ITERATE_RDEV(mddev,rdev,rtmp)
+ rdev_for_each(rdev, rtmp, mddev)
if (rdev->raid_disk >= 0 &&
!test_bit(Faulty, &rdev->flags) &&
!test_bit(In_sync, &rdev->flags) &&
@@ -5381,8 +5563,16 @@ void md_do_sync(mddev_t *mddev)
sector_t sectors;
skipped = 0;
+ if (j >= mddev->resync_max) {
+ sysfs_notify(&mddev->kobj, NULL, "sync_completed");
+ wait_event(mddev->recovery_wait,
+ mddev->resync_max > j
+ || kthread_should_stop());
+ }
+ if (kthread_should_stop())
+ goto interrupted;
sectors = mddev->pers->sync_request(mddev, j, &skipped,
- currspeed < speed_min(mddev));
+ currspeed < speed_min(mddev));
if (sectors == 0) {
set_bit(MD_RECOVERY_ERR, &mddev->recovery);
goto out;
@@ -5424,15 +5614,9 @@ void md_do_sync(mddev_t *mddev)
}
- if (kthread_should_stop()) {
- /*
- * got a signal, exit.
- */
- printk(KERN_INFO
- "md: md_do_sync() got signal ... exiting\n");
- set_bit(MD_RECOVERY_INTR, &mddev->recovery);
- goto out;
- }
+ if (kthread_should_stop())
+ goto interrupted;
+
/*
* this loop exits only if either when we are slower than
@@ -5484,7 +5668,7 @@ void md_do_sync(mddev_t *mddev)
} else {
if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery))
mddev->curr_resync = MaxSector;
- ITERATE_RDEV(mddev,rdev,rtmp)
+ rdev_for_each(rdev, rtmp, mddev)
if (rdev->raid_disk >= 0 &&
!test_bit(Faulty, &rdev->flags) &&
!test_bit(In_sync, &rdev->flags) &&
@@ -5496,9 +5680,22 @@ void md_do_sync(mddev_t *mddev)
skip:
mddev->curr_resync = 0;
+ mddev->resync_max = MaxSector;
+ sysfs_notify(&mddev->kobj, NULL, "sync_completed");
wake_up(&resync_wait);
set_bit(MD_RECOVERY_DONE, &mddev->recovery);
md_wakeup_thread(mddev->thread);
+ return;
+
+ interrupted:
+ /*
+ * got a signal, exit.
+ */
+ printk(KERN_INFO
+ "md: md_do_sync() got signal ... exiting\n");
+ set_bit(MD_RECOVERY_INTR, &mddev->recovery);
+ goto out;
+
}
EXPORT_SYMBOL_GPL(md_do_sync);
@@ -5509,8 +5706,9 @@ static int remove_and_add_spares(mddev_t *mddev)
struct list_head *rtmp;
int spares = 0;
- ITERATE_RDEV(mddev,rdev,rtmp)
+ rdev_for_each(rdev, rtmp, mddev)
if (rdev->raid_disk >= 0 &&
+ !mddev->external &&
(test_bit(Faulty, &rdev->flags) ||
! test_bit(In_sync, &rdev->flags)) &&
atomic_read(&rdev->nr_pending)==0) {
@@ -5524,7 +5722,7 @@ static int remove_and_add_spares(mddev_t *mddev)
}
if (mddev->degraded) {
- ITERATE_RDEV(mddev,rdev,rtmp)
+ rdev_for_each(rdev, rtmp, mddev)
if (rdev->raid_disk < 0
&& !test_bit(Faulty, &rdev->flags)) {
rdev->recovery_offset = 0;
@@ -5589,7 +5787,7 @@ void md_check_recovery(mddev_t *mddev)
}
if ( ! (
- mddev->flags ||
+ (mddev->flags && !mddev->external) ||
test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) ||
test_bit(MD_RECOVERY_DONE, &mddev->recovery) ||
(mddev->safemode == 1) ||
@@ -5605,7 +5803,8 @@ void md_check_recovery(mddev_t *mddev)
if (mddev->safemode && !atomic_read(&mddev->writes_pending) &&
!mddev->in_sync && mddev->recovery_cp == MaxSector) {
mddev->in_sync = 1;
- set_bit(MD_CHANGE_CLEAN, &mddev->flags);
+ if (mddev->persistent)
+ set_bit(MD_CHANGE_CLEAN, &mddev->flags);
}
if (mddev->safemode == 1)
mddev->safemode = 0;
@@ -5637,7 +5836,7 @@ void md_check_recovery(mddev_t *mddev)
* information must be scrapped
*/
if (!mddev->degraded)
- ITERATE_RDEV(mddev,rdev,rtmp)
+ rdev_for_each(rdev, rtmp, mddev)
rdev->saved_raid_disk = -1;
mddev->recovery = 0;
@@ -5714,7 +5913,7 @@ static int md_notify_reboot(struct notifier_block *this,
printk(KERN_INFO "md: stopping all md devices.\n");
- ITERATE_MDDEV(mddev,tmp)
+ for_each_mddev(mddev, tmp)
if (mddev_trylock(mddev)) {
do_md_stop (mddev, 1);
mddev_unlock(mddev);
@@ -5848,7 +6047,7 @@ static __exit void md_exit(void)
unregister_reboot_notifier(&md_notifier);
unregister_sysctl_table(raid_table_header);
remove_proc_entry("mdstat", NULL);
- ITERATE_MDDEV(mddev,tmp) {
+ for_each_mddev(mddev, tmp) {
struct gendisk *disk = mddev->gendisk;
if (!disk)
continue;
diff --git a/drivers/md/mktables.c b/drivers/md/mktables.c
index adef299908c..b61d5767aae 100644
--- a/drivers/md/mktables.c
+++ b/drivers/md/mktables.c
@@ -1,13 +1,10 @@
-#ident "$Id: mktables.c,v 1.2 2002/12/12 22:41:27 hpa Exp $"
-/* ----------------------------------------------------------------------- *
+/* -*- linux-c -*- ------------------------------------------------------- *
*
- * Copyright 2002 H. Peter Anvin - All Rights Reserved
+ * Copyright 2002-2007 H. Peter Anvin - All Rights Reserved
*
- * 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, Inc., 53 Temple Place Ste 330,
- * Bostom MA 02111-1307, USA; either version 2 of the License, or
- * (at your option) any later version; incorporated herein by reference.
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2 or (at your
+ * option) any later version; incorporated herein by reference.
*
* ----------------------------------------------------------------------- */
@@ -26,100 +23,98 @@
static uint8_t gfmul(uint8_t a, uint8_t b)
{
- uint8_t v = 0;
-
- while ( b ) {
- if ( b & 1 ) v ^= a;
- a = (a << 1) ^ (a & 0x80 ? 0x1d : 0);
- b >>= 1;
- }
- return v;
+ uint8_t v = 0;
+
+ while (b) {
+ if (b & 1)
+ v ^= a;
+ a = (a << 1) ^ (a & 0x80 ? 0x1d : 0);
+ b >>= 1;
+ }
+
+ return v;
}
static uint8_t gfpow(uint8_t a, int b)
{
- uint8_t v = 1;
-
- b %= 255;
- if ( b < 0 )
- b += 255;
-
- while ( b ) {
- if ( b & 1 ) v = gfmul(v,a);
- a = gfmul(a,a);
- b >>= 1;
- }
- return v;
+ uint8_t v = 1;
+
+ b %= 255;
+ if (b < 0)
+ b += 255;
+
+ while (b) {
+ if (b & 1)
+ v = gfmul(v, a);
+ a = gfmul(a, a);
+ b >>= 1;
+ }
+
+ return v;
}
int main(int argc, char *argv[])
{
- int i, j, k;
- uint8_t v;
- uint8_t exptbl[256], invtbl[256];
-
- printf("#include \"raid6.h\"\n");
-
- /* Compute multiplication table */
- printf("\nconst u8 __attribute__((aligned(256)))\n"
- "raid6_gfmul[256][256] =\n"
- "{\n");
- for ( i = 0 ; i < 256 ; i++ ) {
- printf("\t{\n");
- for ( j = 0 ; j < 256 ; j += 8 ) {
- printf("\t\t");
- for ( k = 0 ; k < 8 ; k++ ) {
- printf("0x%02x, ", gfmul(i,j+k));
- }
- printf("\n");
- }
- printf("\t},\n");
- }
- printf("};\n");
-
- /* Compute power-of-2 table (exponent) */
- v = 1;
- printf("\nconst u8 __attribute__((aligned(256)))\n"
- "raid6_gfexp[256] =\n"
- "{\n");
- for ( i = 0 ; i < 256 ; i += 8 ) {
- printf("\t");
- for ( j = 0 ; j < 8 ; j++ ) {
- exptbl[i+j] = v;
- printf("0x%02x, ", v);
- v = gfmul(v,2);
- if ( v == 1 ) v = 0; /* For entry 255, not a real entry */
- }
- printf("\n");
- }
- printf("};\n");
-
- /* Compute inverse table x^-1 == x^254 */
- printf("\nconst u8 __attribute__((aligned(256)))\n"
- "raid6_gfinv[256] =\n"
- "{\n");
- for ( i = 0 ; i < 256 ; i += 8 ) {
- printf("\t");
- for ( j = 0 ; j < 8 ; j++ ) {
- invtbl[i+j] = v = gfpow(i+j,254);
- printf("0x%02x, ", v);
- }
- printf("\n");
- }
- printf("};\n");
-
- /* Compute inv(2^x + 1) (exponent-xor-inverse) table */
- printf("\nconst u8 __attribute__((aligned(256)))\n"
- "raid6_gfexi[256] =\n"
- "{\n");
- for ( i = 0 ; i < 256 ; i += 8 ) {
- printf("\t");
- for ( j = 0 ; j < 8 ; j++ ) {
- printf("0x%02x, ", invtbl[exptbl[i+j]^1]);
- }
- printf("\n");
- }
- printf("};\n\n");
-
- return 0;
+ int i, j, k;
+ uint8_t v;
+ uint8_t exptbl[256], invtbl[256];
+
+ printf("#include \"raid6.h\"\n");
+
+ /* Compute multiplication table */
+ printf("\nconst u8 __attribute__((aligned(256)))\n"
+ "raid6_gfmul[256][256] =\n"
+ "{\n");
+ for (i = 0; i < 256; i++) {
+ printf("\t{\n");
+ for (j = 0; j < 256; j += 8) {
+ printf("\t\t");
+ for (k = 0; k < 8; k++)
+ printf("0x%02x,%c", gfmul(i, j + k),
+ (k == 7) ? '\n' : ' ');
+ }
+ printf("\t},\n");
+ }
+ printf("};\n");
+
+ /* Compute power-of-2 table (exponent) */
+ v = 1;
+ printf("\nconst u8 __attribute__((aligned(256)))\n"
+ "raid6_gfexp[256] =\n" "{\n");
+ for (i = 0; i < 256; i += 8) {
+ printf("\t");
+ for (j = 0; j < 8; j++) {
+ exptbl[i + j] = v;
+ printf("0x%02x,%c", v, (j == 7) ? '\n' : ' ');
+ v = gfmul(v, 2);
+ if (v == 1)
+ v = 0; /* For entry 255, not a real entry */
+ }
+ }
+ printf("};\n");
+
+ /* Compute inverse table x^-1 == x^254 */
+ printf("\nconst u8 __attribute__((aligned(256)))\n"
+ "raid6_gfinv[256] =\n" "{\n");
+ for (i = 0; i < 256; i += 8) {
+ printf("\t");
+ for (j = 0; j < 8; j++) {
+ invtbl[i + j] = v = gfpow(i + j, 254);
+ printf("0x%02x,%c", v, (j == 7) ? '\n' : ' ');
+ }
+ }
+ printf("};\n");
+
+ /* Compute inv(2^x + 1) (exponent-xor-inverse) table */
+ printf("\nconst u8 __attribute__((aligned(256)))\n"
+ "raid6_gfexi[256] =\n" "{\n");
+ for (i = 0; i < 256; i += 8) {
+ printf("\t");
+ for (j = 0; j < 8; j++)
+ printf("0x%02x,%c", invtbl[exptbl[i + j] ^ 1],
+ (j == 7) ? '\n' : ' ');
+ }
+ printf("};\n");
+
+ return 0;
}
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index eb631ebed68..3f299d835a2 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -436,7 +436,7 @@ static int multipath_run (mddev_t *mddev)
}
conf->working_disks = 0;
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
disk_idx = rdev->raid_disk;
if (disk_idx < 0 ||
disk_idx >= mddev->raid_disks)
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index f8e591708d1..818b4828409 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -72,11 +72,11 @@ static int create_strip_zones (mddev_t *mddev)
*/
conf->nr_strip_zones = 0;
- ITERATE_RDEV(mddev,rdev1,tmp1) {
+ rdev_for_each(rdev1, tmp1, mddev) {
printk("raid0: looking at %s\n",
bdevname(rdev1->bdev,b));
c = 0;
- ITERATE_RDEV(mddev,rdev2,tmp2) {
+ rdev_for_each(rdev2, tmp2, mddev) {
printk("raid0: comparing %s(%llu)",
bdevname(rdev1->bdev,b),
(unsigned long long)rdev1->size);
@@ -124,7 +124,7 @@ static int create_strip_zones (mddev_t *mddev)
cnt = 0;
smallest = NULL;
zone->dev = conf->devlist;
- ITERATE_RDEV(mddev, rdev1, tmp1) {
+ rdev_for_each(rdev1, tmp1, mddev) {
int j = rdev1->raid_disk;
if (j < 0 || j >= mddev->raid_disks) {
@@ -293,7 +293,7 @@ static int raid0_run (mddev_t *mddev)
/* calculate array device size */
mddev->array_size = 0;
- ITERATE_RDEV(mddev,rdev,tmp)
+ rdev_for_each(rdev, tmp, mddev)
mddev->array_size += rdev->size;
printk("raid0 : md_size is %llu blocks.\n",
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 4a69c416e04..5c7fef091ce 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1684,6 +1684,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
if (!go_faster && conf->nr_waiting)
msleep_interruptible(1000);
+ bitmap_cond_end_sync(mddev->bitmap, sector_nr);
raise_barrier(conf);
conf->next_resync = sector_nr;
@@ -1766,6 +1767,8 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
return rv;
}
+ if (max_sector > mddev->resync_max)
+ max_sector = mddev->resync_max; /* Don't do IO beyond here */
nr_sectors = 0;
sync_blocks = 0;
do {
@@ -1884,7 +1887,7 @@ static int run(mddev_t *mddev)
if (!conf->r1bio_pool)
goto out_no_mem;
- ITERATE_RDEV(mddev, rdev, tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
disk_idx = rdev->raid_disk;
if (disk_idx >= mddev->raid_disks
|| disk_idx < 0)
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 5cdcc938620..017f58113c3 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1657,6 +1657,9 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
return (max_sector - sector_nr) + sectors_skipped;
}
+ if (max_sector > mddev->resync_max)
+ max_sector = mddev->resync_max; /* Don't do IO beyond here */
+
/* make sure whole request will fit in a chunk - if chunks
* are meaningful
*/
@@ -1670,6 +1673,8 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
if (!go_faster && conf->nr_waiting)
msleep_interruptible(1000);
+ bitmap_cond_end_sync(mddev->bitmap, sector_nr);
+
/* Again, very different code for resync and recovery.
* Both must result in an r10bio with a list of bios that
* have bi_end_io, bi_sector, bi_bdev set,
@@ -2021,7 +2026,7 @@ static int run(mddev_t *mddev)
goto out_free_conf;
}
- ITERATE_RDEV(mddev, rdev, tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
disk_idx = rdev->raid_disk;
if (disk_idx >= mddev->raid_disks
|| disk_idx < 0)
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index e8c8157b02f..2d6f1a51359 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -3159,7 +3159,8 @@ static void raid5_activate_delayed(raid5_conf_t *conf)
atomic_inc(&conf->preread_active_stripes);
list_add_tail(&sh->lru, &conf->handle_list);
}
- }
+ } else
+ blk_plug_device(conf->mddev->queue);
}
static void activate_bit_delay(raid5_conf_t *conf)
@@ -3549,7 +3550,8 @@ static int make_request(struct request_queue *q, struct bio * bi)
goto retry;
}
finish_wait(&conf->wait_for_overlap, &w);
- handle_stripe(sh, NULL);
+ set_bit(STRIPE_HANDLE, &sh->state);
+ clear_bit(STRIPE_DELAYED, &sh->state);
release_stripe(sh);
} else {
/* cannot get stripe for read-ahead, just give-up */
@@ -3698,6 +3700,25 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped
release_stripe(sh);
first_sector += STRIPE_SECTORS;
}
+ /* If this takes us to the resync_max point where we have to pause,
+ * then we need to write out the superblock.
+ */
+ sector_nr += conf->chunk_size>>9;
+ if (sector_nr >= mddev->resync_max) {
+ /* Cannot proceed until we've updated the superblock... */
+ wait_event(conf->wait_for_overlap,
+ atomic_read(&conf->reshape_stripes) == 0);
+ mddev->reshape_position = conf->expand_progress;
+ set_bit(MD_CHANGE_DEVS, &mddev->flags);
+ md_wakeup_thread(mddev->thread);
+ wait_event(mddev->sb_wait,
+ !test_bit(MD_CHANGE_DEVS, &mddev->flags)
+ || kthread_should_stop());
+ spin_lock_irq(&conf->device_lock);
+ conf->expand_lo = mddev->reshape_position;
+ spin_unlock_irq(&conf->device_lock);
+ wake_up(&conf->wait_for_overlap);
+ }
return conf->chunk_size>>9;
}
@@ -3734,6 +3755,12 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski
if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
return reshape_request(mddev, sector_nr, skipped);
+ /* No need to check resync_max as we never do more than one
+ * stripe, and as resync_max will always be on a chunk boundary,
+ * if the check in md_do_sync didn't fire, there is no chance
+ * of overstepping resync_max here
+ */
+
/* if there is too many failed drives and we are trying
* to resync, then assert that we are finished, because there is
* nothing we can do.
@@ -3753,6 +3780,9 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski
return sync_blocks * STRIPE_SECTORS; /* keep things rounded to whole stripes */
}
+
+ bitmap_cond_end_sync(mddev->bitmap, sector_nr);
+
pd_idx = stripe_to_pdidx(sector_nr, conf, raid_disks);
sh = get_active_stripe(conf, sector_nr, raid_disks, pd_idx, 1);
if (sh == NULL) {
@@ -3864,7 +3894,7 @@ static int retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio)
* During the scan, completed stripes are saved for us by the interrupt
* handler, so that they will not have to wait for our next wakeup.
*/
-static void raid5d (mddev_t *mddev)
+static void raid5d(mddev_t *mddev)
{
struct stripe_head *sh;
raid5_conf_t *conf = mddev_to_conf(mddev);
@@ -3889,12 +3919,6 @@ static void raid5d (mddev_t *mddev)
activate_bit_delay(conf);
}
- if (list_empty(&conf->handle_list) &&
- atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD &&
- !blk_queue_plugged(mddev->queue) &&
- !list_empty(&conf->delayed_list))
- raid5_activate_delayed(conf);
-
while ((bio = remove_bio_from_retry(conf))) {
int ok;
spin_unlock_irq(&conf->device_lock);
@@ -4108,7 +4132,7 @@ static int run(mddev_t *mddev)
pr_debug("raid5: run(%s) called.\n", mdname(mddev));
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
raid_disk = rdev->raid_disk;
if (raid_disk >= conf->raid_disks
|| raid_disk < 0)
@@ -4521,7 +4545,7 @@ static int raid5_start_reshape(mddev_t *mddev)
if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
return -EBUSY;
- ITERATE_RDEV(mddev, rdev, rtmp)
+ rdev_for_each(rdev, rtmp, mddev)
if (rdev->raid_disk < 0 &&
!test_bit(Faulty, &rdev->flags))
spares++;
@@ -4543,7 +4567,7 @@ static int raid5_start_reshape(mddev_t *mddev)
/* Add some new drives, as many as will fit.
* We know there are enough to make the newly sized array work.
*/
- ITERATE_RDEV(mddev, rdev, rtmp)
+ rdev_for_each(rdev, rtmp, mddev)
if (rdev->raid_disk < 0 &&
!test_bit(Faulty, &rdev->flags)) {
if (raid5_add_disk(mddev, rdev)) {
diff --git a/drivers/md/raid6test/test.c b/drivers/md/raid6test/test.c
index 0d5cd57accd..559cc41b258 100644
--- a/drivers/md/raid6test/test.c
+++ b/drivers/md/raid6test/test.c
@@ -1,12 +1,10 @@
/* -*- linux-c -*- ------------------------------------------------------- *
*
- * Copyright 2002 H. Peter Anvin - All Rights Reserved
+ * Copyright 2002-2007 H. Peter Anvin - All Rights Reserved
*
- * 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, Inc., 53 Temple Place Ste 330,
- * Bostom MA 02111-1307, USA; either version 2 of the License, or
- * (at your option) any later version; incorporated herein by reference.
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2 or (at your
+ * option) any later version; incorporated herein by reference.
*
* ----------------------------------------------------------------------- */
@@ -30,67 +28,87 @@ char *dataptrs[NDISKS];
char data[NDISKS][PAGE_SIZE];
char recovi[PAGE_SIZE], recovj[PAGE_SIZE];
-void makedata(void)
+static void makedata(void)
{
int i, j;
- for ( i = 0 ; i < NDISKS ; i++ ) {
- for ( j = 0 ; j < PAGE_SIZE ; j++ ) {
+ for (i = 0; i < NDISKS; i++) {
+ for (j = 0; j < PAGE_SIZE; j++)
data[i][j] = rand();
- }
+
dataptrs[i] = data[i];
}
}
+static char disk_type(int d)
+{
+ switch (d) {
+ case NDISKS-2:
+ return 'P';
+ case NDISKS-1:
+ return 'Q';
+ default:
+ return 'D';
+ }
+}
+
+static int test_disks(int i, int j)
+{
+ int erra, errb;
+
+ memset(recovi, 0xf0, PAGE_SIZE);
+ memset(recovj, 0xba, PAGE_SIZE);
+
+ dataptrs[i] = recovi;
+ dataptrs[j] = recovj;
+
+ raid6_dual_recov(NDISKS, PAGE_SIZE, i, j, (void **)&dataptrs);
+
+ erra = memcmp(data[i], recovi, PAGE_SIZE);
+ errb = memcmp(data[j], recovj, PAGE_SIZE);
+
+ if (i < NDISKS-2 && j == NDISKS-1) {
+ /* We don't implement the DQ failure scenario, since it's
+ equivalent to a RAID-5 failure (XOR, then recompute Q) */
+ erra = errb = 0;
+ } else {
+ printf("algo=%-8s faila=%3d(%c) failb=%3d(%c) %s\n",
+ raid6_call.name,
+ i, disk_type(i),
+ j, disk_type(j),
+ (!erra && !errb) ? "OK" :
+ !erra ? "ERRB" :
+ !errb ? "ERRA" : "ERRAB");
+ }
+
+ dataptrs[i] = data[i];
+ dataptrs[j] = data[j];
+
+ return erra || errb;
+}
+
int main(int argc, char *argv[])
{
- const struct raid6_calls * const * algo;
+ const struct raid6_calls *const *algo;
int i, j;
- int erra, errb;
+ int err = 0;
makedata();
- for ( algo = raid6_algos ; *algo ; algo++ ) {
- if ( !(*algo)->valid || (*algo)->valid() ) {
+ for (algo = raid6_algos; *algo; algo++) {
+ if (!(*algo)->valid || (*algo)->valid()) {
raid6_call = **algo;
/* Nuke syndromes */
memset(data[NDISKS-2], 0xee, 2*PAGE_SIZE);
/* Generate assumed good syndrome */
- raid6_call.gen_syndrome(NDISKS, PAGE_SIZE, (void **)&dataptrs);
-
- for ( i = 0 ; i < NDISKS-1 ; i++ ) {
- for ( j = i+1 ; j < NDISKS ; j++ ) {
- memset(recovi, 0xf0, PAGE_SIZE);
- memset(recovj, 0xba, PAGE_SIZE);
-
- dataptrs[i] = recovi;
- dataptrs[j] = recovj;
-
- raid6_dual_recov(NDISKS, PAGE_SIZE, i, j, (void **)&dataptrs);
-
- erra = memcmp(data[i], recovi, PAGE_SIZE);
- errb = memcmp(data[j], recovj, PAGE_SIZE);
-
- if ( i < NDISKS-2 && j == NDISKS-1 ) {
- /* We don't implement the DQ failure scenario, since it's
- equivalent to a RAID-5 failure (XOR, then recompute Q) */
- } else {
- printf("algo=%-8s faila=%3d(%c) failb=%3d(%c) %s\n",
- raid6_call.name,
- i, (i==NDISKS-2)?'P':'D',
- j, (j==NDISKS-1)?'Q':(j==NDISKS-2)?'P':'D',
- (!erra && !errb) ? "OK" :
- !erra ? "ERRB" :
- !errb ? "ERRA" :
- "ERRAB");
- }
-
- dataptrs[i] = data[i];
- dataptrs[j] = data[j];
- }
- }
+ raid6_call.gen_syndrome(NDISKS, PAGE_SIZE,
+ (void **)&dataptrs);
+
+ for (i = 0; i < NDISKS-1; i++)
+ for (j = i+1; j < NDISKS; j++)
+ err += test_disks(i, j);
}
printf("\n");
}
@@ -99,5 +117,8 @@ int main(int argc, char *argv[])
/* Pick the best algorithm test */
raid6_select_algo();
- return 0;
+ if (err)
+ printf("\n*** ERRORS FOUND ***\n");
+
+ return err;
}
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 28ddd146c1c..850b8c6f457 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -22,7 +22,6 @@ 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
-obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c
deleted file mode 100644
index 9fa5b702e07..00000000000
--- a/drivers/media/video/tvmixer.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/videodev.h>
-#include <linux/init.h>
-#include <linux/kdev_t.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-
-#include <asm/semaphore.h>
-#include <asm/uaccess.h>
-
-
-#define DEV_MAX 4
-
-static int devnr = -1;
-module_param(devnr, int, 0644);
-
-MODULE_AUTHOR("Gerd Knorr");
-MODULE_LICENSE("GPL");
-
-/* ----------------------------------------------------------------------- */
-
-struct TVMIXER {
- struct i2c_client *dev;
- int minor;
- int count;
-};
-
-static struct TVMIXER devices[DEV_MAX];
-
-static int tvmixer_adapters(struct i2c_adapter *adap);
-static int tvmixer_clients(struct i2c_client *client);
-
-/* ----------------------------------------------------------------------- */
-
-static int mix_to_v4l(int i)
-{
- int r;
-
- r = ((i & 0xff) * 65536 + 50) / 100;
- if (r > 65535) r = 65535;
- if (r < 0) r = 0;
- return r;
-}
-
-static int v4l_to_mix(int i)
-{
- int r;
-
- r = (i * 100 + 32768) / 65536;
- if (r > 100) r = 100;
- if (r < 0) r = 0;
- return r | (r << 8);
-}
-
-static int v4l_to_mix2(int l, int r)
-{
- r = (r * 100 + 32768) / 65536;
- if (r > 100) r = 100;
- if (r < 0) r = 0;
- l = (l * 100 + 32768) / 65536;
- if (l > 100) l = 100;
- if (l < 0) l = 0;
- return (r << 8) | l;
-}
-
-static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct video_audio va;
- int left,right,ret,val = 0;
- struct TVMIXER *mix = file->private_data;
- struct i2c_client *client = mix->dev;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- if (NULL == client)
- return -ENODEV;
-
- if (cmd == SOUND_MIXER_INFO) {
- mixer_info info;
- strlcpy(info.id, "tv card", sizeof(info.id));
- strlcpy(info.name, client->name, sizeof(info.name));
- info.modify_counter = 42 /* FIXME */;
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == SOUND_OLD_MIXER_INFO) {
- _old_mixer_info info;
- strlcpy(info.id, "tv card", sizeof(info.id));
- strlcpy(info.name, client->name, sizeof(info.name));
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, p);
-
- if (_SIOC_DIR(cmd) & _SIOC_WRITE)
- if (get_user(val, p))
- return -EFAULT;
-
- /* read state */
- memset(&va,0,sizeof(va));
- client->driver->command(client,VIDIOCGAUDIO,&va);
-
- switch (cmd) {
- case MIXER_READ(SOUND_MIXER_RECMASK):
- case MIXER_READ(SOUND_MIXER_CAPS):
- case MIXER_READ(SOUND_MIXER_RECSRC):
- case MIXER_WRITE(SOUND_MIXER_RECSRC):
- ret = 0;
- break;
-
- case MIXER_READ(SOUND_MIXER_STEREODEVS):
- ret = SOUND_MASK_VOLUME;
- break;
- case MIXER_READ(SOUND_MIXER_DEVMASK):
- ret = SOUND_MASK_VOLUME;
- if (va.flags & VIDEO_AUDIO_BASS)
- ret |= SOUND_MASK_BASS;
- if (va.flags & VIDEO_AUDIO_TREBLE)
- ret |= SOUND_MASK_TREBLE;
- break;
-
- case MIXER_WRITE(SOUND_MIXER_VOLUME):
- left = mix_to_v4l(val);
- right = mix_to_v4l(val >> 8);
- va.volume = max(left,right);
- va.balance = (32768*min(left,right)) / (va.volume ? va.volume : 1);
- va.balance = (left<right) ? (65535-va.balance) : va.balance;
- if (va.volume)
- va.flags &= ~VIDEO_AUDIO_MUTE;
- client->driver->command(client,VIDIOCSAUDIO,&va);
- client->driver->command(client,VIDIOCGAUDIO,&va);
- /* fall throuth */
- case MIXER_READ(SOUND_MIXER_VOLUME):
- left = (min(65536 - va.balance,32768) *
- va.volume) / 32768;
- right = (min(va.balance,(u16)32768) *
- va.volume) / 32768;
- ret = v4l_to_mix2(left,right);
- break;
-
- case MIXER_WRITE(SOUND_MIXER_BASS):
- va.bass = mix_to_v4l(val);
- client->driver->command(client,VIDIOCSAUDIO,&va);
- client->driver->command(client,VIDIOCGAUDIO,&va);
- /* fall throuth */
- case MIXER_READ(SOUND_MIXER_BASS):
- ret = v4l_to_mix(va.bass);
- break;
-
- case MIXER_WRITE(SOUND_MIXER_TREBLE):
- va.treble = mix_to_v4l(val);
- client->driver->command(client,VIDIOCSAUDIO,&va);
- client->driver->command(client,VIDIOCGAUDIO,&va);
- /* fall throuth */
- case MIXER_READ(SOUND_MIXER_TREBLE):
- ret = v4l_to_mix(va.treble);
- break;
-
- default:
- return -EINVAL;
- }
- if (put_user(ret, p))
- return -EFAULT;
- return 0;
-}
-
-static int tvmixer_open(struct inode *inode, struct file *file)
-{
- int i, minor = iminor(inode);
- struct TVMIXER *mix = NULL;
- struct i2c_client *client = NULL;
-
- for (i = 0; i < DEV_MAX; i++) {
- if (devices[i].minor == minor) {
- mix = devices+i;
- client = mix->dev;
- break;
- }
- }
-
- if (NULL == client)
- return -ENODEV;
-
- /* lock bttv in memory while the mixer is in use */
- file->private_data = mix;
- if (client->adapter->owner)
- try_module_get(client->adapter->owner);
- return 0;
-}
-
-static int tvmixer_release(struct inode *inode, struct file *file)
-{
- struct TVMIXER *mix = file->private_data;
- struct i2c_client *client;
-
- client = mix->dev;
- if (NULL == client) {
- return -ENODEV;
- }
-
- module_put(client->adapter->owner);
- return 0;
-}
-
-static struct i2c_driver driver = {
- .driver = {
- .name = "tvmixer",
- },
- .id = I2C_DRIVERID_TVMIXER,
- .detach_adapter = tvmixer_adapters,
- .attach_adapter = tvmixer_adapters,
- .detach_client = tvmixer_clients,
-};
-
-static const struct file_operations tvmixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = tvmixer_ioctl,
- .open = tvmixer_open,
- .release = tvmixer_release,
-};
-
-/* ----------------------------------------------------------------------- */
-
-static int tvmixer_adapters(struct i2c_adapter *adap)
-{
- struct i2c_client *client;
-
- list_for_each_entry(client, &adap->clients, list)
- tvmixer_clients(client);
- return 0;
-}
-
-static int tvmixer_clients(struct i2c_client *client)
-{
- struct video_audio va;
- int i,minor;
-
- if (!(client->adapter->class & I2C_CLASS_TV_ANALOG))
- return -1;
-
- /* unregister ?? */
- for (i = 0; i < DEV_MAX; i++) {
- if (devices[i].dev == client) {
- /* unregister */
- unregister_sound_mixer(devices[i].minor);
- devices[i].dev = NULL;
- devices[i].minor = -1;
- printk("tvmixer: %s unregistered (#1)\n",
- client->name);
- return 0;
- }
- }
-
- /* look for a free slot */
- for (i = 0; i < DEV_MAX; i++)
- if (NULL == devices[i].dev)
- break;
- if (i == DEV_MAX) {
- printk(KERN_WARNING "tvmixer: DEV_MAX too small\n");
- return -1;
- }
-
- /* audio chip with mixer ??? */
- if (NULL == client->driver->command)
- return -1;
- memset(&va,0,sizeof(va));
- if (0 != client->driver->command(client,VIDIOCGAUDIO,&va))
- return -1;
- if (0 == (va.flags & VIDEO_AUDIO_VOLUME))
- return -1;
-
- /* everything is fine, register */
- if ((minor = register_sound_mixer(&tvmixer_fops,devnr)) < 0) {
- printk(KERN_ERR "tvmixer: cannot allocate mixer device\n");
- return -1;
- }
-
- devices[i].minor = minor;
- devices[i].count = 0;
- devices[i].dev = client;
- printk("tvmixer: %s (%s) registered with minor %d\n",
- client->name,client->adapter->name,minor);
-
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int __init tvmixer_init_module(void)
-{
- int i;
-
- for (i = 0; i < DEV_MAX; i++)
- devices[i].minor = -1;
-
- return i2c_add_driver(&driver);
-}
-
-static void __exit tvmixer_cleanup_module(void)
-{
- int i;
-
- i2c_del_driver(&driver);
- for (i = 0; i < DEV_MAX; i++) {
- if (devices[i].minor != -1) {
- unregister_sound_mixer(devices[i].minor);
- printk("tvmixer: %s unregistered (#2)\n",
- devices[i].dev->name);
- }
- }
-}
-
-module_init(tvmixer_init_module);
-module_exit(tvmixer_cleanup_module);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c
index 7dce318df1b..0846c33296b 100644
--- a/drivers/misc/asus-laptop.c
+++ b/drivers/misc/asus-laptop.c
@@ -33,7 +33,6 @@
* Sam Lin - GPS support
*/
-#include <linux/autoconf.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
diff --git a/drivers/misc/fujitsu-laptop.c b/drivers/misc/fujitsu-laptop.c
index c8d62c268b1..1cfd7f3f129 100644
--- a/drivers/misc/fujitsu-laptop.c
+++ b/drivers/misc/fujitsu-laptop.c
@@ -50,7 +50,6 @@
#include <linux/dmi.h>
#include <linux/backlight.h>
#include <linux/platform_device.h>
-#include <linux/autoconf.h>
#define FUJITSU_DRIVER_VERSION "0.3"
diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c
index 552b7957a92..c884730c5ea 100644
--- a/drivers/misc/lkdtm.c
+++ b/drivers/misc/lkdtm.c
@@ -129,27 +129,28 @@ module_param(cpoint_count, int, 0644);
MODULE_PARM_DESC(cpoint_count, " Crash Point Count, number of times the "\
"crash point is to be hit to trigger action");
-unsigned int jp_do_irq(unsigned int irq)
+static unsigned int jp_do_irq(unsigned int irq)
{
lkdtm_handler();
jprobe_return();
return 0;
}
-irqreturn_t jp_handle_irq_event(unsigned int irq, struct irqaction *action)
+static irqreturn_t jp_handle_irq_event(unsigned int irq,
+ struct irqaction *action)
{
lkdtm_handler();
jprobe_return();
return 0;
}
-void jp_tasklet_action(struct softirq_action *a)
+static void jp_tasklet_action(struct softirq_action *a)
{
lkdtm_handler();
jprobe_return();
}
-void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[])
+static void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[])
{
lkdtm_handler();
jprobe_return();
@@ -157,23 +158,24 @@ void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[])
struct scan_control;
-unsigned long jp_shrink_inactive_list(unsigned long max_scan,
- struct zone *zone, struct scan_control *sc)
+static unsigned long jp_shrink_inactive_list(unsigned long max_scan,
+ struct zone *zone,
+ struct scan_control *sc)
{
lkdtm_handler();
jprobe_return();
return 0;
}
-int jp_hrtimer_start(struct hrtimer *timer, ktime_t tim,
- const enum hrtimer_mode mode)
+static int jp_hrtimer_start(struct hrtimer *timer, ktime_t tim,
+ const enum hrtimer_mode mode)
{
lkdtm_handler();
jprobe_return();
return 0;
}
-int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd)
+static int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd)
{
lkdtm_handler();
jprobe_return();
@@ -270,7 +272,7 @@ void lkdtm_handler(void)
}
}
-int lkdtm_module_init(void)
+static int __init lkdtm_module_init(void)
{
int ret;
@@ -331,7 +333,7 @@ int lkdtm_module_init(void)
return 0;
}
-void lkdtm_module_exit(void)
+static void __exit lkdtm_module_exit(void)
{
unregister_jprobe(&lkdtm);
printk(KERN_INFO "lkdtm : Crash point unregistered\n");
diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c
index 83679c76292..de898c6938f 100644
--- a/drivers/misc/msi-laptop.c
+++ b/drivers/misc/msi-laptop.c
@@ -58,7 +58,6 @@
#include <linux/dmi.h>
#include <linux/backlight.h>
#include <linux/platform_device.h>
-#include <linux/autoconf.h>
#define MSI_DRIVER_VERSION "0.5"
diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c
index cd221fd0fb9..7fa61e907e1 100644
--- a/drivers/misc/phantom.c
+++ b/drivers/misc/phantom.c
@@ -25,7 +25,7 @@
#include <asm/atomic.h>
#include <asm/io.h>
-#define PHANTOM_VERSION "n0.9.7"
+#define PHANTOM_VERSION "n0.9.8"
#define PHANTOM_MAX_MINORS 8
@@ -456,8 +456,9 @@ static int phantom_resume(struct pci_dev *pdev)
#endif
static struct pci_device_id phantom_pci_tbl[] __devinitdata = {
- { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
- .class = PCI_CLASS_BRIDGE_OTHER << 8, .class_mask = 0xffff00 },
+ { .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9050,
+ .subvendor = PCI_VENDOR_ID_PLX, .subdevice = PCI_DEVICE_ID_PLX_9050,
+ .class = PCI_CLASS_BRIDGE_OTHER << 8, .class_mask = 0xffff00 },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, phantom_pci_tbl);
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index be4b9948c76..eeaaa9dce6e 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -4,7 +4,7 @@
* block2mtd.c - create an mtd from a block device
*
* Copyright (C) 2001,2002 Simon Evans <spse@secret.org.uk>
- * Copyright (C) 2004-2006 Jörn Engel <joern@wh.fh-wedel.de>
+ * Copyright (C) 2004-2006 Joern Engel <joern@wh.fh-wedel.de>
*
* Licence: GPL
*/
@@ -485,5 +485,5 @@ module_init(block2mtd_init);
module_exit(block2mtd_exit);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Simon Evans <spse@secret.org.uk> and others");
+MODULE_AUTHOR("Joern Engel <joern@lazybastard.org>");
MODULE_DESCRIPTION("Emulate an MTD using a block device");
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
index 56cc1ca7ffd..180298b92a7 100644
--- a/drivers/mtd/devices/phram.c
+++ b/drivers/mtd/devices/phram.c
@@ -2,7 +2,7 @@
* $Id: phram.c,v 1.16 2005/11/07 11:14:25 gleixner Exp $
*
* Copyright (c) ???? Jochen Schäuble <psionic@psionic.de>
- * Copyright (c) 2003-2004 Jörn Engel <joern@wh.fh-wedel.de>
+ * Copyright (c) 2003-2004 Joern Engel <joern@wh.fh-wedel.de>
*
* Usage:
*
@@ -299,5 +299,5 @@ module_init(init_phram);
module_exit(cleanup_phram);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jörn Engel <joern@wh.fh-wedel.de>");
+MODULE_AUTHOR("Joern Engel <joern@wh.fh-wedel.de>");
MODULE_DESCRIPTION("MTD driver for physical RAM");
diff --git a/drivers/mtd/maps/mtx-1_flash.c b/drivers/mtd/maps/mtx-1_flash.c
index d884f2be28f..2a8fde9b92f 100644
--- a/drivers/mtd/maps/mtx-1_flash.c
+++ b/drivers/mtd/maps/mtx-1_flash.c
@@ -4,7 +4,7 @@
* $Id: mtx-1_flash.c,v 1.2 2005/11/07 11:14:27 gleixner Exp $
*
* (C) 2005 Bruno Randolf <bruno.randolf@4g-systems.biz>
- * (C) 2005 Jörn Engel <joern@wohnheim.fh-wedel.de>
+ * (C) 2005 Joern Engel <joern@wohnheim.fh-wedel.de>
*
*/
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index e9743d3efaf..238628d3a85 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -1540,6 +1540,38 @@ static void __devinit detect_and_report_smsc (void)
smsc_check(0x3f0,0x44);
smsc_check(0x370,0x44);
}
+
+static void __devinit detect_and_report_it87(void)
+{
+ u16 dev;
+ u8 r;
+ if (verbose_probing)
+ printk(KERN_DEBUG "IT8705 Super-IO detection, now testing port 2E ...\n");
+ if (!request_region(0x2e, 1, __FUNCTION__))
+ return;
+ outb(0x87, 0x2e);
+ outb(0x01, 0x2e);
+ outb(0x55, 0x2e);
+ outb(0x55, 0x2e);
+ outb(0x20, 0x2e);
+ dev = inb(0x2f) << 8;
+ outb(0x21, 0x2e);
+ dev |= inb(0x2f);
+ if (dev == 0x8712 || dev == 0x8705 || dev == 0x8715 ||
+ dev == 0x8716 || dev == 0x8718 || dev == 0x8726) {
+ printk(KERN_INFO "IT%04X SuperIO detected.\n", dev);
+ outb(0x07, 0x2E); /* Parallel Port */
+ outb(0x03, 0x2F);
+ outb(0xF0, 0x2E); /* BOOT 0x80 off */
+ r = inb(0x2f);
+ outb(0xF0, 0x2E);
+ outb(r | 8, 0x2F);
+ outb(0x02, 0x2E); /* Lock */
+ outb(0x02, 0x2F);
+
+ release_region(0x2e, 1);
+ }
+}
#endif /* CONFIG_PARPORT_PC_SUPERIO */
static int get_superio_dma (struct parport *p)
@@ -2767,6 +2799,7 @@ enum parport_pc_pci_cards {
netmos_9755,
netmos_9805,
netmos_9815,
+ quatech_sppxp100,
};
@@ -2843,6 +2876,7 @@ static struct parport_pc_pci {
/* netmos_9755 */ { 2, { { 0, 1 }, { 2, 3 },} }, /* untested */
/* netmos_9805 */ { 1, { { 0, -1 }, } }, /* untested */
/* netmos_9815 */ { 2, { { 0, -1 }, { 2, -1 }, } }, /* untested */
+ /* quatech_sppxp100 */ { 1, { { 0, 1 }, } },
};
static const struct pci_device_id parport_pc_pci_tbl[] = {
@@ -2926,6 +2960,9 @@ static const struct pci_device_id parport_pc_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9805 },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9815,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9815 },
+ /* Quatech SPPXP-100 Parallel port PCI ExpressCard */
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SPPXP_100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, quatech_sppxp100 },
{ 0, } /* terminate list */
};
MODULE_DEVICE_TABLE(pci,parport_pc_pci_tbl);
@@ -3159,24 +3196,25 @@ static void __init parport_pc_find_ports (int autoirq, int autodma)
int count = 0, err;
#ifdef CONFIG_PARPORT_PC_SUPERIO
- detect_and_report_winbond ();
- detect_and_report_smsc ();
+ detect_and_report_it87();
+ detect_and_report_winbond();
+ detect_and_report_smsc();
#endif
/* Onboard SuperIO chipsets that show themselves on the PCI bus. */
- count += parport_pc_init_superio (autoirq, autodma);
+ count += parport_pc_init_superio(autoirq, autodma);
/* PnP ports, skip detection if SuperIO already found them */
if (!count) {
- err = pnp_register_driver (&parport_pc_pnp_driver);
+ err = pnp_register_driver(&parport_pc_pnp_driver);
if (!err)
pnp_registered_parport = 1;
}
/* ISA ports and whatever (see asm/parport.h). */
- parport_pc_find_nonpci_ports (autoirq, autodma);
+ parport_pc_find_nonpci_ports(autoirq, autodma);
- err = pci_register_driver (&parport_pc_pci_driver);
+ err = pci_register_driver(&parport_pc_pci_driver);
if (!err)
pci_registered_parport = 1;
}
diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c
index bd6ad8b3816..e2e95b36a60 100644
--- a/drivers/parport/parport_serial.c
+++ b/drivers/parport/parport_serial.c
@@ -77,7 +77,7 @@ static struct parport_pc_pci cards[] __devinitdata = {
/* titan_110l */ { 1, { { 3, -1 }, } },
/* titan_210l */ { 1, { { 3, -1 }, } },
/* netmos_9xx5_combo */ { 1, { { 2, -1 }, }, netmos_parallel_init },
- /* netmos_9855 */ { 1, { { 0, -1 }, }, netmos_parallel_init },
+ /* netmos_9855 */ { 1, { { 2, -1 }, }, netmos_parallel_init },
/* avlab_1s1p */ { 1, { { 1, 2}, } },
/* avlab_1s2p */ { 2, { { 1, 2}, { 3, 4 },} },
/* avlab_2s1p */ { 1, { { 2, 3}, } },
@@ -185,7 +185,7 @@ static struct pciserial_board pci_parport_serial_boards[] __devinitdata = {
.uart_offset = 8,
},
[netmos_9855] = {
- .flags = FL_BASE2 | FL_BASE_BARS,
+ .flags = FL_BASE4 | FL_BASE_BARS,
.num_ports = 1,
.base_baud = 115200,
.uart_offset = 8,
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index 91b2dc956be..8ed26480371 100644
--- a/drivers/pci/dmar.c
+++ b/drivers/pci/dmar.c
@@ -26,6 +26,7 @@
#include <linux/pci.h>
#include <linux/dmar.h>
#include "iova.h"
+#include "intel-iommu.h"
#undef PREFIX
#define PREFIX "DMAR:"
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index 4e01df99681..31fa6c92aa5 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -1088,7 +1088,7 @@ static void dmar_init_reserved_ranges(void)
int i;
u64 addr, size;
- init_iova_domain(&reserved_iova_list);
+ init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
/* IOAPIC ranges shouldn't be accessed by DMA */
iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
@@ -1142,7 +1142,7 @@ static int domain_init(struct dmar_domain *domain, int guest_width)
int adjust_width, agaw;
unsigned long sagaw;
- init_iova_domain(&domain->iovad);
+ init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
spin_lock_init(&domain->mapping_lock);
domain_reserve_special_ranges(domain);
diff --git a/drivers/pci/intel-iommu.h b/drivers/pci/intel-iommu.h
index 459ad1f9dc5..0e4862675ad 100644
--- a/drivers/pci/intel-iommu.h
+++ b/drivers/pci/intel-iommu.h
@@ -23,10 +23,24 @@
#include <linux/types.h>
#include <linux/msi.h>
+#include <linux/sysdev.h>
#include "iova.h"
#include <linux/io.h>
/*
+ * We need a fixed PAGE_SIZE of 4K irrespective of
+ * arch PAGE_SIZE for IOMMU page tables.
+ */
+#define PAGE_SHIFT_4K (12)
+#define PAGE_SIZE_4K (1UL << PAGE_SHIFT_4K)
+#define PAGE_MASK_4K (((u64)-1) << PAGE_SHIFT_4K)
+#define PAGE_ALIGN_4K(addr) (((addr) + PAGE_SIZE_4K - 1) & PAGE_MASK_4K)
+
+#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT_4K)
+#define DMA_32BIT_PFN IOVA_PFN(DMA_32BIT_MASK)
+#define DMA_64BIT_PFN IOVA_PFN(DMA_64BIT_MASK)
+
+/*
* Intel IOMMU register specification per version 1.0 public spec.
*/
diff --git a/drivers/pci/iova.c b/drivers/pci/iova.c
index a84571c2936..8de7ab6c6d0 100644
--- a/drivers/pci/iova.c
+++ b/drivers/pci/iova.c
@@ -9,19 +9,19 @@
#include "iova.h"
void
-init_iova_domain(struct iova_domain *iovad)
+init_iova_domain(struct iova_domain *iovad, unsigned long pfn_32bit)
{
spin_lock_init(&iovad->iova_alloc_lock);
spin_lock_init(&iovad->iova_rbtree_lock);
iovad->rbroot = RB_ROOT;
iovad->cached32_node = NULL;
-
+ iovad->dma_32bit_pfn = pfn_32bit;
}
static struct rb_node *
__get_cached_rbnode(struct iova_domain *iovad, unsigned long *limit_pfn)
{
- if ((*limit_pfn != DMA_32BIT_PFN) ||
+ if ((*limit_pfn != iovad->dma_32bit_pfn) ||
(iovad->cached32_node == NULL))
return rb_last(&iovad->rbroot);
else {
@@ -37,7 +37,7 @@ static void
__cached_rbnode_insert_update(struct iova_domain *iovad,
unsigned long limit_pfn, struct iova *new)
{
- if (limit_pfn != DMA_32BIT_PFN)
+ if (limit_pfn != iovad->dma_32bit_pfn)
return;
iovad->cached32_node = &new->node;
}
diff --git a/drivers/pci/iova.h b/drivers/pci/iova.h
index ae3028d5a94..d521b5b7319 100644
--- a/drivers/pci/iova.h
+++ b/drivers/pci/iova.h
@@ -15,22 +15,9 @@
#include <linux/rbtree.h>
#include <linux/dma-mapping.h>
-/*
- * We need a fixed PAGE_SIZE of 4K irrespective of
- * arch PAGE_SIZE for IOMMU page tables.
- */
-#define PAGE_SHIFT_4K (12)
-#define PAGE_SIZE_4K (1UL << PAGE_SHIFT_4K)
-#define PAGE_MASK_4K (((u64)-1) << PAGE_SHIFT_4K)
-#define PAGE_ALIGN_4K(addr) (((addr) + PAGE_SIZE_4K - 1) & PAGE_MASK_4K)
-
/* IO virtual address start page frame number */
#define IOVA_START_PFN (1)
-#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT_4K)
-#define DMA_32BIT_PFN IOVA_PFN(DMA_32BIT_MASK)
-#define DMA_64BIT_PFN IOVA_PFN(DMA_64BIT_MASK)
-
/* iova structure */
struct iova {
struct rb_node node;
@@ -44,6 +31,7 @@ struct iova_domain {
spinlock_t iova_rbtree_lock; /* Lock to protect update of rbtree */
struct rb_root rbroot; /* iova domain rbtree root */
struct rb_node *cached32_node; /* Save last alloced node */
+ unsigned long dma_32bit_pfn;
};
struct iova *alloc_iova_mem(void);
@@ -56,7 +44,7 @@ struct iova *alloc_iova(struct iova_domain *iovad, unsigned long size,
struct iova *reserve_iova(struct iova_domain *iovad, unsigned long pfn_lo,
unsigned long pfn_hi);
void copy_reserved_iova(struct iova_domain *from, struct iova_domain *to);
-void init_iova_domain(struct iova_domain *iovad);
+void init_iova_domain(struct iova_domain *iovad, unsigned long pfn_32bit);
struct iova *find_iova(struct iova_domain *iovad, unsigned long pfn);
void put_iova_domain(struct iova_domain *iovad);
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
index a262762c5b8..12a1645a2e4 100644
--- a/drivers/pnp/driver.c
+++ b/drivers/pnp/driver.c
@@ -161,8 +161,7 @@ static int pnp_bus_suspend(struct device *dev, pm_message_t state)
return error;
}
- if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE) &&
- pnp_can_disable(pnp_dev)) {
+ if (pnp_can_disable(pnp_dev)) {
error = pnp_stop_dev(pnp_dev);
if (error)
return error;
@@ -185,14 +184,17 @@ static int pnp_bus_resume(struct device *dev)
if (pnp_dev->protocol && pnp_dev->protocol->resume)
pnp_dev->protocol->resume(pnp_dev);
- if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE)) {
+ if (pnp_can_write(pnp_dev)) {
error = pnp_start_dev(pnp_dev);
if (error)
return error;
}
- if (pnp_drv->resume)
- return pnp_drv->resume(pnp_dev);
+ if (pnp_drv->resume) {
+ error = pnp_drv->resume(pnp_dev);
+ if (error)
+ return error;
+ }
return 0;
}
diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c
index 31548044fdd..982658477a5 100644
--- a/drivers/pnp/interface.c
+++ b/drivers/pnp/interface.c
@@ -10,9 +10,12 @@
#include <linux/errno.h>
#include <linux/list.h>
#include <linux/types.h>
+#include <linux/pnp.h>
#include <linux/stat.h>
#include <linux/ctype.h>
#include <linux/slab.h>
+#include <linux/mutex.h>
+
#include <asm/uaccess.h>
#include "base.h"
@@ -315,8 +318,6 @@ static ssize_t pnp_show_current_resources(struct device *dmdev,
return ret;
}
-extern struct semaphore pnp_res_mutex;
-
static ssize_t
pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
const char *ubuf, size_t count)
@@ -361,10 +362,10 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
goto done;
}
if (!strnicmp(buf, "get", 3)) {
- down(&pnp_res_mutex);
+ mutex_lock(&pnp_res_mutex);
if (pnp_can_read(dev))
dev->protocol->get(dev, &dev->res);
- up(&pnp_res_mutex);
+ mutex_unlock(&pnp_res_mutex);
goto done;
}
if (!strnicmp(buf, "set", 3)) {
@@ -373,7 +374,7 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
goto done;
buf += 3;
pnp_init_resource_table(&dev->res);
- down(&pnp_res_mutex);
+ mutex_lock(&pnp_res_mutex);
while (1) {
while (isspace(*buf))
++buf;
@@ -455,7 +456,7 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
}
break;
}
- up(&pnp_res_mutex);
+ mutex_unlock(&pnp_res_mutex);
goto done;
}
diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c
index c6b3d4e63cc..c28caf272c1 100644
--- a/drivers/pnp/manager.c
+++ b/drivers/pnp/manager.c
@@ -12,9 +12,10 @@
#include <linux/pnp.h>
#include <linux/slab.h>
#include <linux/bitmap.h>
+#include <linux/mutex.h>
#include "base.h"
-DECLARE_MUTEX(pnp_res_mutex);
+DEFINE_MUTEX(pnp_res_mutex);
static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
{
@@ -297,7 +298,7 @@ static int pnp_assign_resources(struct pnp_dev *dev, int depnum)
if (!pnp_can_configure(dev))
return -ENODEV;
- down(&pnp_res_mutex);
+ mutex_lock(&pnp_res_mutex);
pnp_clean_resource_table(&dev->res); /* start with a fresh slate */
if (dev->independent) {
port = dev->independent->port;
@@ -366,12 +367,12 @@ static int pnp_assign_resources(struct pnp_dev *dev, int depnum)
} else if (dev->dependent)
goto fail;
- up(&pnp_res_mutex);
+ mutex_unlock(&pnp_res_mutex);
return 1;
fail:
pnp_clean_resource_table(&dev->res);
- up(&pnp_res_mutex);
+ mutex_unlock(&pnp_res_mutex);
return 0;
}
@@ -396,7 +397,7 @@ int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res,
return -ENOMEM;
*bak = dev->res;
- down(&pnp_res_mutex);
+ mutex_lock(&pnp_res_mutex);
dev->res = *res;
if (!(mode & PNP_CONFIG_FORCE)) {
for (i = 0; i < PNP_MAX_PORT; i++) {
@@ -416,14 +417,14 @@ int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res,
goto fail;
}
}
- up(&pnp_res_mutex);
+ mutex_unlock(&pnp_res_mutex);
kfree(bak);
return 0;
fail:
dev->res = *bak;
- up(&pnp_res_mutex);
+ mutex_unlock(&pnp_res_mutex);
kfree(bak);
return -EINVAL;
}
@@ -513,7 +514,7 @@ int pnp_activate_dev(struct pnp_dev *dev)
int error;
if (dev->active)
- return 0; /* the device is already active */
+ return 0;
/* ensure resources are allocated */
if (pnp_auto_config_dev(dev))
@@ -524,7 +525,7 @@ int pnp_activate_dev(struct pnp_dev *dev)
return error;
dev->active = 1;
- return 1;
+ return 0;
}
/**
@@ -538,7 +539,7 @@ int pnp_disable_dev(struct pnp_dev *dev)
int error;
if (!dev->active)
- return 0; /* the device is already disabled */
+ return 0;
error = pnp_stop_dev(dev);
if (error)
@@ -547,11 +548,11 @@ int pnp_disable_dev(struct pnp_dev *dev)
dev->active = 0;
/* release the resources so that other devices can use them */
- down(&pnp_res_mutex);
+ mutex_lock(&pnp_res_mutex);
pnp_clean_resource_table(&dev->res);
- up(&pnp_res_mutex);
+ mutex_unlock(&pnp_res_mutex);
- return 1;
+ return 0;
}
/**
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index 6b9840cce0f..6aa231ef642 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -391,8 +391,8 @@ acpi_status pnpacpi_parse_allocated_resource(acpi_handle handle,
pnpacpi_allocated_resource, res);
}
-static void pnpacpi_parse_dma_option(struct pnp_option *option,
- struct acpi_resource_dma *p)
+static __init void pnpacpi_parse_dma_option(struct pnp_option *option,
+ struct acpi_resource_dma *p)
{
int i;
struct pnp_dma *dma;
@@ -411,8 +411,8 @@ static void pnpacpi_parse_dma_option(struct pnp_option *option,
pnp_register_dma_resource(option, dma);
}
-static void pnpacpi_parse_irq_option(struct pnp_option *option,
- struct acpi_resource_irq *p)
+static __init void pnpacpi_parse_irq_option(struct pnp_option *option,
+ struct acpi_resource_irq *p)
{
int i;
struct pnp_irq *irq;
@@ -431,8 +431,8 @@ static void pnpacpi_parse_irq_option(struct pnp_option *option,
pnp_register_irq_resource(option, irq);
}
-static void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
- struct acpi_resource_extended_irq *p)
+static __init void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
+ struct acpi_resource_extended_irq *p)
{
int i;
struct pnp_irq *irq;
@@ -451,8 +451,8 @@ static void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
pnp_register_irq_resource(option, irq);
}
-static void pnpacpi_parse_port_option(struct pnp_option *option,
- struct acpi_resource_io *io)
+static __init void pnpacpi_parse_port_option(struct pnp_option *option,
+ struct acpi_resource_io *io)
{
struct pnp_port *port;
@@ -470,8 +470,8 @@ static void pnpacpi_parse_port_option(struct pnp_option *option,
pnp_register_port_resource(option, port);
}
-static void pnpacpi_parse_fixed_port_option(struct pnp_option *option,
- struct acpi_resource_fixed_io *io)
+static __init void pnpacpi_parse_fixed_port_option(struct pnp_option *option,
+ struct acpi_resource_fixed_io *io)
{
struct pnp_port *port;
@@ -487,8 +487,8 @@ static void pnpacpi_parse_fixed_port_option(struct pnp_option *option,
pnp_register_port_resource(option, port);
}
-static void pnpacpi_parse_mem24_option(struct pnp_option *option,
- struct acpi_resource_memory24 *p)
+static __init void pnpacpi_parse_mem24_option(struct pnp_option *option,
+ struct acpi_resource_memory24 *p)
{
struct pnp_mem *mem;
@@ -508,8 +508,8 @@ static void pnpacpi_parse_mem24_option(struct pnp_option *option,
pnp_register_mem_resource(option, mem);
}
-static void pnpacpi_parse_mem32_option(struct pnp_option *option,
- struct acpi_resource_memory32 *p)
+static __init void pnpacpi_parse_mem32_option(struct pnp_option *option,
+ struct acpi_resource_memory32 *p)
{
struct pnp_mem *mem;
@@ -529,8 +529,8 @@ static void pnpacpi_parse_mem32_option(struct pnp_option *option,
pnp_register_mem_resource(option, mem);
}
-static void pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
- struct acpi_resource_fixed_memory32 *p)
+static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
+ struct acpi_resource_fixed_memory32 *p)
{
struct pnp_mem *mem;
@@ -549,8 +549,8 @@ static void pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
pnp_register_mem_resource(option, mem);
}
-static void pnpacpi_parse_address_option(struct pnp_option *option,
- struct acpi_resource *r)
+static __init void pnpacpi_parse_address_option(struct pnp_option *option,
+ struct acpi_resource *r)
{
struct acpi_resource_address64 addr, *p = &addr;
acpi_status status;
@@ -596,8 +596,8 @@ struct acpipnp_parse_option_s {
struct pnp_dev *dev;
};
-static acpi_status pnpacpi_option_resource(struct acpi_resource *res,
- void *data)
+static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res,
+ void *data)
{
int priority = 0;
struct acpipnp_parse_option_s *parse_data = data;
@@ -696,8 +696,8 @@ static acpi_status pnpacpi_option_resource(struct acpi_resource *res,
return AE_OK;
}
-acpi_status pnpacpi_parse_resource_option_data(acpi_handle handle,
- struct pnp_dev * dev)
+acpi_status __init pnpacpi_parse_resource_option_data(acpi_handle handle,
+ struct pnp_dev *dev)
{
acpi_status status;
struct acpipnp_parse_option_s parse_data;
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index e33e03f7108..f7e67197a56 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -315,7 +315,7 @@ struct pnp_protocol pnpbios_protocol = {
.disable = pnpbios_disable_resources,
};
-static int insert_device(struct pnp_bios_node *node)
+static int __init insert_device(struct pnp_bios_node *node)
{
struct list_head *pos;
struct pnp_dev *dev;
diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c
index 3fabf11b002..caade353141 100644
--- a/drivers/pnp/pnpbios/rsparser.c
+++ b/drivers/pnp/pnpbios/rsparser.c
@@ -262,8 +262,8 @@ len_err:
* Resource Configuration Options
*/
-static void pnpbios_parse_mem_option(unsigned char *p, int size,
- struct pnp_option *option)
+static __init void pnpbios_parse_mem_option(unsigned char *p, int size,
+ struct pnp_option *option)
{
struct pnp_mem *mem;
@@ -278,8 +278,8 @@ static void pnpbios_parse_mem_option(unsigned char *p, int size,
pnp_register_mem_resource(option, mem);
}
-static void pnpbios_parse_mem32_option(unsigned char *p, int size,
- struct pnp_option *option)
+static __init void pnpbios_parse_mem32_option(unsigned char *p, int size,
+ struct pnp_option *option)
{
struct pnp_mem *mem;
@@ -294,8 +294,8 @@ static void pnpbios_parse_mem32_option(unsigned char *p, int size,
pnp_register_mem_resource(option, mem);
}
-static void pnpbios_parse_fixed_mem32_option(unsigned char *p, int size,
- struct pnp_option *option)
+static __init void pnpbios_parse_fixed_mem32_option(unsigned char *p, int size,
+ struct pnp_option *option)
{
struct pnp_mem *mem;
@@ -309,7 +309,7 @@ static void pnpbios_parse_fixed_mem32_option(unsigned char *p, int size,
pnp_register_mem_resource(option, mem);
}
-static void pnpbios_parse_irq_option(unsigned char *p, int size,
+static __init void pnpbios_parse_irq_option(unsigned char *p, int size,
struct pnp_option *option)
{
struct pnp_irq *irq;
@@ -327,7 +327,7 @@ static void pnpbios_parse_irq_option(unsigned char *p, int size,
pnp_register_irq_resource(option, irq);
}
-static void pnpbios_parse_dma_option(unsigned char *p, int size,
+static __init void pnpbios_parse_dma_option(unsigned char *p, int size,
struct pnp_option *option)
{
struct pnp_dma *dma;
@@ -340,8 +340,8 @@ static void pnpbios_parse_dma_option(unsigned char *p, int size,
pnp_register_dma_resource(option, dma);
}
-static void pnpbios_parse_port_option(unsigned char *p, int size,
- struct pnp_option *option)
+static __init void pnpbios_parse_port_option(unsigned char *p, int size,
+ struct pnp_option *option)
{
struct pnp_port *port;
@@ -356,8 +356,8 @@ static void pnpbios_parse_port_option(unsigned char *p, int size,
pnp_register_port_resource(option, port);
}
-static void pnpbios_parse_fixed_port_option(unsigned char *p, int size,
- struct pnp_option *option)
+static __init void pnpbios_parse_fixed_port_option(unsigned char *p, int size,
+ struct pnp_option *option)
{
struct pnp_port *port;
@@ -371,9 +371,9 @@ static void pnpbios_parse_fixed_port_option(unsigned char *p, int size,
pnp_register_port_resource(option, port);
}
-static unsigned char *pnpbios_parse_resource_option_data(unsigned char *p,
- unsigned char *end,
- struct pnp_dev *dev)
+static __init unsigned char *
+pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end,
+ struct pnp_dev *dev)
{
unsigned int len, tag;
int priority = 0;
@@ -781,7 +781,8 @@ len_err:
* Core Parsing Functions
*/
-int pnpbios_parse_data_stream(struct pnp_dev *dev, struct pnp_bios_node *node)
+int __init pnpbios_parse_data_stream(struct pnp_dev *dev,
+ struct pnp_bios_node *node)
{
unsigned char *p = (char *)node->data;
unsigned char *end = (char *)(node->data + node->size);
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
index e903b8c2b1f..4065139753b 100644
--- a/drivers/pnp/quirks.c
+++ b/drivers/pnp/quirks.c
@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/pnp.h>
#include <linux/io.h>
+#include <linux/dmi.h>
#include <linux/kallsyms.h>
#include "base.h"
@@ -108,6 +109,46 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev)
"pnp: SB audio device quirk - increasing port range\n");
}
+static void quirk_supermicro_h8dce_system(struct pnp_dev *dev)
+{
+ int i;
+ static struct dmi_system_id supermicro_h8dce[] = {
+ {
+ .ident = "Supermicro H8DCE",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "H8DCE"),
+ },
+ },
+ { }
+ };
+
+ if (!dmi_check_system(supermicro_h8dce))
+ return;
+
+ /*
+ * On the Supermicro H8DCE, there's a system device with resources
+ * that overlap BAR 6 of the built-in SATA PCI adapter. If the PNP
+ * system device claims them, the sata_nv driver won't be able to.
+ * More details at:
+ * https://bugzilla.redhat.com/show_bug.cgi?id=280641
+ * https://bugzilla.redhat.com/show_bug.cgi?id=313491
+ * http://lkml.org/lkml/2008/1/9/449
+ * http://thread.gmane.org/gmane.linux.acpi.devel/27312
+ */
+ for (i = 0; i < PNP_MAX_MEM; i++) {
+ if (pnp_mem_valid(dev, i) && pnp_mem_len(dev, i) &&
+ (pnp_mem_start(dev, i) & 0xdfef0000) == 0xdfef0000) {
+ dev_warn(&dev->dev, "disabling 0x%llx-0x%llx to prevent"
+ " conflict with sata_nv PCI device\n",
+ (unsigned long long) pnp_mem_start(dev, i),
+ (unsigned long long) (pnp_mem_start(dev, i) +
+ pnp_mem_len(dev, i) - 1));
+ pnp_mem_flags(dev, i) = 0;
+ }
+ }
+}
+
/*
* PnP Quirks
* Cards or devices that need some tweaking due to incomplete resource info
@@ -128,6 +169,8 @@ static struct pnp_fixup pnp_fixups[] = {
{"CTL0043", quirk_sb16audio_resources},
{"CTL0044", quirk_sb16audio_resources},
{"CTL0045", quirk_sb16audio_resources},
+ {"PNP0c01", quirk_supermicro_h8dce_system},
+ {"PNP0c02", quirk_supermicro_h8dce_system},
{""}
};
diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c
index 87b3493d88e..6f2f90ebb02 100644
--- a/drivers/ps3/ps3av.c
+++ b/drivers/ps3/ps3av.c
@@ -78,23 +78,21 @@ static const struct avset_video_mode {
u32 aspect;
u32 x;
u32 y;
- u32 interlace;
- u32 freq;
} video_mode_table[] = {
{ 0, }, /* auto */
- {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I, A_N, 720, 480, 1, 60},
- {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P, A_N, 720, 480, 0, 60},
- {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ, A_N, 1280, 720, 0, 60},
- {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080, 1, 60},
- {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080, 0, 60},
- {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I, A_N, 720, 576, 1, 50},
- {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P, A_N, 720, 576, 0, 50},
- {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ, A_N, 1280, 720, 0, 50},
- {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080, 1, 50},
- {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080, 0, 50},
- { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA, A_W, 1280, 768, 0, 60},
- { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_SXGA, A_N, 1280, 1024, 0, 60},
- { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WUXGA, A_W, 1920, 1200, 0, 60},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I, A_N, 720, 480},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P, A_N, 720, 480},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ, A_N, 1280, 720},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I, A_N, 720, 576},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P, A_N, 720, 576},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ, A_N, 1280, 720},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080},
+ { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA, A_W, 1280, 768},
+ { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_SXGA, A_N, 1280, 1024},
+ { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WUXGA, A_W, 1920, 1200},
};
/* supported CIDs */
@@ -544,7 +542,7 @@ static void ps3av_set_videomode_packet(u32 id)
static void ps3av_set_videomode_cont(u32 id, u32 old_id)
{
- static int vesa = 0;
+ static int vesa;
int res;
/* video signal off */
@@ -554,9 +552,9 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id)
* AV backend needs non-VESA mode setting at least one time
* when VESA mode is used.
*/
- if (vesa == 0 && (id & PS3AV_MODE_MASK) >= 11) {
+ if (vesa == 0 && (id & PS3AV_MODE_MASK) >= PS3AV_MODE_WXGA) {
/* vesa mode */
- ps3av_set_videomode_packet(2); /* 480P */
+ ps3av_set_videomode_packet(PS3AV_MODE_480P);
}
vesa = 1;
@@ -596,20 +594,21 @@ static const struct {
unsigned mask : 19;
unsigned id : 4;
} ps3av_preferred_modes[] = {
- { .mask = PS3AV_RESBIT_WUXGA << SHIFT_VESA, .id = 13 },
- { .mask = PS3AV_RESBIT_1920x1080P << SHIFT_60, .id = 5 },
- { .mask = PS3AV_RESBIT_1920x1080P << SHIFT_50, .id = 10 },
- { .mask = PS3AV_RESBIT_1920x1080I << SHIFT_60, .id = 4 },
- { .mask = PS3AV_RESBIT_1920x1080I << SHIFT_50, .id = 9 },
- { .mask = PS3AV_RESBIT_SXGA << SHIFT_VESA, .id = 12 },
- { .mask = PS3AV_RESBIT_WXGA << SHIFT_VESA, .id = 11 },
- { .mask = PS3AV_RESBIT_1280x720P << SHIFT_60, .id = 3 },
- { .mask = PS3AV_RESBIT_1280x720P << SHIFT_50, .id = 8 },
- { .mask = PS3AV_RESBIT_720x480P << SHIFT_60, .id = 2 },
- { .mask = PS3AV_RESBIT_720x576P << SHIFT_50, .id = 7 },
+ { PS3AV_RESBIT_WUXGA << SHIFT_VESA, PS3AV_MODE_WUXGA },
+ { PS3AV_RESBIT_1920x1080P << SHIFT_60, PS3AV_MODE_1080P60 },
+ { PS3AV_RESBIT_1920x1080P << SHIFT_50, PS3AV_MODE_1080P50 },
+ { PS3AV_RESBIT_1920x1080I << SHIFT_60, PS3AV_MODE_1080I60 },
+ { PS3AV_RESBIT_1920x1080I << SHIFT_50, PS3AV_MODE_1080I50 },
+ { PS3AV_RESBIT_SXGA << SHIFT_VESA, PS3AV_MODE_SXGA },
+ { PS3AV_RESBIT_WXGA << SHIFT_VESA, PS3AV_MODE_WXGA },
+ { PS3AV_RESBIT_1280x720P << SHIFT_60, PS3AV_MODE_720P60 },
+ { PS3AV_RESBIT_1280x720P << SHIFT_50, PS3AV_MODE_720P50 },
+ { PS3AV_RESBIT_720x480P << SHIFT_60, PS3AV_MODE_480P },
+ { PS3AV_RESBIT_720x576P << SHIFT_50, PS3AV_MODE_576P },
};
-static int ps3av_resbit2id(u32 res_50, u32 res_60, u32 res_vesa)
+static enum ps3av_mode_num ps3av_resbit2id(u32 res_50, u32 res_60,
+ u32 res_vesa)
{
unsigned int i;
u32 res_all;
@@ -638,9 +637,9 @@ static int ps3av_resbit2id(u32 res_50, u32 res_60, u32 res_vesa)
return 0;
}
-static int ps3av_hdmi_get_id(struct ps3av_info_monitor *info)
+static enum ps3av_mode_num ps3av_hdmi_get_id(struct ps3av_info_monitor *info)
{
- int id;
+ enum ps3av_mode_num id;
if (safe_mode)
return PS3AV_DEFAULT_HDMI_MODE_ID_REG_60;
@@ -854,7 +853,7 @@ int ps3av_set_video_mode(u32 id)
/* auto mode */
option = id & ~PS3AV_MODE_MASK;
- if ((id & PS3AV_MODE_MASK) == 0) {
+ if ((id & PS3AV_MODE_MASK) == PS3AV_MODE_AUTO) {
id = ps3av_auto_videomode(&ps3av->av_hw_conf);
if (id < 1) {
printk(KERN_ERR "%s: invalid id :%d\n", __func__, id);
@@ -889,36 +888,6 @@ int ps3av_get_mode(void)
EXPORT_SYMBOL_GPL(ps3av_get_mode);
-int ps3av_get_scanmode(int id)
-{
- int size;
-
- id = id & PS3AV_MODE_MASK;
- size = ARRAY_SIZE(video_mode_table);
- if (id > size - 1 || id < 0) {
- printk(KERN_ERR "%s: invalid mode %d\n", __func__, id);
- return -EINVAL;
- }
- return video_mode_table[id].interlace;
-}
-
-EXPORT_SYMBOL_GPL(ps3av_get_scanmode);
-
-int ps3av_get_refresh_rate(int id)
-{
- int size;
-
- id = id & PS3AV_MODE_MASK;
- size = ARRAY_SIZE(video_mode_table);
- if (id > size - 1 || id < 0) {
- printk(KERN_ERR "%s: invalid mode %d\n", __func__, id);
- return -EINVAL;
- }
- return video_mode_table[id].freq;
-}
-
-EXPORT_SYMBOL_GPL(ps3av_get_refresh_rate);
-
/* get resolution by video_mode */
int ps3av_video_mode2res(u32 id, u32 *xres, u32 *yres)
{
@@ -990,7 +959,7 @@ static int ps3av_probe(struct ps3_system_bus_device *dev)
return -ENOMEM;
mutex_init(&ps3av->mutex);
- ps3av->ps3av_mode = 0;
+ ps3av->ps3av_mode = PS3AV_MODE_AUTO;
ps3av->dev = dev;
INIT_WORK(&ps3av->work, ps3avd);
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 45e4b964817..6402d699072 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -20,6 +20,10 @@ menuconfig RTC_CLASS
if RTC_CLASS
+if GEN_RTC || RTC
+comment "Conflicting RTC option has been selected, check GEN_RTC and RTC"
+endif
+
config RTC_HCTOSYS
bool "Set system time from RTC on startup and resume"
depends on RTC_CLASS = y
@@ -49,7 +53,7 @@ config RTC_HCTOSYS_DEVICE
If the clock you specify here is not battery backed, it may still
be useful to reinitialize system time when resuming from system
- sleep states. Do not specify an RTC here unless it stays powered
+ sleep states. Do not specify an RTC here unless it stays powered
during all this system's supported sleep states.
config RTC_DEBUG
@@ -142,7 +146,7 @@ config RTC_DRV_DS1307
will be called rtc-ds1307.
config RTC_DRV_DS1374
- tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock"
+ tristate "Dallas/Maxim DS1374"
depends on RTC_CLASS && I2C
help
If you say yes here you get support for Dallas Semiconductor
@@ -162,7 +166,7 @@ config RTC_DRV_DS1672
will be called rtc-ds1672.
config RTC_DRV_MAX6900
- tristate "Maxim 6900"
+ tristate "Maxim MAX6900"
help
If you say yes here you will get support for the
Maxim MAX6900 I2C RTC chip.
@@ -180,10 +184,10 @@ config RTC_DRV_RS5C372
will be called rtc-rs5c372.
config RTC_DRV_ISL1208
- tristate "Intersil 1208"
+ tristate "Intersil ISL1208"
help
If you say yes here you get support for the
- Intersil 1208 RTC chip.
+ Intersil ISL1208 RTC chip.
This driver can also be built as a module. If so, the module
will be called rtc-isl1208.
@@ -220,7 +224,7 @@ config RTC_DRV_PCF8583
will be called rtc-pcf8583.
config RTC_DRV_M41T80
- tristate "ST M41T80 series RTC"
+ tristate "ST M41T80/81/82/83/84/85/87"
help
If you say Y here you will get support for the
ST M41T80 RTC chips series. Currently following chips are
@@ -252,23 +256,32 @@ comment "SPI RTC drivers"
if SPI_MASTER
-config RTC_DRV_RS5C348
- tristate "Ricoh RS5C348A/B"
+config RTC_DRV_MAX6902
+ tristate "Maxim MAX6902"
help
- If you say yes here you get support for the
- Ricoh RS5C348A and RS5C348B RTC chips.
+ If you say yes here you will get support for the
+ Maxim MAX6902 SPI RTC chip.
This driver can also be built as a module. If so, the module
- will be called rtc-rs5c348.
+ will be called rtc-max6902.
-config RTC_DRV_MAX6902
- tristate "Maxim 6902"
+config RTC_DRV_R9701
+ tristate "Epson RTC-9701JE"
help
If you say yes here you will get support for the
- Maxim MAX6902 SPI RTC chip.
+ Epson RTC-9701JE SPI RTC chip.
This driver can also be built as a module. If so, the module
- will be called rtc-max6902.
+ will be called rtc-r9701.
+
+config RTC_DRV_RS5C348
+ tristate "Ricoh RS5C348A/B"
+ help
+ If you say yes here you get support for the
+ Ricoh RS5C348A and RS5C348B RTC chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-rs5c348.
endif # SPI_MASTER
@@ -302,34 +315,50 @@ config RTC_DRV_DS1216
help
If you say yes here you get support for the Dallas DS1216 RTC chips.
-config RTC_DRV_DS1553
- tristate "Dallas DS1553"
+config RTC_DRV_DS1302
+ tristate "Dallas DS1302"
+ depends on SH_SECUREEDGE5410
+ help
+ If you say yes here you get support for the Dallas DS1302 RTC chips.
+
+config RTC_DRV_DS1511
+ tristate "Dallas DS1511"
+ depends on RTC_CLASS
help
If you say yes here you get support for the
- Dallas DS1553 timekeeping chip.
+ Dallas DS1511 timekeeping/watchdog chip.
This driver can also be built as a module. If so, the module
- will be called rtc-ds1553.
+ will be called rtc-ds1511.
-config RTC_DRV_STK17TA8
- tristate "Simtek STK17TA8"
- depends on RTC_CLASS
+config RTC_DRV_DS1553
+ tristate "Maxim/Dallas DS1553"
help
If you say yes here you get support for the
- Simtek STK17TA8 timekeeping chip.
+ Maxim/Dallas DS1553 timekeeping chip.
This driver can also be built as a module. If so, the module
- will be called rtc-stk17ta8.
+ will be called rtc-ds1553.
config RTC_DRV_DS1742
- tristate "Dallas DS1742/1743"
+ tristate "Maxim/Dallas DS1742/1743"
help
If you say yes here you get support for the
- Dallas DS1742/1743 timekeeping chip.
+ Maxim/Dallas DS1742/1743 timekeeping chip.
This driver can also be built as a module. If so, the module
will be called rtc-ds1742.
+config RTC_DRV_STK17TA8
+ tristate "Simtek STK17TA8"
+ depends on RTC_CLASS
+ help
+ If you say yes here you get support for the
+ Simtek STK17TA8 timekeeping chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-stk17ta8.
+
config RTC_DRV_M48T86
tristate "ST M48T86/Dallas DS12887"
help
@@ -440,10 +469,47 @@ config RTC_DRV_AT32AP700X
AT32AP700x family processors.
config RTC_DRV_AT91RM9200
- tristate "AT91RM9200"
- depends on ARCH_AT91RM9200
- help
- Driver for the Atmel AT91RM9200's internal RTC (Realtime Clock).
+ tristate "AT91RM9200 or AT91SAM9RL"
+ depends on ARCH_AT91RM9200 || ARCH_AT91SAM9RL
+ help
+ Driver for the internal RTC (Realtime Clock) module found on
+ Atmel AT91RM9200's and AT91SAM9RL chips. On SAM9RL chips
+ this is powered by the backup power supply.
+
+config RTC_DRV_AT91SAM9
+ tristate "AT91SAM9x"
+ depends on ARCH_AT91 && !(ARCH_AT91RM9200 || ARCH_AT91X40)
+ help
+ RTC driver for the Atmel AT91SAM9x internal RTT (Real Time Timer).
+ These timers are powered by the backup power supply (such as a
+ small coin cell battery), but do not need to be used as RTCs.
+
+ (On AT91SAM9rl chips you probably want to use the dedicated RTC
+ module and leave the RTT available for other uses.)
+
+config RTC_DRV_AT91SAM9_RTT
+ int
+ range 0 1
+ default 0
+ prompt "RTT module Number" if ARCH_AT91SAM9263
+ depends on RTC_DRV_AT91SAM9
+ help
+ More than one RTT module is available. You can choose which
+ one will be used as an RTC. The default of zero is normally
+ OK to use, though some systems use that for non-RTC purposes.
+
+config RTC_DRV_AT91SAM9_GPBR
+ int
+ range 0 3 if !ARCH_AT91SAM9263
+ range 0 15 if ARCH_AT91SAM9263
+ default 0
+ prompt "Backup Register Number"
+ depends on RTC_DRV_AT91SAM9
+ help
+ The RTC driver needs to use one of the General Purpose Backup
+ Registers (GPBRs) as well as the RTT. You can choose which one
+ will be used. The default of zero is normally OK to use, but
+ on some systems other software needs to use that register.
config RTC_DRV_BFIN
tristate "Blackfin On-Chip RTC"
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 465db4dd50b..ec703f34ab8 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -19,11 +19,14 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
+obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o
obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o
+obj-$(CONFIG_RTC_DRV_DS1302) += rtc-ds1302.o
obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o
obj-$(CONFIG_RTC_DRV_DS1374) += rtc-ds1374.o
+obj-$(CONFIG_RTC_DRV_DS1511) += rtc-ds1511.o
obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
@@ -38,6 +41,7 @@ obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
+obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c
new file mode 100644
index 00000000000..bbf10ecf416
--- /dev/null
+++ b/drivers/rtc/rtc-at91sam9.c
@@ -0,0 +1,520 @@
+/*
+ * "RTT as Real Time Clock" driver for AT91SAM9 SoC family
+ *
+ * (C) 2007 Michel Benoit
+ *
+ * Based on rtc-at91rm9200.c by Rick Bronson
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+
+#include <asm/mach/time.h>
+#include <asm/arch/board.h>
+#include <asm/arch/at91_rtt.h>
+
+
+/*
+ * This driver uses two configurable hardware resources that live in the
+ * AT91SAM9 backup power domain (intended to be powered at all times)
+ * to implement the Real Time Clock interfaces
+ *
+ * - A "Real-time Timer" (RTT) counts up in seconds from a base time.
+ * We can't assign the counter value (CRTV) ... but we can reset it.
+ *
+ * - One of the "General Purpose Backup Registers" (GPBRs) holds the
+ * base time, normally an offset from the beginning of the POSIX
+ * epoch (1970-Jan-1 00:00:00 UTC). Some systems also include the
+ * local timezone's offset.
+ *
+ * The RTC's value is the RTT counter plus that offset. The RTC's alarm
+ * is likewise a base (ALMV) plus that offset.
+ *
+ * Not all RTTs will be used as RTCs; some systems have multiple RTTs to
+ * choose from, or a "real" RTC module. All systems have multiple GPBR
+ * registers available, likewise usable for more than "RTC" support.
+ */
+
+/*
+ * We store ALARM_DISABLED in ALMV to record that no alarm is set.
+ * It's also the reset value for that field.
+ */
+#define ALARM_DISABLED ((u32)~0)
+
+
+struct sam9_rtc {
+ void __iomem *rtt;
+ struct rtc_device *rtcdev;
+ u32 imr;
+};
+
+#define rtt_readl(rtc, field) \
+ __raw_readl((rtc)->rtt + AT91_RTT_ ## field)
+#define rtt_writel(rtc, field, val) \
+ __raw_writel((val), (rtc)->rtt + AT91_RTT_ ## field)
+
+#define gpbr_readl(rtc) \
+ at91_sys_read(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR)
+#define gpbr_writel(rtc, val) \
+ at91_sys_write(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR, (val))
+
+/*
+ * Read current time and date in RTC
+ */
+static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm)
+{
+ struct sam9_rtc *rtc = dev_get_drvdata(dev);
+ u32 secs, secs2;
+ u32 offset;
+
+ /* read current time offset */
+ offset = gpbr_readl(rtc);
+ if (offset == 0)
+ return -EILSEQ;
+
+ /* reread the counter to help sync the two clock domains */
+ secs = rtt_readl(rtc, VR);
+ secs2 = rtt_readl(rtc, VR);
+ if (secs != secs2)
+ secs = rtt_readl(rtc, VR);
+
+ rtc_time_to_tm(offset + secs, tm);
+
+ dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "readtime",
+ 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ return 0;
+}
+
+/*
+ * Set current time and date in RTC
+ */
+static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
+{
+ struct sam9_rtc *rtc = dev_get_drvdata(dev);
+ int err;
+ u32 offset, alarm, mr;
+ unsigned long secs;
+
+ dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "settime",
+ 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ err = rtc_tm_to_time(tm, &secs);
+ if (err != 0)
+ return err;
+
+ mr = rtt_readl(rtc, MR);
+
+ /* disable interrupts */
+ rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN));
+
+ /* read current time offset */
+ offset = gpbr_readl(rtc);
+
+ /* store the new base time in a battery backup register */
+ secs += 1;
+ gpbr_writel(rtc, secs);
+
+ /* adjust the alarm time for the new base */
+ alarm = rtt_readl(rtc, AR);
+ if (alarm != ALARM_DISABLED) {
+ if (offset > secs) {
+ /* time jumped backwards, increase time until alarm */
+ alarm += (offset - secs);
+ } else if ((alarm + offset) > secs) {
+ /* time jumped forwards, decrease time until alarm */
+ alarm -= (secs - offset);
+ } else {
+ /* time jumped past the alarm, disable alarm */
+ alarm = ALARM_DISABLED;
+ mr &= ~AT91_RTT_ALMIEN;
+ }
+ rtt_writel(rtc, AR, alarm);
+ }
+
+ /* reset the timer, and re-enable interrupts */
+ rtt_writel(rtc, MR, mr | AT91_RTT_RTTRST);
+
+ return 0;
+}
+
+static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct sam9_rtc *rtc = dev_get_drvdata(dev);
+ struct rtc_time *tm = &alrm->time;
+ u32 alarm = rtt_readl(rtc, AR);
+ u32 offset;
+
+ offset = gpbr_readl(rtc);
+ if (offset == 0)
+ return -EILSEQ;
+
+ memset(alrm, 0, sizeof(alrm));
+ if (alarm != ALARM_DISABLED && offset != 0) {
+ rtc_time_to_tm(offset + alarm, tm);
+
+ dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "readalarm",
+ 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ if (rtt_readl(rtc, MR) & AT91_RTT_ALMIEN)
+ alrm->enabled = 1;
+ }
+
+ return 0;
+}
+
+static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct sam9_rtc *rtc = dev_get_drvdata(dev);
+ struct rtc_time *tm = &alrm->time;
+ unsigned long secs;
+ u32 offset;
+ u32 mr;
+ int err;
+
+ err = rtc_tm_to_time(tm, &secs);
+ if (err != 0)
+ return err;
+
+ offset = gpbr_readl(rtc);
+ if (offset == 0) {
+ /* time is not set */
+ return -EILSEQ;
+ }
+ mr = rtt_readl(rtc, MR);
+ rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN);
+
+ /* alarm in the past? finish and leave disabled */
+ if (secs <= offset) {
+ rtt_writel(rtc, AR, ALARM_DISABLED);
+ return 0;
+ }
+
+ /* else set alarm and maybe enable it */
+ rtt_writel(rtc, AR, secs - offset);
+ if (alrm->enabled)
+ rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN);
+
+ dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "setalarm",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour,
+ tm->tm_min, tm->tm_sec);
+
+ return 0;
+}
+
+/*
+ * Handle commands from user-space
+ */
+static int at91_rtc_ioctl(struct device *dev, unsigned int cmd,
+ unsigned long arg)
+{
+ struct sam9_rtc *rtc = dev_get_drvdata(dev);
+ int ret = 0;
+ u32 mr = rtt_readl(rtc, MR);
+
+ dev_dbg(dev, "ioctl: cmd=%08x, arg=%08lx, mr %08x\n", cmd, arg, mr);
+
+ switch (cmd) {
+ case RTC_AIE_OFF: /* alarm off */
+ rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN);
+ break;
+ case RTC_AIE_ON: /* alarm on */
+ rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN);
+ break;
+ case RTC_UIE_OFF: /* update off */
+ rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN);
+ break;
+ case RTC_UIE_ON: /* update on */
+ rtt_writel(rtc, MR, mr | AT91_RTT_RTTINCIEN);
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Provide additional RTC information in /proc/driver/rtc
+ */
+static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+ struct sam9_rtc *rtc = dev_get_drvdata(dev);
+ u32 mr = mr = rtt_readl(rtc, MR);
+
+ seq_printf(seq, "update_IRQ\t: %s\n",
+ (mr & AT91_RTT_RTTINCIEN) ? "yes" : "no");
+ return 0;
+}
+
+/*
+ * IRQ handler for the RTC
+ */
+static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc)
+{
+ struct sam9_rtc *rtc = _rtc;
+ u32 sr, mr;
+ unsigned long events = 0;
+
+ /* Shared interrupt may be for another device. Note: reading
+ * SR clears it, so we must only read it in this irq handler!
+ */
+ mr = rtt_readl(rtc, MR) & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
+ sr = rtt_readl(rtc, SR) & mr;
+ if (!sr)
+ return IRQ_NONE;
+
+ /* alarm status */
+ if (sr & AT91_RTT_ALMS)
+ events |= (RTC_AF | RTC_IRQF);
+
+ /* timer update/increment */
+ if (sr & AT91_RTT_RTTINC)
+ events |= (RTC_UF | RTC_IRQF);
+
+ rtc_update_irq(rtc->rtcdev, 1, events);
+
+ pr_debug("%s: num=%ld, events=0x%02lx\n", __FUNCTION__,
+ events >> 8, events & 0x000000FF);
+
+ return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops at91_rtc_ops = {
+ .ioctl = at91_rtc_ioctl,
+ .read_time = at91_rtc_readtime,
+ .set_time = at91_rtc_settime,
+ .read_alarm = at91_rtc_readalarm,
+ .set_alarm = at91_rtc_setalarm,
+ .proc = at91_rtc_proc,
+};
+
+/*
+ * Initialize and install RTC driver
+ */
+static int __init at91_rtc_probe(struct platform_device *pdev)
+{
+ struct resource *r;
+ struct sam9_rtc *rtc;
+ int ret;
+ u32 mr;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r)
+ return -ENODEV;
+
+ rtc = kzalloc(sizeof *rtc, GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, rtc);
+ rtc->rtt = (void __force __iomem *) (AT91_VA_BASE_SYS - AT91_BASE_SYS);
+ rtc->rtt += r->start;
+
+ mr = rtt_readl(rtc, MR);
+
+ /* unless RTT is counting at 1 Hz, re-initialize it */
+ if ((mr & AT91_RTT_RTPRES) != AT91_SLOW_CLOCK) {
+ mr = AT91_RTT_RTTRST | (AT91_SLOW_CLOCK & AT91_RTT_RTPRES);
+ gpbr_writel(rtc, 0);
+ }
+
+ /* disable all interrupts (same as on shutdown path) */
+ mr &= ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
+ rtt_writel(rtc, MR, mr);
+
+ rtc->rtcdev = rtc_device_register(pdev->name, &pdev->dev,
+ &at91_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc->rtcdev)) {
+ ret = PTR_ERR(rtc->rtcdev);
+ goto fail;
+ }
+
+ /* register irq handler after we know what name we'll use */
+ ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt,
+ IRQF_DISABLED | IRQF_SHARED,
+ rtc->rtcdev->dev.bus_id, rtc);
+ if (ret) {
+ dev_dbg(&pdev->dev, "can't share IRQ %d?\n", AT91_ID_SYS);
+ rtc_device_unregister(rtc->rtcdev);
+ goto fail;
+ }
+
+ /* NOTE: sam9260 rev A silicon has a ROM bug which resets the
+ * RTT on at least some reboots. If you have that chip, you must
+ * initialize the time from some external source like a GPS, wall
+ * clock, discrete RTC, etc
+ */
+
+ if (gpbr_readl(rtc) == 0)
+ dev_warn(&pdev->dev, "%s: SET TIME!\n",
+ rtc->rtcdev->dev.bus_id);
+
+ return 0;
+
+fail:
+ platform_set_drvdata(pdev, NULL);
+ kfree(rtc);
+ return ret;
+}
+
+/*
+ * Disable and remove the RTC driver
+ */
+static int __exit at91_rtc_remove(struct platform_device *pdev)
+{
+ struct sam9_rtc *rtc = platform_get_drvdata(pdev);
+ u32 mr = rtt_readl(rtc, MR);
+
+ /* disable all interrupts */
+ rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN));
+ free_irq(AT91_ID_SYS, rtc);
+
+ rtc_device_unregister(rtc->rtcdev);
+
+ platform_set_drvdata(pdev, NULL);
+ kfree(rtc);
+ return 0;
+}
+
+static void at91_rtc_shutdown(struct platform_device *pdev)
+{
+ struct sam9_rtc *rtc = platform_get_drvdata(pdev);
+ u32 mr = rtt_readl(rtc, MR);
+
+ rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
+ rtt_writel(rtc, MR, mr & ~rtc->imr);
+}
+
+#ifdef CONFIG_PM
+
+/* AT91SAM9 RTC Power management control */
+
+static int at91_rtc_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct sam9_rtc *rtc = platform_get_drvdata(pdev);
+ u32 mr = rtt_readl(rtc, MR);
+
+ /*
+ * This IRQ is shared with DBGU and other hardware which isn't
+ * necessarily a wakeup event source.
+ */
+ rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
+ if (rtc->imr) {
+ if (device_may_wakeup(&pdev->dev) && (mr & AT91_RTT_ALMIEN)) {
+ enable_irq_wake(AT91_ID_SYS);
+ /* don't let RTTINC cause wakeups */
+ if (mr & AT91_RTT_RTTINCIEN)
+ rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN);
+ } else
+ rtt_writel(rtc, MR, mr & ~rtc->imr);
+ }
+
+ return 0;
+}
+
+static int at91_rtc_resume(struct platform_device *pdev)
+{
+ struct sam9_rtc *rtc = platform_get_drvdata(pdev);
+ u32 mr;
+
+ if (rtc->imr) {
+ if (device_may_wakeup(&pdev->dev))
+ disable_irq_wake(AT91_ID_SYS);
+ mr = rtt_readl(rtc, MR);
+ rtt_writel(rtc, MR, mr | rtc->imr);
+ }
+
+ return 0;
+}
+#else
+#define at91_rtc_suspend NULL
+#define at91_rtc_resume NULL
+#endif
+
+static struct platform_driver at91_rtc_driver = {
+ .driver.name = "rtc-at91sam9",
+ .driver.owner = THIS_MODULE,
+ .remove = __exit_p(at91_rtc_remove),
+ .shutdown = at91_rtc_shutdown,
+ .suspend = at91_rtc_suspend,
+ .resume = at91_rtc_resume,
+};
+
+/* Chips can have more than one RTT module, and they can be used for more
+ * than just RTCs. So we can't just register as "the" RTT driver.
+ *
+ * A normal approach in such cases is to create a library to allocate and
+ * free the modules. Here we just use bus_find_device() as like such a
+ * library, binding directly ... no runtime "library" footprint is needed.
+ */
+static int __init at91_rtc_match(struct device *dev, void *v)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ int ret;
+
+ /* continue searching if this isn't the RTT we need */
+ if (strcmp("at91_rtt", pdev->name) != 0
+ || pdev->id != CONFIG_RTC_DRV_AT91SAM9_RTT)
+ goto fail;
+
+ /* else we found it ... but fail unless we can bind to the RTC driver */
+ if (dev->driver) {
+ dev_dbg(dev, "busy, can't use as RTC!\n");
+ goto fail;
+ }
+ dev->driver = &at91_rtc_driver.driver;
+ if (device_attach(dev) == 0) {
+ dev_dbg(dev, "can't attach RTC!\n");
+ goto fail;
+ }
+ ret = at91_rtc_probe(pdev);
+ if (ret == 0)
+ return true;
+
+ dev_dbg(dev, "RTC probe err %d!\n", ret);
+fail:
+ return false;
+}
+
+static int __init at91_rtc_init(void)
+{
+ int status;
+ struct device *rtc;
+
+ status = platform_driver_register(&at91_rtc_driver);
+ if (status)
+ return status;
+ rtc = bus_find_device(&platform_bus_type, NULL,
+ NULL, at91_rtc_match);
+ if (!rtc)
+ platform_driver_unregister(&at91_rtc_driver);
+ return rtc ? 0 : -ENODEV;
+}
+module_init(at91_rtc_init);
+
+static void __exit at91_rtc_exit(void)
+{
+ platform_driver_unregister(&at91_rtc_driver);
+}
+module_exit(at91_rtc_exit);
+
+
+MODULE_AUTHOR("Michel Benoit");
+MODULE_DESCRIPTION("RTC driver for Atmel AT91SAM9x");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c
index 1aa709dda0d..d90ba860d21 100644
--- a/drivers/rtc/rtc-bfin.c
+++ b/drivers/rtc/rtc-bfin.c
@@ -1,6 +1,6 @@
/*
* Blackfin On-Chip Real Time Clock Driver
- * Supports BF53[123]/BF53[467]/BF54[2489]
+ * Supports BF52[257]/BF53[123]/BF53[467]/BF54[24789]
*
* Copyright 2004-2007 Analog Devices Inc.
*
@@ -32,26 +32,25 @@
* writes to clear status registers complete immediately.
*/
-#include <linux/module.h>
-#include <linux/kernel.h>
#include <linux/bcd.h>
-#include <linux/rtc.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/rtc.h>
#include <linux/seq_file.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
#include <asm/blackfin.h>
-#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __FUNCTION__, __LINE__, ## args)
-#define stampit() stamp("here i am")
+#define dev_dbg_stamp(dev) dev_dbg(dev, "%s:%i: here i am\n", __func__, __LINE__)
struct bfin_rtc {
struct rtc_device *rtc_dev;
struct rtc_time rtc_alarm;
- spinlock_t lock;
+ u16 rtc_wrote_regs;
};
/* Bit values for the ISTAT / ICTL registers */
@@ -72,7 +71,7 @@ struct bfin_rtc {
#define SEC_BITS_OFF 0
/* Some helper functions to convert between the common RTC notion of time
- * and the internal Blackfin notion that is stored in 32bits.
+ * and the internal Blackfin notion that is encoded in 32bits.
*/
static inline u32 rtc_time_to_bfin(unsigned long now)
{
@@ -97,7 +96,10 @@ static inline void rtc_bfin_to_tm(u32 rtc_bfin, struct rtc_time *tm)
rtc_time_to_tm(rtc_bfin_to_time(rtc_bfin), tm);
}
-/* Wait for the previous write to a RTC register to complete.
+/**
+ * bfin_rtc_sync_pending - make sure pending writes have complete
+ *
+ * Wait for the previous write to a RTC register to complete.
* Unfortunately, we can't sleep here as that introduces a race condition when
* turning on interrupt events. Consider this:
* - process sets alarm
@@ -112,188 +114,202 @@ static inline void rtc_bfin_to_tm(u32 rtc_bfin, struct rtc_time *tm)
* If anyone can point out the obvious solution here, i'm listening :). This
* shouldn't be an issue on an SMP or preempt system as this function should
* only be called with the rtc lock held.
+ *
+ * Other options:
+ * - disable PREN so the sync happens at 32.768kHZ ... but this changes the
+ * inc rate for all RTC registers from 1HZ to 32.768kHZ ...
+ * - use the write complete IRQ
*/
-static void rtc_bfin_sync_pending(void)
+/*
+static void bfin_rtc_sync_pending_polled(void)
{
- stampit();
- while (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_COMPLETE)) {
+ while (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_COMPLETE))
if (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_PENDING))
break;
- }
bfin_write_RTC_ISTAT(RTC_ISTAT_WRITE_COMPLETE);
}
+*/
+static DECLARE_COMPLETION(bfin_write_complete);
+static void bfin_rtc_sync_pending(struct device *dev)
+{
+ dev_dbg_stamp(dev);
+ while (bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_PENDING)
+ wait_for_completion_timeout(&bfin_write_complete, HZ * 5);
+ dev_dbg_stamp(dev);
+}
-static void rtc_bfin_reset(struct bfin_rtc *rtc)
+/**
+ * bfin_rtc_reset - set RTC to sane/known state
+ *
+ * Initialize the RTC. Enable pre-scaler to scale RTC clock
+ * to 1Hz and clear interrupt/status registers.
+ */
+static void bfin_rtc_reset(struct device *dev)
{
- /* Initialize the RTC. Enable pre-scaler to scale RTC clock
- * to 1Hz and clear interrupt/status registers. */
- spin_lock_irq(&rtc->lock);
- rtc_bfin_sync_pending();
+ struct bfin_rtc *rtc = dev_get_drvdata(dev);
+ dev_dbg_stamp(dev);
+ bfin_rtc_sync_pending(dev);
bfin_write_RTC_PREN(0x1);
- bfin_write_RTC_ICTL(0);
+ bfin_write_RTC_ICTL(RTC_ISTAT_WRITE_COMPLETE);
bfin_write_RTC_SWCNT(0);
bfin_write_RTC_ALARM(0);
bfin_write_RTC_ISTAT(0xFFFF);
- spin_unlock_irq(&rtc->lock);
+ rtc->rtc_wrote_regs = 0;
}
+/**
+ * bfin_rtc_interrupt - handle interrupt from RTC
+ *
+ * Since we handle all RTC events here, we have to make sure the requested
+ * interrupt is enabled (in RTC_ICTL) as the event status register (RTC_ISTAT)
+ * always gets updated regardless of the interrupt being enabled. So when one
+ * even we care about (e.g. stopwatch) goes off, we don't want to turn around
+ * and say that other events have happened as well (e.g. second). We do not
+ * have to worry about pending writes to the RTC_ICTL register as interrupts
+ * only fire if they are enabled in the RTC_ICTL register.
+ */
static irqreturn_t bfin_rtc_interrupt(int irq, void *dev_id)
{
- struct platform_device *pdev = to_platform_device(dev_id);
- struct bfin_rtc *rtc = platform_get_drvdata(pdev);
+ struct device *dev = dev_id;
+ struct bfin_rtc *rtc = dev_get_drvdata(dev);
unsigned long events = 0;
- u16 rtc_istat;
-
- stampit();
+ bool write_complete = false;
+ u16 rtc_istat, rtc_ictl;
- spin_lock_irq(&rtc->lock);
+ dev_dbg_stamp(dev);
rtc_istat = bfin_read_RTC_ISTAT();
+ rtc_ictl = bfin_read_RTC_ICTL();
- if (rtc_istat & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)) {
- bfin_write_RTC_ISTAT(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY);
- events |= RTC_AF | RTC_IRQF;
+ if (rtc_istat & RTC_ISTAT_WRITE_COMPLETE) {
+ bfin_write_RTC_ISTAT(RTC_ISTAT_WRITE_COMPLETE);
+ write_complete = true;
+ complete(&bfin_write_complete);
}
- if (rtc_istat & RTC_ISTAT_STOPWATCH) {
- bfin_write_RTC_ISTAT(RTC_ISTAT_STOPWATCH);
- events |= RTC_PF | RTC_IRQF;
- bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq);
+ if (rtc_ictl & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)) {
+ if (rtc_istat & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)) {
+ bfin_write_RTC_ISTAT(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY);
+ events |= RTC_AF | RTC_IRQF;
+ }
}
- if (rtc_istat & RTC_ISTAT_SEC) {
- bfin_write_RTC_ISTAT(RTC_ISTAT_SEC);
- events |= RTC_UF | RTC_IRQF;
+ if (rtc_ictl & RTC_ISTAT_STOPWATCH) {
+ if (rtc_istat & RTC_ISTAT_STOPWATCH) {
+ bfin_write_RTC_ISTAT(RTC_ISTAT_STOPWATCH);
+ events |= RTC_PF | RTC_IRQF;
+ bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq);
+ }
}
- rtc_update_irq(rtc->rtc_dev, 1, events);
+ if (rtc_ictl & RTC_ISTAT_SEC) {
+ if (rtc_istat & RTC_ISTAT_SEC) {
+ bfin_write_RTC_ISTAT(RTC_ISTAT_SEC);
+ events |= RTC_UF | RTC_IRQF;
+ }
+ }
- spin_unlock_irq(&rtc->lock);
+ if (events)
+ rtc_update_irq(rtc->rtc_dev, 1, events);
- return IRQ_HANDLED;
+ if (write_complete || events)
+ return IRQ_HANDLED;
+ else
+ return IRQ_NONE;
}
static int bfin_rtc_open(struct device *dev)
{
- struct bfin_rtc *rtc = dev_get_drvdata(dev);
int ret;
- stampit();
+ dev_dbg_stamp(dev);
- ret = request_irq(IRQ_RTC, bfin_rtc_interrupt, IRQF_DISABLED, "rtc-bfin", dev);
- if (unlikely(ret)) {
- dev_err(dev, "request RTC IRQ failed with %d\n", ret);
- return ret;
- }
-
- rtc_bfin_reset(rtc);
+ ret = request_irq(IRQ_RTC, bfin_rtc_interrupt, IRQF_SHARED, to_platform_device(dev)->name, dev);
+ if (!ret)
+ bfin_rtc_reset(dev);
return ret;
}
static void bfin_rtc_release(struct device *dev)
{
- struct bfin_rtc *rtc = dev_get_drvdata(dev);
- stampit();
- rtc_bfin_reset(rtc);
+ dev_dbg_stamp(dev);
+ bfin_rtc_reset(dev);
free_irq(IRQ_RTC, dev);
}
+static void bfin_rtc_int_set(struct bfin_rtc *rtc, u16 rtc_int)
+{
+ bfin_write_RTC_ISTAT(rtc_int);
+ bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | rtc_int);
+}
+static void bfin_rtc_int_clear(struct bfin_rtc *rtc, u16 rtc_int)
+{
+ bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & rtc_int);
+}
+static void bfin_rtc_int_set_alarm(struct bfin_rtc *rtc)
+{
+ /* Blackfin has different bits for whether the alarm is
+ * more than 24 hours away.
+ */
+ bfin_rtc_int_set(rtc, (rtc->rtc_alarm.tm_yday == -1 ? RTC_ISTAT_ALARM : RTC_ISTAT_ALARM_DAY));
+}
static int bfin_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{
struct bfin_rtc *rtc = dev_get_drvdata(dev);
+ int ret = 0;
+
+ dev_dbg_stamp(dev);
- stampit();
+ bfin_rtc_sync_pending(dev);
switch (cmd) {
case RTC_PIE_ON:
- stampit();
- spin_lock_irq(&rtc->lock);
- rtc_bfin_sync_pending();
- bfin_write_RTC_ISTAT(RTC_ISTAT_STOPWATCH);
+ dev_dbg_stamp(dev);
+ bfin_rtc_int_set(rtc, RTC_ISTAT_STOPWATCH);
bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq);
- bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | RTC_ISTAT_STOPWATCH);
- spin_unlock_irq(&rtc->lock);
- return 0;
+ break;
case RTC_PIE_OFF:
- stampit();
- spin_lock_irq(&rtc->lock);
- rtc_bfin_sync_pending();
- bfin_write_RTC_SWCNT(0);
- bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~RTC_ISTAT_STOPWATCH);
- spin_unlock_irq(&rtc->lock);
- return 0;
+ dev_dbg_stamp(dev);
+ bfin_rtc_int_clear(rtc, ~RTC_ISTAT_STOPWATCH);
+ break;
case RTC_UIE_ON:
- stampit();
- spin_lock_irq(&rtc->lock);
- rtc_bfin_sync_pending();
- bfin_write_RTC_ISTAT(RTC_ISTAT_SEC);
- bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | RTC_ISTAT_SEC);
- spin_unlock_irq(&rtc->lock);
- return 0;
+ dev_dbg_stamp(dev);
+ bfin_rtc_int_set(rtc, RTC_ISTAT_SEC);
+ break;
case RTC_UIE_OFF:
- stampit();
- spin_lock_irq(&rtc->lock);
- rtc_bfin_sync_pending();
- bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~RTC_ISTAT_SEC);
- spin_unlock_irq(&rtc->lock);
- return 0;
-
- case RTC_AIE_ON: {
- unsigned long rtc_alarm;
- u16 which_alarm;
- int ret = 0;
-
- stampit();
-
- spin_lock_irq(&rtc->lock);
-
- rtc_bfin_sync_pending();
- if (rtc->rtc_alarm.tm_yday == -1) {
- struct rtc_time now;
- rtc_bfin_to_tm(bfin_read_RTC_STAT(), &now);
- now.tm_sec = rtc->rtc_alarm.tm_sec;
- now.tm_min = rtc->rtc_alarm.tm_min;
- now.tm_hour = rtc->rtc_alarm.tm_hour;
- ret = rtc_tm_to_time(&now, &rtc_alarm);
- which_alarm = RTC_ISTAT_ALARM;
- } else {
- ret = rtc_tm_to_time(&rtc->rtc_alarm, &rtc_alarm);
- which_alarm = RTC_ISTAT_ALARM_DAY;
- }
- if (ret == 0) {
- bfin_write_RTC_ISTAT(which_alarm);
- bfin_write_RTC_ALARM(rtc_time_to_bfin(rtc_alarm));
- bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | which_alarm);
- }
-
- spin_unlock_irq(&rtc->lock);
-
- return ret;
- }
+ dev_dbg_stamp(dev);
+ bfin_rtc_int_clear(rtc, ~RTC_ISTAT_SEC);
+ break;
+
+ case RTC_AIE_ON:
+ dev_dbg_stamp(dev);
+ bfin_rtc_int_set_alarm(rtc);
+ break;
case RTC_AIE_OFF:
- stampit();
- spin_lock_irq(&rtc->lock);
- rtc_bfin_sync_pending();
- bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
- spin_unlock_irq(&rtc->lock);
- return 0;
+ dev_dbg_stamp(dev);
+ bfin_rtc_int_clear(rtc, ~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
+ break;
+
+ default:
+ dev_dbg_stamp(dev);
+ ret = -ENOIOCTLCMD;
}
- return -ENOIOCTLCMD;
+ return ret;
}
static int bfin_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct bfin_rtc *rtc = dev_get_drvdata(dev);
- stampit();
+ dev_dbg_stamp(dev);
+
+ if (rtc->rtc_wrote_regs & 0x1)
+ bfin_rtc_sync_pending(dev);
- spin_lock_irq(&rtc->lock);
- rtc_bfin_sync_pending();
rtc_bfin_to_tm(bfin_read_RTC_STAT(), tm);
- spin_unlock_irq(&rtc->lock);
return 0;
}
@@ -304,64 +320,79 @@ static int bfin_rtc_set_time(struct device *dev, struct rtc_time *tm)
int ret;
unsigned long now;
- stampit();
-
- spin_lock_irq(&rtc->lock);
+ dev_dbg_stamp(dev);
ret = rtc_tm_to_time(tm, &now);
if (ret == 0) {
- rtc_bfin_sync_pending();
+ if (rtc->rtc_wrote_regs & 0x1)
+ bfin_rtc_sync_pending(dev);
bfin_write_RTC_STAT(rtc_time_to_bfin(now));
+ rtc->rtc_wrote_regs = 0x1;
}
- spin_unlock_irq(&rtc->lock);
-
return ret;
}
static int bfin_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct bfin_rtc *rtc = dev_get_drvdata(dev);
- stampit();
- memcpy(&alrm->time, &rtc->rtc_alarm, sizeof(struct rtc_time));
- alrm->pending = !!(bfin_read_RTC_ICTL() & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
+ dev_dbg_stamp(dev);
+ alrm->time = rtc->rtc_alarm;
+ bfin_rtc_sync_pending(dev);
+ alrm->enabled = !!(bfin_read_RTC_ICTL() & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
return 0;
}
static int bfin_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct bfin_rtc *rtc = dev_get_drvdata(dev);
- stampit();
- memcpy(&rtc->rtc_alarm, &alrm->time, sizeof(struct rtc_time));
+ unsigned long rtc_alarm;
+
+ dev_dbg_stamp(dev);
+
+ if (rtc_tm_to_time(&alrm->time, &rtc_alarm))
+ return -EINVAL;
+
+ rtc->rtc_alarm = alrm->time;
+
+ bfin_rtc_sync_pending(dev);
+ bfin_write_RTC_ALARM(rtc_time_to_bfin(rtc_alarm));
+ if (alrm->enabled)
+ bfin_rtc_int_set_alarm(rtc);
+
return 0;
}
static int bfin_rtc_proc(struct device *dev, struct seq_file *seq)
{
-#define yesno(x) (x ? "yes" : "no")
+#define yesno(x) ((x) ? "yes" : "no")
u16 ictl = bfin_read_RTC_ICTL();
- stampit();
- seq_printf(seq, "alarm_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_ALARM));
- seq_printf(seq, "wkalarm_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_ALARM_DAY));
- seq_printf(seq, "seconds_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_SEC));
- seq_printf(seq, "periodic_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_STOPWATCH));
-#ifdef DEBUG
- seq_printf(seq, "RTC_STAT\t: 0x%08X\n", bfin_read_RTC_STAT());
- seq_printf(seq, "RTC_ICTL\t: 0x%04X\n", bfin_read_RTC_ICTL());
- seq_printf(seq, "RTC_ISTAT\t: 0x%04X\n", bfin_read_RTC_ISTAT());
- seq_printf(seq, "RTC_SWCNT\t: 0x%04X\n", bfin_read_RTC_SWCNT());
- seq_printf(seq, "RTC_ALARM\t: 0x%08X\n", bfin_read_RTC_ALARM());
- seq_printf(seq, "RTC_PREN\t: 0x%04X\n", bfin_read_RTC_PREN());
-#endif
+ dev_dbg_stamp(dev);
+ seq_printf(seq,
+ "alarm_IRQ\t: %s\n"
+ "wkalarm_IRQ\t: %s\n"
+ "seconds_IRQ\t: %s\n"
+ "periodic_IRQ\t: %s\n",
+ yesno(ictl & RTC_ISTAT_ALARM),
+ yesno(ictl & RTC_ISTAT_ALARM_DAY),
+ yesno(ictl & RTC_ISTAT_SEC),
+ yesno(ictl & RTC_ISTAT_STOPWATCH));
return 0;
+#undef yesno
}
+/**
+ * bfin_irq_set_freq - make sure hardware supports requested freq
+ * @dev: pointer to RTC device structure
+ * @freq: requested frequency rate
+ *
+ * The Blackfin RTC can only generate periodic events at 1 per
+ * second (1 Hz), so reject any attempt at changing it.
+ */
static int bfin_irq_set_freq(struct device *dev, int freq)
{
- struct bfin_rtc *rtc = dev_get_drvdata(dev);
- stampit();
- rtc->rtc_dev->irq_freq = freq;
- return 0;
+ dev_dbg_stamp(dev);
+ return -ENOTTY;
}
static struct rtc_class_ops bfin_rtc_ops = {
@@ -381,27 +412,24 @@ static int __devinit bfin_rtc_probe(struct platform_device *pdev)
struct bfin_rtc *rtc;
int ret = 0;
- stampit();
+ dev_dbg_stamp(&pdev->dev);
rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
if (unlikely(!rtc))
return -ENOMEM;
- spin_lock_init(&rtc->lock);
-
rtc->rtc_dev = rtc_device_register(pdev->name, &pdev->dev, &bfin_rtc_ops, THIS_MODULE);
if (unlikely(IS_ERR(rtc))) {
ret = PTR_ERR(rtc->rtc_dev);
goto err;
}
- rtc->rtc_dev->irq_freq = 0;
- rtc->rtc_dev->max_user_freq = (2 << 16); /* stopwatch is an unsigned 16 bit reg */
+ rtc->rtc_dev->irq_freq = 1;
platform_set_drvdata(pdev, rtc);
return 0;
-err:
+ err:
kfree(rtc);
return ret;
}
@@ -428,7 +456,6 @@ static struct platform_driver bfin_rtc_driver = {
static int __init bfin_rtc_init(void)
{
- stampit();
return platform_driver_register(&bfin_rtc_driver);
}
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 29cf1457ca1..e059f94c79e 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -36,9 +36,24 @@
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
+#ifdef CONFIG_HPET_EMULATE_RTC
+#include <asm/hpet.h>
+#endif
+
/* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */
#include <asm-generic/rtc.h>
+#ifndef CONFIG_HPET_EMULATE_RTC
+#define is_hpet_enabled() 0
+#define hpet_set_alarm_time(hrs, min, sec) do { } while (0)
+#define hpet_set_periodic_freq(arg) 0
+#define hpet_mask_rtc_irq_bit(arg) do { } while (0)
+#define hpet_set_rtc_irq_bit(arg) do { } while (0)
+#define hpet_rtc_timer_init() do { } while (0)
+#define hpet_register_irq_handler(h) 0
+#define hpet_unregister_irq_handler(h) do { } while (0)
+extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id);
+#endif
struct cmos_rtc {
struct rtc_device *rtc;
@@ -199,6 +214,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
sec = t->time.tm_sec;
sec = (sec < 60) ? BIN2BCD(sec) : 0xff;
+ hpet_set_alarm_time(t->time.tm_hour, t->time.tm_min, t->time.tm_sec);
spin_lock_irq(&rtc_lock);
/* next rtc irq must not be from previous alarm setting */
@@ -252,7 +268,8 @@ static int cmos_irq_set_freq(struct device *dev, int freq)
f = 16 - f;
spin_lock_irqsave(&rtc_lock, flags);
- CMOS_WRITE(RTC_REF_CLCK_32KHZ | f, RTC_FREQ_SELECT);
+ if (!hpet_set_periodic_freq(freq))
+ CMOS_WRITE(RTC_REF_CLCK_32KHZ | f, RTC_FREQ_SELECT);
spin_unlock_irqrestore(&rtc_lock, flags);
return 0;
@@ -314,28 +331,37 @@ cmos_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
switch (cmd) {
case RTC_AIE_OFF: /* alarm off */
rtc_control &= ~RTC_AIE;
+ hpet_mask_rtc_irq_bit(RTC_AIE);
break;
case RTC_AIE_ON: /* alarm on */
rtc_control |= RTC_AIE;
+ hpet_set_rtc_irq_bit(RTC_AIE);
break;
case RTC_UIE_OFF: /* update off */
rtc_control &= ~RTC_UIE;
+ hpet_mask_rtc_irq_bit(RTC_UIE);
break;
case RTC_UIE_ON: /* update on */
rtc_control |= RTC_UIE;
+ hpet_set_rtc_irq_bit(RTC_UIE);
break;
case RTC_PIE_OFF: /* periodic off */
rtc_control &= ~RTC_PIE;
+ hpet_mask_rtc_irq_bit(RTC_PIE);
break;
case RTC_PIE_ON: /* periodic on */
rtc_control |= RTC_PIE;
+ hpet_set_rtc_irq_bit(RTC_PIE);
break;
}
- CMOS_WRITE(rtc_control, RTC_CONTROL);
+ if (!is_hpet_enabled())
+ CMOS_WRITE(rtc_control, RTC_CONTROL);
+
rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
if (is_intr(rtc_intr))
rtc_update_irq(cmos->rtc, 1, rtc_intr);
+
spin_unlock_irqrestore(&rtc_lock, flags);
return 0;
}
@@ -393,15 +419,111 @@ static const struct rtc_class_ops cmos_rtc_ops = {
/*----------------------------------------------------------------*/
+/*
+ * All these chips have at least 64 bytes of address space, shared by
+ * RTC registers and NVRAM. Most of those bytes of NVRAM are used
+ * by boot firmware. Modern chips have 128 or 256 bytes.
+ */
+
+#define NVRAM_OFFSET (RTC_REG_D + 1)
+
+static ssize_t
+cmos_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ int retval;
+
+ if (unlikely(off >= attr->size))
+ return 0;
+ if ((off + count) > attr->size)
+ count = attr->size - off;
+
+ spin_lock_irq(&rtc_lock);
+ for (retval = 0, off += NVRAM_OFFSET; count--; retval++, off++)
+ *buf++ = CMOS_READ(off);
+ spin_unlock_irq(&rtc_lock);
+
+ return retval;
+}
+
+static ssize_t
+cmos_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct cmos_rtc *cmos;
+ int retval;
+
+ cmos = dev_get_drvdata(container_of(kobj, struct device, kobj));
+ if (unlikely(off >= attr->size))
+ return -EFBIG;
+ if ((off + count) > attr->size)
+ count = attr->size - off;
+
+ /* NOTE: on at least PCs and Ataris, the boot firmware uses a
+ * checksum on part of the NVRAM data. That's currently ignored
+ * here. If userspace is smart enough to know what fields of
+ * NVRAM to update, updating checksums is also part of its job.
+ */
+ spin_lock_irq(&rtc_lock);
+ for (retval = 0, off += NVRAM_OFFSET; count--; retval++, off++) {
+ /* don't trash RTC registers */
+ if (off == cmos->day_alrm
+ || off == cmos->mon_alrm
+ || off == cmos->century)
+ buf++;
+ else
+ CMOS_WRITE(*buf++, off);
+ }
+ spin_unlock_irq(&rtc_lock);
+
+ return retval;
+}
+
+static struct bin_attribute nvram = {
+ .attr = {
+ .name = "nvram",
+ .mode = S_IRUGO | S_IWUSR,
+ .owner = THIS_MODULE,
+ },
+
+ .read = cmos_nvram_read,
+ .write = cmos_nvram_write,
+ /* size gets set up later */
+};
+
+/*----------------------------------------------------------------*/
+
static struct cmos_rtc cmos_rtc;
static irqreturn_t cmos_interrupt(int irq, void *p)
{
u8 irqstat;
+ u8 rtc_control;
spin_lock(&rtc_lock);
- irqstat = CMOS_READ(RTC_INTR_FLAGS);
- irqstat &= (CMOS_READ(RTC_CONTROL) & RTC_IRQMASK) | RTC_IRQF;
+ /*
+ * In this case it is HPET RTC interrupt handler
+ * calling us, with the interrupt information
+ * passed as arg1, instead of irq.
+ */
+ if (is_hpet_enabled())
+ irqstat = (unsigned long)irq & 0xF0;
+ else {
+ irqstat = CMOS_READ(RTC_INTR_FLAGS);
+ rtc_control = CMOS_READ(RTC_CONTROL);
+ irqstat &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
+ }
+
+ /* All Linux RTC alarms should be treated as if they were oneshot.
+ * Similar code may be needed in system wakeup paths, in case the
+ * alarm woke the system.
+ */
+ if (irqstat & RTC_AIE) {
+ rtc_control = CMOS_READ(RTC_CONTROL);
+ rtc_control &= ~RTC_AIE;
+ CMOS_WRITE(rtc_control, RTC_CONTROL);
+ CMOS_READ(RTC_INTR_FLAGS);
+ }
spin_unlock(&rtc_lock);
if (is_intr(irqstat)) {
@@ -412,11 +534,9 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
}
#ifdef CONFIG_PNP
-#define is_pnp() 1
#define INITSECTION
#else
-#define is_pnp() 0
#define INITSECTION __init
#endif
@@ -426,6 +546,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
struct cmos_rtc_board_info *info = dev->platform_data;
int retval = 0;
unsigned char rtc_control;
+ unsigned address_space;
/* there can be only one ... */
if (cmos_rtc.dev)
@@ -450,15 +571,36 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
cmos_rtc.irq = rtc_irq;
cmos_rtc.iomem = ports;
+ /* Heuristic to deduce NVRAM size ... do what the legacy NVRAM
+ * driver did, but don't reject unknown configs. Old hardware
+ * won't address 128 bytes, and for now we ignore the way newer
+ * chips can address 256 bytes (using two more i/o ports).
+ */
+#if defined(CONFIG_ATARI)
+ address_space = 64;
+#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__)
+ address_space = 128;
+#else
+#warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes.
+ address_space = 128;
+#endif
+
/* For ACPI systems extension info comes from the FADT. On others,
* board specific setup provides it as appropriate. Systems where
* the alarm IRQ isn't automatically a wakeup IRQ (like ACPI, and
* some almost-clones) can provide hooks to make that behave.
+ *
+ * Note that ACPI doesn't preclude putting these registers into
+ * "extended" areas of the chip, including some that we won't yet
+ * expect CMOS_READ and friends to handle.
*/
if (info) {
- cmos_rtc.day_alrm = info->rtc_day_alarm;
- cmos_rtc.mon_alrm = info->rtc_mon_alarm;
- cmos_rtc.century = info->rtc_century;
+ if (info->rtc_day_alarm && info->rtc_day_alarm < 128)
+ cmos_rtc.day_alrm = info->rtc_day_alarm;
+ if (info->rtc_mon_alarm && info->rtc_mon_alarm < 128)
+ cmos_rtc.mon_alrm = info->rtc_mon_alarm;
+ if (info->rtc_century && info->rtc_century < 128)
+ cmos_rtc.century = info->rtc_century;
if (info->wake_on && info->wake_off) {
cmos_rtc.wake_on = info->wake_on;
@@ -485,8 +627,9 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
* doesn't use 32KHz here ... for portability we might need to
* do something about other clock frequencies.
*/
- CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT);
cmos_rtc.rtc->irq_freq = 1024;
+ if (!hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq))
+ CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT);
/* disable irqs.
*
@@ -509,19 +652,39 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
goto cleanup1;
}
- if (is_valid_irq(rtc_irq))
- retval = request_irq(rtc_irq, cmos_interrupt, IRQF_DISABLED,
- cmos_rtc.rtc->dev.bus_id,
+ if (is_valid_irq(rtc_irq)) {
+ irq_handler_t rtc_cmos_int_handler;
+
+ if (is_hpet_enabled()) {
+ int err;
+
+ rtc_cmos_int_handler = hpet_rtc_interrupt;
+ err = hpet_register_irq_handler(cmos_interrupt);
+ if (err != 0) {
+ printk(KERN_WARNING "hpet_register_irq_handler "
+ " failed in rtc_init().");
+ goto cleanup1;
+ }
+ } else
+ rtc_cmos_int_handler = cmos_interrupt;
+
+ retval = request_irq(rtc_irq, rtc_cmos_int_handler,
+ IRQF_DISABLED, cmos_rtc.rtc->dev.bus_id,
cmos_rtc.rtc);
- if (retval < 0) {
- dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq);
- goto cleanup1;
+ if (retval < 0) {
+ dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq);
+ goto cleanup1;
+ }
}
+ hpet_rtc_timer_init();
- /* REVISIT optionally make 50 or 114 bytes NVRAM available,
- * like rtc-ds1553, rtc-ds1742 ... this will often include
- * registers for century, and day/month alarm.
- */
+ /* export at least the first block of NVRAM */
+ nvram.size = address_space - NVRAM_OFFSET;
+ retval = sysfs_create_bin_file(&dev->kobj, &nvram);
+ if (retval < 0) {
+ dev_dbg(dev, "can't create nvram file? %d\n", retval);
+ goto cleanup2;
+ }
pr_info("%s: alarms up to one %s%s\n",
cmos_rtc.rtc->dev.bus_id,
@@ -536,6 +699,9 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
return 0;
+cleanup2:
+ if (is_valid_irq(rtc_irq))
+ free_irq(rtc_irq, cmos_rtc.rtc);
cleanup1:
cmos_rtc.dev = NULL;
rtc_device_unregister(cmos_rtc.rtc);
@@ -563,8 +729,12 @@ static void __exit cmos_do_remove(struct device *dev)
cmos_do_shutdown();
- if (is_valid_irq(cmos->irq))
+ sysfs_remove_bin_file(&dev->kobj, &nvram);
+
+ if (is_valid_irq(cmos->irq)) {
free_irq(cmos->irq, cmos->rtc);
+ hpet_unregister_irq_handler(cmos_interrupt);
+ }
rtc_device_unregister(cmos->rtc);
cmos->rtc = NULL;
@@ -659,9 +829,12 @@ static int cmos_resume(struct device *dev)
/*----------------------------------------------------------------*/
-/* The "CMOS" RTC normally lives on the platform_bus. On ACPI systems,
- * the device node will always be created as a PNPACPI device. Plus
- * pre-ACPI PCs probably list it in the PNPBIOS tables.
+/* On non-x86 systems, a "CMOS" RTC lives most naturally on platform_bus.
+ * ACPI systems always list these as PNPACPI devices, and pre-ACPI PCs
+ * probably list them in similar PNPBIOS tables; so PNP is more common.
+ *
+ * We don't use legacy "poke at the hardware" probing. Ancient PCs that
+ * predate even PNPBIOS should set up platform_bus devices.
*/
#ifdef CONFIG_PNP
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index 025c60a17a4..90dfa0df747 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -246,6 +246,15 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
/* if the driver does not provide the ioctl interface
* or if that particular ioctl was not implemented
* (-ENOIOCTLCMD), we will try to emulate here.
+ *
+ * Drivers *SHOULD NOT* provide ioctl implementations
+ * for these requests. Instead, provide methods to
+ * support the following code, so that the RTC's main
+ * features are accessible without using ioctls.
+ *
+ * RTC and alarm times will be in UTC, by preference,
+ * but dual-booting with MS-Windows implies RTCs must
+ * use the local wall clock time.
*/
switch (cmd) {
diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c
new file mode 100644
index 00000000000..7b002ceeaa7
--- /dev/null
+++ b/drivers/rtc/rtc-ds1302.c
@@ -0,0 +1,262 @@
+/*
+ * Dallas DS1302 RTC Support
+ *
+ * Copyright (C) 2002 David McCullough
+ * Copyright (C) 2003 - 2007 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License version 2. See the file "COPYING" in the main directory of
+ * this archive for more details.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/bcd.h>
+#include <asm/rtc.h>
+
+#define DRV_NAME "rtc-ds1302"
+#define DRV_VERSION "0.1.0"
+
+#define RTC_CMD_READ 0x81 /* Read command */
+#define RTC_CMD_WRITE 0x80 /* Write command */
+
+#define RTC_ADDR_RAM0 0x20 /* Address of RAM0 */
+#define RTC_ADDR_TCR 0x08 /* Address of trickle charge register */
+#define RTC_ADDR_YEAR 0x06 /* Address of year register */
+#define RTC_ADDR_DAY 0x05 /* Address of day of week register */
+#define RTC_ADDR_MON 0x04 /* Address of month register */
+#define RTC_ADDR_DATE 0x03 /* Address of day of month register */
+#define RTC_ADDR_HOUR 0x02 /* Address of hour register */
+#define RTC_ADDR_MIN 0x01 /* Address of minute register */
+#define RTC_ADDR_SEC 0x00 /* Address of second register */
+
+#define RTC_RESET 0x1000
+#define RTC_IODATA 0x0800
+#define RTC_SCLK 0x0400
+
+#ifdef CONFIG_SH_SECUREEDGE5410
+#include <asm/snapgear.h>
+#define set_dp(x) SECUREEDGE_WRITE_IOPORT(x, 0x1c00)
+#define get_dp() SECUREEDGE_READ_IOPORT()
+#else
+#error "Add support for your platform"
+#endif
+
+struct ds1302_rtc {
+ struct rtc_device *rtc_dev;
+ spinlock_t lock;
+};
+
+static void ds1302_sendbits(unsigned int val)
+{
+ int i;
+
+ for (i = 8; (i); i--, val >>= 1) {
+ set_dp((get_dp() & ~RTC_IODATA) | ((val & 0x1) ?
+ RTC_IODATA : 0));
+ set_dp(get_dp() | RTC_SCLK); /* clock high */
+ set_dp(get_dp() & ~RTC_SCLK); /* clock low */
+ }
+}
+
+static unsigned int ds1302_recvbits(void)
+{
+ unsigned int val;
+ int i;
+
+ for (i = 0, val = 0; (i < 8); i++) {
+ val |= (((get_dp() & RTC_IODATA) ? 1 : 0) << i);
+ set_dp(get_dp() | RTC_SCLK); /* clock high */
+ set_dp(get_dp() & ~RTC_SCLK); /* clock low */
+ }
+
+ return val;
+}
+
+static unsigned int ds1302_readbyte(unsigned int addr)
+{
+ unsigned int val;
+
+ set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+
+ set_dp(get_dp() | RTC_RESET);
+ ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_READ);
+ val = ds1302_recvbits();
+ set_dp(get_dp() & ~RTC_RESET);
+
+ return val;
+}
+
+static void ds1302_writebyte(unsigned int addr, unsigned int val)
+{
+ set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+ set_dp(get_dp() | RTC_RESET);
+ ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_WRITE);
+ ds1302_sendbits(val);
+ set_dp(get_dp() & ~RTC_RESET);
+}
+
+static int ds1302_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct ds1302_rtc *rtc = dev_get_drvdata(dev);
+
+ spin_lock_irq(&rtc->lock);
+
+ tm->tm_sec = BCD2BIN(ds1302_readbyte(RTC_ADDR_SEC));
+ tm->tm_min = BCD2BIN(ds1302_readbyte(RTC_ADDR_MIN));
+ tm->tm_hour = BCD2BIN(ds1302_readbyte(RTC_ADDR_HOUR));
+ tm->tm_wday = BCD2BIN(ds1302_readbyte(RTC_ADDR_DAY));
+ tm->tm_mday = BCD2BIN(ds1302_readbyte(RTC_ADDR_DATE));
+ tm->tm_mon = BCD2BIN(ds1302_readbyte(RTC_ADDR_MON)) - 1;
+ tm->tm_year = BCD2BIN(ds1302_readbyte(RTC_ADDR_YEAR));
+
+ if (tm->tm_year < 70)
+ tm->tm_year += 100;
+
+ spin_unlock_irq(&rtc->lock);
+
+ dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+ "mday=%d, mon=%d, year=%d, wday=%d\n",
+ __FUNCTION__,
+ tm->tm_sec, tm->tm_min, tm->tm_hour,
+ tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday);
+
+ if (rtc_valid_tm(tm) < 0)
+ dev_err(dev, "invalid date\n");
+
+ return 0;
+}
+
+static int ds1302_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct ds1302_rtc *rtc = dev_get_drvdata(dev);
+
+ spin_lock_irq(&rtc->lock);
+
+ /* Stop RTC */
+ ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) | 0x80);
+
+ ds1302_writebyte(RTC_ADDR_SEC, BIN2BCD(tm->tm_sec));
+ ds1302_writebyte(RTC_ADDR_MIN, BIN2BCD(tm->tm_min));
+ ds1302_writebyte(RTC_ADDR_HOUR, BIN2BCD(tm->tm_hour));
+ ds1302_writebyte(RTC_ADDR_DAY, BIN2BCD(tm->tm_wday));
+ ds1302_writebyte(RTC_ADDR_DATE, BIN2BCD(tm->tm_mday));
+ ds1302_writebyte(RTC_ADDR_MON, BIN2BCD(tm->tm_mon + 1));
+ ds1302_writebyte(RTC_ADDR_YEAR, BIN2BCD(tm->tm_year % 100));
+
+ /* Start RTC */
+ ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) & ~0x80);
+
+ spin_unlock_irq(&rtc->lock);
+
+ return 0;
+}
+
+static int ds1302_rtc_ioctl(struct device *dev, unsigned int cmd,
+ unsigned long arg)
+{
+ switch (cmd) {
+#ifdef RTC_SET_CHARGE
+ case RTC_SET_CHARGE:
+ {
+ struct ds1302_rtc *rtc = dev_get_drvdata(dev);
+ int tcs_val;
+
+ if (copy_from_user(&tcs_val, (int __user *)arg, sizeof(int)))
+ return -EFAULT;
+
+ spin_lock_irq(&rtc->lock);
+ ds1302_writebyte(RTC_ADDR_TCR, (0xa0 | tcs_val * 0xf));
+ spin_unlock_irq(&rtc->lock);
+ return 0;
+ }
+#endif
+ }
+
+ return -ENOIOCTLCMD;
+}
+
+static struct rtc_class_ops ds1302_rtc_ops = {
+ .read_time = ds1302_rtc_read_time,
+ .set_time = ds1302_rtc_set_time,
+ .ioctl = ds1302_rtc_ioctl,
+};
+
+static int __devinit ds1302_rtc_probe(struct platform_device *pdev)
+{
+ struct ds1302_rtc *rtc;
+ int ret;
+
+ /* Reset */
+ set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+
+ /* Write a magic value to the DS1302 RAM, and see if it sticks. */
+ ds1302_writebyte(RTC_ADDR_RAM0, 0x42);
+ if (ds1302_readbyte(RTC_ADDR_RAM0) != 0x42)
+ return -ENODEV;
+
+ rtc = kzalloc(sizeof(struct ds1302_rtc), GFP_KERNEL);
+ if (unlikely(!rtc))
+ return -ENOMEM;
+
+ spin_lock_init(&rtc->lock);
+ rtc->rtc_dev = rtc_device_register("ds1302", &pdev->dev,
+ &ds1302_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc->rtc_dev)) {
+ ret = PTR_ERR(rtc->rtc_dev);
+ goto out;
+ }
+
+ platform_set_drvdata(pdev, rtc);
+
+ return 0;
+out:
+ kfree(rtc);
+ return ret;
+}
+
+static int __devexit ds1302_rtc_remove(struct platform_device *pdev)
+{
+ struct ds1302_rtc *rtc = platform_get_drvdata(pdev);
+
+ if (likely(rtc->rtc_dev))
+ rtc_device_unregister(rtc->rtc_dev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ kfree(rtc);
+
+ return 0;
+}
+
+static struct platform_driver ds1302_platform_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ds1302_rtc_probe,
+ .remove = __devexit_p(ds1302_rtc_remove),
+};
+
+static int __init ds1302_rtc_init(void)
+{
+ return platform_driver_register(&ds1302_platform_driver);
+}
+
+static void __exit ds1302_rtc_exit(void)
+{
+ platform_driver_unregister(&ds1302_platform_driver);
+}
+
+module_init(ds1302_rtc_init);
+module_exit(ds1302_rtc_exit);
+
+MODULE_DESCRIPTION("Dallas DS1302 RTC driver");
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR("Paul Mundt, David McCullough");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index bc1c7fe94ad..f389a28720d 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -256,7 +256,7 @@ ds1307_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
struct i2c_msg msg[2];
int result;
- client = to_i2c_client(container_of(kobj, struct device, kobj));
+ client = kobj_to_i2c_client(kobj);
ds1307 = i2c_get_clientdata(client);
if (unlikely(off >= NVRAM_SIZE))
@@ -294,7 +294,7 @@ ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
u8 buffer[NVRAM_SIZE + 1];
int ret;
- client = to_i2c_client(container_of(kobj, struct device, kobj));
+ client = kobj_to_i2c_client(kobj);
if (unlikely(off >= NVRAM_SIZE))
return -EFBIG;
@@ -412,11 +412,6 @@ read_rtc:
*/
tmp = ds1307->regs[DS1307_REG_SECS];
switch (ds1307->type) {
- case ds_1340:
- /* FIXME read register with DS1340_BIT_OSF, use that to
- * trigger the "set time" warning (*after* restarting the
- * oscillator!) instead of this weaker ds1307/m41t00 test.
- */
case ds_1307:
case m41t00:
/* clock halted? turn it on, so clock can tick. */
@@ -440,6 +435,24 @@ read_rtc:
goto read_rtc;
}
break;
+ case ds_1340:
+ /* clock halted? turn it on, so clock can tick. */
+ if (tmp & DS1340_BIT_nEOSC)
+ i2c_smbus_write_byte_data(client, DS1307_REG_SECS, 0);
+
+ tmp = i2c_smbus_read_byte_data(client, DS1340_REG_FLAG);
+ if (tmp < 0) {
+ pr_debug("read error %d\n", tmp);
+ err = -EIO;
+ goto exit_free;
+ }
+
+ /* oscillator fault? clear flag, and warn */
+ if (tmp & DS1340_BIT_OSF) {
+ i2c_smbus_write_byte_data(client, DS1340_REG_FLAG, 0);
+ dev_warn(&client->dev, "SET TIME!\n");
+ }
+ break;
case ds_1337:
case ds_1339:
break;
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c
new file mode 100644
index 00000000000..d74b8086fa3
--- /dev/null
+++ b/drivers/rtc/rtc-ds1511.c
@@ -0,0 +1,656 @@
+/*
+ * An rtc driver for the Dallas DS1511
+ *
+ * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ * Copyright (C) 2007 Andrew Sharp <andy.sharp@onstor.com>
+ *
+ * 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.
+ *
+ * Real time clock driver for the Dallas 1511 chip, which also
+ * contains a watchdog timer. There is a tiny amount of code that
+ * platform code could use to mess with the watchdog device a little
+ * bit, but not a full watchdog driver.
+ */
+
+#include <linux/bcd.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#define DRV_VERSION "0.6"
+
+enum ds1511reg {
+ DS1511_SEC = 0x0,
+ DS1511_MIN = 0x1,
+ DS1511_HOUR = 0x2,
+ DS1511_DOW = 0x3,
+ DS1511_DOM = 0x4,
+ DS1511_MONTH = 0x5,
+ DS1511_YEAR = 0x6,
+ DS1511_CENTURY = 0x7,
+ DS1511_AM1_SEC = 0x8,
+ DS1511_AM2_MIN = 0x9,
+ DS1511_AM3_HOUR = 0xa,
+ DS1511_AM4_DATE = 0xb,
+ DS1511_WD_MSEC = 0xc,
+ DS1511_WD_SEC = 0xd,
+ DS1511_CONTROL_A = 0xe,
+ DS1511_CONTROL_B = 0xf,
+ DS1511_RAMADDR_LSB = 0x10,
+ DS1511_RAMDATA = 0x13
+};
+
+#define DS1511_BLF1 0x80
+#define DS1511_BLF2 0x40
+#define DS1511_PRS 0x20
+#define DS1511_PAB 0x10
+#define DS1511_TDF 0x08
+#define DS1511_KSF 0x04
+#define DS1511_WDF 0x02
+#define DS1511_IRQF 0x01
+#define DS1511_TE 0x80
+#define DS1511_CS 0x40
+#define DS1511_BME 0x20
+#define DS1511_TPE 0x10
+#define DS1511_TIE 0x08
+#define DS1511_KIE 0x04
+#define DS1511_WDE 0x02
+#define DS1511_WDS 0x01
+#define DS1511_RAM_MAX 0xff
+
+#define RTC_CMD DS1511_CONTROL_B
+#define RTC_CMD1 DS1511_CONTROL_A
+
+#define RTC_ALARM_SEC DS1511_AM1_SEC
+#define RTC_ALARM_MIN DS1511_AM2_MIN
+#define RTC_ALARM_HOUR DS1511_AM3_HOUR
+#define RTC_ALARM_DATE DS1511_AM4_DATE
+
+#define RTC_SEC DS1511_SEC
+#define RTC_MIN DS1511_MIN
+#define RTC_HOUR DS1511_HOUR
+#define RTC_DOW DS1511_DOW
+#define RTC_DOM DS1511_DOM
+#define RTC_MON DS1511_MONTH
+#define RTC_YEAR DS1511_YEAR
+#define RTC_CENTURY DS1511_CENTURY
+
+#define RTC_TIE DS1511_TIE
+#define RTC_TE DS1511_TE
+
+struct rtc_plat_data {
+ struct rtc_device *rtc;
+ void __iomem *ioaddr; /* virtual base address */
+ unsigned long baseaddr; /* physical base address */
+ int size; /* amount of memory mapped */
+ int irq;
+ unsigned int irqen;
+ int alrm_sec;
+ int alrm_min;
+ int alrm_hour;
+ int alrm_mday;
+};
+
+static DEFINE_SPINLOCK(ds1511_lock);
+
+static __iomem char *ds1511_base;
+static u32 reg_spacing = 1;
+
+ static noinline void
+rtc_write(uint8_t val, uint32_t reg)
+{
+ writeb(val, ds1511_base + (reg * reg_spacing));
+}
+
+ static inline void
+rtc_write_alarm(uint8_t val, enum ds1511reg reg)
+{
+ rtc_write((val | 0x80), reg);
+}
+
+ static noinline uint8_t
+rtc_read(enum ds1511reg reg)
+{
+ return readb(ds1511_base + (reg * reg_spacing));
+}
+
+ static inline void
+rtc_disable_update(void)
+{
+ rtc_write((rtc_read(RTC_CMD) & ~RTC_TE), RTC_CMD);
+}
+
+ static void
+rtc_enable_update(void)
+{
+ rtc_write((rtc_read(RTC_CMD) | RTC_TE), RTC_CMD);
+}
+
+/*
+ * #define DS1511_WDOG_RESET_SUPPORT
+ *
+ * Uncomment this if you want to use these routines in
+ * some platform code.
+ */
+#ifdef DS1511_WDOG_RESET_SUPPORT
+/*
+ * just enough code to set the watchdog timer so that it
+ * will reboot the system
+ */
+ void
+ds1511_wdog_set(unsigned long deciseconds)
+{
+ /*
+ * the wdog timer can take 99.99 seconds
+ */
+ deciseconds %= 10000;
+ /*
+ * set the wdog values in the wdog registers
+ */
+ rtc_write(BIN2BCD(deciseconds % 100), DS1511_WD_MSEC);
+ rtc_write(BIN2BCD(deciseconds / 100), DS1511_WD_SEC);
+ /*
+ * set wdog enable and wdog 'steering' bit to issue a reset
+ */
+ rtc_write(DS1511_WDE | DS1511_WDS, RTC_CMD);
+}
+
+ void
+ds1511_wdog_disable(void)
+{
+ /*
+ * clear wdog enable and wdog 'steering' bits
+ */
+ rtc_write(rtc_read(RTC_CMD) & ~(DS1511_WDE | DS1511_WDS), RTC_CMD);
+ /*
+ * clear the wdog counter
+ */
+ rtc_write(0, DS1511_WD_MSEC);
+ rtc_write(0, DS1511_WD_SEC);
+}
+#endif
+
+/*
+ * set the rtc chip's idea of the time.
+ * stupidly, some callers call with year unmolested;
+ * and some call with year = year - 1900. thanks.
+ */
+ int
+ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
+{
+ u8 mon, day, dow, hrs, min, sec, yrs, cen;
+ unsigned int flags;
+
+ /*
+ * won't have to change this for a while
+ */
+ if (rtc_tm->tm_year < 1900) {
+ rtc_tm->tm_year += 1900;
+ }
+
+ if (rtc_tm->tm_year < 1970) {
+ return -EINVAL;
+ }
+ yrs = rtc_tm->tm_year % 100;
+ cen = rtc_tm->tm_year / 100;
+ mon = rtc_tm->tm_mon + 1; /* tm_mon starts at zero */
+ day = rtc_tm->tm_mday;
+ dow = rtc_tm->tm_wday & 0x7; /* automatic BCD */
+ hrs = rtc_tm->tm_hour;
+ min = rtc_tm->tm_min;
+ sec = rtc_tm->tm_sec;
+
+ if ((mon > 12) || (day == 0)) {
+ return -EINVAL;
+ }
+
+ if (day > rtc_month_days(rtc_tm->tm_mon, rtc_tm->tm_year)) {
+ return -EINVAL;
+ }
+
+ if ((hrs >= 24) || (min >= 60) || (sec >= 60)) {
+ return -EINVAL;
+ }
+
+ /*
+ * each register is a different number of valid bits
+ */
+ sec = BIN2BCD(sec) & 0x7f;
+ min = BIN2BCD(min) & 0x7f;
+ hrs = BIN2BCD(hrs) & 0x3f;
+ day = BIN2BCD(day) & 0x3f;
+ mon = BIN2BCD(mon) & 0x1f;
+ yrs = BIN2BCD(yrs) & 0xff;
+ cen = BIN2BCD(cen) & 0xff;
+
+ spin_lock_irqsave(&ds1511_lock, flags);
+ rtc_disable_update();
+ rtc_write(cen, RTC_CENTURY);
+ rtc_write(yrs, RTC_YEAR);
+ rtc_write((rtc_read(RTC_MON) & 0xe0) | mon, RTC_MON);
+ rtc_write(day, RTC_DOM);
+ rtc_write(hrs, RTC_HOUR);
+ rtc_write(min, RTC_MIN);
+ rtc_write(sec, RTC_SEC);
+ rtc_write(dow, RTC_DOW);
+ rtc_enable_update();
+ spin_unlock_irqrestore(&ds1511_lock, flags);
+
+ return 0;
+}
+
+ int
+ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
+{
+ unsigned int century;
+ unsigned int flags;
+
+ spin_lock_irqsave(&ds1511_lock, flags);
+ rtc_disable_update();
+
+ rtc_tm->tm_sec = rtc_read(RTC_SEC) & 0x7f;
+ rtc_tm->tm_min = rtc_read(RTC_MIN) & 0x7f;
+ rtc_tm->tm_hour = rtc_read(RTC_HOUR) & 0x3f;
+ rtc_tm->tm_mday = rtc_read(RTC_DOM) & 0x3f;
+ rtc_tm->tm_wday = rtc_read(RTC_DOW) & 0x7;
+ rtc_tm->tm_mon = rtc_read(RTC_MON) & 0x1f;
+ rtc_tm->tm_year = rtc_read(RTC_YEAR) & 0x7f;
+ century = rtc_read(RTC_CENTURY);
+
+ rtc_enable_update();
+ spin_unlock_irqrestore(&ds1511_lock, flags);
+
+ rtc_tm->tm_sec = BCD2BIN(rtc_tm->tm_sec);
+ rtc_tm->tm_min = BCD2BIN(rtc_tm->tm_min);
+ rtc_tm->tm_hour = BCD2BIN(rtc_tm->tm_hour);
+ rtc_tm->tm_mday = BCD2BIN(rtc_tm->tm_mday);
+ rtc_tm->tm_wday = BCD2BIN(rtc_tm->tm_wday);
+ rtc_tm->tm_mon = BCD2BIN(rtc_tm->tm_mon);
+ rtc_tm->tm_year = BCD2BIN(rtc_tm->tm_year);
+ century = BCD2BIN(century) * 100;
+
+ /*
+ * Account for differences between how the RTC uses the values
+ * and how they are defined in a struct rtc_time;
+ */
+ century += rtc_tm->tm_year;
+ rtc_tm->tm_year = century - 1900;
+
+ rtc_tm->tm_mon--;
+
+ if (rtc_valid_tm(rtc_tm) < 0) {
+ dev_err(dev, "retrieved date/time is not valid.\n");
+ rtc_time_to_tm(0, rtc_tm);
+ }
+ return 0;
+}
+
+/*
+ * write the alarm register settings
+ *
+ * we only have the use to interrupt every second, otherwise
+ * known as the update interrupt, or the interrupt if the whole
+ * date/hours/mins/secs matches. the ds1511 has many more
+ * permutations, but the kernel doesn't.
+ */
+ static void
+ds1511_rtc_update_alarm(struct rtc_plat_data *pdata)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdata->rtc->irq_lock, flags);
+ rtc_write(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?
+ 0x80 : BIN2BCD(pdata->alrm_mday) & 0x3f,
+ RTC_ALARM_DATE);
+ rtc_write(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ?
+ 0x80 : BIN2BCD(pdata->alrm_hour) & 0x3f,
+ RTC_ALARM_HOUR);
+ rtc_write(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ?
+ 0x80 : BIN2BCD(pdata->alrm_min) & 0x7f,
+ RTC_ALARM_MIN);
+ rtc_write(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ?
+ 0x80 : BIN2BCD(pdata->alrm_sec) & 0x7f,
+ RTC_ALARM_SEC);
+ rtc_write(rtc_read(RTC_CMD) | (pdata->irqen ? RTC_TIE : 0), RTC_CMD);
+ rtc_read(RTC_CMD1); /* clear interrupts */
+ spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags);
+}
+
+ static int
+ds1511_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ if (pdata->irq < 0) {
+ return -EINVAL;
+ }
+ pdata->alrm_mday = alrm->time.tm_mday;
+ pdata->alrm_hour = alrm->time.tm_hour;
+ pdata->alrm_min = alrm->time.tm_min;
+ pdata->alrm_sec = alrm->time.tm_sec;
+ if (alrm->enabled) {
+ pdata->irqen |= RTC_AF;
+ }
+ ds1511_rtc_update_alarm(pdata);
+ return 0;
+}
+
+ static int
+ds1511_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ if (pdata->irq < 0) {
+ return -EINVAL;
+ }
+ alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday;
+ alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour;
+ alrm->time.tm_min = pdata->alrm_min < 0 ? 0 : pdata->alrm_min;
+ alrm->time.tm_sec = pdata->alrm_sec < 0 ? 0 : pdata->alrm_sec;
+ alrm->enabled = (pdata->irqen & RTC_AF) ? 1 : 0;
+ return 0;
+}
+
+ static irqreturn_t
+ds1511_interrupt(int irq, void *dev_id)
+{
+ struct platform_device *pdev = dev_id;
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ unsigned long events = RTC_IRQF;
+
+ /*
+ * read and clear interrupt
+ */
+ if (!(rtc_read(RTC_CMD1) & DS1511_IRQF)) {
+ return IRQ_NONE;
+ }
+ if (rtc_read(RTC_ALARM_SEC) & 0x80) {
+ events |= RTC_UF;
+ } else {
+ events |= RTC_AF;
+ }
+ rtc_update_irq(pdata->rtc, 1, events);
+ return IRQ_HANDLED;
+}
+
+ static void
+ds1511_rtc_release(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ if (pdata->irq >= 0) {
+ pdata->irqen = 0;
+ ds1511_rtc_update_alarm(pdata);
+ }
+}
+
+ static int
+ds1511_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ if (pdata->irq < 0) {
+ return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */
+ }
+ switch (cmd) {
+ case RTC_AIE_OFF:
+ pdata->irqen &= ~RTC_AF;
+ ds1511_rtc_update_alarm(pdata);
+ break;
+ case RTC_AIE_ON:
+ pdata->irqen |= RTC_AF;
+ ds1511_rtc_update_alarm(pdata);
+ break;
+ case RTC_UIE_OFF:
+ pdata->irqen &= ~RTC_UF;
+ ds1511_rtc_update_alarm(pdata);
+ break;
+ case RTC_UIE_ON:
+ pdata->irqen |= RTC_UF;
+ ds1511_rtc_update_alarm(pdata);
+ break;
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static const struct rtc_class_ops ds1511_rtc_ops = {
+ .read_time = ds1511_rtc_read_time,
+ .set_time = ds1511_rtc_set_time,
+ .read_alarm = ds1511_rtc_read_alarm,
+ .set_alarm = ds1511_rtc_set_alarm,
+ .release = ds1511_rtc_release,
+ .ioctl = ds1511_rtc_ioctl,
+};
+
+ static ssize_t
+ds1511_nvram_read(struct kobject *kobj, struct bin_attribute *ba,
+ char *buf, loff_t pos, size_t size)
+{
+ ssize_t count;
+
+ /*
+ * if count is more than one, turn on "burst" mode
+ * turn it off when you're done
+ */
+ if (size > 1) {
+ rtc_write((rtc_read(RTC_CMD) | DS1511_BME), RTC_CMD);
+ }
+ if (pos > DS1511_RAM_MAX) {
+ pos = DS1511_RAM_MAX;
+ }
+ if (size + pos > DS1511_RAM_MAX + 1) {
+ size = DS1511_RAM_MAX - pos + 1;
+ }
+ rtc_write(pos, DS1511_RAMADDR_LSB);
+ for (count = 0; size > 0; count++, size--) {
+ *buf++ = rtc_read(DS1511_RAMDATA);
+ }
+ if (count > 1) {
+ rtc_write((rtc_read(RTC_CMD) & ~DS1511_BME), RTC_CMD);
+ }
+ return count;
+}
+
+ static ssize_t
+ds1511_nvram_write(struct kobject *kobj, struct bin_attribute *bin_attr,
+ char *buf, loff_t pos, size_t size)
+{
+ ssize_t count;
+
+ /*
+ * if count is more than one, turn on "burst" mode
+ * turn it off when you're done
+ */
+ if (size > 1) {
+ rtc_write((rtc_read(RTC_CMD) | DS1511_BME), RTC_CMD);
+ }
+ if (pos > DS1511_RAM_MAX) {
+ pos = DS1511_RAM_MAX;
+ }
+ if (size + pos > DS1511_RAM_MAX + 1) {
+ size = DS1511_RAM_MAX - pos + 1;
+ }
+ rtc_write(pos, DS1511_RAMADDR_LSB);
+ for (count = 0; size > 0; count++, size--) {
+ rtc_write(*buf++, DS1511_RAMDATA);
+ }
+ if (count > 1) {
+ rtc_write((rtc_read(RTC_CMD) & ~DS1511_BME), RTC_CMD);
+ }
+ return count;
+}
+
+static struct bin_attribute ds1511_nvram_attr = {
+ .attr = {
+ .name = "nvram",
+ .mode = S_IRUGO | S_IWUGO,
+ .owner = THIS_MODULE,
+ },
+ .size = DS1511_RAM_MAX,
+ .read = ds1511_nvram_read,
+ .write = ds1511_nvram_write,
+};
+
+ static int __devinit
+ds1511_rtc_probe(struct platform_device *pdev)
+{
+ struct rtc_device *rtc;
+ struct resource *res;
+ struct rtc_plat_data *pdata = NULL;
+ int ret = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ return -ENODEV;
+ }
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ return -ENOMEM;
+ }
+ pdata->irq = -1;
+ pdata->size = res->end - res->start + 1;
+ if (!request_mem_region(res->start, pdata->size, pdev->name)) {
+ ret = -EBUSY;
+ goto out;
+ }
+ pdata->baseaddr = res->start;
+ pdata->size = pdata->size;
+ ds1511_base = ioremap(pdata->baseaddr, pdata->size);
+ if (!ds1511_base) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ pdata->ioaddr = ds1511_base;
+ pdata->irq = platform_get_irq(pdev, 0);
+
+ /*
+ * turn on the clock and the crystal, etc.
+ */
+ rtc_write(0, RTC_CMD);
+ rtc_write(0, RTC_CMD1);
+ /*
+ * clear the wdog counter
+ */
+ rtc_write(0, DS1511_WD_MSEC);
+ rtc_write(0, DS1511_WD_SEC);
+ /*
+ * start the clock
+ */
+ rtc_enable_update();
+
+ /*
+ * check for a dying bat-tree
+ */
+ if (rtc_read(RTC_CMD1) & DS1511_BLF1) {
+ dev_warn(&pdev->dev, "voltage-low detected.\n");
+ }
+
+ /*
+ * if the platform has an interrupt in mind for this device,
+ * then by all means, set it
+ */
+ if (pdata->irq >= 0) {
+ rtc_read(RTC_CMD1);
+ if (request_irq(pdata->irq, ds1511_interrupt,
+ IRQF_DISABLED | IRQF_SHARED, pdev->name, pdev) < 0) {
+
+ dev_warn(&pdev->dev, "interrupt not available.\n");
+ pdata->irq = -1;
+ }
+ }
+
+ rtc = rtc_device_register(pdev->name, &pdev->dev, &ds1511_rtc_ops,
+ THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ ret = PTR_ERR(rtc);
+ goto out;
+ }
+ pdata->rtc = rtc;
+ platform_set_drvdata(pdev, pdata);
+ ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr);
+ if (ret) {
+ goto out;
+ }
+ return 0;
+ out:
+ if (pdata->rtc) {
+ rtc_device_unregister(pdata->rtc);
+ }
+ if (pdata->irq >= 0) {
+ free_irq(pdata->irq, pdev);
+ }
+ if (ds1511_base) {
+ iounmap(ds1511_base);
+ ds1511_base = NULL;
+ }
+ if (pdata->baseaddr) {
+ release_mem_region(pdata->baseaddr, pdata->size);
+ }
+
+ kfree(pdata);
+ return ret;
+}
+
+ static int __devexit
+ds1511_rtc_remove(struct platform_device *pdev)
+{
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ sysfs_remove_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr);
+ rtc_device_unregister(pdata->rtc);
+ pdata->rtc = NULL;
+ if (pdata->irq >= 0) {
+ /*
+ * disable the alarm interrupt
+ */
+ rtc_write(rtc_read(RTC_CMD) & ~RTC_TIE, RTC_CMD);
+ rtc_read(RTC_CMD1);
+ free_irq(pdata->irq, pdev);
+ }
+ iounmap(pdata->ioaddr);
+ ds1511_base = NULL;
+ release_mem_region(pdata->baseaddr, pdata->size);
+ kfree(pdata);
+ return 0;
+}
+
+static struct platform_driver ds1511_rtc_driver = {
+ .probe = ds1511_rtc_probe,
+ .remove = __devexit_p(ds1511_rtc_remove),
+ .driver = {
+ .name = "ds1511",
+ .owner = THIS_MODULE,
+ },
+};
+
+ static int __init
+ds1511_rtc_init(void)
+{
+ return platform_driver_register(&ds1511_rtc_driver);
+}
+
+ static void __exit
+ds1511_rtc_exit(void)
+{
+ return platform_driver_unregister(&ds1511_rtc_driver);
+}
+
+module_init(ds1511_rtc_init);
+module_exit(ds1511_rtc_exit);
+
+MODULE_AUTHOR("Andrew Sharp <andy.sharp@onstor.com>");
+MODULE_DESCRIPTION("Dallas DS1511 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c
index c973ba94c42..8b399700750 100644
--- a/drivers/rtc/rtc-pcf8583.c
+++ b/drivers/rtc/rtc-pcf8583.c
@@ -163,27 +163,17 @@ static int pcf8583_read_mem(struct i2c_client *client, struct rtc_mem *mem)
static int pcf8583_write_mem(struct i2c_client *client, struct rtc_mem *mem)
{
- unsigned char addr[1];
- struct i2c_msg msgs[2] = {
- {
- .addr = client->addr,
- .flags = 0,
- .len = 1,
- .buf = addr,
- }, {
- .addr = client->addr,
- .flags = I2C_M_NOSTART,
- .len = mem->nr,
- .buf = mem->data,
- }
- };
+ unsigned char buf[9];
+ int ret;
- if (mem->loc < 8)
+ if (mem->loc < 8 || mem->nr > 8)
return -EINVAL;
- addr[0] = mem->loc;
+ buf[0] = mem->loc;
+ memcpy(buf + 1, mem->data, mem->nr);
- return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO;
+ ret = i2c_master_send(client, buf, mem->nr + 1);
+ return ret == mem->nr + 1 ? 0 : -EIO;
}
static int pcf8583_rtc_read_time(struct device *dev, struct rtc_time *tm)
diff --git a/drivers/rtc/rtc-r9701.c b/drivers/rtc/rtc-r9701.c
new file mode 100644
index 00000000000..a64626a82d0
--- /dev/null
+++ b/drivers/rtc/rtc-r9701.c
@@ -0,0 +1,178 @@
+/*
+ * Driver for Epson RTC-9701JE
+ *
+ * Copyright (C) 2008 Magnus Damm
+ *
+ * Based on rtc-max6902.c
+ *
+ * Copyright (C) 2006 8D Technologies inc.
+ * Copyright (C) 2004 Compulab 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.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/rtc.h>
+#include <linux/spi/spi.h>
+#include <linux/bcd.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+
+#define RSECCNT 0x00 /* Second Counter */
+#define RMINCNT 0x01 /* Minute Counter */
+#define RHRCNT 0x02 /* Hour Counter */
+#define RWKCNT 0x03 /* Week Counter */
+#define RDAYCNT 0x04 /* Day Counter */
+#define RMONCNT 0x05 /* Month Counter */
+#define RYRCNT 0x06 /* Year Counter */
+#define R100CNT 0x07 /* Y100 Counter */
+#define RMINAR 0x08 /* Minute Alarm */
+#define RHRAR 0x09 /* Hour Alarm */
+#define RWKAR 0x0a /* Week/Day Alarm */
+#define RTIMCNT 0x0c /* Interval Timer */
+#define REXT 0x0d /* Extension Register */
+#define RFLAG 0x0e /* RTC Flag Register */
+#define RCR 0x0f /* RTC Control Register */
+
+static int write_reg(struct device *dev, int address, unsigned char data)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ unsigned char buf[2];
+
+ buf[0] = address & 0x7f;
+ buf[1] = data;
+
+ return spi_write(spi, buf, ARRAY_SIZE(buf));
+}
+
+static int read_regs(struct device *dev, unsigned char *regs, int no_regs)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ u8 txbuf[1], rxbuf[1];
+ int k, ret;
+
+ ret = 0;
+
+ for (k = 0; ret == 0 && k < no_regs; k++) {
+ txbuf[0] = 0x80 | regs[k];
+ ret = spi_write_then_read(spi, txbuf, 1, rxbuf, 1);
+ regs[k] = rxbuf[0];
+ }
+
+ return ret;
+}
+
+static int r9701_get_datetime(struct device *dev, struct rtc_time *dt)
+{
+ unsigned long time;
+ int ret;
+ unsigned char buf[] = { RSECCNT, RMINCNT, RHRCNT,
+ RDAYCNT, RMONCNT, RYRCNT };
+
+ ret = read_regs(dev, buf, ARRAY_SIZE(buf));
+ if (ret)
+ return ret;
+
+ memset(dt, 0, sizeof(*dt));
+
+ dt->tm_sec = BCD2BIN(buf[0]); /* RSECCNT */
+ dt->tm_min = BCD2BIN(buf[1]); /* RMINCNT */
+ dt->tm_hour = BCD2BIN(buf[2]); /* RHRCNT */
+
+ dt->tm_mday = BCD2BIN(buf[3]); /* RDAYCNT */
+ dt->tm_mon = BCD2BIN(buf[4]) - 1; /* RMONCNT */
+ dt->tm_year = BCD2BIN(buf[5]) + 100; /* RYRCNT */
+
+ /* the rtc device may contain illegal values on power up
+ * according to the data sheet. make sure they are valid.
+ */
+
+ return rtc_valid_tm(dt);
+}
+
+static int r9701_set_datetime(struct device *dev, struct rtc_time *dt)
+{
+ int ret, year;
+
+ year = dt->tm_year + 1900;
+ if (year >= 2100 || year < 2000)
+ return -EINVAL;
+
+ ret = write_reg(dev, RHRCNT, BIN2BCD(dt->tm_hour));
+ ret = ret ? ret : write_reg(dev, RMINCNT, BIN2BCD(dt->tm_min));
+ ret = ret ? ret : write_reg(dev, RSECCNT, BIN2BCD(dt->tm_sec));
+ ret = ret ? ret : write_reg(dev, RDAYCNT, BIN2BCD(dt->tm_mday));
+ ret = ret ? ret : write_reg(dev, RMONCNT, BIN2BCD(dt->tm_mon + 1));
+ ret = ret ? ret : write_reg(dev, RYRCNT, BIN2BCD(dt->tm_year - 100));
+ ret = ret ? ret : write_reg(dev, RWKCNT, 1 << dt->tm_wday);
+
+ return ret;
+}
+
+static const struct rtc_class_ops r9701_rtc_ops = {
+ .read_time = r9701_get_datetime,
+ .set_time = r9701_set_datetime,
+};
+
+static int __devinit r9701_probe(struct spi_device *spi)
+{
+ struct rtc_device *rtc;
+ unsigned char tmp;
+ int res;
+
+ rtc = rtc_device_register("r9701",
+ &spi->dev, &r9701_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
+
+ dev_set_drvdata(&spi->dev, rtc);
+
+ tmp = R100CNT;
+ res = read_regs(&spi->dev, &tmp, 1);
+ if (res || tmp != 0x20) {
+ rtc_device_unregister(rtc);
+ return res;
+ }
+
+ return 0;
+}
+
+static int __devexit r9701_remove(struct spi_device *spi)
+{
+ struct rtc_device *rtc = dev_get_drvdata(&spi->dev);
+
+ rtc_device_unregister(rtc);
+ return 0;
+}
+
+static struct spi_driver r9701_driver = {
+ .driver = {
+ .name = "rtc-r9701",
+ .owner = THIS_MODULE,
+ },
+ .probe = r9701_probe,
+ .remove = __devexit_p(r9701_remove),
+};
+
+static __init int r9701_init(void)
+{
+ return spi_register_driver(&r9701_driver);
+}
+module_init(r9701_init);
+
+static __exit void r9701_exit(void)
+{
+ spi_unregister_driver(&r9701_driver);
+}
+module_exit(r9701_exit);
+
+MODULE_DESCRIPTION("r9701 spi RTC driver");
+MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index e2041b4d0c8..86766f1f249 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -20,6 +20,7 @@
#include <linux/rtc.h>
#include <linux/bcd.h>
#include <linux/clk.h>
+#include <linux/log2.h>
#include <asm/hardware.h>
#include <asm/uaccess.h>
@@ -309,9 +310,7 @@ static int s3c_rtc_ioctl(struct device *dev,
break;
case RTC_IRQP_SET:
- /* check for power of 2 */
-
- if ((arg & (arg-1)) != 0 || arg < 1) {
+ if (!is_power_of_2(arg)) {
ret = -EINVAL;
goto exit;
}
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index 2eb38520f0c..ee253cc45de 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -357,23 +357,15 @@ static int sa1100_rtc_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
static int sa1100_rtc_suspend(struct platform_device *pdev, pm_message_t state)
{
- if (pdev->dev.power.power_state.event != state.event) {
- if (state.event == PM_EVENT_SUSPEND &&
- device_may_wakeup(&pdev->dev))
- enable_irq_wake(IRQ_RTCAlrm);
-
- pdev->dev.power.power_state = state;
- }
+ if (device_may_wakeup(&pdev->dev))
+ enable_irq_wake(IRQ_RTCAlrm);
return 0;
}
static int sa1100_rtc_resume(struct platform_device *pdev)
{
- if (pdev->dev.power.power_state.event != PM_EVENT_ON) {
- if (device_may_wakeup(&pdev->dev))
- disable_irq_wake(IRQ_RTCAlrm);
- pdev->dev.power.power_state = PMSG_ON;
- }
+ if (device_may_wakeup(&pdev->dev))
+ disable_irq_wake(IRQ_RTCAlrm);
return 0;
}
#else
diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c
index 2ae0e8304d3..4d27ccc4fc0 100644
--- a/drivers/rtc/rtc-sysfs.c
+++ b/drivers/rtc/rtc-sysfs.c
@@ -17,6 +17,13 @@
/* device attributes */
+/*
+ * NOTE: RTC times displayed in sysfs use the RTC's timezone. That's
+ * ideally UTC. However, PCs that also boot to MS-Windows normally use
+ * the local time and change to match daylight savings time. That affects
+ * attributes including date, time, since_epoch, and wakealarm.
+ */
+
static ssize_t
rtc_sysfs_show_name(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -113,13 +120,13 @@ rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr,
unsigned long alarm;
struct rtc_wkalrm alm;
- /* Don't show disabled alarms; but the RTC could leave the
- * alarm enabled after it's already triggered. Alarms are
- * conceptually one-shot, even though some common hardware
- * (PCs) doesn't actually work that way.
+ /* Don't show disabled alarms. For uniformity, RTC alarms are
+ * conceptually one-shot, even though some common RTCs (on PCs)
+ * don't actually work that way.
*
- * REVISIT maybe we should require RTC implementations to
- * disable the RTC alarm after it triggers, for uniformity.
+ * NOTE: RTC implementations where the alarm doesn't match an
+ * exact YYYY-MM-DD HH:MM[:SS] date *must* disable their RTC
+ * alarms after they trigger, to ensure one-shot semantics.
*/
retval = rtc_read_alarm(to_rtc_device(dev), &alm);
if (retval == 0 && alm.enabled) {
diff --git a/drivers/s390/sysinfo.c b/drivers/s390/sysinfo.c
index 19343f9675c..291ff6235fe 100644
--- a/drivers/s390/sysinfo.c
+++ b/drivers/s390/sysinfo.c
@@ -422,7 +422,7 @@ void s390_adjust_jiffies(void)
/*
* calibrate the delay loop
*/
-void __init calibrate_delay(void)
+void __cpuinit calibrate_delay(void)
{
s390_adjust_jiffies();
/* Print the good old Bogomips line .. */
diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
index 23f27c9c989..5ac3a3e8dfa 100644
--- a/drivers/scsi/a2091.c
+++ b/drivers/scsi/a2091.c
@@ -46,8 +46,7 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
struct Scsi_Host *instance = cmd->device->host;
/* don't allow DMA if the physical address is bad */
- if (addr & A2091_XFER_MASK ||
- (!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual)))
+ if (addr & A2091_XFER_MASK)
{
HDATA(instance)->dma_bounce_len = (cmd->SCp.this_residual + 511)
& ~0x1ff;
diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c
index d7255c8bf28..3aeec963940 100644
--- a/drivers/scsi/a3000.c
+++ b/drivers/scsi/a3000.c
@@ -54,8 +54,7 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
* end of a physical memory chunk, then allocate a bounce
* buffer
*/
- if (addr & A3000_XFER_MASK ||
- (!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual)))
+ if (addr & A3000_XFER_MASK)
{
HDATA(a3000_host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
& ~0x1ff;
diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
index 3bfd9296bbf..93984c9dfe1 100644
--- a/drivers/scsi/aic7xxx_old.c
+++ b/drivers/scsi/aic7xxx_old.c
@@ -6472,7 +6472,7 @@ do_aic7xxx_isr(int irq, void *dev_id)
unsigned long cpu_flags;
struct aic7xxx_host *p;
- p = (struct aic7xxx_host *)dev_id;
+ p = dev_id;
if(!p)
return IRQ_NONE;
spin_lock_irqsave(p->host->host_lock, cpu_flags);
diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c
index 37741e9b5c3..91f85226d08 100644
--- a/drivers/scsi/gvp11.c
+++ b/drivers/scsi/gvp11.c
@@ -54,8 +54,7 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
static int scsi_alloc_out_of_range = 0;
/* use bounce buffer if the physical address is bad */
- if (addr & HDATA(cmd->device->host)->dma_xfer_mask ||
- (!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual)))
+ if (addr & HDATA(cmd->device->host)->dma_xfer_mask)
{
HDATA(cmd->device->host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
& ~0x1ff;
diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c
index d63f11e95ab..bd62131b97a 100644
--- a/drivers/scsi/ibmvscsi/ibmvstgt.c
+++ b/drivers/scsi/ibmvscsi/ibmvstgt.c
@@ -539,9 +539,9 @@ out:
srp_iu_put(iue);
}
-static irqreturn_t ibmvstgt_interrupt(int irq, void *data)
+static irqreturn_t ibmvstgt_interrupt(int dummy, void *data)
{
- struct srp_target *target = (struct srp_target *) data;
+ struct srp_target *target = data;
struct vio_port *vport = target_to_port(target);
vio_disable_interrupts(vport->dma_dev);
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 6c4f0f08178..68e5c632c5d 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -287,7 +287,7 @@ static int idescsi_end_request(ide_drive_t *, int, int);
static ide_startstop_t
idescsi_atapi_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err)
{
- if (HWIF(drive)->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))
+ if (ide_read_status(drive) & (BUSY_STAT | DRQ_STAT))
/* force an abort */
HWIF(drive)->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
@@ -423,7 +423,7 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
}
/* Clear the interrupt */
- stat = drive->hwif->INB(IDE_STATUS_REG);
+ stat = ide_read_status(drive);
if ((stat & DRQ_STAT) == 0) {
/* No more interrupts */
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 4fa7927997a..6a44fb1dc16 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -877,15 +877,15 @@ config SERIAL_SUNHV
systems. Say Y if you want to be able to use this device.
config SERIAL_IP22_ZILOG
- tristate "IP22 Zilog8530 serial support"
- depends on SGI_IP22
+ tristate "SGI Zilog8530 serial support"
+ depends on SGI_HAS_ZILOG
select SERIAL_CORE
help
- This driver supports the Zilog8530 serial ports found on SGI IP22
+ This driver supports the Zilog8530 serial ports found on SGI
systems. Say Y or M if you want to be able to these serial ports.
config SERIAL_IP22_ZILOG_CONSOLE
- bool "Console on IP22 Zilog8530 serial port"
+ bool "Console on SGI Zilog8530 serial port"
depends on SERIAL_IP22_ZILOG=y
select SERIAL_CORE_CONSOLE
@@ -1318,4 +1318,19 @@ config SERIAL_QE
This driver supports the QE serial ports on Freescale embedded
PowerPC that contain a QUICC Engine.
+config SERIAL_SC26XX
+ tristate "SC2681/SC2692 serial port support"
+ depends on SNI_RM
+ select SERIAL_CORE
+ help
+ This is a driver for the onboard serial ports of
+ older RM400 machines.
+
+config SERIAL_SC26XX_CONSOLE
+ bool "Console on SC2681/SC2692 serial port"
+ depends on SERIAL_SC26XX
+ select SERIAL_CORE_CONSOLE
+ help
+ Support for Console on SC2681/SC2692 serial ports.
+
endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 2dd41b4cc8d..640cfe44a56 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -55,6 +55,7 @@ obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o
obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
+obj-$(CONFIG_SERIAL_SC26XX) += sc26xx.o
obj-$(CONFIG_SERIAL_JSM) += jsm/
obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index b5e4478de0e..236af9d3385 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -380,7 +380,7 @@ static void cpm_uart_int_rx(struct uart_port *port)
static irqreturn_t cpm_uart_int(int irq, void *data)
{
u8 events;
- struct uart_port *port = (struct uart_port *)data;
+ struct uart_port *port = data;
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
smc_t __iomem *smcp = pinfo->smcp;
scc_t __iomem *sccp = pinfo->sccp;
diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c
index d31721f2744..bbae5a22021 100644
--- a/drivers/serial/dz.c
+++ b/drivers/serial/dz.c
@@ -324,7 +324,7 @@ static inline void check_modem_status(struct dz_port *dport)
*/
static irqreturn_t dz_interrupt(int irq, void *dev)
{
- struct dz_port *dport = (struct dz_port *)dev;
+ struct dz_port *dport = dev;
unsigned short status;
/* get the reason why we just got an irq */
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index dc1967176fe..56af1f566a4 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -308,7 +308,7 @@ static void imx_start_tx(struct uart_port *port)
static irqreturn_t imx_rtsint(int irq, void *dev_id)
{
- struct imx_port *sport = (struct imx_port *)dev_id;
+ struct imx_port *sport = dev_id;
unsigned int val = readl(sport->port.membase + USR1) & USR1_RTSS;
unsigned long flags;
@@ -324,7 +324,7 @@ static irqreturn_t imx_rtsint(int irq, void *dev_id)
static irqreturn_t imx_txint(int irq, void *dev_id)
{
- struct imx_port *sport = (struct imx_port *)dev_id;
+ struct imx_port *sport = dev_id;
struct circ_buf *xmit = &sport->port.info->xmit;
unsigned long flags;
diff --git a/drivers/serial/sc26xx.c b/drivers/serial/sc26xx.c
new file mode 100644
index 00000000000..a350b6d2a18
--- /dev/null
+++ b/drivers/serial/sc26xx.c
@@ -0,0 +1,755 @@
+/*
+ * SC268xx.c: Serial driver for Philiphs SC2681/SC2692 devices.
+ *
+ * Copyright (C) 2006,2007 Thomas Bogendörfer (tsbogend@alpha.franken.de)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+
+#if defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#define SC26XX_MAJOR 204
+#define SC26XX_MINOR_START 205
+#define SC26XX_NR 2
+
+struct uart_sc26xx_port {
+ struct uart_port port[2];
+ u8 dsr_mask[2];
+ u8 cts_mask[2];
+ u8 dcd_mask[2];
+ u8 ri_mask[2];
+ u8 dtr_mask[2];
+ u8 rts_mask[2];
+ u8 imr;
+};
+
+/* register common to both ports */
+#define RD_ISR 0x14
+#define RD_IPR 0x34
+
+#define WR_ACR 0x10
+#define WR_IMR 0x14
+#define WR_OPCR 0x34
+#define WR_OPR_SET 0x38
+#define WR_OPR_CLR 0x3C
+
+/* access common register */
+#define READ_SC(p, r) readb((p)->membase + RD_##r)
+#define WRITE_SC(p, r, v) writeb((v), (p)->membase + WR_##r)
+
+/* register per port */
+#define RD_PORT_MRx 0x00
+#define RD_PORT_SR 0x04
+#define RD_PORT_RHR 0x0c
+
+#define WR_PORT_MRx 0x00
+#define WR_PORT_CSR 0x04
+#define WR_PORT_CR 0x08
+#define WR_PORT_THR 0x0c
+
+/* SR bits */
+#define SR_BREAK (1 << 7)
+#define SR_FRAME (1 << 6)
+#define SR_PARITY (1 << 5)
+#define SR_OVERRUN (1 << 4)
+#define SR_TXRDY (1 << 2)
+#define SR_RXRDY (1 << 0)
+
+#define CR_RES_MR (1 << 4)
+#define CR_RES_RX (2 << 4)
+#define CR_RES_TX (3 << 4)
+#define CR_STRT_BRK (6 << 4)
+#define CR_STOP_BRK (7 << 4)
+#define CR_DIS_TX (1 << 3)
+#define CR_ENA_TX (1 << 2)
+#define CR_DIS_RX (1 << 1)
+#define CR_ENA_RX (1 << 0)
+
+/* ISR bits */
+#define ISR_RXRDYB (1 << 5)
+#define ISR_TXRDYB (1 << 4)
+#define ISR_RXRDYA (1 << 1)
+#define ISR_TXRDYA (1 << 0)
+
+/* IMR bits */
+#define IMR_RXRDY (1 << 1)
+#define IMR_TXRDY (1 << 0)
+
+/* access port register */
+static inline u8 read_sc_port(struct uart_port *p, u8 reg)
+{
+ return readb(p->membase + p->line * 0x20 + reg);
+}
+
+static inline void write_sc_port(struct uart_port *p, u8 reg, u8 val)
+{
+ writeb(val, p->membase + p->line * 0x20 + reg);
+}
+
+#define READ_SC_PORT(p, r) read_sc_port(p, RD_PORT_##r)
+#define WRITE_SC_PORT(p, r, v) write_sc_port(p, WR_PORT_##r, v)
+
+static void sc26xx_enable_irq(struct uart_port *port, int mask)
+{
+ struct uart_sc26xx_port *up;
+ int line = port->line;
+
+ port -= line;
+ up = container_of(port, struct uart_sc26xx_port, port[0]);
+
+ up->imr |= mask << (line * 4);
+ WRITE_SC(port, IMR, up->imr);
+}
+
+static void sc26xx_disable_irq(struct uart_port *port, int mask)
+{
+ struct uart_sc26xx_port *up;
+ int line = port->line;
+
+ port -= line;
+ up = container_of(port, struct uart_sc26xx_port, port[0]);
+
+ up->imr &= ~(mask << (line * 4));
+ WRITE_SC(port, IMR, up->imr);
+}
+
+static struct tty_struct *receive_chars(struct uart_port *port)
+{
+ struct tty_struct *tty = NULL;
+ int limit = 10000;
+ unsigned char ch;
+ char flag;
+ u8 status;
+
+ if (port->info != NULL) /* Unopened serial console */
+ tty = port->info->tty;
+
+ while (limit-- > 0) {
+ status = READ_SC_PORT(port, SR);
+ if (!(status & SR_RXRDY))
+ break;
+ ch = READ_SC_PORT(port, RHR);
+
+ flag = TTY_NORMAL;
+ port->icount.rx++;
+
+ if (unlikely(status & (SR_BREAK | SR_FRAME |
+ SR_PARITY | SR_OVERRUN))) {
+ if (status & SR_BREAK) {
+ status &= ~(SR_PARITY | SR_FRAME);
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ continue;
+ } else if (status & SR_PARITY)
+ port->icount.parity++;
+ else if (status & SR_FRAME)
+ port->icount.frame++;
+ if (status & SR_OVERRUN)
+ port->icount.overrun++;
+
+ status &= port->read_status_mask;
+ if (status & SR_BREAK)
+ flag = TTY_BREAK;
+ else if (status & SR_PARITY)
+ flag = TTY_PARITY;
+ else if (status & SR_FRAME)
+ flag = TTY_FRAME;
+ }
+
+ if (uart_handle_sysrq_char(port, ch))
+ continue;
+
+ if (status & port->ignore_status_mask)
+ continue;
+
+ tty_insert_flip_char(tty, ch, flag);
+ }
+ return tty;
+}
+
+static void transmit_chars(struct uart_port *port)
+{
+ struct circ_buf *xmit;
+
+ if (!port->info)
+ return;
+
+ xmit = &port->info->xmit;
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ sc26xx_disable_irq(port, IMR_TXRDY);
+ return;
+ }
+ while (!uart_circ_empty(xmit)) {
+ if (!(READ_SC_PORT(port, SR) & SR_TXRDY))
+ break;
+
+ WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ }
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+}
+
+static irqreturn_t sc26xx_interrupt(int irq, void *dev_id)
+{
+ struct uart_sc26xx_port *up = dev_id;
+ struct tty_struct *tty;
+ unsigned long flags;
+ u8 isr;
+
+ spin_lock_irqsave(&up->port[0].lock, flags);
+
+ tty = NULL;
+ isr = READ_SC(&up->port[0], ISR);
+ if (isr & ISR_TXRDYA)
+ transmit_chars(&up->port[0]);
+ if (isr & ISR_RXRDYA)
+ tty = receive_chars(&up->port[0]);
+
+ spin_unlock(&up->port[0].lock);
+
+ if (tty)
+ tty_flip_buffer_push(tty);
+
+ spin_lock(&up->port[1].lock);
+
+ tty = NULL;
+ if (isr & ISR_TXRDYB)
+ transmit_chars(&up->port[1]);
+ if (isr & ISR_RXRDYB)
+ tty = receive_chars(&up->port[1]);
+
+ spin_unlock_irqrestore(&up->port[1].lock, flags);
+
+ if (tty)
+ tty_flip_buffer_push(tty);
+
+ return IRQ_HANDLED;
+}
+
+/* port->lock is not held. */
+static unsigned int sc26xx_tx_empty(struct uart_port *port)
+{
+ return (READ_SC_PORT(port, SR) & SR_TXRDY) ? TIOCSER_TEMT : 0;
+}
+
+/* port->lock held by caller. */
+static void sc26xx_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ struct uart_sc26xx_port *up;
+ int line = port->line;
+
+ port -= line;
+ up = container_of(port, struct uart_sc26xx_port, port[0]);
+
+ if (up->dtr_mask[line]) {
+ if (mctrl & TIOCM_DTR)
+ WRITE_SC(port, OPR_SET, up->dtr_mask[line]);
+ else
+ WRITE_SC(port, OPR_CLR, up->dtr_mask[line]);
+ }
+ if (up->rts_mask[line]) {
+ if (mctrl & TIOCM_RTS)
+ WRITE_SC(port, OPR_SET, up->rts_mask[line]);
+ else
+ WRITE_SC(port, OPR_CLR, up->rts_mask[line]);
+ }
+}
+
+/* port->lock is held by caller and interrupts are disabled. */
+static unsigned int sc26xx_get_mctrl(struct uart_port *port)
+{
+ struct uart_sc26xx_port *up;
+ int line = port->line;
+ unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR;
+ u8 ipr;
+
+ port -= line;
+ up = container_of(port, struct uart_sc26xx_port, port[0]);
+ ipr = READ_SC(port, IPR) ^ 0xff;
+
+ if (up->dsr_mask[line]) {
+ mctrl &= ~TIOCM_DSR;
+ mctrl |= ipr & up->dsr_mask[line] ? TIOCM_DSR : 0;
+ }
+ if (up->cts_mask[line]) {
+ mctrl &= ~TIOCM_CTS;
+ mctrl |= ipr & up->cts_mask[line] ? TIOCM_CTS : 0;
+ }
+ if (up->dcd_mask[line]) {
+ mctrl &= ~TIOCM_CAR;
+ mctrl |= ipr & up->dcd_mask[line] ? TIOCM_CAR : 0;
+ }
+ if (up->ri_mask[line]) {
+ mctrl &= ~TIOCM_RNG;
+ mctrl |= ipr & up->ri_mask[line] ? TIOCM_RNG : 0;
+ }
+ return mctrl;
+}
+
+/* port->lock held by caller. */
+static void sc26xx_stop_tx(struct uart_port *port)
+{
+ return;
+}
+
+/* port->lock held by caller. */
+static void sc26xx_start_tx(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->info->xmit;
+
+ while (!uart_circ_empty(xmit)) {
+ if (!(READ_SC_PORT(port, SR) & SR_TXRDY)) {
+ sc26xx_enable_irq(port, IMR_TXRDY);
+ break;
+ }
+ WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ }
+}
+
+/* port->lock held by caller. */
+static void sc26xx_stop_rx(struct uart_port *port)
+{
+}
+
+/* port->lock held by caller. */
+static void sc26xx_enable_ms(struct uart_port *port)
+{
+}
+
+/* port->lock is not held. */
+static void sc26xx_break_ctl(struct uart_port *port, int break_state)
+{
+ if (break_state == -1)
+ WRITE_SC_PORT(port, CR, CR_STRT_BRK);
+ else
+ WRITE_SC_PORT(port, CR, CR_STOP_BRK);
+}
+
+/* port->lock is not held. */
+static int sc26xx_startup(struct uart_port *port)
+{
+ sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY);
+ WRITE_SC(port, OPCR, 0);
+
+ /* reset tx and rx */
+ WRITE_SC_PORT(port, CR, CR_RES_RX);
+ WRITE_SC_PORT(port, CR, CR_RES_TX);
+
+ /* start rx/tx */
+ WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX);
+
+ /* enable irqs */
+ sc26xx_enable_irq(port, IMR_RXRDY);
+ return 0;
+}
+
+/* port->lock is not held. */
+static void sc26xx_shutdown(struct uart_port *port)
+{
+ /* disable interrupst */
+ sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY);
+
+ /* stop tx/rx */
+ WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX);
+}
+
+/* port->lock is not held. */
+static void sc26xx_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
+{
+ unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
+ unsigned int quot = uart_get_divisor(port, baud);
+ unsigned int iflag, cflag;
+ unsigned long flags;
+ u8 mr1, mr2, csr;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc)
+ udelay(2);
+
+ WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX);
+
+ iflag = termios->c_iflag;
+ cflag = termios->c_cflag;
+
+ port->read_status_mask = SR_OVERRUN;
+ if (iflag & INPCK)
+ port->read_status_mask |= SR_PARITY | SR_FRAME;
+ if (iflag & (BRKINT | PARMRK))
+ port->read_status_mask |= SR_BREAK;
+
+ port->ignore_status_mask = 0;
+ if (iflag & IGNBRK)
+ port->ignore_status_mask |= SR_BREAK;
+ if ((cflag & CREAD) == 0)
+ port->ignore_status_mask |= SR_BREAK | SR_FRAME |
+ SR_PARITY | SR_OVERRUN;
+
+ switch (cflag & CSIZE) {
+ case CS5:
+ mr1 = 0x00;
+ break;
+ case CS6:
+ mr1 = 0x01;
+ break;
+ case CS7:
+ mr1 = 0x02;
+ break;
+ default:
+ case CS8:
+ mr1 = 0x03;
+ break;
+ }
+ mr2 = 0x07;
+ if (cflag & CSTOPB)
+ mr2 = 0x0f;
+ if (cflag & PARENB) {
+ if (cflag & PARODD)
+ mr1 |= (1 << 2);
+ } else
+ mr1 |= (2 << 3);
+
+ switch (baud) {
+ case 50:
+ csr = 0x00;
+ break;
+ case 110:
+ csr = 0x11;
+ break;
+ case 134:
+ csr = 0x22;
+ break;
+ case 200:
+ csr = 0x33;
+ break;
+ case 300:
+ csr = 0x44;
+ break;
+ case 600:
+ csr = 0x55;
+ break;
+ case 1200:
+ csr = 0x66;
+ break;
+ case 2400:
+ csr = 0x88;
+ break;
+ case 4800:
+ csr = 0x99;
+ break;
+ default:
+ case 9600:
+ csr = 0xbb;
+ break;
+ case 19200:
+ csr = 0xcc;
+ break;
+ }
+
+ WRITE_SC_PORT(port, CR, CR_RES_MR);
+ WRITE_SC_PORT(port, MRx, mr1);
+ WRITE_SC_PORT(port, MRx, mr2);
+
+ WRITE_SC(port, ACR, 0x80);
+ WRITE_SC_PORT(port, CSR, csr);
+
+ /* reset tx and rx */
+ WRITE_SC_PORT(port, CR, CR_RES_RX);
+ WRITE_SC_PORT(port, CR, CR_RES_TX);
+
+ WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX);
+ while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc)
+ udelay(2);
+
+ /* XXX */
+ uart_update_timeout(port, cflag,
+ (port->uartclk / (16 * quot)));
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *sc26xx_type(struct uart_port *port)
+{
+ return "SC26XX";
+}
+
+static void sc26xx_release_port(struct uart_port *port)
+{
+}
+
+static int sc26xx_request_port(struct uart_port *port)
+{
+ return 0;
+}
+
+static void sc26xx_config_port(struct uart_port *port, int flags)
+{
+}
+
+static int sc26xx_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ return -EINVAL;
+}
+
+static struct uart_ops sc26xx_ops = {
+ .tx_empty = sc26xx_tx_empty,
+ .set_mctrl = sc26xx_set_mctrl,
+ .get_mctrl = sc26xx_get_mctrl,
+ .stop_tx = sc26xx_stop_tx,
+ .start_tx = sc26xx_start_tx,
+ .stop_rx = sc26xx_stop_rx,
+ .enable_ms = sc26xx_enable_ms,
+ .break_ctl = sc26xx_break_ctl,
+ .startup = sc26xx_startup,
+ .shutdown = sc26xx_shutdown,
+ .set_termios = sc26xx_set_termios,
+ .type = sc26xx_type,
+ .release_port = sc26xx_release_port,
+ .request_port = sc26xx_request_port,
+ .config_port = sc26xx_config_port,
+ .verify_port = sc26xx_verify_port,
+};
+
+static struct uart_port *sc26xx_port;
+
+#ifdef CONFIG_SERIAL_SC26XX_CONSOLE
+static void sc26xx_console_putchar(struct uart_port *port, char c)
+{
+ unsigned long flags;
+ int limit = 1000000;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ while (limit-- > 0) {
+ if (READ_SC_PORT(port, SR) & SR_TXRDY) {
+ WRITE_SC_PORT(port, THR, c);
+ break;
+ }
+ udelay(2);
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void sc26xx_console_write(struct console *con, const char *s, unsigned n)
+{
+ struct uart_port *port = sc26xx_port;
+ int i;
+
+ for (i = 0; i < n; i++) {
+ if (*s == '\n')
+ sc26xx_console_putchar(port, '\r');
+ sc26xx_console_putchar(port, *s++);
+ }
+}
+
+static int __init sc26xx_console_setup(struct console *con, char *options)
+{
+ struct uart_port *port = sc26xx_port;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (port->type != PORT_SC26XX)
+ return -1;
+
+ printk(KERN_INFO "Console: ttySC%d (SC26XX)\n", con->index);
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(port, con, baud, parity, bits, flow);
+}
+
+static struct uart_driver sc26xx_reg;
+static struct console sc26xx_console = {
+ .name = "ttySC",
+ .write = sc26xx_console_write,
+ .device = uart_console_device,
+ .setup = sc26xx_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &sc26xx_reg,
+};
+#define SC26XX_CONSOLE &sc26xx_console
+#else
+#define SC26XX_CONSOLE NULL
+#endif
+
+static struct uart_driver sc26xx_reg = {
+ .owner = THIS_MODULE,
+ .driver_name = "SC26xx",
+ .dev_name = "ttySC",
+ .major = SC26XX_MAJOR,
+ .minor = SC26XX_MINOR_START,
+ .nr = SC26XX_NR,
+ .cons = SC26XX_CONSOLE,
+};
+
+static u8 sc26xx_flags2mask(unsigned int flags, unsigned int bitpos)
+{
+ unsigned int bit = (flags >> bitpos) & 15;
+
+ return bit ? (1 << (bit - 1)) : 0;
+}
+
+static void __devinit sc26xx_init_masks(struct uart_sc26xx_port *up,
+ int line, unsigned int data)
+{
+ up->dtr_mask[line] = sc26xx_flags2mask(data, 0);
+ up->rts_mask[line] = sc26xx_flags2mask(data, 4);
+ up->dsr_mask[line] = sc26xx_flags2mask(data, 8);
+ up->cts_mask[line] = sc26xx_flags2mask(data, 12);
+ up->dcd_mask[line] = sc26xx_flags2mask(data, 16);
+ up->ri_mask[line] = sc26xx_flags2mask(data, 20);
+}
+
+static int __devinit sc26xx_probe(struct platform_device *dev)
+{
+ struct resource *res;
+ struct uart_sc26xx_port *up;
+ unsigned int *sc26xx_data = dev->dev.platform_data;
+ int err;
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ up = kzalloc(sizeof *up, GFP_KERNEL);
+ if (unlikely(!up))
+ return -ENOMEM;
+
+ up->port[0].line = 0;
+ up->port[0].ops = &sc26xx_ops;
+ up->port[0].type = PORT_SC26XX;
+ up->port[0].uartclk = (29491200 / 16); /* arbitrary */
+
+ up->port[0].mapbase = res->start;
+ up->port[0].membase = ioremap_nocache(up->port[0].mapbase, 0x40);
+ up->port[0].iotype = UPIO_MEM;
+ up->port[0].irq = platform_get_irq(dev, 0);
+
+ up->port[0].dev = &dev->dev;
+
+ sc26xx_init_masks(up, 0, sc26xx_data[0]);
+
+ sc26xx_port = &up->port[0];
+
+ up->port[1].line = 1;
+ up->port[1].ops = &sc26xx_ops;
+ up->port[1].type = PORT_SC26XX;
+ up->port[1].uartclk = (29491200 / 16); /* arbitrary */
+
+ up->port[1].mapbase = up->port[0].mapbase;
+ up->port[1].membase = up->port[0].membase;
+ up->port[1].iotype = UPIO_MEM;
+ up->port[1].irq = up->port[0].irq;
+
+ up->port[1].dev = &dev->dev;
+
+ sc26xx_init_masks(up, 1, sc26xx_data[1]);
+
+ err = uart_register_driver(&sc26xx_reg);
+ if (err)
+ goto out_free_port;
+
+ sc26xx_reg.tty_driver->name_base = sc26xx_reg.minor;
+
+ err = uart_add_one_port(&sc26xx_reg, &up->port[0]);
+ if (err)
+ goto out_unregister_driver;
+
+ err = uart_add_one_port(&sc26xx_reg, &up->port[1]);
+ if (err)
+ goto out_remove_port0;
+
+ err = request_irq(up->port[0].irq, sc26xx_interrupt, 0, "sc26xx", up);
+ if (err)
+ goto out_remove_ports;
+
+ dev_set_drvdata(&dev->dev, up);
+ return 0;
+
+out_remove_ports:
+ uart_remove_one_port(&sc26xx_reg, &up->port[1]);
+out_remove_port0:
+ uart_remove_one_port(&sc26xx_reg, &up->port[0]);
+
+out_unregister_driver:
+ uart_unregister_driver(&sc26xx_reg);
+
+out_free_port:
+ kfree(up);
+ sc26xx_port = NULL;
+ return err;
+}
+
+
+static int __exit sc26xx_driver_remove(struct platform_device *dev)
+{
+ struct uart_sc26xx_port *up = dev_get_drvdata(&dev->dev);
+
+ free_irq(up->port[0].irq, up);
+
+ uart_remove_one_port(&sc26xx_reg, &up->port[0]);
+ uart_remove_one_port(&sc26xx_reg, &up->port[1]);
+
+ uart_unregister_driver(&sc26xx_reg);
+
+ kfree(up);
+ sc26xx_port = NULL;
+
+ dev_set_drvdata(&dev->dev, NULL);
+ return 0;
+}
+
+static struct platform_driver sc26xx_driver = {
+ .probe = sc26xx_probe,
+ .remove = __devexit_p(sc26xx_driver_remove),
+ .driver = {
+ .name = "SC26xx",
+ },
+};
+
+static int __init sc26xx_init(void)
+{
+ return platform_driver_register(&sc26xx_driver);
+}
+
+static void __exit sc26xx_exit(void)
+{
+ platform_driver_unregister(&sc26xx_driver);
+}
+
+module_init(sc26xx_init);
+module_exit(sc26xx_exit);
+
+
+MODULE_AUTHOR("Thomas Bogendörfer");
+MODULE_DESCRIPTION("SC681/SC2692 serial driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c
index 80943409edb..bacf68dca01 100644
--- a/drivers/serial/uartlite.c
+++ b/drivers/serial/uartlite.c
@@ -142,7 +142,7 @@ static int ulite_transmit(struct uart_port *port, int stat)
static irqreturn_t ulite_isr(int irq, void *dev_id)
{
- struct uart_port *port = (struct uart_port *)dev_id;
+ struct uart_port *port = dev_id;
int busy;
do {
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index aaaea81e412..d8107890db1 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -144,10 +144,10 @@ config SPI_OMAP_UWIRE
This hooks up to the MicroWire controller on OMAP1 chips.
config SPI_OMAP24XX
- tristate "McSPI driver for OMAP24xx"
- depends on SPI_MASTER && ARCH_OMAP24XX
+ tristate "McSPI driver for OMAP24xx/OMAP34xx"
+ depends on SPI_MASTER && (ARCH_OMAP24XX || ARCH_OMAP34XX)
help
- SPI master controller for OMAP24xx Multichannel SPI
+ SPI master controller for OMAP24xx/OMAP34xx Multichannel SPI
(McSPI) modules.
config SPI_PXA2XX
@@ -176,6 +176,13 @@ config SPI_S3C24XX_GPIO
the inbuilt hardware cannot provide the transfer mode, or
where the board is using non hardware connected pins.
+config SPI_SH_SCI
+ tristate "SuperH SCI SPI controller"
+ depends on SPI_MASTER && SUPERH
+ select SPI_BITBANG
+ help
+ SPI driver for SuperH SCI blocks.
+
config SPI_TXX9
tristate "Toshiba TXx9 SPI controller"
depends on SPI_MASTER && GENERIC_GPIO && CPU_TX49XX
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 41fbac45c32..7fca043ce72 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o
obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o
obj-$(CONFIG_SPI_TXX9) += spi_txx9.o
obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o
+obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.o
# ... add above this line ...
# SPI protocol drivers (device/link on bus)
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index ff10808183a..293b7cab3e5 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -51,7 +51,9 @@ struct atmel_spi {
u8 stopping;
struct list_head queue;
struct spi_transfer *current_transfer;
- unsigned long remaining_bytes;
+ unsigned long current_remaining_bytes;
+ struct spi_transfer *next_transfer;
+ unsigned long next_remaining_bytes;
void *buffer;
dma_addr_t buffer_dma;
@@ -121,6 +123,48 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi)
gpio_set_value(gpio, !active);
}
+static inline int atmel_spi_xfer_is_last(struct spi_message *msg,
+ struct spi_transfer *xfer)
+{
+ return msg->transfers.prev == &xfer->transfer_list;
+}
+
+static inline int atmel_spi_xfer_can_be_chained(struct spi_transfer *xfer)
+{
+ return xfer->delay_usecs == 0 && !xfer->cs_change;
+}
+
+static void atmel_spi_next_xfer_data(struct spi_master *master,
+ struct spi_transfer *xfer,
+ dma_addr_t *tx_dma,
+ dma_addr_t *rx_dma,
+ u32 *plen)
+{
+ struct atmel_spi *as = spi_master_get_devdata(master);
+ u32 len = *plen;
+
+ /* use scratch buffer only when rx or tx data is unspecified */
+ if (xfer->rx_buf)
+ *rx_dma = xfer->rx_dma + xfer->len - len;
+ else {
+ *rx_dma = as->buffer_dma;
+ if (len > BUFFER_SIZE)
+ len = BUFFER_SIZE;
+ }
+ if (xfer->tx_buf)
+ *tx_dma = xfer->tx_dma + xfer->len - len;
+ else {
+ *tx_dma = as->buffer_dma;
+ if (len > BUFFER_SIZE)
+ len = BUFFER_SIZE;
+ memset(as->buffer, 0, len);
+ dma_sync_single_for_device(&as->pdev->dev,
+ as->buffer_dma, len, DMA_TO_DEVICE);
+ }
+
+ *plen = len;
+}
+
/*
* Submit next transfer for DMA.
* lock is held, spi irq is blocked
@@ -130,53 +174,78 @@ static void atmel_spi_next_xfer(struct spi_master *master,
{
struct atmel_spi *as = spi_master_get_devdata(master);
struct spi_transfer *xfer;
- u32 len;
+ u32 len, remaining, total;
dma_addr_t tx_dma, rx_dma;
- xfer = as->current_transfer;
- if (!xfer || as->remaining_bytes == 0) {
- if (xfer)
- xfer = list_entry(xfer->transfer_list.next,
- struct spi_transfer, transfer_list);
- else
- xfer = list_entry(msg->transfers.next,
- struct spi_transfer, transfer_list);
- as->remaining_bytes = xfer->len;
- as->current_transfer = xfer;
- }
+ if (!as->current_transfer)
+ xfer = list_entry(msg->transfers.next,
+ struct spi_transfer, transfer_list);
+ else if (!as->next_transfer)
+ xfer = list_entry(as->current_transfer->transfer_list.next,
+ struct spi_transfer, transfer_list);
+ else
+ xfer = NULL;
- len = as->remaining_bytes;
+ if (xfer) {
+ len = xfer->len;
+ atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len);
+ remaining = xfer->len - len;
- tx_dma = xfer->tx_dma + xfer->len - len;
- rx_dma = xfer->rx_dma + xfer->len - len;
+ spi_writel(as, RPR, rx_dma);
+ spi_writel(as, TPR, tx_dma);
- /* use scratch buffer only when rx or tx data is unspecified */
- if (!xfer->rx_buf) {
- rx_dma = as->buffer_dma;
- if (len > BUFFER_SIZE)
- len = BUFFER_SIZE;
- }
- if (!xfer->tx_buf) {
- tx_dma = as->buffer_dma;
- if (len > BUFFER_SIZE)
- len = BUFFER_SIZE;
- memset(as->buffer, 0, len);
- dma_sync_single_for_device(&as->pdev->dev,
- as->buffer_dma, len, DMA_TO_DEVICE);
+ if (msg->spi->bits_per_word > 8)
+ len >>= 1;
+ spi_writel(as, RCR, len);
+ spi_writel(as, TCR, len);
+
+ dev_dbg(&msg->spi->dev,
+ " start xfer %p: len %u tx %p/%08x rx %p/%08x\n",
+ xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
+ xfer->rx_buf, xfer->rx_dma);
+ } else {
+ xfer = as->next_transfer;
+ remaining = as->next_remaining_bytes;
}
- spi_writel(as, RPR, rx_dma);
- spi_writel(as, TPR, tx_dma);
+ as->current_transfer = xfer;
+ as->current_remaining_bytes = remaining;
- as->remaining_bytes -= len;
- if (msg->spi->bits_per_word > 8)
- len >>= 1;
+ if (remaining > 0)
+ len = remaining;
+ else if (!atmel_spi_xfer_is_last(msg, xfer)
+ && atmel_spi_xfer_can_be_chained(xfer)) {
+ xfer = list_entry(xfer->transfer_list.next,
+ struct spi_transfer, transfer_list);
+ len = xfer->len;
+ } else
+ xfer = NULL;
- /* REVISIT: when xfer->delay_usecs == 0, the PDC "next transfer"
- * mechanism might help avoid the IRQ latency between transfers
- * (and improve the nCS0 errata handling on at91rm9200 chips)
- *
- * We're also waiting for ENDRX before we start the next
+ as->next_transfer = xfer;
+
+ if (xfer) {
+ total = len;
+ atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len);
+ as->next_remaining_bytes = total - len;
+
+ spi_writel(as, RNPR, rx_dma);
+ spi_writel(as, TNPR, tx_dma);
+
+ if (msg->spi->bits_per_word > 8)
+ len >>= 1;
+ spi_writel(as, RNCR, len);
+ spi_writel(as, TNCR, len);
+
+ dev_dbg(&msg->spi->dev,
+ " next xfer %p: len %u tx %p/%08x rx %p/%08x\n",
+ xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
+ xfer->rx_buf, xfer->rx_dma);
+ } else {
+ spi_writel(as, RNCR, 0);
+ spi_writel(as, TNCR, 0);
+ }
+
+ /* REVISIT: We're waiting for ENDRX before we start the next
* transfer because we need to handle some difficult timing
* issues otherwise. If we wait for ENDTX in one transfer and
* then starts waiting for ENDRX in the next, it's difficult
@@ -186,17 +255,7 @@ static void atmel_spi_next_xfer(struct spi_master *master,
*
* It should be doable, though. Just not now...
*/
- spi_writel(as, TNCR, 0);
- spi_writel(as, RNCR, 0);
spi_writel(as, IER, SPI_BIT(ENDRX) | SPI_BIT(OVRES));
-
- dev_dbg(&msg->spi->dev,
- " start xfer %p: len %u tx %p/%08x rx %p/%08x imr %03x\n",
- xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
- xfer->rx_buf, xfer->rx_dma, spi_readl(as, IMR));
-
- spi_writel(as, RCR, len);
- spi_writel(as, TCR, len);
spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN));
}
@@ -294,6 +353,7 @@ atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as,
spin_lock(&as->lock);
as->current_transfer = NULL;
+ as->next_transfer = NULL;
/* continue if needed */
if (list_empty(&as->queue) || as->stopping)
@@ -377,7 +437,7 @@ atmel_spi_interrupt(int irq, void *dev_id)
spi_writel(as, IDR, pending);
- if (as->remaining_bytes == 0) {
+ if (as->current_remaining_bytes == 0) {
msg->actual_length += xfer->len;
if (!msg->is_dma_mapped)
@@ -387,7 +447,7 @@ atmel_spi_interrupt(int irq, void *dev_id)
if (xfer->delay_usecs)
udelay(xfer->delay_usecs);
- if (msg->transfers.prev == &xfer->transfer_list) {
+ if (atmel_spi_xfer_is_last(msg, xfer)) {
/* report completed message */
atmel_spi_msg_done(master, as, msg, 0,
xfer->cs_change);
@@ -490,9 +550,14 @@ static int atmel_spi_setup(struct spi_device *spi)
if (!(spi->mode & SPI_CPHA))
csr |= SPI_BIT(NCPHA);
- /* TODO: DLYBS and DLYBCT */
- csr |= SPI_BF(DLYBS, 10);
- csr |= SPI_BF(DLYBCT, 10);
+ /* DLYBS is mostly irrelevant since we manage chipselect using GPIOs.
+ *
+ * DLYBCT would add delays between words, slowing down transfers.
+ * It could potentially be useful to cope with DMA bottlenecks, but
+ * in those cases it's probably best to just use a lower bitrate.
+ */
+ csr |= SPI_BF(DLYBS, 0);
+ csr |= SPI_BF(DLYBCT, 0);
/* chipselect must have been muxed as GPIO (e.g. in board setup) */
npcs_pin = (unsigned int)spi->controller_data;
diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c
index ea61724ae22..a6ba11afb03 100644
--- a/drivers/spi/omap2_mcspi.c
+++ b/drivers/spi/omap2_mcspi.c
@@ -915,6 +915,28 @@ static u8 __initdata spi2_txdma_id[] = {
OMAP24XX_DMA_SPI2_TX1,
};
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
+static u8 __initdata spi3_rxdma_id[] = {
+ OMAP24XX_DMA_SPI3_RX0,
+ OMAP24XX_DMA_SPI3_RX1,
+};
+
+static u8 __initdata spi3_txdma_id[] = {
+ OMAP24XX_DMA_SPI3_TX0,
+ OMAP24XX_DMA_SPI3_TX1,
+};
+#endif
+
+#ifdef CONFIG_ARCH_OMAP3
+static u8 __initdata spi4_rxdma_id[] = {
+ OMAP34XX_DMA_SPI4_RX0,
+};
+
+static u8 __initdata spi4_txdma_id[] = {
+ OMAP34XX_DMA_SPI4_TX0,
+};
+#endif
+
static int __init omap2_mcspi_probe(struct platform_device *pdev)
{
struct spi_master *master;
@@ -935,7 +957,20 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev)
txdma_id = spi2_txdma_id;
num_chipselect = 2;
break;
- /* REVISIT omap2430 has a third McSPI ... */
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3)
+ case 3:
+ rxdma_id = spi3_rxdma_id;
+ txdma_id = spi3_txdma_id;
+ num_chipselect = 2;
+ break;
+#endif
+#ifdef CONFIG_ARCH_OMAP3
+ case 4:
+ rxdma_id = spi4_rxdma_id;
+ txdma_id = spi4_txdma_id;
+ num_chipselect = 1;
+ break;
+#endif
default:
return -EINVAL;
}
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
index eb817b8eb02..365e0e355ae 100644
--- a/drivers/spi/pxa2xx_spi.c
+++ b/drivers/spi/pxa2xx_spi.c
@@ -1526,17 +1526,6 @@ static void pxa2xx_spi_shutdown(struct platform_device *pdev)
}
#ifdef CONFIG_PM
-static int suspend_devices(struct device *dev, void *pm_message)
-{
- pm_message_t *state = pm_message;
-
- if (dev->power.power_state.event != state->event) {
- dev_warn(dev, "pm state does not match request\n");
- return -1;
- }
-
- return 0;
-}
static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
{
@@ -1544,12 +1533,6 @@ static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
struct ssp_device *ssp = drv_data->ssp;
int status = 0;
- /* Check all childern for current power state */
- if (device_for_each_child(&pdev->dev, &state, suspend_devices) != 0) {
- dev_warn(&pdev->dev, "suspend aborted\n");
- return -1;
- }
-
status = stop_queue(drv_data);
if (status != 0)
return status;
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 682a6a48fec..1ad12afc6ba 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -18,7 +18,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/autoconf.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/init.h>
@@ -77,39 +76,33 @@ static int spi_uevent(struct device *dev, struct kobj_uevent_env *env)
#ifdef CONFIG_PM
-/*
- * NOTE: the suspend() method for an spi_master controller driver
- * should verify that all its child devices are marked as suspended;
- * suspend requests delivered through sysfs power/state files don't
- * enforce such constraints.
- */
static int spi_suspend(struct device *dev, pm_message_t message)
{
- int value;
+ int value = 0;
struct spi_driver *drv = to_spi_driver(dev->driver);
- if (!drv || !drv->suspend)
- return 0;
-
/* suspend will stop irqs and dma; no more i/o */
- value = drv->suspend(to_spi_device(dev), message);
- if (value == 0)
- dev->power.power_state = message;
+ if (drv) {
+ if (drv->suspend)
+ value = drv->suspend(to_spi_device(dev), message);
+ else
+ dev_dbg(dev, "... can't suspend\n");
+ }
return value;
}
static int spi_resume(struct device *dev)
{
- int value;
+ int value = 0;
struct spi_driver *drv = to_spi_driver(dev->driver);
- if (!drv || !drv->resume)
- return 0;
-
/* resume may restart the i/o queue */
- value = drv->resume(to_spi_device(dev));
- if (value == 0)
- dev->power.power_state = PMSG_ON;
+ if (drv) {
+ if (drv->resume)
+ value = drv->resume(to_spi_device(dev));
+ else
+ dev_dbg(dev, "... can't resume\n");
+ }
return value;
}
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index 7ef39a6e8c0..d853fceb6bf 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -1,37 +1,11 @@
/*
- * File: drivers/spi/bfin5xx_spi.c
- * Maintainer:
- * Bryan Wu <bryan.wu@analog.com>
- * Original Author:
- * Luke Yang (Analog Devices Inc.)
- *
- * Created: March. 10th 2006
- * Description: SPI controller driver for Blackfin BF5xx
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * Modified:
- * March 10, 2006 bfin5xx_spi.c Created. (Luke Yang)
- * August 7, 2006 added full duplex mode (Axel Weiss & Luke Yang)
- * July 17, 2007 add support for BF54x SPI0 controller (Bryan Wu)
- * July 30, 2007 add platfrom_resource interface to support multi-port
- * SPI controller (Bryan Wu)
+ * Blackfin On-Chip SPI Driver
*
* Copyright 2004-2007 Analog Devices Inc.
*
- * This program is free software ; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation ; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY ; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * Enter bugs at http://blackfin.uclinux.org/
*
- * You should have received a copy of the GNU General Public License
- * along with this program ; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later.
*/
#include <linux/init.h>
@@ -223,10 +197,9 @@ static void cs_deactive(struct driver_data *drv_data, struct chip_data *chip)
#define MAX_SPI_SSEL 7
/* stop controller and re-config current chip*/
-static int restore_state(struct driver_data *drv_data)
+static void restore_state(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
- int ret = 0;
/* Clear status and disable clock */
write_STAT(drv_data, BIT_STAT_CLR);
@@ -239,13 +212,6 @@ static int restore_state(struct driver_data *drv_data)
bfin_spi_enable(drv_data);
cs_active(drv_data, chip);
-
- if (ret)
- dev_dbg(&drv_data->pdev->dev,
- ": request chip select number %d failed\n",
- chip->chip_select_num);
-
- return ret;
}
/* used to kick off transfer in rx mode */
@@ -286,32 +252,30 @@ static void u8_writer(struct driver_data *drv_data)
dev_dbg(&drv_data->pdev->dev,
"cr8-s is 0x%x\n", read_STAT(drv_data));
- /* poll for SPI completion before start */
- while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
- cpu_relax();
-
while (drv_data->tx < drv_data->tx_end) {
write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
while (read_STAT(drv_data) & BIT_STAT_TXS)
cpu_relax();
++drv_data->tx;
}
+
+ /* poll for SPI completion before return */
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+ cpu_relax();
}
static void u8_cs_chg_writer(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
- /* poll for SPI completion before start */
- while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
- cpu_relax();
-
while (drv_data->tx < drv_data->tx_end) {
cs_active(drv_data, chip);
write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
while (read_STAT(drv_data) & BIT_STAT_TXS)
cpu_relax();
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+ cpu_relax();
cs_deactive(drv_data, chip);
@@ -350,43 +314,28 @@ static void u8_cs_chg_reader(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
- /* poll for SPI completion before start */
- while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
- cpu_relax();
-
- /* clear TDBR buffer before read(else it will be shifted out) */
- write_TDBR(drv_data, 0xFFFF);
+ while (drv_data->rx < drv_data->rx_end) {
+ cs_active(drv_data, chip);
+ read_RDBR(drv_data); /* kick off */
- cs_active(drv_data, chip);
- dummy_read(drv_data);
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
+ cpu_relax();
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+ cpu_relax();
- while (drv_data->rx < drv_data->rx_end - 1) {
+ *(u8 *) (drv_data->rx) = read_SHAW(drv_data);
cs_deactive(drv_data, chip);
- while (!(read_STAT(drv_data) & BIT_STAT_RXS))
- cpu_relax();
- cs_active(drv_data, chip);
- *(u8 *) (drv_data->rx) = read_RDBR(drv_data);
++drv_data->rx;
}
- cs_deactive(drv_data, chip);
-
- while (!(read_STAT(drv_data) & BIT_STAT_RXS))
- cpu_relax();
- *(u8 *) (drv_data->rx) = read_SHAW(drv_data);
- ++drv_data->rx;
}
static void u8_duplex(struct driver_data *drv_data)
{
- /* poll for SPI completion before start */
- while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
- cpu_relax();
-
/* in duplex mode, clk is triggered by writing of TDBR */
while (drv_data->rx < drv_data->rx_end) {
write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
- while (read_STAT(drv_data) & BIT_STAT_TXS)
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
cpu_relax();
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
cpu_relax();
@@ -400,15 +349,12 @@ static void u8_cs_chg_duplex(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
- /* poll for SPI completion before start */
- while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
- cpu_relax();
-
while (drv_data->rx < drv_data->rx_end) {
cs_active(drv_data, chip);
write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
- while (read_STAT(drv_data) & BIT_STAT_TXS)
+
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
cpu_relax();
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
cpu_relax();
@@ -426,32 +372,30 @@ static void u16_writer(struct driver_data *drv_data)
dev_dbg(&drv_data->pdev->dev,
"cr16 is 0x%x\n", read_STAT(drv_data));
- /* poll for SPI completion before start */
- while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
- cpu_relax();
-
while (drv_data->tx < drv_data->tx_end) {
write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
while ((read_STAT(drv_data) & BIT_STAT_TXS))
cpu_relax();
drv_data->tx += 2;
}
+
+ /* poll for SPI completion before return */
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+ cpu_relax();
}
static void u16_cs_chg_writer(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
- /* poll for SPI completion before start */
- while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
- cpu_relax();
-
while (drv_data->tx < drv_data->tx_end) {
cs_active(drv_data, chip);
write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
while ((read_STAT(drv_data) & BIT_STAT_TXS))
cpu_relax();
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+ cpu_relax();
cs_deactive(drv_data, chip);
@@ -519,14 +463,10 @@ static void u16_cs_chg_reader(struct driver_data *drv_data)
static void u16_duplex(struct driver_data *drv_data)
{
- /* poll for SPI completion before start */
- while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
- cpu_relax();
-
/* in duplex mode, clk is triggered by writing of TDBR */
while (drv_data->tx < drv_data->tx_end) {
write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
- while (read_STAT(drv_data) & BIT_STAT_TXS)
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
cpu_relax();
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
cpu_relax();
@@ -540,15 +480,11 @@ static void u16_cs_chg_duplex(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
- /* poll for SPI completion before start */
- while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
- cpu_relax();
-
while (drv_data->tx < drv_data->tx_end) {
cs_active(drv_data, chip);
write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
- while (read_STAT(drv_data) & BIT_STAT_TXS)
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
cpu_relax();
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
cpu_relax();
@@ -616,7 +552,7 @@ static void giveback(struct driver_data *drv_data)
static irqreturn_t dma_irq_handler(int irq, void *dev_id)
{
- struct driver_data *drv_data = (struct driver_data *)dev_id;
+ struct driver_data *drv_data = dev_id;
struct chip_data *chip = drv_data->cur_chip;
struct spi_message *msg = drv_data->cur_msg;
@@ -978,10 +914,7 @@ static void pump_messages(struct work_struct *work)
/* Setup the SSP using the per chip configuration */
drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
- if (restore_state(drv_data)) {
- spin_unlock_irqrestore(&drv_data->lock, flags);
- return;
- };
+ restore_state(drv_data);
list_del_init(&drv_data->cur_msg->queue);
@@ -1187,7 +1120,7 @@ static int setup(struct spi_device *spi)
if ((chip->chip_select_num > 0)
&& (chip->chip_select_num <= spi->master->num_chipselect))
peripheral_request(ssel[spi->master->bus_num]
- [chip->chip_select_num-1], DRV_NAME);
+ [chip->chip_select_num-1], spi->modalias);
cs_deactive(drv_data, chip);
diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c
index 639963eb1ac..1b064712493 100644
--- a/drivers/spi/spi_imx.c
+++ b/drivers/spi/spi_imx.c
@@ -1686,17 +1686,6 @@ static void spi_imx_shutdown(struct platform_device *pdev)
}
#ifdef CONFIG_PM
-static int suspend_devices(struct device *dev, void *pm_message)
-{
- pm_message_t *state = pm_message;
-
- if (dev->power.power_state.event != state->event) {
- dev_warn(dev, "pm state does not match request\n");
- return -1;
- }
-
- return 0;
-}
static int spi_imx_suspend(struct platform_device *pdev, pm_message_t state)
{
diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c
index 89d6685a5ca..6e834b8b9d2 100644
--- a/drivers/spi/spi_s3c24xx.c
+++ b/drivers/spi/spi_s3c24xx.c
@@ -237,10 +237,8 @@ static int __init s3c24xx_spi_probe(struct platform_device *pdev)
{
struct s3c24xx_spi *hw;
struct spi_master *master;
- struct spi_board_info *bi;
struct resource *res;
int err = 0;
- int i;
master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi));
if (master == NULL) {
@@ -348,16 +346,6 @@ static int __init s3c24xx_spi_probe(struct platform_device *pdev)
goto err_register;
}
- /* register all the devices associated */
-
- bi = &hw->pdata->board_info[0];
- for (i = 0; i < hw->pdata->board_size; i++, bi++) {
- dev_info(hw->dev, "registering %s\n", bi->modalias);
-
- bi->controller_data = hw;
- spi_new_device(master, bi);
- }
-
return 0;
err_register:
diff --git a/drivers/spi/spi_s3c24xx_gpio.c b/drivers/spi/spi_s3c24xx_gpio.c
index 109d82c1abc..82ae7d7eca3 100644
--- a/drivers/spi/spi_s3c24xx_gpio.c
+++ b/drivers/spi/spi_s3c24xx_gpio.c
@@ -100,7 +100,6 @@ static int s3c2410_spigpio_probe(struct platform_device *dev)
struct spi_master *master;
struct s3c2410_spigpio *sp;
int ret;
- int i;
master = spi_alloc_master(&dev->dev, sizeof(struct s3c2410_spigpio));
if (master == NULL) {
@@ -143,17 +142,6 @@ static int s3c2410_spigpio_probe(struct platform_device *dev)
if (ret)
goto err_no_bitbang;
- /* register the chips to go with the board */
-
- for (i = 0; i < sp->info->board_size; i++) {
- dev_info(&dev->dev, "registering %p: %s\n",
- &sp->info->board_info[i],
- sp->info->board_info[i].modalias);
-
- sp->info->board_info[i].controller_data = sp;
- spi_new_device(master, sp->info->board_info + i);
- }
-
return 0;
err_no_bitbang:
diff --git a/drivers/spi/spi_sh_sci.c b/drivers/spi/spi_sh_sci.c
new file mode 100644
index 00000000000..3dbe71b16d6
--- /dev/null
+++ b/drivers/spi/spi_sh_sci.c
@@ -0,0 +1,205 @@
+/*
+ * SH SCI SPI interface
+ *
+ * Copyright (c) 2008 Magnus Damm
+ *
+ * Based on S3C24XX GPIO based SPI driver, which is:
+ * Copyright (c) 2006 Ben Dooks
+ * Copyright (c) 2006 Simtec Electronics
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#include <asm/spi.h>
+#include <asm/io.h>
+
+struct sh_sci_spi {
+ struct spi_bitbang bitbang;
+
+ void __iomem *membase;
+ unsigned char val;
+ struct sh_spi_info *info;
+ struct platform_device *dev;
+};
+
+#define SCSPTR(sp) (sp->membase + 0x1c)
+#define PIN_SCK (1 << 2)
+#define PIN_TXD (1 << 0)
+#define PIN_RXD PIN_TXD
+#define PIN_INIT ((1 << 1) | (1 << 3) | PIN_SCK | PIN_TXD)
+
+static inline void setbits(struct sh_sci_spi *sp, int bits, int on)
+{
+ /*
+ * We are the only user of SCSPTR so no locking is required.
+ * Reading bit 2 and 0 in SCSPTR gives pin state as input.
+ * Writing the same bits sets the output value.
+ * This makes regular read-modify-write difficult so we
+ * use sp->val to keep track of the latest register value.
+ */
+
+ if (on)
+ sp->val |= bits;
+ else
+ sp->val &= ~bits;
+
+ iowrite8(sp->val, SCSPTR(sp));
+}
+
+static inline void setsck(struct spi_device *dev, int on)
+{
+ setbits(spi_master_get_devdata(dev->master), PIN_SCK, on);
+}
+
+static inline void setmosi(struct spi_device *dev, int on)
+{
+ setbits(spi_master_get_devdata(dev->master), PIN_TXD, on);
+}
+
+static inline u32 getmiso(struct spi_device *dev)
+{
+ struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
+
+ return (ioread8(SCSPTR(sp)) & PIN_RXD) ? 1 : 0;
+}
+
+#define spidelay(x) ndelay(x)
+
+#define EXPAND_BITBANG_TXRX
+#include <linux/spi/spi_bitbang.h>
+
+static u32 sh_sci_spi_txrx_mode0(struct spi_device *spi,
+ unsigned nsecs, u32 word, u8 bits)
+{
+ return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
+}
+
+static u32 sh_sci_spi_txrx_mode1(struct spi_device *spi,
+ unsigned nsecs, u32 word, u8 bits)
+{
+ return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
+}
+
+static u32 sh_sci_spi_txrx_mode2(struct spi_device *spi,
+ unsigned nsecs, u32 word, u8 bits)
+{
+ return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits);
+}
+
+static u32 sh_sci_spi_txrx_mode3(struct spi_device *spi,
+ unsigned nsecs, u32 word, u8 bits)
+{
+ return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits);
+}
+
+static void sh_sci_spi_chipselect(struct spi_device *dev, int value)
+{
+ struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
+
+ if (sp->info && sp->info->chip_select)
+ (sp->info->chip_select)(sp->info, dev->chip_select, value);
+}
+
+static int sh_sci_spi_probe(struct platform_device *dev)
+{
+ struct resource *r;
+ struct spi_master *master;
+ struct sh_sci_spi *sp;
+ int ret;
+
+ master = spi_alloc_master(&dev->dev, sizeof(struct sh_sci_spi));
+ if (master == NULL) {
+ dev_err(&dev->dev, "failed to allocate spi master\n");
+ ret = -ENOMEM;
+ goto err0;
+ }
+
+ sp = spi_master_get_devdata(master);
+
+ platform_set_drvdata(dev, sp);
+ sp->info = dev->dev.platform_data;
+
+ /* setup spi bitbang adaptor */
+ sp->bitbang.master = spi_master_get(master);
+ sp->bitbang.master->bus_num = sp->info->bus_num;
+ sp->bitbang.master->num_chipselect = sp->info->num_chipselect;
+ sp->bitbang.chipselect = sh_sci_spi_chipselect;
+
+ sp->bitbang.txrx_word[SPI_MODE_0] = sh_sci_spi_txrx_mode0;
+ sp->bitbang.txrx_word[SPI_MODE_1] = sh_sci_spi_txrx_mode1;
+ sp->bitbang.txrx_word[SPI_MODE_2] = sh_sci_spi_txrx_mode2;
+ sp->bitbang.txrx_word[SPI_MODE_3] = sh_sci_spi_txrx_mode3;
+
+ r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (r == NULL) {
+ ret = -ENOENT;
+ goto err1;
+ }
+ sp->membase = ioremap(r->start, r->end - r->start + 1);
+ if (!sp->membase) {
+ ret = -ENXIO;
+ goto err1;
+ }
+ sp->val = ioread8(SCSPTR(sp));
+ setbits(sp, PIN_INIT, 1);
+
+ ret = spi_bitbang_start(&sp->bitbang);
+ if (!ret)
+ return 0;
+
+ setbits(sp, PIN_INIT, 0);
+ iounmap(sp->membase);
+ err1:
+ spi_master_put(sp->bitbang.master);
+ err0:
+ return ret;
+}
+
+static int sh_sci_spi_remove(struct platform_device *dev)
+{
+ struct sh_sci_spi *sp = platform_get_drvdata(dev);
+
+ iounmap(sp->membase);
+ setbits(sp, PIN_INIT, 0);
+ spi_bitbang_stop(&sp->bitbang);
+ spi_master_put(sp->bitbang.master);
+ return 0;
+}
+
+static struct platform_driver sh_sci_spi_drv = {
+ .probe = sh_sci_spi_probe,
+ .remove = sh_sci_spi_remove,
+ .driver = {
+ .name = "spi_sh_sci",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init sh_sci_spi_init(void)
+{
+ return platform_driver_register(&sh_sci_spi_drv);
+}
+module_init(sh_sci_spi_init);
+
+static void __exit sh_sci_spi_exit(void)
+{
+ platform_driver_unregister(&sh_sci_spi_drv);
+}
+module_exit(sh_sci_spi_exit);
+
+MODULE_DESCRIPTION("SH SCI SPI Driver");
+MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index cc246faa359..2a77e9d42c6 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -417,30 +417,28 @@ static void uio_vma_close(struct vm_area_struct *vma)
idev->vma_count--;
}
-static struct page *uio_vma_nopage(struct vm_area_struct *vma,
- unsigned long address, int *type)
+static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct uio_device *idev = vma->vm_private_data;
- struct page* page = NOPAGE_SIGBUS;
+ struct page *page;
int mi = uio_find_mem_index(vma);
if (mi < 0)
- return page;
+ return VM_FAULT_SIGBUS;
if (idev->info->mem[mi].memtype == UIO_MEM_LOGICAL)
page = virt_to_page(idev->info->mem[mi].addr);
else
page = vmalloc_to_page((void*)idev->info->mem[mi].addr);
get_page(page);
- if (type)
- *type = VM_FAULT_MINOR;
- return page;
+ vmf->page = page;
+ return 0;
}
static struct vm_operations_struct uio_vm_ops = {
.open = uio_vma_open,
.close = uio_vma_close,
- .nopage = uio_vma_nopage,
+ .fault = uio_vma_fault,
};
static int uio_mmap_physical(struct vm_area_struct *vma)
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index f8e71114750..fc65c02306d 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -16,6 +16,7 @@
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/backlight.h>
#include <asm/arch/board.h>
#include <asm/arch/cpu.h>
@@ -69,6 +70,107 @@ static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
}
#endif
+static const u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
+ | ATMEL_LCDC_POL_POSITIVE
+ | ATMEL_LCDC_ENA_PWMENABLE;
+
+#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
+
+/* some bl->props field just changed */
+static int atmel_bl_update_status(struct backlight_device *bl)
+{
+ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
+ int power = sinfo->bl_power;
+ int brightness = bl->props.brightness;
+
+ /* REVISIT there may be a meaningful difference between
+ * fb_blank and power ... there seem to be some cases
+ * this doesn't handle correctly.
+ */
+ if (bl->props.fb_blank != sinfo->bl_power)
+ power = bl->props.fb_blank;
+ else if (bl->props.power != sinfo->bl_power)
+ power = bl->props.power;
+
+ if (brightness < 0 && power == FB_BLANK_UNBLANK)
+ brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+ else if (power != FB_BLANK_UNBLANK)
+ brightness = 0;
+
+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
+ brightness ? contrast_ctr : 0);
+
+ bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
+
+ return 0;
+}
+
+static int atmel_bl_get_brightness(struct backlight_device *bl)
+{
+ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
+
+ return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+}
+
+static struct backlight_ops atmel_lcdc_bl_ops = {
+ .update_status = atmel_bl_update_status,
+ .get_brightness = atmel_bl_get_brightness,
+};
+
+static void init_backlight(struct atmel_lcdfb_info *sinfo)
+{
+ struct backlight_device *bl;
+
+ sinfo->bl_power = FB_BLANK_UNBLANK;
+
+ if (sinfo->backlight)
+ return;
+
+ bl = backlight_device_register("backlight", &sinfo->pdev->dev,
+ sinfo, &atmel_lcdc_bl_ops);
+ if (IS_ERR(sinfo->backlight)) {
+ dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n",
+ PTR_ERR(bl));
+ return;
+ }
+ sinfo->backlight = bl;
+
+ bl->props.power = FB_BLANK_UNBLANK;
+ bl->props.fb_blank = FB_BLANK_UNBLANK;
+ bl->props.max_brightness = 0xff;
+ bl->props.brightness = atmel_bl_get_brightness(bl);
+}
+
+static void exit_backlight(struct atmel_lcdfb_info *sinfo)
+{
+ if (sinfo->backlight)
+ backlight_device_unregister(sinfo->backlight);
+}
+
+#else
+
+static void init_backlight(struct atmel_lcdfb_info *sinfo)
+{
+ dev_warn(&sinfo->pdev->dev, "backlight control is not available\n");
+}
+
+static void exit_backlight(struct atmel_lcdfb_info *sinfo)
+{
+}
+
+#endif
+
+static void init_contrast(struct atmel_lcdfb_info *sinfo)
+{
+ /* have some default contrast/backlight settings */
+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
+
+ if (sinfo->lcdcon_is_backlight)
+ init_backlight(sinfo);
+}
+
static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
.type = FB_TYPE_PACKED_PIXELS,
@@ -203,6 +305,26 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
var->transp.offset = var->transp.length = 0;
var->xoffset = var->yoffset = 0;
+ /* Saturate vertical and horizontal timings at maximum values */
+ var->vsync_len = min_t(u32, var->vsync_len,
+ (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
+ var->upper_margin = min_t(u32, var->upper_margin,
+ ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
+ var->lower_margin = min_t(u32, var->lower_margin,
+ ATMEL_LCDC_VFP);
+ var->right_margin = min_t(u32, var->right_margin,
+ (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
+ var->hsync_len = min_t(u32, var->hsync_len,
+ (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
+ var->left_margin = min_t(u32, var->left_margin,
+ ATMEL_LCDC_HBP + 1);
+
+ /* Some parameters can't be zero */
+ var->vsync_len = max_t(u32, var->vsync_len, 1);
+ var->right_margin = max_t(u32, var->right_margin, 1);
+ var->hsync_len = max_t(u32, var->hsync_len, 1);
+ var->left_margin = max_t(u32, var->left_margin, 1);
+
switch (var->bits_per_pixel) {
case 1:
case 2:
@@ -370,10 +492,6 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
/* Disable all interrupts */
lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
- /* Set contrast */
- value = ATMEL_LCDC_PS_DIV8 | ATMEL_LCDC_POL_POSITIVE | ATMEL_LCDC_ENA_PWMENABLE;
- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, value);
- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
/* ...wait for DMA engine to become idle... */
while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
msleep(10);
@@ -577,6 +695,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
sinfo->default_monspecs = pdata_sinfo->default_monspecs;
sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control;
sinfo->guard_time = pdata_sinfo->guard_time;
+ sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight;
} else {
dev_err(dev, "cannot get default configuration\n");
goto free_info;
@@ -670,6 +789,9 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
goto release_mem;
}
+ /* Initialize PWM for contrast or backlight ("off") */
+ init_contrast(sinfo);
+
/* interrupt */
ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info);
if (ret) {
@@ -721,6 +843,7 @@ free_cmap:
unregister_irqs:
free_irq(sinfo->irq_base, info);
unmap_mmio:
+ exit_backlight(sinfo);
iounmap(sinfo->mmio);
release_mem:
release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
@@ -755,6 +878,7 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
if (!sinfo)
return 0;
+ exit_backlight(sinfo);
if (sinfo->atmel_lcdfb_power_control)
sinfo->atmel_lcdfb_power_control(0);
unregister_framebuffer(info);
@@ -781,6 +905,9 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
static struct platform_driver atmel_lcdfb_driver = {
.remove = __exit_p(atmel_lcdfb_remove),
+
+// FIXME need suspend, resume
+
.driver = {
.name = "atmel_lcdfb",
.owner = THIS_MODULE,
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 9609a6c676b..924e2551044 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -50,6 +50,19 @@ config BACKLIGHT_CLASS_DEVICE
To have support for your specific LCD panel you will have to
select the proper drivers which depend on this option.
+config BACKLIGHT_ATMEL_LCDC
+ bool "Atmel LCDC Contrast-as-Backlight control"
+ depends on BACKLIGHT_CLASS_DEVICE && FB_ATMEL
+ default y if MACH_SAM9261EK || MACH_SAM9263EK
+ help
+ This provides a backlight control internal to the Atmel LCDC
+ driver. If the LCD "contrast control" on your board is wired
+ so it controls the backlight brightness, select this option to
+ export this as a PWM-based backlight control.
+
+ If in doubt, it's safe to enable this option; it doesn't kick
+ in unless the board's description says it's wired that way.
+
config BACKLIGHT_CORGI
tristate "Generic (aka Sharp Corgi) Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE
diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c
index c8e7427a0bc..0ce791e6f79 100644
--- a/drivers/video/bf54x-lq043fb.c
+++ b/drivers/video/bf54x-lq043fb.c
@@ -498,8 +498,7 @@ static struct lcd_device *lcd_dev;
static irqreturn_t bfin_bf54x_irq_error(int irq, void *dev_id)
{
-
- /*struct bfin_bf54xfb_info *info = (struct bfin_bf54xfb_info *)dev_id;*/
+ /*struct bfin_bf54xfb_info *info = dev_id;*/
u16 status = bfin_read_EPPI0_STATUS();
diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c
index 308850df16f..69864b1b3f9 100644
--- a/drivers/video/console/bitblit.c
+++ b/drivers/video/console/bitblit.c
@@ -63,7 +63,7 @@ static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy,
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
struct fb_fillrect region;
- region.color = attr_bgcol_ec(bgshift, vc);
+ region.color = attr_bgcol_ec(bgshift, vc, info);
region.dx = sx * vc->vc_font.width;
region.dy = sy * vc->vc_font.height;
region.width = width * vc->vc_font.width;
@@ -213,7 +213,7 @@ static void bit_clear_margins(struct vc_data *vc, struct fb_info *info,
unsigned int bs = info->var.yres - bh;
struct fb_fillrect region;
- region.color = attr_bgcol_ec(bgshift, vc);
+ region.color = attr_bgcol_ec(bgshift, vc, info);
region.rop = ROP_COPY;
if (rw && !bottom_only) {
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 0f32f4a00b2..022282494d3 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -84,7 +84,7 @@
#ifdef CONFIG_MAC
#include <asm/macints.h>
#endif
-#if defined(__mc68000__) || defined(CONFIG_APUS)
+#if defined(__mc68000__)
#include <asm/machdep.h>
#include <asm/setup.h>
#endif
@@ -147,7 +147,7 @@ static char fontname[40];
static int info_idx = -1;
/* console rotation */
-static int rotate;
+static int initial_rotation;
static int fbcon_has_sysfs;
static const struct consw fb_con;
@@ -334,10 +334,7 @@ static inline int get_color(struct vc_data *vc, struct fb_info *info,
switch (depth) {
case 1:
{
- int col = ~(0xfff << (max(info->var.green.length,
- max(info->var.red.length,
- info->var.blue.length)))) & 0xff;
-
+ int col = mono_col(info);
/* 0 or 1 */
int fg = (info->fix.visual != FB_VISUAL_MONO01) ? col : 0;
int bg = (info->fix.visual != FB_VISUAL_MONO01) ? 0 : col;
@@ -537,9 +534,9 @@ static int __init fb_console_setup(char *this_opt)
if (!strncmp(options, "rotate:", 7)) {
options += 7;
if (*options)
- rotate = simple_strtoul(options, &options, 0);
- if (rotate > 3)
- rotate = 0;
+ initial_rotation = simple_strtoul(options, &options, 0);
+ if (initial_rotation > 3)
+ initial_rotation = 0;
}
}
return 1;
@@ -989,7 +986,7 @@ static const char *fbcon_startup(void)
ops->graphics = 1;
ops->cur_rotate = -1;
info->fbcon_par = ops;
- p->con_rotate = rotate;
+ p->con_rotate = initial_rotation;
set_blitting_type(vc, info);
if (info->fix.type != FB_TYPE_TEXT) {
@@ -1176,7 +1173,7 @@ static void fbcon_init(struct vc_data *vc, int init)
con_copy_unimap(vc, svc);
ops = info->fbcon_par;
- p->con_rotate = rotate;
+ p->con_rotate = initial_rotation;
set_blitting_type(vc, info);
cols = vc->vc_cols;
@@ -2795,7 +2792,7 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines)
{
struct fb_info *info = registered_fb[con2fb_map[fg_console]];
struct fbcon_ops *ops = info->fbcon_par;
- struct display *p = &fb_display[fg_console];
+ struct display *disp = &fb_display[fg_console];
int offset, limit, scrollback_old;
if (softback_top) {
@@ -2833,7 +2830,7 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines)
logo_shown = FBCON_LOGO_CANSHOW;
}
fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK);
- fbcon_redraw_softback(vc, p, lines);
+ fbcon_redraw_softback(vc, disp, lines);
fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK);
return 0;
}
@@ -2855,9 +2852,9 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines)
fbcon_cursor(vc, CM_ERASE);
- offset = p->yscroll - scrollback_current;
- limit = p->vrows;
- switch (p->scrollmode) {
+ offset = disp->yscroll - scrollback_current;
+ limit = disp->vrows;
+ switch (disp->scrollmode) {
case SCROLL_WRAP_MOVE:
info->var.vmode |= FB_VMODE_YWRAP;
break;
diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h
index 8e6ef4bc7a5..3706307e70e 100644
--- a/drivers/video/console/fbcon.h
+++ b/drivers/video/console/fbcon.h
@@ -93,10 +93,6 @@ struct fbcon_ops {
(((s) >> (fgshift)) & 0x0f)
#define attr_bgcol(bgshift,s) \
(((s) >> (bgshift)) & 0x0f)
-#define attr_bgcol_ec(bgshift,vc) \
- ((vc) ? (((vc)->vc_video_erase_char >> (bgshift)) & 0x0f) : 0)
-#define attr_fgcol_ec(fgshift,vc) \
- ((vc) ? (((vc)->vc_video_erase_char >> (fgshift)) & 0x0f) : 0)
/* Monochrome */
#define attr_bold(s) \
@@ -108,6 +104,49 @@ struct fbcon_ops {
#define attr_blink(s) \
((s) & 0x8000)
+#define mono_col(info) \
+ (~(0xfff << (max((info)->var.green.length, \
+ max((info)->var.red.length, \
+ (info)->var.blue.length)))) & 0xff)
+
+static inline int attr_col_ec(int shift, struct vc_data *vc,
+ struct fb_info *info, int is_fg)
+{
+ int is_mono01;
+ int col;
+ int fg;
+ int bg;
+
+ if (!vc)
+ return 0;
+
+ if (vc->vc_can_do_color)
+ return is_fg ? attr_fgcol(shift,vc->vc_video_erase_char)
+ : attr_bgcol(shift,vc->vc_video_erase_char);
+
+ if (!info)
+ return 0;
+
+ col = mono_col(info);
+ is_mono01 = info->fix.visual == FB_VISUAL_MONO01;
+
+ if (attr_reverse(vc->vc_video_erase_char)) {
+ fg = is_mono01 ? col : 0;
+ bg = is_mono01 ? 0 : col;
+ }
+ else {
+ fg = is_mono01 ? 0 : col;
+ bg = is_mono01 ? col : 0;
+ }
+
+ return is_fg ? fg : bg;
+}
+
+#define attr_bgcol_ec(bgshift,vc,info) \
+ attr_col_ec(bgshift,vc,info,0);
+#define attr_fgcol_ec(fgshift,vc,info) \
+ attr_col_ec(fgshift,vc,info,1);
+
/* Font */
#define REFCOUNT(fd) (((int *)(fd))[-1])
#define FNTSIZE(fd) (((int *)(fd))[-2])
diff --git a/drivers/video/console/fbcon_ccw.c b/drivers/video/console/fbcon_ccw.c
index 825e6d6972a..bdf913ecf00 100644
--- a/drivers/video/console/fbcon_ccw.c
+++ b/drivers/video/console/fbcon_ccw.c
@@ -84,7 +84,7 @@ static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy,
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
u32 vyres = GETVYRES(ops->p->scrollmode, info);
- region.color = attr_bgcol_ec(bgshift,vc);
+ region.color = attr_bgcol_ec(bgshift,vc,info);
region.dx = sy * vc->vc_font.height;
region.dy = vyres - ((sx + width) * vc->vc_font.width);
region.height = width * vc->vc_font.width;
@@ -198,7 +198,7 @@ static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info,
struct fb_fillrect region;
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
- region.color = attr_bgcol_ec(bgshift,vc);
+ region.color = attr_bgcol_ec(bgshift,vc,info);
region.rop = ROP_COPY;
if (rw && !bottom_only) {
diff --git a/drivers/video/console/fbcon_cw.c b/drivers/video/console/fbcon_cw.c
index c637e631880..a6819b9d177 100644
--- a/drivers/video/console/fbcon_cw.c
+++ b/drivers/video/console/fbcon_cw.c
@@ -70,7 +70,7 @@ static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy,
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
u32 vxres = GETVXRES(ops->p->scrollmode, info);
- region.color = attr_bgcol_ec(bgshift,vc);
+ region.color = attr_bgcol_ec(bgshift,vc,info);
region.dx = vxres - ((sy + height) * vc->vc_font.height);
region.dy = sx * vc->vc_font.width;
region.height = width * vc->vc_font.width;
@@ -182,7 +182,7 @@ static void cw_clear_margins(struct vc_data *vc, struct fb_info *info,
struct fb_fillrect region;
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
- region.color = attr_bgcol_ec(bgshift,vc);
+ region.color = attr_bgcol_ec(bgshift,vc,info);
region.rop = ROP_COPY;
if (rw && !bottom_only) {
diff --git a/drivers/video/console/fbcon_ud.c b/drivers/video/console/fbcon_ud.c
index 1473506df5d..d9b5d6eb68a 100644
--- a/drivers/video/console/fbcon_ud.c
+++ b/drivers/video/console/fbcon_ud.c
@@ -71,7 +71,7 @@ static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy,
u32 vyres = GETVYRES(ops->p->scrollmode, info);
u32 vxres = GETVXRES(ops->p->scrollmode, info);
- region.color = attr_bgcol_ec(bgshift,vc);
+ region.color = attr_bgcol_ec(bgshift,vc,info);
region.dy = vyres - ((sy + height) * vc->vc_font.height);
region.dx = vxres - ((sx + width) * vc->vc_font.width);
region.width = width * vc->vc_font.width;
@@ -228,7 +228,7 @@ static void ud_clear_margins(struct vc_data *vc, struct fb_info *info,
struct fb_fillrect region;
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
- region.color = attr_bgcol_ec(bgshift,vc);
+ region.color = attr_bgcol_ec(bgshift,vc,info);
region.rop = ROP_COPY;
if (rw && !bottom_only) {
diff --git a/drivers/video/console/fonts.c b/drivers/video/console/fonts.c
index 96979c37751..d0c03fd7087 100644
--- a/drivers/video/console/fonts.c
+++ b/drivers/video/console/fonts.c
@@ -15,7 +15,7 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
-#if defined(__mc68000__) || defined(CONFIG_APUS)
+#if defined(__mc68000__)
#include <asm/setup.h>
#endif
#include <linux/font.h>
@@ -120,7 +120,7 @@ const struct font_desc *get_default_font(int xres, int yres, u32 font_w,
for(i=0; i<num_fonts; i++) {
f = fonts[i];
c = f->pref;
-#if defined(__mc68000__) || defined(CONFIG_APUS)
+#if defined(__mc68000__)
#ifdef CONFIG_FONT_PEARL_8x8
if (MACH_IS_AMIGA && f->idx == PEARL8x8_IDX)
c = 100;
diff --git a/drivers/video/console/tileblit.c b/drivers/video/console/tileblit.c
index d981fe4d86c..0056a41e5c3 100644
--- a/drivers/video/console/tileblit.c
+++ b/drivers/video/console/tileblit.c
@@ -40,8 +40,8 @@ static void tile_clear(struct vc_data *vc, struct fb_info *info, int sy,
rect.index = vc->vc_video_erase_char &
((vc->vc_hi_font_mask) ? 0x1ff : 0xff);
- rect.fg = attr_fgcol_ec(fgshift, vc);
- rect.bg = attr_bgcol_ec(bgshift, vc);
+ rect.fg = attr_fgcol_ec(fgshift, vc, info);
+ rect.bg = attr_bgcol_ec(bgshift, vc, info);
rect.sx = sx;
rect.sy = sy;
rect.width = width;
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index f65bcd314d5..6df29a62d72 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -1153,8 +1153,6 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
/* if 512 char mode is already enabled don't re-enable it. */
if ((set) && (ch512 != vga_512_chars)) {
- int i;
-
/* attribute controller */
for (i = 0; i < MAX_NR_CONSOLES; i++) {
struct vc_data *c = vc_cons[i].d;
diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c
index a0c5d9d90d7..0f8cfb988c9 100644
--- a/drivers/video/fb_defio.c
+++ b/drivers/video/fb_defio.c
@@ -25,8 +25,8 @@
#include <linux/pagemap.h>
/* this is to find and return the vmalloc-ed fb pages */
-static struct page* fb_deferred_io_nopage(struct vm_area_struct *vma,
- unsigned long vaddr, int *type)
+static int fb_deferred_io_fault(struct vm_area_struct *vma,
+ struct vm_fault *vmf)
{
unsigned long offset;
struct page *page;
@@ -34,18 +34,17 @@ static struct page* fb_deferred_io_nopage(struct vm_area_struct *vma,
/* info->screen_base is in System RAM */
void *screen_base = (void __force *) info->screen_base;
- offset = (vaddr - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
+ offset = vmf->pgoff << PAGE_SHIFT;
if (offset >= info->fix.smem_len)
- return NOPAGE_SIGBUS;
+ return VM_FAULT_SIGBUS;
page = vmalloc_to_page(screen_base + offset);
if (!page)
- return NOPAGE_OOM;
+ return VM_FAULT_SIGBUS;
get_page(page);
- if (type)
- *type = VM_FAULT_MINOR;
- return page;
+ vmf->page = page;
+ return 0;
}
int fb_deferred_io_fsync(struct file *file, struct dentry *dentry, int datasync)
@@ -84,7 +83,7 @@ static int fb_deferred_io_mkwrite(struct vm_area_struct *vma,
}
static struct vm_operations_struct fb_deferred_io_vm_ops = {
- .nopage = fb_deferred_io_nopage,
+ .fault = fb_deferred_io_fault,
.page_mkwrite = fb_deferred_io_mkwrite,
};
diff --git a/drivers/video/fb_draw.h b/drivers/video/fb_draw.h
index cdafbe14ef1..a2a0618d86a 100644
--- a/drivers/video/fb_draw.h
+++ b/drivers/video/fb_draw.h
@@ -91,6 +91,7 @@ static inline unsigned long fb_rev_pixels_in_long(unsigned long val,
val = comp(val >> 2, val << 2, REV_PIXELS_MASK2);
if (bswapmask & 3)
val = comp(val >> 4, val << 4, REV_PIXELS_MASK4);
+ return val;
}
static inline u32 fb_shifted_pixels_mask_u32(u32 index, u32 bswapmask)
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
index 4ba9c089441..052e1805849 100644
--- a/drivers/video/fbmon.c
+++ b/drivers/video/fbmon.c
@@ -4,7 +4,7 @@
* Copyright (C) 2002 James Simmons <jsimmons@users.sf.net>
*
* Credits:
- *
+ *
* The EDID Parser is a conglomeration from the following sources:
*
* 1. SciTech SNAP Graphics Architecture
@@ -12,13 +12,13 @@
*
* 2. XFree86 4.3.0, interpret_edid.c
* Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE>
- *
- * 3. John Fremlin <vii@users.sourceforge.net> and
+ *
+ * 3. John Fremlin <vii@users.sourceforge.net> and
* Ani Joshi <ajoshi@unixbox.com>
- *
+ *
* Generalized Timing Formula is derived from:
*
- * GTF Spreadsheet by Andy Morrish (1/5/97)
+ * GTF Spreadsheet by Andy Morrish (1/5/97)
* available at http://www.vesa.org
*
* This file is subject to the terms and conditions of the GNU General Public
@@ -36,7 +36,7 @@
#endif
#include "edid.h"
-/*
+/*
* EDID parser
*/
@@ -160,8 +160,8 @@ static int check_edid(unsigned char *edid)
for (i = 0; i < ARRAY_SIZE(brokendb); i++) {
if (!strncmp(manufacturer, brokendb[i].manufacturer, 4) &&
brokendb[i].model == model) {
- fix = brokendb[i].fix;
- break;
+ fix = brokendb[i].fix;
+ break;
}
}
@@ -323,7 +323,7 @@ static void get_dpms_capabilities(unsigned char flags,
(flags & DPMS_SUSPEND) ? "yes" : "no",
(flags & DPMS_STANDBY) ? "yes" : "no");
}
-
+
static void get_chroma(unsigned char *block, struct fb_monspecs *specs)
{
int tmp;
@@ -365,7 +365,7 @@ static void get_chroma(unsigned char *block, struct fb_monspecs *specs)
tmp += 512;
specs->chroma.bluey = tmp/1024;
DPRINTK("BlueY: 0.%03d\n", specs->chroma.bluey);
-
+
tmp = ((block[6] & (3 << 2)) >> 2) | (block[0xd] << 2);
tmp *= 1000;
tmp += 512;
@@ -383,7 +383,7 @@ static void calc_mode_timings(int xres, int yres, int refresh,
struct fb_videomode *mode)
{
struct fb_var_screeninfo *var;
-
+
var = kzalloc(sizeof(struct fb_var_screeninfo), GFP_KERNEL);
if (var) {
@@ -451,11 +451,11 @@ static int get_est_timing(unsigned char *block, struct fb_videomode *mode)
c = block[1];
if (c&0x80) {
- mode[num++] = vesa_modes[9];
+ mode[num++] = vesa_modes[9];
DPRINTK(" 800x600@72Hz\n");
}
if (c&0x40) {
- mode[num++] = vesa_modes[10];
+ mode[num++] = vesa_modes[10];
DPRINTK(" 800x600@75Hz\n");
}
if (c&0x20) {
@@ -495,7 +495,7 @@ static int get_est_timing(unsigned char *block, struct fb_videomode *mode)
static int get_std_timing(unsigned char *block, struct fb_videomode *mode)
{
int xres, yres = 0, refresh, ratio, i;
-
+
xres = (block[0] + 31) * 8;
if (xres <= 256)
return 0;
@@ -519,7 +519,7 @@ static int get_std_timing(unsigned char *block, struct fb_videomode *mode)
DPRINTK(" %dx%d@%dHz\n", xres, yres, refresh);
for (i = 0; i < VESA_MODEDB_SIZE; i++) {
- if (vesa_modes[i].xres == xres &&
+ if (vesa_modes[i].xres == xres &&
vesa_modes[i].yres == yres &&
vesa_modes[i].refresh == refresh) {
*mode = vesa_modes[i];
@@ -536,13 +536,13 @@ static int get_dst_timing(unsigned char *block,
{
int j, num = 0;
- for (j = 0; j < 6; j++, block+= STD_TIMING_DESCRIPTION_SIZE)
+ for (j = 0; j < 6; j++, block += STD_TIMING_DESCRIPTION_SIZE)
num += get_std_timing(block, &mode[num]);
return num;
}
-static void get_detailed_timing(unsigned char *block,
+static void get_detailed_timing(unsigned char *block,
struct fb_videomode *mode)
{
mode->xres = H_ACTIVE;
@@ -553,7 +553,7 @@ static void get_detailed_timing(unsigned char *block,
mode->right_margin = H_SYNC_OFFSET;
mode->left_margin = (H_ACTIVE + H_BLANKING) -
(H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
- mode->upper_margin = V_BLANKING - V_SYNC_OFFSET -
+ mode->upper_margin = V_BLANKING - V_SYNC_OFFSET -
V_SYNC_WIDTH;
mode->lower_margin = V_SYNC_OFFSET;
mode->hsync_len = H_SYNC_WIDTH;
@@ -597,7 +597,7 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
if (mode == NULL)
return NULL;
- if (edid == NULL || !edid_checksum(edid) ||
+ if (edid == NULL || !edid_checksum(edid) ||
!edid_check_header(edid)) {
kfree(mode);
return NULL;
@@ -632,7 +632,7 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa)
num += get_dst_timing(block + 5, &mode[num]);
}
-
+
/* Yikes, EDID data is totally useless */
if (!num) {
kfree(mode);
@@ -686,7 +686,7 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
/* estimate monitor limits based on modes supported */
if (retval) {
struct fb_videomode *modes, *mode;
- int num_modes, i, hz, hscan, pixclock;
+ int num_modes, hz, hscan, pixclock;
int vtotal, htotal;
modes = fb_create_modedb(edid, &num_modes);
@@ -713,7 +713,7 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
hscan = (pixclock + htotal / 2) / htotal;
hscan = (hscan + 500) / 1000 * 1000;
hz = (hscan + vtotal / 2) / vtotal;
-
+
if (specs->dclkmax == 0 || specs->dclkmax < pixclock)
specs->dclkmax = pixclock;
@@ -966,8 +966,8 @@ void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
DPRINTK("========================================\n");
}
-/*
- * VESA Generalized Timing Formula (GTF)
+/*
+ * VESA Generalized Timing Formula (GTF)
*/
#define FLYBACK 550
@@ -996,7 +996,7 @@ struct __fb_timings {
* @hfreq: horizontal freq
*
* DESCRIPTION:
- * vblank = right_margin + vsync_len + left_margin
+ * vblank = right_margin + vsync_len + left_margin
*
* given: right_margin = 1 (V_FRONTPORCH)
* vsync_len = 3
@@ -1010,12 +1010,12 @@ static u32 fb_get_vblank(u32 hfreq)
{
u32 vblank;
- vblank = (hfreq * FLYBACK)/1000;
+ vblank = (hfreq * FLYBACK)/1000;
vblank = (vblank + 500)/1000;
return (vblank + V_FRONTPORCH);
}
-/**
+/**
* fb_get_hblank_by_freq - get horizontal blank time given hfreq
* @hfreq: horizontal freq
* @xres: horizontal resolution in pixels
@@ -1031,7 +1031,7 @@ static u32 fb_get_vblank(u32 hfreq)
*
* where: C = ((offset - scale factor) * blank_scale)
* -------------------------------------- + scale factor
- * 256
+ * 256
* M = blank_scale * gradient
*
*/
@@ -1039,7 +1039,7 @@ static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres)
{
u32 c_val, m_val, duty_cycle, hblank;
- c_val = (((H_OFFSET - H_SCALEFACTOR) * H_BLANKSCALE)/256 +
+ c_val = (((H_OFFSET - H_SCALEFACTOR) * H_BLANKSCALE)/256 +
H_SCALEFACTOR) * 1000;
m_val = (H_BLANKSCALE * H_GRADIENT)/256;
m_val = (m_val * 1000000)/hfreq;
@@ -1048,7 +1048,7 @@ static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres)
return (hblank);
}
-/**
+/**
* fb_get_hblank_by_dclk - get horizontal blank time given pixelclock
* @dclk: pixelclock in Hz
* @xres: horizontal resolution in pixels
@@ -1061,7 +1061,7 @@ static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres)
*
* duty cycle = percent of htotal assigned to inactive display
* duty cycle = C - (M * h_period)
- *
+ *
* where: h_period = SQRT(100 - C + (0.4 * xres * M)/dclk) + C - 100
* -----------------------------------------------
* 2 * M
@@ -1077,11 +1077,11 @@ static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres)
h_period = 100 - C_VAL;
h_period *= h_period;
h_period += (M_VAL * xres * 2 * 1000)/(5 * dclk);
- h_period *=10000;
+ h_period *= 10000;
h_period = int_sqrt(h_period);
h_period -= (100 - C_VAL) * 100;
- h_period *= 1000;
+ h_period *= 1000;
h_period /= 2 * M_VAL;
duty_cycle = C_VAL * 1000 - (M_VAL * h_period)/100;
@@ -1089,7 +1089,7 @@ static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres)
hblank &= ~15;
return (hblank);
}
-
+
/**
* fb_get_hfreq - estimate hsync
* @vfreq: vertical refresh rate
@@ -1100,13 +1100,13 @@ static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres)
* (yres + front_port) * vfreq * 1000000
* hfreq = -------------------------------------
* (1000000 - (vfreq * FLYBACK)
- *
+ *
*/
static u32 fb_get_hfreq(u32 vfreq, u32 yres)
{
u32 divisor, hfreq;
-
+
divisor = (1000000 - (vfreq * FLYBACK))/1000;
hfreq = (yres + V_FRONTPORCH) * vfreq * 1000;
return (hfreq/divisor);
@@ -1117,7 +1117,7 @@ static void fb_timings_vfreq(struct __fb_timings *timings)
timings->hfreq = fb_get_hfreq(timings->vfreq, timings->vactive);
timings->vblank = fb_get_vblank(timings->hfreq);
timings->vtotal = timings->vactive + timings->vblank;
- timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq,
+ timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq,
timings->hactive);
timings->htotal = timings->hactive + timings->hblank;
timings->dclk = timings->htotal * timings->hfreq;
@@ -1128,7 +1128,7 @@ static void fb_timings_hfreq(struct __fb_timings *timings)
timings->vblank = fb_get_vblank(timings->hfreq);
timings->vtotal = timings->vactive + timings->vblank;
timings->vfreq = timings->hfreq/timings->vtotal;
- timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq,
+ timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq,
timings->hactive);
timings->htotal = timings->hactive + timings->hblank;
timings->dclk = timings->htotal * timings->hfreq;
@@ -1136,7 +1136,7 @@ static void fb_timings_hfreq(struct __fb_timings *timings)
static void fb_timings_dclk(struct __fb_timings *timings)
{
- timings->hblank = fb_get_hblank_by_dclk(timings->dclk,
+ timings->hblank = fb_get_hblank_by_dclk(timings->dclk,
timings->hactive);
timings->htotal = timings->hactive + timings->hblank;
timings->hfreq = timings->dclk/timings->htotal;
@@ -1156,29 +1156,29 @@ static void fb_timings_dclk(struct __fb_timings *timings)
* @info: pointer to fb_info
*
* DESCRIPTION:
- * Calculates video mode based on monitor specs using VESA GTF.
- * The GTF is best for VESA GTF compliant monitors but is
+ * Calculates video mode based on monitor specs using VESA GTF.
+ * The GTF is best for VESA GTF compliant monitors but is
* specifically formulated to work for older monitors as well.
*
- * If @flag==0, the function will attempt to maximize the
+ * If @flag==0, the function will attempt to maximize the
* refresh rate. Otherwise, it will calculate timings based on
- * the flag and accompanying value.
+ * the flag and accompanying value.
*
- * If FB_IGNOREMON bit is set in @flags, monitor specs will be
+ * If FB_IGNOREMON bit is set in @flags, monitor specs will be
* ignored and @var will be filled with the calculated timings.
*
* All calculations are based on the VESA GTF Spreadsheet
* available at VESA's public ftp (http://www.vesa.org).
- *
+ *
* NOTES:
* The timings generated by the GTF will be different from VESA
* DMT. It might be a good idea to keep a table of standard
* VESA modes as well. The GTF may also not work for some displays,
* such as, and especially, analog TV.
- *
+ *
* REQUIRES:
* A valid info->monspecs, otherwise 'safe numbers' will be used.
- */
+ */
int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_info *info)
{
struct __fb_timings *timings;
@@ -1191,7 +1191,7 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf
if (!timings)
return -ENOMEM;
- /*
+ /*
* If monspecs are invalid, use values that are enough
* for 640x480@60
*/
@@ -1214,7 +1214,7 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf
timings->hactive = var->xres;
timings->vactive = var->yres;
- if (var->vmode & FB_VMODE_INTERLACED) {
+ if (var->vmode & FB_VMODE_INTERLACED) {
timings->vactive /= 2;
interlace = 2;
}
@@ -1250,9 +1250,9 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf
break;
default:
err = -EINVAL;
-
- }
-
+
+ }
+
if (err || (!(flags & FB_IGNOREMON) &&
(timings->vfreq < vfmin || timings->vfreq > vfmax ||
timings->hfreq < hfmin || timings->hfreq > hfmax ||
@@ -1269,7 +1269,7 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf
var->upper_margin = (timings->vblank * interlace)/dscan -
(var->vsync_len + var->lower_margin);
}
-
+
kfree(timings);
return err;
}
@@ -1291,7 +1291,7 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var,
return -EINVAL;
}
#endif /* CONFIG_FB_MODE_HELPERS */
-
+
/*
* fb_validate_mode - validates var against monitor capabilities
* @var: pointer to fb_var_screeninfo
@@ -1309,7 +1309,7 @@ int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info)
u32 hfreq, vfreq, htotal, vtotal, pixclock;
u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax;
- /*
+ /*
* If monspecs are invalid, use values that are enough
* for 640x480@60
*/
@@ -1333,10 +1333,10 @@ int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info)
if (!var->pixclock)
return -EINVAL;
pixclock = PICOS2KHZ(var->pixclock) * 1000;
-
- htotal = var->xres + var->right_margin + var->hsync_len +
+
+ htotal = var->xres + var->right_margin + var->hsync_len +
var->left_margin;
- vtotal = var->yres + var->lower_margin + var->vsync_len +
+ vtotal = var->yres + var->lower_margin + var->vsync_len +
var->upper_margin;
if (var->vmode & FB_VMODE_INTERLACED)
@@ -1349,7 +1349,7 @@ int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info)
vfreq = hfreq/vtotal;
- return (vfreq < vfmin || vfreq > vfmax ||
+ return (vfreq < vfmin || vfreq > vfmax ||
hfreq < hfmin || hfreq > hfmax ||
pixclock < dclkmin || pixclock > dclkmax) ?
-EINVAL : 0;
diff --git a/drivers/video/geode/lxfb_core.c b/drivers/video/geode/lxfb_core.c
index 583185fd7c9..eb6b8817153 100644
--- a/drivers/video/geode/lxfb_core.c
+++ b/drivers/video/geode/lxfb_core.c
@@ -34,7 +34,7 @@ static int fbsize;
* we try to make it something sane - 640x480-60 is sane
*/
-const struct fb_videomode geode_modedb[] __initdata = {
+static const struct fb_videomode geode_modedb[] __initdata = {
/* 640x480-60 */
{ NULL, 60, 640, 480, 39682, 48, 8, 25, 2, 88, 2,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
diff --git a/drivers/video/hpfb.c b/drivers/video/hpfb.c
index b18486ad8e1..2eb4fb15908 100644
--- a/drivers/video/hpfb.c
+++ b/drivers/video/hpfb.c
@@ -207,7 +207,8 @@ static struct fb_ops hpfb_ops = {
#define HPFB_FBOMSB 0x5d /* Frame buffer offset */
#define HPFB_FBOLSB 0x5f
-static int __init hpfb_init_one(unsigned long phys_base, unsigned long virt_base)
+static int __devinit hpfb_init_one(unsigned long phys_base,
+ unsigned long virt_base)
{
unsigned long fboff, fb_width, fb_height, fb_start;
diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c
index 1a7d7789d87..1d13dd099af 100644
--- a/drivers/video/i810/i810_main.c
+++ b/drivers/video/i810/i810_main.c
@@ -1476,7 +1476,7 @@ static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
struct i810fb_par *par = info->par;
u8 __iomem *mmio = par->mmio_start_virtual;
- if (!par->dev_flags & LOCKUP)
+ if (!(par->dev_flags & LOCKUP))
return -ENXIO;
if (cursor->image.width > 64 || cursor->image.height > 64)
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
index b87ea21d3d7..3a81060137a 100644
--- a/drivers/video/igafb.c
+++ b/drivers/video/igafb.c
@@ -400,6 +400,7 @@ int __init igafb_init(void)
info = kzalloc(size, GFP_ATOMIC);
if (!info) {
printk("igafb_init: can't alloc fb_info\n");
+ pci_dev_put(pdev);
return -ENOMEM;
}
@@ -409,12 +410,14 @@ int __init igafb_init(void)
if ((addr = pdev->resource[0].start) == 0) {
printk("igafb_init: no memory start\n");
kfree(info);
+ pci_dev_put(pdev);
return -ENXIO;
}
if ((info->screen_base = ioremap(addr, 1024*1024*2)) == 0) {
printk("igafb_init: can't remap %lx[2M]\n", addr);
kfree(info);
+ pci_dev_put(pdev);
return -ENXIO;
}
@@ -449,6 +452,7 @@ int __init igafb_init(void)
printk("igafb_init: can't remap %lx[4K]\n", igafb_fix.mmio_start);
iounmap((void *)info->screen_base);
kfree(info);
+ pci_dev_put(pdev);
return -ENXIO;
}
@@ -466,6 +470,7 @@ int __init igafb_init(void)
iounmap((void *)par->io_base);
iounmap(info->screen_base);
kfree(info);
+ pci_dev_put(pdev);
return -ENOMEM;
}
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 5f6fb7d2c40..fa1fff55356 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -1971,7 +1971,7 @@ void intelfbhw_cursor_reset(struct intelfb_info *dinfo)
static irqreturn_t intelfbhw_irq(int irq, void *dev_id)
{
u16 tmp;
- struct intelfb_info *dinfo = (struct intelfb_info *)dev_id;
+ struct intelfb_info *dinfo = dev_id;
spin_lock(&dinfo->int_lock);
diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c
index 4b6a99b5be0..5246b0402d7 100644
--- a/drivers/video/neofb.c
+++ b/drivers/video/neofb.c
@@ -2066,40 +2066,49 @@ static struct fb_info *__devinit neo_alloc_fb_info(struct pci_dev *dev, const st
switch (info->fix.accel) {
case FB_ACCEL_NEOMAGIC_NM2070:
- sprintf(info->fix.id, "MagicGraph 128");
+ snprintf(info->fix.id, sizeof(info->fix.id),
+ "MagicGraph 128");
break;
case FB_ACCEL_NEOMAGIC_NM2090:
- sprintf(info->fix.id, "MagicGraph 128V");
+ snprintf(info->fix.id, sizeof(info->fix.id),
+ "MagicGraph 128V");
break;
case FB_ACCEL_NEOMAGIC_NM2093:
- sprintf(info->fix.id, "MagicGraph 128ZV");
+ snprintf(info->fix.id, sizeof(info->fix.id),
+ "MagicGraph 128ZV");
break;
case FB_ACCEL_NEOMAGIC_NM2097:
- sprintf(info->fix.id, "MagicGraph 128ZV+");
+ snprintf(info->fix.id, sizeof(info->fix.id),
+ "MagicGraph 128ZV+");
break;
case FB_ACCEL_NEOMAGIC_NM2160:
- sprintf(info->fix.id, "MagicGraph 128XD");
+ snprintf(info->fix.id, sizeof(info->fix.id),
+ "MagicGraph 128XD");
break;
case FB_ACCEL_NEOMAGIC_NM2200:
- sprintf(info->fix.id, "MagicGraph 256AV");
+ snprintf(info->fix.id, sizeof(info->fix.id),
+ "MagicGraph 256AV");
info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
FBINFO_HWACCEL_COPYAREA |
FBINFO_HWACCEL_FILLRECT;
break;
case FB_ACCEL_NEOMAGIC_NM2230:
- sprintf(info->fix.id, "MagicGraph 256AV+");
+ snprintf(info->fix.id, sizeof(info->fix.id),
+ "MagicGraph 256AV+");
info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
FBINFO_HWACCEL_COPYAREA |
FBINFO_HWACCEL_FILLRECT;
break;
case FB_ACCEL_NEOMAGIC_NM2360:
- sprintf(info->fix.id, "MagicGraph 256ZX");
+ snprintf(info->fix.id, sizeof(info->fix.id),
+ "MagicGraph 256ZX");
info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
FBINFO_HWACCEL_COPYAREA |
FBINFO_HWACCEL_FILLRECT;
break;
case FB_ACCEL_NEOMAGIC_NM2380:
- sprintf(info->fix.id, "MagicGraph 256XL+");
+ snprintf(info->fix.id, sizeof(info->fix.id),
+ "MagicGraph 256XL+");
info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
FBINFO_HWACCEL_COPYAREA |
FBINFO_HWACCEL_FILLRECT;
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index 30e14eb1f51..74517b1b26a 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -849,9 +849,27 @@ static int nvidiafb_check_var(struct fb_var_screeninfo *var,
if (!mode_valid && info->monspecs.modedb_len)
return -EINVAL;
+ /*
+ * If we're on a flat panel, check if the mode is outside of the
+ * panel dimensions. If so, cap it and try for the next best mode
+ * before bailing out.
+ */
if (par->fpWidth && par->fpHeight && (par->fpWidth < var->xres ||
- par->fpHeight < var->yres))
- return -EINVAL;
+ par->fpHeight < var->yres)) {
+ const struct fb_videomode *mode;
+
+ var->xres = par->fpWidth;
+ var->yres = par->fpHeight;
+
+ mode = fb_find_best_mode(var, &info->modelist);
+ if (!mode) {
+ printk(KERN_ERR PFX "mode out of range of flat "
+ "panel dimensions\n");
+ return -EINVAL;
+ }
+
+ fb_videomode_to_var(var, mode);
+ }
if (var->yres_virtual < var->yres)
var->yres_virtual = var->yres;
diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c
index 5591dfb22b1..30181b59382 100644
--- a/drivers/video/pm2fb.c
+++ b/drivers/video/pm2fb.c
@@ -1159,6 +1159,11 @@ static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image)
u32 fgx, bgx;
const u32 *src = (const u32 *)image->data;
u32 xres = (info->var.xres + 31) & ~31;
+ int raster_mode = 1; /* invert bits */
+
+#ifdef __LITTLE_ENDIAN
+ raster_mode |= 3 << 7; /* reverse byte order */
+#endif
if (info->state != FBINFO_STATE_RUNNING)
return;
@@ -1208,9 +1213,8 @@ static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image)
pm2_WR(par, PM2R_RENDER,
PM2F_RENDER_RECTANGLE |
PM2F_INCREASE_X | PM2F_INCREASE_Y);
- /* BitMapPackEachScanline & invert bits and byte order*/
- /* force background */
- pm2_WR(par, PM2R_RASTERIZER_MODE, (1 << 9) | 1 | (3 << 7));
+ /* BitMapPackEachScanline */
+ pm2_WR(par, PM2R_RASTERIZER_MODE, raster_mode | (1 << 9));
pm2_WR(par, PM2R_CONSTANT_COLOR, fgx);
pm2_WR(par, PM2R_RENDER,
PM2F_RENDER_RECTANGLE |
@@ -1224,8 +1228,7 @@ static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image)
PM2F_RENDER_RECTANGLE |
PM2F_RENDER_FASTFILL |
PM2F_INCREASE_X | PM2F_INCREASE_Y);
- /* invert bits and byte order*/
- pm2_WR(par, PM2R_RASTERIZER_MODE, 1 | (3 << 7));
+ pm2_WR(par, PM2R_RASTERIZER_MODE, raster_mode);
pm2_WR(par, PM2R_FB_BLOCK_COLOR, fgx);
pm2_WR(par, PM2R_RENDER,
PM2F_RENDER_RECTANGLE |
diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c
index 070659992c1..5dba8cdd051 100644
--- a/drivers/video/pm3fb.c
+++ b/drivers/video/pm3fb.c
@@ -1227,7 +1227,7 @@ static struct fb_ops pm3fb_ops = {
/* mmio register are already mapped when this function is called */
/* the pm3fb_fix.smem_start is also set */
-static unsigned long pm3fb_size_memory(struct pm3_par *par)
+static unsigned long __devinit pm3fb_size_memory(struct pm3_par *par)
{
unsigned long memsize = 0;
unsigned long tempBypass, i, temp1, temp2;
diff --git a/drivers/video/pmag-aa-fb.c b/drivers/video/pmag-aa-fb.c
index a864438b600..6515ec11c16 100644
--- a/drivers/video/pmag-aa-fb.c
+++ b/drivers/video/pmag-aa-fb.c
@@ -150,7 +150,7 @@ static int aafbcon_set_font(struct display *disp, int width, int height)
{
struct aafb_info *info = (struct aafb_info *)disp->fb_info;
struct aafb_cursor *c = &info->cursor;
- u8 fgc = ~attr_bgcol_ec(disp, disp->conp);
+ u8 fgc = ~attr_bgcol_ec(disp, disp->conp, &info->info);
if (width > 64 || height > 64 || width < 0 || height < 0)
return -EINVAL;
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
index 044a423a72c..dc3af1c78c5 100644
--- a/drivers/video/ps3fb.c
+++ b/drivers/video/ps3fb.c
@@ -57,8 +57,6 @@
#define GPU_ALIGN_UP(x) _ALIGN_UP((x), 64)
#define GPU_MAX_LINE_LENGTH (65536 - 64)
-#define PS3FB_FULL_MODE_BIT 0x80
-
#define GPU_INTR_STATUS_VSYNC_0 0 /* vsync on head A */
#define GPU_INTR_STATUS_VSYNC_1 1 /* vsync on head B */
#define GPU_INTR_STATUS_FLIP_0 3 /* flip head A */
@@ -118,8 +116,6 @@ struct ps3fb_priv {
unsigned int irq_no;
u64 context_handle, memory_handle;
- void *xdr_ea;
- size_t xdr_size;
struct gpu_driver_info *dinfo;
u64 vblank_count; /* frame count */
@@ -136,42 +132,19 @@ static struct ps3fb_priv ps3fb;
struct ps3fb_par {
u32 pseudo_palette[16];
int mode_id, new_mode_id;
- int res_index;
unsigned int num_frames; /* num of frame buffers */
unsigned int width;
unsigned int height;
- unsigned long full_offset; /* start of fullscreen DDR fb */
- unsigned long fb_offset; /* start of actual DDR fb */
- unsigned long pan_offset;
+ unsigned int ddr_line_length;
+ unsigned int ddr_frame_size;
+ unsigned int xdr_frame_size;
+ unsigned int full_offset; /* start of fullscreen DDR fb */
+ unsigned int fb_offset; /* start of actual DDR fb */
+ unsigned int pan_offset;
};
-struct ps3fb_res_table {
- u32 xres;
- u32 yres;
- u32 xoff;
- u32 yoff;
- u32 type;
-};
-#define PS3FB_RES_FULL 1
-static const struct ps3fb_res_table ps3fb_res[] = {
- /* res_x,y margin_x,y full */
- { 720, 480, 72, 48 , 0},
- { 720, 576, 72, 58 , 0},
- { 1280, 720, 78, 38 , 0},
- { 1920, 1080, 116, 58 , 0},
- /* full mode */
- { 720, 480, 0, 0 , PS3FB_RES_FULL},
- { 720, 576, 0, 0 , PS3FB_RES_FULL},
- { 1280, 720, 0, 0 , PS3FB_RES_FULL},
- { 1920, 1080, 0, 0 , PS3FB_RES_FULL},
- /* vesa: normally full mode */
- { 1280, 768, 0, 0 , 0},
- { 1280, 1024, 0, 0 , 0},
- { 1920, 1200, 0, 0 , 0},
- { 0, 0, 0, 0 , 0} };
-
-/* default resolution */
-#define GPU_RES_INDEX 0 /* 720 x 480 */
+
+#define FIRST_NATIVE_MODE_INDEX 10
static const struct fb_videomode ps3fb_modedb[] = {
/* 60 Hz broadcast modes (modes "1" to "5") */
@@ -211,7 +184,7 @@ static const struct fb_videomode ps3fb_modedb[] = {
"720p", 50, 1124, 644, 13468, 298, 478, 57, 44, 80, 5,
FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
}, {
- /* 1080 */
+ /* 1080i */
"1080i", 50, 1688, 964, 13468, 264, 600, 94, 62, 88, 5,
FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
}, {
@@ -220,24 +193,7 @@ static const struct fb_videomode ps3fb_modedb[] = {
FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
},
- /* VESA modes (modes "11" to "13") */
- {
- /* WXGA */
- "wxga", 60, 1280, 768, 12924, 160, 24, 29, 3, 136, 6,
- 0, FB_VMODE_NONINTERLACED,
- FB_MODE_IS_VESA
- }, {
- /* SXGA */
- "sxga", 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
- FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED,
- FB_MODE_IS_VESA
- }, {
- /* WUXGA */
- "wuxga", 60, 1920, 1200, 6494, 80, 48, 26, 3, 32, 6,
- FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED,
- FB_MODE_IS_VESA
- },
-
+ [FIRST_NATIVE_MODE_INDEX] =
/* 60 Hz broadcast modes (full resolution versions of modes "1" to "5") */
{
/* 480if */
@@ -276,12 +232,30 @@ static const struct fb_videomode ps3fb_modedb[] = {
FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
}, {
/* 1080if */
- "1080f", 50, 1920, 1080, 13468, 148, 484, 36, 4, 88, 5,
+ "1080if", 50, 1920, 1080, 13468, 148, 484, 36, 4, 88, 5,
FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
}, {
/* 1080pf */
"1080pf", 50, 1920, 1080, 6734, 148, 484, 36, 4, 88, 5,
FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
+ },
+
+ /* VESA modes (modes "11" to "13") */
+ {
+ /* WXGA */
+ "wxga", 60, 1280, 768, 12924, 160, 24, 29, 3, 136, 6,
+ 0, FB_VMODE_NONINTERLACED,
+ FB_MODE_IS_VESA
+ }, {
+ /* SXGA */
+ "sxga", 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED,
+ FB_MODE_IS_VESA
+ }, {
+ /* WUXGA */
+ "wuxga", 60, 1920, 1200, 6494, 80, 48, 26, 3, 32, 6,
+ FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED,
+ FB_MODE_IS_VESA
}
};
@@ -289,110 +263,188 @@ static const struct fb_videomode ps3fb_modedb[] = {
#define HEAD_A
#define HEAD_B
-#define X_OFF(i) (ps3fb_res[i].xoff) /* left/right margin (pixel) */
-#define Y_OFF(i) (ps3fb_res[i].yoff) /* top/bottom margin (pixel) */
-#define WIDTH(i) (ps3fb_res[i].xres) /* width of FB */
-#define HEIGHT(i) (ps3fb_res[i].yres) /* height of FB */
#define BPP 4 /* number of bytes per pixel */
-/* Start of the virtual frame buffer (relative to fullscreen ) */
-#define VP_OFF(i) ((WIDTH(i) * Y_OFF(i) + X_OFF(i)) * BPP)
-
static int ps3fb_mode;
module_param(ps3fb_mode, int, 0);
static char *mode_option __devinitdata;
-static int ps3fb_get_res_table(u32 xres, u32 yres, int mode)
+static int ps3fb_cmp_mode(const struct fb_videomode *vmode,
+ const struct fb_var_screeninfo *var)
{
- int full_mode;
- unsigned int i;
- u32 x, y, f;
-
- full_mode = (mode & PS3FB_FULL_MODE_BIT) ? PS3FB_RES_FULL : 0;
- for (i = 0;; i++) {
- x = ps3fb_res[i].xres;
- y = ps3fb_res[i].yres;
- f = ps3fb_res[i].type;
-
- if (!x) {
- pr_debug("ERROR: ps3fb_get_res_table()\n");
- return -1;
- }
+ long xres, yres, left_margin, right_margin, upper_margin, lower_margin;
+ long dx, dy;
+
+ /* maximum values */
+ if (var->xres > vmode->xres || var->yres > vmode->yres ||
+ var->pixclock > vmode->pixclock ||
+ var->hsync_len > vmode->hsync_len ||
+ var->vsync_len > vmode->vsync_len)
+ return -1;
- if (full_mode == PS3FB_RES_FULL && f != PS3FB_RES_FULL)
- continue;
+ /* progressive/interlaced must match */
+ if ((var->vmode & FB_VMODE_MASK) != vmode->vmode)
+ return -1;
- if (x == xres && (yres == 0 || y == yres))
- break;
+ /* minimum resolution */
+ xres = max(var->xres, 1U);
+ yres = max(var->yres, 1U);
+
+ /* minimum margins */
+ left_margin = max(var->left_margin, vmode->left_margin);
+ right_margin = max(var->right_margin, vmode->right_margin);
+ upper_margin = max(var->upper_margin, vmode->upper_margin);
+ lower_margin = max(var->lower_margin, vmode->lower_margin);
+
+ /* resolution + margins may not exceed native parameters */
+ dx = ((long)vmode->left_margin + (long)vmode->xres +
+ (long)vmode->right_margin) -
+ (left_margin + xres + right_margin);
+ if (dx < 0)
+ return -1;
- x = x - 2 * ps3fb_res[i].xoff;
- y = y - 2 * ps3fb_res[i].yoff;
- if (x == xres && (yres == 0 || y == yres))
- break;
+ dy = ((long)vmode->upper_margin + (long)vmode->yres +
+ (long)vmode->lower_margin) -
+ (upper_margin + yres + lower_margin);
+ if (dy < 0)
+ return -1;
+
+ /* exact match */
+ if (!dx && !dy)
+ return 0;
+
+ /* resolution difference */
+ return (vmode->xres - xres) * (vmode->yres - yres);
+}
+
+static const struct fb_videomode *ps3fb_native_vmode(enum ps3av_mode_num id)
+{
+ return &ps3fb_modedb[FIRST_NATIVE_MODE_INDEX + id - 1];
+}
+
+static const struct fb_videomode *ps3fb_vmode(int id)
+{
+ u32 mode = id & PS3AV_MODE_MASK;
+
+ if (mode < PS3AV_MODE_480I || mode > PS3AV_MODE_WUXGA)
+ return NULL;
+
+ if (mode <= PS3AV_MODE_1080P50 && !(id & PS3AV_MODE_FULL)) {
+ /* Non-fullscreen broadcast mode */
+ return &ps3fb_modedb[mode - 1];
}
- return i;
+
+ return ps3fb_native_vmode(mode);
}
-static unsigned int ps3fb_find_mode(const struct fb_var_screeninfo *var,
+static unsigned int ps3fb_find_mode(struct fb_var_screeninfo *var,
u32 *ddr_line_length, u32 *xdr_line_length)
{
- unsigned int i, mode;
-
- for (i = 0; i < ARRAY_SIZE(ps3fb_modedb); i++)
- if (var->xres == ps3fb_modedb[i].xres &&
- var->yres == ps3fb_modedb[i].yres &&
- var->pixclock == ps3fb_modedb[i].pixclock &&
- var->hsync_len == ps3fb_modedb[i].hsync_len &&
- var->vsync_len == ps3fb_modedb[i].vsync_len &&
- var->left_margin == ps3fb_modedb[i].left_margin &&
- var->right_margin == ps3fb_modedb[i].right_margin &&
- var->upper_margin == ps3fb_modedb[i].upper_margin &&
- var->lower_margin == ps3fb_modedb[i].lower_margin &&
- var->sync == ps3fb_modedb[i].sync &&
- (var->vmode & FB_VMODE_MASK) == ps3fb_modedb[i].vmode)
- goto found;
-
- pr_debug("ps3fb_find_mode: mode not found\n");
- return 0;
+ unsigned int id, best_id;
+ int diff, best_diff;
+ const struct fb_videomode *vmode;
+ long gap;
+
+ best_id = 0;
+ best_diff = INT_MAX;
+ pr_debug("%s: wanted %u [%u] %u x %u [%u] %u\n", __func__,
+ var->left_margin, var->xres, var->right_margin,
+ var->upper_margin, var->yres, var->lower_margin);
+ for (id = PS3AV_MODE_480I; id <= PS3AV_MODE_WUXGA; id++) {
+ vmode = ps3fb_native_vmode(id);
+ diff = ps3fb_cmp_mode(vmode, var);
+ pr_debug("%s: mode %u: %u [%u] %u x %u [%u] %u: diff = %d\n",
+ __func__, id, vmode->left_margin, vmode->xres,
+ vmode->right_margin, vmode->upper_margin,
+ vmode->yres, vmode->lower_margin, diff);
+ if (diff < 0)
+ continue;
+ if (diff < best_diff) {
+ best_id = id;
+ if (!diff)
+ break;
+ best_diff = diff;
+ }
+ }
-found:
- /* Cropped broadcast modes use the full line length */
- *ddr_line_length = ps3fb_modedb[i < 10 ? i + 13 : i].xres * BPP;
+ if (!best_id) {
+ pr_debug("%s: no suitable mode found\n", __func__);
+ return 0;
+ }
- if (ps3_compare_firmware_version(1, 9, 0) >= 0) {
- *xdr_line_length = GPU_ALIGN_UP(max(var->xres,
- var->xres_virtual) * BPP);
- if (*xdr_line_length > GPU_MAX_LINE_LENGTH)
- *xdr_line_length = GPU_MAX_LINE_LENGTH;
- } else
- *xdr_line_length = *ddr_line_length;
+ id = best_id;
+ vmode = ps3fb_native_vmode(id);
- /* Full broadcast modes have the full mode bit set */
- mode = i > 12 ? (i - 12) | PS3FB_FULL_MODE_BIT : i + 1;
+ *ddr_line_length = vmode->xres * BPP;
- pr_debug("ps3fb_find_mode: mode %u\n", mode);
+ /* minimum resolution */
+ if (!var->xres)
+ var->xres = 1;
+ if (!var->yres)
+ var->yres = 1;
- return mode;
-}
+ /* minimum virtual resolution */
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
-static const struct fb_videomode *ps3fb_default_mode(int id)
-{
- u32 mode = id & PS3AV_MODE_MASK;
- u32 flags;
+ /* minimum margins */
+ if (var->left_margin < vmode->left_margin)
+ var->left_margin = vmode->left_margin;
+ if (var->right_margin < vmode->right_margin)
+ var->right_margin = vmode->right_margin;
+ if (var->upper_margin < vmode->upper_margin)
+ var->upper_margin = vmode->upper_margin;
+ if (var->lower_margin < vmode->lower_margin)
+ var->lower_margin = vmode->lower_margin;
+
+ /* extra margins */
+ gap = ((long)vmode->left_margin + (long)vmode->xres +
+ (long)vmode->right_margin) -
+ ((long)var->left_margin + (long)var->xres +
+ (long)var->right_margin);
+ if (gap > 0) {
+ var->left_margin += gap/2;
+ var->right_margin += (gap+1)/2;
+ pr_debug("%s: rounded up H to %u [%u] %u\n", __func__,
+ var->left_margin, var->xres, var->right_margin);
+ }
- if (mode < 1 || mode > 13)
- return NULL;
+ gap = ((long)vmode->upper_margin + (long)vmode->yres +
+ (long)vmode->lower_margin) -
+ ((long)var->upper_margin + (long)var->yres +
+ (long)var->lower_margin);
+ if (gap > 0) {
+ var->upper_margin += gap/2;
+ var->lower_margin += (gap+1)/2;
+ pr_debug("%s: rounded up V to %u [%u] %u\n", __func__,
+ var->upper_margin, var->yres, var->lower_margin);
+ }
+
+ /* fixed fields */
+ var->pixclock = vmode->pixclock;
+ var->hsync_len = vmode->hsync_len;
+ var->vsync_len = vmode->vsync_len;
+ var->sync = vmode->sync;
- flags = id & ~PS3AV_MODE_MASK;
+ if (ps3_compare_firmware_version(1, 9, 0) >= 0) {
+ *xdr_line_length = GPU_ALIGN_UP(var->xres_virtual * BPP);
+ if (*xdr_line_length > GPU_MAX_LINE_LENGTH)
+ *xdr_line_length = GPU_MAX_LINE_LENGTH;
+ } else
+ *xdr_line_length = *ddr_line_length;
- if (mode <= 10 && flags & PS3FB_FULL_MODE_BIT) {
- /* Full broadcast mode */
- return &ps3fb_modedb[mode + 12];
+ if (vmode->sync & FB_SYNC_BROADCAST) {
+ /* Full broadcast modes have the full mode bit set */
+ if (vmode->xres == var->xres && vmode->yres == var->yres)
+ id |= PS3AV_MODE_FULL;
}
- return &ps3fb_modedb[mode - 1];
+ pr_debug("%s: mode %u\n", __func__, id);
+ return id;
}
static void ps3fb_sync_image(struct device *dev, u64 frame_offset,
@@ -439,8 +491,7 @@ static void ps3fb_sync_image(struct device *dev, u64 frame_offset,
static int ps3fb_sync(struct fb_info *info, u32 frame)
{
struct ps3fb_par *par = info->par;
- int i, error = 0;
- u32 ddr_line_length, xdr_line_length;
+ int error = 0;
u64 ddr_base, xdr_base;
if (frame > par->num_frames - 1) {
@@ -450,16 +501,13 @@ static int ps3fb_sync(struct fb_info *info, u32 frame)
goto out;
}
- i = par->res_index;
- xdr_line_length = info->fix.line_length;
- ddr_line_length = ps3fb_res[i].xres * BPP;
- xdr_base = frame * info->var.yres_virtual * xdr_line_length;
- ddr_base = frame * ps3fb_res[i].yres * ddr_line_length;
+ xdr_base = frame * par->xdr_frame_size;
+ ddr_base = frame * par->ddr_frame_size;
ps3fb_sync_image(info->device, ddr_base + par->full_offset,
ddr_base + par->fb_offset, xdr_base + par->pan_offset,
- par->width, par->height, ddr_line_length,
- xdr_line_length);
+ par->width, par->height, par->ddr_line_length,
+ info->fix.line_length);
out:
return error;
@@ -498,22 +546,11 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
u32 xdr_line_length, ddr_line_length;
int mode;
- dev_dbg(info->device, "var->xres:%u info->var.xres:%u\n", var->xres,
- info->var.xres);
- dev_dbg(info->device, "var->yres:%u info->var.yres:%u\n", var->yres,
- info->var.yres);
-
- /* FIXME For now we do exact matches only */
mode = ps3fb_find_mode(var, &ddr_line_length, &xdr_line_length);
if (!mode)
return -EINVAL;
/* Virtual screen */
- if (var->xres_virtual < var->xres)
- var->xres_virtual = var->xres;
- if (var->yres_virtual < var->yres)
- var->yres_virtual = var->yres;
-
if (var->xres_virtual > xdr_line_length / BPP) {
dev_dbg(info->device,
"Horizontal virtual screen size too large\n");
@@ -559,7 +596,7 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
}
/* Memory limit */
- if (var->yres_virtual * xdr_line_length > ps3fb.xdr_size) {
+ if (var->yres_virtual * xdr_line_length > info->fix.smem_len) {
dev_dbg(info->device, "Not enough memory\n");
return -ENOMEM;
}
@@ -578,39 +615,38 @@ static int ps3fb_set_par(struct fb_info *info)
{
struct ps3fb_par *par = info->par;
unsigned int mode, ddr_line_length, xdr_line_length, lines, maxlines;
- int i;
- unsigned long offset;
+ unsigned int ddr_xoff, ddr_yoff, offset;
+ const struct fb_videomode *vmode;
u64 dst;
- dev_dbg(info->device, "xres:%d xv:%d yres:%d yv:%d clock:%d\n",
- info->var.xres, info->var.xres_virtual,
- info->var.yres, info->var.yres_virtual, info->var.pixclock);
-
mode = ps3fb_find_mode(&info->var, &ddr_line_length, &xdr_line_length);
if (!mode)
return -EINVAL;
- i = ps3fb_get_res_table(info->var.xres, info->var.yres, mode);
- par->res_index = i;
+ vmode = ps3fb_native_vmode(mode & PS3AV_MODE_MASK);
- info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea);
- info->fix.smem_len = ps3fb.xdr_size;
info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0;
info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0;
info->fix.line_length = xdr_line_length;
- info->screen_base = (char __iomem *)ps3fb.xdr_ea;
+ par->ddr_line_length = ddr_line_length;
+ par->ddr_frame_size = vmode->yres * ddr_line_length;
+ par->xdr_frame_size = info->var.yres_virtual * xdr_line_length;
- par->num_frames = ps3fb.xdr_size /
- max(ps3fb_res[i].yres * ddr_line_length,
- info->var.yres_virtual * xdr_line_length);
+ par->num_frames = info->fix.smem_len /
+ max(par->ddr_frame_size, par->xdr_frame_size);
/* Keep the special bits we cannot set using fb_var_screeninfo */
par->new_mode_id = (par->new_mode_id & ~PS3AV_MODE_MASK) | mode;
par->width = info->var.xres;
par->height = info->var.yres;
- offset = VP_OFF(i);
+
+ /* Start of the virtual frame buffer (relative to fullscreen) */
+ ddr_xoff = info->var.left_margin - vmode->left_margin;
+ ddr_yoff = info->var.upper_margin - vmode->upper_margin;
+ offset = ddr_yoff * ddr_line_length + ddr_xoff * BPP;
+
par->fb_offset = GPU_ALIGN_UP(offset);
par->full_offset = par->fb_offset - offset;
par->pan_offset = info->var.yoffset * xdr_line_length +
@@ -625,16 +661,16 @@ static int ps3fb_set_par(struct fb_info *info)
}
/* Clear XDR frame buffer memory */
- memset(ps3fb.xdr_ea, 0, ps3fb.xdr_size);
+ memset((void __force *)info->screen_base, 0, info->fix.smem_len);
/* Clear DDR frame buffer memory */
- lines = ps3fb_res[i].yres * par->num_frames;
+ lines = vmode->yres * par->num_frames;
if (par->full_offset)
lines++;
- maxlines = ps3fb.xdr_size / ddr_line_length;
+ maxlines = info->fix.smem_len / ddr_line_length;
for (dst = 0; lines; dst += maxlines * ddr_line_length) {
unsigned int l = min(lines, maxlines);
- ps3fb_sync_image(info->device, 0, dst, 0, ps3fb_res[i].xres, l,
+ ps3fb_sync_image(info->device, 0, dst, 0, vmode->xres, l,
ddr_line_length, ddr_line_length);
lines -= l;
}
@@ -797,7 +833,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
case PS3FB_IOCTL_SETMODE:
{
struct ps3fb_par *par = info->par;
- const struct fb_videomode *mode;
+ const struct fb_videomode *vmode;
struct fb_var_screeninfo var;
if (copy_from_user(&val, argp, sizeof(val)))
@@ -810,10 +846,10 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
}
dev_dbg(info->device, "PS3FB_IOCTL_SETMODE:%x\n", val);
retval = -EINVAL;
- mode = ps3fb_default_mode(val);
- if (mode) {
+ vmode = ps3fb_vmode(val);
+ if (vmode) {
var = info->var;
- fb_videomode_to_var(&var, mode);
+ fb_videomode_to_var(&var, vmode);
acquire_console_sem();
info->flags |= FBINFO_MISC_USEREVENT;
/* Force, in case only special bits changed */
@@ -975,10 +1011,9 @@ static int ps3fb_xdr_settings(u64 xdr_lpar, struct device *dev)
__func__, status);
return -ENXIO;
}
- dev_dbg(dev,
- "video:%p xdr_ea:%p ioif:%lx lpar:%lx phys:%lx size:%lx\n",
- ps3fb_videomemory.address, ps3fb.xdr_ea, GPU_IOIF, xdr_lpar,
- virt_to_abs(ps3fb.xdr_ea), ps3fb_videomemory.size);
+ dev_dbg(dev, "video:%p ioif:%lx lpar:%lx size:%lx\n",
+ ps3fb_videomemory.address, GPU_IOIF, xdr_lpar,
+ ps3fb_videomemory.size);
status = lv1_gpu_context_attribute(ps3fb.context_handle,
L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP,
@@ -1055,14 +1090,14 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
struct fb_info *info;
struct ps3fb_par *par;
int retval = -ENOMEM;
- u32 xres, yres;
u64 ddr_lpar = 0;
u64 lpar_dma_control = 0;
u64 lpar_driver_info = 0;
u64 lpar_reports = 0;
u64 lpar_reports_size = 0;
u64 xdr_lpar;
- int status, res_index;
+ void *fb_start;
+ int status;
struct task_struct *task;
unsigned long max_ps3fb_size;
@@ -1080,14 +1115,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
if (!ps3fb_mode)
ps3fb_mode = ps3av_get_mode();
- dev_dbg(&dev->core, "ps3av_mode:%d\n", ps3fb_mode);
-
- if (ps3fb_mode > 0 &&
- !ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) {
- res_index = ps3fb_get_res_table(xres, yres, ps3fb_mode);
- dev_dbg(&dev->core, "res_index:%d\n", res_index);
- } else
- res_index = GPU_RES_INDEX;
+ dev_dbg(&dev->core, "ps3fb_mode: %d\n", ps3fb_mode);
atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */
atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */
@@ -1124,7 +1152,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
}
/* vsync interrupt */
- ps3fb.dinfo = ioremap(lpar_driver_info, 128 * 1024);
+ ps3fb.dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024);
if (!ps3fb.dinfo) {
dev_err(&dev->core, "%s: ioremap failed\n", __func__);
goto err_gpu_context_free;
@@ -1134,22 +1162,10 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
if (retval)
goto err_iounmap_dinfo;
- /* XDR frame buffer */
- ps3fb.xdr_ea = ps3fb_videomemory.address;
- xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb.xdr_ea));
-
/* Clear memory to prevent kernel info leakage into userspace */
- memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size);
-
- /*
- * The GPU command buffer is at the start of video memory
- * As we don't use the full command buffer, we can put the actual
- * frame buffer at offset GPU_FB_START and save some precious XDR
- * memory
- */
- ps3fb.xdr_ea += GPU_FB_START;
- ps3fb.xdr_size = ps3fb_videomemory.size - GPU_FB_START;
+ memset(ps3fb_videomemory.address, 0, ps3fb_videomemory.size);
+ xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address));
retval = ps3fb_xdr_settings(xdr_lpar, &dev->core);
if (retval)
goto err_free_irq;
@@ -1161,15 +1177,22 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
par = info->par;
par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */
par->new_mode_id = ps3fb_mode;
- par->res_index = res_index;
par->num_frames = 1;
- info->screen_base = (char __iomem *)ps3fb.xdr_ea;
info->fbops = &ps3fb_ops;
-
info->fix = ps3fb_fix;
- info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea);
- info->fix.smem_len = ps3fb.xdr_size;
+
+ /*
+ * The GPU command buffer is at the start of video memory
+ * As we don't use the full command buffer, we can put the actual
+ * frame buffer at offset GPU_FB_START and save some precious XDR
+ * memory
+ */
+ fb_start = ps3fb_videomemory.address + GPU_FB_START;
+ info->screen_base = (char __force __iomem *)fb_start;
+ info->fix.smem_start = virt_to_abs(fb_start);
+ info->fix.smem_len = ps3fb_videomemory.size - GPU_FB_START;
+
info->pseudo_palette = par->pseudo_palette;
info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST |
FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
@@ -1180,7 +1203,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
if (!fb_find_mode(&info->var, info, mode_option, ps3fb_modedb,
ARRAY_SIZE(ps3fb_modedb),
- ps3fb_default_mode(par->new_mode_id), 32)) {
+ ps3fb_vmode(par->new_mode_id), 32)) {
retval = -EINVAL;
goto err_fb_dealloc;
}
@@ -1194,9 +1217,9 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
dev->core.driver_data = info;
- dev_info(info->device, "%s %s, using %lu KiB of video memory\n",
+ dev_info(info->device, "%s %s, using %u KiB of video memory\n",
dev_driver_string(info->dev), info->dev->bus_id,
- ps3fb.xdr_size >> 10);
+ info->fix.smem_len >> 10);
task = kthread_run(ps3fbd, info, DEVICE_NAME);
if (IS_ERR(task)) {
@@ -1219,7 +1242,7 @@ err_free_irq:
free_irq(ps3fb.irq_no, &dev->core);
ps3_irq_plug_destroy(ps3fb.irq_no);
err_iounmap_dinfo:
- iounmap((u8 __iomem *)ps3fb.dinfo);
+ iounmap((u8 __force __iomem *)ps3fb.dinfo);
err_gpu_context_free:
lv1_gpu_context_free(ps3fb.context_handle);
err_gpu_memory_free:
@@ -1254,7 +1277,7 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
framebuffer_release(info);
info = dev->core.driver_data = NULL;
}
- iounmap((u8 __iomem *)ps3fb.dinfo);
+ iounmap((u8 __force __iomem *)ps3fb.dinfo);
status = lv1_gpu_context_free(ps3fb.context_handle);
if (status)
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index b3c31d9dc59..71fa6edb5c4 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -110,6 +110,11 @@ static int debug = 0;
/* useful functions */
+static int is_s3c2412(struct s3c2410fb_info *fbi)
+{
+ return (fbi->drv_type == DRV_S3C2412);
+}
+
/* s3c2410fb_set_lcdaddr
*
* initialise lcd controller address pointers
@@ -501,7 +506,7 @@ static void schedule_palette_update(struct s3c2410fb_info *fbi,
{
unsigned long flags;
unsigned long irqen;
- void __iomem *regs = fbi->io;
+ void __iomem *irq_base = fbi->irq_base;
local_irq_save(flags);
@@ -511,9 +516,9 @@ static void schedule_palette_update(struct s3c2410fb_info *fbi,
fbi->palette_ready = 1;
/* enable IRQ */
- irqen = readl(regs + S3C2410_LCDINTMSK);
+ irqen = readl(irq_base + S3C24XX_LCDINTMSK);
irqen &= ~S3C2410_LCDINT_FRSYNC;
- writel(irqen, regs + S3C2410_LCDINTMSK);
+ writel(irqen, irq_base + S3C24XX_LCDINTMSK);
}
local_irq_restore(flags);
@@ -594,15 +599,17 @@ static int s3c2410fb_setcolreg(unsigned regno,
static int s3c2410fb_blank(int blank_mode, struct fb_info *info)
{
struct s3c2410fb_info *fbi = info->par;
- void __iomem *regs = fbi->io;
+ void __iomem *tpal_reg = fbi->io;
dprintk("blank(mode=%d, info=%p)\n", blank_mode, info);
+ tpal_reg += is_s3c2412(fbi) ? S3C2412_TPAL : S3C2410_TPAL;
+
if (blank_mode == FB_BLANK_UNBLANK)
- writel(0x0, regs + S3C2410_TPAL);
+ writel(0x0, tpal_reg);
else {
dprintk("setting TPAL to output 0x000000\n");
- writel(S3C2410_TPAL_EN, regs + S3C2410_TPAL);
+ writel(S3C2410_TPAL_EN, tpal_reg);
}
return 0;
@@ -663,7 +670,7 @@ static int __init s3c2410fb_map_video_memory(struct fb_info *info)
dma_addr_t map_dma;
unsigned map_size = PAGE_ALIGN(info->fix.smem_len);
- dprintk("map_video_memory(fbi=%p)\n", fbi);
+ dprintk("map_video_memory(fbi=%p) map_size %u\n", fbi, map_size);
info->screen_base = dma_alloc_writecombine(fbi->dev, map_size,
&map_dma, GFP_KERNEL);
@@ -672,7 +679,7 @@ static int __init s3c2410fb_map_video_memory(struct fb_info *info)
/* prevent initial garbage on screen */
dprintk("map_video_memory: clear %p:%08x\n",
info->screen_base, map_size);
- memset(info->screen_base, 0xf0, map_size);
+ memset(info->screen_base, 0x00, map_size);
info->fix.smem_start = map_dma;
@@ -709,6 +716,16 @@ static int s3c2410fb_init_registers(struct fb_info *info)
struct s3c2410fb_mach_info *mach_info = fbi->dev->platform_data;
unsigned long flags;
void __iomem *regs = fbi->io;
+ void __iomem *tpal;
+ void __iomem *lpcsel;
+
+ if (is_s3c2412(fbi)) {
+ tpal = regs + S3C2412_TPAL;
+ lpcsel = regs + S3C2412_TCONSEL;
+ } else {
+ tpal = regs + S3C2410_TPAL;
+ lpcsel = regs + S3C2410_LPCSEL;
+ }
/* Initialise LCD with values from haret */
@@ -724,12 +741,12 @@ static int s3c2410fb_init_registers(struct fb_info *info)
local_irq_restore(flags);
dprintk("LPCSEL = 0x%08lx\n", mach_info->lpcsel);
- writel(mach_info->lpcsel, regs + S3C2410_LPCSEL);
+ writel(mach_info->lpcsel, lpcsel);
- dprintk("replacing TPAL %08x\n", readl(regs + S3C2410_TPAL));
+ dprintk("replacing TPAL %08x\n", readl(tpal));
/* ensure temporary palette disabled */
- writel(0x00, regs + S3C2410_TPAL);
+ writel(0x00, tpal);
return 0;
}
@@ -763,15 +780,15 @@ static void s3c2410fb_write_palette(struct s3c2410fb_info *fbi)
static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)
{
struct s3c2410fb_info *fbi = dev_id;
- void __iomem *regs = fbi->io;
- unsigned long lcdirq = readl(regs + S3C2410_LCDINTPND);
+ void __iomem *irq_base = fbi->irq_base;
+ unsigned long lcdirq = readl(irq_base + S3C24XX_LCDINTPND);
if (lcdirq & S3C2410_LCDINT_FRSYNC) {
if (fbi->palette_ready)
s3c2410fb_write_palette(fbi);
- writel(S3C2410_LCDINT_FRSYNC, regs + S3C2410_LCDINTPND);
- writel(S3C2410_LCDINT_FRSYNC, regs + S3C2410_LCDSRCPND);
+ writel(S3C2410_LCDINT_FRSYNC, irq_base + S3C24XX_LCDINTPND);
+ writel(S3C2410_LCDINT_FRSYNC, irq_base + S3C24XX_LCDSRCPND);
}
return IRQ_HANDLED;
@@ -779,7 +796,8 @@ static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)
static char driver_name[] = "s3c2410fb";
-static int __init s3c2410fb_probe(struct platform_device *pdev)
+static int __init s3c24xxfb_probe(struct platform_device *pdev,
+ enum s3c_drv_type drv_type)
{
struct s3c2410fb_info *info;
struct s3c2410fb_display *display;
@@ -799,6 +817,12 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
return -EINVAL;
}
+ if (mach_info->default_display >= mach_info->num_displays) {
+ dev_err(&pdev->dev, "default is %d but only %d displays\n",
+ mach_info->default_display, mach_info->num_displays);
+ return -EINVAL;
+ }
+
display = mach_info->displays + mach_info->default_display;
irq = platform_get_irq(pdev, 0);
@@ -815,6 +839,7 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
info = fbinfo->par;
info->dev = &pdev->dev;
+ info->drv_type = drv_type;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
@@ -838,6 +863,8 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
goto release_mem;
}
+ info->irq_base = info->io + ((drv_type == DRV_S3C2412) ? S3C2412_LCDINTBASE : S3C2410_LCDINTBASE);
+
dprintk("devinit\n");
strcpy(fbinfo->fix.id, driver_name);
@@ -946,6 +973,16 @@ dealloc_fb:
return ret;
}
+static int __init s3c2410fb_probe(struct platform_device *pdev)
+{
+ return s3c24xxfb_probe(pdev, DRV_S3C2410);
+}
+
+static int __init s3c2412fb_probe(struct platform_device *pdev)
+{
+ return s3c24xxfb_probe(pdev, DRV_S3C2412);
+}
+
/* s3c2410fb_stop_lcd
*
* shutdown the lcd controller
@@ -1047,14 +1084,31 @@ static struct platform_driver s3c2410fb_driver = {
},
};
+static struct platform_driver s3c2412fb_driver = {
+ .probe = s3c2412fb_probe,
+ .remove = s3c2410fb_remove,
+ .suspend = s3c2410fb_suspend,
+ .resume = s3c2410fb_resume,
+ .driver = {
+ .name = "s3c2412-lcd",
+ .owner = THIS_MODULE,
+ },
+};
+
int __init s3c2410fb_init(void)
{
- return platform_driver_register(&s3c2410fb_driver);
+ int ret = platform_driver_register(&s3c2410fb_driver);
+
+ if (ret == 0)
+ ret = platform_driver_register(&s3c2412fb_driver);;
+
+ return ret;
}
static void __exit s3c2410fb_cleanup(void)
{
platform_driver_unregister(&s3c2410fb_driver);
+ platform_driver_unregister(&s3c2412fb_driver);
}
module_init(s3c2410fb_init);
diff --git a/drivers/video/s3c2410fb.h b/drivers/video/s3c2410fb.h
index 6ce5dc26c5f..dbb73b95e2e 100644
--- a/drivers/video/s3c2410fb.h
+++ b/drivers/video/s3c2410fb.h
@@ -25,13 +25,20 @@
#ifndef __S3C2410FB_H
#define __S3C2410FB_H
+enum s3c_drv_type {
+ DRV_S3C2410,
+ DRV_S3C2412,
+};
+
struct s3c2410fb_info {
struct device *dev;
struct clk *clk;
struct resource *mem;
void __iomem *io;
+ void __iomem *irq_base;
+ enum s3c_drv_type drv_type;
struct s3c2410fb_hw regs;
unsigned int palette_ready;
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
index 93ae747440c..73803624c13 100644
--- a/drivers/video/sis/sis_main.c
+++ b/drivers/video/sis/sis_main.c
@@ -427,7 +427,7 @@ sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
monitor->feature = buffer[0x18];
- if(!buffer[0x14] & 0x80) {
+ if(!(buffer[0x14] & 0x80)) {
if(!(buffer[0x14] & 0x08)) {
printk(KERN_INFO
"sisfb: WARNING: Monitor does not support separate syncs\n");
@@ -4621,9 +4621,9 @@ sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
temp = pdev->vendor;
- pci_dev_put(pdev);
if(temp == pcivendor) {
ret = 1;
+ pci_dev_put(pdev);
break;
}
}
diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
index 58f200c69be..e83dfba7e63 100644
--- a/drivers/video/sm501fb.c
+++ b/drivers/video/sm501fb.c
@@ -641,6 +641,7 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
{
unsigned long control;
void __iomem *ctrl_reg = fbi->regs + SM501_DC_PANEL_CONTROL;
+ struct sm501_platdata_fbsub *pd = fbi->pdata->fb_pnl;
control = readl(ctrl_reg);
@@ -657,26 +658,34 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
sm501fb_sync_regs(fbi);
mdelay(10);
- control |= SM501_DC_PANEL_CONTROL_BIAS; /* VBIASEN */
- writel(control, ctrl_reg);
- sm501fb_sync_regs(fbi);
- mdelay(10);
-
- control |= SM501_DC_PANEL_CONTROL_FPEN;
- writel(control, ctrl_reg);
+ if (pd->flags & SM501FB_FLAG_PANEL_USE_VBIASEN) {
+ control |= SM501_DC_PANEL_CONTROL_BIAS; /* VBIASEN */
+ writel(control, ctrl_reg);
+ sm501fb_sync_regs(fbi);
+ mdelay(10);
+ }
+ if (pd->flags & SM501FB_FLAG_PANEL_USE_FPEN) {
+ control |= SM501_DC_PANEL_CONTROL_FPEN;
+ writel(control, ctrl_reg);
+ sm501fb_sync_regs(fbi);
+ mdelay(10);
+ }
} else if (!to && (control & SM501_DC_PANEL_CONTROL_VDD) != 0) {
/* disable panel power */
+ if (pd->flags & SM501FB_FLAG_PANEL_USE_FPEN) {
+ control &= ~SM501_DC_PANEL_CONTROL_FPEN;
+ writel(control, ctrl_reg);
+ sm501fb_sync_regs(fbi);
+ mdelay(10);
+ }
- control &= ~SM501_DC_PANEL_CONTROL_FPEN;
- writel(control, ctrl_reg);
- sm501fb_sync_regs(fbi);
- mdelay(10);
-
- control &= ~SM501_DC_PANEL_CONTROL_BIAS;
- writel(control, ctrl_reg);
- sm501fb_sync_regs(fbi);
- mdelay(10);
+ if (pd->flags & SM501FB_FLAG_PANEL_USE_VBIASEN) {
+ control &= ~SM501_DC_PANEL_CONTROL_BIAS;
+ writel(control, ctrl_reg);
+ sm501fb_sync_regs(fbi);
+ mdelay(10);
+ }
control &= ~SM501_DC_PANEL_CONTROL_DATA;
writel(control, ctrl_reg);
@@ -1267,6 +1276,7 @@ static int sm501fb_start(struct sm501fb_info *info,
{
struct resource *res;
struct device *dev;
+ int k;
int ret;
info->dev = dev = &pdev->dev;
@@ -1328,6 +1338,13 @@ static int sm501fb_start(struct sm501fb_info *info,
info->fbmem_len = (res->end - res->start)+1;
+ /* clear framebuffer memory - avoids garbage data on unused fb */
+ memset(info->fbmem, 0, info->fbmem_len);
+
+ /* clear palette ram - undefined at power on */
+ for (k = 0; k < (256 * 3); k++)
+ writel(0, info->regs + SM501_DC_PANEL_PALETTE + (k * 4));
+
/* enable display controller */
sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1);
@@ -1681,6 +1698,15 @@ static int sm501fb_suspend_fb(struct sm501fb_info *info,
if (par->screen.size == 0)
return 0;
+ /* blank the relevant interface to ensure unit power minimised */
+ (par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi);
+
+ /* tell console/fb driver we are suspending */
+
+ acquire_console_sem();
+ fb_set_suspend(fbi, 1);
+ release_console_sem();
+
/* backup copies in case chip is powered down over suspend */
par->store_fb = vmalloc(par->screen.size);
@@ -1700,12 +1726,6 @@ static int sm501fb_suspend_fb(struct sm501fb_info *info,
memcpy_fromio(par->store_fb, par->screen.k_addr, par->screen.size);
memcpy_fromio(par->store_cursor, par->cursor.k_addr, par->cursor.size);
- /* blank the relevant interface to ensure unit power minimised */
- (par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi);
-
- acquire_console_sem();
- fb_set_suspend(fbi, 1);
- release_console_sem();
return 0;
diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
index 057bdd59380..71e179ea5f9 100644
--- a/drivers/video/tdfxfb.c
+++ b/drivers/video/tdfxfb.c
@@ -1342,7 +1342,7 @@ out_err:
}
#ifndef MODULE
-static void tdfxfb_setup(char *options)
+static void __init tdfxfb_setup(char *options)
{
char *this_opt;
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
index a14ef894d57..be27b9c1ed7 100644
--- a/drivers/video/uvesafb.c
+++ b/drivers/video/uvesafb.c
@@ -2003,12 +2003,12 @@ static void __devexit uvesafb_exit(void)
module_exit(uvesafb_exit);
-static inline int param_get_scroll(char *buffer, struct kernel_param *kp)
+static int param_get_scroll(char *buffer, struct kernel_param *kp)
{
return 0;
}
-static inline int param_set_scroll(const char *val, struct kernel_param *kp)
+static int param_set_scroll(const char *val, struct kernel_param *kp)
{
ypan = 0;
@@ -2022,11 +2022,11 @@ static inline int param_set_scroll(const char *val, struct kernel_param *kp)
return 0;
}
-#define param_check_scroll(name, p) __param_check(name, p, void);
+#define param_check_scroll(name, p) __param_check(name, p, void)
module_param_named(scroll, ypan, scroll, 0);
MODULE_PARM_DESC(scroll,
- "Scrolling mode, set to 'redraw', ''ypan' or 'ywrap'");
+ "Scrolling mode, set to 'redraw', 'ypan', or 'ywrap'");
module_param_named(vgapal, pmi_setpal, invbool, 0);
MODULE_PARM_DESC(vgapal, "Set palette using VGA registers");
module_param_named(pmipal, pmi_setpal, bool, 0);
diff --git a/drivers/video/vermilion/vermilion.c b/drivers/video/vermilion/vermilion.c
index 1c656667b93..2aa71eb67c2 100644
--- a/drivers/video/vermilion/vermilion.c
+++ b/drivers/video/vermilion/vermilion.c
@@ -651,7 +651,7 @@ static int vmlfb_check_var_locked(struct fb_var_screeninfo *var,
return -EINVAL;
}
- pitch = __ALIGN_MASK((var->xres * var->bits_per_pixel) >> 3, 0x3F);
+ pitch = ALIGN((var->xres * var->bits_per_pixel) >> 3, 0x40);
mem = pitch * var->yres_virtual;
if (mem > vinfo->vram_contig_size) {
return -ENOMEM;
@@ -785,8 +785,7 @@ static int vmlfb_set_par_locked(struct vml_info *vinfo)
int clock;
vinfo->bytes_per_pixel = var->bits_per_pixel >> 3;
- vinfo->stride =
- __ALIGN_MASK(var->xres_virtual * vinfo->bytes_per_pixel, 0x3F);
+ vinfo->stride = ALIGN(var->xres_virtual * vinfo->bytes_per_pixel, 0x40);
info->fix.line_length = vinfo->stride;
if (!subsys)
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 622aece1acc..c8a4332d113 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -23,6 +23,7 @@
#include <linux/swap.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
+#include <linux/delay.h>
struct virtio_balloon
{
diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig
index 8236d447adf..c4493091c65 100644
--- a/drivers/w1/masters/Kconfig
+++ b/drivers/w1/masters/Kconfig
@@ -42,5 +42,15 @@ config W1_MASTER_DS1WM
in HP iPAQ devices like h5xxx, h2200, and ASIC3-based like
hx4700.
+config W1_MASTER_GPIO
+ tristate "GPIO 1-wire busmaster"
+ depends on GENERIC_GPIO
+ help
+ Say Y here if you want to communicate with your 1-wire devices using
+ GPIO pins. This driver uses the GPIO API to control the wire.
+
+ This support is also available as a module. If so, the module
+ will be called w1-gpio.ko.
+
endmenu
diff --git a/drivers/w1/masters/Makefile b/drivers/w1/masters/Makefile
index 11551b32818..1420b5bbdda 100644
--- a/drivers/w1/masters/Makefile
+++ b/drivers/w1/masters/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_W1_MASTER_MATROX) += matrox_w1.o
obj-$(CONFIG_W1_MASTER_DS2490) += ds2490.o
obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o
obj-$(CONFIG_W1_MASTER_DS1WM) += ds1wm.o
+obj-$(CONFIG_W1_MASTER_GPIO) += w1-gpio.o
diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c
new file mode 100644
index 00000000000..9e1138a75e8
--- /dev/null
+++ b/drivers/w1/masters/w1-gpio.c
@@ -0,0 +1,124 @@
+/*
+ * w1-gpio - GPIO w1 bus master driver
+ *
+ * Copyright (C) 2007 Ville Syrjala <syrjala@sci.fi>
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/w1-gpio.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+
+#include <asm/gpio.h>
+
+static void w1_gpio_write_bit_dir(void *data, u8 bit)
+{
+ struct w1_gpio_platform_data *pdata = data;
+
+ if (bit)
+ gpio_direction_input(pdata->pin);
+ else
+ gpio_direction_output(pdata->pin, 0);
+}
+
+static void w1_gpio_write_bit_val(void *data, u8 bit)
+{
+ struct w1_gpio_platform_data *pdata = data;
+
+ gpio_set_value(pdata->pin, bit);
+}
+
+static u8 w1_gpio_read_bit(void *data)
+{
+ struct w1_gpio_platform_data *pdata = data;
+
+ return gpio_get_value(pdata->pin);
+}
+
+static int __init w1_gpio_probe(struct platform_device *pdev)
+{
+ struct w1_bus_master *master;
+ struct w1_gpio_platform_data *pdata = pdev->dev.platform_data;
+ int err;
+
+ if (!pdata)
+ return -ENXIO;
+
+ master = kzalloc(sizeof(struct w1_bus_master), GFP_KERNEL);
+ if (!master)
+ return -ENOMEM;
+
+ err = gpio_request(pdata->pin, "w1");
+ if (err)
+ goto free_master;
+
+ master->data = pdata;
+ master->read_bit = w1_gpio_read_bit;
+
+ if (pdata->is_open_drain) {
+ gpio_direction_output(pdata->pin, 1);
+ master->write_bit = w1_gpio_write_bit_val;
+ } else {
+ gpio_direction_input(pdata->pin);
+ master->write_bit = w1_gpio_write_bit_dir;
+ }
+
+ err = w1_add_master_device(master);
+ if (err)
+ goto free_gpio;
+
+ platform_set_drvdata(pdev, master);
+
+ return 0;
+
+ free_gpio:
+ gpio_free(pdata->pin);
+ free_master:
+ kfree(master);
+
+ return err;
+}
+
+static int __exit w1_gpio_remove(struct platform_device *pdev)
+{
+ struct w1_bus_master *master = platform_get_drvdata(pdev);
+ struct w1_gpio_platform_data *pdata = pdev->dev.platform_data;
+
+ w1_remove_master_device(master);
+ gpio_free(pdata->pin);
+ kfree(master);
+
+ return 0;
+}
+
+static struct platform_driver w1_gpio_driver = {
+ .driver = {
+ .name = "w1-gpio",
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(w1_gpio_remove),
+};
+
+static int __init w1_gpio_init(void)
+{
+ return platform_driver_probe(&w1_gpio_driver, w1_gpio_probe);
+}
+
+static void __exit w1_gpio_exit(void)
+{
+ platform_driver_unregister(&w1_gpio_driver);
+}
+
+module_init(w1_gpio_init);
+module_exit(w1_gpio_exit);
+
+MODULE_DESCRIPTION("GPIO w1 bus master driver");
+MODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c
index 112f4ec5903..fb28acaeed6 100644
--- a/drivers/w1/slaves/w1_therm.c
+++ b/drivers/w1/slaves/w1_therm.c
@@ -92,6 +92,7 @@ struct w1_therm_family_converter
int (*convert)(u8 rom[9]);
};
+/* The return value is millidegrees Centigrade. */
static inline int w1_DS18B20_convert_temp(u8 rom[9]);
static inline int w1_DS18S20_convert_temp(u8 rom[9]);
@@ -113,7 +114,7 @@ static struct w1_therm_family_converter w1_therm_families[] = {
static inline int w1_DS18B20_convert_temp(u8 rom[9])
{
s16 t = (rom[1] << 8) | rom[0];
- t /= 16;
+ t = t*1000/16;
return t;
}
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 33e50310e9e..7293c9b11f9 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -675,7 +675,6 @@ static void w1_slave_found(void *data, u64 rn)
struct w1_slave *sl;
struct list_head *ent;
struct w1_reg_num *tmp;
- int family_found = 0;
struct w1_master *dev;
u64 rn_le = cpu_to_le64(rn);
@@ -698,9 +697,6 @@ static void w1_slave_found(void *data, u64 rn)
sl->reg_num.crc == tmp->crc) {
set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags);
break;
- } else if (sl->reg_num.family == tmp->family) {
- family_found = 1;
- break;
}
slave_count++;