summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/Kconfig16
-rw-r--r--drivers/block/Makefile2
-rw-r--r--drivers/block/aoe/aoe.h69
-rw-r--r--drivers/block/aoe/aoeblk.c72
-rw-r--r--drivers/block/aoe/aoechr.c93
-rw-r--r--drivers/block/aoe/aoecmd.c742
-rw-r--r--drivers/block/aoe/aoedev.c277
-rw-r--r--drivers/block/aoe/aoemain.c2
-rw-r--r--drivers/block/aoe/aoenet.c15
-rw-r--r--drivers/block/brd.c583
-rw-r--r--drivers/block/nbd.c10
-rw-r--r--drivers/block/rd.c537
-rw-r--r--drivers/char/applicom.c24
-rw-r--r--drivers/char/moxa.c23
-rw-r--r--drivers/char/n_tty.c148
-rw-r--r--drivers/char/rocket.c21
-rw-r--r--drivers/char/tty_audit.c2
-rw-r--r--drivers/char/tty_io.c561
-rw-r--r--drivers/char/tty_ioctl.c362
-rw-r--r--drivers/firmware/dmi_scan.c25
-rw-r--r--drivers/ide/ppc/mpc8xx.c1
-rw-r--r--drivers/input/joystick/analog.c6
-rw-r--r--drivers/isdn/capi/capifs.c7
-rw-r--r--drivers/leds/Kconfig7
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/leds-atmel-pwm.c157
-rw-r--r--drivers/lguest/lguest_device.c2
-rw-r--r--drivers/misc/Kconfig9
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/atmel_pwm.c409
-rw-r--r--drivers/net/Kconfig3
-rw-r--r--drivers/net/smc91x.h12
-rw-r--r--drivers/parport/Kconfig3
-rw-r--r--drivers/parport/ieee1284_ops.c2
-rw-r--r--drivers/pci/Makefile1
-rw-r--r--drivers/pci/intel-iommu.c32
-rw-r--r--drivers/pci/intel-iommu.h4
-rw-r--r--drivers/serial/8250.c20
-rw-r--r--drivers/serial/8250_early.c23
-rw-r--r--drivers/serial/8250_gsc.c17
-rw-r--r--drivers/serial/8250_hp300.c35
-rw-r--r--drivers/serial/8250_hub6.c24
-rw-r--r--drivers/serial/8250_pci.c109
-rw-r--r--drivers/serial/Kconfig15
-rw-r--r--drivers/serial/atmel_serial.c884
-rw-r--r--drivers/serial/serial_core.c59
-rw-r--r--drivers/usb/gadget/net2280.c6
-rw-r--r--drivers/video/console/Kconfig2
48 files changed, 3586 insertions, 1849 deletions
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 64e5148..b6d230b 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 7691505..01c9724 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 07f02f8..280e71e 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 826d123..0c39782 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 d5480e3..e8e60e7 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 4d59d50..44beb17 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 51f5071..f9a1cd9 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 a04b7d6..7b15a5e 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 4e6deb7..8460ef7 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 0000000..8536480
--- /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 ae31060..018753c 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 06e23be..0000000
--- 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 1f0b752..a7c4990 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 2fc255a..64b7b2b 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 90c3969..46b2a1c 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(&current->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 68c289f..72f2892 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 bacded0..7722466 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 79c86c4..613ec81 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 d4b6d64..f95a80b 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 1412d7b..653265a 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 06190b1..38fbfb8 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 f32e031..708c5ae 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 2dd1b57..6d7c47e 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/leds/Kconfig b/drivers/leds/Kconfig
index 851a3b0..859814f 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 bc6afc8..84ced3b 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 0000000..af61f55
--- /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 84f85e2..1b2ec0b 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 4e7f000..c143a86 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
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 7f13549..3b12f5d 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 0000000..f8d3b9a
--- /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 9cc25fd..50c2b60 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 271c28d..51d4134 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 d449b15..b7bcdcc 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 525312f..2e21af4 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 9f04d17..4d1ce2e 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 31fa6c9..a4c3089 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 0e48626..07f5f63 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 b8a4bd9..77f7a7f 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 1f16de7..38776e8 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 c5d0add..4eb7437 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 2cf0953..0e1410f 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 daf569c..7609150 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 0a4ac2b..a8bec49 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 84a054d..b82595c 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 60f5290..fad245b 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 276da14..0f5a179 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/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index 33469cf..e018623 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 2b53d1f..06f87b0 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
OpenPOWER on IntegriCloud