diff options
Diffstat (limited to 'drivers')
55 files changed, 3664 insertions, 1881 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 7ef172c2a1d6..f688c214be0c 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -204,13 +204,25 @@ config ACPI_NUMA config ACPI_WMI tristate "WMI (EXPERIMENTAL)" + depends on X86 depends on EXPERIMENTAL help - This driver adds support for the ACPI-WMI mapper device (PNP0C14) - found on some systems. + This driver adds support for the ACPI-WMI (Windows Management + Instrumentation) mapper device (PNP0C14) found on some systems. + + ACPI-WMI is a proprietary extension to ACPI to expose parts of the + ACPI firmware to userspace - this is done through various vendor + defined methods and data blocks in a PNP0C14 device, which are then + made available for userspace to call. + + The implementation of this in Linux currently only exposes this to + other kernel space drivers. + + This driver is a required dependency to build the firmware specific + drivers needed on many machines, including Acer and HP laptops. - NOTE: You will need another driver or userspace application on top of - this to actually use anything defined in the ACPI-WMI mapper. + It is safe to enable this driver even if your DSDT doesn't define + any ACPI-WMI devices. config ACPI_ASUS tristate "ASUS/Medion Laptop Extras" diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index 6dbaa2d15fe0..9ce983ed60f0 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -445,6 +445,8 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { * DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T61"), * _OSI(Linux) is a NOP: * DMI_MATCH(DMI_PRODUCT_VERSION, "3000 N100"), + * _OSI(Linux) effect unknown + * DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X61"), */ { .callback = dmi_enable_osi_linux, @@ -464,6 +466,14 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { }, { .callback = dmi_unknown_osi_linux, + .ident = "Lenovo ThinkPad X61", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X61"), + }, + }, + { + .callback = dmi_unknown_osi_linux, .ident = "Lenovo 3000 V100", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), @@ -505,6 +515,16 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "NEC VERSA M360"), }, }, + /* Panasonic */ + { + .callback = dmi_unknown_osi_linux, + .ident = "Panasonic", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"), + /* Toughbook CF-52 */ + DMI_MATCH(DMI_PRODUCT_NAME, "CF-52CCABVBG"), + }, + }, /* * Disable OSI(Linux) warnings on all "Samsung Electronics" * diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 27ccd68b8f46..a14501c98f40 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -343,7 +343,7 @@ struct acpi_table_header *acpi_find_dsdt_initrd(void) struct kstat stat; char *ramfs_dsdt_name = "/DSDT.aml"; - printk(KERN_INFO PREFIX "Checking initramfs for custom DSDT"); + printk(KERN_INFO PREFIX "Checking initramfs for custom DSDT\n"); /* * Never do this at home, only the user-space is allowed to open a file. diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index f32010bee4d5..b477a4be8a69 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -50,6 +50,10 @@ ACPI_MODULE_NAME("processor_perflib"); static DEFINE_MUTEX(performance_mutex); +/* Use cpufreq debug layer for _PPC changes. */ +#define cpufreq_printk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, \ + "cpufreq-core", msg) + /* * _PPC support is implemented as a CPUfreq policy notifier: * This means each time a CPUfreq driver registered also with @@ -131,6 +135,9 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr) return -ENODEV; } + cpufreq_printk("CPU %d: _PPC is %d - frequency %s limited\n", pr->id, + (int)ppc, ppc ? "" : "not"); + pr->performance_platform_limit = (int)ppc; return 0; diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 64e5148d82bc..b6d230b3209f 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -322,7 +322,7 @@ config BLK_DEV_UB If unsure, say N. config BLK_DEV_RAM - tristate "RAM disk support" + tristate "RAM block device support" ---help--- Saying Y here will allow you to use a portion of your RAM memory as a block device, so that you can make file systems on it, read and @@ -357,15 +357,15 @@ config BLK_DEV_RAM_SIZE The default value is 4096 kilobytes. Only change this if you know what you are doing. -config BLK_DEV_RAM_BLOCKSIZE - int "Default RAM disk block size (bytes)" +config BLK_DEV_XIP + bool "Support XIP filesystems on RAM block device" depends on BLK_DEV_RAM - default "1024" + default n help - The default value is 1024 bytes. PAGE_SIZE is a much more - efficient choice however. The default is kept to ensure initrd - setups function - apparently needed by the rd_load_image routine - that supposes the filesystem in the image uses a 1024 blocksize. + Support XIP filesystems (such as ext2 with XIP support on) on + top of block ram device. This will slightly enlarge the kernel, and + will prevent RAM block device backing store memory from being + allocated from highmem (only a problem for highmem systems). config CDROM_PKTCDVD tristate "Packet writing on CD/DVD media" diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 7691505a2e12..01c972415cb2 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -11,7 +11,7 @@ obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o obj-$(CONFIG_PS3_DISK) += ps3disk.o obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o obj-$(CONFIG_AMIGA_Z2RAM) += z2ram.o -obj-$(CONFIG_BLK_DEV_RAM) += rd.o +obj-$(CONFIG_BLK_DEV_RAM) += brd.o obj-$(CONFIG_BLK_DEV_LOOP) += loop.o obj-$(CONFIG_BLK_DEV_PS2) += ps2esdi.o obj-$(CONFIG_BLK_DEV_XD) += xd.o diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index 07f02f855ab5..280e71ee744c 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -1,5 +1,5 @@ -/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */ -#define VERSION "32" +/* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */ +#define VERSION "47" #define AOE_MAJOR 152 #define DEVICE_NAME "aoe" @@ -76,10 +76,8 @@ enum { DEVFL_EXT = (1<<2), /* device accepts lba48 commands */ DEVFL_CLOSEWAIT = (1<<3), /* device is waiting for all closes to revalidate */ DEVFL_GDALLOC = (1<<4), /* need to alloc gendisk */ - DEVFL_PAUSE = (1<<5), + DEVFL_KICKME = (1<<5), /* slow polling network card catch */ DEVFL_NEWSIZE = (1<<6), /* need to update dev size in block layer */ - DEVFL_MAXBCNT = (1<<7), /* d->maxbcnt is not changeable */ - DEVFL_KICKME = (1<<8), BUFFL_FAIL = 1, }; @@ -88,17 +86,25 @@ enum { DEFAULTBCNT = 2 * 512, /* 2 sectors */ NPERSHELF = 16, /* number of slots per shelf address */ FREETAG = -1, - MIN_BUFS = 8, + MIN_BUFS = 16, + NTARGETS = 8, + NAOEIFS = 8, + NSKBPOOLMAX = 128, + + TIMERTICK = HZ / 10, + MINTIMER = HZ >> 2, + MAXTIMER = HZ << 1, + HELPWAIT = 20, }; struct buf { struct list_head bufs; - ulong start_time; /* for disk stats */ + ulong stime; /* for disk stats */ ulong flags; ulong nframesout; - char *bufaddr; ulong resid; ulong bv_resid; + ulong bv_off; sector_t sector; struct bio *bio; struct bio_vec *bv; @@ -114,19 +120,38 @@ struct frame { struct sk_buff *skb; }; +struct aoeif { + struct net_device *nd; + unsigned char lost; + unsigned char lostjumbo; + ushort maxbcnt; +}; + +struct aoetgt { + unsigned char addr[6]; + ushort nframes; + struct frame *frames; + struct aoeif ifs[NAOEIFS]; + struct aoeif *ifp; /* current aoeif in use */ + ushort nout; + ushort maxout; + u16 lasttag; /* last tag sent */ + u16 useme; + ulong lastwadj; /* last window adjustment */ + int wpkts, rpkts; + int dataref; +}; + struct aoedev { struct aoedev *next; - unsigned char addr[6]; /* remote mac addr */ - ushort flags; ulong sysminor; ulong aoemajor; - ulong aoeminor; + u16 aoeminor; + u16 flags; u16 nopen; /* (bd_openers isn't available without sleeping) */ - u16 lasttag; /* last tag sent */ u16 rttavg; /* round trip average of requests/responses */ u16 mintimer; u16 fw_ver; /* version of blade's firmware */ - u16 maxbcnt; struct work_struct work;/* disk create work struct */ struct gendisk *gd; struct request_queue blkq; @@ -134,15 +159,17 @@ struct aoedev { sector_t ssize; struct timer_list timer; spinlock_t lock; - struct net_device *ifp; /* interface ed is attached to */ struct sk_buff *sendq_hd; /* packets needing to be sent, list head */ struct sk_buff *sendq_tl; + struct sk_buff *skbpool_hd; + struct sk_buff *skbpool_tl; + int nskbpool; mempool_t *bufpool; /* for deadlock-free Buf allocation */ struct list_head bufq; /* queue of bios to work on */ struct buf *inprocess; /* the one we're currently working on */ - ushort lostjumbo; - ushort nframes; /* number of frames below */ - struct frame *frames; + struct aoetgt *targets[NTARGETS]; + struct aoetgt **tgt; /* target in use when working */ + struct aoetgt **htgt; /* target needing rexmit assistance */ }; @@ -160,14 +187,16 @@ void aoecmd_cfg(ushort aoemajor, unsigned char aoeminor); void aoecmd_ata_rsp(struct sk_buff *); void aoecmd_cfg_rsp(struct sk_buff *); void aoecmd_sleepwork(struct work_struct *); -struct sk_buff *new_skb(ulong); +void aoecmd_cleanslate(struct aoedev *); +struct sk_buff *aoecmd_ata_id(struct aoedev *); int aoedev_init(void); void aoedev_exit(void); struct aoedev *aoedev_by_aoeaddr(int maj, int min); -struct aoedev *aoedev_by_sysminor_m(ulong sysminor, ulong bufcnt); +struct aoedev *aoedev_by_sysminor_m(ulong sysminor); void aoedev_downdev(struct aoedev *d); int aoedev_isbusy(struct aoedev *d); +int aoedev_flush(const char __user *str, size_t size); int aoenet_init(void); void aoenet_exit(void); @@ -175,4 +204,4 @@ void aoenet_xmit(struct sk_buff *); int is_aoe_netif(struct net_device *ifp); int set_aoe_iflist(const char __user *str, size_t size); -u64 mac_addr(char addr[6]); +unsigned long long mac_addr(char addr[6]); diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 826d12381e21..0c39782b2660 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */ /* * aoeblk.c * block device routines @@ -24,7 +24,7 @@ static ssize_t aoedisk_show_state(struct device *dev, return snprintf(page, PAGE_SIZE, "%s%s\n", (d->flags & DEVFL_UP) ? "up" : "down", - (d->flags & DEVFL_PAUSE) ? ",paused" : + (d->flags & DEVFL_KICKME) ? ",kickme" : (d->nopen && !(d->flags & DEVFL_UP)) ? ",closewait" : ""); /* I'd rather see nopen exported so we can ditch closewait */ } @@ -33,17 +33,48 @@ static ssize_t aoedisk_show_mac(struct device *dev, { struct gendisk *disk = dev_to_disk(dev); struct aoedev *d = disk->private_data; + struct aoetgt *t = d->targets[0]; - return snprintf(page, PAGE_SIZE, "%012llx\n", - (unsigned long long)mac_addr(d->addr)); + if (t == NULL) + return snprintf(page, PAGE_SIZE, "none\n"); + return snprintf(page, PAGE_SIZE, "%012llx\n", mac_addr(t->addr)); } static ssize_t aoedisk_show_netif(struct device *dev, struct device_attribute *attr, char *page) { struct gendisk *disk = dev_to_disk(dev); struct aoedev *d = disk->private_data; + struct net_device *nds[8], **nd, **nnd, **ne; + struct aoetgt **t, **te; + struct aoeif *ifp, *e; + char *p; + + memset(nds, 0, sizeof nds); + nd = nds; + ne = nd + ARRAY_SIZE(nds); + t = d->targets; + te = t + NTARGETS; + for (; t < te && *t; t++) { + ifp = (*t)->ifs; + e = ifp + NAOEIFS; + for (; ifp < e && ifp->nd; ifp++) { + for (nnd = nds; nnd < nd; nnd++) + if (*nnd == ifp->nd) + break; + if (nnd == nd && nd != ne) + *nd++ = ifp->nd; + } + } - return snprintf(page, PAGE_SIZE, "%s\n", d->ifp->name); + ne = nd; + nd = nds; + if (*nd == NULL) + return snprintf(page, PAGE_SIZE, "none\n"); + for (p = page; nd < ne; nd++) + p += snprintf(p, PAGE_SIZE - (p-page), "%s%s", + p == page ? "" : ",", (*nd)->name); + p += snprintf(p, PAGE_SIZE - (p-page), "\n"); + return p-page; } /* firmware version */ static ssize_t aoedisk_show_fwver(struct device *dev, @@ -134,7 +165,23 @@ aoeblk_make_request(struct request_queue *q, struct bio *bio) blk_queue_bounce(q, &bio); + if (bio == NULL) { + printk(KERN_ERR "aoe: bio is NULL\n"); + BUG(); + return 0; + } d = bio->bi_bdev->bd_disk->private_data; + if (d == NULL) { + printk(KERN_ERR "aoe: bd_disk->private_data is NULL\n"); + BUG(); + bio_endio(bio, -ENXIO); + return 0; + } else if (bio->bi_io_vec == NULL) { + printk(KERN_ERR "aoe: bi_io_vec is NULL\n"); + BUG(); + bio_endio(bio, -ENXIO); + return 0; + } buf = mempool_alloc(d->bufpool, GFP_NOIO); if (buf == NULL) { printk(KERN_INFO "aoe: buf allocation failure\n"); @@ -143,19 +190,19 @@ aoeblk_make_request(struct request_queue *q, struct bio *bio) } memset(buf, 0, sizeof(*buf)); INIT_LIST_HEAD(&buf->bufs); - buf->start_time = jiffies; + buf->stime = jiffies; buf->bio = bio; buf->resid = bio->bi_size; buf->sector = bio->bi_sector; buf->bv = &bio->bi_io_vec[bio->bi_idx]; - WARN_ON(buf->bv->bv_len == 0); buf->bv_resid = buf->bv->bv_len; - buf->bufaddr = page_address(buf->bv->bv_page) + buf->bv->bv_offset; + WARN_ON(buf->bv_resid == 0); + buf->bv_off = buf->bv->bv_offset; spin_lock_irqsave(&d->lock, flags); if ((d->flags & DEVFL_UP) == 0) { - printk(KERN_INFO "aoe: device %ld.%ld is not up\n", + printk(KERN_INFO "aoe: device %ld.%d is not up\n", d->aoemajor, d->aoeminor); spin_unlock_irqrestore(&d->lock, flags); mempool_free(buf, d->bufpool); @@ -208,14 +255,15 @@ aoeblk_gdalloc(void *vp) gd = alloc_disk(AOE_PARTITIONS); if (gd == NULL) { - printk(KERN_ERR "aoe: cannot allocate disk structure for %ld.%ld\n", + printk(KERN_ERR + "aoe: cannot allocate disk structure for %ld.%d\n", d->aoemajor, d->aoeminor); goto err; } d->bufpool = mempool_create_slab_pool(MIN_BUFS, buf_pool_cache); if (d->bufpool == NULL) { - printk(KERN_ERR "aoe: cannot allocate bufpool for %ld.%ld\n", + printk(KERN_ERR "aoe: cannot allocate bufpool for %ld.%d\n", d->aoemajor, d->aoeminor); goto err_disk; } @@ -229,7 +277,7 @@ aoeblk_gdalloc(void *vp) gd->fops = &aoe_bdops; gd->private_data = d; gd->capacity = d->ssize; - snprintf(gd->disk_name, sizeof gd->disk_name, "etherd/e%ld.%ld", + snprintf(gd->disk_name, sizeof gd->disk_name, "etherd/e%ld.%d", d->aoemajor, d->aoeminor); gd->queue = &d->blkq; diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c index d5480e34cb22..e8e60e7a2e70 100644 --- a/drivers/block/aoe/aoechr.c +++ b/drivers/block/aoe/aoechr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */ /* * aoechr.c * AoE character device driver @@ -6,6 +6,7 @@ #include <linux/hdreg.h> #include <linux/blkdev.h> +#include <linux/delay.h> #include "aoe.h" enum { @@ -14,6 +15,7 @@ enum { MINOR_DISCOVER, MINOR_INTERFACES, MINOR_REVALIDATE, + MINOR_FLUSH, MSGSZ = 2048, NMSG = 100, /* message backlog to retain */ }; @@ -42,6 +44,7 @@ static struct aoe_chardev chardevs[] = { { MINOR_DISCOVER, "discover" }, { MINOR_INTERFACES, "interfaces" }, { MINOR_REVALIDATE, "revalidate" }, + { MINOR_FLUSH, "flush" }, }; static int @@ -68,6 +71,7 @@ revalidate(const char __user *str, size_t size) int major, minor, n; ulong flags; struct aoedev *d; + struct sk_buff *skb; char buf[16]; if (size >= sizeof buf) @@ -85,13 +89,20 @@ revalidate(const char __user *str, size_t size) d = aoedev_by_aoeaddr(major, minor); if (!d) return -EINVAL; - spin_lock_irqsave(&d->lock, flags); - d->flags &= ~DEVFL_MAXBCNT; - d->flags |= DEVFL_PAUSE; + aoecmd_cleanslate(d); +loop: + skb = aoecmd_ata_id(d); spin_unlock_irqrestore(&d->lock, flags); + /* try again if we are able to sleep a bit, + * otherwise give up this revalidation + */ + if (!skb && !msleep_interruptible(200)) { + spin_lock_irqsave(&d->lock, flags); + goto loop; + } + aoenet_xmit(skb); aoecmd_cfg(major, minor); - return 0; } @@ -149,6 +160,9 @@ aoechr_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offp break; case MINOR_REVALIDATE: ret = revalidate(buf, cnt); + break; + case MINOR_FLUSH: + ret = aoedev_flush(buf, cnt); } if (ret == 0) ret = cnt; @@ -185,52 +199,51 @@ aoechr_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off) ulong flags; n = (unsigned long) filp->private_data; - switch (n) { - case MINOR_ERR: - spin_lock_irqsave(&emsgs_lock, flags); -loop: - em = emsgs + emsgs_head_idx; - if ((em->flags & EMFL_VALID) == 0) { - if (filp->f_flags & O_NDELAY) { - spin_unlock_irqrestore(&emsgs_lock, flags); - return -EAGAIN; - } - nblocked_emsgs_readers++; + if (n != MINOR_ERR) + return -EFAULT; + + spin_lock_irqsave(&emsgs_lock, flags); + for (;;) { + em = emsgs + emsgs_head_idx; + if ((em->flags & EMFL_VALID) != 0) + break; + if (filp->f_flags & O_NDELAY) { spin_unlock_irqrestore(&emsgs_lock, flags); + return -EAGAIN; + } + nblocked_emsgs_readers++; - n = down_interruptible(&emsgs_sema); + spin_unlock_irqrestore(&emsgs_lock, flags); + + n = down_interruptible(&emsgs_sema); - spin_lock_irqsave(&emsgs_lock, flags); + spin_lock_irqsave(&emsgs_lock, flags); - nblocked_emsgs_readers--; + nblocked_emsgs_readers--; - if (n) { - spin_unlock_irqrestore(&emsgs_lock, flags); - return -ERESTARTSYS; - } - goto loop; - } - if (em->len > cnt) { + if (n) { spin_unlock_irqrestore(&emsgs_lock, flags); - return -EAGAIN; + return -ERESTARTSYS; } - mp = em->msg; - len = em->len; - em->msg = NULL; - em->flags &= ~EMFL_VALID; + } + if (em->len > cnt) { + spin_unlock_irqrestore(&emsgs_lock, flags); + return -EAGAIN; + } + mp = em->msg; + len = em->len; + em->msg = NULL; + em->flags &= ~EMFL_VALID; - emsgs_head_idx++; - emsgs_head_idx %= ARRAY_SIZE(emsgs); + emsgs_head_idx++; + emsgs_head_idx %= ARRAY_SIZE(emsgs); - spin_unlock_irqrestore(&emsgs_lock, flags); + spin_unlock_irqrestore(&emsgs_lock, flags); - n = copy_to_user(buf, mp, len); - kfree(mp); - return n == 0 ? len : -EFAULT; - default: - return -EFAULT; - } + n = copy_to_user(buf, mp, len); + kfree(mp); + return n == 0 ? len : -EFAULT; } static const struct file_operations aoe_fops = { diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 4d59d5057734..44beb17e8090 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */ /* * aoecmd.c * Filesystem request handling methods @@ -9,19 +9,21 @@ #include <linux/skbuff.h> #include <linux/netdevice.h> #include <linux/genhd.h> +#include <linux/moduleparam.h> #include <net/net_namespace.h> #include <asm/unaligned.h> #include "aoe.h" -#define TIMERTICK (HZ / 10) -#define MINTIMER (2 * TIMERTICK) -#define MAXTIMER (HZ << 1) - static int aoe_deadsecs = 60 * 3; module_param(aoe_deadsecs, int, 0644); MODULE_PARM_DESC(aoe_deadsecs, "After aoe_deadsecs seconds, give up and fail dev."); -struct sk_buff * +static int aoe_maxout = 16; +module_param(aoe_maxout, int, 0644); +MODULE_PARM_DESC(aoe_maxout, + "Only aoe_maxout outstanding packets for every MAC on eX.Y."); + +static struct sk_buff * new_skb(ulong len) { struct sk_buff *skb; @@ -43,12 +45,12 @@ new_skb(ulong len) } static struct frame * -getframe(struct aoedev *d, int tag) +getframe(struct aoetgt *t, int tag) { struct frame *f, *e; - f = d->frames; - e = f + d->nframes; + f = t->frames; + e = f + t->nframes; for (; f<e; f++) if (f->tag == tag) return f; @@ -61,21 +63,21 @@ getframe(struct aoedev *d, int tag) * This driver reserves tag -1 to mean "unused frame." */ static int -newtag(struct aoedev *d) +newtag(struct aoetgt *t) { register ulong n; n = jiffies & 0xffff; - return n |= (++d->lasttag & 0x7fff) << 16; + return n |= (++t->lasttag & 0x7fff) << 16; } static int -aoehdr_atainit(struct aoedev *d, struct aoe_hdr *h) +aoehdr_atainit(struct aoedev *d, struct aoetgt *t, struct aoe_hdr *h) { - u32 host_tag = newtag(d); + u32 host_tag = newtag(t); - memcpy(h->src, d->ifp->dev_addr, sizeof h->src); - memcpy(h->dst, d->addr, sizeof h->dst); + memcpy(h->src, t->ifp->nd->dev_addr, sizeof h->src); + memcpy(h->dst, t->addr, sizeof h->dst); h->type = __constant_cpu_to_be16(ETH_P_AOE); h->verfl = AOE_HVER; h->major = cpu_to_be16(d->aoemajor); @@ -98,42 +100,162 @@ put_lba(struct aoe_atahdr *ah, sector_t lba) } static void -aoecmd_ata_rw(struct aoedev *d, struct frame *f) +ifrotate(struct aoetgt *t) +{ + t->ifp++; + if (t->ifp >= &t->ifs[NAOEIFS] || t->ifp->nd == NULL) + t->ifp = t->ifs; + if (t->ifp->nd == NULL) { + printk(KERN_INFO "aoe: no interface to rotate to\n"); + BUG(); + } +} + +static void +skb_pool_put(struct aoedev *d, struct sk_buff *skb) +{ + if (!d->skbpool_hd) + d->skbpool_hd = skb; + else + d->skbpool_tl->next = skb; + d->skbpool_tl = skb; +} + +static struct sk_buff * +skb_pool_get(struct aoedev *d) +{ + struct sk_buff *skb; + + skb = d->skbpool_hd; + if (skb && atomic_read(&skb_shinfo(skb)->dataref) == 1) { + d->skbpool_hd = skb->next; + skb->next = NULL; + return skb; + } + if (d->nskbpool < NSKBPOOLMAX + && (skb = new_skb(ETH_ZLEN))) { + d->nskbpool++; + return skb; + } + return NULL; +} + +/* freeframe is where we do our load balancing so it's a little hairy. */ +static struct frame * +freeframe(struct aoedev *d) +{ + struct frame *f, *e, *rf; + struct aoetgt **t; + struct sk_buff *skb; + + if (d->targets[0] == NULL) { /* shouldn't happen, but I'm paranoid */ + printk(KERN_ERR "aoe: NULL TARGETS!\n"); + return NULL; + } + t = d->tgt; + t++; + if (t >= &d->targets[NTARGETS] || !*t) + t = d->targets; + for (;;) { + if ((*t)->nout < (*t)->maxout + && t != d->htgt + && (*t)->ifp->nd) { + rf = NULL; + f = (*t)->frames; + e = f + (*t)->nframes; + for (; f < e; f++) { + if (f->tag != FREETAG) + continue; + skb = f->skb; + if (!skb + && !(f->skb = skb = new_skb(ETH_ZLEN))) + continue; + if (atomic_read(&skb_shinfo(skb)->dataref) + != 1) { + if (!rf) + rf = f; + continue; + } +gotone: skb_shinfo(skb)->nr_frags = skb->data_len = 0; + skb_trim(skb, 0); + d->tgt = t; + ifrotate(*t); + return f; + } + /* Work can be done, but the network layer is + holding our precious packets. Try to grab + one from the pool. */ + f = rf; + if (f == NULL) { /* more paranoia */ + printk(KERN_ERR + "aoe: freeframe: %s.\n", + "unexpected null rf"); + d->flags |= DEVFL_KICKME; + return NULL; + } + skb = skb_pool_get(d); + if (skb) { + skb_pool_put(d, f->skb); + f->skb = skb; + goto gotone; + } + (*t)->dataref++; + if ((*t)->nout == 0) + d->flags |= DEVFL_KICKME; + } + if (t == d->tgt) /* we've looped and found nada */ + break; + t++; + if (t >= &d->targets[NTARGETS] || !*t) + t = d->targets; + } + return NULL; +} + +static int +aoecmd_ata_rw(struct aoedev *d) { + struct frame *f; struct aoe_hdr *h; struct aoe_atahdr *ah; struct buf *buf; + struct bio_vec *bv; + struct aoetgt *t; struct sk_buff *skb; ulong bcnt; - register sector_t sector; char writebit, extbit; writebit = 0x10; extbit = 0x4; + f = freeframe(d); + if (f == NULL) + return 0; + t = *d->tgt; buf = d->inprocess; - - sector = buf->sector; - bcnt = buf->bv_resid; - if (bcnt > d->maxbcnt) - bcnt = d->maxbcnt; - + bv = buf->bv; + bcnt = t->ifp->maxbcnt; + if (bcnt == 0) + bcnt = DEFAULTBCNT; + if (bcnt > buf->bv_resid) + bcnt = buf->bv_resid; /* initialize the headers & frame */ skb = f->skb; h = (struct aoe_hdr *) skb_mac_header(skb); ah = (struct aoe_atahdr *) (h+1); skb_put(skb, sizeof *h + sizeof *ah); memset(h, 0, skb->len); - f->tag = aoehdr_atainit(d, h); + f->tag = aoehdr_atainit(d, t, h); + t->nout++; f->waited = 0; f->buf = buf; - f->bufaddr = buf->bufaddr; + f->bufaddr = page_address(bv->bv_page) + buf->bv_off; f->bcnt = bcnt; - f->lba = sector; + f->lba = buf->sector; /* set up ata header */ ah->scnt = bcnt >> 9; - put_lba(ah, sector); + put_lba(ah, buf->sector); if (d->flags & DEVFL_EXT) { ah->aflags |= AOEAFL_EXT; } else { @@ -141,14 +263,14 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) ah->lba3 &= 0x0f; ah->lba3 |= 0xe0; /* LBA bit + obsolete 0xa0 */ } - if (bio_data_dir(buf->bio) == WRITE) { - skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr), - offset_in_page(f->bufaddr), bcnt); + skb_fill_page_desc(skb, 0, bv->bv_page, buf->bv_off, bcnt); ah->aflags |= AOEAFL_WRITE; skb->len += bcnt; skb->data_len = bcnt; + t->wpkts++; } else { + t->rpkts++; writebit = 0; } @@ -156,29 +278,29 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) /* mark all tracking fields and load out */ buf->nframesout += 1; - buf->bufaddr += bcnt; + buf->bv_off += bcnt; buf->bv_resid -= bcnt; -/* printk(KERN_DEBUG "aoe: bv_resid=%ld\n", buf->bv_resid); */ buf->resid -= bcnt; buf->sector += bcnt >> 9; if (buf->resid == 0) { d->inprocess = NULL; } else if (buf->bv_resid == 0) { - buf->bv++; - WARN_ON(buf->bv->bv_len == 0); - buf->bv_resid = buf->bv->bv_len; - buf->bufaddr = page_address(buf->bv->bv_page) + buf->bv->bv_offset; + buf->bv = ++bv; + buf->bv_resid = bv->bv_len; + WARN_ON(buf->bv_resid == 0); + buf->bv_off = bv->bv_offset; } - skb->dev = d->ifp; + skb->dev = t->ifp->nd; skb = skb_clone(skb, GFP_ATOMIC); - if (skb == NULL) - return; - if (d->sendq_hd) - d->sendq_tl->next = skb; - else - d->sendq_hd = skb; - d->sendq_tl = skb; + if (skb) { + if (d->sendq_hd) + d->sendq_tl->next = skb; + else + d->sendq_hd = skb; + d->sendq_tl = skb; + } + return 1; } /* some callers cannot sleep, and they can call this function, @@ -232,62 +354,8 @@ cont: return sl; } -static struct frame * -freeframe(struct aoedev *d) -{ - struct frame *f, *e; - int n = 0; - - f = d->frames; - e = f + d->nframes; - for (; f<e; f++) { - if (f->tag != FREETAG) - continue; - if (atomic_read(&skb_shinfo(f->skb)->dataref) == 1) { - skb_shinfo(f->skb)->nr_frags = f->skb->data_len = 0; - skb_trim(f->skb, 0); - return f; - } - n++; - } - if (n == d->nframes) /* wait for network layer */ - d->flags |= DEVFL_KICKME; - - return NULL; -} - -/* enters with d->lock held */ -void -aoecmd_work(struct aoedev *d) -{ - struct frame *f; - struct buf *buf; - - if (d->flags & DEVFL_PAUSE) { - if (!aoedev_isbusy(d)) - d->sendq_hd = aoecmd_cfg_pkts(d->aoemajor, - d->aoeminor, &d->sendq_tl); - return; - } - -loop: - f = freeframe(d); - if (f == NULL) - return; - if (d->inprocess == NULL) { - if (list_empty(&d->bufq)) - return; - buf = container_of(d->bufq.next, struct buf, bufs); - list_del(d->bufq.next); -/*printk(KERN_DEBUG "aoe: bi_size=%ld\n", buf->bio->bi_size); */ - d->inprocess = buf; - } - aoecmd_ata_rw(d, f); - goto loop; -} - static void -rexmit(struct aoedev *d, struct frame *f) +resend(struct aoedev *d, struct aoetgt *t, struct frame *f) { struct sk_buff *skb; struct aoe_hdr *h; @@ -295,41 +363,46 @@ rexmit(struct aoedev *d, struct frame *f) char buf[128]; u32 n; - n = newtag(d); + ifrotate(t); + n = newtag(t); + skb = f->skb; + h = (struct aoe_hdr *) skb_mac_header(skb); + ah = (struct aoe_atahdr *) (h+1); snprintf(buf, sizeof buf, - "%15s e%ld.%ld oldtag=%08x@%08lx newtag=%08x\n", - "retransmit", - d->aoemajor, d->aoeminor, f->tag, jiffies, n); + "%15s e%ld.%d oldtag=%08x@%08lx newtag=%08x " + "s=%012llx d=%012llx nout=%d\n", + "retransmit", d->aoemajor, d->aoeminor, f->tag, jiffies, n, + mac_addr(h->src), + mac_addr(h->dst), t->nout); aoechr_error(buf); - skb = f->skb; - h = (struct aoe_hdr *) skb_mac_header(skb); - ah = (struct aoe_atahdr *) (h+1); f->tag = n; h->tag = cpu_to_be32(n); - memcpy(h->dst, d->addr, sizeof h->dst); - memcpy(h->src, d->ifp->dev_addr, sizeof h->src); - - n = DEFAULTBCNT / 512; - if (ah->scnt > n) { - ah->scnt = n; + memcpy(h->dst, t->addr, sizeof h->dst); + memcpy(h->src, t->ifp->nd->dev_addr, sizeof h->src); + + switch (ah->cmdstat) { + default: + break; + case WIN_READ: + case WIN_READ_EXT: + case WIN_WRITE: + case WIN_WRITE_EXT: + put_lba(ah, f->lba); + + n = f->bcnt; + if (n > DEFAULTBCNT) + n = DEFAULTBCNT; + ah->scnt = n >> 9; if (ah->aflags & AOEAFL_WRITE) { skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr), - offset_in_page(f->bufaddr), DEFAULTBCNT); - skb->len = sizeof *h + sizeof *ah + DEFAULTBCNT; - skb->data_len = DEFAULTBCNT; - } - if (++d->lostjumbo > (d->nframes << 1)) - if (d->maxbcnt != DEFAULTBCNT) { - printk(KERN_INFO "aoe: e%ld.%ld: too many lost jumbo on %s - using 1KB frames.\n", - d->aoemajor, d->aoeminor, d->ifp->name); - d->maxbcnt = DEFAULTBCNT; - d->flags |= DEVFL_MAXBCNT; + offset_in_page(f->bufaddr), n); + skb->len = sizeof *h + sizeof *ah + n; + skb->data_len = n; } } - - skb->dev = d->ifp; + skb->dev = t->ifp->nd; skb = skb_clone(skb, GFP_ATOMIC); if (skb == NULL) return; @@ -352,10 +425,92 @@ tsince(int tag) return n; } +static struct aoeif * +getif(struct aoetgt *t, struct net_device *nd) +{ + struct aoeif *p, *e; + + p = t->ifs; + e = p + NAOEIFS; + for (; p < e; p++) + if (p->nd == nd) + return p; + return NULL; +} + +static struct aoeif * +addif(struct aoetgt *t, struct net_device *nd) +{ + struct aoeif *p; + + p = getif(t, NULL); + if (!p) + return NULL; + p->nd = nd; + p->maxbcnt = DEFAULTBCNT; + p->lost = 0; + p->lostjumbo = 0; + return p; +} + +static void +ejectif(struct aoetgt *t, struct aoeif *ifp) +{ + struct aoeif *e; + ulong n; + + e = t->ifs + NAOEIFS - 1; + n = (e - ifp) * sizeof *ifp; + memmove(ifp, ifp+1, n); + e->nd = NULL; +} + +static int +sthtith(struct aoedev *d) +{ + struct frame *f, *e, *nf; + struct sk_buff *skb; + struct aoetgt *ht = *d->htgt; + + f = ht->frames; + e = f + ht->nframes; + for (; f < e; f++) { + if (f->tag == FREETAG) + continue; + nf = freeframe(d); + if (!nf) + return 0; + skb = nf->skb; + *nf = *f; + f->skb = skb; + f->tag = FREETAG; + nf->waited = 0; + ht->nout--; + (*d->tgt)->nout++; + resend(d, *d->tgt, nf); + } + /* he's clean, he's useless. take away his interfaces */ + memset(ht->ifs, 0, sizeof ht->ifs); + d->htgt = NULL; + return 1; +} + +static inline unsigned char +ata_scnt(unsigned char *packet) { + struct aoe_hdr *h; + struct aoe_atahdr *ah; + + h = (struct aoe_hdr *) packet; + ah = (struct aoe_atahdr *) (h+1); + return ah->scnt; +} + static void rexmit_timer(ulong vp) { struct aoedev *d; + struct aoetgt *t, **tt, **te; + struct aoeif *ifp; struct frame *f, *e; struct sk_buff *sl; register long timeout; @@ -374,31 +529,79 @@ rexmit_timer(ulong vp) spin_unlock_irqrestore(&d->lock, flags); return; } - f = d->frames; - e = f + d->nframes; - for (; f<e; f++) { - if (f->tag != FREETAG && tsince(f->tag) >= timeout) { + tt = d->targets; + te = tt + NTARGETS; + for (; tt < te && *tt; tt++) { + t = *tt; + f = t->frames; + e = f + t->nframes; + for (; f < e; f++) { + if (f->tag == FREETAG + || tsince(f->tag) < timeout) + continue; n = f->waited += timeout; n /= HZ; - if (n > aoe_deadsecs) { /* waited too long for response */ + if (n > aoe_deadsecs) { + /* waited too long. device failure. */ aoedev_downdev(d); break; } - rexmit(d, f); + + if (n > HELPWAIT /* see if another target can help */ + && (tt != d->targets || d->targets[1])) + d->htgt = tt; + + if (t->nout == t->maxout) { + if (t->maxout > 1) + t->maxout--; + t->lastwadj = jiffies; + } + + ifp = getif(t, f->skb->dev); + if (ifp && ++ifp->lost > (t->nframes << 1) + && (ifp != t->ifs || t->ifs[1].nd)) { + ejectif(t, ifp); + ifp = NULL; + } + + if (ata_scnt(skb_mac_header(f->skb)) > DEFAULTBCNT / 512 + && ifp && ++ifp->lostjumbo > (t->nframes << 1) + && ifp->maxbcnt != DEFAULTBCNT) { + printk(KERN_INFO + "aoe: e%ld.%d: " + "too many lost jumbo on " + "%s:%012llx - " + "falling back to %d frames.\n", + d->aoemajor, d->aoeminor, + ifp->nd->name, mac_addr(t->addr), + DEFAULTBCNT); + ifp->maxbcnt = 0; + } + resend(d, t, f); + } + + /* window check */ + if (t->nout == t->maxout + && t->maxout < t->nframes + && (jiffies - t->lastwadj)/HZ > 10) { + t->maxout++; + t->lastwadj = jiffies; } } - if (d->flags & DEVFL_KICKME) { + + if (d->sendq_hd) { + n = d->rttavg <<= 1; + if (n > MAXTIMER) + d->rttavg = MAXTIMER; + } + + if (d->flags & DEVFL_KICKME || d->htgt) { d->flags &= ~DEVFL_KICKME; aoecmd_work(d); } sl = d->sendq_hd; d->sendq_hd = d->sendq_tl = NULL; - if (sl) { - n = d->rttavg <<= 1; - if (n > MAXTIMER) - d->rttavg = MAXTIMER; - } d->timer.expires = jiffies + TIMERTICK; add_timer(&d->timer); @@ -408,6 +611,25 @@ rexmit_timer(ulong vp) aoenet_xmit(sl); } +/* enters with d->lock held */ +void +aoecmd_work(struct aoedev *d) +{ + struct buf *buf; +loop: + if (d->htgt && !sthtith(d)) + return; + if (d->inprocess == NULL) { + if (list_empty(&d->bufq)) + return; + buf = container_of(d->bufq.next, struct buf, bufs); + list_del(d->bufq.next); + d->inprocess = buf; + } + if (aoecmd_ata_rw(d)) + goto loop; +} + /* this function performs work that has been deferred until sleeping is OK */ void @@ -440,7 +662,7 @@ aoecmd_sleepwork(struct work_struct *work) } static void -ataid_complete(struct aoedev *d, unsigned char *id) +ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id) { u64 ssize; u16 n; @@ -475,24 +697,20 @@ ataid_complete(struct aoedev *d, unsigned char *id) } if (d->ssize != ssize) - printk(KERN_INFO "aoe: %012llx e%lu.%lu v%04x has %llu sectors\n", - (unsigned long long)mac_addr(d->addr), + printk(KERN_INFO + "aoe: %012llx e%ld.%d v%04x has %llu sectors\n", + mac_addr(t->addr), d->aoemajor, d->aoeminor, d->fw_ver, (long long)ssize); d->ssize = ssize; d->geo.start = 0; + if (d->flags & (DEVFL_GDALLOC|DEVFL_NEWSIZE)) + return; if (d->gd != NULL) { d->gd->capacity = ssize; d->flags |= DEVFL_NEWSIZE; - } else { - if (d->flags & DEVFL_GDALLOC) { - printk(KERN_ERR "aoe: can't schedule work for e%lu.%lu, %s\n", - d->aoemajor, d->aoeminor, - "it's already on! This shouldn't happen.\n"); - return; - } + } else d->flags |= DEVFL_GDALLOC; - } schedule_work(&d->work); } @@ -519,6 +737,31 @@ calc_rttavg(struct aoedev *d, int rtt) d->rttavg += n >> 2; } +static struct aoetgt * +gettgt(struct aoedev *d, char *addr) +{ + struct aoetgt **t, **e; + + t = d->targets; + e = t + NTARGETS; + for (; t < e && *t; t++) + if (memcmp((*t)->addr, addr, sizeof((*t)->addr)) == 0) + return *t; + return NULL; +} + +static inline void +diskstats(struct gendisk *disk, struct bio *bio, ulong duration) +{ + unsigned long n_sect = bio->bi_size >> 9; + const int rw = bio_data_dir(bio); + + disk_stat_inc(disk, ios[rw]); + disk_stat_add(disk, ticks[rw], duration); + disk_stat_add(disk, sectors[rw], n_sect); + disk_stat_add(disk, io_ticks, duration); +} + void aoecmd_ata_rsp(struct sk_buff *skb) { @@ -528,6 +771,8 @@ aoecmd_ata_rsp(struct sk_buff *skb) struct frame *f; struct buf *buf; struct sk_buff *sl; + struct aoetgt *t; + struct aoeif *ifp; register long n; ulong flags; char ebuf[128]; @@ -547,7 +792,14 @@ aoecmd_ata_rsp(struct sk_buff *skb) spin_lock_irqsave(&d->lock, flags); n = be32_to_cpu(get_unaligned(&hin->tag)); - f = getframe(d, n); + t = gettgt(d, hin->src); + if (t == NULL) { + printk(KERN_INFO "aoe: can't find target e%ld.%d:%012llx\n", + d->aoemajor, d->aoeminor, mac_addr(hin->src)); + spin_unlock_irqrestore(&d->lock, flags); + return; + } + f = getframe(t, n); if (f == NULL) { calc_rttavg(d, -tsince(n)); spin_unlock_irqrestore(&d->lock, flags); @@ -569,24 +821,24 @@ aoecmd_ata_rsp(struct sk_buff *skb) ahout = (struct aoe_atahdr *) (hout+1); buf = f->buf; - if (ahout->cmdstat == WIN_IDENTIFY) - d->flags &= ~DEVFL_PAUSE; if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */ printk(KERN_ERR - "aoe: ata error cmd=%2.2Xh stat=%2.2Xh from e%ld.%ld\n", + "aoe: ata error cmd=%2.2Xh stat=%2.2Xh from e%ld.%d\n", ahout->cmdstat, ahin->cmdstat, d->aoemajor, d->aoeminor); if (buf) buf->flags |= BUFFL_FAIL; } else { + if (d->htgt && t == *d->htgt) /* I'll help myself, thank you. */ + d->htgt = NULL; n = ahout->scnt << 9; switch (ahout->cmdstat) { case WIN_READ: case WIN_READ_EXT: if (skb->len - sizeof *hin - sizeof *ahin < n) { printk(KERN_ERR - "aoe: runt data size in read. skb->len=%d\n", - skb->len); + "aoe: %s. skb->len=%d need=%ld\n", + "runt data size in read", skb->len, n); /* fail frame f? just returning will rexmit. */ spin_unlock_irqrestore(&d->lock, flags); return; @@ -594,32 +846,18 @@ aoecmd_ata_rsp(struct sk_buff *skb) memcpy(f->bufaddr, ahin+1, n); case WIN_WRITE: case WIN_WRITE_EXT: + ifp = getif(t, skb->dev); + if (ifp) { + ifp->lost = 0; + if (n > DEFAULTBCNT) + ifp->lostjumbo = 0; + } if (f->bcnt -= n) { - skb = f->skb; + f->lba += n >> 9; f->bufaddr += n; - put_lba(ahout, f->lba += ahout->scnt); - n = f->bcnt; - if (n > DEFAULTBCNT) - n = DEFAULTBCNT; - ahout->scnt = n >> 9; - if (ahout->aflags & AOEAFL_WRITE) { - skb_fill_page_desc(skb, 0, - virt_to_page(f->bufaddr), - offset_in_page(f->bufaddr), n); - skb->len = sizeof *hout + sizeof *ahout + n; - skb->data_len = n; - } - f->tag = newtag(d); - hout->tag = cpu_to_be32(f->tag); - skb->dev = d->ifp; - skb = skb_clone(skb, GFP_ATOMIC); - spin_unlock_irqrestore(&d->lock, flags); - if (skb) - aoenet_xmit(skb); - return; + resend(d, t, f); + goto xmit; } - if (n > DEFAULTBCNT) - d->lostjumbo = 0; break; case WIN_IDENTIFY: if (skb->len - sizeof *hin - sizeof *ahin < 512) { @@ -629,7 +867,7 @@ aoecmd_ata_rsp(struct sk_buff *skb) spin_unlock_irqrestore(&d->lock, flags); return; } - ataid_complete(d, (char *) (ahin+1)); + ataid_complete(d, t, (char *) (ahin+1)); break; default: printk(KERN_INFO @@ -640,28 +878,19 @@ aoecmd_ata_rsp(struct sk_buff *skb) } } - if (buf) { - buf->nframesout -= 1; - if (buf->nframesout == 0 && buf->resid == 0) { - unsigned long duration = jiffies - buf->start_time; - unsigned long n_sect = buf->bio->bi_size >> 9; - struct gendisk *disk = d->gd; - const int rw = bio_data_dir(buf->bio); - - disk_stat_inc(disk, ios[rw]); - disk_stat_add(disk, ticks[rw], duration); - disk_stat_add(disk, sectors[rw], n_sect); - disk_stat_add(disk, io_ticks, duration); - n = (buf->flags & BUFFL_FAIL) ? -EIO : 0; - bio_endio(buf->bio, n); - mempool_free(buf, d->bufpool); - } + if (buf && --buf->nframesout == 0 && buf->resid == 0) { + diskstats(d->gd, buf->bio, jiffies - buf->stime); + n = (buf->flags & BUFFL_FAIL) ? -EIO : 0; + bio_endio(buf->bio, n); + mempool_free(buf, d->bufpool); } f->buf = NULL; f->tag = FREETAG; + t->nout--; aoecmd_work(d); +xmit: sl = d->sendq_hd; d->sendq_hd = d->sendq_tl = NULL; @@ -679,23 +908,20 @@ aoecmd_cfg(ushort aoemajor, unsigned char aoeminor) aoenet_xmit(sl); } -/* - * Since we only call this in one place (and it only prepares one frame) - * we just return the skb. Usually we'd chain it up to the aoedev sendq. - */ -static struct sk_buff * +struct sk_buff * aoecmd_ata_id(struct aoedev *d) { struct aoe_hdr *h; struct aoe_atahdr *ah; struct frame *f; struct sk_buff *skb; + struct aoetgt *t; f = freeframe(d); - if (f == NULL) { - printk(KERN_ERR "aoe: can't get a frame. This shouldn't happen.\n"); + if (f == NULL) return NULL; - } + + t = *d->tgt; /* initialize the headers & frame */ skb = f->skb; @@ -703,7 +929,8 @@ aoecmd_ata_id(struct aoedev *d) ah = (struct aoe_atahdr *) (h+1); skb_put(skb, sizeof *h + sizeof *ah); memset(h, 0, skb->len); - f->tag = aoehdr_atainit(d, h); + f->tag = aoehdr_atainit(d, t, h); + t->nout++; f->waited = 0; /* set up ata header */ @@ -711,7 +938,7 @@ aoecmd_ata_id(struct aoedev *d) ah->cmdstat = WIN_IDENTIFY; ah->lba3 = 0xa0; - skb->dev = d->ifp; + skb->dev = t->ifp->nd; d->rttavg = MAXTIMER; d->timer.function = rexmit_timer; @@ -719,15 +946,52 @@ aoecmd_ata_id(struct aoedev *d) return skb_clone(skb, GFP_ATOMIC); } +static struct aoetgt * +addtgt(struct aoedev *d, char *addr, ulong nframes) +{ + struct aoetgt *t, **tt, **te; + struct frame *f, *e; + + tt = d->targets; + te = tt + NTARGETS; + for (; tt < te && *tt; tt++) + ; + + if (tt == te) { + printk(KERN_INFO + "aoe: device addtgt failure; too many targets\n"); + return NULL; + } + t = kcalloc(1, sizeof *t, GFP_ATOMIC); + f = kcalloc(nframes, sizeof *f, GFP_ATOMIC); + if (!t || !f) { + kfree(f); + kfree(t); + printk(KERN_INFO "aoe: cannot allocate memory to add target\n"); + return NULL; + } + + t->nframes = nframes; + t->frames = f; + e = f + nframes; + for (; f < e; f++) + f->tag = FREETAG; + memcpy(t->addr, addr, sizeof t->addr); + t->ifp = t->ifs; + t->maxout = t->nframes; + return *tt = t; +} + void aoecmd_cfg_rsp(struct sk_buff *skb) { struct aoedev *d; struct aoe_hdr *h; struct aoe_cfghdr *ch; + struct aoetgt *t; + struct aoeif *ifp; ulong flags, sysminor, aoemajor; struct sk_buff *sl; - enum { MAXFRAMES = 16 }; u16 n; h = (struct aoe_hdr *) skb_mac_header(skb); @@ -752,10 +1016,10 @@ aoecmd_cfg_rsp(struct sk_buff *skb) } n = be16_to_cpu(ch->bufcnt); - if (n > MAXFRAMES) /* keep it reasonable */ - n = MAXFRAMES; + if (n > aoe_maxout) /* keep it reasonable */ + n = aoe_maxout; - d = aoedev_by_sysminor_m(sysminor, n); + d = aoedev_by_sysminor_m(sysminor); if (d == NULL) { printk(KERN_INFO "aoe: device sysminor_m failure\n"); return; @@ -763,38 +1027,74 @@ aoecmd_cfg_rsp(struct sk_buff *skb) spin_lock_irqsave(&d->lock, flags); - /* permit device to migrate mac and network interface */ - d->ifp = skb->dev; - memcpy(d->addr, h->src, sizeof d->addr); - if (!(d->flags & DEVFL_MAXBCNT)) { - n = d->ifp->mtu; + t = gettgt(d, h->src); + if (!t) { + t = addtgt(d, h->src, n); + if (!t) { + spin_unlock_irqrestore(&d->lock, flags); + return; + } + } + ifp = getif(t, skb->dev); + if (!ifp) { + ifp = addif(t, skb->dev); + if (!ifp) { + printk(KERN_INFO + "aoe: device addif failure; " + "too many interfaces?\n"); + spin_unlock_irqrestore(&d->lock, flags); + return; + } + } + if (ifp->maxbcnt) { + n = ifp->nd->mtu; n -= sizeof (struct aoe_hdr) + sizeof (struct aoe_atahdr); n /= 512; if (n > ch->scnt) n = ch->scnt; n = n ? n * 512 : DEFAULTBCNT; - if (n != d->maxbcnt) { + if (n != ifp->maxbcnt) { printk(KERN_INFO - "aoe: e%ld.%ld: setting %d byte data frames on %s\n", - d->aoemajor, d->aoeminor, n, d->ifp->name); - d->maxbcnt = n; + "aoe: e%ld.%d: setting %d%s%s:%012llx\n", + d->aoemajor, d->aoeminor, n, + " byte data frames on ", ifp->nd->name, + mac_addr(t->addr)); + ifp->maxbcnt = n; } } /* don't change users' perspective */ - if (d->nopen && !(d->flags & DEVFL_PAUSE)) { + if (d->nopen) { spin_unlock_irqrestore(&d->lock, flags); return; } - d->flags |= DEVFL_PAUSE; /* force pause */ - d->mintimer = MINTIMER; d->fw_ver = be16_to_cpu(ch->fwver); - /* check for already outstanding ataid */ - sl = aoedev_isbusy(d) == 0 ? aoecmd_ata_id(d) : NULL; + sl = aoecmd_ata_id(d); spin_unlock_irqrestore(&d->lock, flags); aoenet_xmit(sl); } +void +aoecmd_cleanslate(struct aoedev *d) +{ + struct aoetgt **t, **te; + struct aoeif *p, *e; + + d->mintimer = MINTIMER; + + t = d->targets; + te = t + NTARGETS; + for (; t < te && *t; t++) { + (*t)->maxout = (*t)->nframes; + p = (*t)->ifs; + e = p + NAOEIFS; + for (; p < e; p++) { + p->lostjumbo = 0; + p->lost = 0; + p->maxbcnt = DEFAULTBCNT; + } + } +} diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c index 51f50710e5fc..f9a1cd9edb77 100644 --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */ /* * aoedev.c * AoE device utility functions; maintains device list. @@ -7,23 +7,32 @@ #include <linux/hdreg.h> #include <linux/blkdev.h> #include <linux/netdevice.h> +#include <linux/delay.h> #include "aoe.h" +static void dummy_timer(ulong); +static void aoedev_freedev(struct aoedev *); +static void freetgt(struct aoedev *d, struct aoetgt *t); +static void skbpoolfree(struct aoedev *d); + static struct aoedev *devlist; -static spinlock_t devlist_lock; +static DEFINE_SPINLOCK(devlist_lock); int aoedev_isbusy(struct aoedev *d) { + struct aoetgt **t, **te; struct frame *f, *e; - f = d->frames; - e = f + d->nframes; - do { - if (f->tag != FREETAG) - return 1; - } while (++f < e); - + t = d->targets; + te = t + NTARGETS; + for (; t < te && *t; t++) { + f = (*t)->frames; + e = f + (*t)->nframes; + for (; f < e; f++) + if (f->tag != FREETAG) + return 1; + } return 0; } @@ -55,75 +64,41 @@ dummy_timer(ulong vp) add_timer(&d->timer); } -/* called with devlist lock held */ -static struct aoedev * -aoedev_newdev(ulong nframes) -{ - struct aoedev *d; - struct frame *f, *e; - - d = kzalloc(sizeof *d, GFP_ATOMIC); - f = kcalloc(nframes, sizeof *f, GFP_ATOMIC); - switch (!d || !f) { - case 0: - d->nframes = nframes; - d->frames = f; - e = f + nframes; - for (; f<e; f++) { - f->tag = FREETAG; - f->skb = new_skb(ETH_ZLEN); - if (!f->skb) - break; - } - if (f == e) - break; - while (f > d->frames) { - f--; - dev_kfree_skb(f->skb); - } - default: - if (f) - kfree(f); - if (d) - kfree(d); - return NULL; - } - INIT_WORK(&d->work, aoecmd_sleepwork); - spin_lock_init(&d->lock); - init_timer(&d->timer); - d->timer.data = (ulong) d; - d->timer.function = dummy_timer; - d->timer.expires = jiffies + HZ; - add_timer(&d->timer); - d->bufpool = NULL; /* defer to aoeblk_gdalloc */ - INIT_LIST_HEAD(&d->bufq); - d->next = devlist; - devlist = d; - - return d; -} - void aoedev_downdev(struct aoedev *d) { + struct aoetgt **t, **te; struct frame *f, *e; struct buf *buf; struct bio *bio; - f = d->frames; - e = f + d->nframes; - for (; f<e; f->tag = FREETAG, f->buf = NULL, f++) { - if (f->tag == FREETAG || f->buf == NULL) - continue; - buf = f->buf; - bio = buf->bio; - if (--buf->nframesout == 0) { - mempool_free(buf, d->bufpool); - bio_endio(bio, -EIO); + t = d->targets; + te = t + NTARGETS; + for (; t < te && *t; t++) { + f = (*t)->frames; + e = f + (*t)->nframes; + for (; f < e; f->tag = FREETAG, f->buf = NULL, f++) { + if (f->tag == FREETAG || f->buf == NULL) + continue; + buf = f->buf; + bio = buf->bio; + if (--buf->nframesout == 0 + && buf != d->inprocess) { + mempool_free(buf, d->bufpool); + bio_endio(bio, -EIO); + } } - skb_shinfo(f->skb)->nr_frags = f->skb->data_len = 0; + (*t)->maxout = (*t)->nframes; + (*t)->nout = 0; + } + buf = d->inprocess; + if (buf) { + bio = buf->bio; + mempool_free(buf, d->bufpool); + bio_endio(bio, -EIO); } d->inprocess = NULL; + d->htgt = NULL; while (!list_empty(&d->bufq)) { buf = container_of(d->bufq.next, struct buf, bufs); @@ -136,12 +111,114 @@ aoedev_downdev(struct aoedev *d) if (d->gd) d->gd->capacity = 0; - d->flags &= ~(DEVFL_UP | DEVFL_PAUSE); + d->flags &= ~DEVFL_UP; +} + +static void +aoedev_freedev(struct aoedev *d) +{ + struct aoetgt **t, **e; + + if (d->gd) { + aoedisk_rm_sysfs(d); + del_gendisk(d->gd); + put_disk(d->gd); + } + t = d->targets; + e = t + NTARGETS; + for (; t < e && *t; t++) + freetgt(d, *t); + if (d->bufpool) + mempool_destroy(d->bufpool); + skbpoolfree(d); + kfree(d); +} + +int +aoedev_flush(const char __user *str, size_t cnt) +{ + ulong flags; + struct aoedev *d, **dd; + struct aoedev *rmd = NULL; + char buf[16]; + int all = 0; + + if (cnt >= 3) { + if (cnt > sizeof buf) + cnt = sizeof buf; + if (copy_from_user(buf, str, cnt)) + return -EFAULT; + all = !strncmp(buf, "all", 3); + } + + flush_scheduled_work(); + spin_lock_irqsave(&devlist_lock, flags); + dd = &devlist; + while ((d = *dd)) { + spin_lock(&d->lock); + if ((!all && (d->flags & DEVFL_UP)) + || (d->flags & (DEVFL_GDALLOC|DEVFL_NEWSIZE)) + || d->nopen) { + spin_unlock(&d->lock); + dd = &d->next; + continue; + } + *dd = d->next; + aoedev_downdev(d); + d->flags |= DEVFL_TKILL; + spin_unlock(&d->lock); + d->next = rmd; + rmd = d; + } + spin_unlock_irqrestore(&devlist_lock, flags); + while ((d = rmd)) { + rmd = d->next; + del_timer_sync(&d->timer); + aoedev_freedev(d); /* must be able to sleep */ + } + return 0; +} + +/* I'm not really sure that this is a realistic problem, but if the +network driver goes gonzo let's just leak memory after complaining. */ +static void +skbfree(struct sk_buff *skb) +{ + enum { Sms = 100, Tms = 3*1000}; + int i = Tms / Sms; + + if (skb == NULL) + return; + while (atomic_read(&skb_shinfo(skb)->dataref) != 1 && i-- > 0) + msleep(Sms); + if (i <= 0) { + printk(KERN_ERR + "aoe: %s holds ref: %s\n", + skb->dev ? skb->dev->name : "netif", + "cannot free skb -- memory leaked."); + return; + } + skb_shinfo(skb)->nr_frags = skb->data_len = 0; + skb_trim(skb, 0); + dev_kfree_skb(skb); +} + +static void +skbpoolfree(struct aoedev *d) +{ + struct sk_buff *skb; + + while ((skb = d->skbpool_hd)) { + d->skbpool_hd = skb->next; + skb->next = NULL; + skbfree(skb); + } + d->skbpool_tl = NULL; } /* find it or malloc it */ struct aoedev * -aoedev_by_sysminor_m(ulong sysminor, ulong bufcnt) +aoedev_by_sysminor_m(ulong sysminor) { struct aoedev *d; ulong flags; @@ -151,43 +228,43 @@ aoedev_by_sysminor_m(ulong sysminor, ulong bufcnt) for (d=devlist; d; d=d->next) if (d->sysminor == sysminor) break; - - if (d == NULL) { - d = aoedev_newdev(bufcnt); - if (d == NULL) { - spin_unlock_irqrestore(&devlist_lock, flags); - printk(KERN_INFO "aoe: aoedev_newdev failure.\n"); - return NULL; - } - d->sysminor = sysminor; - d->aoemajor = AOEMAJOR(sysminor); - d->aoeminor = AOEMINOR(sysminor); - } - + if (d) + goto out; + d = kcalloc(1, sizeof *d, GFP_ATOMIC); + if (!d) + goto out; + INIT_WORK(&d->work, aoecmd_sleepwork); + spin_lock_init(&d->lock); + init_timer(&d->timer); + d->timer.data = (ulong) d; + d->timer.function = dummy_timer; + d->timer.expires = jiffies + HZ; + add_timer(&d->timer); + d->bufpool = NULL; /* defer to aoeblk_gdalloc */ + d->tgt = d->targets; + INIT_LIST_HEAD(&d->bufq); + d->sysminor = sysminor; + d->aoemajor = AOEMAJOR(sysminor); + d->aoeminor = AOEMINOR(sysminor); + d->mintimer = MINTIMER; + d->next = devlist; + devlist = d; + out: spin_unlock_irqrestore(&devlist_lock, flags); return d; } static void -aoedev_freedev(struct aoedev *d) +freetgt(struct aoedev *d, struct aoetgt *t) { struct frame *f, *e; - if (d->gd) { - aoedisk_rm_sysfs(d); - del_gendisk(d->gd); - put_disk(d->gd); - } - f = d->frames; - e = f + d->nframes; - for (; f<e; f++) { - skb_shinfo(f->skb)->nr_frags = 0; - dev_kfree_skb(f->skb); - } - kfree(d->frames); - if (d->bufpool) - mempool_destroy(d->bufpool); - kfree(d); + f = t->frames; + e = f + t->nframes; + for (; f < e; f++) + skbfree(f->skb); + kfree(t->frames); + kfree(t); } void @@ -214,7 +291,5 @@ aoedev_exit(void) int __init aoedev_init(void) { - spin_lock_init(&devlist_lock); return 0; } - diff --git a/drivers/block/aoe/aoemain.c b/drivers/block/aoe/aoemain.c index a04b7d613299..7b15a5e9cec0 100644 --- a/drivers/block/aoe/aoemain.c +++ b/drivers/block/aoe/aoemain.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */ /* * aoemain.c * Module initialization routines, discover timer diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c index 4e6deb7f5c24..8460ef736d56 100644 --- a/drivers/block/aoe/aoenet.c +++ b/drivers/block/aoe/aoenet.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */ /* * aoenet.c * Ethernet portion of AoE driver @@ -83,7 +83,7 @@ set_aoe_iflist(const char __user *user_str, size_t size) return 0; } -u64 +unsigned long long mac_addr(char addr[6]) { __be64 n = 0; @@ -91,7 +91,7 @@ mac_addr(char addr[6]) memcpy(p + 2, addr, 6); /* (sizeof addr != 6) */ - return __be64_to_cpu(n); + return (unsigned long long) __be64_to_cpu(n); } void @@ -137,9 +137,12 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, if (n > NECODES) n = 0; if (net_ratelimit()) - printk(KERN_ERR "aoe: error packet from %d.%d; ecode=%d '%s'\n", - be16_to_cpu(get_unaligned(&h->major)), h->minor, - h->err, aoe_errlist[n]); + printk(KERN_ERR + "%s%d.%d@%s; ecode=%d '%s'\n", + "aoe: error packet from ", + be16_to_cpu(get_unaligned(&h->major)), + h->minor, skb->dev->name, + h->err, aoe_errlist[n]); goto exit; } diff --git a/drivers/block/brd.c b/drivers/block/brd.c new file mode 100644 index 000000000000..85364804364f --- /dev/null +++ b/drivers/block/brd.c @@ -0,0 +1,583 @@ +/* + * Ram backed block device driver. + * + * Copyright (C) 2007 Nick Piggin + * Copyright (C) 2007 Novell Inc. + * + * Parts derived from drivers/block/rd.c, and drivers/block/loop.c, copyright + * of their respective owners. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/major.h> +#include <linux/blkdev.h> +#include <linux/bio.h> +#include <linux/highmem.h> +#include <linux/gfp.h> +#include <linux/radix-tree.h> +#include <linux/buffer_head.h> /* invalidate_bh_lrus() */ + +#include <asm/uaccess.h> + +#define SECTOR_SHIFT 9 +#define PAGE_SECTORS_SHIFT (PAGE_SHIFT - SECTOR_SHIFT) +#define PAGE_SECTORS (1 << PAGE_SECTORS_SHIFT) + +/* + * Each block ramdisk device has a radix_tree brd_pages of pages that stores + * the pages containing the block device's contents. A brd page's ->index is + * its offset in PAGE_SIZE units. This is similar to, but in no way connected + * with, the kernel's pagecache or buffer cache (which sit above our block + * device). + */ +struct brd_device { + int brd_number; + int brd_refcnt; + loff_t brd_offset; + loff_t brd_sizelimit; + unsigned brd_blocksize; + + struct request_queue *brd_queue; + struct gendisk *brd_disk; + struct list_head brd_list; + + /* + * Backing store of pages and lock to protect it. This is the contents + * of the block device. + */ + spinlock_t brd_lock; + struct radix_tree_root brd_pages; +}; + +/* + * Look up and return a brd's page for a given sector. + */ +static struct page *brd_lookup_page(struct brd_device *brd, sector_t sector) +{ + pgoff_t idx; + struct page *page; + + /* + * The page lifetime is protected by the fact that we have opened the + * device node -- brd pages will never be deleted under us, so we + * don't need any further locking or refcounting. + * + * This is strictly true for the radix-tree nodes as well (ie. we + * don't actually need the rcu_read_lock()), however that is not a + * documented feature of the radix-tree API so it is better to be + * safe here (we don't have total exclusion from radix tree updates + * here, only deletes). + */ + rcu_read_lock(); + idx = sector >> PAGE_SECTORS_SHIFT; /* sector to page index */ + page = radix_tree_lookup(&brd->brd_pages, idx); + rcu_read_unlock(); + + BUG_ON(page && page->index != idx); + + return page; +} + +/* + * Look up and return a brd's page for a given sector. + * If one does not exist, allocate an empty page, and insert that. Then + * return it. + */ +static struct page *brd_insert_page(struct brd_device *brd, sector_t sector) +{ + pgoff_t idx; + struct page *page; + gfp_t gfp_flags; + + page = brd_lookup_page(brd, sector); + if (page) + return page; + + /* + * Must use NOIO because we don't want to recurse back into the + * block or filesystem layers from page reclaim. + * + * Cannot support XIP and highmem, because our ->direct_access + * routine for XIP must return memory that is always addressable. + * If XIP was reworked to use pfns and kmap throughout, this + * restriction might be able to be lifted. + */ + gfp_flags = GFP_NOIO | __GFP_ZERO; +#ifndef CONFIG_BLK_DEV_XIP + gfp_flags |= __GFP_HIGHMEM; +#endif + page = alloc_page(GFP_NOIO | __GFP_HIGHMEM | __GFP_ZERO); + if (!page) + return NULL; + + if (radix_tree_preload(GFP_NOIO)) { + __free_page(page); + return NULL; + } + + spin_lock(&brd->brd_lock); + idx = sector >> PAGE_SECTORS_SHIFT; + if (radix_tree_insert(&brd->brd_pages, idx, page)) { + __free_page(page); + page = radix_tree_lookup(&brd->brd_pages, idx); + BUG_ON(!page); + BUG_ON(page->index != idx); + } else + page->index = idx; + spin_unlock(&brd->brd_lock); + + radix_tree_preload_end(); + + return page; +} + +/* + * Free all backing store pages and radix tree. This must only be called when + * there are no other users of the device. + */ +#define FREE_BATCH 16 +static void brd_free_pages(struct brd_device *brd) +{ + unsigned long pos = 0; + struct page *pages[FREE_BATCH]; + int nr_pages; + + do { + int i; + + nr_pages = radix_tree_gang_lookup(&brd->brd_pages, + (void **)pages, pos, FREE_BATCH); + + for (i = 0; i < nr_pages; i++) { + void *ret; + + BUG_ON(pages[i]->index < pos); + pos = pages[i]->index; + ret = radix_tree_delete(&brd->brd_pages, pos); + BUG_ON(!ret || ret != pages[i]); + __free_page(pages[i]); + } + + pos++; + + /* + * This assumes radix_tree_gang_lookup always returns as + * many pages as possible. If the radix-tree code changes, + * so will this have to. + */ + } while (nr_pages == FREE_BATCH); +} + +/* + * copy_to_brd_setup must be called before copy_to_brd. It may sleep. + */ +static int copy_to_brd_setup(struct brd_device *brd, sector_t sector, size_t n) +{ + unsigned int offset = (sector & (PAGE_SECTORS-1)) << SECTOR_SHIFT; + size_t copy; + + copy = min_t(size_t, n, PAGE_SIZE - offset); + if (!brd_insert_page(brd, sector)) + return -ENOMEM; + if (copy < n) { + sector += copy >> SECTOR_SHIFT; + if (!brd_insert_page(brd, sector)) + return -ENOMEM; + } + return 0; +} + +/* + * Copy n bytes from src to the brd starting at sector. Does not sleep. + */ +static void copy_to_brd(struct brd_device *brd, const void *src, + sector_t sector, size_t n) +{ + struct page *page; + void *dst; + unsigned int offset = (sector & (PAGE_SECTORS-1)) << SECTOR_SHIFT; + size_t copy; + + copy = min_t(size_t, n, PAGE_SIZE - offset); + page = brd_lookup_page(brd, sector); + BUG_ON(!page); + + dst = kmap_atomic(page, KM_USER1); + memcpy(dst + offset, src, copy); + kunmap_atomic(dst, KM_USER1); + + if (copy < n) { + src += copy; + sector += copy >> SECTOR_SHIFT; + copy = n - copy; + page = brd_lookup_page(brd, sector); + BUG_ON(!page); + + dst = kmap_atomic(page, KM_USER1); + memcpy(dst, src, copy); + kunmap_atomic(dst, KM_USER1); + } +} + +/* + * Copy n bytes to dst from the brd starting at sector. Does not sleep. + */ +static void copy_from_brd(void *dst, struct brd_device *brd, + sector_t sector, size_t n) +{ + struct page *page; + void *src; + unsigned int offset = (sector & (PAGE_SECTORS-1)) << SECTOR_SHIFT; + size_t copy; + + copy = min_t(size_t, n, PAGE_SIZE - offset); + page = brd_lookup_page(brd, sector); + if (page) { + src = kmap_atomic(page, KM_USER1); + memcpy(dst, src + offset, copy); + kunmap_atomic(src, KM_USER1); + } else + memset(dst, 0, copy); + + if (copy < n) { + dst += copy; + sector += copy >> SECTOR_SHIFT; + copy = n - copy; + page = brd_lookup_page(brd, sector); + if (page) { + src = kmap_atomic(page, KM_USER1); + memcpy(dst, src, copy); + kunmap_atomic(src, KM_USER1); + } else + memset(dst, 0, copy); + } +} + +/* + * Process a single bvec of a bio. + */ +static int brd_do_bvec(struct brd_device *brd, struct page *page, + unsigned int len, unsigned int off, int rw, + sector_t sector) +{ + void *mem; + int err = 0; + + if (rw != READ) { + err = copy_to_brd_setup(brd, sector, len); + if (err) + goto out; + } + + mem = kmap_atomic(page, KM_USER0); + if (rw == READ) { + copy_from_brd(mem + off, brd, sector, len); + flush_dcache_page(page); + } else + copy_to_brd(brd, mem + off, sector, len); + kunmap_atomic(mem, KM_USER0); + +out: + return err; +} + +static int brd_make_request(struct request_queue *q, struct bio *bio) +{ + struct block_device *bdev = bio->bi_bdev; + struct brd_device *brd = bdev->bd_disk->private_data; + int rw; + struct bio_vec *bvec; + sector_t sector; + int i; + int err = -EIO; + + sector = bio->bi_sector; + if (sector + (bio->bi_size >> SECTOR_SHIFT) > + get_capacity(bdev->bd_disk)) + goto out; + + rw = bio_rw(bio); + if (rw == READA) + rw = READ; + + bio_for_each_segment(bvec, bio, i) { + unsigned int len = bvec->bv_len; + err = brd_do_bvec(brd, bvec->bv_page, len, + bvec->bv_offset, rw, sector); + if (err) + break; + sector += len >> SECTOR_SHIFT; + } + +out: + bio_endio(bio, err); + + return 0; +} + +#ifdef CONFIG_BLK_DEV_XIP +static int brd_direct_access (struct block_device *bdev, sector_t sector, + unsigned long *data) +{ + struct brd_device *brd = bdev->bd_disk->private_data; + struct page *page; + + if (!brd) + return -ENODEV; + if (sector & (PAGE_SECTORS-1)) + return -EINVAL; + if (sector + PAGE_SECTORS > get_capacity(bdev->bd_disk)) + return -ERANGE; + page = brd_insert_page(brd, sector); + if (!page) + return -ENOMEM; + *data = (unsigned long)page_address(page); + + return 0; +} +#endif + +static int brd_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int error; + struct block_device *bdev = inode->i_bdev; + struct brd_device *brd = bdev->bd_disk->private_data; + + if (cmd != BLKFLSBUF) + return -ENOTTY; + + /* + * ram device BLKFLSBUF has special semantics, we want to actually + * release and destroy the ramdisk data. + */ + mutex_lock(&bdev->bd_mutex); + error = -EBUSY; + if (bdev->bd_openers <= 1) { + /* + * Invalidate the cache first, so it isn't written + * back to the device. + * + * Another thread might instantiate more buffercache here, + * but there is not much we can do to close that race. + */ + invalidate_bh_lrus(); + truncate_inode_pages(bdev->bd_inode->i_mapping, 0); + brd_free_pages(brd); + error = 0; + } + mutex_unlock(&bdev->bd_mutex); + + return error; +} + +static struct block_device_operations brd_fops = { + .owner = THIS_MODULE, + .ioctl = brd_ioctl, +#ifdef CONFIG_BLK_DEV_XIP + .direct_access = brd_direct_access, +#endif +}; + +/* + * And now the modules code and kernel interface. + */ +static int rd_nr; +int rd_size = CONFIG_BLK_DEV_RAM_SIZE; +module_param(rd_nr, int, 0); +MODULE_PARM_DESC(rd_nr, "Maximum number of brd devices"); +module_param(rd_size, int, 0); +MODULE_PARM_DESC(rd_size, "Size of each RAM disk in kbytes."); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_BLOCKDEV_MAJOR(RAMDISK_MAJOR); + +#ifndef MODULE +/* Legacy boot options - nonmodular */ +static int __init ramdisk_size(char *str) +{ + rd_size = simple_strtol(str, NULL, 0); + return 1; +} +static int __init ramdisk_size2(char *str) +{ + return ramdisk_size(str); +} +__setup("ramdisk=", ramdisk_size); +__setup("ramdisk_size=", ramdisk_size2); +#endif + +/* + * The device scheme is derived from loop.c. Keep them in synch where possible + * (should share code eventually). + */ +static LIST_HEAD(brd_devices); +static DEFINE_MUTEX(brd_devices_mutex); + +static struct brd_device *brd_alloc(int i) +{ + struct brd_device *brd; + struct gendisk *disk; + + brd = kzalloc(sizeof(*brd), GFP_KERNEL); + if (!brd) + goto out; + brd->brd_number = i; + spin_lock_init(&brd->brd_lock); + INIT_RADIX_TREE(&brd->brd_pages, GFP_ATOMIC); + + brd->brd_queue = blk_alloc_queue(GFP_KERNEL); + if (!brd->brd_queue) + goto out_free_dev; + blk_queue_make_request(brd->brd_queue, brd_make_request); + blk_queue_max_sectors(brd->brd_queue, 1024); + blk_queue_bounce_limit(brd->brd_queue, BLK_BOUNCE_ANY); + + disk = brd->brd_disk = alloc_disk(1); + if (!disk) + goto out_free_queue; + disk->major = RAMDISK_MAJOR; + disk->first_minor = i; + disk->fops = &brd_fops; + disk->private_data = brd; + disk->queue = brd->brd_queue; + sprintf(disk->disk_name, "ram%d", i); + set_capacity(disk, rd_size * 2); + + return brd; + +out_free_queue: + blk_cleanup_queue(brd->brd_queue); +out_free_dev: + kfree(brd); +out: + return NULL; +} + +static void brd_free(struct brd_device *brd) +{ + put_disk(brd->brd_disk); + blk_cleanup_queue(brd->brd_queue); + brd_free_pages(brd); + kfree(brd); +} + +static struct brd_device *brd_init_one(int i) +{ + struct brd_device *brd; + + list_for_each_entry(brd, &brd_devices, brd_list) { + if (brd->brd_number == i) + goto out; + } + + brd = brd_alloc(i); + if (brd) { + add_disk(brd->brd_disk); + list_add_tail(&brd->brd_list, &brd_devices); + } +out: + return brd; +} + +static void brd_del_one(struct brd_device *brd) +{ + list_del(&brd->brd_list); + del_gendisk(brd->brd_disk); + brd_free(brd); +} + +static struct kobject *brd_probe(dev_t dev, int *part, void *data) +{ + struct brd_device *brd; + struct kobject *kobj; + + mutex_lock(&brd_devices_mutex); + brd = brd_init_one(dev & MINORMASK); + kobj = brd ? get_disk(brd->brd_disk) : ERR_PTR(-ENOMEM); + mutex_unlock(&brd_devices_mutex); + + *part = 0; + return kobj; +} + +static int __init brd_init(void) +{ + int i, nr; + unsigned long range; + struct brd_device *brd, *next; + + /* + * brd module now has a feature to instantiate underlying device + * structure on-demand, provided that there is an access dev node. + * However, this will not work well with user space tool that doesn't + * know about such "feature". In order to not break any existing + * tool, we do the following: + * + * (1) if rd_nr is specified, create that many upfront, and this + * also becomes a hard limit. + * (2) if rd_nr is not specified, create 1 rd device on module + * load, user can further extend brd device by create dev node + * themselves and have kernel automatically instantiate actual + * device on-demand. + */ + if (rd_nr > 1UL << MINORBITS) + return -EINVAL; + + if (rd_nr) { + nr = rd_nr; + range = rd_nr; + } else { + nr = CONFIG_BLK_DEV_RAM_COUNT; + range = 1UL << MINORBITS; + } + + if (register_blkdev(RAMDISK_MAJOR, "ramdisk")) + return -EIO; + + for (i = 0; i < nr; i++) { + brd = brd_alloc(i); + if (!brd) + goto out_free; + list_add_tail(&brd->brd_list, &brd_devices); + } + + /* point of no return */ + + list_for_each_entry(brd, &brd_devices, brd_list) + add_disk(brd->brd_disk); + + blk_register_region(MKDEV(RAMDISK_MAJOR, 0), range, + THIS_MODULE, brd_probe, NULL, NULL); + + printk(KERN_INFO "brd: module loaded\n"); + return 0; + +out_free: + list_for_each_entry_safe(brd, next, &brd_devices, brd_list) { + list_del(&brd->brd_list); + brd_free(brd); + } + + unregister_blkdev(RAMDISK_MAJOR, "brd"); + return -ENOMEM; +} + +static void __exit brd_exit(void) +{ + unsigned long range; + struct brd_device *brd, *next; + + range = rd_nr ? rd_nr : 1UL << MINORBITS; + + list_for_each_entry_safe(brd, next, &brd_devices, brd_list) + brd_del_one(brd); + + blk_unregister_region(MKDEV(RAMDISK_MAJOR, 0), range); + unregister_blkdev(RAMDISK_MAJOR, "ramdisk"); +} + +module_init(brd_init); +module_exit(brd_exit); + diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index ae3106045ee5..018753c59b8e 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -54,7 +54,7 @@ static unsigned int debugflags; #endif /* NDEBUG */ static unsigned int nbds_max = 16; -static struct nbd_device nbd_dev[MAX_NBD]; +static struct nbd_device *nbd_dev; /* * Use just one lock (or at most 1 per NIC). Two arguments for this: @@ -649,11 +649,9 @@ static int __init nbd_init(void) BUILD_BUG_ON(sizeof(struct nbd_request) != 28); - if (nbds_max > MAX_NBD) { - printk(KERN_CRIT "nbd: cannot allocate more than %u nbds; %u requested.\n", MAX_NBD, - nbds_max); - return -EINVAL; - } + nbd_dev = kcalloc(nbds_max, sizeof(*nbd_dev), GFP_KERNEL); + if (!nbd_dev) + return -ENOMEM; for (i = 0; i < nbds_max; i++) { struct gendisk *disk = alloc_disk(1); diff --git a/drivers/block/rd.c b/drivers/block/rd.c deleted file mode 100644 index 06e23be70904..000000000000 --- a/drivers/block/rd.c +++ /dev/null @@ -1,537 +0,0 @@ -/* - * ramdisk.c - Multiple RAM disk driver - gzip-loading version - v. 0.8 beta. - * - * (C) Chad Page, Theodore Ts'o, et. al, 1995. - * - * This RAM disk is designed to have filesystems created on it and mounted - * just like a regular floppy disk. - * - * It also does something suggested by Linus: use the buffer cache as the - * RAM disk data. This makes it possible to dynamically allocate the RAM disk - * buffer - with some consequences I have to deal with as I write this. - * - * This code is based on the original ramdisk.c, written mostly by - * Theodore Ts'o (TYT) in 1991. The code was largely rewritten by - * Chad Page to use the buffer cache to store the RAM disk data in - * 1995; Theodore then took over the driver again, and cleaned it up - * for inclusion in the mainline kernel. - * - * The original CRAMDISK code was written by Richard Lyons, and - * adapted by Chad Page to use the new RAM disk interface. Theodore - * Ts'o rewrote it so that both the compressed RAM disk loader and the - * kernel decompressor uses the same inflate.c codebase. The RAM disk - * loader now also loads into a dynamic (buffer cache based) RAM disk, - * not the old static RAM disk. Support for the old static RAM disk has - * been completely removed. - * - * Loadable module support added by Tom Dyas. - * - * Further cleanups by Chad Page (page0588@sundance.sjsu.edu): - * Cosmetic changes in #ifdef MODULE, code movement, etc. - * When the RAM disk module is removed, free the protected buffers - * Default RAM disk size changed to 2.88 MB - * - * Added initrd: Werner Almesberger & Hans Lermen, Feb '96 - * - * 4/25/96 : Made RAM disk size a parameter (default is now 4 MB) - * - Chad Page - * - * Add support for fs images split across >1 disk, Paul Gortmaker, Mar '98 - * - * Make block size and block size shift for RAM disks a global macro - * and set blk_size for -ENOSPC, Werner Fink <werner@suse.de>, Apr '99 - */ - -#include <linux/string.h> -#include <linux/slab.h> -#include <asm/atomic.h> -#include <linux/bio.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/pagemap.h> -#include <linux/blkdev.h> -#include <linux/genhd.h> -#include <linux/buffer_head.h> /* for invalidate_bdev() */ -#include <linux/backing-dev.h> -#include <linux/blkpg.h> -#include <linux/writeback.h> -#include <linux/log2.h> - -#include <asm/uaccess.h> - -/* Various static variables go here. Most are used only in the RAM disk code. - */ - -static struct gendisk *rd_disks[CONFIG_BLK_DEV_RAM_COUNT]; -static struct block_device *rd_bdev[CONFIG_BLK_DEV_RAM_COUNT];/* Protected device data */ -static struct request_queue *rd_queue[CONFIG_BLK_DEV_RAM_COUNT]; - -/* - * Parameters for the boot-loading of the RAM disk. These are set by - * init/main.c (from arguments to the kernel command line) or from the - * architecture-specific setup routine (from the stored boot sector - * information). - */ -int rd_size = CONFIG_BLK_DEV_RAM_SIZE; /* Size of the RAM disks */ -/* - * It would be very desirable to have a soft-blocksize (that in the case - * of the ramdisk driver is also the hardblocksize ;) of PAGE_SIZE because - * doing that we'll achieve a far better MM footprint. Using a rd_blocksize of - * BLOCK_SIZE in the worst case we'll make PAGE_SIZE/BLOCK_SIZE buffer-pages - * unfreeable. With a rd_blocksize of PAGE_SIZE instead we are sure that only - * 1 page will be protected. Depending on the size of the ramdisk you - * may want to change the ramdisk blocksize to achieve a better or worse MM - * behaviour. The default is still BLOCK_SIZE (needed by rd_load_image that - * supposes the filesystem in the image uses a BLOCK_SIZE blocksize). - */ -static int rd_blocksize = CONFIG_BLK_DEV_RAM_BLOCKSIZE; - -/* - * Copyright (C) 2000 Linus Torvalds. - * 2000 Transmeta Corp. - * aops copied from ramfs. - */ - -/* - * If a ramdisk page has buffers, some may be uptodate and some may be not. - * To bring the page uptodate we zero out the non-uptodate buffers. The - * page must be locked. - */ -static void make_page_uptodate(struct page *page) -{ - if (page_has_buffers(page)) { - struct buffer_head *bh = page_buffers(page); - struct buffer_head *head = bh; - - do { - if (!buffer_uptodate(bh)) { - memset(bh->b_data, 0, bh->b_size); - /* - * akpm: I'm totally undecided about this. The - * buffer has just been magically brought "up to - * date", but nobody should want to be reading - * it anyway, because it hasn't been used for - * anything yet. It is still in a "not read - * from disk yet" state. - * - * But non-uptodate buffers against an uptodate - * page are against the rules. So do it anyway. - */ - set_buffer_uptodate(bh); - } - } while ((bh = bh->b_this_page) != head); - } else { - memset(page_address(page), 0, PAGE_CACHE_SIZE); - } - flush_dcache_page(page); - SetPageUptodate(page); -} - -static int ramdisk_readpage(struct file *file, struct page *page) -{ - if (!PageUptodate(page)) - make_page_uptodate(page); - unlock_page(page); - return 0; -} - -static int ramdisk_prepare_write(struct file *file, struct page *page, - unsigned offset, unsigned to) -{ - if (!PageUptodate(page)) - make_page_uptodate(page); - return 0; -} - -static int ramdisk_commit_write(struct file *file, struct page *page, - unsigned offset, unsigned to) -{ - set_page_dirty(page); - return 0; -} - -/* - * ->writepage to the blockdev's mapping has to redirty the page so that the - * VM doesn't go and steal it. We return AOP_WRITEPAGE_ACTIVATE so that the VM - * won't try to (pointlessly) write the page again for a while. - * - * Really, these pages should not be on the LRU at all. - */ -static int ramdisk_writepage(struct page *page, struct writeback_control *wbc) -{ - if (!PageUptodate(page)) - make_page_uptodate(page); - SetPageDirty(page); - if (wbc->for_reclaim) - return AOP_WRITEPAGE_ACTIVATE; - unlock_page(page); - return 0; -} - -/* - * This is a little speedup thing: short-circuit attempts to write back the - * ramdisk blockdev inode to its non-existent backing store. - */ -static int ramdisk_writepages(struct address_space *mapping, - struct writeback_control *wbc) -{ - return 0; -} - -/* - * ramdisk blockdev pages have their own ->set_page_dirty() because we don't - * want them to contribute to dirty memory accounting. - */ -static int ramdisk_set_page_dirty(struct page *page) -{ - if (!TestSetPageDirty(page)) - return 1; - return 0; -} - -/* - * releasepage is called by pagevec_strip/try_to_release_page if - * buffers_heads_over_limit is true. Without a releasepage function - * try_to_free_buffers is called instead. That can unset the dirty - * bit of our ram disk pages, which will be eventually freed, even - * if the page is still in use. - */ -static int ramdisk_releasepage(struct page *page, gfp_t dummy) -{ - return 0; -} - -static const struct address_space_operations ramdisk_aops = { - .readpage = ramdisk_readpage, - .prepare_write = ramdisk_prepare_write, - .commit_write = ramdisk_commit_write, - .writepage = ramdisk_writepage, - .set_page_dirty = ramdisk_set_page_dirty, - .writepages = ramdisk_writepages, - .releasepage = ramdisk_releasepage, -}; - -static int rd_blkdev_pagecache_IO(int rw, struct bio_vec *vec, sector_t sector, - struct address_space *mapping) -{ - pgoff_t index = sector >> (PAGE_CACHE_SHIFT - 9); - unsigned int vec_offset = vec->bv_offset; - int offset = (sector << 9) & ~PAGE_CACHE_MASK; - int size = vec->bv_len; - int err = 0; - - do { - int count; - struct page *page; - char *src; - char *dst; - - count = PAGE_CACHE_SIZE - offset; - if (count > size) - count = size; - size -= count; - - page = grab_cache_page(mapping, index); - if (!page) { - err = -ENOMEM; - goto out; - } - - if (!PageUptodate(page)) - make_page_uptodate(page); - - index++; - - if (rw == READ) { - src = kmap_atomic(page, KM_USER0) + offset; - dst = kmap_atomic(vec->bv_page, KM_USER1) + vec_offset; - } else { - src = kmap_atomic(vec->bv_page, KM_USER0) + vec_offset; - dst = kmap_atomic(page, KM_USER1) + offset; - } - offset = 0; - vec_offset += count; - - memcpy(dst, src, count); - - kunmap_atomic(src, KM_USER0); - kunmap_atomic(dst, KM_USER1); - - if (rw == READ) - flush_dcache_page(vec->bv_page); - else - set_page_dirty(page); - unlock_page(page); - put_page(page); - } while (size); - - out: - return err; -} - -/* - * Basically, my strategy here is to set up a buffer-head which can't be - * deleted, and make that my Ramdisk. If the request is outside of the - * allocated size, we must get rid of it... - * - * 19-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Added devfs support - * - */ -static int rd_make_request(struct request_queue *q, struct bio *bio) -{ - struct block_device *bdev = bio->bi_bdev; - struct address_space * mapping = bdev->bd_inode->i_mapping; - sector_t sector = bio->bi_sector; - unsigned long len = bio->bi_size >> 9; - int rw = bio_data_dir(bio); - struct bio_vec *bvec; - int ret = 0, i; - - if (sector + len > get_capacity(bdev->bd_disk)) - goto fail; - - if (rw==READA) - rw=READ; - - bio_for_each_segment(bvec, bio, i) { - ret |= rd_blkdev_pagecache_IO(rw, bvec, sector, mapping); - sector += bvec->bv_len >> 9; - } - if (ret) - goto fail; - - bio_endio(bio, 0); - return 0; -fail: - bio_io_error(bio); - return 0; -} - -static int rd_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int error; - struct block_device *bdev = inode->i_bdev; - - if (cmd != BLKFLSBUF) - return -ENOTTY; - - /* - * special: we want to release the ramdisk memory, it's not like with - * the other blockdevices where this ioctl only flushes away the buffer - * cache - */ - error = -EBUSY; - mutex_lock(&bdev->bd_mutex); - if (bdev->bd_openers <= 2) { - truncate_inode_pages(bdev->bd_inode->i_mapping, 0); - error = 0; - } - mutex_unlock(&bdev->bd_mutex); - return error; -} - -/* - * This is the backing_dev_info for the blockdev inode itself. It doesn't need - * writeback and it does not contribute to dirty memory accounting. - */ -static struct backing_dev_info rd_backing_dev_info = { - .ra_pages = 0, /* No readahead */ - .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK | BDI_CAP_MAP_COPY, - .unplug_io_fn = default_unplug_io_fn, -}; - -/* - * This is the backing_dev_info for the files which live atop the ramdisk - * "device". These files do need writeback and they do contribute to dirty - * memory accounting. - */ -static struct backing_dev_info rd_file_backing_dev_info = { - .ra_pages = 0, /* No readahead */ - .capabilities = BDI_CAP_MAP_COPY, /* Does contribute to dirty memory */ - .unplug_io_fn = default_unplug_io_fn, -}; - -static int rd_open(struct inode *inode, struct file *filp) -{ - unsigned unit = iminor(inode); - - if (rd_bdev[unit] == NULL) { - struct block_device *bdev = inode->i_bdev; - struct address_space *mapping; - unsigned bsize; - gfp_t gfp_mask; - - inode = igrab(bdev->bd_inode); - rd_bdev[unit] = bdev; - bdev->bd_openers++; - bsize = bdev_hardsect_size(bdev); - bdev->bd_block_size = bsize; - inode->i_blkbits = blksize_bits(bsize); - inode->i_size = get_capacity(bdev->bd_disk)<<9; - - mapping = inode->i_mapping; - mapping->a_ops = &ramdisk_aops; - mapping->backing_dev_info = &rd_backing_dev_info; - bdev->bd_inode_backing_dev_info = &rd_file_backing_dev_info; - - /* - * Deep badness. rd_blkdev_pagecache_IO() needs to allocate - * pagecache pages within a request_fn. We cannot recur back - * into the filesystem which is mounted atop the ramdisk, because - * that would deadlock on fs locks. And we really don't want - * to reenter rd_blkdev_pagecache_IO when we're already within - * that function. - * - * So we turn off __GFP_FS and __GFP_IO. - * - * And to give this thing a hope of working, turn on __GFP_HIGH. - * Hopefully, there's enough regular memory allocation going on - * for the page allocator emergency pools to keep the ramdisk - * driver happy. - */ - gfp_mask = mapping_gfp_mask(mapping); - gfp_mask &= ~(__GFP_FS|__GFP_IO); - gfp_mask |= __GFP_HIGH; - mapping_set_gfp_mask(mapping, gfp_mask); - } - - return 0; -} - -static struct block_device_operations rd_bd_op = { - .owner = THIS_MODULE, - .open = rd_open, - .ioctl = rd_ioctl, -}; - -/* - * Before freeing the module, invalidate all of the protected buffers! - */ -static void __exit rd_cleanup(void) -{ - int i; - - for (i = 0; i < CONFIG_BLK_DEV_RAM_COUNT; i++) { - struct block_device *bdev = rd_bdev[i]; - rd_bdev[i] = NULL; - if (bdev) { - invalidate_bdev(bdev); - blkdev_put(bdev); - } - del_gendisk(rd_disks[i]); - put_disk(rd_disks[i]); - blk_cleanup_queue(rd_queue[i]); - } - unregister_blkdev(RAMDISK_MAJOR, "ramdisk"); - - bdi_destroy(&rd_file_backing_dev_info); - bdi_destroy(&rd_backing_dev_info); -} - -/* - * This is the registration and initialization section of the RAM disk driver - */ -static int __init rd_init(void) -{ - int i; - int err; - - err = bdi_init(&rd_backing_dev_info); - if (err) - goto out2; - - err = bdi_init(&rd_file_backing_dev_info); - if (err) { - bdi_destroy(&rd_backing_dev_info); - goto out2; - } - - err = -ENOMEM; - - if (rd_blocksize > PAGE_SIZE || rd_blocksize < 512 || - !is_power_of_2(rd_blocksize)) { - printk("RAMDISK: wrong blocksize %d, reverting to defaults\n", - rd_blocksize); - rd_blocksize = BLOCK_SIZE; - } - - for (i = 0; i < CONFIG_BLK_DEV_RAM_COUNT; i++) { - rd_disks[i] = alloc_disk(1); - if (!rd_disks[i]) - goto out; - - rd_queue[i] = blk_alloc_queue(GFP_KERNEL); - if (!rd_queue[i]) { - put_disk(rd_disks[i]); - goto out; - } - } - - if (register_blkdev(RAMDISK_MAJOR, "ramdisk")) { - err = -EIO; - goto out; - } - - for (i = 0; i < CONFIG_BLK_DEV_RAM_COUNT; i++) { - struct gendisk *disk = rd_disks[i]; - - blk_queue_make_request(rd_queue[i], &rd_make_request); - blk_queue_hardsect_size(rd_queue[i], rd_blocksize); - - /* rd_size is given in kB */ - disk->major = RAMDISK_MAJOR; - disk->first_minor = i; - disk->fops = &rd_bd_op; - disk->queue = rd_queue[i]; - disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO; - sprintf(disk->disk_name, "ram%d", i); - set_capacity(disk, rd_size * 2); - add_disk(rd_disks[i]); - } - - /* rd_size is given in kB */ - printk("RAMDISK driver initialized: " - "%d RAM disks of %dK size %d blocksize\n", - CONFIG_BLK_DEV_RAM_COUNT, rd_size, rd_blocksize); - - return 0; -out: - while (i--) { - put_disk(rd_disks[i]); - blk_cleanup_queue(rd_queue[i]); - } - bdi_destroy(&rd_backing_dev_info); - bdi_destroy(&rd_file_backing_dev_info); -out2: - return err; -} - -module_init(rd_init); -module_exit(rd_cleanup); - -/* options - nonmodular */ -#ifndef MODULE -static int __init ramdisk_size(char *str) -{ - rd_size = simple_strtol(str,NULL,0); - return 1; -} -static int __init ramdisk_blocksize(char *str) -{ - rd_blocksize = simple_strtol(str,NULL,0); - return 1; -} -__setup("ramdisk_size=", ramdisk_size); -__setup("ramdisk_blocksize=", ramdisk_blocksize); -#endif - -/* options - modular */ -module_param(rd_size, int, 0); -MODULE_PARM_DESC(rd_size, "Size of each RAM disk in kbytes."); -module_param(rd_blocksize, int, 0); -MODULE_PARM_DESC(rd_blocksize, "Blocksize of each RAM disk in bytes."); -MODULE_ALIAS_BLOCKDEV_MAJOR(RAMDISK_MAJOR); - -MODULE_LICENSE("GPL"); diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c index 1f0b752e5de1..a7c4990b5b6b 100644 --- a/drivers/char/applicom.c +++ b/drivers/char/applicom.c @@ -57,7 +57,6 @@ #define PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN 0x0002 #define PCI_DEVICE_ID_APPLICOM_PCI2000PFB 0x0003 #endif -#define MAX_PCI_DEVICE_NUM 3 static char *applicom_pci_devnames[] = { "PCI board", @@ -66,12 +65,9 @@ static char *applicom_pci_devnames[] = { }; static struct pci_device_id applicom_pci_tbl[] = { - { PCI_VENDOR_ID_APPLICOM, PCI_DEVICE_ID_APPLICOM_PCIGENERIC, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_APPLICOM, PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_APPLICOM, PCI_DEVICE_ID_APPLICOM_PCI2000PFB, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VDEVICE(APPLICOM, PCI_DEVICE_ID_APPLICOM_PCIGENERIC) }, + { PCI_VDEVICE(APPLICOM, PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN) }, + { PCI_VDEVICE(APPLICOM, PCI_DEVICE_ID_APPLICOM_PCI2000PFB) }, { 0 } }; MODULE_DEVICE_TABLE(pci, applicom_pci_tbl); @@ -197,31 +193,29 @@ static int __init applicom_init(void) while ( (dev = pci_get_class(PCI_CLASS_OTHERS << 16, dev))) { - if (dev->vendor != PCI_VENDOR_ID_APPLICOM) - continue; - - if (dev->device > MAX_PCI_DEVICE_NUM || dev->device == 0) + if (!pci_match_id(applicom_pci_tbl, dev)) continue; if (pci_enable_device(dev)) return -EIO; - RamIO = ioremap(dev->resource[0].start, LEN_RAM_IO); + RamIO = ioremap(pci_resource_start(dev, 0), LEN_RAM_IO); if (!RamIO) { printk(KERN_INFO "ac.o: Failed to ioremap PCI memory " "space at 0x%llx\n", - (unsigned long long)dev->resource[0].start); + (unsigned long long)pci_resource_start(dev, 0)); pci_disable_device(dev); return -EIO; } printk(KERN_INFO "Applicom %s found at mem 0x%llx, irq %d\n", applicom_pci_devnames[dev->device-1], - (unsigned long long)dev->resource[0].start, + (unsigned long long)pci_resource_start(dev, 0), dev->irq); - boardno = ac_register_board(dev->resource[0].start, RamIO,0); + boardno = ac_register_board(pci_resource_start(dev, 0), + RamIO, 0); if (!boardno) { printk(KERN_INFO "ac.o: PCI Applicom device doesn't have correct signature.\n"); iounmap(RamIO); diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index 2fc255a21486..64b7b2b18352 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -207,7 +207,7 @@ static int moxa_tiocmget(struct tty_struct *tty, struct file *file); static int moxa_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); static void moxa_poll(unsigned long); -static void moxa_set_tty_param(struct tty_struct *); +static void moxa_set_tty_param(struct tty_struct *, struct ktermios *); static int moxa_block_till_ready(struct tty_struct *, struct file *, struct moxa_port *); static void moxa_setup_empty_event(struct tty_struct *); @@ -500,7 +500,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp) ch->tty = tty; if (!(ch->asyncflags & ASYNC_INITIALIZED)) { ch->statusflags = 0; - moxa_set_tty_param(tty); + moxa_set_tty_param(tty, tty->termios); MoxaPortLineCtrl(ch->port, 1, 1); MoxaPortEnable(ch->port); ch->asyncflags |= ASYNC_INITIALIZED; @@ -803,7 +803,7 @@ static void moxa_set_termios(struct tty_struct *tty, if (ch == NULL) return; - moxa_set_tty_param(tty); + moxa_set_tty_param(tty, old_termios); if (!(old_termios->c_cflag & CLOCAL) && (tty->termios->c_cflag & CLOCAL)) wake_up_interruptible(&ch->open_wait); @@ -903,11 +903,11 @@ static void moxa_poll(unsigned long ignored) /******************************************************************************/ -static void moxa_set_tty_param(struct tty_struct *tty) +static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_termios) { register struct ktermios *ts; struct moxa_port *ch; - int rts, cts, txflow, rxflow, xany; + int rts, cts, txflow, rxflow, xany, baud; ch = (struct moxa_port *) tty->driver_data; ts = tty->termios; @@ -924,8 +924,15 @@ static void moxa_set_tty_param(struct tty_struct *tty) rxflow = 1; if (ts->c_iflag & IXANY) xany = 1; + + /* Clear the features we don't support */ + ts->c_cflag &= ~CMSPAR; MoxaPortFlowCtrl(ch->port, rts, cts, txflow, rxflow, xany); - MoxaPortSetTermio(ch->port, ts, tty_get_baud_rate(tty)); + baud = MoxaPortSetTermio(ch->port, ts, tty_get_baud_rate(tty)); + if (baud == -1) + baud = tty_termios_baud_rate(old_termios); + /* Not put the baud rate into the termios data */ + tty_encode_baud_rate(tty, baud, baud); } static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp, @@ -2065,7 +2072,7 @@ int MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud) if (baud >= 921600L) return (-1); } - MoxaPortSetBaud(port, baud); + baud = MoxaPortSetBaud(port, baud); if (termio->c_iflag & (IXON | IXOFF | IXANY)) { writeb(termio->c_cc[VSTART], ofsAddr + FuncArg); @@ -2074,7 +2081,7 @@ int MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud) moxa_wait_finish(ofsAddr); } - return (0); + return (baud); } int MoxaPortGetLineOut(int port, int *dtrState, int *rtsState) diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 90c3969012a3..46b2a1cc8b54 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -1,6 +1,6 @@ /* * n_tty.c --- implements the N_TTY line discipline. - * + * * This code used to be in tty_io.c, but things are getting hairy * enough that it made sense to split things off. (The N_TTY * processing has changed so much that it's hardly recognizable, @@ -8,19 +8,19 @@ * * Note that the open routine for N_TTY is guaranteed never to return * an error. This is because Linux will fall back to setting a line - * to N_TTY if it can not switch to any other line discipline. + * to N_TTY if it can not switch to any other line discipline. * * Written by Theodore Ts'o, Copyright 1994. - * + * * This file also contains code originally written by Linus Torvalds, * Copyright 1991, 1992, 1993, and by Julian Cowley, Copyright 1994. - * + * * This file may be redistributed under the terms of the GNU General Public * License. * * Reduced memory usage for older ARM systems - Russell King. * - * 2000/01/20 Fixed SMP locking on put_tty_queue using bits of + * 2000/01/20 Fixed SMP locking on put_tty_queue using bits of * the patch by Andrew J. Kroll <ag784@freenet.buffalo.edu> * who actually finally proved there really was a race. * @@ -144,11 +144,11 @@ static void put_tty_queue(unsigned char c, struct tty_struct *tty) * Can sleep, may be called under the atomic_read_lock mutex but * this is not guaranteed. */ - -static void check_unthrottle(struct tty_struct * tty) + +static void check_unthrottle(struct tty_struct *tty) { if (tty->count && - test_and_clear_bit(TTY_THROTTLED, &tty->flags) && + test_and_clear_bit(TTY_THROTTLED, &tty->flags) && tty->driver->unthrottle) tty->driver->unthrottle(tty); } @@ -157,7 +157,7 @@ static void check_unthrottle(struct tty_struct * tty) * reset_buffer_flags - reset buffer state * @tty: terminal to reset * - * Reset the read buffer counters, clear the flags, + * Reset the read buffer counters, clear the flags, * and make sure the driver is unthrottled. Called * from n_tty_open() and n_tty_flush_buffer(). */ @@ -186,12 +186,12 @@ static void reset_buffer_flags(struct tty_struct *tty) * FIXME: tty->ctrl_status is not spinlocked and relies on * lock_kernel() still. */ - -static void n_tty_flush_buffer(struct tty_struct * tty) + +static void n_tty_flush_buffer(struct tty_struct *tty) { /* clear everything and unthrottle the driver */ reset_buffer_flags(tty); - + if (!tty->link) return; @@ -206,9 +206,9 @@ static void n_tty_flush_buffer(struct tty_struct * tty) * @tty: tty device * * Report the number of characters buffered to be delivered to user - * at this instant in time. + * at this instant in time. */ - + static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty) { unsigned long flags; @@ -234,7 +234,7 @@ static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty) * character. We use this to correctly compute the on screen size * of the character when printing */ - + static inline int is_utf8_continuation(unsigned char c) { return (c & 0xc0) == 0x80; @@ -247,7 +247,7 @@ static inline int is_utf8_continuation(unsigned char c) * Returns true if the utf8 character 'c' is a multibyte continuation * character and the terminal is in unicode mode. */ - + static inline int is_continuation(unsigned char c, struct tty_struct *tty) { return I_IUTF8(tty) && is_utf8_continuation(c); @@ -266,7 +266,7 @@ static inline int is_continuation(unsigned char c, struct tty_struct *tty) * Called from both the receive and transmit sides and can be called * re-entrantly. Relies on lock_kernel() still. */ - + static int opost(unsigned char c, struct tty_struct *tty) { int space, spaces; @@ -339,9 +339,9 @@ static int opost(unsigned char c, struct tty_struct *tty) * * Called from write_chan under the tty layer write lock. */ - -static ssize_t opost_block(struct tty_struct * tty, - const unsigned char * buf, unsigned int nr) + +static ssize_t opost_block(struct tty_struct *tty, + const unsigned char *buf, unsigned int nr) { int space; int i; @@ -386,7 +386,7 @@ static ssize_t opost_block(struct tty_struct * tty, break_out: if (tty->driver->flush_chars) tty->driver->flush_chars(tty); - i = tty->driver->write(tty, buf, i); + i = tty->driver->write(tty, buf, i); return i; } @@ -398,7 +398,7 @@ break_out: * * Queue a byte to the driver layer for output */ - + static inline void put_char(unsigned char c, struct tty_struct *tty) { tty->driver->put_char(tty, c); @@ -409,7 +409,7 @@ static inline void put_char(unsigned char c, struct tty_struct *tty) * @c: unicode byte to echo * @tty: terminal device * - * Echo user input back onto the screen. This must be called only when + * Echo user input back onto the screen. This must be called only when * L_ECHO(tty) is true. Called from the driver receive_buf path. */ @@ -441,7 +441,7 @@ static inline void finish_erasing(struct tty_struct *tty) * present in the stream from the driver layer. Handles the complexities * of UTF-8 multibyte symbols. */ - + static void eraser(unsigned char c, struct tty_struct *tty) { enum { ERASE, WERASE, KILL } kill_type; @@ -541,7 +541,7 @@ static void eraser(unsigned char c, struct tty_struct *tty) /* should never happen */ if (tty->column > 0x80000000) - tty->column = 0; + tty->column = 0; /* Now backup to that column. */ while (tty->column > col) { @@ -585,7 +585,7 @@ static void eraser(unsigned char c, struct tty_struct *tty) * settings and character used. Called from the driver receive_buf * path so serialized. */ - + static inline void isig(int sig, struct tty_struct *tty, int flush) { if (tty->pgrp) @@ -606,7 +606,7 @@ static inline void isig(int sig, struct tty_struct *tty, int flush) * * Called from the receive_buf path so single threaded. */ - + static inline void n_tty_receive_break(struct tty_struct *tty) { if (I_IGNBRK(tty)) @@ -635,7 +635,7 @@ static inline void n_tty_receive_break(struct tty_struct *tty) * need locking as num_overrun and overrun_time are function * private. */ - + static inline void n_tty_receive_overrun(struct tty_struct *tty) { char buf[64]; @@ -662,9 +662,8 @@ static inline void n_tty_receive_overrun(struct tty_struct *tty) static inline void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c) { - if (I_IGNPAR(tty)) { + if (I_IGNPAR(tty)) return; - } if (I_PARMRK(tty)) { put_tty_queue('\377', tty); put_tty_queue('\0', tty); @@ -682,7 +681,7 @@ static inline void n_tty_receive_parity_error(struct tty_struct *tty, * @c: character * * Process an individual character of input received from the driver. - * This is serialized with respect to itself by the rules for the + * This is serialized with respect to itself by the rules for the * driver above. */ @@ -694,7 +693,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) put_tty_queue(c, tty); return; } - + if (I_ISTRIP(tty)) c &= 0x7f; if (I_IUCLC(tty) && L_IEXTEN(tty)) @@ -739,7 +738,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) put_tty_queue(c, tty); return; } - + if (c == '\r') { if (I_IGNCR(tty)) return; @@ -825,8 +824,8 @@ send_signal: goto handle_newline; } if (c == EOF_CHAR(tty)) { - if (tty->canon_head != tty->read_head) - set_bit(TTY_PUSH, &tty->flags); + if (tty->canon_head != tty->read_head) + set_bit(TTY_PUSH, &tty->flags); c = __DISABLED_CHAR; goto handle_newline; } @@ -850,7 +849,7 @@ send_signal: if (I_PARMRK(tty) && c == (unsigned char) '\377') put_tty_queue(c, tty); - handle_newline: +handle_newline: spin_lock_irqsave(&tty->read_lock, flags); set_bit(tty->read_head, tty->read_flags); put_tty_queue_nolock(c, tty); @@ -863,7 +862,7 @@ send_signal: return; } } - + finish_erasing(tty); if (L_ECHO(tty)) { if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { @@ -884,7 +883,7 @@ send_signal: put_tty_queue(c, tty); put_tty_queue(c, tty); -} +} /** @@ -898,12 +897,10 @@ send_signal: static void n_tty_write_wakeup(struct tty_struct *tty) { - if (tty->fasync) - { - set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + if (tty->fasync) { + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); kill_fasync(&tty->fasync, SIGIO, POLL_OUT); } - return; } /** @@ -918,7 +915,7 @@ static void n_tty_write_wakeup(struct tty_struct *tty) * not from interrupt context. The driver is responsible for making * calls one at a time and in order (or using flush_to_ldisc) */ - + static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { @@ -950,7 +947,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, tty->read_cnt += i; spin_unlock_irqrestore(&tty->read_lock, cpuflags); } else { - for (i=count, p = cp, f = fp; i; i--, p++) { + for (i = count, p = cp, f = fp; i; i--, p++) { if (f) flags = *f++; switch (flags) { @@ -968,7 +965,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, n_tty_receive_overrun(tty); break; default: - printk("%s: unknown flag %d\n", + printk(KERN_ERR "%s: unknown flag %d\n", tty_name(tty, buf), flags); break; } @@ -1001,7 +998,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, int is_ignored(int sig) { return (sigismember(¤t->blocked, sig) || - current->sighand->action[sig-1].sa.sa_handler == SIG_IGN); + current->sighand->action[sig-1].sa.sa_handler == SIG_IGN); } /** @@ -1011,16 +1008,16 @@ int is_ignored(int sig) * * Called by the tty layer when the user changes termios flags so * that the line discipline can plan ahead. This function cannot sleep - * and is protected from re-entry by the tty layer. The user is + * and is protected from re-entry by the tty layer. The user is * guaranteed that this function will not be re-entered or in progress * when the ldisc is closed. */ - -static void n_tty_set_termios(struct tty_struct *tty, struct ktermios * old) + +static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) { if (!tty) return; - + tty->icanon = (L_ICANON(tty) != 0); if (test_bit(TTY_HW_COOK_IN, &tty->flags)) { tty->raw = 1; @@ -1085,12 +1082,12 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios * old) * n_tty_close - close the ldisc for this tty * @tty: device * - * Called from the terminal layer when this line discipline is - * being shut down, either because of a close or becsuse of a + * Called from the terminal layer when this line discipline is + * being shut down, either because of a close or becsuse of a * discipline change. The function will not be called while other * ldisc methods are in progress. */ - + static void n_tty_close(struct tty_struct *tty) { n_tty_flush_buffer(tty); @@ -1104,7 +1101,7 @@ static void n_tty_close(struct tty_struct *tty) * n_tty_open - open an ldisc * @tty: terminal to open * - * Called when this line discipline is being attached to the + * Called when this line discipline is being attached to the * terminal device. Can sleep. Called serialized so that no * other events will occur in parallel. No further open will occur * until a close. @@ -1157,7 +1154,7 @@ static inline int input_available_p(struct tty_struct *tty, int amt) * Called under the tty->atomic_read_lock sem * */ - + static int copy_from_read_buf(struct tty_struct *tty, unsigned char __user **b, size_t *nr) @@ -1186,7 +1183,8 @@ static int copy_from_read_buf(struct tty_struct *tty, return retval; } -extern ssize_t redirected_tty_write(struct file *,const char *,size_t,loff_t *); +extern ssize_t redirected_tty_write(struct file *, const char *, + size_t, loff_t *); /** * job_control - check job control @@ -1194,10 +1192,10 @@ extern ssize_t redirected_tty_write(struct file *,const char *,size_t,loff_t *); * @file: file handle * * Perform job control management checks on this file/tty descriptor - * and if appropriate send any needed signals and return a negative + * and if appropriate send any needed signals and return a negative * error code if action should be taken. */ - + static int job_control(struct tty_struct *tty, struct file *file) { /* Job control check -- must be done at start and after @@ -1208,7 +1206,7 @@ static int job_control(struct tty_struct *tty, struct file *file) if (file->f_op->write != redirected_tty_write && current->signal->tty == tty) { if (!tty->pgrp) - printk("read_chan: no tty->pgrp!\n"); + printk(KERN_ERR "read_chan: no tty->pgrp!\n"); else if (task_pgrp(current) != tty->pgrp) { if (is_ignored(SIGTTIN) || is_current_pgrp_orphaned()) @@ -1220,7 +1218,7 @@ static int job_control(struct tty_struct *tty, struct file *file) } return 0; } - + /** * read_chan - read function for tty @@ -1236,7 +1234,7 @@ static int job_control(struct tty_struct *tty, struct file *file) * * This code must be sure never to sleep through a hangup. */ - + static ssize_t read_chan(struct tty_struct *tty, struct file *file, unsigned char __user *buf, size_t nr) { @@ -1252,14 +1250,14 @@ static ssize_t read_chan(struct tty_struct *tty, struct file *file, do_it_again: if (!tty->read_buf) { - printk("n_tty_read_chan: called with read_buf == NULL?!?\n"); + printk(KERN_ERR "n_tty_read_chan: read_buf == NULL?!?\n"); return -EIO; } c = job_control(tty, file); - if(c < 0) + if (c < 0) return c; - + minimum = time = 0; timeout = MAX_SCHEDULE_TIMEOUT; if (!tty->icanon) { @@ -1287,8 +1285,7 @@ do_it_again: if (file->f_flags & O_NONBLOCK) { if (!mutex_trylock(&tty->atomic_read_lock)) return -EAGAIN; - } - else { + } else { if (mutex_lock_interruptible(&tty->atomic_read_lock)) return -ERESTARTSYS; } @@ -1314,11 +1311,11 @@ do_it_again: so that any interrupt will set the state back to TASK_RUNNING. */ set_current_state(TASK_INTERRUPTIBLE); - + if (((minimum - (b - buf)) < tty->minimum_to_wake) && ((minimum - (b - buf)) >= 1)) tty->minimum_to_wake = (minimum - (b - buf)); - + if (!input_available_p(tty, 0)) { if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { retval = -EIO; @@ -1355,7 +1352,7 @@ do_it_again: if (tty->icanon) { /* N.B. avoid overrun if nr == 0 */ while (nr && tty->read_cnt) { - int eol; + int eol; eol = test_and_clear_bit(tty->read_tail, tty->read_flags); @@ -1427,7 +1424,7 @@ do_it_again: if (size) { retval = size; if (nr) - clear_bit(TTY_PUSH, &tty->flags); + clear_bit(TTY_PUSH, &tty->flags); } else if (test_and_clear_bit(TTY_PUSH, &tty->flags)) goto do_it_again; @@ -1450,9 +1447,9 @@ do_it_again: * * This code must be sure never to sleep through a hangup. */ - -static ssize_t write_chan(struct tty_struct * tty, struct file * file, - const unsigned char * buf, size_t nr) + +static ssize_t write_chan(struct tty_struct *tty, struct file *file, + const unsigned char *buf, size_t nr) { const unsigned char *b = buf; DECLARE_WAITQUEUE(wait, current); @@ -1542,8 +1539,9 @@ break_out: * recompute the new limits. Possibly set_termios should issue * a read wakeup to fix this bug. */ - -static unsigned int normal_poll(struct tty_struct * tty, struct file * file, poll_table *wait) + +static unsigned int normal_poll(struct tty_struct *tty, struct file *file, + poll_table *wait) { unsigned int mask = 0; diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 68c289fe2dc2..72f289279d8f 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -715,11 +715,10 @@ static void configure_r_port(struct r_port *info, unsigned rocketMode; int bits, baud, divisor; CHANNEL_t *cp; + struct ktermios *t = info->tty->termios; - if (!info->tty || !info->tty->termios) - return; cp = &info->channel; - cflag = info->tty->termios->c_cflag; + cflag = t->c_cflag; /* Byte size and parity */ if ((cflag & CSIZE) == CS8) { @@ -754,10 +753,7 @@ static void configure_r_port(struct r_port *info, baud = 9600; divisor = ((rp_baud_base[info->board] + (baud >> 1)) / baud) - 1; if ((divisor >= 8192 || divisor < 0) && old_termios) { - info->tty->termios->c_cflag &= ~CBAUD; - info->tty->termios->c_cflag |= - (old_termios->c_cflag & CBAUD); - baud = tty_get_baud_rate(info->tty); + baud = tty_termios_baud_rate(old_termios); if (!baud) baud = 9600; divisor = (rp_baud_base[info->board] / baud) - 1; @@ -769,6 +765,9 @@ static void configure_r_port(struct r_port *info, info->cps = baud / bits; sSetBaud(cp, divisor); + /* FIXME: Should really back compute a baud rate from the divisor */ + tty_encode_baud_rate(info->tty, baud, baud); + if (cflag & CRTSCTS) { info->intmask |= DELTA_CTS; sEnCTSFlowCtl(cp); @@ -1202,15 +1201,14 @@ static void rp_set_termios(struct tty_struct *tty, cflag = tty->termios->c_cflag; - if (cflag == old_termios->c_cflag) - return; - /* * This driver doesn't support CS5 or CS6 */ if (((cflag & CSIZE) == CS5) || ((cflag & CSIZE) == CS6)) tty->termios->c_cflag = ((cflag & ~CSIZE) | (old_termios->c_cflag & CSIZE)); + /* Or CMSPAR */ + tty->termios->c_cflag &= ~CMSPAR; configure_r_port(info, old_termios); @@ -1401,6 +1399,9 @@ static int reset_rm2(struct r_port *info, void __user *arg) { int reset; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (copy_from_user(&reset, arg, sizeof (int))) return -EFAULT; if (reset) diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c index bacded0eefab..7722466e052f 100644 --- a/drivers/char/tty_audit.c +++ b/drivers/char/tty_audit.c @@ -27,7 +27,7 @@ static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor, { struct tty_audit_buf *buf; - buf = kmalloc(sizeof (*buf), GFP_KERNEL); + buf = kmalloc(sizeof(*buf), GFP_KERNEL); if (!buf) goto err; if (PAGE_SIZE != N_TTY_BUF_SIZE) diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 79c86c47947f..613ec816ce60 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -19,7 +19,7 @@ * Also restructured routines so that there is more of a separation * between the high-level tty routines (tty_io.c and tty_ioctl.c) and * the low-level tty routines (serial.c, pty.c, console.c). This - * makes for cleaner and more compact code. -TYT, 9/17/92 + * makes for cleaner and more compact code. -TYT, 9/17/92 * * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines * which can be dynamically activated and de-activated by the line @@ -41,7 +41,7 @@ * * New TIOCLINUX variants added. * -- mj@k332.feld.cvut.cz, 19-Nov-95 - * + * * Restrict vt switching via ioctl() * -- grif@cs.ucr.edu, 5-Dec-95 * @@ -62,7 +62,8 @@ * -- Russell King <rmk@arm.linux.org.uk> * * Move do_SAK() into process context. Less stack use in devfs functions. - * alloc_tty_struct() always uses kmalloc() -- Andrew Morton <andrewm@uow.edu.eu> 17Mar01 + * alloc_tty_struct() always uses kmalloc() + * -- Andrew Morton <andrewm@uow.edu.eu> 17Mar01 */ #include <linux/types.h> @@ -126,7 +127,7 @@ EXPORT_SYMBOL(tty_std_termios); /* This list gets poked at by procfs and various bits of boot up code. This could do with some rationalisation such as pulling the tty proc function into this file */ - + LIST_HEAD(tty_drivers); /* linked list of tty drivers */ /* Mutex to protect creating and releasing a tty. This is shared with @@ -136,7 +137,7 @@ EXPORT_SYMBOL(tty_mutex); #ifdef CONFIG_UNIX98_PTYS extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */ -extern int pty_limit; /* Config limit on Unix98 ptys */ +extern int pty_limit; /* Config limit on Unix98 ptys */ static DEFINE_IDR(allocated_ptys); static DEFINE_MUTEX(allocated_ptys_lock); static int ptmx_open(struct inode *, struct file *); @@ -146,19 +147,20 @@ static void initialize_tty_struct(struct tty_struct *tty); static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *); static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *); -ssize_t redirected_tty_write(struct file *, const char __user *, size_t, loff_t *); +ssize_t redirected_tty_write(struct file *, const char __user *, + size_t, loff_t *); static unsigned int tty_poll(struct file *, poll_table *); static int tty_open(struct inode *, struct file *); static int tty_release(struct inode *, struct file *); -int tty_ioctl(struct inode * inode, struct file * file, +int tty_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); #ifdef CONFIG_COMPAT -static long tty_compat_ioctl(struct file * file, unsigned int cmd, +static long tty_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); #else #define tty_compat_ioctl NULL #endif -static int tty_fasync(int fd, struct file * filp, int on); +static int tty_fasync(int fd, struct file *filp, int on); static void release_tty(struct tty_struct *tty, int idx); static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty); static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty); @@ -244,7 +246,7 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) #ifdef CHECK_TTY_COUNT struct list_head *p; int count = 0; - + file_list_lock(); list_for_each(p, &tty->tty_files) { count++; @@ -281,11 +283,11 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) static void tty_buffer_free_all(struct tty_struct *tty) { struct tty_buffer *thead; - while((thead = tty->buf.head) != NULL) { + while ((thead = tty->buf.head) != NULL) { tty->buf.head = thead->next; kfree(thead); } - while((thead = tty->buf.free) != NULL) { + while ((thead = tty->buf.free) != NULL) { tty->buf.free = thead->next; kfree(thead); } @@ -331,7 +333,7 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size) if (tty->buf.memory_used + size > 65536) return NULL; p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC); - if(p == NULL) + if (p == NULL) return NULL; p->used = 0; p->size = size; @@ -361,7 +363,7 @@ static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b) tty->buf.memory_used -= b->size; WARN_ON(tty->buf.memory_used < 0); - if(b->size >= 512) + if (b->size >= 512) kfree(b); else { b->next = tty->buf.free; @@ -384,7 +386,7 @@ static void __tty_buffer_flush(struct tty_struct *tty) { struct tty_buffer *thead; - while((thead = tty->buf.head) != NULL) { + while ((thead = tty->buf.head) != NULL) { tty->buf.head = thead->next; tty_buffer_free(tty, thead); } @@ -436,9 +438,9 @@ static void tty_buffer_flush(struct tty_struct *tty) static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) { struct tty_buffer **tbh = &tty->buf.free; - while((*tbh) != NULL) { + while ((*tbh) != NULL) { struct tty_buffer *t = *tbh; - if(t->size >= size) { + if (t->size >= size) { *tbh = t->next; t->next = NULL; t->used = 0; @@ -450,7 +452,7 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) tbh = &((*tbh)->next); } /* Round the buffer size out */ - size = (size + 0xFF) & ~ 0xFF; + size = (size + 0xFF) & ~0xFF; return tty_buffer_alloc(tty, size); /* Should possibly check if this fails for the largest buffer we have queued and recycle that ? */ @@ -520,7 +522,7 @@ int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars, int space = tty_buffer_request_room(tty, size - copied); struct tty_buffer *tb = tty->buf.tail; /* If there is no space then tb may be NULL */ - if(unlikely(space == 0)) + if (unlikely(space == 0)) break; memcpy(tb->char_buf_ptr + tb->used, chars, space); memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); @@ -556,7 +558,7 @@ int tty_insert_flip_string_flags(struct tty_struct *tty, int space = tty_buffer_request_room(tty, size - copied); struct tty_buffer *tb = tty->buf.tail; /* If there is no space then tb may be NULL */ - if(unlikely(space == 0)) + if (unlikely(space == 0)) break; memcpy(tb->char_buf_ptr + tb->used, chars, space); memcpy(tb->flag_buf_ptr + tb->used, flags, space); @@ -608,7 +610,8 @@ EXPORT_SYMBOL(tty_schedule_flip); * Locking: May call functions taking tty->buf.lock */ -int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size) +int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, + size_t size) { int space = tty_buffer_request_room(tty, size); if (likely(space)) { @@ -638,7 +641,8 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string); * Locking: May call functions taking tty->buf.lock */ -int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size) +int tty_prepare_flip_string_flags(struct tty_struct *tty, + unsigned char **chars, char **flags, size_t size) { int space = tty_buffer_request_room(tty, size); if (likely(space)) { @@ -660,12 +664,12 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); * @num: line discipline number * * This is probably overkill for real world processors but - * they are not on hot paths so a little discipline won't do + * they are not on hot paths so a little discipline won't do * any harm. * * Locking: takes termios_mutex */ - + static void tty_set_termios_ldisc(struct tty_struct *tty, int num) { mutex_lock(&tty->termios_mutex); @@ -678,10 +682,11 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num) * must be taken with irqs off because there are hangup path * callers who will do ldisc lookups and cannot sleep. */ - + static DEFINE_SPINLOCK(tty_ldisc_lock); static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait); -static struct tty_ldisc tty_ldiscs[NR_LDISCS]; /* line disc dispatch table */ +/* Line disc dispatch table */ +static struct tty_ldisc tty_ldiscs[NR_LDISCS]; /** * tty_register_ldisc - install a line discipline @@ -700,17 +705,17 @@ int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc) { unsigned long flags; int ret = 0; - + if (disc < N_TTY || disc >= NR_LDISCS) return -EINVAL; - + spin_lock_irqsave(&tty_ldisc_lock, flags); tty_ldiscs[disc] = *new_ldisc; tty_ldiscs[disc].num = disc; tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED; tty_ldiscs[disc].refcount = 0; spin_unlock_irqrestore(&tty_ldisc_lock, flags); - + return ret; } EXPORT_SYMBOL(tty_register_ldisc); @@ -766,20 +771,18 @@ struct tty_ldisc *tty_ldisc_get(int disc) if (disc < N_TTY || disc >= NR_LDISCS) return NULL; - + spin_lock_irqsave(&tty_ldisc_lock, flags); ld = &tty_ldiscs[disc]; /* Check the entry is defined */ - if(ld->flags & LDISC_FLAG_DEFINED) - { + if (ld->flags & LDISC_FLAG_DEFINED) { /* If the module is being unloaded we can't use it */ if (!try_module_get(ld->owner)) - ld = NULL; + ld = NULL; else /* lock it */ ld->refcount++; - } - else + } else ld = NULL; spin_unlock_irqrestore(&tty_ldisc_lock, flags); return ld; @@ -802,9 +805,9 @@ void tty_ldisc_put(int disc) { struct tty_ldisc *ld; unsigned long flags; - + BUG_ON(disc < N_TTY || disc >= NR_LDISCS); - + spin_lock_irqsave(&tty_ldisc_lock, flags); ld = &tty_ldiscs[disc]; BUG_ON(ld->refcount == 0); @@ -812,7 +815,7 @@ void tty_ldisc_put(int disc) module_put(ld->owner); spin_unlock_irqrestore(&tty_ldisc_lock, flags); } - + EXPORT_SYMBOL_GPL(tty_ldisc_put); /** @@ -851,11 +854,10 @@ static int tty_ldisc_try(struct tty_struct *tty) unsigned long flags; struct tty_ldisc *ld; int ret = 0; - + spin_lock_irqsave(&tty_ldisc_lock, flags); ld = &tty->ldisc; - if(test_bit(TTY_LDISC, &tty->flags)) - { + if (test_bit(TTY_LDISC, &tty->flags)) { ld->refcount++; ret = 1; } @@ -867,8 +869,8 @@ static int tty_ldisc_try(struct tty_struct *tty) * tty_ldisc_ref_wait - wait for the tty ldisc * @tty: tty device * - * Dereference the line discipline for the terminal and take a - * reference to it. If the line discipline is in flux then + * Dereference the line discipline for the terminal and take a + * reference to it. If the line discipline is in flux then * wait patiently until it changes. * * Note: Must not be called from an IRQ/timer context. The caller @@ -878,12 +880,12 @@ static int tty_ldisc_try(struct tty_struct *tty) * * Locking: call functions take tty_ldisc_lock */ - + struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) { /* wait_event is a macro */ wait_event(tty_ldisc_wait, tty_ldisc_try(tty)); - if(tty->ldisc.refcount == 0) + if (tty->ldisc.refcount == 0) printk(KERN_ERR "tty_ldisc_ref_wait\n"); return &tty->ldisc; } @@ -894,16 +896,16 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); * tty_ldisc_ref - get the tty ldisc * @tty: tty device * - * Dereference the line discipline for the terminal and take a - * reference to it. If the line discipline is in flux then + * Dereference the line discipline for the terminal and take a + * reference to it. If the line discipline is in flux then * return NULL. Can be called from IRQ and timer functions. * * Locking: called functions take tty_ldisc_lock */ - + struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty) { - if(tty_ldisc_try(tty)) + if (tty_ldisc_try(tty)) return &tty->ldisc; return NULL; } @@ -919,19 +921,19 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref); * * Locking: takes tty_ldisc_lock */ - + void tty_ldisc_deref(struct tty_ldisc *ld) { unsigned long flags; BUG_ON(ld == NULL); - + spin_lock_irqsave(&tty_ldisc_lock, flags); - if(ld->refcount == 0) + if (ld->refcount == 0) printk(KERN_ERR "tty_ldisc_deref: no references.\n"); else ld->refcount--; - if(ld->refcount == 0) + if (ld->refcount == 0) wake_up(&tty_ldisc_wait); spin_unlock_irqrestore(&tty_ldisc_lock, flags); } @@ -954,7 +956,7 @@ static void tty_ldisc_enable(struct tty_struct *tty) set_bit(TTY_LDISC, &tty->flags); wake_up(&tty_ldisc_wait); } - + /** * tty_set_ldisc - set line discipline * @tty: the terminal to set @@ -966,7 +968,7 @@ static void tty_ldisc_enable(struct tty_struct *tty) * Locking: takes tty_ldisc_lock. * called functions take termios_mutex */ - + static int tty_set_ldisc(struct tty_struct *tty, int ldisc) { int retval = 0; @@ -1022,7 +1024,7 @@ restart: spin_lock_irqsave(&tty_ldisc_lock, flags); if (tty->ldisc.refcount || (o_tty && o_tty->ldisc.refcount)) { - if(tty->ldisc.refcount) { + if (tty->ldisc.refcount) { /* Free the new ldisc we grabbed. Must drop the lock first. */ spin_unlock_irqrestore(&tty_ldisc_lock, flags); @@ -1031,14 +1033,14 @@ restart: * There are several reasons we may be busy, including * random momentary I/O traffic. We must therefore * retry. We could distinguish between blocking ops - * and retries if we made tty_ldisc_wait() smarter. That - * is up for discussion. + * and retries if we made tty_ldisc_wait() smarter. + * That is up for discussion. */ if (wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0) return -ERESTARTSYS; goto restart; } - if(o_tty && o_tty->ldisc.refcount) { + if (o_tty && o_tty->ldisc.refcount) { spin_unlock_irqrestore(&tty_ldisc_lock, flags); tty_ldisc_put(ldisc); if (wait_event_interruptible(tty_ldisc_wait, o_tty->ldisc.refcount == 0) < 0) @@ -1046,9 +1048,10 @@ restart: goto restart; } } - - /* if the TTY_LDISC bit is set, then we are racing against another ldisc change */ - + /* + * If the TTY_LDISC bit is set, then we are racing against + * another ldisc change + */ if (!test_bit(TTY_LDISC, &tty->flags)) { spin_unlock_irqrestore(&tty_ldisc_lock, flags); tty_ldisc_put(ldisc); @@ -1072,7 +1075,6 @@ restart: /* * Wait for ->hangup_work and ->buf.work handlers to terminate */ - flush_scheduled_work(); /* Shutdown the current discipline. */ if (tty->ldisc.close) @@ -1106,21 +1108,21 @@ restart: /* At this point we hold a reference to the new ldisc and a a reference to the old ldisc. If we ended up flipping back to the existing ldisc we have two references to it */ - + if (tty->ldisc.num != o_ldisc.num && tty->driver->set_ldisc) tty->driver->set_ldisc(tty); - + tty_ldisc_put(o_ldisc.num); - + /* * Allow ldisc referencing to occur as soon as the driver * ldisc callback completes. */ - + tty_ldisc_enable(tty); if (o_tty) tty_ldisc_enable(o_tty); - + /* Restart it in case no characters kick it off. Safe if already running */ if (work) @@ -1164,7 +1166,7 @@ static struct tty_driver *get_tty_driver(dev_t device, int *index) * Locking: none */ -int tty_check_change(struct tty_struct * tty) +int tty_check_change(struct tty_struct *tty) { if (current->signal->tty != tty) return 0; @@ -1185,31 +1187,31 @@ int tty_check_change(struct tty_struct * tty) EXPORT_SYMBOL(tty_check_change); -static ssize_t hung_up_tty_read(struct file * file, char __user * buf, +static ssize_t hung_up_tty_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { return 0; } -static ssize_t hung_up_tty_write(struct file * file, const char __user * buf, +static ssize_t hung_up_tty_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { return -EIO; } /* No kernel lock held - none needed ;) */ -static unsigned int hung_up_tty_poll(struct file * filp, poll_table * wait) +static unsigned int hung_up_tty_poll(struct file *filp, poll_table *wait) { return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM; } -static int hung_up_tty_ioctl(struct inode * inode, struct file * file, +static int hung_up_tty_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { return cmd == TIOCSPGRP ? -ENOTTY : -EIO; } -static long hung_up_tty_compat_ioctl(struct file * file, +static long hung_up_tty_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { return cmd == TIOCSPGRP ? -ENOTTY : -EIO; @@ -1274,15 +1276,15 @@ static struct file *redirect; * informs the line discipline if present that the driver is ready * to receive more output data. */ - + void tty_wakeup(struct tty_struct *tty) { struct tty_ldisc *ld; - + if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) { ld = tty_ldisc_ref(tty); - if(ld) { - if(ld->write_wakeup) + if (ld) { + if (ld->write_wakeup) ld->write_wakeup(tty); tty_ldisc_deref(ld); } @@ -1299,12 +1301,12 @@ EXPORT_SYMBOL_GPL(tty_wakeup); * Flush the line discipline queue (if any) for this tty. If there * is no line discipline active this is a no-op. */ - + void tty_ldisc_flush(struct tty_struct *tty) { struct tty_ldisc *ld = tty_ldisc_ref(tty); - if(ld) { - if(ld->flush_buffer) + if (ld) { + if (ld->flush_buffer) ld->flush_buffer(tty); tty_ldisc_deref(ld); } @@ -1328,7 +1330,7 @@ static void tty_reset_termios(struct tty_struct *tty) tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios); mutex_unlock(&tty->termios_mutex); } - + /** * do_tty_hangup - actual handler for hangup events * @work: tty device @@ -1355,7 +1357,7 @@ static void do_tty_hangup(struct work_struct *work) { struct tty_struct *tty = container_of(work, struct tty_struct, hangup_work); - struct file * cons_filp = NULL; + struct file *cons_filp = NULL; struct file *filp, *f = NULL; struct task_struct *p; struct tty_ldisc *ld; @@ -1373,7 +1375,7 @@ static void do_tty_hangup(struct work_struct *work) redirect = NULL; } spin_unlock(&redirect_lock); - + check_tty_count(tty, "do_tty_hangup"); file_list_lock(); /* This breaks for file handles being sent over AF_UNIX sockets ? */ @@ -1387,13 +1389,14 @@ static void do_tty_hangup(struct work_struct *work) filp->f_op = &hung_up_tty_fops; } file_list_unlock(); - - /* FIXME! What are the locking issues here? This may me overdoing things.. - * this question is especially important now that we've removed the irqlock. */ - + /* + * FIXME! What are the locking issues here? This may me overdoing + * things... This question is especially important now that we've + * removed the irqlock. + */ ld = tty_ldisc_ref(tty); - if(ld != NULL) /* We may have no line discipline at this point */ - { + if (ld != NULL) { + /* We may have no line discipline at this point */ if (ld->flush_buffer) ld->flush_buffer(tty); if (tty->driver->flush_buffer) @@ -1404,26 +1407,24 @@ static void do_tty_hangup(struct work_struct *work) if (ld->hangup) ld->hangup(tty); } - - /* FIXME: Once we trust the LDISC code better we can wait here for - ldisc completion and fix the driver call race */ - + /* + * FIXME: Once we trust the LDISC code better we can wait here for + * ldisc completion and fix the driver call race + */ wake_up_interruptible(&tty->write_wait); wake_up_interruptible(&tty->read_wait); - /* * Shutdown the current line discipline, and reset it to * N_TTY. */ if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) tty_reset_termios(tty); - /* Defer ldisc switch */ /* tty_deferred_ldisc_switch(N_TTY); - + This should get done automatically when the port closes and tty_release is called */ - + read_lock(&tasklist_lock); if (tty->session) { do_each_pid_task(tty->session, PIDTYPE_SID, p) { @@ -1451,10 +1452,10 @@ static void do_tty_hangup(struct work_struct *work) tty->pgrp = NULL; tty->ctrl_status = 0; /* - * If one of the devices matches a console pointer, we - * cannot just call hangup() because that will cause - * tty->count and state->count to go out of sync. - * So we just call close() the right number of times. + * If one of the devices matches a console pointer, we + * cannot just call hangup() because that will cause + * tty->count and state->count to go out of sync. + * So we just call close() the right number of times. */ if (cons_filp) { if (tty->driver->close) @@ -1462,12 +1463,12 @@ static void do_tty_hangup(struct work_struct *work) tty->driver->close(tty, cons_filp); } else if (tty->driver->hangup) (tty->driver->hangup)(tty); - - /* We don't want to have driver/ldisc interactions beyond - the ones we did here. The driver layer expects no - calls after ->hangup() from the ldisc side. However we - can't yet guarantee all that */ - + /* + * We don't want to have driver/ldisc interactions beyond + * the ones we did here. The driver layer expects no + * calls after ->hangup() from the ldisc side. However we + * can't yet guarantee all that. + */ set_bit(TTY_HUPPED, &tty->flags); if (ld) { tty_ldisc_enable(tty); @@ -1486,11 +1487,10 @@ static void do_tty_hangup(struct work_struct *work) * schedule a hangup sequence to run after this event. */ -void tty_hangup(struct tty_struct * tty) +void tty_hangup(struct tty_struct *tty) { #ifdef TTY_DEBUG_HANGUP char buf[64]; - printk(KERN_DEBUG "%s hangup...\n", tty_name(tty, buf)); #endif schedule_work(&tty->hangup_work); @@ -1507,7 +1507,7 @@ EXPORT_SYMBOL(tty_hangup); * is complete. That guarantee is necessary for security reasons. */ -void tty_vhangup(struct tty_struct * tty) +void tty_vhangup(struct tty_struct *tty) { #ifdef TTY_DEBUG_HANGUP char buf[64]; @@ -1516,6 +1516,7 @@ void tty_vhangup(struct tty_struct * tty) #endif do_tty_hangup(&tty->hangup_work); } + EXPORT_SYMBOL(tty_vhangup); /** @@ -1526,7 +1527,7 @@ EXPORT_SYMBOL(tty_vhangup); * loss */ -int tty_hung_up_p(struct file * filp) +int tty_hung_up_p(struct file *filp) { return (filp->f_op == &hung_up_tty_fops); } @@ -1534,8 +1535,12 @@ int tty_hung_up_p(struct file * filp) EXPORT_SYMBOL(tty_hung_up_p); /** - * is_tty - checker whether file is a TTY + * is_tty - checker whether file is a TTY + * @filp: file handle that may be a tty + * + * Check if the file handle is a tty handle. */ + int is_tty(struct file *filp) { return filp->f_op->read == tty_read @@ -1601,7 +1606,7 @@ void disassociate_ctty(int on_exit) put_pid(old_pgrp); } mutex_unlock(&tty_mutex); - unlock_kernel(); + unlock_kernel(); return; } if (tty_pgrp) { @@ -1711,7 +1716,6 @@ void start_tty(struct tty_struct *tty) } if (tty->driver->start) (tty->driver->start)(tty); - /* If we have a running line discipline it may need kicking */ tty_wakeup(tty); } @@ -1735,11 +1739,11 @@ EXPORT_SYMBOL(start_tty); * in new code. Multiple read calls may be outstanding in parallel. */ -static ssize_t tty_read(struct file * file, char __user * buf, size_t count, +static ssize_t tty_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { int i; - struct tty_struct * tty; + struct tty_struct *tty; struct inode *inode; struct tty_ldisc *ld; @@ -1755,7 +1759,7 @@ static ssize_t tty_read(struct file * file, char __user * buf, size_t count, ld = tty_ldisc_ref_wait(tty); lock_kernel(); if (ld->read) - i = (ld->read)(tty,file,buf,count); + i = (ld->read)(tty, file, buf, count); else i = -EIO; tty_ldisc_deref(ld); @@ -1795,7 +1799,7 @@ static inline ssize_t do_tty_write( { ssize_t ret, written = 0; unsigned int chunk; - + ret = tty_write_lock(tty, file->f_flags & O_NDELAY); if (ret < 0) return ret; @@ -1891,21 +1895,22 @@ out: * kernel lock for historical reasons. New code should not rely on this. */ -static ssize_t tty_write(struct file * file, const char __user * buf, size_t count, - loff_t *ppos) +static ssize_t tty_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) { - struct tty_struct * tty; + struct tty_struct *tty; struct inode *inode = file->f_path.dentry->d_inode; ssize_t ret; struct tty_ldisc *ld; - + tty = (struct tty_struct *)file->private_data; if (tty_paranoia_check(tty, inode, "tty_write")) return -EIO; - if (!tty || !tty->driver->write || (test_bit(TTY_IO_ERROR, &tty->flags))) - return -EIO; + if (!tty || !tty->driver->write || + (test_bit(TTY_IO_ERROR, &tty->flags))) + return -EIO; - ld = tty_ldisc_ref_wait(tty); + ld = tty_ldisc_ref_wait(tty); if (!ld->write) ret = -EIO; else @@ -1914,8 +1919,8 @@ static ssize_t tty_write(struct file * file, const char __user * buf, size_t cou return ret; } -ssize_t redirected_tty_write(struct file * file, const char __user * buf, size_t count, - loff_t *ppos) +ssize_t redirected_tty_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) { struct file *p = NULL; @@ -1932,7 +1937,6 @@ ssize_t redirected_tty_write(struct file * file, const char __user * buf, size_t fput(p); return res; } - return tty_write(file, buf, count, ppos); } @@ -1954,8 +1958,8 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p) int i = index + driver->name_base; /* ->name is initialized to "ttyp", but "tty" is expected */ sprintf(p, "%s%c%x", - driver->subtype == PTY_TYPE_SLAVE ? "tty" : driver->name, - ptychar[i >> 4 & 0xf], i & 0xf); + driver->subtype == PTY_TYPE_SLAVE ? "tty" : driver->name, + ptychar[i >> 4 & 0xf], i & 0xf); } /** @@ -2034,7 +2038,7 @@ static int init_dev(struct tty_driver *driver, int idx, * First time open is complex, especially for PTY devices. * This code guarantees that either everything succeeds and the * TTY is ready for operation, or else the table slots are vacated - * and the allocated memory released. (Except that the termios + * and the allocated memory released. (Except that the termios * and locked termios may be retained.) */ @@ -2048,7 +2052,7 @@ static int init_dev(struct tty_driver *driver, int idx, ltp = o_ltp = NULL; tty = alloc_tty_struct(); - if(!tty) + if (!tty) goto fail_no_mem; initialize_tty_struct(tty); tty->driver = driver; @@ -2109,9 +2113,8 @@ static int init_dev(struct tty_driver *driver, int idx, /* * Everything allocated ... set up the o_tty structure. */ - if (!(driver->other->flags & TTY_DRIVER_DEVPTS_MEM)) { + if (!(driver->other->flags & TTY_DRIVER_DEVPTS_MEM)) driver->other->ttys[idx] = o_tty; - } if (!*o_tp_loc) *o_tp_loc = o_tp; if (!*o_ltp_loc) @@ -2127,15 +2130,14 @@ static int init_dev(struct tty_driver *driver, int idx, o_tty->link = tty; } - /* + /* * All structures have been allocated, so now we install them. * Failures after this point use release_tty to clean up, so * there's no need to null out the local pointers. */ - if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) { + if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) driver->ttys[idx] = tty; - } - + if (!*tp_loc) *tp_loc = tp; if (!*ltp_loc) @@ -2148,7 +2150,7 @@ static int init_dev(struct tty_driver *driver, int idx, driver->refcount++; tty->count++; - /* + /* * Structures all installed ... call the ldisc open routines. * If we fail here just call release_tty to clean up. No need * to decrement the use counts, as release_tty doesn't care. @@ -2185,7 +2187,7 @@ fast_track: if (driver->type == TTY_DRIVER_TYPE_PTY && driver->subtype == PTY_TYPE_MASTER) { /* - * special case for PTY masters: only one open permitted, + * special case for PTY masters: only one open permitted, * and the slave side open count is incremented as well. */ if (tty->count) { @@ -2198,11 +2200,11 @@ fast_track: tty->driver = driver; /* N.B. why do this every time?? */ /* FIXME */ - if(!test_bit(TTY_LDISC, &tty->flags)) + if (!test_bit(TTY_LDISC, &tty->flags)) printk(KERN_ERR "init_dev but no ldisc\n"); success: *ret_tty = tty; - + /* All paths come through here to release the mutex */ end_init: return retval; @@ -2304,7 +2306,7 @@ static void release_tty(struct tty_struct *tty, int idx) * WSH 09/09/97: rewritten to avoid some nasty race conditions that could * lead to double frees or releasing memory still in use. */ -static void release_dev(struct file * filp) +static void release_dev(struct file *filp) { struct tty_struct *tty, *o_tty; int pty_master, tty_closing, o_tty_closing, do_sleep; @@ -2312,9 +2314,10 @@ static void release_dev(struct file * filp) int idx; char buf[64]; unsigned long flags; - + tty = (struct tty_struct *)filp->private_data; - if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "release_dev")) + if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, + "release_dev")) return; check_tty_count(tty, "release_dev"); @@ -2374,7 +2377,7 @@ static void release_dev(struct file * filp) idx, tty->name); return; } - if (o_tty->termios_locked != + if (o_tty->termios_locked != tty->driver->other->termios_locked[idx]) { printk(KERN_DEBUG "release_dev: other->termios_locked[" "%d] not o_termios_locked for (%s)\n", @@ -2410,7 +2413,7 @@ static void release_dev(struct file * filp) while (1) { /* Guard against races with tty->count changes elsewhere and opens on /dev/tty */ - + mutex_lock(&tty_mutex); tty_closing = tty->count <= 1; o_tty_closing = o_tty && @@ -2444,11 +2447,11 @@ static void release_dev(struct file * filp) "active!\n", tty_name(tty, buf)); mutex_unlock(&tty_mutex); schedule(); - } + } /* - * The closing flags are now consistent with the open counts on - * both sides, and we've completed the last operation that could + * The closing flags are now consistent with the open counts on + * both sides, and we've completed the last operation that could * block, so it's safe to proceed with closing. */ if (pty_master) { @@ -2464,7 +2467,7 @@ static void release_dev(struct file * filp) tty->count, tty_name(tty, buf)); tty->count = 0; } - + /* * We've decremented tty->count, so we need to remove this file * descriptor off the tty->tty_files list; this serves two @@ -2484,9 +2487,9 @@ static void release_dev(struct file * filp) * case of a pty we may have to wait around for the other side * to close, and TTY_CLOSING makes sure we can't be reopened. */ - if(tty_closing) + if (tty_closing) set_bit(TTY_CLOSING, &tty->flags); - if(o_tty_closing) + if (o_tty_closing) set_bit(TTY_CLOSING, &o_tty->flags); /* @@ -2507,7 +2510,7 @@ static void release_dev(struct file * filp) /* check whether both sides are closing ... */ if (!tty_closing || (o_tty && !o_tty_closing)) return; - + #ifdef TTY_DEBUG_HANGUP printk(KERN_DEBUG "freeing tty structure..."); #endif @@ -2522,17 +2525,16 @@ static void release_dev(struct file * filp) /* * Wait for ->hangup_work and ->buf.work handlers to terminate */ - + flush_scheduled_work(); - + /* * Wait for any short term users (we know they are just driver * side waiters as the file is closing so user count on the file * side is zero. */ spin_lock_irqsave(&tty_ldisc_lock, flags); - while(tty->ldisc.refcount) - { + while (tty->ldisc.refcount) { spin_unlock_irqrestore(&tty_ldisc_lock, flags); wait_event(tty_ldisc_wait, tty->ldisc.refcount == 0); spin_lock_irqsave(&tty_ldisc_lock, flags); @@ -2547,12 +2549,12 @@ static void release_dev(struct file * filp) if (tty->ldisc.close) (tty->ldisc.close)(tty); tty_ldisc_put(tty->ldisc.num); - + /* * Switch the line discipline back */ tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); - tty_set_termios_ldisc(tty,N_TTY); + tty_set_termios_ldisc(tty, N_TTY); if (o_tty) { /* FIXME: could o_tty be in setldisc here ? */ clear_bit(TTY_LDISC, &o_tty->flags); @@ -2560,7 +2562,7 @@ static void release_dev(struct file * filp) (o_tty->ldisc.close)(o_tty); tty_ldisc_put(o_tty->ldisc.num); tty_ldisc_assign(o_tty, tty_ldisc_get(N_TTY)); - tty_set_termios_ldisc(o_tty,N_TTY); + tty_set_termios_ldisc(o_tty, N_TTY); } /* * The release_tty function takes care of the details of clearing @@ -2600,7 +2602,7 @@ static void release_dev(struct file * filp) * ->siglock protects ->signal/->sighand */ -static int tty_open(struct inode * inode, struct file * filp) +static int tty_open(struct inode *inode, struct file *filp) { struct tty_struct *tty; int noctty, retval; @@ -2610,15 +2612,15 @@ static int tty_open(struct inode * inode, struct file * filp) unsigned short saved_flags = filp->f_flags; nonseekable_open(inode, filp); - + retry_open: noctty = filp->f_flags & O_NOCTTY; index = -1; retval = 0; - + mutex_lock(&tty_mutex); - if (device == MKDEV(TTYAUX_MAJOR,0)) { + if (device == MKDEV(TTYAUX_MAJOR, 0)) { tty = get_current_tty(); if (!tty) { mutex_unlock(&tty_mutex); @@ -2631,7 +2633,7 @@ retry_open: goto got_driver; } #ifdef CONFIG_VT - if (device == MKDEV(TTY_MAJOR,0)) { + if (device == MKDEV(TTY_MAJOR, 0)) { extern struct tty_driver *console_driver; driver = console_driver; index = fg_console; @@ -2639,7 +2641,7 @@ retry_open: goto got_driver; } #endif - if (device == MKDEV(TTYAUX_MAJOR,1)) { + if (device == MKDEV(TTYAUX_MAJOR, 1)) { driver = console_device(&index); if (driver) { /* Don't let /dev/console block */ @@ -2679,7 +2681,8 @@ got_driver: } filp->f_flags = saved_flags; - if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN)) + if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && + !capable(CAP_SYS_ADMIN)) retval = -EBUSY; if (retval) { @@ -2723,11 +2726,11 @@ got_driver: * Allocate a unix98 pty master device from the ptmx driver. * * Locking: tty_mutex protects theinit_dev work. tty->count should - protect the rest. + * protect the rest. * allocated_ptys_lock handles the list of free pty numbers */ -static int ptmx_open(struct inode * inode, struct file * filp) +static int ptmx_open(struct inode *inode, struct file *filp) { struct tty_struct *tty; int retval; @@ -2759,7 +2762,7 @@ static int ptmx_open(struct inode * inode, struct file * filp) mutex_lock(&tty_mutex); retval = init_dev(ptm_driver, index, &tty); mutex_unlock(&tty_mutex); - + if (retval) goto out; @@ -2800,7 +2803,7 @@ out: * Takes bkl. See release_dev */ -static int tty_release(struct inode * inode, struct file * filp) +static int tty_release(struct inode *inode, struct file *filp) { lock_kernel(); release_dev(filp); @@ -2820,16 +2823,16 @@ static int tty_release(struct inode * inode, struct file * filp) * may be re-entered freely by other callers. */ -static unsigned int tty_poll(struct file * filp, poll_table * wait) +static unsigned int tty_poll(struct file *filp, poll_table *wait) { - struct tty_struct * tty; + struct tty_struct *tty; struct tty_ldisc *ld; int ret = 0; tty = (struct tty_struct *)filp->private_data; if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_poll")) return 0; - + ld = tty_ldisc_ref_wait(tty); if (ld->poll) ret = (ld->poll)(tty, filp, wait); @@ -2837,15 +2840,15 @@ static unsigned int tty_poll(struct file * filp, poll_table * wait) return ret; } -static int tty_fasync(int fd, struct file * filp, int on) +static int tty_fasync(int fd, struct file *filp, int on) { - struct tty_struct * tty; + struct tty_struct *tty; int retval; tty = (struct tty_struct *)filp->private_data; if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_fasync")) return 0; - + retval = fasync_helper(fd, filp, on, &tty->fasync); if (retval <= 0) return retval; @@ -2893,7 +2896,7 @@ static int tiocsti(struct tty_struct *tty, char __user *p) { char ch, mbz = 0; struct tty_ldisc *ld; - + if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN)) return -EPERM; if (get_user(ch, p)) @@ -2915,7 +2918,7 @@ static int tiocsti(struct tty_struct *tty, char __user *p) * is consistent. */ -static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg) +static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg) { int err; @@ -2944,7 +2947,7 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg) */ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, - struct winsize __user * arg) + struct winsize __user *arg) { struct winsize tmp_ws; @@ -2960,7 +2963,7 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, if (vc_lock_resize(tty->driver_data, tmp_ws.ws_col, tmp_ws.ws_row)) { mutex_unlock(&tty->termios_mutex); - return -ENXIO; + return -ENXIO; } } #endif @@ -3070,7 +3073,7 @@ static int tiocsctty(struct tty_struct *tty, int arg) * This tty is already the controlling * tty for another session group! */ - if ((arg == 1) && capable(CAP_SYS_ADMIN)) { + if (arg == 1 && capable(CAP_SYS_ADMIN)) { /* * Steal it away */ @@ -3303,14 +3306,14 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int /* * Split this up, as gcc can choke on it otherwise.. */ -int tty_ioctl(struct inode * inode, struct file * file, +int tty_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct tty_struct *tty, *real_tty; void __user *p = (void __user *)arg; int retval; struct tty_ldisc *ld; - + tty = (struct tty_struct *)file->private_data; if (tty_paranoia_check(tty, inode, "tty_ioctl")) return -EINVAL; @@ -3326,13 +3329,13 @@ int tty_ioctl(struct inode * inode, struct file * file, * Break handling by driver */ if (!tty->driver->break_ctl) { - switch(cmd) { + switch (cmd) { case TIOCSBRK: case TIOCCBRK: if (tty->driver->ioctl) return tty->driver->ioctl(tty, file, cmd, arg); return -EINVAL; - + /* These two ioctl's always return success; even if */ /* the driver doesn't support them. */ case TCSBRK: @@ -3354,7 +3357,7 @@ int tty_ioctl(struct inode * inode, struct file * file, case TIOCSBRK: case TIOCCBRK: case TCSBRK: - case TCSBRKP: + case TCSBRKP: retval = tty_check_change(tty); if (retval) return retval; @@ -3367,81 +3370,80 @@ int tty_ioctl(struct inode * inode, struct file * file, } switch (cmd) { - case TIOCSTI: - return tiocsti(tty, p); - case TIOCGWINSZ: - return tiocgwinsz(tty, p); - case TIOCSWINSZ: - return tiocswinsz(tty, real_tty, p); - case TIOCCONS: - return real_tty!=tty ? -EINVAL : tioccons(file); - case FIONBIO: - return fionbio(file, p); - case TIOCEXCL: - set_bit(TTY_EXCLUSIVE, &tty->flags); - return 0; - case TIOCNXCL: - clear_bit(TTY_EXCLUSIVE, &tty->flags); - return 0; - case TIOCNOTTY: - if (current->signal->tty != tty) - return -ENOTTY; - no_tty(); - return 0; - case TIOCSCTTY: - return tiocsctty(tty, arg); - case TIOCGPGRP: - return tiocgpgrp(tty, real_tty, p); - case TIOCSPGRP: - return tiocspgrp(tty, real_tty, p); - case TIOCGSID: - return tiocgsid(tty, real_tty, p); - case TIOCGETD: - /* FIXME: check this is ok */ - return put_user(tty->ldisc.num, (int __user *)p); - case TIOCSETD: - return tiocsetd(tty, p); + case TIOCSTI: + return tiocsti(tty, p); + case TIOCGWINSZ: + return tiocgwinsz(tty, p); + case TIOCSWINSZ: + return tiocswinsz(tty, real_tty, p); + case TIOCCONS: + return real_tty != tty ? -EINVAL : tioccons(file); + case FIONBIO: + return fionbio(file, p); + case TIOCEXCL: + set_bit(TTY_EXCLUSIVE, &tty->flags); + return 0; + case TIOCNXCL: + clear_bit(TTY_EXCLUSIVE, &tty->flags); + return 0; + case TIOCNOTTY: + if (current->signal->tty != tty) + return -ENOTTY; + no_tty(); + return 0; + case TIOCSCTTY: + return tiocsctty(tty, arg); + case TIOCGPGRP: + return tiocgpgrp(tty, real_tty, p); + case TIOCSPGRP: + return tiocspgrp(tty, real_tty, p); + case TIOCGSID: + return tiocgsid(tty, real_tty, p); + case TIOCGETD: + /* FIXME: check this is ok */ + return put_user(tty->ldisc.num, (int __user *)p); + case TIOCSETD: + return tiocsetd(tty, p); #ifdef CONFIG_VT - case TIOCLINUX: - return tioclinux(tty, arg); + case TIOCLINUX: + return tioclinux(tty, arg); #endif - /* - * Break handling - */ - case TIOCSBRK: /* Turn break on, unconditionally */ - tty->driver->break_ctl(tty, -1); - return 0; - - case TIOCCBRK: /* Turn break off, unconditionally */ - tty->driver->break_ctl(tty, 0); - return 0; - case TCSBRK: /* SVID version: non-zero arg --> no break */ - /* non-zero arg means wait for all output data - * to be sent (performed above) but don't send break. - * This is used by the tcdrain() termios function. - */ - if (!arg) - return send_break(tty, 250); - return 0; - case TCSBRKP: /* support for POSIX tcsendbreak() */ - return send_break(tty, arg ? arg*100 : 250); - - case TIOCMGET: - return tty_tiocmget(tty, file, p); + /* + * Break handling + */ + case TIOCSBRK: /* Turn break on, unconditionally */ + tty->driver->break_ctl(tty, -1); + return 0; - case TIOCMSET: - case TIOCMBIC: - case TIOCMBIS: - return tty_tiocmset(tty, file, cmd, p); - case TCFLSH: - switch (arg) { - case TCIFLUSH: - case TCIOFLUSH: - /* flush tty buffer and allow ldisc to process ioctl */ - tty_buffer_flush(tty); - break; - } + case TIOCCBRK: /* Turn break off, unconditionally */ + tty->driver->break_ctl(tty, 0); + return 0; + case TCSBRK: /* SVID version: non-zero arg --> no break */ + /* non-zero arg means wait for all output data + * to be sent (performed above) but don't send break. + * This is used by the tcdrain() termios function. + */ + if (!arg) + return send_break(tty, 250); + return 0; + case TCSBRKP: /* support for POSIX tcsendbreak() */ + return send_break(tty, arg ? arg*100 : 250); + + case TIOCMGET: + return tty_tiocmget(tty, file, p); + case TIOCMSET: + case TIOCMBIC: + case TIOCMBIS: + return tty_tiocmset(tty, file, cmd, p); + case TCFLSH: + switch (arg) { + case TCIFLUSH: + case TCIOFLUSH: + /* flush tty buffer and allow ldisc to process ioctl */ + tty_buffer_flush(tty); break; + } + break; } if (tty->driver->ioctl) { retval = (tty->driver->ioctl)(tty, file, cmd, arg); @@ -3460,7 +3462,7 @@ int tty_ioctl(struct inode * inode, struct file * file, } #ifdef CONFIG_COMPAT -static long tty_compat_ioctl(struct file * file, unsigned int cmd, +static long tty_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct inode *inode = file->f_dentry->d_inode; @@ -3491,7 +3493,7 @@ static long tty_compat_ioctl(struct file * file, unsigned int cmd, * prevent trojan horses by killing all processes associated with this * tty when the user hits the "Secure Attention Key". Required for * super-paranoid applications --- see the Orange Book for more details. - * + * * This code could be nicer; ideally it should send a HUP, wait a few * seconds, then send a INT, and then a KILL signal. But you then * have to coordinate with the init process, since all processes associated @@ -3515,16 +3517,16 @@ void __do_SAK(struct tty_struct *tty) int i; struct file *filp; struct fdtable *fdt; - + if (!tty) return; session = tty->session; - + tty_ldisc_flush(tty); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - + read_lock(&tasklist_lock); /* Kill the entire session */ do_each_pid_task(session, PIDTYPE_SID, p) { @@ -3552,7 +3554,7 @@ void __do_SAK(struct tty_struct *tty) */ spin_lock(&p->files->file_lock); fdt = files_fdtable(p->files); - for (i=0; i < fdt->max_fds; i++) { + for (i = 0; i < fdt->max_fds; i++) { filp = fcheck_files(p->files, i); if (!filp) continue; @@ -3606,7 +3608,7 @@ EXPORT_SYMBOL(do_SAK); * while invoking the line discipline receive_buf method. The * receive_buf method is single threaded for each tty instance. */ - + static void flush_to_ldisc(struct work_struct *work) { struct tty_struct *tty = @@ -3622,7 +3624,8 @@ static void flush_to_ldisc(struct work_struct *work) return; spin_lock_irqsave(&tty->buf.lock, flags); - set_bit(TTY_FLUSHING, &tty->flags); /* So we know a flush is running */ + /* So we know a flush is running */ + set_bit(TTY_FLUSHING, &tty->flags); head = tty->buf.head; if (head != NULL) { tty->buf.head = NULL; @@ -3795,7 +3798,8 @@ struct device *tty_register_device(struct tty_driver *driver, unsigned index, void tty_unregister_device(struct tty_driver *driver, unsigned index) { - device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index); + device_destroy(tty_class, + MKDEV(driver->major, driver->minor_start) + index); } EXPORT_SYMBOL(tty_register_device); @@ -3859,7 +3863,7 @@ EXPORT_SYMBOL(tty_set_operations); int tty_register_driver(struct tty_driver *driver) { int error; - int i; + int i; dev_t dev; void **p = NULL; @@ -3873,8 +3877,8 @@ int tty_register_driver(struct tty_driver *driver) } if (!driver->major) { - error = alloc_chrdev_region(&dev, driver->minor_start, driver->num, - driver->name); + error = alloc_chrdev_region(&dev, driver->minor_start, + driver->num, driver->name); if (!error) { driver->major = MAJOR(dev); driver->minor_start = MINOR(dev); @@ -3891,7 +3895,8 @@ int tty_register_driver(struct tty_driver *driver) if (p) { driver->ttys = (struct tty_struct **)p; driver->termios = (struct ktermios **)(p + driver->num); - driver->termios_locked = (struct ktermios **)(p + driver->num * 2); + driver->termios_locked = (struct ktermios **) + (p + driver->num * 2); } else { driver->ttys = NULL; driver->termios = NULL; @@ -3911,13 +3916,13 @@ int tty_register_driver(struct tty_driver *driver) if (!driver->put_char) driver->put_char = tty_default_put_char; - + mutex_lock(&tty_mutex); list_add(&driver->tty_drivers, &tty_drivers); mutex_unlock(&tty_mutex); - - if ( !(driver->flags & TTY_DRIVER_DYNAMIC_DEV) ) { - for(i = 0; i < driver->num; i++) + + if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) { + for (i = 0; i < driver->num; i++) tty_register_device(driver, i, NULL); } proc_tty_register_driver(driver); @@ -4037,7 +4042,7 @@ void __init console_init(void) (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY); /* - * set up the console device so that later boot sequences can + * set up the console device so that later boot sequences can * inform about problems etc.. */ call = __con_initcall_start; diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index d4b6d64e858b..f95a80b2265f 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -50,11 +50,11 @@ * Locking: none */ -void tty_wait_until_sent(struct tty_struct * tty, long timeout) +void tty_wait_until_sent(struct tty_struct *tty, long timeout) { #ifdef TTY_DEBUG_WAIT_UNTIL_SENT char buf[64]; - + printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf)); #endif if (!tty->driver->chars_in_buffer) @@ -67,7 +67,6 @@ void tty_wait_until_sent(struct tty_struct * tty, long timeout) if (tty->driver->wait_until_sent) tty->driver->wait_until_sent(tty, timeout); } - EXPORT_SYMBOL(tty_wait_until_sent); static void unset_locked_termios(struct ktermios *termios, @@ -75,8 +74,8 @@ static void unset_locked_termios(struct ktermios *termios, struct ktermios *locked) { int i; - -#define NOSET_MASK(x,y,z) (x = ((x) & ~(z)) | ((y) & (z))) + +#define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z))) if (!locked) { printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n"); @@ -88,7 +87,7 @@ static void unset_locked_termios(struct ktermios *termios, NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag); NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag); termios->c_line = locked->c_line ? old->c_line : termios->c_line; - for (i=0; i < NCCS; i++) + for (i = 0; i < NCCS; i++) termios->c_cc[i] = locked->c_cc[i] ? old->c_cc[i] : termios->c_cc[i]; /* FIXME: What should we do for i/ospeed */ @@ -163,7 +162,6 @@ speed_t tty_termios_baud_rate(struct ktermios *termios) } return baud_table[cbaud]; } - EXPORT_SYMBOL(tty_termios_baud_rate); /** @@ -203,7 +201,6 @@ speed_t tty_termios_input_baud_rate(struct ktermios *termios) return tty_termios_baud_rate(termios); #endif } - EXPORT_SYMBOL(tty_termios_input_baud_rate); /** @@ -338,7 +335,6 @@ speed_t tty_get_baud_rate(struct tty_struct *tty) return baud; } - EXPORT_SYMBOL(tty_get_baud_rate); /** @@ -361,7 +357,6 @@ void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old) new->c_ispeed = old->c_ispeed; new->c_ospeed = old->c_ospeed; } - EXPORT_SYMBOL(tty_termios_copy_hw); /** @@ -395,16 +390,16 @@ EXPORT_SYMBOL(tty_termios_hw_change); * Locking: termios_sem */ -static void change_termios(struct tty_struct * tty, struct ktermios * new_termios) +static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) { int canon_change; struct ktermios old_termios = *tty->termios; struct tty_ldisc *ld; - + /* * Perform the actual termios internal changes under lock. */ - + /* FIXME: we need to decide on some locking/ordering semantics for the set_termios notification eventually */ @@ -419,7 +414,7 @@ static void change_termios(struct tty_struct * tty, struct ktermios * new_termio tty->canon_data = 0; tty->erasing = 0; } - + /* This bit should be in the ldisc code */ if (canon_change && !L_ICANON(tty) && tty->read_cnt) /* Get characters left over from canonical mode. */ @@ -442,7 +437,7 @@ static void change_termios(struct tty_struct * tty, struct ktermios * new_termio wake_up_interruptible(&tty->link->read_wait); } } - + if (tty->driver->set_termios) (*tty->driver->set_termios)(tty, &old_termios); else @@ -470,7 +465,7 @@ static void change_termios(struct tty_struct * tty, struct ktermios * new_termio * Called functions take ldisc and termios_sem locks */ -static int set_termios(struct tty_struct * tty, void __user *arg, int opt) +static int set_termios(struct tty_struct *tty, void __user *arg, int opt) { struct ktermios tmp_termios; struct tty_ldisc *ld; @@ -501,19 +496,19 @@ static int set_termios(struct tty_struct * tty, void __user *arg, int opt) return -EFAULT; #endif - /* If old style Bfoo values are used then load c_ispeed/c_ospeed with the real speed - so its unconditionally usable */ + /* If old style Bfoo values are used then load c_ispeed/c_ospeed + * with the real speed so its unconditionally usable */ tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios); tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios); ld = tty_ldisc_ref(tty); - + if (ld != NULL) { if ((opt & TERMIOS_FLUSH) && ld->flush_buffer) ld->flush_buffer(tty); tty_ldisc_deref(ld); } - + if (opt & TERMIOS_WAIT) { tty_wait_until_sent(tty, 0); if (signal_pending(current)) @@ -529,14 +524,14 @@ static int set_termios(struct tty_struct * tty, void __user *arg, int opt) return 0; } -static int get_termio(struct tty_struct * tty, struct termio __user * termio) +static int get_termio(struct tty_struct *tty, struct termio __user *termio) { if (kernel_termios_to_user_termio(termio, tty->termios)) return -EFAULT; return 0; } -static unsigned long inq_canon(struct tty_struct * tty) +static unsigned long inq_canon(struct tty_struct *tty) { int nr, head, tail; @@ -561,7 +556,7 @@ static unsigned long inq_canon(struct tty_struct * tty) * * The "sg_flags" translation is a joke.. */ -static int get_sgflags(struct tty_struct * tty) +static int get_sgflags(struct tty_struct *tty) { int flags = 0; @@ -579,7 +574,7 @@ static int get_sgflags(struct tty_struct * tty) return flags; } -static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) +static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb) { struct sgttyb tmp; @@ -590,11 +585,11 @@ static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) tmp.sg_kill = tty->termios->c_cc[VKILL]; tmp.sg_flags = get_sgflags(tty); mutex_unlock(&tty->termios_mutex); - + return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0; } -static void set_sgflags(struct ktermios * termios, int flags) +static void set_sgflags(struct ktermios *termios, int flags) { termios->c_iflag = ICRNL | IXON; termios->c_oflag = 0; @@ -631,7 +626,7 @@ static void set_sgflags(struct ktermios * termios, int flags) * Locking: termios_sem */ -static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) +static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb) { int retval; struct sgttyb tmp; @@ -640,7 +635,7 @@ static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) retval = tty_check_change(tty); if (retval) return retval; - + if (copy_from_user(&tmp, sgttyb, sizeof(tmp))) return -EFAULT; @@ -651,7 +646,8 @@ static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) set_sgflags(&termios, tmp.sg_flags); /* Try and encode into Bfoo format */ #ifdef BOTHER - tty_termios_encode_baud_rate(&termios, termios.c_ispeed, termios.c_ospeed); + tty_termios_encode_baud_rate(&termios, termios.c_ispeed, + termios.c_ospeed); #endif mutex_unlock(&tty->termios_mutex); change_termios(tty, &termios); @@ -660,7 +656,7 @@ static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) #endif #ifdef TIOCGETC -static int get_tchars(struct tty_struct * tty, struct tchars __user * tchars) +static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars) { struct tchars tmp; @@ -673,7 +669,7 @@ static int get_tchars(struct tty_struct * tty, struct tchars __user * tchars) return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0; } -static int set_tchars(struct tty_struct * tty, struct tchars __user * tchars) +static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars) { struct tchars tmp; @@ -690,20 +686,22 @@ static int set_tchars(struct tty_struct * tty, struct tchars __user * tchars) #endif #ifdef TIOCGLTC -static int get_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars) +static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars) { struct ltchars tmp; tmp.t_suspc = tty->termios->c_cc[VSUSP]; - tmp.t_dsuspc = tty->termios->c_cc[VSUSP]; /* what is dsuspc anyway? */ + /* what is dsuspc anyway? */ + tmp.t_dsuspc = tty->termios->c_cc[VSUSP]; tmp.t_rprntc = tty->termios->c_cc[VREPRINT]; - tmp.t_flushc = tty->termios->c_cc[VEOL2]; /* what is flushc anyway? */ + /* what is flushc anyway? */ + tmp.t_flushc = tty->termios->c_cc[VEOL2]; tmp.t_werasc = tty->termios->c_cc[VWERASE]; tmp.t_lnextc = tty->termios->c_cc[VLNEXT]; return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0; } -static int set_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars) +static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars) { struct ltchars tmp; @@ -711,9 +709,11 @@ static int set_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars) return -EFAULT; tty->termios->c_cc[VSUSP] = tmp.t_suspc; - tty->termios->c_cc[VEOL2] = tmp.t_dsuspc; /* what is dsuspc anyway? */ + /* what is dsuspc anyway? */ + tty->termios->c_cc[VEOL2] = tmp.t_dsuspc; tty->termios->c_cc[VREPRINT] = tmp.t_rprntc; - tty->termios->c_cc[VEOL2] = tmp.t_flushc; /* what is flushc anyway? */ + /* what is flushc anyway? */ + tty->termios->c_cc[VEOL2] = tmp.t_flushc; tty->termios->c_cc[VWERASE] = tmp.t_werasc; tty->termios->c_cc[VLNEXT] = tmp.t_lnextc; return 0; @@ -761,10 +761,10 @@ static int send_prio_char(struct tty_struct *tty, char ch) * consistent mode setting. */ -int tty_mode_ioctl(struct tty_struct * tty, struct file *file, +int tty_mode_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - struct tty_struct * real_tty; + struct tty_struct *real_tty; void __user *p = (void __user *)arg; if (tty->driver->type == TTY_DRIVER_TYPE_PTY && @@ -775,100 +775,100 @@ int tty_mode_ioctl(struct tty_struct * tty, struct file *file, switch (cmd) { #ifdef TIOCGETP - case TIOCGETP: - return get_sgttyb(real_tty, (struct sgttyb __user *) arg); - case TIOCSETP: - case TIOCSETN: - return set_sgttyb(real_tty, (struct sgttyb __user *) arg); + case TIOCGETP: + return get_sgttyb(real_tty, (struct sgttyb __user *) arg); + case TIOCSETP: + case TIOCSETN: + return set_sgttyb(real_tty, (struct sgttyb __user *) arg); #endif #ifdef TIOCGETC - case TIOCGETC: - return get_tchars(real_tty, p); - case TIOCSETC: - return set_tchars(real_tty, p); + case TIOCGETC: + return get_tchars(real_tty, p); + case TIOCSETC: + return set_tchars(real_tty, p); #endif #ifdef TIOCGLTC - case TIOCGLTC: - return get_ltchars(real_tty, p); - case TIOCSLTC: - return set_ltchars(real_tty, p); + case TIOCGLTC: + return get_ltchars(real_tty, p); + case TIOCSLTC: + return set_ltchars(real_tty, p); #endif - case TCSETSF: - return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD); - case TCSETSW: - return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD); - case TCSETS: - return set_termios(real_tty, p, TERMIOS_OLD); + case TCSETSF: + return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD); + case TCSETSW: + return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD); + case TCSETS: + return set_termios(real_tty, p, TERMIOS_OLD); #ifndef TCGETS2 - case TCGETS: - if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios)) - return -EFAULT; - return 0; + case TCGETS: + if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios)) + return -EFAULT; + return 0; #else - case TCGETS: - if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios)) - return -EFAULT; - return 0; - case TCGETS2: - if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios)) - return -EFAULT; - return 0; - case TCSETSF2: - return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT); - case TCSETSW2: - return set_termios(real_tty, p, TERMIOS_WAIT); - case TCSETS2: - return set_termios(real_tty, p, 0); + case TCGETS: + if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios)) + return -EFAULT; + return 0; + case TCGETS2: + if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios)) + return -EFAULT; + return 0; + case TCSETSF2: + return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT); + case TCSETSW2: + return set_termios(real_tty, p, TERMIOS_WAIT); + case TCSETS2: + return set_termios(real_tty, p, 0); #endif - case TCGETA: - return get_termio(real_tty, p); - case TCSETAF: - return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO); - case TCSETAW: - return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO); - case TCSETA: - return set_termios(real_tty, p, TERMIOS_TERMIO); + case TCGETA: + return get_termio(real_tty, p); + case TCSETAF: + return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO); + case TCSETAW: + return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO); + case TCSETA: + return set_termios(real_tty, p, TERMIOS_TERMIO); #ifndef TCGETS2 - case TIOCGLCKTRMIOS: - if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked)) - return -EFAULT; - return 0; - - case TIOCSLCKTRMIOS: - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios __user *) arg)) - return -EFAULT; - return 0; + case TIOCGLCKTRMIOS: + if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked)) + return -EFAULT; + return 0; + case TIOCSLCKTRMIOS: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (user_termios_to_kernel_termios(real_tty->termios_locked, + (struct termios __user *) arg)) + return -EFAULT; + return 0; #else - case TIOCGLCKTRMIOS: - if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked)) - return -EFAULT; - return 0; - - case TIOCSLCKTRMIOS: - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (user_termios_to_kernel_termios_1(real_tty->termios_locked, (struct termios __user *) arg)) - return -EFAULT; + case TIOCGLCKTRMIOS: + if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked)) + return -EFAULT; + return 0; + case TIOCSLCKTRMIOS: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (user_termios_to_kernel_termios_1(real_tty->termios_locked, + (struct termios __user *) arg)) + return -EFAULT; return 0; #endif - case TIOCGSOFTCAR: - return put_user(C_CLOCAL(tty) ? 1 : 0, (int __user *)arg); - case TIOCSSOFTCAR: - if (get_user(arg, (unsigned int __user *) arg)) - return -EFAULT; - mutex_lock(&tty->termios_mutex); - tty->termios->c_cflag = - ((tty->termios->c_cflag & ~CLOCAL) | - (arg ? CLOCAL : 0)); - mutex_unlock(&tty->termios_mutex); - return 0; - default: - return -ENOIOCTLCMD; + case TIOCGSOFTCAR: + return put_user(C_CLOCAL(tty) ? 1 : 0, + (int __user *)arg); + case TIOCSSOFTCAR: + if (get_user(arg, (unsigned int __user *) arg)) + return -EFAULT; + mutex_lock(&tty->termios_mutex); + tty->termios->c_cflag = + ((tty->termios->c_cflag & ~CLOCAL) | + (arg ? CLOCAL : 0)); + mutex_unlock(&tty->termios_mutex); + return 0; + default: + return -ENOIOCTLCMD; } } - EXPORT_SYMBOL_GPL(tty_mode_ioctl); int tty_perform_flush(struct tty_struct *tty, unsigned long arg) @@ -899,13 +899,12 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg) tty_ldisc_deref(ld); return 0; } - EXPORT_SYMBOL_GPL(tty_perform_flush); -int n_tty_ioctl(struct tty_struct * tty, struct file * file, +int n_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - struct tty_struct * real_tty; + struct tty_struct *real_tty; int retval; if (tty->driver->type == TTY_DRIVER_TYPE_PTY && @@ -915,68 +914,67 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, real_tty = tty; switch (cmd) { - case TCXONC: - retval = tty_check_change(tty); - if (retval) - return retval; - switch (arg) { - case TCOOFF: - if (!tty->flow_stopped) { - tty->flow_stopped = 1; - stop_tty(tty); - } - break; - case TCOON: - if (tty->flow_stopped) { - tty->flow_stopped = 0; - start_tty(tty); - } - break; - case TCIOFF: - if (STOP_CHAR(tty) != __DISABLED_CHAR) - return send_prio_char(tty, STOP_CHAR(tty)); - break; - case TCION: - if (START_CHAR(tty) != __DISABLED_CHAR) - return send_prio_char(tty, START_CHAR(tty)); - break; - default: - return -EINVAL; + case TCXONC: + retval = tty_check_change(tty); + if (retval) + return retval; + switch (arg) { + case TCOOFF: + if (!tty->flow_stopped) { + tty->flow_stopped = 1; + stop_tty(tty); } - return 0; - case TCFLSH: - return tty_perform_flush(tty, arg); - case TIOCOUTQ: - return put_user(tty->driver->chars_in_buffer ? - tty->driver->chars_in_buffer(tty) : 0, - (int __user *) arg); - case TIOCINQ: - retval = tty->read_cnt; - if (L_ICANON(tty)) - retval = inq_canon(tty); - return put_user(retval, (unsigned int __user *) arg); - case TIOCPKT: - { - int pktmode; - - if (tty->driver->type != TTY_DRIVER_TYPE_PTY || - tty->driver->subtype != PTY_TYPE_MASTER) - return -ENOTTY; - if (get_user(pktmode, (int __user *) arg)) - return -EFAULT; - if (pktmode) { - if (!tty->packet) { - tty->packet = 1; - tty->link->ctrl_status = 0; - } - } else - tty->packet = 0; - return 0; - } + break; + case TCOON: + if (tty->flow_stopped) { + tty->flow_stopped = 0; + start_tty(tty); + } + break; + case TCIOFF: + if (STOP_CHAR(tty) != __DISABLED_CHAR) + return send_prio_char(tty, STOP_CHAR(tty)); + break; + case TCION: + if (START_CHAR(tty) != __DISABLED_CHAR) + return send_prio_char(tty, START_CHAR(tty)); + break; default: - /* Try the mode commands */ - return tty_mode_ioctl(tty, file, cmd, arg); + return -EINVAL; } + return 0; + case TCFLSH: + return tty_perform_flush(tty, arg); + case TIOCOUTQ: + return put_user(tty->driver->chars_in_buffer ? + tty->driver->chars_in_buffer(tty) : 0, + (int __user *) arg); + case TIOCINQ: + retval = tty->read_cnt; + if (L_ICANON(tty)) + retval = inq_canon(tty); + return put_user(retval, (unsigned int __user *) arg); + case TIOCPKT: + { + int pktmode; + + if (tty->driver->type != TTY_DRIVER_TYPE_PTY || + tty->driver->subtype != PTY_TYPE_MASTER) + return -ENOTTY; + if (get_user(pktmode, (int __user *) arg)) + return -EFAULT; + if (pktmode) { + if (!tty->packet) { + tty->packet = 1; + tty->link->ctrl_status = 0; + } + } else + tty->packet = 0; + return 0; + } + default: + /* Try the mode commands */ + return tty_mode_ioctl(tty, file, cmd, arg); + } } - EXPORT_SYMBOL(n_tty_ioctl); diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 1412d7bcdbd1..653265a40b7f 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -250,6 +250,28 @@ static void __init dmi_save_ipmi_device(const struct dmi_header *dm) list_add(&dev->list, &dmi_devices); } +static void __init dmi_save_extended_devices(const struct dmi_header *dm) +{ + const u8 *d = (u8*) dm + 5; + struct dmi_device *dev; + + /* Skip disabled device */ + if ((*d & 0x80) == 0) + return; + + dev = dmi_alloc(sizeof(*dev)); + if (!dev) { + printk(KERN_ERR "dmi_save_extended_devices: out of memory.\n"); + return; + } + + dev->type = *d-- & 0x7f; + dev->name = dmi_string(dm, *d); + dev->device_data = NULL; + + list_add(&dev->list, &dmi_devices); +} + /* * Process a DMI table entry. Right now all we care about are the BIOS * and machine entries. For 2.5 we should pull the smbus controller info @@ -292,6 +314,9 @@ static void __init dmi_decode(const struct dmi_header *dm) break; case 38: /* IPMI Device Information */ dmi_save_ipmi_device(dm); + break; + case 41: /* Onboard Devices Extended Information */ + dmi_save_extended_devices(dm); } } diff --git a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c index 06190b1c4ec5..38fbfb8d5445 100644 --- a/drivers/ide/ppc/mpc8xx.c +++ b/drivers/ide/ppc/mpc8xx.c @@ -17,7 +17,6 @@ #include <linux/ptrace.h> #include <linux/slab.h> #include <linux/user.h> -#include <linux/a.out.h> #include <linux/tty.h> #include <linux/major.h> #include <linux/interrupt.h> diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c index f32e031dcb27..708c5ae13b24 100644 --- a/drivers/input/joystick/analog.c +++ b/drivers/input/joystick/analog.c @@ -1,6 +1,4 @@ /* - * $Id: analog.c,v 1.68 2002/01/22 20:18:32 vojtech Exp $ - * * Copyright (c) 1996-2001 Vojtech Pavlik */ @@ -164,6 +162,10 @@ static unsigned int get_time_pit(void) #define GET_TIME(x) do { x = get_cycles(); } while (0) #define DELTA(x,y) ((y)-(x)) #define TIME_NAME "PCC" +#elif defined(CONFIG_MN10300) +#define GET_TIME(x) do { x = get_cycles(); } while (0) +#define DELTA(x, y) ((x) - (y)) +#define TIME_NAME "TSC" #else #define FAKE_TIME static unsigned long analog_faketime = 0; diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c index 2dd1b57b0ba4..6d7c47ec0367 100644 --- a/drivers/isdn/capi/capifs.c +++ b/drivers/isdn/capi/capifs.c @@ -52,6 +52,7 @@ static int capifs_remount(struct super_block *s, int *flags, char *data) gid_t gid = 0; umode_t mode = 0600; char *this_char; + char *new_opt = kstrdup(data, GFP_KERNEL); this_char = NULL; while ((this_char = strsep(&data, ",")) != NULL) { @@ -72,11 +73,16 @@ static int capifs_remount(struct super_block *s, int *flags, char *data) return -EINVAL; } } + + kfree(s->s_options); + s->s_options = new_opt; + config.setuid = setuid; config.setgid = setgid; config.uid = uid; config.gid = gid; config.mode = mode; + return 0; } @@ -84,6 +90,7 @@ static struct super_operations capifs_sops = { .statfs = simple_statfs, .remount_fs = capifs_remount, + .show_options = generic_show_options, }; diff --git a/drivers/isdn/hisax/amd7930_fn.c b/drivers/isdn/hisax/amd7930_fn.c index c0d7036404a5..341faf58a65c 100644 --- a/drivers/isdn/hisax/amd7930_fn.c +++ b/drivers/isdn/hisax/amd7930_fn.c @@ -744,8 +744,7 @@ dbusy_timer_handler(struct IsdnCardState *cs) -void __devinit -Amd7930_init(struct IsdnCardState *cs) +void Amd7930_init(struct IsdnCardState *cs) { WORD *ptr; BYTE cmd, cnt; diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 851a3b01781e..859814f62cb0 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -18,6 +18,13 @@ config LEDS_CLASS comment "LED drivers" +config LEDS_ATMEL_PWM + tristate "LED Support using Atmel PWM outputs" + depends on LEDS_CLASS && ATMEL_PWM + help + This option enables support for LEDs driven using outputs + of the dedicated PWM controller found on newer Atmel SOCs. + config LEDS_CORGI tristate "LED Support for the Sharp SL-C7x0 series" depends on LEDS_CLASS && PXA_SHARP_C7xx diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index bc6afc8dcb27..84ced3b1a13d 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_LEDS_CLASS) += led-class.o obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o # LED Platform Drivers +obj-$(CONFIG_LEDS_ATMEL_PWM) += leds-atmel-pwm.o obj-$(CONFIG_LEDS_CORGI) += leds-corgi.o obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o obj-$(CONFIG_LEDS_SPITZ) += leds-spitz.o diff --git a/drivers/leds/leds-atmel-pwm.c b/drivers/leds/leds-atmel-pwm.c new file mode 100644 index 000000000000..af61f55571fe --- /dev/null +++ b/drivers/leds/leds-atmel-pwm.c @@ -0,0 +1,157 @@ +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/leds.h> +#include <linux/io.h> +#include <linux/atmel_pwm.h> + + +struct pwmled { + struct led_classdev cdev; + struct pwm_channel pwmc; + struct gpio_led *desc; + u32 mult; + u8 active_low; +}; + + +/* + * For simplicity, we use "brightness" as if it were a linear function + * of PWM duty cycle. However, a logarithmic function of duty cycle is + * probably a better match for perceived brightness: two is half as bright + * as four, four is half as bright as eight, etc + */ +static void pwmled_brightness(struct led_classdev *cdev, enum led_brightness b) +{ + struct pwmled *led; + + /* update the duty cycle for the *next* period */ + led = container_of(cdev, struct pwmled, cdev); + pwm_channel_writel(&led->pwmc, PWM_CUPD, led->mult * (unsigned) b); +} + +/* + * NOTE: we reuse the platform_data structure of GPIO leds, + * but repurpose its "gpio" number as a PWM channel number. + */ +static int __init pwmled_probe(struct platform_device *pdev) +{ + const struct gpio_led_platform_data *pdata; + struct pwmled *leds; + unsigned i; + int status; + + pdata = pdev->dev.platform_data; + if (!pdata || pdata->num_leds < 1) + return -ENODEV; + + leds = kcalloc(pdata->num_leds, sizeof(*leds), GFP_KERNEL); + if (!leds) + return -ENOMEM; + + for (i = 0; i < pdata->num_leds; i++) { + struct pwmled *led = leds + i; + const struct gpio_led *dat = pdata->leds + i; + u32 tmp; + + led->cdev.name = dat->name; + led->cdev.brightness = LED_OFF; + led->cdev.brightness_set = pwmled_brightness; + led->cdev.default_trigger = dat->default_trigger; + + led->active_low = dat->active_low; + + status = pwm_channel_alloc(dat->gpio, &led->pwmc); + if (status < 0) + goto err; + + /* + * Prescale clock by 2^x, so PWM counts in low MHz. + * Start each cycle with the LED active, so increasing + * the duty cycle gives us more time on (== brighter). + */ + tmp = 5; + if (!led->active_low) + tmp |= PWM_CPR_CPOL; + pwm_channel_writel(&led->pwmc, PWM_CMR, tmp); + + /* + * Pick a period so PWM cycles at 100+ Hz; and a multiplier + * for scaling duty cycle: brightness * mult. + */ + tmp = (led->pwmc.mck / (1 << 5)) / 100; + tmp /= 255; + led->mult = tmp; + pwm_channel_writel(&led->pwmc, PWM_CDTY, + led->cdev.brightness * 255); + pwm_channel_writel(&led->pwmc, PWM_CPRD, + LED_FULL * tmp); + + pwm_channel_enable(&led->pwmc); + + /* Hand it over to the LED framework */ + status = led_classdev_register(&pdev->dev, &led->cdev); + if (status < 0) { + pwm_channel_free(&led->pwmc); + goto err; + } + } + + platform_set_drvdata(pdev, leds); + return 0; + +err: + if (i > 0) { + for (i = i - 1; i >= 0; i--) { + led_classdev_unregister(&leds[i].cdev); + pwm_channel_free(&leds[i].pwmc); + } + } + kfree(leds); + + return status; +} + +static int __exit pwmled_remove(struct platform_device *pdev) +{ + const struct gpio_led_platform_data *pdata; + struct pwmled *leds; + unsigned i; + + pdata = pdev->dev.platform_data; + leds = platform_get_drvdata(pdev); + + for (i = 0; i < pdata->num_leds; i++) { + struct pwmled *led = leds + i; + + led_classdev_unregister(&led->cdev); + pwm_channel_free(&led->pwmc); + } + + kfree(leds); + platform_set_drvdata(pdev, NULL); + return 0; +} + +static struct platform_driver pwmled_driver = { + .driver = { + .name = "leds-atmel-pwm", + .owner = THIS_MODULE, + }, + /* REVISIT add suspend() and resume() methods */ + .remove = __exit_p(pwmled_remove), +}; + +static int __init modinit(void) +{ + return platform_driver_probe(&pwmled_driver, pwmled_probe); +} +module_init(modinit); + +static void __exit modexit(void) +{ + platform_driver_unregister(&pwmled_driver); +} +module_exit(modexit); + +MODULE_DESCRIPTION("Driver for LEDs with PWM-controlled brightness"); +MODULE_LICENSE("GPL"); diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c index 84f85e23cca7..1b2ec0bf5eb1 100644 --- a/drivers/lguest/lguest_device.c +++ b/drivers/lguest/lguest_device.c @@ -47,7 +47,7 @@ struct lguest_device { /* Since the virtio infrastructure hands us a pointer to the virtio_device all * the time, it helps to have a curt macro to get a pointer to the struct * lguest_device it's enclosed in. */ -#define to_lgdev(vdev) container_of(vdev, struct lguest_device, vdev) +#define to_lgdev(vd) container_of(vd, struct lguest_device, vdev) /*D:130 * Device configurations diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 7b5220ca7d7f..c143a86c2ea6 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -13,6 +13,15 @@ menuconfig MISC_DEVICES if MISC_DEVICES +config ATMEL_PWM + tristate "Atmel AT32/AT91 PWM support" + depends on AVR32 || ARCH_AT91 + help + This option enables device driver support for the PWM channels + on certain Atmel prcoessors. Pulse Width Modulation is used for + purposes including software controlled power-efficent backlights + on LCD displays, motor control, and waveform generation. + config IBM_ASM tristate "Device driver for IBM RSA service processor" depends on X86 && PCI && INPUT && EXPERIMENTAL @@ -97,9 +106,9 @@ config ACER_WMI depends on X86 depends on EXPERIMENTAL depends on ACPI - depends on ACPI_WMI depends on LEDS_CLASS depends on BACKLIGHT_CLASS_DEVICE + select ACPI_WMI ---help--- This is a driver for newer Acer (and Wistron) laptops. It adds wireless radio and bluetooth control, and on some laptops, @@ -146,7 +155,7 @@ config TC1100_WMI tristate "HP Compaq TC1100 Tablet WMI Extras" depends on X86 && !X86_64 depends on ACPI - depends on ACPI_WMI + select ACPI_WMI ---help--- This is a driver for the WMI extensions (wireless and bluetooth power control) of the HP Compaq TC1100 tablet. @@ -279,6 +288,7 @@ config ATMEL_SSC config INTEL_MENLOW tristate "Thermal Management driver for Intel menlow platform" depends on ACPI_THERMAL + depends on X86 ---help--- ACPI thermal management enhancement driver on Intel Menlow platform. diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 7f13549cc87e..3b12f5da8562 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o obj-$(CONFIG_ACER_WMI) += acer-wmi.o obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o +obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o obj-$(CONFIG_LKDTM) += lkdtm.o diff --git a/drivers/misc/atmel_pwm.c b/drivers/misc/atmel_pwm.c new file mode 100644 index 000000000000..f8d3b9a76cbd --- /dev/null +++ b/drivers/misc/atmel_pwm.c @@ -0,0 +1,409 @@ +#include <linux/module.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/atmel_pwm.h> + + +/* + * This is a simple driver for the PWM controller found in various newer + * Atmel SOCs, including the AVR32 series and the AT91sam9263. + * + * Chips with current Linux ports have only 4 PWM channels, out of max 32. + * AT32UC3A and AT32UC3B chips have 7 channels (but currently no Linux). + * Docs are inconsistent about the width of the channel counter registers; + * it's at least 16 bits, but several places say 20 bits. + */ +#define PWM_NCHAN 4 /* max 32 */ + +struct pwm { + spinlock_t lock; + struct platform_device *pdev; + u32 mask; + int irq; + void __iomem *base; + struct clk *clk; + struct pwm_channel *channel[PWM_NCHAN]; + void (*handler[PWM_NCHAN])(struct pwm_channel *); +}; + + +/* global PWM controller registers */ +#define PWM_MR 0x00 +#define PWM_ENA 0x04 +#define PWM_DIS 0x08 +#define PWM_SR 0x0c +#define PWM_IER 0x10 +#define PWM_IDR 0x14 +#define PWM_IMR 0x18 +#define PWM_ISR 0x1c + +static inline void pwm_writel(const struct pwm *p, unsigned offset, u32 val) +{ + __raw_writel(val, p->base + offset); +} + +static inline u32 pwm_readl(const struct pwm *p, unsigned offset) +{ + return __raw_readl(p->base + offset); +} + +static inline void __iomem *pwmc_regs(const struct pwm *p, int index) +{ + return p->base + 0x200 + index * 0x20; +} + +static struct pwm *pwm; + +static void pwm_dumpregs(struct pwm_channel *ch, char *tag) +{ + struct device *dev = &pwm->pdev->dev; + + dev_dbg(dev, "%s: mr %08x, sr %08x, imr %08x\n", + tag, + pwm_readl(pwm, PWM_MR), + pwm_readl(pwm, PWM_SR), + pwm_readl(pwm, PWM_IMR)); + dev_dbg(dev, + "pwm ch%d - mr %08x, dty %u, prd %u, cnt %u\n", + ch->index, + pwm_channel_readl(ch, PWM_CMR), + pwm_channel_readl(ch, PWM_CDTY), + pwm_channel_readl(ch, PWM_CPRD), + pwm_channel_readl(ch, PWM_CCNT)); +} + + +/** + * pwm_channel_alloc - allocate an unused PWM channel + * @index: identifies the channel + * @ch: structure to be initialized + * + * Drivers allocate PWM channels according to the board's wiring, and + * matching board-specific setup code. Returns zero or negative errno. + */ +int pwm_channel_alloc(int index, struct pwm_channel *ch) +{ + unsigned long flags; + int status = 0; + + /* insist on PWM init, with this signal pinned out */ + if (!pwm || !(pwm->mask & 1 << index)) + return -ENODEV; + + if (index < 0 || index >= PWM_NCHAN || !ch) + return -EINVAL; + memset(ch, 0, sizeof *ch); + + spin_lock_irqsave(&pwm->lock, flags); + if (pwm->channel[index]) + status = -EBUSY; + else { + clk_enable(pwm->clk); + + ch->regs = pwmc_regs(pwm, index); + ch->index = index; + + /* REVISIT: ap7000 seems to go 2x as fast as we expect!! */ + ch->mck = clk_get_rate(pwm->clk); + + pwm->channel[index] = ch; + pwm->handler[index] = NULL; + + /* channel and irq are always disabled when we return */ + pwm_writel(pwm, PWM_DIS, 1 << index); + pwm_writel(pwm, PWM_IDR, 1 << index); + } + spin_unlock_irqrestore(&pwm->lock, flags); + return status; +} +EXPORT_SYMBOL(pwm_channel_alloc); + +static int pwmcheck(struct pwm_channel *ch) +{ + int index; + + if (!pwm) + return -ENODEV; + if (!ch) + return -EINVAL; + index = ch->index; + if (index < 0 || index >= PWM_NCHAN || pwm->channel[index] != ch) + return -EINVAL; + + return index; +} + +/** + * pwm_channel_free - release a previously allocated channel + * @ch: the channel being released + * + * The channel is completely shut down (counter and IRQ disabled), + * and made available for re-use. Returns zero, or negative errno. + */ +int pwm_channel_free(struct pwm_channel *ch) +{ + unsigned long flags; + int t; + + spin_lock_irqsave(&pwm->lock, flags); + t = pwmcheck(ch); + if (t >= 0) { + pwm->channel[t] = NULL; + pwm->handler[t] = NULL; + + /* channel and irq are always disabled when we return */ + pwm_writel(pwm, PWM_DIS, 1 << t); + pwm_writel(pwm, PWM_IDR, 1 << t); + + clk_disable(pwm->clk); + t = 0; + } + spin_unlock_irqrestore(&pwm->lock, flags); + return t; +} +EXPORT_SYMBOL(pwm_channel_free); + +int __pwm_channel_onoff(struct pwm_channel *ch, int enabled) +{ + unsigned long flags; + int t; + + /* OMITTED FUNCTIONALITY: starting several channels in synch */ + + spin_lock_irqsave(&pwm->lock, flags); + t = pwmcheck(ch); + if (t >= 0) { + pwm_writel(pwm, enabled ? PWM_ENA : PWM_DIS, 1 << t); + t = 0; + pwm_dumpregs(ch, enabled ? "enable" : "disable"); + } + spin_unlock_irqrestore(&pwm->lock, flags); + + return t; +} +EXPORT_SYMBOL(__pwm_channel_onoff); + +/** + * pwm_clk_alloc - allocate and configure CLKA or CLKB + * @prescale: from 0..10, the power of two used to divide MCK + * @div: from 1..255, the linear divisor to use + * + * Returns PWM_CPR_CLKA, PWM_CPR_CLKB, or negative errno. The allocated + * clock will run with a period of (2^prescale * div) / MCK, or twice as + * long if center aligned PWM output is used. The clock must later be + * deconfigured using pwm_clk_free(). + */ +int pwm_clk_alloc(unsigned prescale, unsigned div) +{ + unsigned long flags; + u32 mr; + u32 val = (prescale << 8) | div; + int ret = -EBUSY; + + if (prescale >= 10 || div == 0 || div > 255) + return -EINVAL; + + spin_lock_irqsave(&pwm->lock, flags); + mr = pwm_readl(pwm, PWM_MR); + if ((mr & 0xffff) == 0) { + mr |= val; + ret = PWM_CPR_CLKA; + } + if ((mr & (0xffff << 16)) == 0) { + mr |= val << 16; + ret = PWM_CPR_CLKB; + } + if (ret > 0) + pwm_writel(pwm, PWM_MR, mr); + spin_unlock_irqrestore(&pwm->lock, flags); + return ret; +} +EXPORT_SYMBOL(pwm_clk_alloc); + +/** + * pwm_clk_free - deconfigure and release CLKA or CLKB + * + * Reverses the effect of pwm_clk_alloc(). + */ +void pwm_clk_free(unsigned clk) +{ + unsigned long flags; + u32 mr; + + spin_lock_irqsave(&pwm->lock, flags); + mr = pwm_readl(pwm, PWM_MR); + if (clk == PWM_CPR_CLKA) + pwm_writel(pwm, PWM_MR, mr & ~(0xffff << 0)); + if (clk == PWM_CPR_CLKB) + pwm_writel(pwm, PWM_MR, mr & ~(0xffff << 16)); + spin_unlock_irqrestore(&pwm->lock, flags); +} +EXPORT_SYMBOL(pwm_clk_free); + +/** + * pwm_channel_handler - manage channel's IRQ handler + * @ch: the channel + * @handler: the handler to use, possibly NULL + * + * If the handler is non-null, the handler will be called after every + * period of this PWM channel. If the handler is null, this channel + * won't generate an IRQ. + */ +int pwm_channel_handler(struct pwm_channel *ch, + void (*handler)(struct pwm_channel *ch)) +{ + unsigned long flags; + int t; + + spin_lock_irqsave(&pwm->lock, flags); + t = pwmcheck(ch); + if (t >= 0) { + pwm->handler[t] = handler; + pwm_writel(pwm, handler ? PWM_IER : PWM_IDR, 1 << t); + t = 0; + } + spin_unlock_irqrestore(&pwm->lock, flags); + + return t; +} +EXPORT_SYMBOL(pwm_channel_handler); + +static irqreturn_t pwm_irq(int id, void *_pwm) +{ + struct pwm *p = _pwm; + irqreturn_t handled = IRQ_NONE; + u32 irqstat; + int index; + + spin_lock(&p->lock); + + /* ack irqs, then handle them */ + irqstat = pwm_readl(pwm, PWM_ISR); + + while (irqstat) { + struct pwm_channel *ch; + void (*handler)(struct pwm_channel *ch); + + index = ffs(irqstat) - 1; + irqstat &= ~(1 << index); + ch = pwm->channel[index]; + handler = pwm->handler[index]; + if (handler && ch) { + spin_unlock(&p->lock); + handler(ch); + spin_lock(&p->lock); + handled = IRQ_HANDLED; + } + } + + spin_unlock(&p->lock); + return handled; +} + +static int __init pwm_probe(struct platform_device *pdev) +{ + struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + int irq = platform_get_irq(pdev, 0); + u32 *mp = pdev->dev.platform_data; + struct pwm *p; + int status = -EIO; + + if (pwm) + return -EBUSY; + if (!r || irq < 0 || !mp || !*mp) + return -ENODEV; + if (*mp & ~((1<<PWM_NCHAN)-1)) { + dev_warn(&pdev->dev, "mask 0x%x ... more than %d channels\n", + *mp, PWM_NCHAN); + return -EINVAL; + } + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; + + spin_lock_init(&p->lock); + p->pdev = pdev; + p->mask = *mp; + p->irq = irq; + p->base = ioremap(r->start, r->end - r->start + 1); + if (!p->base) + goto fail; + p->clk = clk_get(&pdev->dev, "mck"); + if (IS_ERR(p->clk)) { + status = PTR_ERR(p->clk); + p->clk = NULL; + goto fail; + } + + status = request_irq(irq, pwm_irq, 0, pdev->name, p); + if (status < 0) + goto fail; + + pwm = p; + platform_set_drvdata(pdev, p); + + return 0; + +fail: + if (p->clk) + clk_put(p->clk); + if (p->base) + iounmap(p->base); + + kfree(p); + return status; +} + +static int __exit pwm_remove(struct platform_device *pdev) +{ + struct pwm *p = platform_get_drvdata(pdev); + + if (p != pwm) + return -EINVAL; + + clk_enable(pwm->clk); + pwm_writel(pwm, PWM_DIS, (1 << PWM_NCHAN) - 1); + pwm_writel(pwm, PWM_IDR, (1 << PWM_NCHAN) - 1); + clk_disable(pwm->clk); + + pwm = NULL; + + free_irq(p->irq, p); + clk_put(p->clk); + iounmap(p->base); + kfree(p); + + return 0; +} + +static struct platform_driver atmel_pwm_driver = { + .driver = { + .name = "atmel_pwm", + .owner = THIS_MODULE, + }, + .remove = __exit_p(pwm_remove), + + /* NOTE: PWM can keep running in AVR32 "idle" and "frozen" states; + * and all AT91sam9263 states, albeit at reduced clock rate if + * MCK becomes the slow clock (i.e. what Linux labels STR). + */ +}; + +static int __init pwm_init(void) +{ + return platform_driver_probe(&atmel_pwm_driver, pwm_probe); +} +module_init(pwm_init); + +static void __exit pwm_exit(void) +{ + platform_driver_unregister(&atmel_pwm_driver); +} +module_exit(pwm_exit); + +MODULE_DESCRIPTION("Driver for AT32/AT91 PWM module"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 9cc25fd80b60..50c2b60e1fee 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -879,7 +879,8 @@ config SMC91X tristate "SMC 91C9x/91C1xxx support" select CRC32 select MII - depends on ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH || SOC_AU1X00 || BLACKFIN + depends on ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH || \ + SOC_AU1X00 || BLACKFIN || MN10300 help This is a driver for SMC's 91x series of Ethernet chipsets, including the SMC91C94 and the SMC91C111. Say Y if you want it diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 271c28dc9baa..51d4134b37b1 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -450,8 +450,20 @@ static inline void LPD7_SMC_outsw (unsigned char* a, int r, #define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l) #define SMC_IRQ_FLAGS (-1) /* from resource */ +#elif defined(CONFIG_MN10300) + +/* + * MN10300/AM33 configuration + */ + +#include <asm/unit/smc91111.h> + #else +/* + * Default configuration + */ + #define SMC_CAN_USE_8BIT 1 #define SMC_CAN_USE_16BIT 1 #define SMC_CAN_USE_32BIT 1 diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig index d449b150930e..b7bcdcc5c724 100644 --- a/drivers/parport/Kconfig +++ b/drivers/parport/Kconfig @@ -35,7 +35,8 @@ if PARPORT config PARPORT_PC tristate "PC-style hardware" - depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV && (!M68K || ISA) + depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV && \ + (!M68K || ISA) && !MN10300 ---help--- You should say Y here if you have a PC-style parallel port. All IBM PC compatible computers and some Alphas have PC-style diff --git a/drivers/parport/ieee1284_ops.c b/drivers/parport/ieee1284_ops.c index 525312f2fe9c..2e21af43d91e 100644 --- a/drivers/parport/ieee1284_ops.c +++ b/drivers/parport/ieee1284_ops.c @@ -888,7 +888,7 @@ size_t parport_ieee1284_epp_read_addr (struct parport *port, /* Event 59: set nSelectIn (nAStrb) high */ parport_frob_control (port, PARPORT_CONTROL_SELECT, - PARPORT_CONTROL_SELECT); + 0); /* Event 60: wait for Busy to go low */ if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 9f04d17576d6..4d1ce2e7361e 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_PPC32) += setup-irq.o obj-$(CONFIG_PPC) += setup-bus.o obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o obj-$(CONFIG_X86_VISWS) += setup-irq.o +obj-$(CONFIG_MN10300) += setup-bus.o # # ACPI Related PCI FW Functions diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 31fa6c92aa5e..a4c3089f892a 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -692,6 +692,23 @@ static int iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did, DMA_TLB_PSI_FLUSH, non_present_entry_flush); } +static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu) +{ + u32 pmen; + unsigned long flags; + + spin_lock_irqsave(&iommu->register_lock, flags); + pmen = readl(iommu->reg + DMAR_PMEN_REG); + pmen &= ~DMA_PMEN_EPM; + writel(pmen, iommu->reg + DMAR_PMEN_REG); + + /* wait for the protected region status bit to clear */ + IOMMU_WAIT_OP(iommu, DMAR_PMEN_REG, + readl, !(pmen & DMA_PMEN_PRS), pmen); + + spin_unlock_irqrestore(&iommu->register_lock, flags); +} + static int iommu_enable_translation(struct intel_iommu *iommu) { u32 sts; @@ -728,7 +745,7 @@ static int iommu_disable_translation(struct intel_iommu *iommu) /* iommu interrupt handling. Most stuff are MSI-like. */ -static char *fault_reason_strings[] = +static const char *fault_reason_strings[] = { "Software", "Present bit in root entry is clear", @@ -743,14 +760,13 @@ static char *fault_reason_strings[] = "non-zero reserved fields in RTP", "non-zero reserved fields in CTP", "non-zero reserved fields in PTE", - "Unknown" }; -#define MAX_FAULT_REASON_IDX ARRAY_SIZE(fault_reason_strings) - 1 +#define MAX_FAULT_REASON_IDX (ARRAY_SIZE(fault_reason_strings) - 1) -char *dmar_get_fault_reason(u8 fault_reason) +const char *dmar_get_fault_reason(u8 fault_reason) { - if (fault_reason >= MAX_FAULT_REASON_IDX) - return fault_reason_strings[MAX_FAULT_REASON_IDX - 1]; + if (fault_reason > MAX_FAULT_REASON_IDX) + return "Unknown"; else return fault_reason_strings[fault_reason]; } @@ -808,7 +824,7 @@ void dmar_msi_read(int irq, struct msi_msg *msg) static int iommu_page_fault_do_one(struct intel_iommu *iommu, int type, u8 fault_reason, u16 source_id, u64 addr) { - char *reason; + const char *reason; reason = dmar_get_fault_reason(fault_reason); @@ -1730,6 +1746,8 @@ int __init init_dmars(void) iommu_flush_context_global(iommu, 0); iommu_flush_iotlb_global(iommu, 0); + iommu_disable_protect_mem_regions(iommu); + ret = iommu_enable_translation(iommu); if (ret) goto error; diff --git a/drivers/pci/intel-iommu.h b/drivers/pci/intel-iommu.h index 0e4862675ad2..07f5f6353bda 100644 --- a/drivers/pci/intel-iommu.h +++ b/drivers/pci/intel-iommu.h @@ -140,6 +140,10 @@ static inline void dmar_writeq(void __iomem *addr, u64 val) #define DMA_TLB_IH_NONLEAF (((u64)1) << 6) #define DMA_TLB_MAX_SIZE (0x3f) +/* PMEN_REG */ +#define DMA_PMEN_EPM (((u32)1)<<31) +#define DMA_PMEN_PRS (((u32)1)<<0) + /* GCMD_REG */ #define DMA_GCMD_TE (((u32)1) << 31) #define DMA_GCMD_SRTP (((u32)1) << 30) diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index b8a4bd94f51d..77f7a7f0646e 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -305,7 +305,7 @@ static inline int map_8250_out_reg(struct uart_8250_port *up, int offset) return au_io_out_map[offset]; } -#elif defined (CONFIG_SERIAL_8250_RM9K) +#elif defined(CONFIG_SERIAL_8250_RM9K) static const u8 regmap_in[8] = { @@ -475,7 +475,7 @@ static inline void _serial_dl_write(struct uart_8250_port *up, int value) serial_outp(up, UART_DLM, value >> 8 & 0xff); } -#if defined (CONFIG_SERIAL_8250_AU1X00) +#if defined(CONFIG_SERIAL_8250_AU1X00) /* Au1x00 haven't got a standard divisor latch */ static int serial_dl_read(struct uart_8250_port *up) { @@ -492,7 +492,7 @@ static void serial_dl_write(struct uart_8250_port *up, int value) else _serial_dl_write(up, value); } -#elif defined (CONFIG_SERIAL_8250_RM9K) +#elif defined(CONFIG_SERIAL_8250_RM9K) static int serial_dl_read(struct uart_8250_port *up) { return (up->port.iotype == UPIO_RM9000) ? @@ -1185,8 +1185,8 @@ static void autoconfig_irq(struct uart_8250_port *up) irqs = probe_irq_on(); serial_outp(up, UART_MCR, 0); - udelay (10); - if (up->port.flags & UPF_FOURPORT) { + udelay(10); + if (up->port.flags & UPF_FOURPORT) { serial_outp(up, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); } else { @@ -1199,7 +1199,7 @@ static void autoconfig_irq(struct uart_8250_port *up) (void)serial_inp(up, UART_IIR); (void)serial_inp(up, UART_MSR); serial_outp(up, UART_TX, 0xFF); - udelay (20); + udelay(20); irq = probe_irq_off(irqs); serial_outp(up, UART_MCR, save_mcr); @@ -1343,7 +1343,7 @@ receive_chars(struct uart_8250_port *up, unsigned int *status) uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag); - ignore_char: +ignore_char: lsr = serial_inp(up, UART_LSR); } while ((lsr & UART_LSR_DR) && (max_count-- > 0)); spin_unlock(&up->port.lock); @@ -1633,7 +1633,8 @@ static void serial8250_backup_timeout(unsigned long data) serial_out(up, UART_IER, ier); /* Standard timer interval plus 0.2s to keep the port running */ - mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout) + HZ/5); + mod_timer(&up->timer, + jiffies + poll_timeout(up->port.timeout) + HZ / 5); } static unsigned int serial8250_tx_empty(struct uart_port *port) @@ -1844,7 +1845,7 @@ static int serial8250_startup(struct uart_port *port) up->timer.function = serial8250_backup_timeout; up->timer.data = (unsigned long)up; mod_timer(&up->timer, jiffies + - poll_timeout(up->port.timeout) + HZ/5); + poll_timeout(up->port.timeout) + HZ / 5); } } @@ -2173,6 +2174,7 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios, } serial8250_set_mctrl(&up->port, up->port.mctrl); spin_unlock_irqrestore(&up->port.lock, flags); + tty_termios_encode_baud_rate(termios, baud, baud); } static void diff --git a/drivers/serial/8250_early.c b/drivers/serial/8250_early.c index 1f16de719962..38776e8b064b 100644 --- a/drivers/serial/8250_early.c +++ b/drivers/serial/8250_early.c @@ -82,7 +82,8 @@ static void __init serial_putc(struct uart_port *port, int c) serial_out(port, UART_TX, c); } -static void __init early_serial8250_write(struct console *console, const char *s, unsigned int count) +static void __init early_serial8250_write(struct console *console, + const char *s, unsigned int count) { struct uart_port *port = &early_device.port; unsigned int ier; @@ -132,7 +133,8 @@ static void __init init_port(struct early_serial8250_device *device) serial_out(port, UART_LCR, c & ~UART_LCR_DLAB); } -static int __init parse_options(struct early_serial8250_device *device, char *options) +static int __init parse_options(struct early_serial8250_device *device, + char *options) { struct uart_port *port = &device->port; int mmio, length; @@ -145,8 +147,10 @@ static int __init parse_options(struct early_serial8250_device *device, char *op port->iotype = UPIO_MEM; port->mapbase = simple_strtoul(options + 5, &options, 0); #ifdef CONFIG_FIX_EARLYCON_MEM - set_fixmap_nocache(FIX_EARLYCON_MEM_BASE, port->mapbase & PAGE_MASK); - port->membase = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE); + set_fixmap_nocache(FIX_EARLYCON_MEM_BASE, + port->mapbase & PAGE_MASK); + port->membase = + (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE); port->membase += port->mapbase & ~PAGE_MASK; #else port->membase = ioremap(port->mapbase, 64); @@ -165,7 +169,8 @@ static int __init parse_options(struct early_serial8250_device *device, char *op } else return -EINVAL; - if ((options = strchr(options, ','))) { + options = strchr(options, ','); + if (options) { options++; device->baud = simple_strtoul(options, NULL, 0); length = min(strcspn(options, " "), sizeof(device->options)); @@ -179,7 +184,7 @@ static int __init parse_options(struct early_serial8250_device *device, char *op printk(KERN_INFO "Early serial console at %s 0x%llx (options '%s')\n", mmio ? "MMIO" : "I/O port", mmio ? (unsigned long long) port->mapbase - : (unsigned long long) port->iobase, + : (unsigned long long) port->iobase, device->options); return 0; } @@ -199,7 +204,8 @@ static int __init early_serial8250_setup(char *options) if (device->port.membase || device->port.iobase) return 0; - if ((err = parse_options(device, options)) < 0) + err = parse_options(device, options); + if (err < 0) return err; init_port(device); @@ -219,7 +225,8 @@ int __init setup_early_serial8250_console(char *cmdline) } options = strchr(cmdline, ',') + 1; - if ((err = early_serial8250_setup(options)) < 0) + err = early_serial8250_setup(options); + if (err < 0) return err; register_console(&early_serial8250_console); diff --git a/drivers/serial/8250_gsc.c b/drivers/serial/8250_gsc.c index c5d0addfda4f..4eb7437a404a 100644 --- a/drivers/serial/8250_gsc.c +++ b/drivers/serial/8250_gsc.c @@ -25,8 +25,7 @@ #include "8250.h" -static int __init -serial_init_chip(struct parisc_device *dev) +static int __init serial_init_chip(struct parisc_device *dev) { struct uart_port port; unsigned long address; @@ -38,18 +37,17 @@ serial_init_chip(struct parisc_device *dev) * what we have here is a missing parent device, so tell * the user what they're missing. */ - if (parisc_parent(dev)->id.hw_type != HPHW_IOA) { - printk(KERN_INFO "Serial: device 0x%lx not configured.\n" + if (parisc_parent(dev)->id.hw_type != HPHW_IOA) + printk(KERN_INFO + "Serial: device 0x%lx not configured.\n" "Enable support for Wax, Lasi, Asp or Dino.\n", dev->hpa.start); - } return -ENODEV; } address = dev->hpa.start; - if (dev->id.sversion != 0x8d) { + if (dev->id.sversion != 0x8d) address += 0x800; - } memset(&port, 0, sizeof(port)); port.iotype = UPIO_MEM; @@ -63,11 +61,12 @@ serial_init_chip(struct parisc_device *dev) err = serial8250_register_port(&port); if (err < 0) { - printk(KERN_WARNING "serial8250_register_port returned error %d\n", err); + printk(KERN_WARNING + "serial8250_register_port returned error %d\n", err); iounmap(port.membase); return err; } - + return 0; } diff --git a/drivers/serial/8250_hp300.c b/drivers/serial/8250_hp300.c index 2cf0953fe0ec..0e1410f2c033 100644 --- a/drivers/serial/8250_hp300.c +++ b/drivers/serial/8250_hp300.c @@ -36,7 +36,7 @@ static struct hp300_port *hp300_ports; #ifdef CONFIG_HPDCA static int __devinit hpdca_init_one(struct dio_dev *d, - const struct dio_device_id *ent); + const struct dio_device_id *ent); static void __devexit hpdca_remove_one(struct dio_dev *d); static struct dio_device_id hpdca_dio_tbl[] = { @@ -85,7 +85,7 @@ extern int hp300_uart_scode; #ifdef CONFIG_SERIAL_8250_CONSOLE /* - * Parse the bootinfo to find descriptions for headless console and + * Parse the bootinfo to find descriptions for headless console and * debug serial ports and register them with the 8250 driver. * This function should be called before serial_console_init() is called * to make sure the serial console will be available for use. IA-64 kernel @@ -126,13 +126,11 @@ int __init hp300_setup_serial_console(void) printk(KERN_WARNING "Serial console is APCI but support is disabled (CONFIG_HPAPCI)!\n"); return 0; #endif - } - else { + } else { #ifdef CONFIG_HPDCA unsigned long pa = dio_scodetophysaddr(scode); - if (!pa) { + if (!pa) return 0; - } printk(KERN_INFO "Serial console is HP DCA at select code %d\n", scode); @@ -145,26 +143,23 @@ int __init hp300_setup_serial_console(void) /* Enable board-interrupts */ out_8(pa + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE); - if (DIO_ID(pa + DIO_VIRADDRBASE) & 0x80) { + if (DIO_ID(pa + DIO_VIRADDRBASE) & 0x80) add_preferred_console("ttyS", port.line, "9600n8"); - } #else printk(KERN_WARNING "Serial console is DCA but support is disabled (CONFIG_HPDCA)!\n"); return 0; #endif } - if (early_serial_setup(&port) < 0) { + if (early_serial_setup(&port) < 0) printk(KERN_WARNING "hp300_setup_serial_console(): early_serial_setup() failed.\n"); - } - return 0; } #endif /* CONFIG_SERIAL_8250_CONSOLE */ #ifdef CONFIG_HPDCA static int __devinit hpdca_init_one(struct dio_dev *d, - const struct dio_device_id *ent) + const struct dio_device_id *ent) { struct uart_port port; int line; @@ -210,7 +205,7 @@ static int __devinit hpdca_init_one(struct dio_dev *d, static int __init hp300_8250_init(void) { - static int called = 0; + static int called; #ifdef CONFIG_HPAPCI int line; unsigned long base; @@ -239,13 +234,12 @@ static int __init hp300_8250_init(void) * Port 1 is either the console or the DCA. */ for (i = 1; i < 4; i++) { - /* Port 1 is the console on a 425e, on other machines it's mapped to - * DCA. + /* Port 1 is the console on a 425e, on other machines it's + * mapped to DCA. */ #ifdef CONFIG_SERIAL_8250_CONSOLE - if (i == 1) { + if (i == 1) continue; - } #endif /* Create new serial device */ @@ -259,7 +253,8 @@ static int __init hp300_8250_init(void) /* Memory mapped I/O */ uport.iotype = UPIO_MEM; - uport.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF; + uport.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ \ + | UPF_BOOT_AUTOCONF; /* XXX - no interrupt support yet */ uport.irq = 0; uport.uartclk = HPAPCI_BAUD_BASE * 16; @@ -270,8 +265,8 @@ static int __init hp300_8250_init(void) line = serial8250_register_port(&uport); if (line < 0) { - printk(KERN_NOTICE "8250_hp300: register_serial() APCI %d" - " irq %d failed\n", i, uport.irq); + printk(KERN_NOTICE "8250_hp300: register_serial() APCI" + " %d irq %d failed\n", i, uport.irq); kfree(port); continue; } diff --git a/drivers/serial/8250_hub6.c b/drivers/serial/8250_hub6.c index daf569cd3c8f..7609150e7d5e 100644 --- a/drivers/serial/8250_hub6.c +++ b/drivers/serial/8250_hub6.c @@ -23,18 +23,18 @@ } static struct plat_serial8250_port hub6_data[] = { - HUB6(0,0), - HUB6(0,1), - HUB6(0,2), - HUB6(0,3), - HUB6(0,4), - HUB6(0,5), - HUB6(1,0), - HUB6(1,1), - HUB6(1,2), - HUB6(1,3), - HUB6(1,4), - HUB6(1,5), + HUB6(0, 0), + HUB6(0, 1), + HUB6(0, 2), + HUB6(0, 3), + HUB6(0, 4), + HUB6(0, 5), + HUB6(1, 0), + HUB6(1, 1), + HUB6(1, 2), + HUB6(1, 3), + HUB6(1, 4), + HUB6(1, 5), { }, }; diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index 0a4ac2b6eb5a..a8bec498cad6 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c @@ -140,7 +140,7 @@ afavlab_setup(struct serial_private *priv, struct pciserial_board *board, struct uart_port *port, int idx) { unsigned int bar, offset = board->first_offset; - + bar = FL_GET_BASE(board->flags); if (idx < 4) bar += idx; @@ -227,8 +227,8 @@ static int pci_inteli960ni_init(struct pci_dev *dev) return -ENODEV; /* is firmware started? */ - pci_read_config_dword(dev, 0x44, (void*) &oldval); - if (oldval == 0x00001000L) { /* RESET value */ + pci_read_config_dword(dev, 0x44, (void *)&oldval); + if (oldval == 0x00001000L) { /* RESET value */ printk(KERN_DEBUG "Local i960 firmware missing"); return -ENODEV; } @@ -253,11 +253,11 @@ static int pci_plx9050_init(struct pci_dev *dev) irq_config = 0x41; if (dev->vendor == PCI_VENDOR_ID_PANACOM || - dev->subsystem_vendor == PCI_SUBVENDOR_ID_EXSYS) { + dev->subsystem_vendor == PCI_SUBVENDOR_ID_EXSYS) irq_config = 0x43; - } + if ((dev->vendor == PCI_VENDOR_ID_PLX) && - (dev->device == PCI_DEVICE_ID_PLX_ROMULUS)) { + (dev->device == PCI_DEVICE_ID_PLX_ROMULUS)) /* * As the megawolf cards have the int pins active * high, and have 2 UART chips, both ints must be @@ -267,8 +267,6 @@ static int pci_plx9050_init(struct pci_dev *dev) * deep FIFOs */ irq_config = 0x5b; - } - /* * enable/disable interrupts */ @@ -343,14 +341,14 @@ static int sbs_init(struct pci_dev *dev) { u8 __iomem *p; - p = ioremap(pci_resource_start(dev, 0),pci_resource_len(dev,0)); + p = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); if (p == NULL) return -ENOMEM; /* Set bit-4 Control Register (UART RESET) in to reset the uarts */ - writeb(0x10,p + OCT_REG_CR_OFF); + writeb(0x10, p + OCT_REG_CR_OFF); udelay(50); - writeb(0x0,p + OCT_REG_CR_OFF); + writeb(0x0, p + OCT_REG_CR_OFF); /* Set bit-2 (INTENABLE) of Control Register */ writeb(0x4, p + OCT_REG_CR_OFF); @@ -367,10 +365,10 @@ static void __devexit sbs_exit(struct pci_dev *dev) { u8 __iomem *p; - p = ioremap(pci_resource_start(dev, 0),pci_resource_len(dev,0)); - if (p != NULL) { + p = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); + /* FIXME: What if resource_len < OCT_REG_CR_OFF */ + if (p != NULL) writeb(0, p + OCT_REG_CR_OFF); - } iounmap(p); } @@ -386,7 +384,7 @@ static void __devexit sbs_exit(struct pci_dev *dev) * with other OSes (like M$ DOS). * * SIIG support added by Andrey Panin <pazke@donpac.ru>, 10/1999 - * + * * There is two family of SIIG serial cards with different PCI * interface chip and different configuration methods: * - 10x cards have control registers in IO and/or memory space; @@ -489,21 +487,21 @@ static const unsigned short timedia_single_port[] = { static const unsigned short timedia_dual_port[] = { 0x0002, 0x4036, 0x4037, 0x4038, 0x4078, 0x4079, 0x4085, - 0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079, - 0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079, + 0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079, + 0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079, 0x9137, 0x9138, 0x9237, 0x9238, 0xA079, 0xB079, 0xC079, 0xD079, 0 }; static const unsigned short timedia_quad_port[] = { - 0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157, - 0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159, + 0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157, + 0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159, 0x9256, 0x9257, 0xA056, 0xA157, 0xA158, 0xA159, 0xB056, 0xB157, 0 }; static const unsigned short timedia_eight_port[] = { - 0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166, + 0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166, 0x9167, 0x9168, 0xA066, 0xA167, 0xA168, 0 }; @@ -656,7 +654,8 @@ static int pci_ite887x_init(struct pci_dev *dev) ITE_887x_POSIO_ENABLE | ITE_887x_POSIO_SPEED | ITE_887x_POSIO_IOSIZE_32 | inta_addr[i]); /* write INTCBAR - ioport */ - pci_write_config_dword(dev, ITE_887x_INTCBAR, inta_addr[i]); + pci_write_config_dword(dev, ITE_887x_INTCBAR, + inta_addr[i]); ret = inb(inta_addr[i]); if (ret != 0xff) { /* ioport connected */ @@ -755,7 +754,7 @@ pci_default_setup(struct serial_private *priv, struct pciserial_board *board, if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr) return 1; - + return setup_port(priv, port, bar, offset, board->reg_shift); } @@ -843,7 +842,7 @@ static struct pci_serial_quirk pci_serial_quirks[] = { .init = pci_plx9050_init, .setup = pci_default_setup, .exit = __devexit_p(pci_plx9050_exit), - }, + }, { .vendor = PCI_VENDOR_ID_PANACOM, .device = PCI_DEVICE_ID_PANACOM_DUALMODEM, @@ -1032,7 +1031,7 @@ static struct pci_serial_quirk *find_quirk(struct pci_dev *dev) quirk_id_matches(quirk->device, dev->device) && quirk_id_matches(quirk->subvendor, dev->subsystem_vendor) && quirk_id_matches(quirk->subdevice, dev->subsystem_device)) - break; + break; return quirk; } @@ -1711,7 +1710,7 @@ static struct pciserial_board pci_boards[] __devinitdata = { }; static const struct pci_device_id softmodem_blacklist[] = { - { PCI_VDEVICE ( AL, 0x5457 ), }, /* ALi Corporation M5457 AC'97 Modem */ + { PCI_VDEVICE(AL, 0x5457), }, /* ALi Corporation M5457 AC'97 Modem */ }; /* @@ -1724,13 +1723,13 @@ serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board) { const struct pci_device_id *blacklist; int num_iomem, num_port, first_port = -1, i; - + /* * If it is not a communications device or the programming * interface is greater than 6, give up. * * (Should we try to make guesses for multiport serial devices - * later?) + * later?) */ if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) && ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) || @@ -1863,25 +1862,23 @@ pciserial_init_ports(struct pci_dev *dev, struct pciserial_board *board) break; #ifdef SERIAL_DEBUG_PCI - printk("Setup PCI port: port %x, irq %d, type %d\n", + printk(KERN_DEBUG "Setup PCI port: port %x, irq %d, type %d\n", serial_port.iobase, serial_port.irq, serial_port.iotype); #endif - + priv->line[i] = serial8250_register_port(&serial_port); if (priv->line[i] < 0) { printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), priv->line[i]); break; } } - priv->nr = i; - return priv; - err_deinit: +err_deinit: if (quirk->exit) quirk->exit(dev); - err_out: +err_out: return priv; } EXPORT_SYMBOL_GPL(pciserial_init_ports); @@ -2171,22 +2168,22 @@ static struct pci_device_id serial_pci_tbl[] = { pbn_b0_8_1843200_200 }, { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_bt_1_115200 }, { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_bt_2_115200 }, { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_bt_4_115200 }, { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_bt_2_115200 }, { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_bt_4_115200 }, { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_8_115200 }, { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, @@ -2201,11 +2198,11 @@ static struct pci_device_id serial_pci_tbl[] = { /* * VScom SPCOM800, from sl@s.pl */ - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_8_921600 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_4_921600 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_KEYSPAN, @@ -2223,27 +2220,27 @@ static struct pci_device_id serial_pci_tbl[] = { pbn_b2_4_115200 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_CHASE_PCIFAST, - PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0, + PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0, pbn_b2_4_460800 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_CHASE_PCIFAST, - PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0, + PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0, pbn_b2_8_460800 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_CHASE_PCIFAST, - PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0, + PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0, pbn_b2_16_460800 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_CHASE_PCIFAST, - PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0, + PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0, pbn_b2_16_460800 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_CHASE_PCIRAS, - PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0, + PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0, pbn_b2_4_460800 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_CHASE_PCIRAS, - PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0, + PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0, pbn_b2_8_460800 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_EXSYS, @@ -2269,10 +2266,12 @@ static struct pci_device_id serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b1_8_115200 }, { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954, - PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, 0, 0, + PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, + 0, 0, pbn_b0_4_921600 }, { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, - PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL, 0, 0, + PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL, + 0, 0, pbn_b0_4_1152000 }, /* @@ -2312,7 +2311,7 @@ static struct pci_device_id serial_pci_tbl[] = { * Digitan DS560-558, from jimd@esoft.com */ { PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b1_1_115200 }, /* @@ -2320,16 +2319,16 @@ static struct pci_device_id serial_pci_tbl[] = { * The 400L and 800L have a custom setup quirk. */ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_1_921600 }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_2_921600 }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_4_921600 }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_4_921600 }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100L, PCI_ANY_ID, PCI_ANY_ID, 0, 0, diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 84a054d7e986..b82595cf13e8 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -380,6 +380,21 @@ config SERIAL_ATMEL_CONSOLE console is the device which receives all kernel messages and warnings and which allows logins in single user mode). +config SERIAL_ATMEL_PDC + bool "Support DMA transfers on AT91 / AT32 serial port" + depends on SERIAL_ATMEL + default y + help + Say Y here if you wish to use the PDC to do DMA transfers to + and from the Atmel AT91 / AT32 serial port. In order to + actually use DMA transfers, make sure that the use_dma_tx + and use_dma_rx members in the atmel_uart_data struct is set + appropriately for each port. + + Note that break and error handling currently doesn't work + properly when DMA is enabled. Make sure that ports where + this matters don't use DMA. + config SERIAL_ATMEL_TTYAT bool "Install as device ttyATn instead of ttySn" depends on SERIAL_ATMEL=y diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index 60f52904aad0..fad245b064d6 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -7,6 +7,8 @@ * Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd. * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. * + * DMA support added by Chip Coldwell. + * * 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 @@ -33,6 +35,7 @@ #include <linux/sysrq.h> #include <linux/tty_flip.h> #include <linux/platform_device.h> +#include <linux/dma-mapping.h> #include <linux/atmel_pdc.h> #include <linux/atmel_serial.h> @@ -46,6 +49,10 @@ #include <asm/arch/gpio.h> #endif +#define PDC_BUFFER_SIZE 512 +/* Revisit: We should calculate this based on the actual port settings */ +#define PDC_RX_TIMEOUT (3 * 10) /* 3 bytes */ + #if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ #endif @@ -73,6 +80,7 @@ #define ATMEL_ISR_PASS_LIMIT 256 +/* UART registers. CR is write-only, hence no GET macro */ #define UART_PUT_CR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_CR) #define UART_GET_MR(port) __raw_readl((port)->membase + ATMEL_US_MR) #define UART_PUT_MR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_MR) @@ -86,8 +94,6 @@ #define UART_PUT_BRGR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_BRGR) #define UART_PUT_RTOR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_RTOR) -// #define UART_GET_CR(port) __raw_readl((port)->membase + ATMEL_US_CR) // is write-only - /* PDC registers */ #define UART_PUT_PTCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR) #define UART_GET_PTSR(port) __raw_readl((port)->membase + ATMEL_PDC_PTSR) @@ -100,12 +106,24 @@ #define UART_PUT_TPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TPR) #define UART_PUT_TCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TCR) -//#define UART_PUT_TNPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TNPR) -//#define UART_PUT_TNCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TNCR) static int (*atmel_open_hook)(struct uart_port *); static void (*atmel_close_hook)(struct uart_port *); +struct atmel_dma_buffer { + unsigned char *buf; + dma_addr_t dma_addr; + unsigned int dma_size; + unsigned int ofs; +}; + +struct atmel_uart_char { + u16 status; + u16 ch; +}; + +#define ATMEL_SERIAL_RINGSIZE 1024 + /* * We wrap our port structure around the generic uart_port. */ @@ -114,6 +132,19 @@ struct atmel_uart_port { struct clk *clk; /* uart clock */ unsigned short suspended; /* is port suspended? */ int break_active; /* break being received */ + + short use_dma_rx; /* enable PDC receiver */ + short pdc_rx_idx; /* current PDC RX buffer */ + struct atmel_dma_buffer pdc_rx[2]; /* PDC receier */ + + short use_dma_tx; /* enable PDC transmitter */ + struct atmel_dma_buffer pdc_tx; /* PDC transmitter */ + + struct tasklet_struct tasklet; + unsigned int irq_status; + unsigned int irq_status_prev; + + struct circ_buf rx_ring; }; static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART]; @@ -122,6 +153,38 @@ static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART]; static struct console atmel_console; #endif +static inline struct atmel_uart_port * +to_atmel_uart_port(struct uart_port *uart) +{ + return container_of(uart, struct atmel_uart_port, uart); +} + +#ifdef CONFIG_SERIAL_ATMEL_PDC +static bool atmel_use_dma_rx(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + return atmel_port->use_dma_rx; +} + +static bool atmel_use_dma_tx(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + return atmel_port->use_dma_tx; +} +#else +static bool atmel_use_dma_rx(struct uart_port *port) +{ + return false; +} + +static bool atmel_use_dma_tx(struct uart_port *port) +{ + return false; +} +#endif + /* * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty. */ @@ -141,8 +204,8 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) #ifdef CONFIG_ARCH_AT91RM9200 if (cpu_is_at91rm9200()) { /* - * AT91RM9200 Errata #39: RTS0 is not internally connected to PA21. - * We need to drive the pin manually. + * AT91RM9200 Errata #39: RTS0 is not internally connected + * to PA21. We need to drive the pin manually. */ if (port->mapbase == AT91RM9200_BASE_US0) { if (mctrl & TIOCM_RTS) @@ -203,7 +266,12 @@ static u_int atmel_get_mctrl(struct uart_port *port) */ static void atmel_stop_tx(struct uart_port *port) { - UART_PUT_IDR(port, ATMEL_US_TXRDY); + if (atmel_use_dma_tx(port)) { + /* disable PDC transmit */ + UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); + UART_PUT_IDR(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE); + } else + UART_PUT_IDR(port, ATMEL_US_TXRDY); } /* @@ -211,7 +279,17 @@ static void atmel_stop_tx(struct uart_port *port) */ static void atmel_start_tx(struct uart_port *port) { - UART_PUT_IER(port, ATMEL_US_TXRDY); + if (atmel_use_dma_tx(port)) { + if (UART_GET_PTSR(port) & ATMEL_PDC_TXTEN) + /* The transmitter is already running. Yes, we + really need this.*/ + return; + + UART_PUT_IER(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE); + /* re-enable PDC transmit */ + UART_PUT_PTCR(port, ATMEL_PDC_TXTEN); + } else + UART_PUT_IER(port, ATMEL_US_TXRDY); } /* @@ -219,7 +297,12 @@ static void atmel_start_tx(struct uart_port *port) */ static void atmel_stop_rx(struct uart_port *port) { - UART_PUT_IDR(port, ATMEL_US_RXRDY); + if (atmel_use_dma_rx(port)) { + /* disable PDC receive */ + UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS); + UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); + } else + UART_PUT_IDR(port, ATMEL_US_RXRDY); } /* @@ -227,7 +310,8 @@ static void atmel_stop_rx(struct uart_port *port) */ static void atmel_enable_ms(struct uart_port *port) { - UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC); + UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC + | ATMEL_US_DCDIC | ATMEL_US_CTSIC); } /* @@ -242,22 +326,63 @@ static void atmel_break_ctl(struct uart_port *port, int break_state) } /* + * Stores the incoming character in the ring buffer + */ +static void +atmel_buffer_rx_char(struct uart_port *port, unsigned int status, + unsigned int ch) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct circ_buf *ring = &atmel_port->rx_ring; + struct atmel_uart_char *c; + + if (!CIRC_SPACE(ring->head, ring->tail, ATMEL_SERIAL_RINGSIZE)) + /* Buffer overflow, ignore char */ + return; + + c = &((struct atmel_uart_char *)ring->buf)[ring->head]; + c->status = status; + c->ch = ch; + + /* Make sure the character is stored before we update head. */ + smp_wmb(); + + ring->head = (ring->head + 1) & (ATMEL_SERIAL_RINGSIZE - 1); +} + +/* + * Deal with parity, framing and overrun errors. + */ +static void atmel_pdc_rxerr(struct uart_port *port, unsigned int status) +{ + /* clear error */ + UART_PUT_CR(port, ATMEL_US_RSTSTA); + + if (status & ATMEL_US_RXBRK) { + /* ignore side-effect */ + status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); + port->icount.brk++; + } + if (status & ATMEL_US_PARE) + port->icount.parity++; + if (status & ATMEL_US_FRAME) + port->icount.frame++; + if (status & ATMEL_US_OVRE) + port->icount.overrun++; +} + +/* * Characters received (called from interrupt handler) */ static void atmel_rx_chars(struct uart_port *port) { - struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; - struct tty_struct *tty = port->info->tty; - unsigned int status, ch, flg; + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + unsigned int status, ch; status = UART_GET_CSR(port); while (status & ATMEL_US_RXRDY) { ch = UART_GET_CHAR(port); - port->icount.rx++; - - flg = TTY_NORMAL; - /* * note that the error handling code is * out of the main execution path @@ -265,15 +390,14 @@ static void atmel_rx_chars(struct uart_port *port) if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME | ATMEL_US_OVRE | ATMEL_US_RXBRK) || atmel_port->break_active)) { - UART_PUT_CR(port, ATMEL_US_RSTSTA); /* clear error */ + + /* clear error */ + UART_PUT_CR(port, ATMEL_US_RSTSTA); + if (status & ATMEL_US_RXBRK && !atmel_port->break_active) { - status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); /* ignore side-effect */ - port->icount.brk++; atmel_port->break_active = 1; UART_PUT_IER(port, ATMEL_US_RXBRK); - if (uart_handle_break(port)) - goto ignore_char; } else { /* * This is either the end-of-break @@ -286,52 +410,30 @@ static void atmel_rx_chars(struct uart_port *port) status &= ~ATMEL_US_RXBRK; atmel_port->break_active = 0; } - if (status & ATMEL_US_PARE) - port->icount.parity++; - if (status & ATMEL_US_FRAME) - port->icount.frame++; - if (status & ATMEL_US_OVRE) - port->icount.overrun++; - - status &= port->read_status_mask; - - if (status & ATMEL_US_RXBRK) - flg = TTY_BREAK; - else if (status & ATMEL_US_PARE) - flg = TTY_PARITY; - else if (status & ATMEL_US_FRAME) - flg = TTY_FRAME; } - if (uart_handle_sysrq_char(port, ch)) - goto ignore_char; - - uart_insert_char(port, status, ATMEL_US_OVRE, ch, flg); - - ignore_char: + atmel_buffer_rx_char(port, status, ch); status = UART_GET_CSR(port); } - tty_flip_buffer_push(tty); + tasklet_schedule(&atmel_port->tasklet); } /* - * Transmit characters (called from interrupt handler) + * Transmit characters (called from tasklet with TXRDY interrupt + * disabled) */ static void atmel_tx_chars(struct uart_port *port) { struct circ_buf *xmit = &port->info->xmit; - if (port->x_char) { + if (port->x_char && UART_GET_CSR(port) & ATMEL_US_TXRDY) { UART_PUT_CHAR(port, port->x_char); port->icount.tx++; port->x_char = 0; - return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - atmel_stop_tx(port); + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) return; - } while (UART_GET_CSR(port) & ATMEL_US_TXRDY) { UART_PUT_CHAR(port, xmit->buf[xmit->tail]); @@ -344,8 +446,88 @@ static void atmel_tx_chars(struct uart_port *port) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); - if (uart_circ_empty(xmit)) - atmel_stop_tx(port); + if (!uart_circ_empty(xmit)) + UART_PUT_IER(port, ATMEL_US_TXRDY); +} + +/* + * receive interrupt handler. + */ +static void +atmel_handle_receive(struct uart_port *port, unsigned int pending) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + if (atmel_use_dma_rx(port)) { + /* + * PDC receive. Just schedule the tasklet and let it + * figure out the details. + * + * TODO: We're not handling error flags correctly at + * the moment. + */ + if (pending & (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)) { + UART_PUT_IDR(port, (ATMEL_US_ENDRX + | ATMEL_US_TIMEOUT)); + tasklet_schedule(&atmel_port->tasklet); + } + + if (pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE | + ATMEL_US_FRAME | ATMEL_US_PARE)) + atmel_pdc_rxerr(port, pending); + } + + /* Interrupt receive */ + if (pending & ATMEL_US_RXRDY) + atmel_rx_chars(port); + else if (pending & ATMEL_US_RXBRK) { + /* + * End of break detected. If it came along with a + * character, atmel_rx_chars will handle it. + */ + UART_PUT_CR(port, ATMEL_US_RSTSTA); + UART_PUT_IDR(port, ATMEL_US_RXBRK); + atmel_port->break_active = 0; + } +} + +/* + * transmit interrupt handler. (Transmit is IRQF_NODELAY safe) + */ +static void +atmel_handle_transmit(struct uart_port *port, unsigned int pending) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + if (atmel_use_dma_tx(port)) { + /* PDC transmit */ + if (pending & (ATMEL_US_ENDTX | ATMEL_US_TXBUFE)) { + UART_PUT_IDR(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE); + tasklet_schedule(&atmel_port->tasklet); + } + } else { + /* Interrupt transmit */ + if (pending & ATMEL_US_TXRDY) { + UART_PUT_IDR(port, ATMEL_US_TXRDY); + tasklet_schedule(&atmel_port->tasklet); + } + } +} + +/* + * status flags interrupt handler. + */ +static void +atmel_handle_status(struct uart_port *port, unsigned int pending, + unsigned int status) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC + | ATMEL_US_CTSIC)) { + atmel_port->irq_status = status; + tasklet_schedule(&atmel_port->tasklet); + } } /* @@ -354,47 +536,255 @@ static void atmel_tx_chars(struct uart_port *port) static irqreturn_t atmel_interrupt(int irq, void *dev_id) { struct uart_port *port = dev_id; - struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; unsigned int status, pending, pass_counter = 0; - status = UART_GET_CSR(port); - pending = status & UART_GET_IMR(port); - while (pending) { - /* Interrupt receive */ - if (pending & ATMEL_US_RXRDY) - atmel_rx_chars(port); - else if (pending & ATMEL_US_RXBRK) { + do { + status = UART_GET_CSR(port); + pending = status & UART_GET_IMR(port); + if (!pending) + break; + + atmel_handle_receive(port, pending); + atmel_handle_status(port, pending, status); + atmel_handle_transmit(port, pending); + } while (pass_counter++ < ATMEL_ISR_PASS_LIMIT); + + return IRQ_HANDLED; +} + +/* + * Called from tasklet with ENDTX and TXBUFE interrupts disabled. + */ +static void atmel_tx_dma(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct circ_buf *xmit = &port->info->xmit; + struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; + int count; + + xmit->tail += pdc->ofs; + xmit->tail &= UART_XMIT_SIZE - 1; + + port->icount.tx += pdc->ofs; + pdc->ofs = 0; + + if (!uart_circ_empty(xmit)) { + /* more to transmit - setup next transfer */ + + /* disable PDC transmit */ + UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); + dma_sync_single_for_device(port->dev, + pdc->dma_addr, + pdc->dma_size, + DMA_TO_DEVICE); + + count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + pdc->ofs = count; + + UART_PUT_TPR(port, pdc->dma_addr + xmit->tail); + UART_PUT_TCR(port, count); + /* re-enable PDC transmit and interrupts */ + UART_PUT_PTCR(port, ATMEL_PDC_TXTEN); + UART_PUT_IER(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE); + } else { + /* nothing left to transmit - disable the transmitter */ + + /* disable PDC transmit */ + UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); +} + +static void atmel_rx_from_ring(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct circ_buf *ring = &atmel_port->rx_ring; + unsigned int flg; + unsigned int status; + + while (ring->head != ring->tail) { + struct atmel_uart_char c; + + /* Make sure c is loaded after head. */ + smp_rmb(); + + c = ((struct atmel_uart_char *)ring->buf)[ring->tail]; + + ring->tail = (ring->tail + 1) & (ATMEL_SERIAL_RINGSIZE - 1); + + port->icount.rx++; + status = c.status; + flg = TTY_NORMAL; + + /* + * note that the error handling code is + * out of the main execution path + */ + if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME + | ATMEL_US_OVRE | ATMEL_US_RXBRK))) { + if (status & ATMEL_US_RXBRK) { + /* ignore side-effect */ + status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); + + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } + if (status & ATMEL_US_PARE) + port->icount.parity++; + if (status & ATMEL_US_FRAME) + port->icount.frame++; + if (status & ATMEL_US_OVRE) + port->icount.overrun++; + + status &= port->read_status_mask; + + if (status & ATMEL_US_RXBRK) + flg = TTY_BREAK; + else if (status & ATMEL_US_PARE) + flg = TTY_PARITY; + else if (status & ATMEL_US_FRAME) + flg = TTY_FRAME; + } + + + if (uart_handle_sysrq_char(port, c.ch)) + continue; + + uart_insert_char(port, status, ATMEL_US_OVRE, c.ch, flg); + } + + /* + * Drop the lock here since it might end up calling + * uart_start(), which takes the lock. + */ + spin_unlock(&port->lock); + tty_flip_buffer_push(port->info->tty); + spin_lock(&port->lock); +} + +static void atmel_rx_from_dma(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct tty_struct *tty = port->info->tty; + struct atmel_dma_buffer *pdc; + int rx_idx = atmel_port->pdc_rx_idx; + unsigned int head; + unsigned int tail; + unsigned int count; + + do { + /* Reset the UART timeout early so that we don't miss one */ + UART_PUT_CR(port, ATMEL_US_STTTO); + + pdc = &atmel_port->pdc_rx[rx_idx]; + head = UART_GET_RPR(port) - pdc->dma_addr; + tail = pdc->ofs; + + /* If the PDC has switched buffers, RPR won't contain + * any address within the current buffer. Since head + * is unsigned, we just need a one-way comparison to + * find out. + * + * In this case, we just need to consume the entire + * buffer and resubmit it for DMA. This will clear the + * ENDRX bit as well, so that we can safely re-enable + * all interrupts below. + */ + head = min(head, pdc->dma_size); + + if (likely(head != tail)) { + dma_sync_single_for_cpu(port->dev, pdc->dma_addr, + pdc->dma_size, DMA_FROM_DEVICE); + /* - * End of break detected. If it came along - * with a character, atmel_rx_chars will - * handle it. + * head will only wrap around when we recycle + * the DMA buffer, and when that happens, we + * explicitly set tail to 0. So head will + * always be greater than tail. */ - UART_PUT_CR(port, ATMEL_US_RSTSTA); - UART_PUT_IDR(port, ATMEL_US_RXBRK); - atmel_port->break_active = 0; + count = head - tail; + + tty_insert_flip_string(tty, pdc->buf + pdc->ofs, count); + + dma_sync_single_for_device(port->dev, pdc->dma_addr, + pdc->dma_size, DMA_FROM_DEVICE); + + port->icount.rx += count; + pdc->ofs = head; } - // TODO: All reads to CSR will clear these interrupts! - if (pending & ATMEL_US_RIIC) port->icount.rng++; - if (pending & ATMEL_US_DSRIC) port->icount.dsr++; - if (pending & ATMEL_US_DCDIC) + /* + * If the current buffer is full, we need to check if + * the next one contains any additional data. + */ + if (head >= pdc->dma_size) { + pdc->ofs = 0; + UART_PUT_RNPR(port, pdc->dma_addr); + UART_PUT_RNCR(port, pdc->dma_size); + + rx_idx = !rx_idx; + atmel_port->pdc_rx_idx = rx_idx; + } + } while (head >= pdc->dma_size); + + /* + * Drop the lock here since it might end up calling + * uart_start(), which takes the lock. + */ + spin_unlock(&port->lock); + tty_flip_buffer_push(tty); + spin_lock(&port->lock); + + UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); +} + +/* + * tasklet handling tty stuff outside the interrupt handler. + */ +static void atmel_tasklet_func(unsigned long data) +{ + struct uart_port *port = (struct uart_port *)data; + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + unsigned int status; + unsigned int status_change; + + /* The interrupt handler does not take the lock */ + spin_lock(&port->lock); + + if (atmel_use_dma_tx(port)) + atmel_tx_dma(port); + else + atmel_tx_chars(port); + + status = atmel_port->irq_status; + status_change = status ^ atmel_port->irq_status_prev; + + if (status_change & (ATMEL_US_RI | ATMEL_US_DSR + | ATMEL_US_DCD | ATMEL_US_CTS)) { + /* TODO: All reads to CSR will clear these interrupts! */ + if (status_change & ATMEL_US_RI) + port->icount.rng++; + if (status_change & ATMEL_US_DSR) + port->icount.dsr++; + if (status_change & ATMEL_US_DCD) uart_handle_dcd_change(port, !(status & ATMEL_US_DCD)); - if (pending & ATMEL_US_CTSIC) + if (status_change & ATMEL_US_CTS) uart_handle_cts_change(port, !(status & ATMEL_US_CTS)); - if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC)) - wake_up_interruptible(&port->info->delta_msr_wait); - /* Interrupt transmit */ - if (pending & ATMEL_US_TXRDY) - atmel_tx_chars(port); + wake_up_interruptible(&port->info->delta_msr_wait); - if (pass_counter++ > ATMEL_ISR_PASS_LIMIT) - break; - - status = UART_GET_CSR(port); - pending = status & UART_GET_IMR(port); + atmel_port->irq_status_prev = status; } - return IRQ_HANDLED; + + if (atmel_use_dma_rx(port)) + atmel_rx_from_dma(port); + else + atmel_rx_from_ring(port); + + spin_unlock(&port->lock); } /* @@ -402,6 +792,8 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id) */ static int atmel_startup(struct uart_port *port) { + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct tty_struct *tty = port->info->tty; int retval; /* @@ -414,13 +806,64 @@ static int atmel_startup(struct uart_port *port) /* * Allocate the IRQ */ - retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED, "atmel_serial", port); + retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED, + tty ? tty->name : "atmel_serial", port); if (retval) { printk("atmel_serial: atmel_startup - Can't get irq\n"); return retval; } /* + * Initialize DMA (if necessary) + */ + if (atmel_use_dma_rx(port)) { + int i; + + for (i = 0; i < 2; i++) { + struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i]; + + pdc->buf = kmalloc(PDC_BUFFER_SIZE, GFP_KERNEL); + if (pdc->buf == NULL) { + if (i != 0) { + dma_unmap_single(port->dev, + atmel_port->pdc_rx[0].dma_addr, + PDC_BUFFER_SIZE, + DMA_FROM_DEVICE); + kfree(atmel_port->pdc_rx[0].buf); + } + free_irq(port->irq, port); + return -ENOMEM; + } + pdc->dma_addr = dma_map_single(port->dev, + pdc->buf, + PDC_BUFFER_SIZE, + DMA_FROM_DEVICE); + pdc->dma_size = PDC_BUFFER_SIZE; + pdc->ofs = 0; + } + + atmel_port->pdc_rx_idx = 0; + + UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr); + UART_PUT_RCR(port, PDC_BUFFER_SIZE); + + UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr); + UART_PUT_RNCR(port, PDC_BUFFER_SIZE); + } + if (atmel_use_dma_tx(port)) { + struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; + struct circ_buf *xmit = &port->info->xmit; + + pdc->buf = xmit->buf; + pdc->dma_addr = dma_map_single(port->dev, + pdc->buf, + UART_XMIT_SIZE, + DMA_TO_DEVICE); + pdc->dma_size = UART_XMIT_SIZE; + pdc->ofs = 0; + } + + /* * If there is a specific "open" function (to register * control line interrupts) */ @@ -436,9 +879,21 @@ static int atmel_startup(struct uart_port *port) * Finally, enable the serial port */ UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); - UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); /* enable xmit & rcvr */ + /* enable xmit & rcvr */ + UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); - UART_PUT_IER(port, ATMEL_US_RXRDY); /* enable receive only */ + if (atmel_use_dma_rx(port)) { + /* set UART timeout */ + UART_PUT_RTOR(port, PDC_RX_TIMEOUT); + UART_PUT_CR(port, ATMEL_US_STTTO); + + UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); + /* enable PDC controller */ + UART_PUT_PTCR(port, ATMEL_PDC_RXTEN); + } else { + /* enable receive only */ + UART_PUT_IER(port, ATMEL_US_RXRDY); + } return 0; } @@ -448,6 +903,38 @@ static int atmel_startup(struct uart_port *port) */ static void atmel_shutdown(struct uart_port *port) { + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + /* + * Ensure everything is stopped. + */ + atmel_stop_rx(port); + atmel_stop_tx(port); + + /* + * Shut-down the DMA. + */ + if (atmel_use_dma_rx(port)) { + int i; + + for (i = 0; i < 2; i++) { + struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i]; + + dma_unmap_single(port->dev, + pdc->dma_addr, + pdc->dma_size, + DMA_FROM_DEVICE); + kfree(pdc->buf); + } + } + if (atmel_use_dma_tx(port)) { + struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; + + dma_unmap_single(port->dev, + pdc->dma_addr, + pdc->dma_size, + DMA_TO_DEVICE); + } + /* * Disable all interrupts, port and break condition. */ @@ -470,45 +957,48 @@ static void atmel_shutdown(struct uart_port *port) /* * Power / Clock management. */ -static void atmel_serial_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) +static void atmel_serial_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) { - struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); switch (state) { - case 0: - /* - * Enable the peripheral clock for this serial port. - * This is called on uart_open() or a resume event. - */ - clk_enable(atmel_port->clk); - break; - case 3: - /* - * Disable the peripheral clock for this serial port. - * This is called on uart_close() or a suspend event. - */ - clk_disable(atmel_port->clk); - break; - default: - printk(KERN_ERR "atmel_serial: unknown pm %d\n", state); + case 0: + /* + * Enable the peripheral clock for this serial port. + * This is called on uart_open() or a resume event. + */ + clk_enable(atmel_port->clk); + break; + case 3: + /* + * Disable the peripheral clock for this serial port. + * This is called on uart_close() or a suspend event. + */ + clk_disable(atmel_port->clk); + break; + default: + printk(KERN_ERR "atmel_serial: unknown pm %d\n", state); } } /* * Change the port parameters */ -static void atmel_set_termios(struct uart_port *port, struct ktermios * termios, struct ktermios * old) +static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { unsigned long flags; unsigned int mode, imr, quot, baud; /* Get current mode register */ - mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL | ATMEL_US_NBSTOP | ATMEL_US_PAR); + mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL + | ATMEL_US_NBSTOP | ATMEL_US_PAR); - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); quot = uart_get_divisor(port, baud); - if (quot > 65535) { /* BRGR is 16-bit, so switch to slower clock */ + if (quot > 65535) { /* BRGR is 16-bit, so switch to slower clock */ quot /= 8; mode |= ATMEL_US_USCLKS_MCK_DIV8; } @@ -535,18 +1025,17 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios * termios, /* parity */ if (termios->c_cflag & PARENB) { - if (termios->c_cflag & CMSPAR) { /* Mark or Space parity */ + /* Mark or Space parity */ + if (termios->c_cflag & CMSPAR) { if (termios->c_cflag & PARODD) mode |= ATMEL_US_PAR_MARK; else mode |= ATMEL_US_PAR_SPACE; - } - else if (termios->c_cflag & PARODD) + } else if (termios->c_cflag & PARODD) mode |= ATMEL_US_PAR_ODD; else mode |= ATMEL_US_PAR_EVEN; - } - else + } else mode |= ATMEL_US_PAR_NONE; spin_lock_irqsave(&port->lock, flags); @@ -557,6 +1046,10 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios * termios, if (termios->c_iflag & (BRKINT | PARMRK)) port->read_status_mask |= ATMEL_US_RXBRK; + if (atmel_use_dma_rx(port)) + /* need to enable error interrupts */ + UART_PUT_IER(port, port->read_status_mask); + /* * Characters to ignore */ @@ -572,16 +1065,16 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios * termios, if (termios->c_iflag & IGNPAR) port->ignore_status_mask |= ATMEL_US_OVRE; } - - // TODO: Ignore all characters if CREAD is set. + /* TODO: Ignore all characters if CREAD is set.*/ /* update the per-port timeout */ uart_update_timeout(port, termios->c_cflag, baud); - /* disable interrupts and drain transmitter */ - imr = UART_GET_IMR(port); /* get interrupt mask */ - UART_PUT_IDR(port, -1); /* disable all interrupts */ - while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY)) { barrier(); } + /* save/disable interrupts and drain transmitter */ + imr = UART_GET_IMR(port); + UART_PUT_IDR(port, -1); + while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY)) + cpu_relax(); /* disable receiver and transmitter */ UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS); @@ -707,7 +1200,8 @@ static struct uart_ops atmel_pops = { /* * Configure the port from the platform device resource info. */ -static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, struct platform_device *pdev) +static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, + struct platform_device *pdev) { struct uart_port *port = &atmel_port->uart; struct atmel_uart_data *data = pdev->dev.platform_data; @@ -722,6 +1216,11 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, struct port->mapbase = pdev->resource[0].start; port->irq = pdev->resource[1].start; + tasklet_init(&atmel_port->tasklet, atmel_tasklet_func, + (unsigned long)port); + + memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring)); + if (data->regs) /* Already mapped by setup code */ port->membase = data->regs; @@ -730,11 +1229,17 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, struct port->membase = NULL; } - if (!atmel_port->clk) { /* for console, the clock could already be configured */ + /* for console, the clock could already be configured */ + if (!atmel_port->clk) { atmel_port->clk = clk_get(&pdev->dev, "usart"); clk_enable(atmel_port->clk); port->uartclk = clk_get_rate(atmel_port->clk); } + + atmel_port->use_dma_rx = data->use_dma_rx; + atmel_port->use_dma_tx = data->use_dma_tx; + if (atmel_use_dma_tx(port)) + port->fifosize = PDC_BUFFER_SIZE; } /* @@ -754,12 +1259,11 @@ void __init atmel_register_uart_fns(struct atmel_port_fns *fns) atmel_pops.set_wake = fns->set_wake; } - #ifdef CONFIG_SERIAL_ATMEL_CONSOLE static void atmel_console_putchar(struct uart_port *port, int ch) { while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY)) - barrier(); + cpu_relax(); UART_PUT_CHAR(port, ch); } @@ -772,38 +1276,40 @@ static void atmel_console_write(struct console *co, const char *s, u_int count) unsigned int status, imr; /* - * First, save IMR and then disable interrupts + * First, save IMR and then disable interrupts */ - imr = UART_GET_IMR(port); /* get interrupt mask */ + imr = UART_GET_IMR(port); UART_PUT_IDR(port, ATMEL_US_RXRDY | ATMEL_US_TXRDY); uart_console_write(port, s, count, atmel_console_putchar); /* - * Finally, wait for transmitter to become empty - * and restore IMR + * Finally, wait for transmitter to become empty + * and restore IMR */ do { status = UART_GET_CSR(port); } while (!(status & ATMEL_US_TXRDY)); - UART_PUT_IER(port, imr); /* set interrupts back the way they were */ + /* set interrupts back the way they were */ + UART_PUT_IER(port, imr); } /* - * If the port was already initialised (eg, by a boot loader), try to determine - * the current setup. + * If the port was already initialised (eg, by a boot loader), + * try to determine the current setup. */ -static void __init atmel_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits) +static void __init atmel_console_get_options(struct uart_port *port, int *baud, + int *parity, int *bits) { unsigned int mr, quot; -// TODO: CR is a write-only register -// unsigned int cr; -// -// cr = UART_GET_CR(port) & (ATMEL_US_RXEN | ATMEL_US_TXEN); -// if (cr == (ATMEL_US_RXEN | ATMEL_US_TXEN)) { -// /* ok, the port was enabled */ -// } + /* + * If the baud rate generator isn't running, the port wasn't + * initialized by the boot loader. + */ + quot = UART_GET_BRGR(port); + if (!quot) + return; mr = UART_GET_MR(port) & ATMEL_US_CHRL; if (mr == ATMEL_US_CHRL_8) @@ -823,7 +1329,6 @@ static void __init atmel_console_get_options(struct uart_port *port, int *baud, * lower than one of those, as it would make us fall through * to a much lower baud rate than we really want. */ - quot = UART_GET_BRGR(port); *baud = port->uartclk / (16 * (quot - 1)); } @@ -835,10 +1340,12 @@ static int __init atmel_console_setup(struct console *co, char *options) int parity = 'n'; int flow = 'n'; - if (port->membase == 0) /* Port not initialized yet - delay setup */ + if (port->membase == NULL) { + /* Port not initialized yet - delay setup */ return -ENODEV; + } - UART_PUT_IDR(port, -1); /* disable interrupts */ + UART_PUT_IDR(port, -1); UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); @@ -870,13 +1377,16 @@ static struct console atmel_console = { static int __init atmel_console_init(void) { if (atmel_default_console_device) { - add_preferred_console(ATMEL_DEVICENAME, atmel_default_console_device->id, NULL); - atmel_init_port(&(atmel_ports[atmel_default_console_device->id]), atmel_default_console_device); + add_preferred_console(ATMEL_DEVICENAME, + atmel_default_console_device->id, NULL); + atmel_init_port(&atmel_ports[atmel_default_console_device->id], + atmel_default_console_device); register_console(&atmel_console); } return 0; } + console_initcall(atmel_console_init); /* @@ -884,34 +1394,48 @@ console_initcall(atmel_console_init); */ static int __init atmel_late_console_init(void) { - if (atmel_default_console_device && !(atmel_console.flags & CON_ENABLED)) + if (atmel_default_console_device + && !(atmel_console.flags & CON_ENABLED)) register_console(&atmel_console); return 0; } + core_initcall(atmel_late_console_init); +static inline bool atmel_is_console_port(struct uart_port *port) +{ + return port->cons && port->cons->index == port->line; +} + #else #define ATMEL_CONSOLE_DEVICE NULL + +static inline bool atmel_is_console_port(struct uart_port *port) +{ + return false; +} #endif static struct uart_driver atmel_uart = { - .owner = THIS_MODULE, - .driver_name = "atmel_serial", - .dev_name = ATMEL_DEVICENAME, - .major = SERIAL_ATMEL_MAJOR, - .minor = MINOR_START, - .nr = ATMEL_MAX_UART, - .cons = ATMEL_CONSOLE_DEVICE, + .owner = THIS_MODULE, + .driver_name = "atmel_serial", + .dev_name = ATMEL_DEVICENAME, + .major = SERIAL_ATMEL_MAJOR, + .minor = MINOR_START, + .nr = ATMEL_MAX_UART, + .cons = ATMEL_CONSOLE_DEVICE, }; #ifdef CONFIG_PM -static int atmel_serial_suspend(struct platform_device *pdev, pm_message_t state) +static int atmel_serial_suspend(struct platform_device *pdev, + pm_message_t state) { struct uart_port *port = platform_get_drvdata(pdev); - struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - if (device_may_wakeup(&pdev->dev) && !at91_suspend_entering_slow_clock()) + if (device_may_wakeup(&pdev->dev) + && !at91_suspend_entering_slow_clock()) enable_irq_wake(port->irq); else { uart_suspend_port(&atmel_uart, port); @@ -924,13 +1448,12 @@ static int atmel_serial_suspend(struct platform_device *pdev, pm_message_t state static int atmel_serial_resume(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); - struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); if (atmel_port->suspended) { uart_resume_port(&atmel_uart, port); atmel_port->suspended = 0; - } - else + } else disable_irq_wake(port->irq); return 0; @@ -943,15 +1466,40 @@ static int atmel_serial_resume(struct platform_device *pdev) static int __devinit atmel_serial_probe(struct platform_device *pdev) { struct atmel_uart_port *port; + void *data; int ret; + BUILD_BUG_ON(!is_power_of_2(ATMEL_SERIAL_RINGSIZE)); + port = &atmel_ports[pdev->id]; atmel_init_port(port, pdev); + if (!atmel_use_dma_rx(&port->uart)) { + ret = -ENOMEM; + data = kmalloc(sizeof(struct atmel_uart_char) + * ATMEL_SERIAL_RINGSIZE, GFP_KERNEL); + if (!data) + goto err_alloc_ring; + port->rx_ring.buf = data; + } + ret = uart_add_one_port(&atmel_uart, &port->uart); - if (!ret) { - device_init_wakeup(&pdev->dev, 1); - platform_set_drvdata(pdev, port); + if (ret) + goto err_add_port; + + device_init_wakeup(&pdev->dev, 1); + platform_set_drvdata(pdev, port); + + return 0; + +err_add_port: + kfree(port->rx_ring.buf); + port->rx_ring.buf = NULL; +err_alloc_ring: + if (!atmel_is_console_port(&port->uart)) { + clk_disable(port->clk); + clk_put(port->clk); + port->clk = NULL; } return ret; @@ -960,19 +1508,21 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev) static int __devexit atmel_serial_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); - struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); int ret = 0; - clk_disable(atmel_port->clk); - clk_put(atmel_port->clk); - device_init_wakeup(&pdev->dev, 0); platform_set_drvdata(pdev, NULL); - if (port) { - ret = uart_remove_one_port(&atmel_uart, port); - kfree(port); - } + ret = uart_remove_one_port(&atmel_uart, port); + + tasklet_kill(&atmel_port->tasklet); + kfree(atmel_port->rx_ring.buf); + + /* "port" is allocated statically, so we shouldn't free it */ + + clk_disable(atmel_port->clk); + clk_put(atmel_port->clk); return ret; } diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 276da148c57e..0f5a17987cca 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -58,7 +58,8 @@ static struct lock_class_key port_lock_key; #define uart_console(port) (0) #endif -static void uart_change_speed(struct uart_state *state, struct ktermios *old_termios); +static void uart_change_speed(struct uart_state *state, + struct ktermios *old_termios); static void uart_wait_until_sent(struct tty_struct *tty, int timeout); static void uart_change_pm(struct uart_state *state, int pm_state); @@ -129,8 +130,8 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear) spin_unlock_irqrestore(&port->lock, flags); } -#define uart_set_mctrl(port,set) uart_update_mctrl(port,set,0) -#define uart_clear_mctrl(port,clear) uart_update_mctrl(port,0,clear) +#define uart_set_mctrl(port, set) uart_update_mctrl(port, set, 0) +#define uart_clear_mctrl(port, clear) uart_update_mctrl(port, 0, clear) /* * Startup the port. This will be called once per open. All calls @@ -290,7 +291,7 @@ uart_update_timeout(struct uart_port *port, unsigned int cflag, break; default: bits = 10; - break; // CS8 + break; /* CS8 */ } if (cflag & CSTOPB) @@ -622,7 +623,7 @@ static int uart_get_info(struct uart_state *state, tmp.close_delay = state->close_delay / 10; tmp.closing_wait = state->closing_wait == USF_CLOSING_WAIT_NONE ? ASYNC_CLOSING_WAIT_NONE : - state->closing_wait / 10; + state->closing_wait / 10; tmp.custom_divisor = port->custom_divisor; tmp.hub6 = port->hub6; tmp.io_type = port->iotype; @@ -788,7 +789,8 @@ static int uart_set_info(struct uart_state *state, * We failed anyway. */ retval = -EBUSY; - goto exit; // Added to return the correct error -Ram Gupta + /* Added to return the correct error -Ram Gupta */ + goto exit; } } @@ -858,7 +860,7 @@ static int uart_get_lsr_info(struct uart_state *state, ((uart_circ_chars_pending(&state->info->xmit) > 0) && !state->info->tty->stopped && !state->info->tty->hw_stopped)) result &= ~TIOCSER_TEMT; - + return put_user(result, value); } @@ -996,8 +998,8 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg) ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { - ret = 0; - break; + ret = 0; + break; } schedule(); @@ -1137,7 +1139,8 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, return ret; } -static void uart_set_termios(struct tty_struct *tty, struct ktermios *old_termios) +static void uart_set_termios(struct tty_struct *tty, + struct ktermios *old_termios) { struct uart_state *state = tty->driver_data; unsigned long flags; @@ -1213,7 +1216,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp) { struct uart_state *state = tty->driver_data; struct uart_port *port; - + BUG_ON(!kernel_locked()); if (!state || !state->port) @@ -1278,8 +1281,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp) uart_shutdown(state); uart_flush_buffer(tty); - tty_ldisc_flush(tty); - + tty_ldisc_flush(tty); + tty->closing = 0; state->info->tty = NULL; @@ -1341,7 +1344,7 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout) expire = jiffies + timeout; pr_debug("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n", - port->line, jiffies, expire); + port->line, jiffies, expire); /* * Check whether the transmitter is empty every 'char_time'. @@ -1460,10 +1463,9 @@ uart_block_til_ready(struct file *filp, struct uart_state *state) * have set TTY_IO_ERROR for a non-existant port. */ if ((filp->f_flags & O_NONBLOCK) || - (info->tty->termios->c_cflag & CLOCAL) || - (info->tty->flags & (1 << TTY_IO_ERROR))) { + (info->tty->termios->c_cflag & CLOCAL) || + (info->tty->flags & (1 << TTY_IO_ERROR))) break; - } /* * Set DTR to allow modem to know we're waiting. Do @@ -1551,8 +1553,8 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line) } /* - * In 2.4.5, calls to uart_open are serialised by the BKL in - * linux/fs/devices.c:chrdev_open() + * calls to uart_open are serialised by the BKL in + * fs/char_dev.c:chrdev_open() * Note that if this fails, then uart_close() _will_ be called. * * In time, we want to scrap the "opening nonpresent ports" @@ -1674,7 +1676,7 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i) port->line, uart_type(port), mmio ? "mmio:0x" : "port:", mmio ? (unsigned long long)port->mapbase - : (unsigned long long) port->iobase, + : (unsigned long long) port->iobase, port->irq); if (port->type == PORT_UNKNOWN) { @@ -1682,8 +1684,7 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i) return ret + 1; } - if(capable(CAP_SYS_ADMIN)) - { + if (capable(CAP_SYS_ADMIN)) { mutex_lock(&state->mutex); pm_state = state->pm_state; if (pm_state) @@ -1709,12 +1710,12 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i) if (port->icount.overrun) ret += sprintf(buf + ret, " oe:%d", port->icount.overrun); - -#define INFOBIT(bit,str) \ + +#define INFOBIT(bit, str) \ if (port->mctrl & (bit)) \ strncat(stat_buf, (str), sizeof(stat_buf) - \ strlen(stat_buf) - 2) -#define STATBIT(bit,str) \ +#define STATBIT(bit, str) \ if (status & (bit)) \ strncat(stat_buf, (str), sizeof(stat_buf) - \ strlen(stat_buf) - 2) @@ -1730,7 +1731,7 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i) if (stat_buf[0]) stat_buf[0] = ' '; strcat(stat_buf, "\n"); - + ret += sprintf(buf + ret, stat_buf); } else { strcat(buf, "\n"); @@ -1992,11 +1993,11 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) /* * Wait for the transmitter to empty. */ - for (tries = 3; !ops->tx_empty(port) && tries; tries--) { + for (tries = 3; !ops->tx_empty(port) && tries; tries--) msleep(10); - } if (!tries) - printk(KERN_ERR "%s%s%s%d: Unable to drain transmitter\n", + printk(KERN_ERR "%s%s%s%d: Unable to drain " + "transmitter\n", port->dev ? port->dev->bus_id : "", port->dev ? ": " : "", drv->dev_name, port->line); diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 9b3f61200000..69f19f224875 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -9,7 +9,7 @@ menuconfig THERMAL Generic Thermal Sysfs driver offers a generic mechanism for thermal management. Usually it's made up of one or more thermal zone and cooling device. - each thermal zone contains its own temperature, trip points, + Each thermal zone contains its own temperature, trip points, cooling devices. All platforms with ACPI thermal support can use this driver. - If you want this support, you should say Y here + If you want this support, you should say Y here. diff --git a/drivers/thermal/thermal.c b/drivers/thermal/thermal.c index 3273e348fd14..e782b3e7fcdb 100644 --- a/drivers/thermal/thermal.c +++ b/drivers/thermal/thermal.c @@ -267,7 +267,7 @@ thermal_cooling_device_cur_state_store(struct device *dev, } static struct device_attribute dev_attr_cdev_type = - __ATTR(type, 0444, thermal_cooling_device_type_show, NULL); +__ATTR(type, 0444, thermal_cooling_device_type_show, NULL); static DEVICE_ATTR(max_state, 0444, thermal_cooling_device_max_state_show, NULL); static DEVICE_ATTR(cur_state, 0644, @@ -276,7 +276,7 @@ static DEVICE_ATTR(cur_state, 0644, static ssize_t thermal_cooling_device_trip_point_show(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, char *buf) { struct thermal_cooling_device_instance *instance; @@ -293,11 +293,12 @@ thermal_cooling_device_trip_point_show(struct device *dev, /** * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone - * this function is usually called in the thermal zone device .bind callback. * @tz: thermal zone device * @trip: indicates which trip point the cooling devices is * associated with in this thermal zone. * @cdev: thermal cooling device + * + * This function is usually called in the thermal zone device .bind callback. */ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, int trip, @@ -307,8 +308,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, struct thermal_cooling_device_instance *pos; int result; - if (trip >= tz->trips || - (trip < 0 && trip != THERMAL_TRIPS_NONE)) + if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE)) return -EINVAL; if (!tz || !cdev) @@ -361,15 +361,17 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, kfree(dev); return result; } + EXPORT_SYMBOL(thermal_zone_bind_cooling_device); /** * thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone - * this function is usually called in the thermal zone device .unbind callback. * @tz: thermal zone device * @trip: indicates which trip point the cooling devices is * associated with in this thermal zone. * @cdev: thermal cooling device + * + * This function is usually called in the thermal zone device .unbind callback. */ int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz, int trip, @@ -379,8 +381,7 @@ int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz, mutex_lock(&tz->lock); list_for_each_entry_safe(pos, next, &tz->cooling_devices, node) { - if (pos->tz == tz && pos->trip == trip - && pos->cdev == cdev) { + if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) { list_del(&pos->node); mutex_unlock(&tz->lock); goto unbind; @@ -397,6 +398,7 @@ int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz, kfree(pos); return 0; } + EXPORT_SYMBOL(thermal_zone_unbind_cooling_device); static void thermal_release(struct device *dev) @@ -425,7 +427,10 @@ static struct class thermal_class = { * @ops: standard thermal cooling devices callbacks. */ struct thermal_cooling_device *thermal_cooling_device_register(char *type, - void *devdata, struct thermal_cooling_device_ops *ops) + void *devdata, + struct + thermal_cooling_device_ops + *ops) { struct thermal_cooling_device *cdev; struct thermal_zone_device *pos; @@ -435,7 +440,7 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type, return NULL; if (!ops || !ops->get_max_state || !ops->get_cur_state || - !ops->set_cur_state) + !ops->set_cur_state) return NULL; cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL); @@ -462,8 +467,7 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type, /* sys I/F */ if (type) { - result = device_create_file(&cdev->device, - &dev_attr_cdev_type); + result = device_create_file(&cdev->device, &dev_attr_cdev_type); if (result) goto unregister; } @@ -496,11 +500,11 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type, device_unregister(&cdev->device); return NULL; } + EXPORT_SYMBOL(thermal_cooling_device_register); /** * thermal_cooling_device_unregister - removes the registered thermal cooling device - * * @cdev: the thermal cooling device to remove. * * thermal_cooling_device_unregister() must be called when the device is no @@ -533,8 +537,7 @@ void thermal_cooling_device_unregister(struct } mutex_unlock(&thermal_list_lock); if (cdev->type[0]) - device_remove_file(&cdev->device, - &dev_attr_cdev_type); + device_remove_file(&cdev->device, &dev_attr_cdev_type); device_remove_file(&cdev->device, &dev_attr_max_state); device_remove_file(&cdev->device, &dev_attr_cur_state); @@ -542,6 +545,7 @@ void thermal_cooling_device_unregister(struct device_unregister(&cdev->device); return; } + EXPORT_SYMBOL(thermal_cooling_device_unregister); /** @@ -555,8 +559,10 @@ EXPORT_SYMBOL(thermal_cooling_device_unregister); * longer needed. */ struct thermal_zone_device *thermal_zone_device_register(char *type, - int trips, void *devdata, - struct thermal_zone_device_ops *ops) + int trips, + void *devdata, struct + thermal_zone_device_ops + *ops) { struct thermal_zone_device *tz; struct thermal_cooling_device *pos; @@ -625,9 +631,9 @@ struct thermal_zone_device *thermal_zone_device_register(char *type, list_add_tail(&tz->node, &thermal_tz_list); if (ops->bind) list_for_each_entry(pos, &thermal_cdev_list, node) { - result = ops->bind(tz, pos); - if (result) - break; + result = ops->bind(tz, pos); + if (result) + break; } mutex_unlock(&thermal_list_lock); @@ -639,11 +645,11 @@ struct thermal_zone_device *thermal_zone_device_register(char *type, device_unregister(&tz->device); return NULL; } + EXPORT_SYMBOL(thermal_zone_device_register); /** * thermal_device_unregister - removes the registered thermal zone device - * * @tz: the thermal zone device to remove */ void thermal_zone_device_unregister(struct thermal_zone_device *tz) @@ -685,6 +691,7 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) device_unregister(&tz->device); return; } + EXPORT_SYMBOL(thermal_zone_device_unregister); static int __init thermal_init(void) diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 33469cf5aec3..e01862300169 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -1418,8 +1418,8 @@ show_function (struct device *_dev, struct device_attribute *attr, char *buf) } static DEVICE_ATTR (function, S_IRUGO, show_function, NULL); -static ssize_t -show_registers (struct device *_dev, struct device_attribute *attr, char *buf) +static ssize_t net2280_show_registers(struct device *_dev, + struct device_attribute *attr, char *buf) { struct net2280 *dev; char *next; @@ -1571,7 +1571,7 @@ show_registers (struct device *_dev, struct device_attribute *attr, char *buf) return PAGE_SIZE - size; } -static DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL); +static DEVICE_ATTR(registers, S_IRUGO, net2280_show_registers, NULL); static ssize_t show_queues (struct device *_dev, struct device_attribute *attr, char *buf) diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index 2b53d1f56281..06f87b04f207 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -6,7 +6,7 @@ menu "Console display driver support" config VGA_CONSOLE bool "VGA text console" if EMBEDDED || !X86 - depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH && !BLACKFIN && !AVR32 + depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH && !BLACKFIN && !AVR32 && !MN10300 default y help Saying Y here will allow you to use Linux in text mode through a |