diff --git a/[refs] b/[refs] index 74d8175655bf..351acffad7a6 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: a57c21c7159e07c27e317ea3513dfb382be3f153 +refs/heads/master: b0999cc55bd49e315ec82d2fb770a0d9ef7cbed8 diff --git a/trunk/Documentation/trace/power.txt b/trunk/Documentation/trace/power.txt new file mode 100644 index 000000000000..cd805e16dc27 --- /dev/null +++ b/trunk/Documentation/trace/power.txt @@ -0,0 +1,17 @@ +The power tracer collects detailed information about C-state and P-state +transitions, instead of just looking at the high-level "average" +information. + +There is a helper script found in scrips/tracing/power.pl in the kernel +sources which can be used to parse this information and create a +Scalable Vector Graphics (SVG) picture from the trace data. + +To use this tracer: + + echo 0 > /sys/kernel/debug/tracing/tracing_enabled + echo power > /sys/kernel/debug/tracing/current_tracer + echo 1 > /sys/kernel/debug/tracing/tracing_enabled + sleep 1 + echo 0 > /sys/kernel/debug/tracing/tracing_enabled + cat /sys/kernel/debug/tracing/trace | \ + perl scripts/tracing/power.pl > out.sv diff --git a/trunk/arch/mn10300/kernel/asm-offsets.c b/trunk/arch/mn10300/kernel/asm-offsets.c index 82b40079ad76..2646fcbd7d89 100644 --- a/trunk/arch/mn10300/kernel/asm-offsets.c +++ b/trunk/arch/mn10300/kernel/asm-offsets.c @@ -95,7 +95,7 @@ void foo(void) OFFSET(__iobase, mn10300_serial_port, _iobase); DEFINE(__UART_XMIT_SIZE, UART_XMIT_SIZE); - OFFSET(__xmit_buffer, uart_state, xmit.buf); - OFFSET(__xmit_head, uart_state, xmit.head); - OFFSET(__xmit_tail, uart_state, xmit.tail); + OFFSET(__xmit_buffer, uart_info, xmit.buf); + OFFSET(__xmit_head, uart_info, xmit.head); + OFFSET(__xmit_tail, uart_info, xmit.tail); } diff --git a/trunk/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/trunk/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c index 7d5c3b0ea8da..7bb676c533aa 100644 --- a/trunk/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/trunk/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include @@ -72,6 +72,8 @@ static DEFINE_PER_CPU(struct acpi_cpufreq_data *, drv_data); static DEFINE_PER_CPU(struct aperfmperf, old_perf); +DEFINE_TRACE(power_mark); + /* acpi_perf_data is a pointer to percpu data. */ static struct acpi_processor_performance *acpi_perf_data; @@ -330,6 +332,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, unsigned int next_perf_state = 0; /* Index into perf table */ unsigned int i; int result = 0; + struct power_trace it; dprintk("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu); @@ -361,7 +364,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, } } - trace_power_frequency(POWER_PSTATE, data->freq_table[next_state].frequency); + trace_power_mark(&it, POWER_PSTATE, next_perf_state); switch (data->cpu_feature) { case SYSTEM_INTEL_MSR_CAPABLE: diff --git a/trunk/arch/x86/kernel/cpu/perf_counter.c b/trunk/arch/x86/kernel/cpu/perf_counter.c index dbdf712fae9e..2732e2c1e4d3 100644 --- a/trunk/arch/x86/kernel/cpu/perf_counter.c +++ b/trunk/arch/x86/kernel/cpu/perf_counter.c @@ -36,10 +36,10 @@ static u64 perf_counter_mask __read_mostly; #define BTS_RECORD_SIZE 24 /* The size of a per-cpu BTS buffer in bytes: */ -#define BTS_BUFFER_SIZE (BTS_RECORD_SIZE * 2048) +#define BTS_BUFFER_SIZE (BTS_RECORD_SIZE * 1024) /* The BTS overflow threshold in bytes from the end of the buffer: */ -#define BTS_OVFL_TH (BTS_RECORD_SIZE * 128) +#define BTS_OVFL_TH (BTS_RECORD_SIZE * 64) /* @@ -1488,7 +1488,8 @@ void perf_counter_print_debug(void) local_irq_restore(flags); } -static void intel_pmu_drain_bts_buffer(struct cpu_hw_counters *cpuc) +static void intel_pmu_drain_bts_buffer(struct cpu_hw_counters *cpuc, + struct perf_sample_data *data) { struct debug_store *ds = cpuc->ds; struct bts_record { @@ -1497,11 +1498,8 @@ static void intel_pmu_drain_bts_buffer(struct cpu_hw_counters *cpuc) u64 flags; }; struct perf_counter *counter = cpuc->counters[X86_PMC_IDX_FIXED_BTS]; + unsigned long orig_ip = data->regs->ip; struct bts_record *at, *top; - struct perf_output_handle handle; - struct perf_event_header header; - struct perf_sample_data data; - struct pt_regs regs; if (!counter) return; @@ -1512,38 +1510,19 @@ static void intel_pmu_drain_bts_buffer(struct cpu_hw_counters *cpuc) at = (struct bts_record *)(unsigned long)ds->bts_buffer_base; top = (struct bts_record *)(unsigned long)ds->bts_index; - if (top <= at) - return; - ds->bts_index = ds->bts_buffer_base; - - data.period = counter->hw.last_period; - data.addr = 0; - regs.ip = 0; - - /* - * Prepare a generic sample, i.e. fill in the invariant fields. - * We will overwrite the from and to address before we output - * the sample. - */ - perf_prepare_sample(&header, &data, counter, ®s); - - if (perf_output_begin(&handle, counter, - header.size * (top - at), 1, 1)) - return; - for (; at < top; at++) { - data.ip = at->from; - data.addr = at->to; + data->regs->ip = at->from; + data->addr = at->to; - perf_output_sample(&handle, &header, &data, counter); + perf_counter_output(counter, 1, data); } - perf_output_end(&handle); + data->regs->ip = orig_ip; + data->addr = 0; /* There's new data available. */ - counter->hw.interrupts++; counter->pending_kill = POLL_IN; } @@ -1573,9 +1552,13 @@ static void x86_pmu_disable(struct perf_counter *counter) x86_perf_counter_update(counter, hwc, idx); /* Drain the remaining BTS records. */ - if (unlikely(idx == X86_PMC_IDX_FIXED_BTS)) - intel_pmu_drain_bts_buffer(cpuc); + if (unlikely(idx == X86_PMC_IDX_FIXED_BTS)) { + struct perf_sample_data data; + struct pt_regs regs; + data.regs = ®s; + intel_pmu_drain_bts_buffer(cpuc, &data); + } cpuc->counters[idx] = NULL; clear_bit(idx, cpuc->used_mask); @@ -1636,6 +1619,7 @@ static int p6_pmu_handle_irq(struct pt_regs *regs) int idx, handled = 0; u64 val; + data.regs = regs; data.addr = 0; cpuc = &__get_cpu_var(cpu_hw_counters); @@ -1660,7 +1644,7 @@ static int p6_pmu_handle_irq(struct pt_regs *regs) if (!x86_perf_counter_set_period(counter, hwc, idx)) continue; - if (perf_counter_overflow(counter, 1, &data, regs)) + if (perf_counter_overflow(counter, 1, &data)) p6_pmu_disable_counter(hwc, idx); } @@ -1681,12 +1665,13 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) int bit, loops; u64 ack, status; + data.regs = regs; data.addr = 0; cpuc = &__get_cpu_var(cpu_hw_counters); perf_disable(); - intel_pmu_drain_bts_buffer(cpuc); + intel_pmu_drain_bts_buffer(cpuc, &data); status = intel_pmu_get_status(); if (!status) { perf_enable(); @@ -1717,7 +1702,7 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) data.period = counter->hw.last_period; - if (perf_counter_overflow(counter, 1, &data, regs)) + if (perf_counter_overflow(counter, 1, &data)) intel_pmu_disable_counter(&counter->hw, bit); } @@ -1744,6 +1729,7 @@ static int amd_pmu_handle_irq(struct pt_regs *regs) int idx, handled = 0; u64 val; + data.regs = regs; data.addr = 0; cpuc = &__get_cpu_var(cpu_hw_counters); @@ -1768,7 +1754,7 @@ static int amd_pmu_handle_irq(struct pt_regs *regs) if (!x86_perf_counter_set_period(counter, hwc, idx)) continue; - if (perf_counter_overflow(counter, 1, &data, regs)) + if (perf_counter_overflow(counter, 1, &data)) amd_pmu_disable_counter(hwc, idx); } diff --git a/trunk/arch/x86/kernel/cpuid.c b/trunk/arch/x86/kernel/cpuid.c index 6a52d4b36a30..b07af8861244 100644 --- a/trunk/arch/x86/kernel/cpuid.c +++ b/trunk/arch/x86/kernel/cpuid.c @@ -182,7 +182,7 @@ static struct notifier_block __refdata cpuid_class_cpu_notifier = .notifier_call = cpuid_class_cpu_callback, }; -static char *cpuid_devnode(struct device *dev, mode_t *mode) +static char *cpuid_nodename(struct device *dev) { return kasprintf(GFP_KERNEL, "cpu/%u/cpuid", MINOR(dev->devt)); } @@ -203,7 +203,7 @@ static int __init cpuid_init(void) err = PTR_ERR(cpuid_class); goto out_chrdev; } - cpuid_class->devnode = cpuid_devnode; + cpuid_class->nodename = cpuid_nodename; for_each_online_cpu(i) { err = cpuid_device_create(i); if (err != 0) diff --git a/trunk/arch/x86/kernel/microcode_core.c b/trunk/arch/x86/kernel/microcode_core.c index 0db7969b0dde..9371448290ac 100644 --- a/trunk/arch/x86/kernel/microcode_core.c +++ b/trunk/arch/x86/kernel/microcode_core.c @@ -236,7 +236,7 @@ static const struct file_operations microcode_fops = { static struct miscdevice microcode_dev = { .minor = MICROCODE_MINOR, .name = "microcode", - .nodename = "cpu/microcode", + .devnode = "cpu/microcode", .fops = µcode_fops, }; diff --git a/trunk/arch/x86/kernel/msr.c b/trunk/arch/x86/kernel/msr.c index 6a3cefc7dda1..7dd950094178 100644 --- a/trunk/arch/x86/kernel/msr.c +++ b/trunk/arch/x86/kernel/msr.c @@ -241,7 +241,7 @@ static struct notifier_block __refdata msr_class_cpu_notifier = { .notifier_call = msr_class_cpu_callback, }; -static char *msr_devnode(struct device *dev, mode_t *mode) +static char *msr_nodename(struct device *dev) { return kasprintf(GFP_KERNEL, "cpu/%u/msr", MINOR(dev->devt)); } @@ -262,7 +262,7 @@ static int __init msr_init(void) err = PTR_ERR(msr_class); goto out_chrdev; } - msr_class->devnode = msr_devnode; + msr_class->nodename = msr_nodename; for_each_online_cpu(i) { err = msr_device_create(i); if (err != 0) diff --git a/trunk/arch/x86/kernel/process.c b/trunk/arch/x86/kernel/process.c index 847ab4160315..071166a4ba83 100644 --- a/trunk/arch/x86/kernel/process.c +++ b/trunk/arch/x86/kernel/process.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include @@ -25,6 +25,9 @@ EXPORT_SYMBOL(idle_nomwait); struct kmem_cache *task_xstate_cachep; +DEFINE_TRACE(power_start); +DEFINE_TRACE(power_end); + int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) { *dst = *src; @@ -296,7 +299,9 @@ static inline int hlt_use_halt(void) void default_idle(void) { if (hlt_use_halt()) { - trace_power_start(POWER_CSTATE, 1); + struct power_trace it; + + trace_power_start(&it, POWER_CSTATE, 1); current_thread_info()->status &= ~TS_POLLING; /* * TS_POLLING-cleared state must be visible before we @@ -309,6 +314,7 @@ void default_idle(void) else local_irq_enable(); current_thread_info()->status |= TS_POLLING; + trace_power_end(&it); } else { local_irq_enable(); /* loop is done by the caller */ @@ -366,7 +372,9 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait); */ void mwait_idle_with_hints(unsigned long ax, unsigned long cx) { - trace_power_start(POWER_CSTATE, (ax>>4)+1); + struct power_trace it; + + trace_power_start(&it, POWER_CSTATE, (ax>>4)+1); if (!need_resched()) { if (cpu_has(¤t_cpu_data, X86_FEATURE_CLFLUSH_MONITOR)) clflush((void *)¤t_thread_info()->flags); @@ -376,13 +384,15 @@ void mwait_idle_with_hints(unsigned long ax, unsigned long cx) if (!need_resched()) __mwait(ax, cx); } + trace_power_end(&it); } /* Default MONITOR/MWAIT with no hints, used for default C1 state */ static void mwait_idle(void) { + struct power_trace it; if (!need_resched()) { - trace_power_start(POWER_CSTATE, 1); + trace_power_start(&it, POWER_CSTATE, 1); if (cpu_has(¤t_cpu_data, X86_FEATURE_CLFLUSH_MONITOR)) clflush((void *)¤t_thread_info()->flags); @@ -392,6 +402,7 @@ static void mwait_idle(void) __sti_mwait(0, 0); else local_irq_enable(); + trace_power_end(&it); } else local_irq_enable(); } @@ -403,11 +414,13 @@ static void mwait_idle(void) */ static void poll_idle(void) { - trace_power_start(POWER_CSTATE, 0); + struct power_trace it; + + trace_power_start(&it, POWER_CSTATE, 0); local_irq_enable(); while (!need_resched()) cpu_relax(); - trace_power_end(0); + trace_power_end(&it); } /* diff --git a/trunk/block/bsg.c b/trunk/block/bsg.c index 0676301f16d0..5f184bb3ff9e 100644 --- a/trunk/block/bsg.c +++ b/trunk/block/bsg.c @@ -1062,7 +1062,7 @@ EXPORT_SYMBOL_GPL(bsg_register_queue); static struct cdev bsg_cdev; -static char *bsg_devnode(struct device *dev, mode_t *mode) +static char *bsg_nodename(struct device *dev) { return kasprintf(GFP_KERNEL, "bsg/%s", dev_name(dev)); } @@ -1087,7 +1087,7 @@ static int __init bsg_init(void) ret = PTR_ERR(bsg_class); goto destroy_kmemcache; } - bsg_class->devnode = bsg_devnode; + bsg_class->nodename = bsg_nodename; ret = alloc_chrdev_region(&devid, 0, BSG_MAX_DEVS, "bsg"); if (ret) diff --git a/trunk/block/genhd.c b/trunk/block/genhd.c index 517e4332cb37..2ad91ddad8e2 100644 --- a/trunk/block/genhd.c +++ b/trunk/block/genhd.c @@ -998,12 +998,12 @@ struct class block_class = { .name = "block", }; -static char *block_devnode(struct device *dev, mode_t *mode) +static char *block_nodename(struct device *dev) { struct gendisk *disk = dev_to_disk(dev); - if (disk->devnode) - return disk->devnode(disk, mode); + if (disk->nodename) + return disk->nodename(disk); return NULL; } @@ -1011,7 +1011,7 @@ static struct device_type disk_type = { .name = "disk", .groups = disk_attr_groups, .release = disk_release, - .devnode = block_devnode, + .nodename = block_nodename, }; #ifdef CONFIG_PROC_FS diff --git a/trunk/drivers/base/core.c b/trunk/drivers/base/core.c index 6bee6af8d8e1..390e664ec1c7 100644 --- a/trunk/drivers/base/core.c +++ b/trunk/drivers/base/core.c @@ -166,16 +166,13 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, if (MAJOR(dev->devt)) { const char *tmp; const char *name; - mode_t mode = 0; add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt)); add_uevent_var(env, "MINOR=%u", MINOR(dev->devt)); - name = device_get_devnode(dev, &mode, &tmp); + name = device_get_nodename(dev, &tmp); if (name) { add_uevent_var(env, "DEVNAME=%s", name); kfree(tmp); - if (mode) - add_uevent_var(env, "DEVMODE=%#o", mode & 0777); } } @@ -1151,9 +1148,8 @@ static struct device *next_device(struct klist_iter *i) } /** - * device_get_devnode - path of device node file + * device_get_nodename - path of device node file * @dev: device - * @mode: returned file access mode * @tmp: possibly allocated string * * Return the relative path of a possible device node. @@ -1161,22 +1157,21 @@ static struct device *next_device(struct klist_iter *i) * a name. This memory is returned in tmp and needs to be * freed by the caller. */ -const char *device_get_devnode(struct device *dev, - mode_t *mode, const char **tmp) +const char *device_get_nodename(struct device *dev, const char **tmp) { char *s; *tmp = NULL; /* the device type may provide a specific name */ - if (dev->type && dev->type->devnode) - *tmp = dev->type->devnode(dev, mode); + if (dev->type && dev->type->nodename) + *tmp = dev->type->nodename(dev); if (*tmp) return *tmp; /* the class may provide a specific name */ - if (dev->class && dev->class->devnode) - *tmp = dev->class->devnode(dev, mode); + if (dev->class && dev->class->nodename) + *tmp = dev->class->nodename(dev); if (*tmp) return *tmp; diff --git a/trunk/drivers/base/devtmpfs.c b/trunk/drivers/base/devtmpfs.c index a1cb5afe6801..fd488ad4263a 100644 --- a/trunk/drivers/base/devtmpfs.c +++ b/trunk/drivers/base/devtmpfs.c @@ -6,10 +6,9 @@ * During bootup, before any driver core device is registered, * devtmpfs, a tmpfs-based filesystem is created. Every driver-core * device which requests a device node, will add a node in this - * filesystem. - * By default, all devices are named after the the name of the - * device, owned by root and have a default mode of 0600. Subsystems - * can overwrite the default setting if needed. + * filesystem. The node is named after the the name of the device, + * or the susbsytem can provide a custom name. All devices are + * owned by root and have a mode of 0600. */ #include @@ -21,7 +20,6 @@ #include #include #include -#include #include static struct vfsmount *dev_mnt; @@ -136,7 +134,7 @@ int devtmpfs_create_node(struct device *dev) const char *tmp = NULL; const char *nodename; const struct cred *curr_cred; - mode_t mode = 0; + mode_t mode; struct nameidata nd; struct dentry *dentry; int err; @@ -144,16 +142,14 @@ int devtmpfs_create_node(struct device *dev) if (!dev_mnt) return 0; - nodename = device_get_devnode(dev, &mode, &tmp); + nodename = device_get_nodename(dev, &tmp); if (!nodename) return -ENOMEM; - if (mode == 0) - mode = 0600; if (is_blockdev(dev)) - mode |= S_IFBLK; + mode = S_IFBLK|0600; else - mode |= S_IFCHR; + mode = S_IFCHR|0600; curr_cred = override_creds(&init_cred); err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, @@ -169,12 +165,8 @@ int devtmpfs_create_node(struct device *dev) dentry = lookup_create(&nd, 0); if (!IS_ERR(dentry)) { - int umask; - - umask = sys_umask(0000); err = vfs_mknod(nd.path.dentry->d_inode, dentry, mode, dev->devt); - sys_umask(umask); /* mark as kernel created inode */ if (!err) dentry->d_inode->i_private = &dev_mnt; @@ -279,7 +271,7 @@ int devtmpfs_delete_node(struct device *dev) if (!dev_mnt) return 0; - nodename = device_get_devnode(dev, NULL, &tmp); + nodename = device_get_nodename(dev, &tmp); if (!nodename) return -ENOMEM; diff --git a/trunk/drivers/block/aoe/aoechr.c b/trunk/drivers/block/aoe/aoechr.c index 62141ec09a22..19888354188f 100644 --- a/trunk/drivers/block/aoe/aoechr.c +++ b/trunk/drivers/block/aoe/aoechr.c @@ -266,7 +266,7 @@ static const struct file_operations aoe_fops = { .owner = THIS_MODULE, }; -static char *aoe_devnode(struct device *dev, mode_t *mode) +static char *aoe_nodename(struct device *dev) { return kasprintf(GFP_KERNEL, "etherd/%s", dev_name(dev)); } @@ -288,7 +288,7 @@ aoechr_init(void) unregister_chrdev(AOE_MAJOR, "aoechr"); return PTR_ERR(aoe_class); } - aoe_class->devnode = aoe_devnode; + aoe_class->nodename = aoe_nodename; for (i = 0; i < ARRAY_SIZE(chardevs); ++i) device_create(aoe_class, NULL, diff --git a/trunk/drivers/block/pktcdvd.c b/trunk/drivers/block/pktcdvd.c index fd5bb8ad59a9..95f11cdef203 100644 --- a/trunk/drivers/block/pktcdvd.c +++ b/trunk/drivers/block/pktcdvd.c @@ -2857,7 +2857,7 @@ static struct block_device_operations pktcdvd_ops = { .media_changed = pkt_media_changed, }; -static char *pktcdvd_devnode(struct gendisk *gd, mode_t *mode) +static char *pktcdvd_nodename(struct gendisk *gd) { return kasprintf(GFP_KERNEL, "pktcdvd/%s", gd->disk_name); } @@ -2914,7 +2914,7 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev) disk->fops = &pktcdvd_ops; disk->flags = GENHD_FL_REMOVABLE; strcpy(disk->disk_name, pd->name); - disk->devnode = pktcdvd_devnode; + disk->nodename = pktcdvd_nodename; disk->private_data = pd; disk->queue = blk_alloc_queue(GFP_KERNEL); if (!disk->queue) @@ -3070,7 +3070,7 @@ static const struct file_operations pkt_ctl_fops = { static struct miscdevice pkt_misc = { .minor = MISC_DYNAMIC_MINOR, .name = DRIVER_NAME, - .nodename = "pktcdvd/control", + .name = "pktcdvd/control", .fops = &pkt_ctl_fops }; diff --git a/trunk/drivers/char/cyclades.c b/trunk/drivers/char/cyclades.c index df5038bbcbc2..2dafc2da0648 100644 --- a/trunk/drivers/char/cyclades.c +++ b/trunk/drivers/char/cyclades.c @@ -11,7 +11,7 @@ * Initially written by Randolph Bentson . * Modified and maintained by Marcio Saito . * - * Copyright (C) 2007-2009 Jiri Slaby + * Copyright (C) 2007 Jiri Slaby * * Much of the design and some of the code came from serial.c * which was copyright (C) 1991, 1992 Linus Torvalds. It was @@ -19,9 +19,577 @@ * and then fixed as suggested by Michael K. Johnson 12/12/92. * Converted to pci probing and cleaned up by Jiri Slaby. * + * This version supports shared IRQ's (only for PCI boards). + * + * Prevent users from opening non-existing Z ports. + * + * Revision 2.3.2.8 2000/07/06 18:14:16 ivan + * Fixed the PCI detection function to work properly on Alpha systems. + * Implemented support for TIOCSERGETLSR ioctl. + * Implemented full support for non-standard baud rates. + * + * Revision 2.3.2.7 2000/06/01 18:26:34 ivan + * Request PLX I/O region, although driver doesn't use it, to avoid + * problems with other drivers accessing it. + * Removed count for on-board buffer characters in cy_chars_in_buffer + * (Cyclades-Z only). + * + * Revision 2.3.2.6 2000/05/05 13:56:05 ivan + * Driver now reports physical instead of virtual memory addresses. + * Masks were added to some Cyclades-Z read accesses. + * Implemented workaround for PLX9050 bug that would cause a system lockup + * in certain systems, depending on the MMIO addresses allocated to the + * board. + * Changed the Tx interrupt programming in the CD1400 chips to boost up + * performance (Cyclom-Y only). + * Code is now compliant with the new module interface (module_[init|exit]). + * Make use of the PCI helper functions to access PCI resources. + * Did some code "housekeeping". + * + * Revision 2.3.2.5 2000/01/19 14:35:33 ivan + * Fixed bug in cy_set_termios on CRTSCTS flag turnoff. + * + * Revision 2.3.2.4 2000/01/17 09:19:40 ivan + * Fixed SMP locking in Cyclom-Y interrupt handler. + * + * Revision 2.3.2.3 1999/12/28 12:11:39 ivan + * Added a new cyclades_card field called nports to allow the driver to + * know the exact number of ports found by the Z firmware after its load; + * RX buffer contention prevention logic on interrupt op mode revisited + * (Cyclades-Z only); + * Revisited printk's for Z debug; + * Driver now makes sure that the constant SERIAL_XMIT_SIZE is defined; + * + * Revision 2.3.2.2 1999/10/01 11:27:43 ivan + * Fixed bug in cyz_poll that would make all ports but port 0 + * unable to transmit/receive data (Cyclades-Z only); + * Implemented logic to prevent the RX buffer from being stuck with data + * due to a driver / firmware race condition in interrupt op mode + * (Cyclades-Z only); + * Fixed bug in block_til_ready logic that would lead to a system crash; + * Revisited cy_close spinlock usage; + * + * Revision 2.3.2.1 1999/09/28 11:01:22 ivan + * Revisited CONFIG_PCI conditional compilation for PCI board support; + * Implemented TIOCGICOUNT and TIOCMIWAIT ioctl support; + * _Major_ cleanup on the Cyclades-Z interrupt support code / logic; + * Removed CTS handling from the driver -- this is now completely handled + * by the firmware (Cyclades-Z only); + * Flush RX on-board buffers on a port open (Cyclades-Z only); + * Fixed handling of ASYNC_SPD_* TTY flags; + * Module unload now unmaps all memory area allocated by ioremap; + * + * Revision 2.3.1.1 1999/07/15 16:45:53 ivan + * Removed CY_PROC conditional compilation; + * Implemented SMP-awareness for the driver; + * Implemented a new ISA IRQ autoprobe that uses the irq_probe_[on|off] + * functions; + * The driver now accepts memory addresses (maddr=0xMMMMM) and IRQs + * (irq=NN) as parameters (only for ISA boards); + * Fixed bug in set_line_char that would prevent the Cyclades-Z + * ports from being configured at speeds above 115.2Kbps; + * Fixed bug in cy_set_termios that would prevent XON/XOFF flow control + * switching from working properly; + * The driver now only prints IRQ info for the Cyclades-Z if it's + * configured to work in interrupt mode; + * + * Revision 2.2.2.3 1999/06/28 11:13:29 ivan + * Added support for interrupt mode operation for the Z cards; + * Removed the driver inactivity control for the Z; + * Added a missing MOD_DEC_USE_COUNT in the cy_open function for when + * the Z firmware is not loaded yet; + * Replaced the "manual" Z Tx flush buffer by a call to a FW command of + * same functionality; + * Implemented workaround for IRQ setting loss on the PCI configuration + * registers after a PCI bridge EEPROM reload (affects PLX9060 only); + * + * Revision 2.2.2.2 1999/05/14 17:18:15 ivan + * /proc entry location changed to /proc/tty/driver/cyclades; + * Added support to shared IRQ's (only for PCI boards); + * Added support for Cobalt Qube2 systems; + * IRQ [de]allocation scheme revisited; + * BREAK implementation changed in order to make use of the 'break_ctl' + * TTY facility; + * Fixed typo in TTY structure field 'driver_name'; + * Included a PCI bridge reset and EEPROM reload in the board + * initialization code (for both Y and Z series). + * + * Revision 2.2.2.1 1999/04/08 16:17:43 ivan + * Fixed a bug in cy_wait_until_sent that was preventing the port to be + * closed properly after a SIGINT; + * Module usage counter scheme revisited; + * Added support to the upcoming Y PCI boards (i.e., support to additional + * PCI Device ID's). + * + * Revision 2.2.1.10 1999/01/20 16:14:29 ivan + * Removed all unnecessary page-alignement operations in ioremap calls + * (ioremap is currently safe for these operations). + * + * Revision 2.2.1.9 1998/12/30 18:18:30 ivan + * Changed access to PLX PCI bridge registers from I/O to MMIO, in + * order to make PLX9050-based boards work with certain motherboards. + * + * Revision 2.2.1.8 1998/11/13 12:46:20 ivan + * cy_close function now resets (correctly) the tty->closing flag; + * JIFFIES_DIFF macro fixed. + * + * Revision 2.2.1.7 1998/09/03 12:07:28 ivan + * Fixed bug in cy_close function, which was not informing HW of + * which port should have the reception disabled before doing so; + * fixed Cyclom-8YoP hardware detection bug. + * + * Revision 2.2.1.6 1998/08/20 17:15:39 ivan + * Fixed bug in cy_close function, which causes malfunction + * of one of the first 4 ports when a higher port is closed + * (Cyclom-Y only). + * + * Revision 2.2.1.5 1998/08/10 18:10:28 ivan + * Fixed Cyclom-4Yo hardware detection bug. + * + * Revision 2.2.1.4 1998/08/04 11:02:50 ivan + * /proc/cyclades implementation with great collaboration of + * Marc Lewis ; + * cyy_interrupt was changed to avoid occurrence of kernel oopses + * during PPP operation. + * + * Revision 2.2.1.3 1998/06/01 12:09:10 ivan + * General code review in order to comply with 2.1 kernel standards; + * data loss prevention for slow devices revisited (cy_wait_until_sent + * was created); + * removed conditional compilation for new/old PCI structure support + * (now the driver only supports the new PCI structure). + * + * Revision 2.2.1.1 1998/03/19 16:43:12 ivan + * added conditional compilation for new/old PCI structure support; + * removed kernel series (2.0.x / 2.1.x) conditional compilation. + * + * Revision 2.1.1.3 1998/03/16 18:01:12 ivan + * cleaned up the data loss fix; + * fixed XON/XOFF handling once more (Cyclades-Z); + * general review of the driver routines; + * introduction of a mechanism to prevent data loss with slow + * printers, by forcing a delay before closing the port. + * + * Revision 2.1.1.2 1998/02/17 16:50:00 ivan + * fixed detection/handling of new CD1400 in Ye boards; + * fixed XON/XOFF handling (Cyclades-Z); + * fixed data loss caused by a premature port close; + * introduction of a flag that holds the CD1400 version ID per port + * (used by the CYGETCD1400VER new ioctl). + * + * Revision 2.1.1.1 1997/12/03 17:31:19 ivan + * Code review for the module cleanup routine; + * fixed RTS and DTR status report for new CD1400's in get_modem_info; + * includes anonymous changes regarding signal_pending. + * + * Revision 2.1 1997/11/01 17:42:41 ivan + * Changes in the driver to support Alpha systems (except 8Zo V_1); + * BREAK fix for the Cyclades-Z boards; + * driver inactivity control by FW implemented; + * introduction of flag that allows driver to take advantage of + * a special CD1400 feature related to HW flow control; + * added support for the CD1400 rev. J (Cyclom-Y boards); + * introduction of ioctls to: + * - control the rtsdtr_inv flag (Cyclom-Y); + * - control the rflow flag (Cyclom-Y); + * - adjust the polling interval (Cyclades-Z); + * + * Revision 1.36.4.33 1997/06/27 19:00:00 ivan + * Fixes related to kernel version conditional + * compilation. + * + * Revision 1.36.4.32 1997/06/14 19:30:00 ivan + * Compatibility issues between kernels 2.0.x and + * 2.1.x (mainly related to clear_bit function). + * + * Revision 1.36.4.31 1997/06/03 15:30:00 ivan + * Changes to define the memory window according to the + * board type. + * + * Revision 1.36.4.30 1997/05/16 15:30:00 daniel + * Changes to support new cycladesZ boards. + * + * Revision 1.36.4.29 1997/05/12 11:30:00 daniel + * Merge of Bentson's and Daniel's version 1.36.4.28. + * Corrects bug in cy_detect_pci: check if there are more + * ports than the number of static structs allocated. + * Warning message during initialization if this driver is + * used with the new generation of cycladesZ boards. Those + * will be supported only in next release of the driver. + * Corrects bug in cy_detect_pci and cy_detect_isa that + * returned wrong number of VALID boards, when a cyclomY + * was found with no serial modules connected. + * Changes to use current (2.1.x) kernel subroutine names + * and created macros for compilation with 2.0.x kernel, + * instead of the other way around. + * + * Revision 1.36.4.28 1997/05/?? ??:00:00 bentson + * Change queue_task_irq_off to queue_task_irq. + * The inline function queue_task_irq_off (tqueue.h) + * was removed from latest releases of 2.1.x kernel. + * Use of macro __init to mark the initialization + * routines, so memory can be reused. + * Also incorporate implementation of critical region + * in function cleanup_module() created by anonymous + * linuxer. + * + * Revision 1.36.4.28 1997/04/25 16:00:00 daniel + * Change to support new firmware that solves DCD problem: + * application could fail to receive SIGHUP signal when DCD + * varying too fast. + * + * Revision 1.36.4.27 1997/03/26 10:30:00 daniel + * Changed for support linux versions 2.1.X. + * Backward compatible with linux versions 2.0.X. + * Corrected illegal use of filler field in + * CH_CTRL struct. + * Deleted some debug messages. + * + * Revision 1.36.4.26 1997/02/27 12:00:00 daniel + * Included check for NULL tty pointer in cyz_poll. + * + * Revision 1.36.4.25 1997/02/26 16:28:30 bentson + * Bill Foster at Blarg! Online services noticed that + * some of the switch elements of -Z modem control + * lacked a closing "break;" + * + * Revision 1.36.4.24 1997/02/24 11:00:00 daniel + * Changed low water threshold for buffer xmit_buf + * + * Revision 1.36.4.23 1996/12/02 21:50:16 bentson + * Marcio provided fix to modem status fetch for -Z + * + * Revision 1.36.4.22 1996/10/28 22:41:17 bentson + * improve mapping of -Z control page (thanks to Steve + * Price for help on this) + * + * Revision 1.36.4.21 1996/09/10 17:00:10 bentson + * shift from CPU-bound to memcopy in cyz_polling operation + * + * Revision 1.36.4.20 1996/09/09 18:30:32 Bentson + * Added support to set and report higher speeds. + * + * Revision 1.36.4.19c 1996/08/09 10:00:00 Marcio Saito + * Some fixes in the HW flow control for the BETA release. + * Don't try to register the IRQ. + * + * Revision 1.36.4.19 1996/08/08 16:23:18 Bentson + * make sure "cyc" appears in all kernel messages; all soft interrupts + * handled by same routine; recognize out-of-band reception; comment + * out some diagnostic messages; leave RTS/CTS flow control to hardware; + * fix race condition in -Z buffer management; only -Y needs to explicitly + * flush chars; tidy up some startup messages; + * + * Revision 1.36.4.18 1996/07/25 18:57:31 bentson + * shift MOD_INC_USE_COUNT location to match + * serial.c; purge some diagnostic messages; + * + * Revision 1.36.4.17 1996/07/25 18:01:08 bentson + * enable modem status messages and fetch & process them; note + * time of last activity type for each port; set_line_char now + * supports more than line 0 and treats 0 baud correctly; + * get_modem_info senses rs_status; + * + * Revision 1.36.4.16 1996/07/20 08:43:15 bentson + * barely works--now's time to turn on + * more features 'til it breaks + * + * Revision 1.36.4.15 1996/07/19 22:30:06 bentson + * check more -Z board status; shorten boot message + * + * Revision 1.36.4.14 1996/07/19 22:20:37 bentson + * fix reference to ch_ctrl in startup; verify return + * values from cyz_issue_cmd and cyz_update_channel; + * more stuff to get modem control correct; + * + * Revision 1.36.4.13 1996/07/11 19:53:33 bentson + * more -Z stuff folded in; re-order changes to put -Z stuff + * after -Y stuff (to make changes clearer) + * + * Revision 1.36.4.12 1996/07/11 15:40:55 bentson + * Add code to poll Cyclades-Z. Add code to get & set RS-232 control. + * Add code to send break. Clear firmware ID word at startup (so + * that other code won't talk to inactive board). + * + * Revision 1.36.4.11 1996/07/09 05:28:29 bentson + * add code for -Z in set_line_char + * + * Revision 1.36.4.10 1996/07/08 19:28:37 bentson + * fold more -Z stuff (or in some cases, error messages) + * into driver; add text to "don't know what to do" messages. + * + * Revision 1.36.4.9 1996/07/08 18:38:38 bentson + * moved compile-time flags near top of file; cosmetic changes + * to narrow text (to allow 2-up printing); changed many declarations + * to "static" to limit external symbols; shuffled code order to + * coalesce -Y and -Z specific code, also to put internal functions + * in order of tty_driver structure; added code to recognize -Z + * ports (and for moment, do nothing or report error); add cy_startup + * to parse boot command line for extra base addresses for ISA probes; + * + * Revision 1.36.4.8 1996/06/25 17:40:19 bentson + * reorder some code, fix types of some vars (int vs. long), + * add cy_setup to support user declared ISA addresses + * + * Revision 1.36.4.7 1996/06/21 23:06:18 bentson + * dump ioctl based firmware load (it's now a user level + * program); ensure uninitialzed ports cannot be used + * + * Revision 1.36.4.6 1996/06/20 23:17:19 bentson + * rename vars and restructure some code + * + * Revision 1.36.4.5 1996/06/14 15:09:44 bentson + * get right status back after boot load + * + * Revision 1.36.4.4 1996/06/13 19:51:44 bentson + * successfully loads firmware + * + * Revision 1.36.4.3 1996/06/13 06:08:33 bentson + * add more of the code for the boot/load ioctls + * + * Revision 1.36.4.2 1996/06/11 21:00:51 bentson + * start to add Z functionality--starting with ioctl + * for loading firmware + * + * Revision 1.36.4.1 1996/06/10 18:03:02 bentson + * added code to recognize Z/PCI card at initialization; report + * presence, but card is not initialized (because firmware needs + * to be loaded) + * + * Revision 1.36.3.8 1996/06/07 16:29:00 bentson + * starting minor number at zero; added missing verify_area + * as noted by Heiko Eißfeldt + * + * Revision 1.36.3.7 1996/04/19 21:06:18 bentson + * remove unneeded boot message & fix CLOCAL hardware flow + * control (Miquel van Smoorenburg ); + * remove unused diagnostic statements; minor 0 is first; + * + * Revision 1.36.3.6 1996/03/13 13:21:17 marcio + * The kernel function vremap (available only in later 1.3.xx kernels) + * allows the access to memory addresses above the RAM. This revision + * of the driver supports PCI boards below 1Mb (device id 0x100) and + * above 1Mb (device id 0x101). + * + * Revision 1.36.3.5 1996/03/07 15:20:17 bentson + * Some global changes to interrupt handling spilled into + * this driver--mostly unused arguments in system function + * calls. Also added change by Marcio Saito which should + * reduce lost interrupts at startup by fast processors. + * + * Revision 1.36.3.4 1995/11/13 20:45:10 bentson + * Changes by Corey Minyard distributed + * in 1.3.41 kernel to remove a possible race condition, extend + * some error messages, and let the driver run as a loadable module + * Change by Alan Wendt to remove a + * possible race condition. + * Change by Marcio Saito to fix PCI addressing. + * + * Revision 1.36.3.3 1995/11/13 19:44:48 bentson + * Changes by Linus Torvalds in 1.3.33 kernel distribution + * required due to reordering of driver initialization. + * Drivers are now initialized *after* memory management. + * + * Revision 1.36.3.2 1995/09/08 22:07:14 bentson + * remove printk from ISR; fix typo + * + * Revision 1.36.3.1 1995/09/01 12:00:42 marcio + * Minor fixes in the PCI board support. PCI function calls in + * conditional compilation (CONFIG_PCI). Thanks to Jim Duncan + * . "bad serial count" message removed. + * + * Revision 1.36.3 1995/08/22 09:19:42 marcio + * Cyclom-Y/PCI support added. Changes in the cy_init routine and + * board initialization. Changes in the boot messages. The driver + * supports up to 4 boards and 64 ports by default. + * + * Revision 1.36.1.4 1995/03/29 06:14:14 bentson + * disambiguate between Cyclom-16Y and Cyclom-32Ye; + * + * Revision 1.36.1.3 1995/03/23 22:15:35 bentson + * add missing break in modem control block in ioctl switch statement + * (discovered by Michael Edward Chastain ); + * + * Revision 1.36.1.2 1995/03/22 19:16:22 bentson + * make sure CTS flow control is set as soon as possible (thanks + * to note from David Lambert ); + * + * Revision 1.36.1.1 1995/03/13 15:44:43 bentson + * initialize defaults for receive threshold and stale data timeout; + * cosmetic changes; + * + * Revision 1.36 1995/03/10 23:33:53 bentson + * added support of chips 4-7 in 32 port Cyclom-Ye; + * fix cy_interrupt pointer dereference problem + * (Joe Portman ); + * give better error response if open is attempted on non-existent port + * (Zachariah Vaum ); + * correct command timeout (Kenneth Lerman ); + * conditional compilation for -16Y on systems with fast, noisy bus; + * comment out diagnostic print function; + * cleaned up table of base addresses; + * set receiver time-out period register to correct value, + * set receive threshold to better default values, + * set chip timer to more accurate 200 Hz ticking, + * add code to monitor and modify receive parameters + * (Rik Faith Nick Simicich + * ); + * + * Revision 1.35 1994/12/16 13:54:18 steffen + * additional patch by Marcio Saito for board detection + * Accidently left out in 1.34 + * + * Revision 1.34 1994/12/10 12:37:12 steffen + * This is the corrected version as suggested by Marcio Saito + * + * Revision 1.33 1994/12/01 22:41:18 bentson + * add hooks to support more high speeds directly; add tytso + * patch regarding CLOCAL wakeups + * + * Revision 1.32 1994/11/23 19:50:04 bentson + * allow direct kernel control of higher signalling rates; + * look for cards at additional locations + * + * Revision 1.31 1994/11/16 04:33:28 bentson + * ANOTHER fix from Corey Minyard, minyard@wf-rch.cirr.com-- + * a problem in chars_in_buffer has been resolved by some + * small changes; this should yield smoother output + * + * Revision 1.30 1994/11/16 04:28:05 bentson + * Fix from Corey Minyard, Internet: minyard@metronet.com, + * UUCP: minyard@wf-rch.cirr.com, WORK: minyardbnr.ca, to + * cy_hangup that appears to clear up much (all?) of the + * DTR glitches; also he's added/cleaned-up diagnostic messages + * + * Revision 1.29 1994/11/16 04:16:07 bentson + * add change proposed by Ralph Sims, ralphs@halcyon.com, to + * operate higher speeds in same way as other serial ports; + * add more serial ports (for up to two 16-port muxes). + * + * Revision 1.28 1994/11/04 00:13:16 root + * turn off diagnostic messages + * + * Revision 1.27 1994/11/03 23:46:37 root + * bunch of changes to bring driver into greater conformance + * with the serial.c driver (looking for missed fixes) + * + * Revision 1.26 1994/11/03 22:40:36 root + * automatic interrupt probing fixed. + * + * Revision 1.25 1994/11/03 20:17:02 root + * start to implement auto-irq + * + * Revision 1.24 1994/11/03 18:01:55 root + * still working on modem signals--trying not to drop DTR + * during the getty/login processes + * + * Revision 1.23 1994/11/03 17:51:36 root + * extend baud rate support; set receive threshold as function + * of baud rate; fix some problems with RTS/CTS; + * + * Revision 1.22 1994/11/02 18:05:35 root + * changed arguments to udelay to type long to get + * delays to be of correct duration + * + * Revision 1.21 1994/11/02 17:37:30 root + * employ udelay (after calibrating loops_per_second earlier + * in init/main.c) instead of using home-grown delay routines + * + * Revision 1.20 1994/11/02 03:11:38 root + * cy_chars_in_buffer forces a return value of 0 to let + * login work (don't know why it does); some functions + * that were returning EFAULT, now executes the code; + * more work on deciding when to disable xmit interrupts; + * + * Revision 1.19 1994/11/01 20:10:14 root + * define routine to start transmission interrupts (by enabling + * transmit interrupts); directly enable/disable modem interrupts; + * + * Revision 1.18 1994/11/01 18:40:45 bentson + * Don't always enable transmit interrupts in startup; interrupt on + * TxMpty instead of TxRdy to help characters get out before shutdown; + * restructure xmit interrupt to check for chars first and quit if + * none are ready to go; modem status (MXVRx) is upright, _not_ inverted + * (to my view); + * + * Revision 1.17 1994/10/30 04:39:45 bentson + * rename serial_driver and callout_driver to cy_serial_driver and + * cy_callout_driver to avoid linkage interference; initialize + * info->type to PORT_CIRRUS; ruggedize paranoia test; elide ->port + * from cyclades_port structure; add paranoia check to cy_close; + * + * Revision 1.16 1994/10/30 01:14:33 bentson + * change major numbers; add some _early_ return statements; + * + * Revision 1.15 1994/10/29 06:43:15 bentson + * final tidying up for clean compile; enable some error reporting + * + * Revision 1.14 1994/10/28 20:30:22 Bentson + * lots of changes to drag the driver towards the new tty_io + * structures and operation. not expected to work, but may + * compile cleanly. + * + * Revision 1.13 1994/07/21 23:08:57 Bentson + * add some diagnostic cruft; support 24 lines (for testing + * both -8Y and -16Y cards; be more thorough in servicing all + * chips during interrupt; add "volatile" a few places to + * circumvent compiler optimizations; fix base & offset + * computations in block_til_ready (was causing chip 0 to + * stop operation) + * + * Revision 1.12 1994/07/19 16:42:11 Bentson + * add some hackery for kernel version 1.1.8; expand + * error messages; refine timing for delay loops and + * declare loop params volatile + * + * Revision 1.11 1994/06/11 21:53:10 bentson + * get use of save_car right in transmit interrupt service + * + * Revision 1.10.1.1 1994/06/11 21:31:18 bentson + * add some diagnostic printing; try to fix save_car stuff + * + * Revision 1.10 1994/06/11 20:36:08 bentson + * clean up compiler warnings + * + * Revision 1.9 1994/06/11 19:42:46 bentson + * added a bunch of code to support modem signalling + * + * Revision 1.8 1994/06/11 17:57:07 bentson + * recognize break & parity error + * + * Revision 1.7 1994/06/05 05:51:34 bentson + * Reorder baud table to be monotonic; add cli to CP; discard + * incoming characters and status if the line isn't open; start to + * fold code into cy_throttle; start to port get_serial_info, + * set_serial_info, get_modem_info, set_modem_info, and send_break + * from serial.c; expand cy_ioctl; relocate and expand config_setup; + * get flow control characters from tty struct; invalidate ports w/o + * hardware; + * + * Revision 1.6 1994/05/31 18:42:21 bentson + * add a loop-breaker in the interrupt service routine; + * note when port is initialized so that it can be shut + * down under the right conditions; receive works without + * any obvious errors + * + * Revision 1.5 1994/05/30 00:55:02 bentson + * transmit works without obvious errors + * + * Revision 1.4 1994/05/27 18:46:27 bentson + * incorporated more code from lib_y.c; can now print short + * strings under interrupt control to port zero; seems to + * select ports/channels/lines correctly + * + * Revision 1.3 1994/05/25 22:12:44 bentson + * shifting from multi-port on a card to proper multiplexor + * data structures; added skeletons of most routines + * + * Revision 1.2 1994/05/19 13:21:43 bentson + * start to crib from other sources + * */ -#define CY_VERSION "2.6" +#define CY_VERSION "2.5" /* If you need to install more boards than NR_CARDS, change the constant in the definition below. No other change is necessary to support up to @@ -80,7 +648,9 @@ #include #include +#include #include +#include #include #include @@ -90,11 +660,13 @@ #include #include +static void cy_throttle(struct tty_struct *tty); static void cy_send_xchar(struct tty_struct *tty, char ch); #ifndef SERIAL_XMIT_SIZE #define SERIAL_XMIT_SIZE (min(PAGE_SIZE, 4096)) #endif +#define WAKEUP_CHARS 256 #define STD_COM_FLAGS (0) @@ -184,25 +756,25 @@ static int cy_next_channel; /* next minor available */ * HI VHI * 20 */ -static const int baud_table[] = { +static int baud_table[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000, 230400, 0 }; -static const char baud_co_25[] = { /* 25 MHz clock option table */ +static char baud_co_25[] = { /* 25 MHz clock option table */ /* value => 00 01 02 03 04 */ /* divide by 8 32 128 512 2048 */ 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static const char baud_bpr_25[] = { /* 25 MHz baud rate period table */ +static char baud_bpr_25[] = { /* 25 MHz baud rate period table */ 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3, 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15 }; -static const char baud_co_60[] = { /* 60 MHz clock option table (CD1400 J) */ +static char baud_co_60[] = { /* 60 MHz clock option table (CD1400 J) */ /* value => 00 01 02 03 04 */ /* divide by 8 32 128 512 2048 */ 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, @@ -210,13 +782,13 @@ static const char baud_co_60[] = { /* 60 MHz clock option table (CD1400 J) */ 0x00 }; -static const char baud_bpr_60[] = { /* 60 MHz baud rate period table (CD1400 J) */ +static char baud_bpr_60[] = { /* 60 MHz baud rate period table (CD1400 J) */ 0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62, 0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32, 0x21 }; -static const char baud_cor3[] = { /* receive threshold */ +static char baud_cor3[] = { /* receive threshold */ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07, 0x07 @@ -233,7 +805,7 @@ static const char baud_cor3[] = { /* receive threshold */ * cables. */ -static const char rflow_thr[] = { /* rflow threshold */ +static char rflow_thr[] = { /* rflow threshold */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a @@ -242,7 +814,7 @@ static const char rflow_thr[] = { /* rflow threshold */ /* The Cyclom-Ye has placed the sequential chips in non-sequential * address order. This look-up table overcomes that problem. */ -static const unsigned int cy_chip_offset[] = { 0x0000, +static int cy_chip_offset[] = { 0x0000, 0x0400, 0x0800, 0x0C00, @@ -255,7 +827,7 @@ static const unsigned int cy_chip_offset[] = { 0x0000, /* PCI related definitions */ #ifdef CONFIG_PCI -static const struct pci_device_id cy_pci_dev_id[] = { +static struct pci_device_id cy_pci_dev_id[] __devinitdata = { /* PCI < 1Mb */ { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) }, /* PCI > 1Mb */ @@ -278,7 +850,7 @@ MODULE_DEVICE_TABLE(pci, cy_pci_dev_id); #endif static void cy_start(struct tty_struct *); -static void cy_set_line_char(struct cyclades_port *, struct tty_struct *); +static void set_line_char(struct cyclades_port *); static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32); #ifdef CONFIG_ISA static unsigned detect_isa_irq(void __iomem *); @@ -297,20 +869,6 @@ static void cyz_rx_restart(unsigned long); static struct timer_list cyz_rx_full_timer[NR_PORTS]; #endif /* CONFIG_CYZ_INTR */ -static inline void cyy_writeb(struct cyclades_port *port, u32 reg, u8 val) -{ - struct cyclades_card *card = port->card; - - cy_writeb(port->u.cyy.base_addr + (reg << card->bus_index), val); -} - -static inline u8 cyy_readb(struct cyclades_port *port, u32 reg) -{ - struct cyclades_card *card = port->card; - - return readb(port->u.cyy.base_addr + (reg << card->bus_index)); -} - static inline bool cy_is_Z(struct cyclades_card *card) { return card->num_chips == (unsigned int)-1; @@ -335,7 +893,7 @@ static inline bool cyz_is_loaded(struct cyclades_card *card) } static inline int serial_paranoia_check(struct cyclades_port *info, - const char *name, const char *routine) + char *name, const char *routine) { #ifdef SERIAL_PARANOIA_CHECK if (!info) { @@ -351,7 +909,7 @@ static inline int serial_paranoia_check(struct cyclades_port *info, } #endif return 0; -} +} /* serial_paranoia_check */ /***********************************************************/ /********* Start of block of Cyclom-Y specific code ********/ @@ -363,14 +921,13 @@ static inline int serial_paranoia_check(struct cyclades_port *info, This function is only called from inside spinlock-protected code. */ -static int __cyy_issue_cmd(void __iomem *base_addr, u8 cmd, int index) +static int cyy_issue_cmd(void __iomem *base_addr, u_char cmd, int index) { - void __iomem *ccr = base_addr + (CyCCR << index); unsigned int i; /* Check to see that the previous command has completed */ for (i = 0; i < 100; i++) { - if (readb(ccr) == 0) + if (readb(base_addr + (CyCCR << index)) == 0) break; udelay(10L); } @@ -380,16 +937,10 @@ static int __cyy_issue_cmd(void __iomem *base_addr, u8 cmd, int index) return -1; /* Issue the new command */ - cy_writeb(ccr, cmd); + cy_writeb(base_addr + (CyCCR << index), cmd); return 0; -} - -static inline int cyy_issue_cmd(struct cyclades_port *port, u8 cmd) -{ - return __cyy_issue_cmd(port->u.cyy.base_addr, cmd, - port->card->bus_index); -} +} /* cyy_issue_cmd */ #ifdef CONFIG_ISA /* ISA interrupt detection code */ @@ -409,12 +960,12 @@ static unsigned detect_isa_irq(void __iomem *address) irqs = probe_irq_on(); /* Wait ... */ - msleep(5); + udelay(5000L); /* Enable the Tx interrupts on the CD1400 */ local_irq_save(flags); cy_writeb(address + (CyCAR << index), 0); - __cyy_issue_cmd(address, CyCHAN_CTL | CyENB_XMTR, index); + cyy_issue_cmd(address, CyCHAN_CTL | CyENB_XMTR, index); cy_writeb(address + (CyCAR << index), 0); cy_writeb(address + (CySRER << index), @@ -422,7 +973,7 @@ static unsigned detect_isa_irq(void __iomem *address) local_irq_restore(flags); /* Wait ... */ - msleep(5); + udelay(5000L); /* Check which interrupt is in use */ irq = probe_irq_off(irqs); @@ -448,7 +999,7 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, struct cyclades_port *info; struct tty_struct *tty; int len, index = cinfo->bus_index; - u8 ivr, save_xir, channel, save_car, data, char_count; + u8 save_xir, channel, save_car, data, char_count; #ifdef CY_DEBUG_INTERRUPTS printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip); @@ -457,25 +1008,26 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, save_xir = readb(base_addr + (CyRIR << index)); channel = save_xir & CyIRChannel; info = &cinfo->ports[channel + chip * 4]; - save_car = cyy_readb(info, CyCAR); - cyy_writeb(info, CyCAR, save_xir); - ivr = cyy_readb(info, CyRIVR) & CyIVRMask; + save_car = readb(base_addr + (CyCAR << index)); + cy_writeb(base_addr + (CyCAR << index), save_xir); - tty = tty_port_tty_get(&info->port); /* if there is nowhere to put the data, discard it */ - if (tty == NULL) { - if (ivr == CyIVRRxEx) { /* exception */ - data = cyy_readb(info, CyRDSR); + if (info->port.tty == NULL) { + if ((readb(base_addr + (CyRIVR << index)) & CyIVRMask) == + CyIVRRxEx) { /* exception */ + data = readb(base_addr + (CyRDSR << index)); } else { /* normal character reception */ - char_count = cyy_readb(info, CyRDCR); + char_count = readb(base_addr + (CyRDCR << index)); while (char_count--) - data = cyy_readb(info, CyRDSR); + data = readb(base_addr + (CyRDSR << index)); } goto end; } /* there is an open port for this data */ - if (ivr == CyIVRRxEx) { /* exception */ - data = cyy_readb(info, CyRDSR); + tty = info->port.tty; + if ((readb(base_addr + (CyRIVR << index)) & CyIVRMask) == + CyIVRRxEx) { /* exception */ + data = readb(base_addr + (CyRDSR << index)); /* For statistics only */ if (data & CyBREAK) @@ -489,29 +1041,28 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, if (data & info->ignore_status_mask) { info->icount.rx++; - tty_kref_put(tty); return; } if (tty_buffer_request_room(tty, 1)) { if (data & info->read_status_mask) { if (data & CyBREAK) { tty_insert_flip_char(tty, - cyy_readb(info, CyRDSR), - TTY_BREAK); + readb(base_addr + (CyRDSR << + index)), TTY_BREAK); info->icount.rx++; if (info->port.flags & ASYNC_SAK) do_SAK(tty); } else if (data & CyFRAME) { tty_insert_flip_char(tty, - cyy_readb(info, CyRDSR), - TTY_FRAME); + readb(base_addr + (CyRDSR << + index)), TTY_FRAME); info->icount.rx++; info->idle_stats.frame_errs++; } else if (data & CyPARITY) { /* Pieces of seven... */ tty_insert_flip_char(tty, - cyy_readb(info, CyRDSR), - TTY_PARITY); + readb(base_addr + (CyRDSR << + index)), TTY_PARITY); info->icount.rx++; info->idle_stats.parity_errs++; } else if (data & CyOVERRUN) { @@ -523,8 +1074,8 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, the next incoming character. */ tty_insert_flip_char(tty, - cyy_readb(info, CyRDSR), - TTY_FRAME); + readb(base_addr + (CyRDSR << + index)), TTY_FRAME); info->icount.rx++; info->idle_stats.overruns++; /* These two conditions may imply */ @@ -548,7 +1099,7 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, } } else { /* normal character reception */ /* load # chars available from the chip */ - char_count = cyy_readb(info, CyRDCR); + char_count = readb(base_addr + (CyRDCR << index)); #ifdef CY_ENABLE_MONITORING ++info->mon.int_count; @@ -559,7 +1110,7 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, #endif len = tty_buffer_request_room(tty, char_count); while (len--) { - data = cyy_readb(info, CyRDSR); + data = readb(base_addr + (CyRDSR << index)); tty_insert_flip_char(tty, data, TTY_NORMAL); info->idle_stats.recv_bytes++; info->icount.rx++; @@ -570,18 +1121,16 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, info->idle_stats.recv_idle = jiffies; } tty_schedule_flip(tty); - tty_kref_put(tty); end: /* end of service */ - cyy_writeb(info, CyRIR, save_xir & 0x3f); - cyy_writeb(info, CyCAR, save_car); + cy_writeb(base_addr + (CyRIR << index), save_xir & 0x3f); + cy_writeb(base_addr + (CyCAR << index), save_car); } static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip, void __iomem *base_addr) { struct cyclades_port *info; - struct tty_struct *tty; int char_count, index = cinfo->bus_index; u8 save_xir, channel, save_car, outch; @@ -605,9 +1154,9 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip, goto end; } info = &cinfo->ports[channel + chip * 4]; - tty = tty_port_tty_get(&info->port); - if (tty == NULL) { - cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy); + if (info->port.tty == NULL) { + cy_writeb(base_addr + (CySRER << index), + readb(base_addr + (CySRER << index)) & ~CyTxRdy); goto end; } @@ -616,7 +1165,7 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip, if (info->x_char) { /* send special char */ outch = info->x_char; - cyy_writeb(info, CyTDR, outch); + cy_writeb(base_addr + (CyTDR << index), outch); char_count--; info->icount.tx++; info->x_char = 0; @@ -624,14 +1173,14 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip, if (info->breakon || info->breakoff) { if (info->breakon) { - cyy_writeb(info, CyTDR, 0); - cyy_writeb(info, CyTDR, 0x81); + cy_writeb(base_addr + (CyTDR << index), 0); + cy_writeb(base_addr + (CyTDR << index), 0x81); info->breakon = 0; char_count -= 2; } if (info->breakoff) { - cyy_writeb(info, CyTDR, 0); - cyy_writeb(info, CyTDR, 0x83); + cy_writeb(base_addr + (CyTDR << index), 0); + cy_writeb(base_addr + (CyTDR << index), 0x83); info->breakoff = 0; char_count -= 2; } @@ -639,23 +1188,27 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip, while (char_count-- > 0) { if (!info->xmit_cnt) { - if (cyy_readb(info, CySRER) & CyTxMpty) { - cyy_writeb(info, CySRER, - cyy_readb(info, CySRER) & ~CyTxMpty); + if (readb(base_addr + (CySRER << index)) & CyTxMpty) { + cy_writeb(base_addr + (CySRER << index), + readb(base_addr + (CySRER << index)) & + ~CyTxMpty); } else { - cyy_writeb(info, CySRER, CyTxMpty | - (cyy_readb(info, CySRER) & ~CyTxRdy)); + cy_writeb(base_addr + (CySRER << index), + (readb(base_addr + (CySRER << index)) & + ~CyTxRdy) | CyTxMpty); } goto done; } if (info->port.xmit_buf == NULL) { - cyy_writeb(info, CySRER, - cyy_readb(info, CySRER) & ~CyTxRdy); + cy_writeb(base_addr + (CySRER << index), + readb(base_addr + (CySRER << index)) & + ~CyTxRdy); goto done; } - if (tty->stopped || tty->hw_stopped) { - cyy_writeb(info, CySRER, - cyy_readb(info, CySRER) & ~CyTxRdy); + if (info->port.tty->stopped || info->port.tty->hw_stopped) { + cy_writeb(base_addr + (CySRER << index), + readb(base_addr + (CySRER << index)) & + ~CyTxRdy); goto done; } /* Because the Embedded Transmit Commands have been enabled, @@ -672,15 +1225,15 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip, info->xmit_cnt--; info->xmit_tail = (info->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1); - cyy_writeb(info, CyTDR, outch); + cy_writeb(base_addr + (CyTDR << index), outch); info->icount.tx++; } else { if (char_count > 1) { info->xmit_cnt--; info->xmit_tail = (info->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1); - cyy_writeb(info, CyTDR, outch); - cyy_writeb(info, CyTDR, 0); + cy_writeb(base_addr + (CyTDR << index), outch); + cy_writeb(base_addr + (CyTDR << index), 0); info->icount.tx++; char_count--; } @@ -688,19 +1241,17 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip, } done: - tty_wakeup(tty); - tty_kref_put(tty); + tty_wakeup(info->port.tty); end: /* end of service */ - cyy_writeb(info, CyTIR, save_xir & 0x3f); - cyy_writeb(info, CyCAR, save_car); + cy_writeb(base_addr + (CyTIR << index), save_xir & 0x3f); + cy_writeb(base_addr + (CyCAR << index), save_car); } static void cyy_chip_modem(struct cyclades_card *cinfo, int chip, void __iomem *base_addr) { struct cyclades_port *info; - struct tty_struct *tty; int index = cinfo->bus_index; u8 save_xir, channel, save_car, mdm_change, mdm_status; @@ -708,14 +1259,13 @@ static void cyy_chip_modem(struct cyclades_card *cinfo, int chip, save_xir = readb(base_addr + (CyMIR << index)); channel = save_xir & CyIRChannel; info = &cinfo->ports[channel + chip * 4]; - save_car = cyy_readb(info, CyCAR); - cyy_writeb(info, CyCAR, save_xir); + save_car = readb(base_addr + (CyCAR << index)); + cy_writeb(base_addr + (CyCAR << index), save_xir); - mdm_change = cyy_readb(info, CyMISR); - mdm_status = cyy_readb(info, CyMSVR1); + mdm_change = readb(base_addr + (CyMISR << index)); + mdm_status = readb(base_addr + (CyMSVR1 << index)); - tty = tty_port_tty_get(&info->port); - if (!tty) + if (!info->port.tty) goto end; if (mdm_change & CyANY_DELTA) { @@ -729,32 +1279,35 @@ static void cyy_chip_modem(struct cyclades_card *cinfo, int chip, if (mdm_change & CyRI) info->icount.rng++; - wake_up_interruptible(&info->port.delta_msr_wait); + wake_up_interruptible(&info->delta_msr_wait); } if ((mdm_change & CyDCD) && (info->port.flags & ASYNC_CHECK_CD)) { - if (mdm_status & CyDCD) - wake_up_interruptible(&info->port.open_wait); - else - tty_hangup(tty); + if (!(mdm_status & CyDCD)) { + tty_hangup(info->port.tty); + info->port.flags &= ~ASYNC_NORMAL_ACTIVE; + } + wake_up_interruptible(&info->port.open_wait); } if ((mdm_change & CyCTS) && (info->port.flags & ASYNC_CTS_FLOW)) { - if (tty->hw_stopped) { + if (info->port.tty->hw_stopped) { if (mdm_status & CyCTS) { /* cy_start isn't used because... !!! */ - tty->hw_stopped = 0; - cyy_writeb(info, CySRER, - cyy_readb(info, CySRER) | CyTxRdy); - tty_wakeup(tty); + info->port.tty->hw_stopped = 0; + cy_writeb(base_addr + (CySRER << index), + readb(base_addr + (CySRER << index)) | + CyTxRdy); + tty_wakeup(info->port.tty); } } else { if (!(mdm_status & CyCTS)) { /* cy_stop isn't used because ... !!! */ - tty->hw_stopped = 1; - cyy_writeb(info, CySRER, - cyy_readb(info, CySRER) & ~CyTxRdy); + info->port.tty->hw_stopped = 1; + cy_writeb(base_addr + (CySRER << index), + readb(base_addr + (CySRER << index)) & + ~CyTxRdy); } } } @@ -762,11 +1315,10 @@ static void cyy_chip_modem(struct cyclades_card *cinfo, int chip, } if (mdm_change & CyRI) { }*/ - tty_kref_put(tty); end: /* end of service */ - cyy_writeb(info, CyMIR, save_xir & 0x3f); - cyy_writeb(info, CyCAR, save_car); + cy_writeb(base_addr + (CyMIR << index), save_xir & 0x3f); + cy_writeb(base_addr + (CyCAR << index), save_car); } /* The real interrupt service routine is called @@ -837,56 +1389,6 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } /* cyy_interrupt */ -static void cyy_change_rts_dtr(struct cyclades_port *info, unsigned int set, - unsigned int clear) -{ - struct cyclades_card *card = info->card; - int channel = info->line - card->first_line; - u32 rts, dtr, msvrr, msvrd; - - channel &= 0x03; - - if (info->rtsdtr_inv) { - msvrr = CyMSVR2; - msvrd = CyMSVR1; - rts = CyDTR; - dtr = CyRTS; - } else { - msvrr = CyMSVR1; - msvrd = CyMSVR2; - rts = CyRTS; - dtr = CyDTR; - } - if (set & TIOCM_RTS) { - cyy_writeb(info, CyCAR, channel); - cyy_writeb(info, msvrr, rts); - } - if (clear & TIOCM_RTS) { - cyy_writeb(info, CyCAR, channel); - cyy_writeb(info, msvrr, ~rts); - } - if (set & TIOCM_DTR) { - cyy_writeb(info, CyCAR, channel); - cyy_writeb(info, msvrd, dtr); -#ifdef CY_DEBUG_DTR - printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n"); - printk(KERN_DEBUG " status: 0x%x, 0x%x\n", - cyy_readb(info, CyMSVR1), - cyy_readb(info, CyMSVR2)); -#endif - } - if (clear & TIOCM_DTR) { - cyy_writeb(info, CyCAR, channel); - cyy_writeb(info, msvrd, ~dtr); -#ifdef CY_DEBUG_DTR - printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n"); - printk(KERN_DEBUG " status: 0x%x, 0x%x\n", - cyy_readb(info, CyMSVR1), - cyy_readb(info, CyMSVR2)); -#endif - } -} - /***********************************************************/ /********* End of block of Cyclom-Y specific code **********/ /******** Start of block of Cyclades-Z specific code *******/ @@ -896,9 +1398,15 @@ static int cyz_fetch_msg(struct cyclades_card *cinfo, __u32 *channel, __u8 *cmd, __u32 *param) { - struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl; + struct FIRM_ID __iomem *firm_id; + struct ZFW_CTRL __iomem *zfw_ctrl; + struct BOARD_CTRL __iomem *board_ctrl; unsigned long loc_doorbell; + firm_id = cinfo->base_addr + ID_ADDRESS; + zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); + board_ctrl = &zfw_ctrl->board_ctrl; + loc_doorbell = readl(&cinfo->ctl_addr.p9060->loc_doorbell); if (loc_doorbell) { *cmd = (char)(0xff & loc_doorbell); @@ -914,13 +1422,19 @@ static int cyz_issue_cmd(struct cyclades_card *cinfo, __u32 channel, __u8 cmd, __u32 param) { - struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl; + struct FIRM_ID __iomem *firm_id; + struct ZFW_CTRL __iomem *zfw_ctrl; + struct BOARD_CTRL __iomem *board_ctrl; __u32 __iomem *pci_doorbell; unsigned int index; + firm_id = cinfo->base_addr + ID_ADDRESS; if (!cyz_is_loaded(cinfo)) return -1; + zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); + board_ctrl = &zfw_ctrl->board_ctrl; + index = 0; pci_doorbell = &cinfo->ctl_addr.p9060->pci_doorbell; while ((readl(pci_doorbell) & 0xff) != 0) { @@ -935,10 +1449,11 @@ cyz_issue_cmd(struct cyclades_card *cinfo, return 0; } /* cyz_issue_cmd */ -static void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty) +static void cyz_handle_rx(struct cyclades_port *info, + struct BUF_CTRL __iomem *buf_ctrl) { - struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl; struct cyclades_card *cinfo = info->card; + struct tty_struct *tty = info->port.tty; unsigned int char_count; int len; #ifdef BLOCKMOVE @@ -1027,10 +1542,11 @@ static void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty) } } -static void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty) +static void cyz_handle_tx(struct cyclades_port *info, + struct BUF_CTRL __iomem *buf_ctrl) { - struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl; struct cyclades_card *cinfo = info->card; + struct tty_struct *tty = info->port.tty; u8 data; unsigned int char_count; #ifdef BLOCKMOVE @@ -1105,24 +1621,34 @@ static void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty) static void cyz_handle_cmd(struct cyclades_card *cinfo) { - struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl; struct tty_struct *tty; struct cyclades_port *info; + static struct FIRM_ID __iomem *firm_id; + static struct ZFW_CTRL __iomem *zfw_ctrl; + static struct BOARD_CTRL __iomem *board_ctrl; + static struct CH_CTRL __iomem *ch_ctrl; + static struct BUF_CTRL __iomem *buf_ctrl; __u32 channel, param, fw_ver; __u8 cmd; int special_count; int delta_count; + firm_id = cinfo->base_addr + ID_ADDRESS; + zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); + board_ctrl = &zfw_ctrl->board_ctrl; fw_ver = readl(&board_ctrl->fw_version); while (cyz_fetch_msg(cinfo, &channel, &cmd, ¶m) == 1) { special_count = 0; delta_count = 0; info = &cinfo->ports[channel]; - tty = tty_port_tty_get(&info->port); + tty = info->port.tty; if (tty == NULL) continue; + ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]); + buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]); + switch (cmd) { case C_CM_PR_ERROR: tty_insert_flip_char(tty, 0, TTY_PARITY); @@ -1143,12 +1669,15 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) info->icount.dcd++; delta_count++; if (info->port.flags & ASYNC_CHECK_CD) { - u32 dcd = fw_ver > 241 ? param : - readl(&info->u.cyz.ch_ctrl->rs_status); - if (dcd & C_RS_DCD) + if ((fw_ver > 241 ? ((u_long) param) : + readl(&ch_ctrl->rs_status)) & + C_RS_DCD) { + wake_up_interruptible(&info->port.open_wait); + } else { + tty_hangup(info->port.tty); wake_up_interruptible(&info->port.open_wait); - else - tty_hangup(tty); + info->port.flags &= ~ASYNC_NORMAL_ACTIVE; + } } break; case C_CM_MCTS: @@ -1177,7 +1706,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, " "port %ld\n", info->card, channel); #endif - cyz_handle_rx(info, tty); + cyz_handle_rx(info, buf_ctrl); break; case C_CM_TXBEMPTY: case C_CM_TXLOWWM: @@ -1187,7 +1716,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, " "port %ld\n", info->card, channel); #endif - cyz_handle_tx(info, tty); + cyz_handle_tx(info, buf_ctrl); break; #endif /* CONFIG_CYZ_INTR */ case C_CM_FATAL: @@ -1197,10 +1726,9 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) break; } if (delta_count) - wake_up_interruptible(&info->port.delta_msr_wait); + wake_up_interruptible(&info->delta_msr_wait); if (special_count) tty_schedule_flip(tty); - tty_kref_put(tty); } } @@ -1246,6 +1774,10 @@ static void cyz_poll(unsigned long arg) { struct cyclades_card *cinfo; struct cyclades_port *info; + struct tty_struct *tty; + struct FIRM_ID __iomem *firm_id; + struct ZFW_CTRL __iomem *zfw_ctrl; + struct BUF_CTRL __iomem *buf_ctrl; unsigned long expires = jiffies + HZ; unsigned int port, card; @@ -1257,6 +1789,10 @@ static void cyz_poll(unsigned long arg) if (!cyz_is_loaded(cinfo)) continue; + firm_id = cinfo->base_addr + ID_ADDRESS; + zfw_ctrl = cinfo->base_addr + + (readl(&firm_id->zfwctrl_addr) & 0xfffff); + /* Skip first polling cycle to avoid racing conditions with the FW */ if (!cinfo->intr_enabled) { cinfo->intr_enabled = 1; @@ -1266,17 +1802,13 @@ static void cyz_poll(unsigned long arg) cyz_handle_cmd(cinfo); for (port = 0; port < cinfo->nports; port++) { - struct tty_struct *tty; - info = &cinfo->ports[port]; - tty = tty_port_tty_get(&info->port); - /* OK to pass NULL to the handle functions below. - They need to drop the data in that case. */ + tty = info->port.tty; + buf_ctrl = &(zfw_ctrl->buf_ctrl[port]); if (!info->throttle) - cyz_handle_rx(info, tty); - cyz_handle_tx(info, tty); - tty_kref_put(tty); + cyz_handle_rx(info, buf_ctrl); + cyz_handle_tx(info, buf_ctrl); } /* poll every 'cyz_polling_cycle' period */ expires = jiffies + cyz_polling_cycle; @@ -1292,12 +1824,13 @@ static void cyz_poll(unsigned long arg) /* This is called whenever a port becomes active; interrupts are enabled and DTR & RTS are turned on. */ -static int cy_startup(struct cyclades_port *info, struct tty_struct *tty) +static int startup(struct cyclades_port *info) { struct cyclades_card *card; unsigned long flags; int retval = 0; - int channel; + void __iomem *base_addr; + int chip, channel, index; unsigned long page; card = info->card; @@ -1309,11 +1842,15 @@ static int cy_startup(struct cyclades_port *info, struct tty_struct *tty) spin_lock_irqsave(&card->card_lock, flags); - if (info->port.flags & ASYNC_INITIALIZED) + if (info->port.flags & ASYNC_INITIALIZED) { + free_page(page); goto errout; + } if (!info->type) { - set_bit(TTY_IO_ERROR, &tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); + free_page(page); goto errout; } @@ -1324,53 +1861,96 @@ static int cy_startup(struct cyclades_port *info, struct tty_struct *tty) spin_unlock_irqrestore(&card->card_lock, flags); - cy_set_line_char(info, tty); + set_line_char(info); if (!cy_is_Z(card)) { + chip = channel >> 2; channel &= 0x03; + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); +#ifdef CY_DEBUG_OPEN + printk(KERN_DEBUG "cyc startup card %d, chip %d, channel %d, " + "base_addr %p\n", + card, chip, channel, base_addr); +#endif spin_lock_irqsave(&card->card_lock, flags); - cyy_writeb(info, CyCAR, channel); + cy_writeb(base_addr + (CyCAR << index), (u_char) channel); - cyy_writeb(info, CyRTPR, + cy_writeb(base_addr + (CyRTPR << index), (info->default_timeout ? info->default_timeout : 0x02)); /* 10ms rx timeout */ - cyy_issue_cmd(info, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR); + cyy_issue_cmd(base_addr, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR, + index); + + cy_writeb(base_addr + (CyCAR << index), (u_char) channel); + cy_writeb(base_addr + (CyMSVR1 << index), CyRTS); + cy_writeb(base_addr + (CyMSVR2 << index), CyDTR); + +#ifdef CY_DEBUG_DTR + printk(KERN_DEBUG "cyc:startup raising DTR\n"); + printk(KERN_DEBUG " status: 0x%x, 0x%x\n", + readb(base_addr + (CyMSVR1 << index)), + readb(base_addr + (CyMSVR2 << index))); +#endif + + cy_writeb(base_addr + (CySRER << index), + readb(base_addr + (CySRER << index)) | CyRxData); + info->port.flags |= ASYNC_INITIALIZED; + + if (info->port.tty) + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + info->breakon = info->breakoff = 0; + memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats)); + info->idle_stats.in_use = + info->idle_stats.recv_idle = + info->idle_stats.xmit_idle = jiffies; - cyy_change_rts_dtr(info, TIOCM_RTS | TIOCM_DTR, 0); + spin_unlock_irqrestore(&card->card_lock, flags); - cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyRxData); } else { - struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl; + struct FIRM_ID __iomem *firm_id; + struct ZFW_CTRL __iomem *zfw_ctrl; + struct BOARD_CTRL __iomem *board_ctrl; + struct CH_CTRL __iomem *ch_ctrl; + + base_addr = card->base_addr; + firm_id = base_addr + ID_ADDRESS; if (!cyz_is_loaded(card)) return -ENODEV; + zfw_ctrl = card->base_addr + + (readl(&firm_id->zfwctrl_addr) & 0xfffff); + board_ctrl = &zfw_ctrl->board_ctrl; + ch_ctrl = zfw_ctrl->ch_ctrl; + #ifdef CY_DEBUG_OPEN printk(KERN_DEBUG "cyc startup Z card %d, channel %d, " - "base_addr %p\n", card, channel, card->base_addr); + "base_addr %p\n", card, channel, base_addr); #endif spin_lock_irqsave(&card->card_lock, flags); - cy_writel(&ch_ctrl->op_mode, C_CH_ENABLE); + cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE); #ifdef Z_WAKE #ifdef CONFIG_CYZ_INTR - cy_writel(&ch_ctrl->intr_enable, + cy_writel(&ch_ctrl[channel].intr_enable, C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM | C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD); #else - cy_writel(&ch_ctrl->intr_enable, + cy_writel(&ch_ctrl[channel].intr_enable, C_IN_IOCTLW | C_IN_MDCD); #endif /* CONFIG_CYZ_INTR */ #else #ifdef CONFIG_CYZ_INTR - cy_writel(&ch_ctrl->intr_enable, + cy_writel(&ch_ctrl[channel].intr_enable, C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM | C_IN_RXNNDT | C_IN_MDCD); #else - cy_writel(&ch_ctrl->intr_enable, C_IN_MDCD); + cy_writel(&ch_ctrl[channel].intr_enable, C_IN_MDCD); #endif /* CONFIG_CYZ_INTR */ #endif /* Z_WAKE */ @@ -1389,22 +1969,32 @@ static int cy_startup(struct cyclades_port *info, struct tty_struct *tty) /* set timeout !!! */ /* set RTS and DTR !!! */ - tty_port_raise_dtr_rts(&info->port); + cy_writel(&ch_ctrl[channel].rs_control, + readl(&ch_ctrl[channel].rs_control) | C_RS_RTS | + C_RS_DTR); + retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L); + if (retval != 0) { + printk(KERN_ERR "cyc:startup(3) retval on ttyC%d was " + "%x\n", info->line, retval); + } +#ifdef CY_DEBUG_DTR + printk(KERN_DEBUG "cyc:startup raising Z DTR\n"); +#endif /* enable send, recv, modem !!! */ - } - - info->port.flags |= ASYNC_INITIALIZED; - clear_bit(TTY_IO_ERROR, &tty->flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - info->breakon = info->breakoff = 0; - memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats)); - info->idle_stats.in_use = - info->idle_stats.recv_idle = - info->idle_stats.xmit_idle = jiffies; + info->port.flags |= ASYNC_INITIALIZED; + if (info->port.tty) + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + info->breakon = info->breakoff = 0; + memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats)); + info->idle_stats.in_use = + info->idle_stats.recv_idle = + info->idle_stats.xmit_idle = jiffies; - spin_unlock_irqrestore(&card->card_lock, flags); + spin_unlock_irqrestore(&card->card_lock, flags); + } #ifdef CY_DEBUG_OPEN printk(KERN_DEBUG "cyc startup done\n"); @@ -1413,20 +2003,28 @@ static int cy_startup(struct cyclades_port *info, struct tty_struct *tty) errout: spin_unlock_irqrestore(&card->card_lock, flags); - free_page(page); return retval; } /* startup */ static void start_xmit(struct cyclades_port *info) { - struct cyclades_card *card = info->card; + struct cyclades_card *card; unsigned long flags; - int channel = info->line - card->first_line; + void __iomem *base_addr; + int chip, channel, index; + card = info->card; + channel = info->line - card->first_line; if (!cy_is_Z(card)) { + chip = channel >> 2; + channel &= 0x03; + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); + spin_lock_irqsave(&card->card_lock, flags); - cyy_writeb(info, CyCAR, channel & 0x03); - cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy); + cy_writeb(base_addr + (CyCAR << index), channel); + cy_writeb(base_addr + (CySRER << index), + readb(base_addr + (CySRER << index)) | CyTxRdy); spin_unlock_irqrestore(&card->card_lock, flags); } else { #ifdef CONFIG_CYZ_INTR @@ -1449,11 +2047,12 @@ static void start_xmit(struct cyclades_port *info) * This routine shuts down a serial port; interrupts are disabled, * and DTR is dropped if the hangup on close termio flag is on. */ -static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty) +static void shutdown(struct cyclades_port *info) { struct cyclades_card *card; unsigned long flags; - int channel; + void __iomem *base_addr; + int chip, channel, index; if (!(info->port.flags & ASYNC_INITIALIZED)) return; @@ -1461,10 +2060,21 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty) card = info->card; channel = info->line - card->first_line; if (!cy_is_Z(card)) { + chip = channel >> 2; + channel &= 0x03; + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); + +#ifdef CY_DEBUG_OPEN + printk(KERN_DEBUG "cyc shutdown Y card %d, chip %d, " + "channel %d, base_addr %p\n", + card, chip, channel, base_addr); +#endif + spin_lock_irqsave(&card->card_lock, flags); /* Clear delta_msr_wait queue to avoid mem leaks. */ - wake_up_interruptible(&info->port.delta_msr_wait); + wake_up_interruptible(&info->delta_msr_wait); if (info->port.xmit_buf) { unsigned char *temp; @@ -1472,25 +2082,47 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty) info->port.xmit_buf = NULL; free_page((unsigned long)temp); } - if (tty->termios->c_cflag & HUPCL) - cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR); - - cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR); + cy_writeb(base_addr + (CyCAR << index), (u_char) channel); + if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) { + cy_writeb(base_addr + (CyMSVR1 << index), ~CyRTS); + cy_writeb(base_addr + (CyMSVR2 << index), ~CyDTR); +#ifdef CY_DEBUG_DTR + printk(KERN_DEBUG "cyc shutdown dropping DTR\n"); + printk(KERN_DEBUG " status: 0x%x, 0x%x\n", + readb(base_addr + (CyMSVR1 << index)), + readb(base_addr + (CyMSVR2 << index))); +#endif + } + cyy_issue_cmd(base_addr, CyCHAN_CTL | CyDIS_RCVR, index); /* it may be appropriate to clear _XMIT at some later date (after testing)!!! */ - set_bit(TTY_IO_ERROR, &tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); info->port.flags &= ~ASYNC_INITIALIZED; spin_unlock_irqrestore(&card->card_lock, flags); } else { + struct FIRM_ID __iomem *firm_id; + struct ZFW_CTRL __iomem *zfw_ctrl; + struct BOARD_CTRL __iomem *board_ctrl; + struct CH_CTRL __iomem *ch_ctrl; + int retval; + + base_addr = card->base_addr; #ifdef CY_DEBUG_OPEN printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, " - "base_addr %p\n", card, channel, card->base_addr); + "base_addr %p\n", card, channel, base_addr); #endif + firm_id = base_addr + ID_ADDRESS; if (!cyz_is_loaded(card)) return; + zfw_ctrl = card->base_addr + + (readl(&firm_id->zfwctrl_addr) & 0xfffff); + board_ctrl = &zfw_ctrl->board_ctrl; + ch_ctrl = zfw_ctrl->ch_ctrl; + spin_lock_irqsave(&card->card_lock, flags); if (info->port.xmit_buf) { @@ -1500,10 +2132,23 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty) free_page((unsigned long)temp); } - if (tty->termios->c_cflag & HUPCL) - tty_port_lower_dtr_rts(&info->port); + if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) { + cy_writel(&ch_ctrl[channel].rs_control, + (__u32)(readl(&ch_ctrl[channel].rs_control) & + ~(C_RS_RTS | C_RS_DTR))); + retval = cyz_issue_cmd(info->card, channel, + C_CM_IOCTLM, 0L); + if (retval != 0) { + printk(KERN_ERR"cyc:shutdown retval on ttyC%d " + "was %x\n", info->line, retval); + } +#ifdef CY_DEBUG_DTR + printk(KERN_DEBUG "cyc:shutdown dropping Z DTR\n"); +#endif + } - set_bit(TTY_IO_ERROR, &tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); info->port.flags &= ~ASYNC_INITIALIZED; spin_unlock_irqrestore(&card->card_lock, flags); @@ -1520,6 +2165,199 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty) * ------------------------------------------------------------ */ +static int +block_til_ready(struct tty_struct *tty, struct file *filp, + struct cyclades_port *info) +{ + DECLARE_WAITQUEUE(wait, current); + struct cyclades_card *cinfo; + unsigned long flags; + int chip, channel, index; + int retval; + void __iomem *base_addr; + + cinfo = info->card; + channel = info->line - cinfo->first_line; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) { + wait_event_interruptible(info->port.close_wait, + !(info->port.flags & ASYNC_CLOSING)); + return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS; + } + + /* + * If non-blocking mode is set, then make the check up front + * and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + info->port.flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->port.count is dropped by one, so that + * cy_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->port.open_wait, &wait); +#ifdef CY_DEBUG_OPEN + printk(KERN_DEBUG "cyc block_til_ready before block: ttyC%d, " + "count = %d\n", info->line, info->port.count); +#endif + spin_lock_irqsave(&cinfo->card_lock, flags); + if (!tty_hung_up_p(filp)) + info->port.count--; + spin_unlock_irqrestore(&cinfo->card_lock, flags); +#ifdef CY_DEBUG_COUNT + printk(KERN_DEBUG "cyc block_til_ready: (%d): decrementing count to " + "%d\n", current->pid, info->port.count); +#endif + info->port.blocked_open++; + + if (!cy_is_Z(cinfo)) { + chip = channel >> 2; + channel &= 0x03; + index = cinfo->bus_index; + base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index); + + while (1) { + spin_lock_irqsave(&cinfo->card_lock, flags); + if ((tty->termios->c_cflag & CBAUD)) { + cy_writeb(base_addr + (CyCAR << index), + (u_char) channel); + cy_writeb(base_addr + (CyMSVR1 << index), + CyRTS); + cy_writeb(base_addr + (CyMSVR2 << index), + CyDTR); +#ifdef CY_DEBUG_DTR + printk(KERN_DEBUG "cyc:block_til_ready raising " + "DTR\n"); + printk(KERN_DEBUG " status: 0x%x, 0x%x\n", + readb(base_addr + (CyMSVR1 << index)), + readb(base_addr + (CyMSVR2 << index))); +#endif + } + spin_unlock_irqrestore(&cinfo->card_lock, flags); + + set_current_state(TASK_INTERRUPTIBLE); + if (tty_hung_up_p(filp) || + !(info->port.flags & ASYNC_INITIALIZED)) { + retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); + break; + } + + spin_lock_irqsave(&cinfo->card_lock, flags); + cy_writeb(base_addr + (CyCAR << index), + (u_char) channel); + if (!(info->port.flags & ASYNC_CLOSING) && (C_CLOCAL(tty) || + (readb(base_addr + + (CyMSVR1 << index)) & CyDCD))) { + spin_unlock_irqrestore(&cinfo->card_lock, flags); + break; + } + spin_unlock_irqrestore(&cinfo->card_lock, flags); + + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } +#ifdef CY_DEBUG_OPEN + printk(KERN_DEBUG "cyc block_til_ready blocking: " + "ttyC%d, count = %d\n", + info->line, info->port.count); +#endif + schedule(); + } + } else { + struct FIRM_ID __iomem *firm_id; + struct ZFW_CTRL __iomem *zfw_ctrl; + struct BOARD_CTRL __iomem *board_ctrl; + struct CH_CTRL __iomem *ch_ctrl; + + base_addr = cinfo->base_addr; + firm_id = base_addr + ID_ADDRESS; + if (!cyz_is_loaded(cinfo)) { + __set_current_state(TASK_RUNNING); + remove_wait_queue(&info->port.open_wait, &wait); + return -EINVAL; + } + + zfw_ctrl = base_addr + (readl(&firm_id->zfwctrl_addr) + & 0xfffff); + board_ctrl = &zfw_ctrl->board_ctrl; + ch_ctrl = zfw_ctrl->ch_ctrl; + + while (1) { + if ((tty->termios->c_cflag & CBAUD)) { + cy_writel(&ch_ctrl[channel].rs_control, + readl(&ch_ctrl[channel].rs_control) | + C_RS_RTS | C_RS_DTR); + retval = cyz_issue_cmd(cinfo, + channel, C_CM_IOCTLM, 0L); + if (retval != 0) { + printk(KERN_ERR "cyc:block_til_ready " + "retval on ttyC%d was %x\n", + info->line, retval); + } +#ifdef CY_DEBUG_DTR + printk(KERN_DEBUG "cyc:block_til_ready raising " + "Z DTR\n"); +#endif + } + + set_current_state(TASK_INTERRUPTIBLE); + if (tty_hung_up_p(filp) || + !(info->port.flags & ASYNC_INITIALIZED)) { + retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); + break; + } + if (!(info->port.flags & ASYNC_CLOSING) && (C_CLOCAL(tty) || + (readl(&ch_ctrl[channel].rs_status) & + C_RS_DCD))) { + break; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } +#ifdef CY_DEBUG_OPEN + printk(KERN_DEBUG "cyc block_til_ready blocking: " + "ttyC%d, count = %d\n", + info->line, info->port.count); +#endif + schedule(); + } + } + __set_current_state(TASK_RUNNING); + remove_wait_queue(&info->port.open_wait, &wait); + if (!tty_hung_up_p(filp)) { + info->port.count++; +#ifdef CY_DEBUG_COUNT + printk(KERN_DEBUG "cyc:block_til_ready (%d): incrementing " + "count to %d\n", current->pid, info->port.count); +#endif + } + info->port.blocked_open--; +#ifdef CY_DEBUG_OPEN + printk(KERN_DEBUG "cyc:block_til_ready after blocking: ttyC%d, " + "count = %d\n", info->line, info->port.count); +#endif + if (retval) + return retval; + info->port.flags |= ASYNC_NORMAL_ACTIVE; + return 0; +} /* block_til_ready */ + /* * This routine is called whenever a serial port is opened. It * performs the serial-specific initialization for the tty structure. @@ -1598,6 +2436,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp) printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line); #endif tty->driver_data = info; + info->port.tty = tty; if (serial_paranoia_check(info, tty->name, "cy_open")) return -ENODEV; @@ -1623,11 +2462,11 @@ static int cy_open(struct tty_struct *tty, struct file *filp) /* * Start up serial port */ - retval = cy_startup(info, tty); + retval = startup(info); if (retval) return retval; - retval = tty_port_block_til_ready(&info->port, tty, filp); + retval = block_til_ready(tty, filp, info); if (retval) { #ifdef CY_DEBUG_OPEN printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready " @@ -1637,7 +2476,6 @@ static int cy_open(struct tty_struct *tty, struct file *filp) } info->throttle = 0; - tty_port_tty_set(&info->port, tty); #ifdef CY_DEBUG_OPEN printk(KERN_DEBUG "cyc:cy_open done\n"); @@ -1652,6 +2490,8 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout) { struct cyclades_card *card; struct cyclades_port *info = tty->driver_data; + void __iomem *base_addr; + int chip, channel, index; unsigned long orig_jiffies; int char_time; @@ -1695,8 +2535,13 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout) timeout, char_time, jiffies); #endif card = info->card; + channel = (info->line) - (card->first_line); if (!cy_is_Z(card)) { - while (cyy_readb(info, CySRER) & CyTxRdy) { + chip = channel >> 2; + channel &= 0x03; + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); + while (readb(base_addr + (CySRER << index)) & CyTxRdy) { #ifdef CY_DEBUG_WAIT_UNTIL_SENT printk(KERN_DEBUG "Not clean (jiff=%lu)...", jiffies); #endif @@ -1750,37 +2595,103 @@ static void cy_flush_buffer(struct tty_struct *tty) } /* cy_flush_buffer */ -static void cy_do_close(struct tty_port *port) +/* + * This routine is called when a particular tty device is closed. + */ +static void cy_close(struct tty_struct *tty, struct file *filp) { - struct cyclades_port *info = container_of(port, struct cyclades_port, - port); + struct cyclades_port *info = tty->driver_data; struct cyclades_card *card; unsigned long flags; - int channel; + +#ifdef CY_DEBUG_OTHER + printk(KERN_DEBUG "cyc:cy_close ttyC%d\n", info->line); +#endif + + if (!info || serial_paranoia_check(info, tty->name, "cy_close")) + return; card = info->card; - channel = info->line - card->first_line; + + spin_lock_irqsave(&card->card_lock, flags); + /* If the TTY is being hung up, nothing to do */ + if (tty_hung_up_p(filp)) { + spin_unlock_irqrestore(&card->card_lock, flags); + return; + } +#ifdef CY_DEBUG_OPEN + printk(KERN_DEBUG "cyc:cy_close ttyC%d, count = %d\n", info->line, + info->port.count); +#endif + if ((tty->count == 1) && (info->port.count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. Info->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk(KERN_ERR "cyc:cy_close: bad serial port count; " + "tty->count is 1, info->port.count is %d\n", info->port.count); + info->port.count = 1; + } +#ifdef CY_DEBUG_COUNT + printk(KERN_DEBUG "cyc:cy_close at (%d): decrementing count to %d\n", + current->pid, info->port.count - 1); +#endif + if (--info->port.count < 0) { +#ifdef CY_DEBUG_COUNT + printk(KERN_DEBUG "cyc:cyc_close setting count to 0\n"); +#endif + info->port.count = 0; + } + if (info->port.count) { + spin_unlock_irqrestore(&card->card_lock, flags); + return; + } + info->port.flags |= ASYNC_CLOSING; + + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + spin_unlock_irqrestore(&card->card_lock, flags); + if (info->port.closing_wait != CY_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->port.closing_wait); + spin_lock_irqsave(&card->card_lock, flags); if (!cy_is_Z(card)) { + int channel = info->line - card->first_line; + int index = card->bus_index; + void __iomem *base_addr = card->base_addr + + (cy_chip_offset[channel >> 2] << index); /* Stop accepting input */ - cyy_writeb(info, CyCAR, channel & 0x03); - cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyRxData); + channel &= 0x03; + cy_writeb(base_addr + (CyCAR << index), (u_char) channel); + cy_writeb(base_addr + (CySRER << index), + readb(base_addr + (CySRER << index)) & ~CyRxData); if (info->port.flags & ASYNC_INITIALIZED) { /* Waiting for on-board buffers to be empty before closing the port */ spin_unlock_irqrestore(&card->card_lock, flags); - cy_wait_until_sent(port->tty, info->timeout); + cy_wait_until_sent(tty, info->timeout); spin_lock_irqsave(&card->card_lock, flags); } } else { #ifdef Z_WAKE /* Waiting for on-board buffers to be empty before closing the port */ - struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl; + void __iomem *base_addr = card->base_addr; + struct FIRM_ID __iomem *firm_id = base_addr + ID_ADDRESS; + struct ZFW_CTRL __iomem *zfw_ctrl = + base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); + struct CH_CTRL __iomem *ch_ctrl = zfw_ctrl->ch_ctrl; + int channel = info->line - card->first_line; int retval; - if (readl(&ch_ctrl->flow_status) != C_FS_TXIDLE) { + if (readl(&ch_ctrl[channel].flow_status) != C_FS_TXIDLE) { retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L); if (retval != 0) { printk(KERN_DEBUG "cyc:cy_close retval on " @@ -1790,21 +2701,34 @@ static void cy_do_close(struct tty_port *port) wait_for_completion_interruptible(&info->shutdown_wait); spin_lock_irqsave(&card->card_lock, flags); } -#endif +#endif + } + + spin_unlock_irqrestore(&card->card_lock, flags); + shutdown(info); + cy_flush_buffer(tty); + tty_ldisc_flush(tty); + spin_lock_irqsave(&card->card_lock, flags); + + tty->closing = 0; + info->port.tty = NULL; + if (info->port.blocked_open) { + spin_unlock_irqrestore(&card->card_lock, flags); + if (info->port.close_delay) { + msleep_interruptible(jiffies_to_msecs + (info->port.close_delay)); + } + wake_up_interruptible(&info->port.open_wait); + spin_lock_irqsave(&card->card_lock, flags); } - spin_unlock_irqrestore(&card->card_lock, flags); - cy_shutdown(info, port->tty); -} + info->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); + wake_up_interruptible(&info->port.close_wait); -/* - * This routine is called when a particular tty device is closed. - */ -static void cy_close(struct tty_struct *tty, struct file *filp) -{ - struct cyclades_port *info = tty->driver_data; - if (!info || serial_paranoia_check(info, tty->name, "cy_close")) - return; - tty_port_close(&info->port, tty, filp); +#ifdef CY_DEBUG_OTHER + printk(KERN_DEBUG "cyc:cy_close done\n"); +#endif + + spin_unlock_irqrestore(&card->card_lock, flags); } /* cy_close */ /* This routine gets called when tty_write has put something into @@ -1947,13 +2871,18 @@ static int cy_write_room(struct tty_struct *tty) static int cy_chars_in_buffer(struct tty_struct *tty) { + struct cyclades_card *card; struct cyclades_port *info = tty->driver_data; + int channel; if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer")) return 0; + card = info->card; + channel = (info->line) - (card->first_line); + #ifdef Z_EXT_CHARS_IN_BUFFER - if (!cy_is_Z(info->card)) { + if (!cy_is_Z(card)) { #endif /* Z_EXT_CHARS_IN_BUFFER */ #ifdef CY_DEBUG_IO printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n", @@ -1962,11 +2891,20 @@ static int cy_chars_in_buffer(struct tty_struct *tty) return info->xmit_cnt; #ifdef Z_EXT_CHARS_IN_BUFFER } else { - struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl; + static struct FIRM_ID *firm_id; + static struct ZFW_CTRL *zfw_ctrl; + static struct CH_CTRL *ch_ctrl; + static struct BUF_CTRL *buf_ctrl; int char_count; __u32 tx_put, tx_get, tx_bufsize; lock_kernel(); + firm_id = card->base_addr + ID_ADDRESS; + zfw_ctrl = card->base_addr + + (readl(&firm_id->zfwctrl_addr) & 0xfffff); + ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]); + buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]); + tx_get = readl(&buf_ctrl->tx_get); tx_put = readl(&buf_ctrl->tx_put); tx_bufsize = readl(&buf_ctrl->tx_bufsize); @@ -2019,44 +2957,48 @@ static void cyy_baud_calc(struct cyclades_port *info, __u32 baud) * This routine finds or computes the various line characteristics. * It used to be called config_setup */ -static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty) +static void set_line_char(struct cyclades_port *info) { struct cyclades_card *card; unsigned long flags; - int channel; + void __iomem *base_addr; + int chip, channel, index; unsigned cflag, iflag; int baud, baud_rate = 0; int i; - if (!tty->termios) /* XXX can this happen at all? */ + if (!info->port.tty || !info->port.tty->termios) return; if (info->line == -1) return; - cflag = tty->termios->c_cflag; - iflag = tty->termios->c_iflag; + cflag = info->port.tty->termios->c_cflag; + iflag = info->port.tty->termios->c_iflag; /* * Set up the tty->alt_speed kludge */ - if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - tty->alt_speed = 57600; - if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - tty->alt_speed = 115200; - if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) - tty->alt_speed = 230400; - if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) - tty->alt_speed = 460800; + if (info->port.tty) { + if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + info->port.tty->alt_speed = 57600; + if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + info->port.tty->alt_speed = 115200; + if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + info->port.tty->alt_speed = 230400; + if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + info->port.tty->alt_speed = 460800; + } card = info->card; channel = info->line - card->first_line; if (!cy_is_Z(card)) { - u32 cflags; + + index = card->bus_index; /* baud rate */ - baud = tty_get_baud_rate(tty); + baud = tty_get_baud_rate(info->port.tty); if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) { if (info->custom_divisor) @@ -2165,68 +3107,124 @@ static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty) cable. Contact Marcio Saito for details. ***********************************************/ + chip = channel >> 2; channel &= 0x03; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); spin_lock_irqsave(&card->card_lock, flags); - cyy_writeb(info, CyCAR, channel); + cy_writeb(base_addr + (CyCAR << index), (u_char) channel); /* tx and rx baud rate */ - cyy_writeb(info, CyTCOR, info->tco); - cyy_writeb(info, CyTBPR, info->tbpr); - cyy_writeb(info, CyRCOR, info->rco); - cyy_writeb(info, CyRBPR, info->rbpr); + cy_writeb(base_addr + (CyTCOR << index), info->tco); + cy_writeb(base_addr + (CyTBPR << index), info->tbpr); + cy_writeb(base_addr + (CyRCOR << index), info->rco); + cy_writeb(base_addr + (CyRBPR << index), info->rbpr); /* set line characteristics according configuration */ - cyy_writeb(info, CySCHR1, START_CHAR(tty)); - cyy_writeb(info, CySCHR2, STOP_CHAR(tty)); - cyy_writeb(info, CyCOR1, info->cor1); - cyy_writeb(info, CyCOR2, info->cor2); - cyy_writeb(info, CyCOR3, info->cor3); - cyy_writeb(info, CyCOR4, info->cor4); - cyy_writeb(info, CyCOR5, info->cor5); + cy_writeb(base_addr + (CySCHR1 << index), + START_CHAR(info->port.tty)); + cy_writeb(base_addr + (CySCHR2 << index), STOP_CHAR(info->port.tty)); + cy_writeb(base_addr + (CyCOR1 << index), info->cor1); + cy_writeb(base_addr + (CyCOR2 << index), info->cor2); + cy_writeb(base_addr + (CyCOR3 << index), info->cor3); + cy_writeb(base_addr + (CyCOR4 << index), info->cor4); + cy_writeb(base_addr + (CyCOR5 << index), info->cor5); - cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch | - CyCOR3ch); + cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch | + CyCOR3ch, index); /* !!! Is this needed? */ - cyy_writeb(info, CyCAR, channel); - cyy_writeb(info, CyRTPR, + cy_writeb(base_addr + (CyCAR << index), (u_char) channel); + cy_writeb(base_addr + (CyRTPR << index), (info->default_timeout ? info->default_timeout : 0x02)); /* 10ms rx timeout */ - cflags = CyCTS; - if (!C_CLOCAL(tty)) - cflags |= CyDSR | CyRI | CyDCD; - /* without modem intr */ - cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyMdmCh); - /* act on 1->0 modem transitions */ - if ((cflag & CRTSCTS) && info->rflow) - cyy_writeb(info, CyMCOR1, cflags | rflow_thr[i]); - else - cyy_writeb(info, CyMCOR1, cflags); - /* act on 0->1 modem transitions */ - cyy_writeb(info, CyMCOR2, cflags); + if (C_CLOCAL(info->port.tty)) { + /* without modem intr */ + cy_writeb(base_addr + (CySRER << index), + readb(base_addr + (CySRER << index)) | CyMdmCh); + /* act on 1->0 modem transitions */ + if ((cflag & CRTSCTS) && info->rflow) { + cy_writeb(base_addr + (CyMCOR1 << index), + (CyCTS | rflow_thr[i])); + } else { + cy_writeb(base_addr + (CyMCOR1 << index), + CyCTS); + } + /* act on 0->1 modem transitions */ + cy_writeb(base_addr + (CyMCOR2 << index), CyCTS); + } else { + /* without modem intr */ + cy_writeb(base_addr + (CySRER << index), + readb(base_addr + + (CySRER << index)) | CyMdmCh); + /* act on 1->0 modem transitions */ + if ((cflag & CRTSCTS) && info->rflow) { + cy_writeb(base_addr + (CyMCOR1 << index), + (CyDSR | CyCTS | CyRI | CyDCD | + rflow_thr[i])); + } else { + cy_writeb(base_addr + (CyMCOR1 << index), + CyDSR | CyCTS | CyRI | CyDCD); + } + /* act on 0->1 modem transitions */ + cy_writeb(base_addr + (CyMCOR2 << index), + CyDSR | CyCTS | CyRI | CyDCD); + } - if (i == 0) /* baud rate is zero, turn off line */ - cyy_change_rts_dtr(info, 0, TIOCM_DTR); - else - cyy_change_rts_dtr(info, TIOCM_DTR, 0); + if (i == 0) { /* baud rate is zero, turn off line */ + if (info->rtsdtr_inv) { + cy_writeb(base_addr + (CyMSVR1 << index), + ~CyRTS); + } else { + cy_writeb(base_addr + (CyMSVR2 << index), + ~CyDTR); + } +#ifdef CY_DEBUG_DTR + printk(KERN_DEBUG "cyc:set_line_char dropping DTR\n"); + printk(KERN_DEBUG " status: 0x%x, 0x%x\n", + readb(base_addr + (CyMSVR1 << index)), + readb(base_addr + (CyMSVR2 << index))); +#endif + } else { + if (info->rtsdtr_inv) { + cy_writeb(base_addr + (CyMSVR1 << index), + CyRTS); + } else { + cy_writeb(base_addr + (CyMSVR2 << index), + CyDTR); + } +#ifdef CY_DEBUG_DTR + printk(KERN_DEBUG "cyc:set_line_char raising DTR\n"); + printk(KERN_DEBUG " status: 0x%x, 0x%x\n", + readb(base_addr + (CyMSVR1 << index)), + readb(base_addr + (CyMSVR2 << index))); +#endif + } - clear_bit(TTY_IO_ERROR, &tty->flags); + if (info->port.tty) + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); spin_unlock_irqrestore(&card->card_lock, flags); } else { - struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl; + struct FIRM_ID __iomem *firm_id; + struct ZFW_CTRL __iomem *zfw_ctrl; + struct CH_CTRL __iomem *ch_ctrl; __u32 sw_flow; int retval; + firm_id = card->base_addr + ID_ADDRESS; if (!cyz_is_loaded(card)) return; + zfw_ctrl = card->base_addr + + (readl(&firm_id->zfwctrl_addr) & 0xfffff); + ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]); + /* baud rate */ - baud = tty_get_baud_rate(tty); + baud = tty_get_baud_rate(info->port.tty); if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) { if (info->custom_divisor) @@ -2337,38 +3335,45 @@ static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty) "was %x\n", info->line, retval); } - clear_bit(TTY_IO_ERROR, &tty->flags); + if (info->port.tty) + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); } } /* set_line_char */ -static int cy_get_serial_info(struct cyclades_port *info, +static int +get_serial_info(struct cyclades_port *info, struct serial_struct __user *retinfo) { + struct serial_struct tmp; struct cyclades_card *cinfo = info->card; - struct serial_struct tmp = { - .type = info->type, - .line = info->line, - .port = (info->card - cy_card) * 0x100 + info->line - - cinfo->first_line, - .irq = cinfo->irq, - .flags = info->port.flags, - .close_delay = info->port.close_delay, - .closing_wait = info->port.closing_wait, - .baud_base = info->baud, - .custom_divisor = info->custom_divisor, - .hub6 = 0, /*!!! */ - }; + + if (!retinfo) + return -EFAULT; + memset(&tmp, 0, sizeof(tmp)); + tmp.type = info->type; + tmp.line = info->line; + tmp.port = (info->card - cy_card) * 0x100 + info->line - + cinfo->first_line; + tmp.irq = cinfo->irq; + tmp.flags = info->port.flags; + tmp.close_delay = info->port.close_delay; + tmp.closing_wait = info->port.closing_wait; + tmp.baud_base = info->baud; + tmp.custom_divisor = info->custom_divisor; + tmp.hub6 = 0; /*!!! */ return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0; -} +} /* get_serial_info */ static int -cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty, +set_serial_info(struct cyclades_port *info, struct serial_struct __user *new_info) { struct serial_struct new_serial; + struct cyclades_port old_info; if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) return -EFAULT; + old_info = *info; if (!capable(CAP_SYS_ADMIN)) { if (new_serial.close_delay != info->port.close_delay || @@ -2398,10 +3403,10 @@ cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty, check_and_exit: if (info->port.flags & ASYNC_INITIALIZED) { - cy_set_line_char(info, tty); + set_line_char(info); return 0; } else { - return cy_startup(info, tty); + return startup(info); } } /* set_serial_info */ @@ -2417,14 +3422,24 @@ cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty, */ static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value) { - struct cyclades_card *card = info->card; + struct cyclades_card *card; + int chip, channel, index; + unsigned char status; unsigned int result; unsigned long flags; - u8 status; + void __iomem *base_addr; + card = info->card; + channel = (info->line) - (card->first_line); if (!cy_is_Z(card)) { + chip = channel >> 2; + channel &= 0x03; + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); + spin_lock_irqsave(&card->card_lock, flags); - status = cyy_readb(info, CySRER) & (CyTxRdy | CyTxMpty); + status = readb(base_addr + (CySRER << index)) & + (CyTxRdy | CyTxMpty); spin_unlock_irqrestore(&card->card_lock, flags); result = (status ? 0 : TIOCSER_TEMT); } else { @@ -2438,23 +3453,34 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file) { struct cyclades_port *info = tty->driver_data; struct cyclades_card *card; - int result; + int chip, channel, index; + void __iomem *base_addr; + unsigned long flags; + unsigned char status; + unsigned long lstatus; + unsigned int result; + struct FIRM_ID __iomem *firm_id; + struct ZFW_CTRL __iomem *zfw_ctrl; + struct BOARD_CTRL __iomem *board_ctrl; + struct CH_CTRL __iomem *ch_ctrl; if (serial_paranoia_check(info, tty->name, __func__)) return -ENODEV; - card = info->card; - lock_kernel(); + + card = info->card; + channel = info->line - card->first_line; if (!cy_is_Z(card)) { - unsigned long flags; - int channel = info->line - card->first_line; - u8 status; + chip = channel >> 2; + channel &= 0x03; + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); spin_lock_irqsave(&card->card_lock, flags); - cyy_writeb(info, CyCAR, channel & 0x03); - status = cyy_readb(info, CyMSVR1); - status |= cyy_readb(info, CyMSVR2); + cy_writeb(base_addr + (CyCAR << index), (u_char) channel); + status = readb(base_addr + (CyMSVR1 << index)); + status |= readb(base_addr + (CyMSVR2 << index)); spin_unlock_irqrestore(&card->card_lock, flags); if (info->rtsdtr_inv) { @@ -2469,22 +3495,27 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file) ((status & CyDSR) ? TIOCM_DSR : 0) | ((status & CyCTS) ? TIOCM_CTS : 0); } else { - u32 lstatus; - - if (!cyz_is_loaded(card)) { - result = -ENODEV; - goto end; + base_addr = card->base_addr; + firm_id = card->base_addr + ID_ADDRESS; + if (cyz_is_loaded(card)) { + zfw_ctrl = card->base_addr + + (readl(&firm_id->zfwctrl_addr) & 0xfffff); + board_ctrl = &zfw_ctrl->board_ctrl; + ch_ctrl = zfw_ctrl->ch_ctrl; + lstatus = readl(&ch_ctrl[channel].rs_status); + result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) | + ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) | + ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) | + ((lstatus & C_RS_RI) ? TIOCM_RNG : 0) | + ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) | + ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0); + } else { + result = 0; + unlock_kernel(); + return -ENODEV; } - lstatus = readl(&info->u.cyz.ch_ctrl->rs_status); - result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) | - ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) | - ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) | - ((lstatus & C_RS_RI) ? TIOCM_RNG : 0) | - ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) | - ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0); } -end: unlock_kernel(); return result; } /* cy_tiomget */ @@ -2495,53 +3526,150 @@ cy_tiocmset(struct tty_struct *tty, struct file *file, { struct cyclades_port *info = tty->driver_data; struct cyclades_card *card; + int chip, channel, index; + void __iomem *base_addr; unsigned long flags; + struct FIRM_ID __iomem *firm_id; + struct ZFW_CTRL __iomem *zfw_ctrl; + struct BOARD_CTRL __iomem *board_ctrl; + struct CH_CTRL __iomem *ch_ctrl; + int retval; if (serial_paranoia_check(info, tty->name, __func__)) return -ENODEV; card = info->card; + channel = (info->line) - (card->first_line); if (!cy_is_Z(card)) { - spin_lock_irqsave(&card->card_lock, flags); - cyy_change_rts_dtr(info, set, clear); - spin_unlock_irqrestore(&card->card_lock, flags); - } else { - struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl; - int retval, channel = info->line - card->first_line; - u32 rs; - - if (!cyz_is_loaded(card)) - return -ENODEV; + chip = channel >> 2; + channel &= 0x03; + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); - spin_lock_irqsave(&card->card_lock, flags); - rs = readl(&ch_ctrl->rs_control); - if (set & TIOCM_RTS) - rs |= C_RS_RTS; - if (clear & TIOCM_RTS) - rs &= ~C_RS_RTS; + if (set & TIOCM_RTS) { + spin_lock_irqsave(&card->card_lock, flags); + cy_writeb(base_addr + (CyCAR << index), + (u_char) channel); + if (info->rtsdtr_inv) { + cy_writeb(base_addr + (CyMSVR2 << index), + CyDTR); + } else { + cy_writeb(base_addr + (CyMSVR1 << index), + CyRTS); + } + spin_unlock_irqrestore(&card->card_lock, flags); + } + if (clear & TIOCM_RTS) { + spin_lock_irqsave(&card->card_lock, flags); + cy_writeb(base_addr + (CyCAR << index), + (u_char) channel); + if (info->rtsdtr_inv) { + cy_writeb(base_addr + (CyMSVR2 << index), + ~CyDTR); + } else { + cy_writeb(base_addr + (CyMSVR1 << index), + ~CyRTS); + } + spin_unlock_irqrestore(&card->card_lock, flags); + } if (set & TIOCM_DTR) { - rs |= C_RS_DTR; + spin_lock_irqsave(&card->card_lock, flags); + cy_writeb(base_addr + (CyCAR << index), + (u_char) channel); + if (info->rtsdtr_inv) { + cy_writeb(base_addr + (CyMSVR1 << index), + CyRTS); + } else { + cy_writeb(base_addr + (CyMSVR2 << index), + CyDTR); + } #ifdef CY_DEBUG_DTR - printk(KERN_DEBUG "cyc:set_modem_info raising Z DTR\n"); + printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n"); + printk(KERN_DEBUG " status: 0x%x, 0x%x\n", + readb(base_addr + (CyMSVR1 << index)), + readb(base_addr + (CyMSVR2 << index))); #endif + spin_unlock_irqrestore(&card->card_lock, flags); } if (clear & TIOCM_DTR) { - rs &= ~C_RS_DTR; + spin_lock_irqsave(&card->card_lock, flags); + cy_writeb(base_addr + (CyCAR << index), + (u_char) channel); + if (info->rtsdtr_inv) { + cy_writeb(base_addr + (CyMSVR1 << index), + ~CyRTS); + } else { + cy_writeb(base_addr + (CyMSVR2 << index), + ~CyDTR); + } + +#ifdef CY_DEBUG_DTR + printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n"); + printk(KERN_DEBUG " status: 0x%x, 0x%x\n", + readb(base_addr + (CyMSVR1 << index)), + readb(base_addr + (CyMSVR2 << index))); +#endif + spin_unlock_irqrestore(&card->card_lock, flags); + } + } else { + base_addr = card->base_addr; + + firm_id = card->base_addr + ID_ADDRESS; + if (cyz_is_loaded(card)) { + zfw_ctrl = card->base_addr + + (readl(&firm_id->zfwctrl_addr) & 0xfffff); + board_ctrl = &zfw_ctrl->board_ctrl; + ch_ctrl = zfw_ctrl->ch_ctrl; + + if (set & TIOCM_RTS) { + spin_lock_irqsave(&card->card_lock, flags); + cy_writel(&ch_ctrl[channel].rs_control, + readl(&ch_ctrl[channel].rs_control) | + C_RS_RTS); + spin_unlock_irqrestore(&card->card_lock, flags); + } + if (clear & TIOCM_RTS) { + spin_lock_irqsave(&card->card_lock, flags); + cy_writel(&ch_ctrl[channel].rs_control, + readl(&ch_ctrl[channel].rs_control) & + ~C_RS_RTS); + spin_unlock_irqrestore(&card->card_lock, flags); + } + if (set & TIOCM_DTR) { + spin_lock_irqsave(&card->card_lock, flags); + cy_writel(&ch_ctrl[channel].rs_control, + readl(&ch_ctrl[channel].rs_control) | + C_RS_DTR); +#ifdef CY_DEBUG_DTR + printk(KERN_DEBUG "cyc:set_modem_info raising " + "Z DTR\n"); +#endif + spin_unlock_irqrestore(&card->card_lock, flags); + } + if (clear & TIOCM_DTR) { + spin_lock_irqsave(&card->card_lock, flags); + cy_writel(&ch_ctrl[channel].rs_control, + readl(&ch_ctrl[channel].rs_control) & + ~C_RS_DTR); #ifdef CY_DEBUG_DTR - printk(KERN_DEBUG "cyc:set_modem_info clearing " - "Z DTR\n"); + printk(KERN_DEBUG "cyc:set_modem_info clearing " + "Z DTR\n"); #endif + spin_unlock_irqrestore(&card->card_lock, flags); + } + } else { + return -ENODEV; } - cy_writel(&ch_ctrl->rs_control, rs); + spin_lock_irqsave(&card->card_lock, flags); retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L); - spin_unlock_irqrestore(&card->card_lock, flags); if (retval != 0) { printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d " "was %x\n", info->line, retval); } + spin_unlock_irqrestore(&card->card_lock, flags); } return 0; -} +} /* cy_tiocmset */ /* * cy_break() --- routine which turns the break handling on or off @@ -2606,18 +3734,41 @@ static int cy_break(struct tty_struct *tty, int break_state) return retval; } /* cy_break */ +static int get_mon_info(struct cyclades_port *info, + struct cyclades_monitor __user *mon) +{ + + if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor))) + return -EFAULT; + info->mon.int_count = 0; + info->mon.char_count = 0; + info->mon.char_max = 0; + info->mon.char_last = 0; + return 0; +} /* get_mon_info */ + static int set_threshold(struct cyclades_port *info, unsigned long value) { - struct cyclades_card *card = info->card; + struct cyclades_card *card; + void __iomem *base_addr; + int channel, chip, index; unsigned long flags; + card = info->card; + channel = info->line - card->first_line; if (!cy_is_Z(card)) { + chip = channel >> 2; + channel &= 0x03; + index = card->bus_index; + base_addr = + card->base_addr + (cy_chip_offset[chip] << index); + info->cor3 &= ~CyREC_FIFO; info->cor3 |= value & CyREC_FIFO; spin_lock_irqsave(&card->card_lock, flags); - cyy_writeb(info, CyCOR3, info->cor3); - cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR3ch); + cy_writeb(base_addr + (CyCOR3 << index), info->cor3); + cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR3ch, index); spin_unlock_irqrestore(&card->card_lock, flags); } return 0; @@ -2626,23 +3777,55 @@ static int set_threshold(struct cyclades_port *info, unsigned long value) static int get_threshold(struct cyclades_port *info, unsigned long __user *value) { - struct cyclades_card *card = info->card; + struct cyclades_card *card; + void __iomem *base_addr; + int channel, chip, index; + unsigned long tmp; + card = info->card; + channel = info->line - card->first_line; if (!cy_is_Z(card)) { - u8 tmp = cyy_readb(info, CyCOR3) & CyREC_FIFO; + chip = channel >> 2; + channel &= 0x03; + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); + + tmp = readb(base_addr + (CyCOR3 << index)) & CyREC_FIFO; return put_user(tmp, value); } return 0; } /* get_threshold */ +static int set_default_threshold(struct cyclades_port *info, + unsigned long value) +{ + info->default_threshold = value & 0x0f; + return 0; +} /* set_default_threshold */ + +static int get_default_threshold(struct cyclades_port *info, + unsigned long __user *value) +{ + return put_user(info->default_threshold, value); +} /* get_default_threshold */ + static int set_timeout(struct cyclades_port *info, unsigned long value) { - struct cyclades_card *card = info->card; + struct cyclades_card *card; + void __iomem *base_addr; + int channel, chip, index; unsigned long flags; + card = info->card; + channel = info->line - card->first_line; if (!cy_is_Z(card)) { + chip = channel >> 2; + channel &= 0x03; + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); + spin_lock_irqsave(&card->card_lock, flags); - cyy_writeb(info, CyRTPR, value & 0xff); + cy_writeb(base_addr + (CyRTPR << index), value & 0xff); spin_unlock_irqrestore(&card->card_lock, flags); } return 0; @@ -2651,35 +3834,36 @@ static int set_timeout(struct cyclades_port *info, unsigned long value) static int get_timeout(struct cyclades_port *info, unsigned long __user *value) { - struct cyclades_card *card = info->card; + struct cyclades_card *card; + void __iomem *base_addr; + int channel, chip, index; + unsigned long tmp; + card = info->card; + channel = info->line - card->first_line; if (!cy_is_Z(card)) { - u8 tmp = cyy_readb(info, CyRTPR); + chip = channel >> 2; + channel &= 0x03; + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); + + tmp = readb(base_addr + (CyRTPR << index)); return put_user(tmp, value); } return 0; } /* get_timeout */ -static int cy_cflags_changed(struct cyclades_port *info, unsigned long arg, - struct cyclades_icount *cprev) +static int set_default_timeout(struct cyclades_port *info, unsigned long value) { - struct cyclades_icount cnow; - unsigned long flags; - int ret; - - spin_lock_irqsave(&info->card->card_lock, flags); - cnow = info->icount; /* atomic copy */ - spin_unlock_irqrestore(&info->card->card_lock, flags); - - ret = ((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev->dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev->cts)); - - *cprev = cnow; + info->default_timeout = value & 0xff; + return 0; +} /* set_default_timeout */ - return ret; -} +static int get_default_timeout(struct cyclades_port *info, + unsigned long __user *value) +{ + return put_user(info->default_timeout, value); +} /* get_default_timeout */ /* * This routine allows the tty driver to implement device- @@ -2691,7 +3875,8 @@ cy_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { struct cyclades_port *info = tty->driver_data; - struct cyclades_icount cnow; /* kernel counter temps */ + struct cyclades_icount cprev, cnow; /* kernel counter temps */ + struct serial_icounter_struct __user *p_cuser; /* user space */ int ret_val = 0; unsigned long flags; void __user *argp = (void __user *)arg; @@ -2707,11 +3892,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file, switch (cmd) { case CYGETMON: - if (copy_to_user(argp, &info->mon, sizeof(info->mon))) { - ret_val = -EFAULT; - break; - } - memset(&info->mon, 0, sizeof(info->mon)); + ret_val = get_mon_info(info, argp); break; case CYGETTHRESH: ret_val = get_threshold(info, argp); @@ -2720,11 +3901,10 @@ cy_ioctl(struct tty_struct *tty, struct file *file, ret_val = set_threshold(info, arg); break; case CYGETDEFTHRESH: - ret_val = put_user(info->default_threshold, - (unsigned long __user *)argp); + ret_val = get_default_threshold(info, argp); break; case CYSETDEFTHRESH: - info->default_threshold = arg & 0x0f; + ret_val = set_default_threshold(info, arg); break; case CYGETTIMEOUT: ret_val = get_timeout(info, argp); @@ -2733,20 +3913,21 @@ cy_ioctl(struct tty_struct *tty, struct file *file, ret_val = set_timeout(info, arg); break; case CYGETDEFTIMEOUT: - ret_val = put_user(info->default_timeout, - (unsigned long __user *)argp); + ret_val = get_default_timeout(info, argp); break; case CYSETDEFTIMEOUT: - info->default_timeout = arg & 0xff; + ret_val = set_default_timeout(info, arg); break; case CYSETRFLOW: info->rflow = (int)arg; + ret_val = 0; break; case CYGETRFLOW: ret_val = info->rflow; break; case CYSETRTSDTR_INV: info->rtsdtr_inv = (int)arg; + ret_val = 0; break; case CYGETRTSDTR_INV: ret_val = info->rtsdtr_inv; @@ -2757,6 +3938,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file, #ifndef CONFIG_CYZ_INTR case CYZSETPOLLCYCLE: cyz_polling_cycle = (arg * HZ) / 1000; + ret_val = 0; break; case CYZGETPOLLCYCLE: ret_val = (cyz_polling_cycle * 1000) / HZ; @@ -2764,15 +3946,16 @@ cy_ioctl(struct tty_struct *tty, struct file *file, #endif /* CONFIG_CYZ_INTR */ case CYSETWAIT: info->port.closing_wait = (unsigned short)arg * HZ / 100; + ret_val = 0; break; case CYGETWAIT: ret_val = info->port.closing_wait / (HZ / 100); break; case TIOCGSERIAL: - ret_val = cy_get_serial_info(info, argp); + ret_val = get_serial_info(info, argp); break; case TIOCSSERIAL: - ret_val = cy_set_serial_info(info, tty, argp); + ret_val = set_serial_info(info, argp); break; case TIOCSERGETLSR: /* Get line status register */ ret_val = get_lsr_info(info, argp); @@ -2788,8 +3971,17 @@ cy_ioctl(struct tty_struct *tty, struct file *file, /* note the counters on entry */ cnow = info->icount; spin_unlock_irqrestore(&info->card->card_lock, flags); - ret_val = wait_event_interruptible(info->port.delta_msr_wait, - cy_cflags_changed(info, arg, &cnow)); + ret_val = wait_event_interruptible(info->delta_msr_wait, ({ + cprev = cnow; + spin_lock_irqsave(&info->card->card_lock, flags); + cnow = info->icount; /* atomic copy */ + spin_unlock_irqrestore(&info->card->card_lock, flags); + + ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)); + })); break; /* @@ -2798,29 +3990,46 @@ cy_ioctl(struct tty_struct *tty, struct file *file, * NB: both 1->0 and 0->1 transitions are counted except for * RI where only 0->1 is counted. */ - case TIOCGICOUNT: { - struct serial_icounter_struct sic = { }; - + case TIOCGICOUNT: spin_lock_irqsave(&info->card->card_lock, flags); cnow = info->icount; spin_unlock_irqrestore(&info->card->card_lock, flags); - - sic.cts = cnow.cts; - sic.dsr = cnow.dsr; - sic.rng = cnow.rng; - sic.dcd = cnow.dcd; - sic.rx = cnow.rx; - sic.tx = cnow.tx; - sic.frame = cnow.frame; - sic.overrun = cnow.overrun; - sic.parity = cnow.parity; - sic.brk = cnow.brk; - sic.buf_overrun = cnow.buf_overrun; - - if (copy_to_user(argp, &sic, sizeof(sic))) - ret_val = -EFAULT; + p_cuser = argp; + ret_val = put_user(cnow.cts, &p_cuser->cts); + if (ret_val) + break; + ret_val = put_user(cnow.dsr, &p_cuser->dsr); + if (ret_val) + break; + ret_val = put_user(cnow.rng, &p_cuser->rng); + if (ret_val) + break; + ret_val = put_user(cnow.dcd, &p_cuser->dcd); + if (ret_val) + break; + ret_val = put_user(cnow.rx, &p_cuser->rx); + if (ret_val) + break; + ret_val = put_user(cnow.tx, &p_cuser->tx); + if (ret_val) + break; + ret_val = put_user(cnow.frame, &p_cuser->frame); + if (ret_val) + break; + ret_val = put_user(cnow.overrun, &p_cuser->overrun); + if (ret_val) + break; + ret_val = put_user(cnow.parity, &p_cuser->parity); + if (ret_val) + break; + ret_val = put_user(cnow.brk, &p_cuser->brk); + if (ret_val) + break; + ret_val = put_user(cnow.buf_overrun, &p_cuser->buf_overrun); + if (ret_val) + break; + ret_val = 0; break; - } default: ret_val = -ENOIOCTLCMD; } @@ -2846,7 +4055,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios) printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line); #endif - cy_set_line_char(info, tty); + set_line_char(info); if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { @@ -2903,6 +4112,8 @@ static void cy_throttle(struct tty_struct *tty) struct cyclades_port *info = tty->driver_data; struct cyclades_card *card; unsigned long flags; + void __iomem *base_addr; + int chip, channel, index; #ifdef CY_DEBUG_THROTTLE char buf[64]; @@ -2924,9 +4135,24 @@ static void cy_throttle(struct tty_struct *tty) } if (tty->termios->c_cflag & CRTSCTS) { + channel = info->line - card->first_line; if (!cy_is_Z(card)) { + chip = channel >> 2; + channel &= 0x03; + index = card->bus_index; + base_addr = card->base_addr + + (cy_chip_offset[chip] << index); + spin_lock_irqsave(&card->card_lock, flags); - cyy_change_rts_dtr(info, 0, TIOCM_RTS); + cy_writeb(base_addr + (CyCAR << index), + (u_char) channel); + if (info->rtsdtr_inv) { + cy_writeb(base_addr + (CyMSVR2 << index), + ~CyDTR); + } else { + cy_writeb(base_addr + (CyMSVR1 << index), + ~CyRTS); + } spin_unlock_irqrestore(&card->card_lock, flags); } else { info->throttle = 1; @@ -2944,6 +4170,8 @@ static void cy_unthrottle(struct tty_struct *tty) struct cyclades_port *info = tty->driver_data; struct cyclades_card *card; unsigned long flags; + void __iomem *base_addr; + int chip, channel, index; #ifdef CY_DEBUG_THROTTLE char buf[64]; @@ -2964,9 +4192,24 @@ static void cy_unthrottle(struct tty_struct *tty) if (tty->termios->c_cflag & CRTSCTS) { card = info->card; + channel = info->line - card->first_line; if (!cy_is_Z(card)) { + chip = channel >> 2; + channel &= 0x03; + index = card->bus_index; + base_addr = card->base_addr + + (cy_chip_offset[chip] << index); + spin_lock_irqsave(&card->card_lock, flags); - cyy_change_rts_dtr(info, TIOCM_RTS, 0); + cy_writeb(base_addr + (CyCAR << index), + (u_char) channel); + if (info->rtsdtr_inv) { + cy_writeb(base_addr + (CyMSVR2 << index), + CyDTR); + } else { + cy_writeb(base_addr + (CyMSVR1 << index), + CyRTS); + } spin_unlock_irqrestore(&card->card_lock, flags); } else { info->throttle = 0; @@ -2981,7 +4224,8 @@ static void cy_stop(struct tty_struct *tty) { struct cyclades_card *cinfo; struct cyclades_port *info = tty->driver_data; - int channel; + void __iomem *base_addr; + int chip, channel, index; unsigned long flags; #ifdef CY_DEBUG_OTHER @@ -2994,9 +4238,16 @@ static void cy_stop(struct tty_struct *tty) cinfo = info->card; channel = info->line - cinfo->first_line; if (!cy_is_Z(cinfo)) { + index = cinfo->bus_index; + chip = channel >> 2; + channel &= 0x03; + base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index); + spin_lock_irqsave(&cinfo->card_lock, flags); - cyy_writeb(info, CyCAR, channel & 0x03); - cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy); + cy_writeb(base_addr + (CyCAR << index), + (u_char)(channel & 0x0003)); /* index channel */ + cy_writeb(base_addr + (CySRER << index), + readb(base_addr + (CySRER << index)) & ~CyTxRdy); spin_unlock_irqrestore(&cinfo->card_lock, flags); } } /* cy_stop */ @@ -3005,7 +4256,8 @@ static void cy_start(struct tty_struct *tty) { struct cyclades_card *cinfo; struct cyclades_port *info = tty->driver_data; - int channel; + void __iomem *base_addr; + int chip, channel, index; unsigned long flags; #ifdef CY_DEBUG_OTHER @@ -3017,10 +4269,17 @@ static void cy_start(struct tty_struct *tty) cinfo = info->card; channel = info->line - cinfo->first_line; + index = cinfo->bus_index; if (!cy_is_Z(cinfo)) { + chip = channel >> 2; + channel &= 0x03; + base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index); + spin_lock_irqsave(&cinfo->card_lock, flags); - cyy_writeb(info, CyCAR, channel & 0x03); - cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy); + cy_writeb(base_addr + (CyCAR << index), + (u_char) (channel & 0x0003)); /* index channel */ + cy_writeb(base_addr + (CySRER << index), + readb(base_addr + (CySRER << index)) | CyTxRdy); spin_unlock_irqrestore(&cinfo->card_lock, flags); } } /* cy_start */ @@ -3040,83 +4299,16 @@ static void cy_hangup(struct tty_struct *tty) return; cy_flush_buffer(tty); - cy_shutdown(info, tty); - tty_port_hangup(&info->port); -} /* cy_hangup */ - -static int cyy_carrier_raised(struct tty_port *port) -{ - struct cyclades_port *info = container_of(port, struct cyclades_port, - port); - struct cyclades_card *cinfo = info->card; - unsigned long flags; - int channel = info->line - cinfo->first_line; - u32 cd; - - spin_lock_irqsave(&cinfo->card_lock, flags); - cyy_writeb(info, CyCAR, channel & 0x03); - cd = cyy_readb(info, CyMSVR1) & CyDCD; - spin_unlock_irqrestore(&cinfo->card_lock, flags); - - return cd; -} - -static void cyy_dtr_rts(struct tty_port *port, int raise) -{ - struct cyclades_port *info = container_of(port, struct cyclades_port, - port); - struct cyclades_card *cinfo = info->card; - unsigned long flags; - - spin_lock_irqsave(&cinfo->card_lock, flags); - cyy_change_rts_dtr(info, raise ? TIOCM_RTS | TIOCM_DTR : 0, - raise ? 0 : TIOCM_RTS | TIOCM_DTR); - spin_unlock_irqrestore(&cinfo->card_lock, flags); -} - -static int cyz_carrier_raised(struct tty_port *port) -{ - struct cyclades_port *info = container_of(port, struct cyclades_port, - port); - - return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD; -} - -static void cyz_dtr_rts(struct tty_port *port, int raise) -{ - struct cyclades_port *info = container_of(port, struct cyclades_port, - port); - struct cyclades_card *cinfo = info->card; - struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl; - int ret, channel = info->line - cinfo->first_line; - u32 rs; - - rs = readl(&ch_ctrl->rs_control); - if (raise) - rs |= C_RS_RTS | C_RS_DTR; - else - rs &= ~(C_RS_RTS | C_RS_DTR); - cy_writel(&ch_ctrl->rs_control, rs); - ret = cyz_issue_cmd(cinfo, channel, C_CM_IOCTLM, 0L); - if (ret != 0) - printk(KERN_ERR "%s: retval on ttyC%d was %x\n", - __func__, info->line, ret); -#ifdef CY_DEBUG_DTR - printk(KERN_DEBUG "%s: raising Z DTR\n", __func__); + shutdown(info); + info->port.count = 0; +#ifdef CY_DEBUG_COUNT + printk(KERN_DEBUG "cyc:cy_hangup (%d): setting count to 0\n", + current->pid); #endif -} - -static const struct tty_port_operations cyy_port_ops = { - .carrier_raised = cyy_carrier_raised, - .dtr_rts = cyy_dtr_rts, - .shutdown = cy_do_close, -}; - -static const struct tty_port_operations cyz_port_ops = { - .carrier_raised = cyz_carrier_raised, - .dtr_rts = cyz_dtr_rts, - .shutdown = cy_do_close, -}; + info->port.tty = NULL; + info->port.flags &= ~ASYNC_NORMAL_ACTIVE; + wake_up_interruptible(&info->port.open_wait); +} /* cy_hangup */ /* * --------------------------------------------------------------------- @@ -3129,7 +4321,8 @@ static const struct tty_port_operations cyz_port_ops = { static int __devinit cy_init_card(struct cyclades_card *cinfo) { struct cyclades_port *info; - unsigned int channel, port; + unsigned int port; + unsigned short chip_number; spin_lock_init(&cinfo->card_lock); cinfo->intr_enabled = 0; @@ -3141,9 +4334,9 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo) return -ENOMEM; } - for (channel = 0, port = cinfo->first_line; channel < cinfo->nports; - channel++, port++) { - info = &cinfo->ports[channel]; + for (port = cinfo->first_line; port < cinfo->first_line + cinfo->nports; + port++) { + info = &cinfo->ports[port - cinfo->first_line]; tty_port_init(&info->port); info->magic = CYCLADES_MAGIC; info->card = cinfo; @@ -3153,19 +4346,10 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo) info->port.close_delay = 5 * HZ / 10; info->port.flags = STD_COM_FLAGS; init_completion(&info->shutdown_wait); + init_waitqueue_head(&info->delta_msr_wait); if (cy_is_Z(cinfo)) { - struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS; - struct ZFW_CTRL *zfw_ctrl; - - info->port.ops = &cyz_port_ops; info->type = PORT_STARTECH; - - zfw_ctrl = cinfo->base_addr + - (readl(&firm_id->zfwctrl_addr) & 0xfffff); - info->u.cyz.ch_ctrl = &zfw_ctrl->ch_ctrl[channel]; - info->u.cyz.buf_ctrl = &zfw_ctrl->buf_ctrl[channel]; - if (cinfo->hw_ver == ZO_V1) info->xmit_fifo_size = CYZ_FIFO_SIZE; else @@ -3175,20 +4359,17 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo) cyz_rx_restart, (unsigned long)info); #endif } else { - unsigned short chip_number; int index = cinfo->bus_index; - - info->port.ops = &cyy_port_ops; info->type = PORT_CIRRUS; info->xmit_fifo_size = CyMAX_CHAR_FIFO; info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS; info->cor2 = CyETC; info->cor3 = 0x08; /* _very_ small rcv threshold */ - chip_number = channel / CyPORTS_PER_CHIP; - info->u.cyy.base_addr = cinfo->base_addr + - (cy_chip_offset[chip_number] << index); - info->chip_rev = cyy_readb(info, CyGFRCR); + chip_number = (port - cinfo->first_line) / 4; + info->chip_rev = readb(cinfo->base_addr + + (cy_chip_offset[chip_number] << index) + + (CyGFRCR << index)); if (info->chip_rev >= CD1400_REV_J) { /* It is a CD1400 rev. J or later */ @@ -3879,14 +5060,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, } cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP; } else { - struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS; - struct ZFW_CTRL __iomem *zfw_ctrl; - - zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff); - cy_card[card_no].hw_ver = mailbox; cy_card[card_no].num_chips = (unsigned int)-1; - cy_card[card_no].board_ctrl = &zfw_ctrl->board_ctrl; #ifdef CONFIG_CYZ_INTR /* allocate IRQ only if board has an IRQ */ if (irq != 0 && irq != 255) { @@ -4016,30 +5191,18 @@ static int cyclades_proc_show(struct seq_file *m, void *v) for (j = 0; j < cy_card[i].nports; j++) { info = &cy_card[i].ports[j]; - if (info->port.count) { - /* XXX is the ldisc num worth this? */ - struct tty_struct *tty; - struct tty_ldisc *ld; - int num = 0; - tty = tty_port_tty_get(&info->port); - if (tty) { - ld = tty_ldisc_ref(tty); - if (ld) { - num = ld->ops->num; - tty_ldisc_deref(ld); - } - tty_kref_put(tty); - } + if (info->port.count) seq_printf(m, "%3d %8lu %10lu %8lu " - "%10lu %8lu %9lu %6d\n", info->line, + "%10lu %8lu %9lu %6ld\n", info->line, (cur_jifs - info->idle_stats.in_use) / HZ, info->idle_stats.xmit_bytes, (cur_jifs - info->idle_stats.xmit_idle)/ HZ, info->idle_stats.recv_bytes, (cur_jifs - info->idle_stats.recv_idle)/ HZ, info->idle_stats.overruns, - num); - } else + /* FIXME: double check locking */ + (long)info->port.tty->ldisc->ops->num); + else seq_printf(m, "%3d %8lu %10lu %8lu " "%10lu %8lu %9lu %6ld\n", info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L); diff --git a/trunk/drivers/char/esp.c b/trunk/drivers/char/esp.c index b19d43cd9542..a5c59fc2b0ff 100644 --- a/trunk/drivers/char/esp.c +++ b/trunk/drivers/char/esp.c @@ -572,7 +572,7 @@ static void check_modem_status(struct esp_struct *info) info->icount.dcd++; if (status & UART_MSR_DCTS) info->icount.cts++; - wake_up_interruptible(&info->port.delta_msr_wait); + wake_up_interruptible(&info->delta_msr_wait); } if ((info->port.flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { @@ -927,7 +927,7 @@ static void shutdown(struct esp_struct *info) * clear delta_msr_wait queue to avoid mem leaks: we may free the irq * here so the queue might never be waken up */ - wake_up_interruptible(&info->port.delta_msr_wait); + wake_up_interruptible(&info->delta_msr_wait); wake_up_interruptible(&info->break_wait); /* stop a DMA transfer on the port being closed */ @@ -1800,7 +1800,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file *file, spin_unlock_irqrestore(&info->lock, flags); while (1) { /* FIXME: convert to new style wakeup */ - interruptible_sleep_on(&info->port.delta_msr_wait); + interruptible_sleep_on(&info->delta_msr_wait); /* see if a signal did it */ if (signal_pending(current)) return -ERESTARTSYS; @@ -2452,6 +2452,7 @@ static int __init espserial_init(void) info->config.flow_off = flow_off; info->config.pio_threshold = pio_threshold; info->next_port = ports; + init_waitqueue_head(&info->delta_msr_wait); init_waitqueue_head(&info->break_wait); ports = info; printk(KERN_INFO "ttyP%d at 0x%04x (irq = %d) is an ESP ", diff --git a/trunk/drivers/char/hw_random/core.c b/trunk/drivers/char/hw_random/core.c index 1573aebd54b5..fc93e2fc7c71 100644 --- a/trunk/drivers/char/hw_random/core.c +++ b/trunk/drivers/char/hw_random/core.c @@ -153,7 +153,7 @@ static const struct file_operations rng_chrdev_ops = { static struct miscdevice rng_miscdev = { .minor = RNG_MISCDEV_MINOR, .name = RNG_MODULE_NAME, - .nodename = "hwrng", + .devnode = "hwrng", .fops = &rng_chrdev_ops, }; diff --git a/trunk/drivers/char/isicom.c b/trunk/drivers/char/isicom.c index 426bfdd7f3e0..4f1f4cd670da 100644 --- a/trunk/drivers/char/isicom.c +++ b/trunk/drivers/char/isicom.c @@ -846,53 +846,37 @@ static int isicom_carrier_raised(struct tty_port *port) return (ip->status & ISI_DCD)?1 : 0; } -static struct tty_port *isicom_find_port(struct tty_struct *tty) +static int isicom_open(struct tty_struct *tty, struct file *filp) { struct isi_port *port; struct isi_board *card; unsigned int board; - int line = tty->index; + int error, line; + line = tty->index; if (line < 0 || line > PORT_COUNT-1) - return NULL; + return -ENODEV; board = BOARD(line); card = &isi_card[board]; if (!(card->status & FIRMWARE_LOADED)) - return NULL; + return -ENODEV; /* open on a port greater than the port count for the card !!! */ if (line > ((board * 16) + card->port_count - 1)) - return NULL; + return -ENODEV; port = &isi_ports[line]; if (isicom_paranoia_check(port, tty->name, "isicom_open")) - return NULL; - - return &port->port; -} - -static int isicom_open(struct tty_struct *tty, struct file *filp) -{ - struct isi_port *port; - struct isi_board *card; - struct tty_port *tport; - int error = 0; - - tport = isicom_find_port(tty); - if (tport == NULL) return -ENODEV; - port = container_of(tport, struct isi_port, port); - card = &isi_card[BOARD(tty->index)]; + isicom_setup_board(card); /* FIXME: locking on port.count etc */ port->port.count++; tty->driver_data = port; tty_port_tty_set(&port->port, tty); - /* FIXME: Locking on Initialized flag */ - if (!test_bit(ASYNCB_INITIALIZED, &tport->flags)) - error = isicom_setup_port(tty); + error = isicom_setup_port(tty); if (error == 0) error = tty_port_block_til_ready(&port->port, tty, filp); return error; @@ -968,12 +952,19 @@ static void isicom_flush_buffer(struct tty_struct *tty) tty_wakeup(tty); } -static void isicom_close_port(struct tty_port *port) +static void isicom_close(struct tty_struct *tty, struct file *filp) { - struct isi_port *ip = container_of(port, struct isi_port, port); - struct isi_board *card = ip->card; + struct isi_port *ip = tty->driver_data; + struct tty_port *port = &ip->port; + struct isi_board *card; unsigned long flags; + BUG_ON(!ip); + + card = ip->card; + if (isicom_paranoia_check(ip, tty->name, "isicom_close")) + return; + /* indicate to the card that no more data can be received on this port */ spin_lock_irqsave(&card->card_lock, flags); @@ -983,19 +974,9 @@ static void isicom_close_port(struct tty_port *port) } isicom_shutdown_port(ip); spin_unlock_irqrestore(&card->card_lock, flags); -} - -static void isicom_close(struct tty_struct *tty, struct file *filp) -{ - struct isi_port *ip = tty->driver_data; - struct tty_port *port = &ip->port; - if (isicom_paranoia_check(ip, tty->name, "isicom_close")) - return; - if (tty_port_close_start(port, tty, filp) == 0) - return; - isicom_close_port(port); isicom_flush_buffer(tty); + tty_port_close_end(port, tty); } diff --git a/trunk/drivers/char/mem.c b/trunk/drivers/char/mem.c index 0aede1d6a9ea..0491cdf63f2a 100644 --- a/trunk/drivers/char/mem.c +++ b/trunk/drivers/char/mem.c @@ -866,25 +866,24 @@ static const struct file_operations kmsg_fops = { static const struct memdev { const char *name; - mode_t mode; const struct file_operations *fops; struct backing_dev_info *dev_info; } devlist[] = { - [1] = { "mem", 0, &mem_fops, &directly_mappable_cdev_bdi }, + [ 1] = { "mem", &mem_fops, &directly_mappable_cdev_bdi }, #ifdef CONFIG_DEVKMEM - [2] = { "kmem", 0, &kmem_fops, &directly_mappable_cdev_bdi }, + [ 2] = { "kmem", &kmem_fops, &directly_mappable_cdev_bdi }, #endif - [3] = { "null", 0666, &null_fops, NULL }, + [ 3] = {"null", &null_fops, NULL }, #ifdef CONFIG_DEVPORT - [4] = { "port", 0, &port_fops, NULL }, + [ 4] = { "port", &port_fops, NULL }, #endif - [5] = { "zero", 0666, &zero_fops, &zero_bdi }, - [7] = { "full", 0666, &full_fops, NULL }, - [8] = { "random", 0666, &random_fops, NULL }, - [9] = { "urandom", 0666, &urandom_fops, NULL }, - [11] = { "kmsg", 0, &kmsg_fops, NULL }, + [ 5] = { "zero", &zero_fops, &zero_bdi }, + [ 7] = { "full", &full_fops, NULL }, + [ 8] = { "random", &random_fops, NULL }, + [ 9] = { "urandom", &urandom_fops, NULL }, + [11] = { "kmsg", &kmsg_fops, NULL }, #ifdef CONFIG_CRASH_DUMP - [12] = { "oldmem", 0, &oldmem_fops, NULL }, + [12] = { "oldmem", &oldmem_fops, NULL }, #endif }; @@ -921,13 +920,6 @@ static const struct file_operations memory_fops = { .open = memory_open, }; -static char *mem_devnode(struct device *dev, mode_t *mode) -{ - if (mode && devlist[MINOR(dev->devt)].mode) - *mode = devlist[MINOR(dev->devt)].mode; - return NULL; -} - static struct class *mem_class; static int __init chr_dev_init(void) @@ -943,7 +935,6 @@ static int __init chr_dev_init(void) printk("unable to get major %d for memory devs\n", MEM_MAJOR); mem_class = class_create(THIS_MODULE, "mem"); - mem_class->devnode = mem_devnode; for (minor = 1; minor < ARRAY_SIZE(devlist); minor++) { if (!devlist[minor].name) continue; diff --git a/trunk/drivers/char/misc.c b/trunk/drivers/char/misc.c index 1ee27cc23426..62c99fa59e2b 100644 --- a/trunk/drivers/char/misc.c +++ b/trunk/drivers/char/misc.c @@ -263,14 +263,12 @@ int misc_deregister(struct miscdevice *misc) EXPORT_SYMBOL(misc_register); EXPORT_SYMBOL(misc_deregister); -static char *misc_devnode(struct device *dev, mode_t *mode) +static char *misc_nodename(struct device *dev) { struct miscdevice *c = dev_get_drvdata(dev); - if (mode && c->mode) - *mode = c->mode; - if (c->nodename) - return kstrdup(c->nodename, GFP_KERNEL); + if (c->devnode) + return kstrdup(c->devnode, GFP_KERNEL); return NULL; } @@ -289,7 +287,7 @@ static int __init misc_init(void) err = -EIO; if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) goto fail_printk; - misc_class->devnode = misc_devnode; + misc_class->nodename = misc_nodename; return 0; fail_printk: diff --git a/trunk/drivers/char/mxser.c b/trunk/drivers/char/mxser.c index 5e28d39b9e81..dbf8d52f31d0 100644 --- a/trunk/drivers/char/mxser.c +++ b/trunk/drivers/char/mxser.c @@ -48,7 +48,7 @@ #include "mxser.h" -#define MXSER_VERSION "2.0.5" /* 1.14 */ +#define MXSER_VERSION "2.0.4" /* 1.12 */ #define MXSERMAJOR 174 #define MXSER_BOARDS 4 /* Max. boards */ @@ -69,7 +69,6 @@ #define PCI_DEVICE_ID_POS104UL 0x1044 #define PCI_DEVICE_ID_CB108 0x1080 #define PCI_DEVICE_ID_CP102UF 0x1023 -#define PCI_DEVICE_ID_CP112UL 0x1120 #define PCI_DEVICE_ID_CB114 0x1142 #define PCI_DEVICE_ID_CP114UL 0x1143 #define PCI_DEVICE_ID_CB134I 0x1341 @@ -140,8 +139,7 @@ static const struct mxser_cardinfo mxser_cards[] = { { "CP-138U series", 8, }, { "POS-104UL series", 4, }, { "CP-114UL series", 4, }, -/*30*/ { "CP-102UF series", 2, }, - { "CP-112UL series", 2, }, +/*30*/ { "CP-102UF series", 2, } }; /* driver_data correspond to the lines in the structure above @@ -172,7 +170,6 @@ static struct pci_device_id mxser_pcibrds[] = { { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_POS104UL), .driver_data = 28 }, { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP114UL), .driver_data = 29 }, { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP102UF), .driver_data = 30 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP112UL), .driver_data = 31 }, { } }; MODULE_DEVICE_TABLE(pci, mxser_pcibrds); @@ -261,6 +258,7 @@ struct mxser_port { struct mxser_mon mon_data; spinlock_t slock; + wait_queue_head_t delta_msr_wait; }; struct mxser_board { @@ -820,7 +818,7 @@ static void mxser_check_modem_status(struct tty_struct *tty, if (status & UART_MSR_DCTS) port->icount.cts++; port->mon_data.modem_status = status; - wake_up_interruptible(&port->port.delta_msr_wait); + wake_up_interruptible(&port->delta_msr_wait); if ((port->port.flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { if (status & UART_MSR_DCD) @@ -975,7 +973,7 @@ static void mxser_shutdown(struct tty_struct *tty) * clear delta_msr_wait queue to avoid mem leaks: we may free the irq * here so the queue might never be waken up */ - wake_up_interruptible(&info->port.delta_msr_wait); + wake_up_interruptible(&info->delta_msr_wait); /* * Free the IRQ, if necessary @@ -1075,17 +1073,34 @@ static void mxser_flush_buffer(struct tty_struct *tty) } -static void mxser_close_port(struct tty_struct *tty, struct tty_port *port) +/* + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * async structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + */ +static void mxser_close(struct tty_struct *tty, struct file *filp) { - struct mxser_port *info = container_of(port, struct mxser_port, port); + struct mxser_port *info = tty->driver_data; + struct tty_port *port = &info->port; + unsigned long timeout; + + if (tty->index == MXSER_PORTS) + return; + if (!info) + return; + + if (tty_port_close_start(port, tty, filp) == 0) + return; + /* * Save the termios structure, since this port may have * separate termios for callout and dialin. * * FIXME: Can this go ? */ - if (port->flags & ASYNC_NORMAL_ACTIVE) + if (info->port.flags & ASYNC_NORMAL_ACTIVE) info->normal_termios = *tty->termios; /* * At this point we stop accepting input. To do this, we @@ -1097,7 +1112,7 @@ static void mxser_close_port(struct tty_struct *tty, struct tty_port *port) if (info->board->chip_flag) info->IER &= ~MOXA_MUST_RECV_ISR; - if (port->flags & ASYNC_INITIALIZED) { + if (info->port.flags & ASYNC_INITIALIZED) { outb(info->IER, info->ioaddr + UART_IER); /* * Before we drop DTR, make sure the UART transmitter @@ -1112,26 +1127,8 @@ static void mxser_close_port(struct tty_struct *tty, struct tty_port *port) } } mxser_shutdown(tty); - -} - -/* - * This routine is called when the serial port gets closed. First, we - * wait for the last remaining data to be sent. Then, we unlink its - * async structure from the interrupt chain if necessary, and we free - * that IRQ if nothing is left in the chain. - */ -static void mxser_close(struct tty_struct *tty, struct file *filp) -{ - struct mxser_port *info = tty->driver_data; - struct tty_port *port = &info->port; - - if (tty->index == MXSER_PORTS) - return; - if (tty_port_close_start(port, tty, filp) == 0) - return; - mxser_close_port(tty, port); mxser_flush_buffer(tty); + /* Right now the tty_port set is done outside of the close_end helper as we don't yet have everyone using refcounts */ tty_port_close_end(port, tty); @@ -1764,7 +1761,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, cnow = info->icount; /* note the counters on entry */ spin_unlock_irqrestore(&info->slock, flags); - return wait_event_interruptible(info->port.delta_msr_wait, + return wait_event_interruptible(info->delta_msr_wait, mxser_cflags_changed(info, arg, &cnow)); /* * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) @@ -1806,7 +1803,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, lock_kernel(); len = mxser_chars_in_buffer(tty); - lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_THRE; + lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT; len += (lsr ? 0 : 1); unlock_kernel(); @@ -2416,6 +2413,7 @@ static int __devinit mxser_initbrd(struct mxser_board *brd, info->port.close_delay = 5 * HZ / 10; info->port.closing_wait = 30 * HZ; info->normal_termios = mxvar_sdriver->init_termios; + init_waitqueue_head(&info->delta_msr_wait); memset(&info->mon_data, 0, sizeof(struct mxser_mon)); info->err_shadow = 0; spin_lock_init(&info->slock); diff --git a/trunk/drivers/char/n_tty.c b/trunk/drivers/char/n_tty.c index 2e50f4dfc79c..4e28b35024ec 100644 --- a/trunk/drivers/char/n_tty.c +++ b/trunk/drivers/char/n_tty.c @@ -272,8 +272,7 @@ static inline int is_continuation(unsigned char c, struct tty_struct *tty) * * This is a helper function that handles one output character * (including special characters like TAB, CR, LF, etc.), - * doing OPOST processing and putting the results in the - * tty driver's write buffer. + * putting the results in the tty driver's write buffer. * * Note that Linux currently ignores TABDLY, CRDLY, VTDLY, FFDLY * and NLDLY. They simply aren't relevant in the world today. @@ -351,9 +350,8 @@ static int do_output_char(unsigned char c, struct tty_struct *tty, int space) * @c: character (or partial unicode symbol) * @tty: terminal device * - * Output one character with OPOST processing. - * Returns -1 when the output device is full and the character - * must be retried. + * Perform OPOST processing. Returns -1 when the output device is + * full and the character must be retried. * * Locking: output_lock to protect column state and space left * (also, this is called from n_tty_write under the @@ -379,11 +377,8 @@ static int process_output(unsigned char c, struct tty_struct *tty) /** * process_output_block - block post processor * @tty: terminal device - * @buf: character buffer - * @nr: number of bytes to output - * - * Output a block of characters with OPOST processing. - * Returns the number of characters output. + * @inbuf: user buffer + * @nr: number of bytes * * This path is used to speed up block console writes, among other * things when processing blocks of output data. It handles only @@ -576,23 +571,33 @@ static void process_echoes(struct tty_struct *tty) break; default: + if (iscntrl(op)) { + if (L_ECHOCTL(tty)) { + /* + * Ensure there is enough space + * for the whole ctrl pair. + */ + if (space < 2) { + no_space_left = 1; + break; + } + tty_put_char(tty, '^'); + tty_put_char(tty, op ^ 0100); + tty->column += 2; + space -= 2; + } else { + if (!space) { + no_space_left = 1; + break; + } + tty_put_char(tty, op); + space--; + } + } /* - * If the op is not a special byte code, - * it is a ctrl char tagged to be echoed - * as "^X" (where X is the letter - * representing the control char). - * Note that we must ensure there is - * enough space for the whole ctrl pair. - * + * If above falls through, this was an + * undefined op. */ - if (space < 2) { - no_space_left = 1; - break; - } - tty_put_char(tty, '^'); - tty_put_char(tty, op ^ 0100); - tty->column += 2; - space -= 2; cp += 2; nr -= 2; } @@ -600,18 +605,12 @@ static void process_echoes(struct tty_struct *tty) if (no_space_left) break; } else { - if (O_OPOST(tty) && - !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) { - int retval = do_output_char(c, tty, space); - if (retval < 0) - break; - space -= retval; - } else { - if (!space) - break; - tty_put_char(tty, c); - space -= 1; - } + int retval; + + retval = do_output_char(c, tty, space); + if (retval < 0) + break; + space -= retval; cp += 1; nr -= 1; } @@ -799,8 +798,8 @@ static void echo_char_raw(unsigned char c, struct tty_struct *tty) * 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. * - * This variant tags control characters to be echoed as "^X" - * (where X is the letter representing the control char). + * This variant tags control characters to be possibly echoed as + * as "^X" (where X is the letter representing the control char). * * Locking: echo_lock to protect the echo buffer */ @@ -813,7 +812,7 @@ static void echo_char(unsigned char c, struct tty_struct *tty) add_echo_byte(ECHO_OP_START, tty); add_echo_byte(ECHO_OP_START, tty); } else { - if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') + if (iscntrl(c) && c != '\t') add_echo_byte(ECHO_OP_START, tty); add_echo_byte(c, tty); } diff --git a/trunk/drivers/char/raw.c b/trunk/drivers/char/raw.c index 64acd05f71c8..40268db02e22 100644 --- a/trunk/drivers/char/raw.c +++ b/trunk/drivers/char/raw.c @@ -261,7 +261,7 @@ static const struct file_operations raw_ctl_fops = { static struct cdev raw_cdev; -static char *raw_devnode(struct device *dev, mode_t *mode) +static char *raw_nodename(struct device *dev) { return kasprintf(GFP_KERNEL, "raw/%s", dev_name(dev)); } @@ -289,7 +289,7 @@ static int __init raw_init(void) ret = PTR_ERR(raw_class); goto error_region; } - raw_class->devnode = raw_devnode; + raw_class->nodename = raw_nodename; device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), NULL, "rawctl"); return 0; diff --git a/trunk/drivers/char/riscom8.c b/trunk/drivers/char/riscom8.c index 3cfa22d469e0..171711acf5cd 100644 --- a/trunk/drivers/char/riscom8.c +++ b/trunk/drivers/char/riscom8.c @@ -343,7 +343,7 @@ static void rc_receive_exc(struct riscom_board const *bp) if (port == NULL) return; - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; #ifdef RC_REPORT_OVERRUN status = rc_in(bp, CD180_RCSR); @@ -355,18 +355,18 @@ static void rc_receive_exc(struct riscom_board const *bp) #endif ch = rc_in(bp, CD180_RDR); if (!status) - goto out; + return; if (status & RCSR_TOUT) { printk(KERN_WARNING "rc%d: port %d: Receiver timeout. " "Hardware problems ?\n", board_No(bp), port_No(port)); - goto out; + return; } else if (status & RCSR_BREAK) { printk(KERN_INFO "rc%d: port %d: Handling break...\n", board_No(bp), port_No(port)); flag = TTY_BREAK; - if (tty && (port->port.flags & ASYNC_SAK)) + if (port->port.flags & ASYNC_SAK) do_SAK(tty); } else if (status & RCSR_PE) @@ -380,12 +380,8 @@ static void rc_receive_exc(struct riscom_board const *bp) else flag = TTY_NORMAL; - if (tty) { - tty_insert_flip_char(tty, ch, flag); - tty_flip_buffer_push(tty); - } -out: - tty_kref_put(tty); + tty_insert_flip_char(tty, ch, flag); + tty_flip_buffer_push(tty); } static void rc_receive(struct riscom_board const *bp) @@ -398,7 +394,7 @@ static void rc_receive(struct riscom_board const *bp) if (port == NULL) return; - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; count = rc_in(bp, CD180_RDCR); @@ -407,14 +403,15 @@ static void rc_receive(struct riscom_board const *bp) #endif while (count--) { - u8 ch = rc_in(bp, CD180_RDR); - if (tty) - tty_insert_flip_char(tty, ch, TTY_NORMAL); - } - if (tty) { - tty_flip_buffer_push(tty); - tty_kref_put(tty); + if (tty_buffer_request_room(tty, 1) == 0) { + printk(KERN_WARNING "rc%d: port %d: Working around " + "flip buffer overflow.\n", + board_No(bp), port_No(port)); + break; + } + tty_insert_flip_char(tty, rc_in(bp, CD180_RDR), TTY_NORMAL); } + tty_flip_buffer_push(tty); } static void rc_transmit(struct riscom_board const *bp) @@ -427,22 +424,22 @@ static void rc_transmit(struct riscom_board const *bp) if (port == NULL) return; - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (port->IER & IER_TXEMPTY) { /* FIFO drained */ rc_out(bp, CD180_CAR, port_No(port)); port->IER &= ~IER_TXEMPTY; rc_out(bp, CD180_IER, port->IER); - goto out; + return; } if ((port->xmit_cnt <= 0 && !port->break_length) - || (tty && (tty->stopped || tty->hw_stopped))) { + || tty->stopped || tty->hw_stopped) { rc_out(bp, CD180_CAR, port_No(port)); port->IER &= ~IER_TXRDY; rc_out(bp, CD180_IER, port->IER); - goto out; + return; } if (port->break_length) { @@ -467,7 +464,7 @@ static void rc_transmit(struct riscom_board const *bp) rc_out(bp, CD180_CCR, CCR_CORCHG2); port->break_length = 0; } - goto out; + return; } count = CD180_NFIFO; @@ -483,10 +480,8 @@ static void rc_transmit(struct riscom_board const *bp) port->IER &= ~IER_TXRDY; rc_out(bp, CD180_IER, port->IER); } - if (tty && port->xmit_cnt <= port->wakeup_chars) + if (port->xmit_cnt <= port->wakeup_chars) tty_wakeup(tty); -out: - tty_kref_put(tty); } static void rc_check_modem(struct riscom_board const *bp) @@ -499,43 +494,37 @@ static void rc_check_modem(struct riscom_board const *bp) if (port == NULL) return; - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; mcr = rc_in(bp, CD180_MCR); if (mcr & MCR_CDCHG) { if (rc_in(bp, CD180_MSVR) & MSVR_CD) wake_up_interruptible(&port->port.open_wait); - else if (tty) + else tty_hangup(tty); } #ifdef RISCOM_BRAIN_DAMAGED_CTS if (mcr & MCR_CTSCHG) { if (rc_in(bp, CD180_MSVR) & MSVR_CTS) { + tty->hw_stopped = 0; port->IER |= IER_TXRDY; - if (tty) { - tty->hw_stopped = 0; - if (port->xmit_cnt <= port->wakeup_chars) - tty_wakeup(tty); - } + if (port->xmit_cnt <= port->wakeup_chars) + tty_wakeup(tty); } else { - if (tty) - tty->hw_stopped = 1; + tty->hw_stopped = 1; port->IER &= ~IER_TXRDY; } rc_out(bp, CD180_IER, port->IER); } if (mcr & MCR_DSRCHG) { if (rc_in(bp, CD180_MSVR) & MSVR_DSR) { + tty->hw_stopped = 0; port->IER |= IER_TXRDY; - if (tty) { - tty->hw_stopped = 0; - if (port->xmit_cnt <= port->wakeup_chars) - tty_wakeup(tty); - } + if (port->xmit_cnt <= port->wakeup_chars) + tty_wakeup(tty); } else { - if (tty) - tty->hw_stopped = 1; + tty->hw_stopped = 1; port->IER &= ~IER_TXRDY; } rc_out(bp, CD180_IER, port->IER); @@ -544,7 +533,6 @@ static void rc_check_modem(struct riscom_board const *bp) /* Clear change bits */ rc_out(bp, CD180_MCR, 0); - tty_kref_put(tty); } /* The main interrupt processing routine */ @@ -644,9 +632,9 @@ static void rc_shutdown_board(struct riscom_board *bp) * Setting up port characteristics. * Must be called with disabled interrupts */ -static void rc_change_speed(struct tty_struct *tty, struct riscom_board *bp, - struct riscom_port *port) +static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port) { + struct tty_struct *tty = port->port.tty; unsigned long baud; long tmp; unsigned char cor1 = 0, cor3 = 0; @@ -793,8 +781,7 @@ static void rc_change_speed(struct tty_struct *tty, struct riscom_board *bp, } /* Must be called with interrupts enabled */ -static int rc_setup_port(struct tty_struct *tty, struct riscom_board *bp, - struct riscom_port *port) +static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port) { unsigned long flags; @@ -806,11 +793,11 @@ static int rc_setup_port(struct tty_struct *tty, struct riscom_board *bp, spin_lock_irqsave(&riscom_lock, flags); - clear_bit(TTY_IO_ERROR, &tty->flags); + clear_bit(TTY_IO_ERROR, &port->port.tty->flags); if (port->port.count == 1) bp->count++; port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; - rc_change_speed(tty, bp, port); + rc_change_speed(bp, port); port->port.flags |= ASYNC_INITIALIZED; spin_unlock_irqrestore(&riscom_lock, flags); @@ -911,9 +898,9 @@ static int rc_open(struct tty_struct *tty, struct file *filp) port->port.count++; tty->driver_data = port; - tty_port_tty_set(&port->port, tty); + port->port.tty = tty; - error = rc_setup_port(tty, bp, port); + error = rc_setup_port(bp, port); if (error == 0) error = tty_port_block_til_ready(&port->port, tty, filp); return error; @@ -934,12 +921,20 @@ static void rc_flush_buffer(struct tty_struct *tty) tty_wakeup(tty); } -static void rc_close_port(struct tty_port *port) +static void rc_close(struct tty_struct *tty, struct file *filp) { + struct riscom_port *port = tty->driver_data; + struct riscom_board *bp; unsigned long flags; - struct riscom_port *rp = container_of(port, struct riscom_port, port); - struct riscom_board *bp = port_Board(rp); unsigned long timeout; + + if (!port || rc_paranoia_check(port, tty->name, "close")) + return; + + bp = port_Board(port); + + if (tty_port_close_start(&port->port, tty, filp) == 0) + return; /* * At this point we stop accepting input. To do this, we @@ -949,37 +944,31 @@ static void rc_close_port(struct tty_port *port) */ spin_lock_irqsave(&riscom_lock, flags); - rp->IER &= ~IER_RXD; - if (port->flags & ASYNC_INITIALIZED) { - rp->IER &= ~IER_TXRDY; - rp->IER |= IER_TXEMPTY; - rc_out(bp, CD180_CAR, port_No(rp)); - rc_out(bp, CD180_IER, rp->IER); + port->IER &= ~IER_RXD; + if (port->port.flags & ASYNC_INITIALIZED) { + port->IER &= ~IER_TXRDY; + port->IER |= IER_TXEMPTY; + rc_out(bp, CD180_CAR, port_No(port)); + rc_out(bp, CD180_IER, port->IER); /* * Before we drop DTR, make sure the UART transmitter * has completely drained; this is especially * important if there is a transmit FIFO! */ timeout = jiffies + HZ; - while (rp->IER & IER_TXEMPTY) { + while (port->IER & IER_TXEMPTY) { spin_unlock_irqrestore(&riscom_lock, flags); - msleep_interruptible(jiffies_to_msecs(rp->timeout)); + msleep_interruptible(jiffies_to_msecs(port->timeout)); spin_lock_irqsave(&riscom_lock, flags); if (time_after(jiffies, timeout)) break; } } - rc_shutdown_port(port->tty, bp, rp); + rc_shutdown_port(tty, bp, port); + rc_flush_buffer(tty); spin_unlock_irqrestore(&riscom_lock, flags); -} - -static void rc_close(struct tty_struct *tty, struct file *filp) -{ - struct riscom_port *port = tty->driver_data; - if (!port || rc_paranoia_check(port, tty->name, "close")) - return; - tty_port_close(&port->port, tty, filp); + tty_port_close_end(&port->port, tty); } static int rc_write(struct tty_struct *tty, @@ -1181,7 +1170,7 @@ static int rc_send_break(struct tty_struct *tty, int length) return 0; } -static int rc_set_serial_info(struct tty_struct *tty, struct riscom_port *port, +static int rc_set_serial_info(struct riscom_port *port, struct serial_struct __user *newinfo) { struct serial_struct tmp; @@ -1191,6 +1180,17 @@ static int rc_set_serial_info(struct tty_struct *tty, struct riscom_port *port, if (copy_from_user(&tmp, newinfo, sizeof(tmp))) return -EFAULT; +#if 0 + if ((tmp.irq != bp->irq) || + (tmp.port != bp->base) || + (tmp.type != PORT_CIRRUS) || + (tmp.baud_base != (RC_OSCFREQ + CD180_TPC/2) / CD180_TPC) || + (tmp.custom_divisor != 0) || + (tmp.xmit_fifo_size != CD180_NFIFO) || + (tmp.flags & ~RISCOM_LEGAL_FLAGS)) + return -EINVAL; +#endif + change_speed = ((port->port.flags & ASYNC_SPD_MASK) != (tmp.flags & ASYNC_SPD_MASK)); @@ -1212,7 +1212,7 @@ static int rc_set_serial_info(struct tty_struct *tty, struct riscom_port *port, unsigned long flags; spin_lock_irqsave(&riscom_lock, flags); - rc_change_speed(tty, bp, port); + rc_change_speed(bp, port); spin_unlock_irqrestore(&riscom_lock, flags); } return 0; @@ -1255,7 +1255,7 @@ static int rc_ioctl(struct tty_struct *tty, struct file *filp, break; case TIOCSSERIAL: lock_kernel(); - retval = rc_set_serial_info(tty, port, argp); + retval = rc_set_serial_info(port, argp); unlock_kernel(); break; default: @@ -1350,12 +1350,21 @@ static void rc_start(struct tty_struct *tty) static void rc_hangup(struct tty_struct *tty) { struct riscom_port *port = tty->driver_data; + struct riscom_board *bp; + unsigned long flags; if (rc_paranoia_check(port, tty->name, "rc_hangup")) return; - rc_shutdown_port(tty, port_Board(port), port); - tty_port_hangup(&port->port); + bp = port_Board(port); + + rc_shutdown_port(tty, bp, port); + spin_lock_irqsave(&port->port.lock, flags); + port->port.count = 0; + port->port.flags &= ~ASYNC_NORMAL_ACTIVE; + port->port.tty = NULL; + wake_up_interruptible(&port->port.open_wait); + spin_unlock_irqrestore(&port->port.lock, flags); } static void rc_set_termios(struct tty_struct *tty, @@ -1368,7 +1377,7 @@ static void rc_set_termios(struct tty_struct *tty, return; spin_lock_irqsave(&riscom_lock, flags); - rc_change_speed(tty, port_Board(port), port); + rc_change_speed(port_Board(port), port); spin_unlock_irqrestore(&riscom_lock, flags); if ((old_termios->c_cflag & CRTSCTS) && @@ -1401,7 +1410,6 @@ static const struct tty_operations riscom_ops = { static const struct tty_port_operations riscom_port_ops = { .carrier_raised = carrier_raised, - .shutdown = rc_close_port, }; diff --git a/trunk/drivers/char/tty_io.c b/trunk/drivers/char/tty_io.c index ea18a129b0b5..a3afa0c387cd 100644 --- a/trunk/drivers/char/tty_io.c +++ b/trunk/drivers/char/tty_io.c @@ -1184,7 +1184,6 @@ int tty_init_termios(struct tty_struct *tty) tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios); return 0; } -EXPORT_SYMBOL_GPL(tty_init_termios); /** * tty_driver_install_tty() - install a tty entry in the driver @@ -1387,14 +1386,10 @@ EXPORT_SYMBOL(tty_shutdown); * tty_mutex - sometimes only * takes the file list lock internally when working on the list * of ttys that the driver keeps. - * - * This method gets called from a work queue so that the driver private - * shutdown ops can sleep (needed for USB at least) */ -static void release_one_tty(struct work_struct *work) +static void release_one_tty(struct kref *kref) { - struct tty_struct *tty = - container_of(work, struct tty_struct, hangup_work); + struct tty_struct *tty = container_of(kref, struct tty_struct, kref); struct tty_driver *driver = tty->driver; if (tty->ops->shutdown) @@ -1412,15 +1407,6 @@ static void release_one_tty(struct work_struct *work) free_tty_struct(tty); } -static void queue_release_one_tty(struct kref *kref) -{ - struct tty_struct *tty = container_of(kref, struct tty_struct, kref); - /* The hangup queue is now free so we can reuse it rather than - waste a chunk of memory for each port */ - INIT_WORK(&tty->hangup_work, release_one_tty); - schedule_work(&tty->hangup_work); -} - /** * tty_kref_put - release a tty kref * @tty: tty device @@ -1432,7 +1418,7 @@ static void queue_release_one_tty(struct kref *kref) void tty_kref_put(struct tty_struct *tty) { if (tty) - kref_put(&tty->kref, queue_release_one_tty); + kref_put(&tty->kref, release_one_tty); } EXPORT_SYMBOL(tty_kref_put); @@ -2099,7 +2085,7 @@ static int tioccons(struct file *file) * the generic functionality existed. This piece of history is preserved * in the expected tty API of posix OS's. * - * Locking: none, the open file handle ensures it won't go away. + * Locking: none, the open fle handle ensures it won't go away. */ static int fionbio(struct file *file, int __user *p) @@ -3070,22 +3056,11 @@ void __init console_init(void) } } -static char *tty_devnode(struct device *dev, mode_t *mode) -{ - if (!mode) - return NULL; - if (dev->devt == MKDEV(TTYAUX_MAJOR, 0) || - dev->devt == MKDEV(TTYAUX_MAJOR, 2)) - *mode = 0666; - return NULL; -} - static int __init tty_class_init(void) { tty_class = class_create(THIS_MODULE, "tty"); if (IS_ERR(tty_class)) return PTR_ERR(tty_class); - tty_class->devnode = tty_devnode; return 0; } diff --git a/trunk/drivers/char/tty_ioctl.c b/trunk/drivers/char/tty_ioctl.c index 8e67d5c642a4..ad6ba4ed2808 100644 --- a/trunk/drivers/char/tty_ioctl.c +++ b/trunk/drivers/char/tty_ioctl.c @@ -393,7 +393,9 @@ void tty_termios_encode_baud_rate(struct ktermios *termios, termios->c_cflag |= (BOTHER << IBSHIFT); #else if (ifound == -1 || ofound == -1) { - printk_once(KERN_WARNING "tty: Unable to return correct " + static int warned; + if (!warned++) + printk(KERN_WARNING "tty: Unable to return correct " "speed data as your architecture needs updating.\n"); } #endif diff --git a/trunk/drivers/char/tty_ldisc.c b/trunk/drivers/char/tty_ldisc.c index aafdbaebc16a..e48af9f79219 100644 --- a/trunk/drivers/char/tty_ldisc.c +++ b/trunk/drivers/char/tty_ldisc.c @@ -145,33 +145,48 @@ int tty_unregister_ldisc(int disc) } EXPORT_SYMBOL(tty_unregister_ldisc); -static struct tty_ldisc_ops *get_ldops(int disc) + +/** + * tty_ldisc_try_get - try and reference an ldisc + * @disc: ldisc number + * + * Attempt to open and lock a line discipline into place. Return + * the line discipline refcounted or an error. + */ + +static struct tty_ldisc *tty_ldisc_try_get(int disc) { unsigned long flags; - struct tty_ldisc_ops *ldops, *ret; + struct tty_ldisc *ld; + struct tty_ldisc_ops *ldops; + int err = -EINVAL; + + ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL); + if (ld == NULL) + return ERR_PTR(-ENOMEM); spin_lock_irqsave(&tty_ldisc_lock, flags); - ret = ERR_PTR(-EINVAL); + ld->ops = NULL; ldops = tty_ldiscs[disc]; + /* Check the entry is defined */ if (ldops) { - ret = ERR_PTR(-EAGAIN); - if (try_module_get(ldops->owner)) { + /* If the module is being unloaded we can't use it */ + if (!try_module_get(ldops->owner)) + err = -EAGAIN; + else { + /* lock it */ ldops->refcount++; - ret = ldops; + ld->ops = ldops; + atomic_set(&ld->users, 1); + err = 0; } } spin_unlock_irqrestore(&tty_ldisc_lock, flags); - return ret; -} - -static void put_ldops(struct tty_ldisc_ops *ldops) -{ - unsigned long flags; - - spin_lock_irqsave(&tty_ldisc_lock, flags); - ldops->refcount--; - module_put(ldops->owner); - spin_unlock_irqrestore(&tty_ldisc_lock, flags); + if (err) { + kfree(ld); + return ERR_PTR(err); + } + return ld; } /** @@ -190,31 +205,14 @@ static void put_ldops(struct tty_ldisc_ops *ldops) static struct tty_ldisc *tty_ldisc_get(int disc) { struct tty_ldisc *ld; - struct tty_ldisc_ops *ldops; if (disc < N_TTY || disc >= NR_LDISCS) return ERR_PTR(-EINVAL); - - /* - * Get the ldisc ops - we may need to request them to be loaded - * dynamically and try again. - */ - ldops = get_ldops(disc); - if (IS_ERR(ldops)) { + ld = tty_ldisc_try_get(disc); + if (IS_ERR(ld)) { request_module("tty-ldisc-%d", disc); - ldops = get_ldops(disc); - if (IS_ERR(ldops)) - return ERR_CAST(ldops); + ld = tty_ldisc_try_get(disc); } - - ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL); - if (ld == NULL) { - put_ldops(ldops); - return ERR_PTR(-ENOMEM); - } - - ld->ops = ldops; - atomic_set(&ld->users, 1); return ld; } @@ -236,13 +234,13 @@ static void tty_ldiscs_seq_stop(struct seq_file *m, void *v) static int tty_ldiscs_seq_show(struct seq_file *m, void *v) { int i = *(loff_t *)v; - struct tty_ldisc_ops *ldops; + struct tty_ldisc *ld; - ldops = get_ldops(i); - if (IS_ERR(ldops)) + ld = tty_ldisc_try_get(i); + if (IS_ERR(ld)) return 0; - seq_printf(m, "%-10s %2d\n", ldops->name ? ldops->name : "???", i); - put_ldops(ldops); + seq_printf(m, "%-10s %2d\n", ld->ops->name ? ld->ops->name : "???", i); + put_ldisc(ld); return 0; } diff --git a/trunk/drivers/char/tty_port.c b/trunk/drivers/char/tty_port.c index a4bbb28f10be..9769b1149f76 100644 --- a/trunk/drivers/char/tty_port.c +++ b/trunk/drivers/char/tty_port.c @@ -23,7 +23,6 @@ void tty_port_init(struct tty_port *port) memset(port, 0, sizeof(*port)); init_waitqueue_head(&port->open_wait); init_waitqueue_head(&port->close_wait); - init_waitqueue_head(&port->delta_msr_wait); mutex_init(&port->mutex); spin_lock_init(&port->lock); port->close_delay = (50 * HZ) / 100; @@ -97,14 +96,6 @@ void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty) } EXPORT_SYMBOL(tty_port_tty_set); -static void tty_port_shutdown(struct tty_port *port) -{ - if (port->ops->shutdown && - test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) - port->ops->shutdown(port); - -} - /** * tty_port_hangup - hangup helper * @port: tty port @@ -125,8 +116,6 @@ void tty_port_hangup(struct tty_port *port) port->tty = NULL; spin_unlock_irqrestore(&port->lock, flags); wake_up_interruptible(&port->open_wait); - wake_up_interruptible(&port->delta_msr_wait); - tty_port_shutdown(port); } EXPORT_SYMBOL(tty_port_hangup); @@ -307,17 +296,15 @@ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct f if (port->count) { spin_unlock_irqrestore(&port->lock, flags); - if (port->ops->drop) - port->ops->drop(port); return 0; } - set_bit(ASYNCB_CLOSING, &port->flags); + port->flags |= ASYNC_CLOSING; tty->closing = 1; spin_unlock_irqrestore(&port->lock, flags); /* Don't block on a stalled port, just pull the chain */ if (tty->flow_stopped) tty_driver_flush_buffer(tty); - if (test_bit(ASYNCB_INITIALIZED, &port->flags) && + if (port->flags & ASYNC_INITIALIZED && port->closing_wait != ASYNC_CLOSING_WAIT_NONE) tty_wait_until_sent(tty, port->closing_wait); if (port->drain_delay) { @@ -331,9 +318,6 @@ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct f timeout = 2 * HZ; schedule_timeout_interruptible(timeout); } - /* Don't call port->drop for the last reference. Callers will want - to drop the last active reference in ->shutdown() or the tty - shutdown path */ return 1; } EXPORT_SYMBOL(tty_port_close_start); @@ -364,14 +348,3 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty) spin_unlock_irqrestore(&port->lock, flags); } EXPORT_SYMBOL(tty_port_close_end); - -void tty_port_close(struct tty_port *port, struct tty_struct *tty, - struct file *filp) -{ - if (tty_port_close_start(port, tty, filp) == 0) - return; - tty_port_shutdown(port); - tty_port_close_end(port, tty); - tty_port_tty_set(port, NULL); -} -EXPORT_SYMBOL(tty_port_close); diff --git a/trunk/drivers/char/vt.c b/trunk/drivers/char/vt.c index 0c80c68cd047..6aa88f50b039 100644 --- a/trunk/drivers/char/vt.c +++ b/trunk/drivers/char/vt.c @@ -252,6 +252,7 @@ static void notify_update(struct vc_data *vc) struct vt_notifier_param param = { .vc = vc }; atomic_notifier_call_chain(&vt_notifier_list, VT_UPDATE, ¶m); } + /* * Low-Level Functions */ @@ -934,7 +935,6 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, if (CON_IS_VISIBLE(vc)) update_screen(vc); - vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num); return err; } @@ -2129,7 +2129,11 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co currcons = vc->vc_num; if (!vc_cons_allocated(currcons)) { /* could this happen? */ - printk_once("con_write: tty %d not allocated\n", currcons+1); + static int error = 0; + if (!error) { + error = 1; + printk("con_write: tty %d not allocated\n", currcons+1); + } release_console_sem(); return 0; } @@ -2906,9 +2910,6 @@ static const struct tty_operations con_ops = { .flush_chars = con_flush_chars, .chars_in_buffer = con_chars_in_buffer, .ioctl = vt_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = vt_compat_ioctl, -#endif .stop = con_stop, .start = con_start, .throttle = con_throttle, @@ -2954,6 +2955,7 @@ int __init vty_init(const struct file_operations *console_fops) } #ifndef VT_SINGLE_DRIVER +#include static struct class *vtconsole_class; @@ -3636,7 +3638,6 @@ void do_blank_screen(int entering_gfx) blank_state = blank_vesa_wait; mod_timer(&console_timer, jiffies + vesa_off_interval); } - vt_event_post(VT_EVENT_BLANK, vc->vc_num, vc->vc_num); } EXPORT_SYMBOL(do_blank_screen); @@ -3681,7 +3682,6 @@ void do_unblank_screen(int leaving_gfx) console_blank_hook(0); set_palette(vc); set_cursor(vc); - vt_event_post(VT_EVENT_UNBLANK, vc->vc_num, vc->vc_num); } EXPORT_SYMBOL(do_unblank_screen); diff --git a/trunk/drivers/char/vt_ioctl.c b/trunk/drivers/char/vt_ioctl.c index 29c651ab0d78..95189f288f8c 100644 --- a/trunk/drivers/char/vt_ioctl.c +++ b/trunk/drivers/char/vt_ioctl.c @@ -16,8 +16,6 @@ #include #include #include -#include -#include #include #include #include @@ -63,133 +61,6 @@ extern struct tty_driver *console_driver; static void complete_change_console(struct vc_data *vc); -/* - * User space VT_EVENT handlers - */ - -struct vt_event_wait { - struct list_head list; - struct vt_event event; - int done; -}; - -static LIST_HEAD(vt_events); -static DEFINE_SPINLOCK(vt_event_lock); -static DECLARE_WAIT_QUEUE_HEAD(vt_event_waitqueue); - -/** - * vt_event_post - * @event: the event that occurred - * @old: old console - * @new: new console - * - * Post an VT event to interested VT handlers - */ - -void vt_event_post(unsigned int event, unsigned int old, unsigned int new) -{ - struct list_head *pos, *head; - unsigned long flags; - int wake = 0; - - spin_lock_irqsave(&vt_event_lock, flags); - head = &vt_events; - - list_for_each(pos, head) { - struct vt_event_wait *ve = list_entry(pos, - struct vt_event_wait, list); - if (!(ve->event.event & event)) - continue; - ve->event.event = event; - /* kernel view is consoles 0..n-1, user space view is - console 1..n with 0 meaning current, so we must bias */ - ve->event.old = old + 1; - ve->event.new = new + 1; - wake = 1; - ve->done = 1; - } - spin_unlock_irqrestore(&vt_event_lock, flags); - if (wake) - wake_up_interruptible(&vt_event_waitqueue); -} - -/** - * vt_event_wait - wait for an event - * @vw: our event - * - * Waits for an event to occur which completes our vt_event_wait - * structure. On return the structure has wv->done set to 1 for success - * or 0 if some event such as a signal ended the wait. - */ - -static void vt_event_wait(struct vt_event_wait *vw) -{ - unsigned long flags; - /* Prepare the event */ - INIT_LIST_HEAD(&vw->list); - vw->done = 0; - /* Queue our event */ - spin_lock_irqsave(&vt_event_lock, flags); - list_add(&vw->list, &vt_events); - spin_unlock_irqrestore(&vt_event_lock, flags); - /* Wait for it to pass */ - wait_event_interruptible(vt_event_waitqueue, vw->done); - /* Dequeue it */ - spin_lock_irqsave(&vt_event_lock, flags); - list_del(&vw->list); - spin_unlock_irqrestore(&vt_event_lock, flags); -} - -/** - * vt_event_wait_ioctl - event ioctl handler - * @arg: argument to ioctl - * - * Implement the VT_WAITEVENT ioctl using the VT event interface - */ - -static int vt_event_wait_ioctl(struct vt_event __user *event) -{ - struct vt_event_wait vw; - - if (copy_from_user(&vw.event, event, sizeof(struct vt_event))) - return -EFAULT; - /* Highest supported event for now */ - if (vw.event.event & ~VT_MAX_EVENT) - return -EINVAL; - - vt_event_wait(&vw); - /* If it occurred report it */ - if (vw.done) { - if (copy_to_user(event, &vw.event, sizeof(struct vt_event))) - return -EFAULT; - return 0; - } - return -EINTR; -} - -/** - * vt_waitactive - active console wait - * @event: event code - * @n: new console - * - * Helper for event waits. Used to implement the legacy - * event waiting ioctls in terms of events - */ - -int vt_waitactive(int n) -{ - struct vt_event_wait vw; - do { - if (n == fg_console + 1) - break; - vw.event.event = VT_EVENT_SWITCH; - vt_event_wait(&vw); - if (vw.done == 0) - return -EINTR; - } while (vw.event.new != n); - return 0; -} - /* * these are the valid i/o ports we're allowed to change. they map all the * video ports @@ -489,8 +360,6 @@ do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_ return 0; } - - /* * We handle the console-specific ioctl's here. We allow the * capability to modify any console, not just the fg_console. @@ -973,41 +842,6 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, } break; - case VT_SETACTIVATE: - { - struct vt_setactivate vsa; - - if (!perm) - goto eperm; - - if (copy_from_user(&vsa, (struct vt_setactivate __user *)arg, - sizeof(struct vt_setactivate))) - return -EFAULT; - if (vsa.console == 0 || vsa.console > MAX_NR_CONSOLES) - ret = -ENXIO; - else { - vsa.console--; - acquire_console_sem(); - ret = vc_allocate(vsa.console); - if (ret == 0) { - struct vc_data *nvc; - /* This is safe providing we don't drop the - console sem between vc_allocate and - finishing referencing nvc */ - nvc = vc_cons[vsa.console].d; - nvc->vt_mode = vsa.mode; - nvc->vt_mode.frsig = 0; - put_pid(nvc->vt_pid); - nvc->vt_pid = get_pid(task_pid(current)); - } - release_console_sem(); - if (ret) - break; - /* Commence switch and lock */ - set_console(arg); - } - } - /* * wait until the specified VT has been activated */ @@ -1017,7 +851,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, if (arg == 0 || arg > MAX_NR_CONSOLES) ret = -ENXIO; else - ret = vt_waitactive(arg); + ret = vt_waitactive(arg - 1); break; /* @@ -1325,9 +1159,6 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, ret = put_user(vc->vc_hi_font_mask, (unsigned short __user *)arg); break; - case VT_WAITEVENT: - ret = vt_event_wait_ioctl((struct vt_event __user *)arg); - break; default: ret = -ENOIOCTLCMD; } @@ -1339,6 +1170,54 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, goto out; } +/* + * Sometimes we want to wait until a particular VT has been activated. We + * do it in a very simple manner. Everybody waits on a single queue and + * get woken up at once. Those that are satisfied go on with their business, + * while those not ready go back to sleep. Seems overkill to add a wait + * to each vt just for this - usually this does nothing! + */ +static DECLARE_WAIT_QUEUE_HEAD(vt_activate_queue); + +/* + * Sleeps until a vt is activated, or the task is interrupted. Returns + * 0 if activation, -EINTR if interrupted by a signal handler. + */ +int vt_waitactive(int vt) +{ + int retval; + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&vt_activate_queue, &wait); + for (;;) { + retval = 0; + + /* + * Synchronize with redraw_screen(). By acquiring the console + * semaphore we make sure that the console switch is completed + * before we return. If we didn't wait for the semaphore, we + * could return at a point where fg_console has already been + * updated, but the console switch hasn't been completed. + */ + acquire_console_sem(); + set_current_state(TASK_INTERRUPTIBLE); + if (vt == fg_console) { + release_console_sem(); + break; + } + release_console_sem(); + retval = -ERESTARTNOHAND; + if (signal_pending(current)) + break; + schedule(); + } + remove_wait_queue(&vt_activate_queue, &wait); + __set_current_state(TASK_RUNNING); + return retval; +} + +#define vt_wake_waitactive() wake_up(&vt_activate_queue) + void reset_vc(struct vc_data *vc) { vc->vc_mode = KD_TEXT; @@ -1377,216 +1256,12 @@ void vc_SAK(struct work_struct *work) release_console_sem(); } -#ifdef CONFIG_COMPAT - -struct compat_consolefontdesc { - unsigned short charcount; /* characters in font (256 or 512) */ - unsigned short charheight; /* scan lines per character (1-32) */ - compat_caddr_t chardata; /* font data in expanded form */ -}; - -static inline int -compat_fontx_ioctl(int cmd, struct compat_consolefontdesc __user *user_cfd, - int perm, struct console_font_op *op) -{ - struct compat_consolefontdesc cfdarg; - int i; - - if (copy_from_user(&cfdarg, user_cfd, sizeof(struct compat_consolefontdesc))) - return -EFAULT; - - switch (cmd) { - case PIO_FONTX: - if (!perm) - return -EPERM; - op->op = KD_FONT_OP_SET; - op->flags = KD_FONT_FLAG_OLD; - op->width = 8; - op->height = cfdarg.charheight; - op->charcount = cfdarg.charcount; - op->data = compat_ptr(cfdarg.chardata); - return con_font_op(vc_cons[fg_console].d, op); - case GIO_FONTX: - op->op = KD_FONT_OP_GET; - op->flags = KD_FONT_FLAG_OLD; - op->width = 8; - op->height = cfdarg.charheight; - op->charcount = cfdarg.charcount; - op->data = compat_ptr(cfdarg.chardata); - i = con_font_op(vc_cons[fg_console].d, op); - if (i) - return i; - cfdarg.charheight = op->height; - cfdarg.charcount = op->charcount; - if (copy_to_user(user_cfd, &cfdarg, sizeof(struct compat_consolefontdesc))) - return -EFAULT; - return 0; - } - return -EINVAL; -} - -struct compat_console_font_op { - compat_uint_t op; /* operation code KD_FONT_OP_* */ - compat_uint_t flags; /* KD_FONT_FLAG_* */ - compat_uint_t width, height; /* font size */ - compat_uint_t charcount; - compat_caddr_t data; /* font data with height fixed to 32 */ -}; - -static inline int -compat_kdfontop_ioctl(struct compat_console_font_op __user *fontop, - int perm, struct console_font_op *op, struct vc_data *vc) -{ - int i; - - if (copy_from_user(op, fontop, sizeof(struct compat_console_font_op))) - return -EFAULT; - if (!perm && op->op != KD_FONT_OP_GET) - return -EPERM; - op->data = compat_ptr(((struct compat_console_font_op *)op)->data); - op->flags |= KD_FONT_FLAG_OLD; - i = con_font_op(vc, op); - if (i) - return i; - ((struct compat_console_font_op *)op)->data = (unsigned long)op->data; - if (copy_to_user(fontop, op, sizeof(struct compat_console_font_op))) - return -EFAULT; - return 0; -} - -struct compat_unimapdesc { - unsigned short entry_ct; - compat_caddr_t entries; -}; - -static inline int -compat_unimap_ioctl(unsigned int cmd, struct compat_unimapdesc __user *user_ud, - int perm, struct vc_data *vc) -{ - struct compat_unimapdesc tmp; - struct unipair __user *tmp_entries; - - if (copy_from_user(&tmp, user_ud, sizeof tmp)) - return -EFAULT; - tmp_entries = compat_ptr(tmp.entries); - if (tmp_entries) - if (!access_ok(VERIFY_WRITE, tmp_entries, - tmp.entry_ct*sizeof(struct unipair))) - return -EFAULT; - switch (cmd) { - case PIO_UNIMAP: - if (!perm) - return -EPERM; - return con_set_unimap(vc, tmp.entry_ct, tmp_entries); - case GIO_UNIMAP: - if (!perm && fg_console != vc->vc_num) - return -EPERM; - return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp_entries); - } - return 0; -} - -long vt_compat_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) -{ - struct vc_data *vc = tty->driver_data; - struct console_font_op op; /* used in multiple places here */ - struct kbd_struct *kbd; - unsigned int console; - void __user *up = (void __user *)arg; - int perm; - int ret = 0; - - console = vc->vc_num; - - lock_kernel(); - - if (!vc_cons_allocated(console)) { /* impossible? */ - ret = -ENOIOCTLCMD; - goto out; - } - - /* - * To have permissions to do most of the vt ioctls, we either have - * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG. - */ - perm = 0; - if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG)) - perm = 1; - - kbd = kbd_table + console; - switch (cmd) { - /* - * these need special handlers for incompatible data structures - */ - case PIO_FONTX: - case GIO_FONTX: - ret = compat_fontx_ioctl(cmd, up, perm, &op); - break; - - case KDFONTOP: - ret = compat_kdfontop_ioctl(up, perm, &op, vc); - break; - - case PIO_UNIMAP: - case GIO_UNIMAP: - ret = do_unimap_ioctl(cmd, up, perm, vc); - break; - - /* - * all these treat 'arg' as an integer - */ - case KIOCSOUND: - case KDMKTONE: -#ifdef CONFIG_X86 - case KDADDIO: - case KDDELIO: -#endif - case KDSETMODE: - case KDMAPDISP: - case KDUNMAPDISP: - case KDSKBMODE: - case KDSKBMETA: - case KDSKBLED: - case KDSETLED: - case KDSIGACCEPT: - case VT_ACTIVATE: - case VT_WAITACTIVE: - case VT_RELDISP: - case VT_DISALLOCATE: - case VT_RESIZE: - case VT_RESIZEX: - goto fallback; - - /* - * the rest has a compatible data structure behind arg, - * but we have to convert it to a proper 64 bit pointer. - */ - default: - arg = (unsigned long)compat_ptr(arg); - goto fallback; - } -out: - unlock_kernel(); - return ret; - -fallback: - unlock_kernel(); - return vt_ioctl(tty, file, cmd, arg); -} - - -#endif /* CONFIG_COMPAT */ - - /* - * Performs the back end of a vt switch. Called under the console - * semaphore. + * Performs the back end of a vt switch */ static void complete_change_console(struct vc_data *vc) { unsigned char old_vc_mode; - int old = fg_console; last_console = fg_console; @@ -1650,7 +1325,7 @@ static void complete_change_console(struct vc_data *vc) /* * Wake anyone waiting for their VT to activate */ - vt_event_post(VT_EVENT_SWITCH, old, vc->vc_num); + vt_wake_waitactive(); return; } @@ -1723,58 +1398,3 @@ void change_console(struct vc_data *new_vc) complete_change_console(new_vc); } - -/* Perform a kernel triggered VT switch for suspend/resume */ - -static int disable_vt_switch; - -int vt_move_to_console(unsigned int vt, int alloc) -{ - int prev; - - acquire_console_sem(); - /* Graphics mode - up to X */ - if (disable_vt_switch) { - release_console_sem(); - return 0; - } - prev = fg_console; - - if (alloc && vc_allocate(vt)) { - /* we can't have a free VC for now. Too bad, - * we don't want to mess the screen for now. */ - release_console_sem(); - return -ENOSPC; - } - - if (set_console(vt)) { - /* - * We're unable to switch to the SUSPEND_CONSOLE. - * Let the calling function know so it can decide - * what to do. - */ - release_console_sem(); - return -EIO; - } - release_console_sem(); - if (vt_waitactive(vt + 1)) { - pr_debug("Suspend: Can't switch VCs."); - return -EINTR; - } - return prev; -} - -/* - * Normally during a suspend, we allocate a new console and switch to it. - * When we resume, we switch back to the original console. This switch - * can be slow, so on systems where the framebuffer can handle restoration - * of video registers anyways, there's little point in doing the console - * switch. This function allows you to disable it by passing it '0'. - */ -void pm_set_vt_switch(int do_switch) -{ - acquire_console_sem(); - disable_vt_switch = !do_switch; - release_console_sem(); -} -EXPORT_SYMBOL(pm_set_vt_switch); diff --git a/trunk/drivers/cpuidle/cpuidle.c b/trunk/drivers/cpuidle/cpuidle.c index ad41f19b8e3f..8504a2108557 100644 --- a/trunk/drivers/cpuidle/cpuidle.c +++ b/trunk/drivers/cpuidle/cpuidle.c @@ -17,7 +17,6 @@ #include #include #include -#include #include "cpuidle.h" @@ -92,7 +91,6 @@ static void cpuidle_idle_call(void) /* give the governor an opportunity to reflect on the outcome */ if (cpuidle_curr_governor->reflect) cpuidle_curr_governor->reflect(dev); - trace_power_end(0); } /** diff --git a/trunk/drivers/gpu/drm/drm_sysfs.c b/trunk/drivers/gpu/drm/drm_sysfs.c index 5301f226cb1c..f7a615b80c70 100644 --- a/trunk/drivers/gpu/drm/drm_sysfs.c +++ b/trunk/drivers/gpu/drm/drm_sysfs.c @@ -76,7 +76,7 @@ static ssize_t version_show(struct class *dev, char *buf) CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE); } -static char *drm_devnode(struct device *dev, mode_t *mode) +static char *drm_nodename(struct device *dev) { return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev)); } @@ -112,7 +112,7 @@ struct class *drm_sysfs_create(struct module *owner, char *name) if (err) goto err_out_class; - class->devnode = drm_devnode; + class->nodename = drm_nodename; return class; diff --git a/trunk/drivers/hid/usbhid/hiddev.c b/trunk/drivers/hid/usbhid/hiddev.c index 8b6ee247bfe4..4d1dc0cf1401 100644 --- a/trunk/drivers/hid/usbhid/hiddev.c +++ b/trunk/drivers/hid/usbhid/hiddev.c @@ -852,14 +852,14 @@ static const struct file_operations hiddev_fops = { #endif }; -static char *hiddev_devnode(struct device *dev, mode_t *mode) +static char *hiddev_nodename(struct device *dev) { return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev)); } static struct usb_class_driver hiddev_class = { .name = "hiddev%d", - .devnode = hiddev_devnode, + .nodename = hiddev_nodename, .fops = &hiddev_fops, .minor_base = HIDDEV_MINOR_BASE, }; diff --git a/trunk/drivers/i2c/busses/i2c-mv64xxx.c b/trunk/drivers/i2c/busses/i2c-mv64xxx.c index c3869d94ad42..bbab0e166630 100644 --- a/trunk/drivers/i2c/busses/i2c-mv64xxx.c +++ b/trunk/drivers/i2c/busses/i2c-mv64xxx.c @@ -293,13 +293,13 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) } } -static int +static irqreturn_t mv64xxx_i2c_intr(int irq, void *dev_id) { struct mv64xxx_i2c_data *drv_data = dev_id; unsigned long flags; u32 status; - int rc = IRQ_NONE; + irqreturn_t rc = IRQ_NONE; spin_lock_irqsave(&drv_data->lock, flags); while (readl(drv_data->reg_base + MV64XXX_I2C_REG_CONTROL) & diff --git a/trunk/drivers/input/input.c b/trunk/drivers/input/input.c index 556539d617a4..851791d955f3 100644 --- a/trunk/drivers/input/input.c +++ b/trunk/drivers/input/input.c @@ -1265,14 +1265,14 @@ static struct device_type input_dev_type = { .uevent = input_dev_uevent, }; -static char *input_devnode(struct device *dev, mode_t *mode) +static char *input_nodename(struct device *dev) { return kasprintf(GFP_KERNEL, "input/%s", dev_name(dev)); } struct class input_class = { .name = "input", - .devnode = input_devnode, + .nodename = input_nodename, }; EXPORT_SYMBOL_GPL(input_class); diff --git a/trunk/drivers/isdn/gigaset/interface.c b/trunk/drivers/isdn/gigaset/interface.c index f33ac27de643..8ff7e35c7069 100644 --- a/trunk/drivers/isdn/gigaset/interface.c +++ b/trunk/drivers/isdn/gigaset/interface.c @@ -408,28 +408,33 @@ static int if_write_room(struct tty_struct *tty) return retval; } +/* FIXME: This function does not have error returns */ + static int if_chars_in_buffer(struct tty_struct *tty) { struct cardstate *cs; - int retval = 0; + int retval = -ENODEV; cs = (struct cardstate *) tty->driver_data; if (!cs) { pr_err("%s: no cardstate\n", __func__); - return 0; + return -ENODEV; } gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); - mutex_lock(&cs->mutex); + if (mutex_lock_interruptible(&cs->mutex)) + return -ERESTARTSYS; // FIXME -EINTR? - if (!cs->connected) + if (!cs->connected) { gig_dbg(DEBUG_IF, "not connected"); - else if (!cs->open_count) + retval = -ENODEV; + } else if (!cs->open_count) dev_warn(cs->dev, "%s: device not opened\n", __func__); - else if (cs->mstate != MS_LOCKED) + else if (cs->mstate != MS_LOCKED) { dev_warn(cs->dev, "can't write to unlocked device\n"); - else + retval = -EBUSY; + } else retval = cs->ops->chars_in_buffer(cs); mutex_unlock(&cs->mutex); diff --git a/trunk/drivers/md/dm-ioctl.c b/trunk/drivers/md/dm-ioctl.c index a67942931582..7f77f18fcafa 100644 --- a/trunk/drivers/md/dm-ioctl.c +++ b/trunk/drivers/md/dm-ioctl.c @@ -1532,7 +1532,7 @@ static const struct file_operations _ctl_fops = { static struct miscdevice _dm_misc = { .minor = MISC_DYNAMIC_MINOR, .name = DM_NAME, - .nodename = "mapper/control", + .devnode = "mapper/control", .fops = &_ctl_fops }; diff --git a/trunk/drivers/media/dvb/dvb-core/dvbdev.c b/trunk/drivers/media/dvb/dvb-core/dvbdev.c index 94159b90f733..479dd05762a5 100644 --- a/trunk/drivers/media/dvb/dvb-core/dvbdev.c +++ b/trunk/drivers/media/dvb/dvb-core/dvbdev.c @@ -447,7 +447,7 @@ static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env) return 0; } -static char *dvb_devnode(struct device *dev, mode_t *mode) +static char *dvb_nodename(struct device *dev) { struct dvb_device *dvbdev = dev_get_drvdata(dev); @@ -478,7 +478,7 @@ static int __init init_dvbdev(void) goto error; } dvb_class->dev_uevent = dvb_uevent; - dvb_class->devnode = dvb_devnode; + dvb_class->nodename = dvb_nodename; return 0; error: diff --git a/trunk/drivers/net/slip.c b/trunk/drivers/net/slip.c index e17c535a577e..26f6ee93a064 100644 --- a/trunk/drivers/net/slip.c +++ b/trunk/drivers/net/slip.c @@ -616,14 +616,6 @@ static void sl_uninit(struct net_device *dev) sl_free_bufs(sl); } -/* Hook the destructor so we can free slip devices at the right point in time */ -static void sl_free_netdev(struct net_device *dev) -{ - int i = dev->base_addr; - free_netdev(dev); - slip_devs[i] = NULL; -} - static const struct net_device_ops sl_netdev_ops = { .ndo_init = sl_init, .ndo_uninit = sl_uninit, @@ -642,7 +634,7 @@ static const struct net_device_ops sl_netdev_ops = { static void sl_setup(struct net_device *dev) { dev->netdev_ops = &sl_netdev_ops; - dev->destructor = sl_free_netdev; + dev->destructor = free_netdev; dev->hard_header_len = 0; dev->addr_len = 0; @@ -720,6 +712,8 @@ static void sl_sync(void) static struct slip *sl_alloc(dev_t line) { int i; + int sel = -1; + int score = -1; struct net_device *dev = NULL; struct slip *sl; @@ -730,7 +724,55 @@ static struct slip *sl_alloc(dev_t line) dev = slip_devs[i]; if (dev == NULL) break; + + sl = netdev_priv(dev); + if (sl->leased) { + if (sl->line != line) + continue; + if (sl->tty) + return NULL; + + /* Clear ESCAPE & ERROR flags */ + sl->flags &= (1 << SLF_INUSE); + return sl; + } + + if (sl->tty) + continue; + + if (current->pid == sl->pid) { + if (sl->line == line && score < 3) { + sel = i; + score = 3; + continue; + } + if (score < 2) { + sel = i; + score = 2; + } + continue; + } + if (sl->line == line && score < 1) { + sel = i; + score = 1; + continue; + } + if (score < 0) { + sel = i; + score = 0; + } + } + + if (sel >= 0) { + i = sel; + dev = slip_devs[i]; + if (score > 1) { + sl = netdev_priv(dev); + sl->flags &= (1 << SLF_INUSE); + return sl; + } } + /* Sorry, too many, all slots in use */ if (i >= slip_maxdev) return NULL; @@ -866,14 +908,31 @@ static int slip_open(struct tty_struct *tty) return err; } +/* + + FIXME: 1,2 are fixed 3 was never true anyway. + + Let me to blame a bit. + 1. TTY module calls this funstion on soft interrupt. + 2. TTY module calls this function WITH MASKED INTERRUPTS! + 3. TTY module does not notify us about line discipline + shutdown, + + Seems, now it is clean. The solution is to consider netdevice and + line discipline sides as two independent threads. + + By-product (not desired): sl? does not feel hangups and remains open. + It is supposed, that user level program (dip, diald, slattach...) + will catch SIGHUP and make the rest of work. + + I see no way to make more with current tty code. --ANK + */ + /* * Close down a SLIP channel. * This means flushing out any pending queues, and then returning. This * call is serialized against other ldisc functions. - * - * We also use this method fo a hangup event */ - static void slip_close(struct tty_struct *tty) { struct slip *sl = tty->disc_data; @@ -892,16 +951,10 @@ static void slip_close(struct tty_struct *tty) del_timer_sync(&sl->keepalive_timer); del_timer_sync(&sl->outfill_timer); #endif - /* Flush network side */ - unregister_netdev(sl->dev); - /* This will complete via sl_free_netdev */ -} -static int slip_hangup(struct tty_struct *tty) -{ - slip_close(tty); - return 0; + /* Count references from TTY module */ } + /************************************************************************ * STANDARD SLIP ENCAPSULATION * ************************************************************************/ @@ -1258,7 +1311,6 @@ static struct tty_ldisc_ops sl_ldisc = { .name = "slip", .open = slip_open, .close = slip_close, - .hangup = slip_hangup, .ioctl = slip_ioctl, .receive_buf = slip_receive_buf, .write_wakeup = slip_write_wakeup, @@ -1332,8 +1384,6 @@ static void __exit slip_exit(void) } } while (busy && time_before(jiffies, timeout)); - /* FIXME: hangup is async so we should wait when doing this second - phase */ for (i = 0; i < slip_maxdev; i++) { dev = slip_devs[i]; diff --git a/trunk/drivers/net/tun.c b/trunk/drivers/net/tun.c index d3ee1994b02f..3f5d28851aa2 100644 --- a/trunk/drivers/net/tun.c +++ b/trunk/drivers/net/tun.c @@ -1370,7 +1370,7 @@ static const struct file_operations tun_fops = { static struct miscdevice tun_miscdev = { .minor = TUN_MINOR, .name = "tun", - .nodename = "net/tun", + .devnode = "net/tun", .fops = &tun_fops, }; diff --git a/trunk/drivers/serial/21285.c b/trunk/drivers/serial/21285.c index 1e3d19397a59..cb6d85d7ff43 100644 --- a/trunk/drivers/serial/21285.c +++ b/trunk/drivers/serial/21285.c @@ -86,7 +86,7 @@ static void serial21285_enable_ms(struct uart_port *port) static irqreturn_t serial21285_rx_chars(int irq, void *dev_id) { struct uart_port *port = dev_id; - struct tty_struct *tty = port->state->port.tty; + struct tty_struct *tty = port->info->port.tty; unsigned int status, ch, flag, rxs, max_count = 256; status = *CSR_UARTFLG; @@ -124,7 +124,7 @@ static irqreturn_t serial21285_rx_chars(int irq, void *dev_id) static irqreturn_t serial21285_tx_chars(int irq, void *dev_id) { struct uart_port *port = dev_id; - struct circ_buf *xmit = &port->state->xmit; + struct circ_buf *xmit = &port->info->xmit; int count = 256; if (port->x_char) { @@ -235,8 +235,8 @@ serial21285_set_termios(struct uart_port *port, struct ktermios *termios, baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); quot = uart_get_divisor(port, baud); - if (port->state && port->state->port.tty) { - struct tty_struct *tty = port->state->port.tty; + if (port->info && port->info->port.tty) { + struct tty_struct *tty = port->info->port.tty; unsigned int b = port->uartclk / (16 * quot); tty_encode_baud_rate(tty, b, b); } diff --git a/trunk/drivers/serial/8250.c b/trunk/drivers/serial/8250.c index 2209620d2349..fb867a9f55e9 100644 --- a/trunk/drivers/serial/8250.c +++ b/trunk/drivers/serial/8250.c @@ -1382,7 +1382,7 @@ static void serial8250_enable_ms(struct uart_port *port) static void receive_chars(struct uart_8250_port *up, unsigned int *status) { - struct tty_struct *tty = up->port.state->port.tty; + struct tty_struct *tty = up->port.info->port.tty; unsigned char ch, lsr = *status; int max_count = 256; char flag; @@ -1457,7 +1457,7 @@ receive_chars(struct uart_8250_port *up, unsigned int *status) static void transmit_chars(struct uart_8250_port *up) { - struct circ_buf *xmit = &up->port.state->xmit; + struct circ_buf *xmit = &up->port.info->xmit; int count; if (up->port.x_char) { @@ -1500,7 +1500,7 @@ static unsigned int check_modem_status(struct uart_8250_port *up) status |= up->msr_saved_flags; up->msr_saved_flags = 0; if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI && - up->port.state != NULL) { + up->port.info != NULL) { if (status & UART_MSR_TERI) up->port.icount.rng++; if (status & UART_MSR_DDSR) @@ -1510,7 +1510,7 @@ static unsigned int check_modem_status(struct uart_8250_port *up) if (status & UART_MSR_DCTS) uart_handle_cts_change(&up->port, status & UART_MSR_CTS); - wake_up_interruptible(&up->port.state->port.delta_msr_wait); + wake_up_interruptible(&up->port.info->delta_msr_wait); } return status; @@ -1677,7 +1677,7 @@ static int serial_link_irq_chain(struct uart_8250_port *up) INIT_LIST_HEAD(&up->list); i->head = &up->list; spin_unlock_irq(&i->lock); - irq_flags |= up->port.irqflags; + ret = request_irq(up->port.irq, serial8250_interrupt, irq_flags, "serial", i); if (ret < 0) @@ -1764,7 +1764,7 @@ static void serial8250_backup_timeout(unsigned long data) up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; spin_unlock_irqrestore(&up->port.lock, flags); if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) && - (!uart_circ_empty(&up->port.state->xmit) || up->port.x_char) && + (!uart_circ_empty(&up->port.info->xmit) || up->port.x_char) && (lsr & UART_LSR_THRE)) { iir &= ~(UART_IIR_ID | UART_IIR_NO_INT); iir |= UART_IIR_THRI; @@ -2026,7 +2026,7 @@ static int serial8250_startup(struct uart_port *port) * allow register changes to become visible. */ spin_lock_irqsave(&up->port.lock, flags); - if (up->port.irqflags & IRQF_SHARED) + if (up->port.flags & UPF_SHARE_IRQ) disable_irq_nosync(up->port.irq); wait_for_xmitr(up, UART_LSR_THRE); @@ -2039,7 +2039,7 @@ static int serial8250_startup(struct uart_port *port) iir = serial_in(up, UART_IIR); serial_out(up, UART_IER, 0); - if (up->port.irqflags & IRQF_SHARED) + if (up->port.flags & UPF_SHARE_IRQ) enable_irq(up->port.irq); spin_unlock_irqrestore(&up->port.lock, flags); @@ -2272,9 +2272,7 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios, /* * Ask the core to calculate the divisor for us. */ - baud = uart_get_baud_rate(port, termios, old, - port->uartclk / 16 / 0xffff, - port->uartclk / 16); + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); quot = serial8250_get_divisor(port, baud); /* @@ -2673,7 +2671,6 @@ static void __init serial8250_isa_init_ports(void) i++, up++) { up->port.iobase = old_serial_port[i].port; up->port.irq = irq_canonicalize(old_serial_port[i].irq); - up->port.irqflags = old_serial_port[i].irqflags; up->port.uartclk = old_serial_port[i].baud_base * 16; up->port.flags = old_serial_port[i].flags; up->port.hub6 = old_serial_port[i].hub6; @@ -2682,7 +2679,7 @@ static void __init serial8250_isa_init_ports(void) up->port.regshift = old_serial_port[i].iomem_reg_shift; set_io_from_upio(&up->port); if (share_irqs) - up->port.irqflags |= IRQF_SHARED; + up->port.flags |= UPF_SHARE_IRQ; } } @@ -2872,7 +2869,6 @@ int __init early_serial_setup(struct uart_port *port) p->iobase = port->iobase; p->membase = port->membase; p->irq = port->irq; - p->irqflags = port->irqflags; p->uartclk = port->uartclk; p->fifosize = port->fifosize; p->regshift = port->regshift; @@ -2946,7 +2942,6 @@ static int __devinit serial8250_probe(struct platform_device *dev) port.iobase = p->iobase; port.membase = p->membase; port.irq = p->irq; - port.irqflags = p->irqflags; port.uartclk = p->uartclk; port.regshift = p->regshift; port.iotype = p->iotype; @@ -2959,7 +2954,7 @@ static int __devinit serial8250_probe(struct platform_device *dev) port.serial_out = p->serial_out; port.dev = &dev->dev; if (share_irqs) - port.irqflags |= IRQF_SHARED; + port.flags |= UPF_SHARE_IRQ; ret = serial8250_register_port(&port); if (ret < 0) { dev_err(&dev->dev, "unable to register port at index %d " @@ -3101,7 +3096,6 @@ int serial8250_register_port(struct uart_port *port) uart->port.iobase = port->iobase; uart->port.membase = port->membase; uart->port.irq = port->irq; - uart->port.irqflags = port->irqflags; uart->port.uartclk = port->uartclk; uart->port.fifosize = port->fifosize; uart->port.regshift = port->regshift; diff --git a/trunk/drivers/serial/8250.h b/trunk/drivers/serial/8250.h index 6e19ea3e48d5..520260326f3d 100644 --- a/trunk/drivers/serial/8250.h +++ b/trunk/drivers/serial/8250.h @@ -25,7 +25,6 @@ struct old_serial_port { unsigned char io_type; unsigned char *iomem_base; unsigned short iomem_reg_shift; - unsigned long irqflags; }; /* diff --git a/trunk/drivers/serial/amba-pl010.c b/trunk/drivers/serial/amba-pl010.c index 429a8ae86933..58a4879c7e48 100644 --- a/trunk/drivers/serial/amba-pl010.c +++ b/trunk/drivers/serial/amba-pl010.c @@ -117,7 +117,7 @@ static void pl010_enable_ms(struct uart_port *port) static void pl010_rx_chars(struct uart_amba_port *uap) { - struct tty_struct *tty = uap->port.state->port.tty; + struct tty_struct *tty = uap->port.info->port.tty; unsigned int status, ch, flag, rsr, max_count = 256; status = readb(uap->port.membase + UART01x_FR); @@ -172,7 +172,7 @@ static void pl010_rx_chars(struct uart_amba_port *uap) static void pl010_tx_chars(struct uart_amba_port *uap) { - struct circ_buf *xmit = &uap->port.state->xmit; + struct circ_buf *xmit = &uap->port.info->xmit; int count; if (uap->port.x_char) { @@ -225,7 +225,7 @@ static void pl010_modem_status(struct uart_amba_port *uap) if (delta & UART01x_FR_CTS) uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS); - wake_up_interruptible(&uap->port.state->port.delta_msr_wait); + wake_up_interruptible(&uap->port.info->delta_msr_wait); } static irqreturn_t pl010_int(int irq, void *dev_id) diff --git a/trunk/drivers/serial/amba-pl011.c b/trunk/drivers/serial/amba-pl011.c index ef7adc8135dd..72ba0c6d3551 100644 --- a/trunk/drivers/serial/amba-pl011.c +++ b/trunk/drivers/serial/amba-pl011.c @@ -124,7 +124,7 @@ static void pl011_enable_ms(struct uart_port *port) static void pl011_rx_chars(struct uart_amba_port *uap) { - struct tty_struct *tty = uap->port.state->port.tty; + struct tty_struct *tty = uap->port.info->port.tty; unsigned int status, ch, flag, max_count = 256; status = readw(uap->port.membase + UART01x_FR); @@ -175,7 +175,7 @@ static void pl011_rx_chars(struct uart_amba_port *uap) static void pl011_tx_chars(struct uart_amba_port *uap) { - struct circ_buf *xmit = &uap->port.state->xmit; + struct circ_buf *xmit = &uap->port.info->xmit; int count; if (uap->port.x_char) { @@ -226,7 +226,7 @@ static void pl011_modem_status(struct uart_amba_port *uap) if (delta & UART01x_FR_CTS) uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS); - wake_up_interruptible(&uap->port.state->port.delta_msr_wait); + wake_up_interruptible(&uap->port.info->delta_msr_wait); } static irqreturn_t pl011_int(int irq, void *dev_id) diff --git a/trunk/drivers/serial/atmel_serial.c b/trunk/drivers/serial/atmel_serial.c index 3551c5cb7094..607d43a31048 100644 --- a/trunk/drivers/serial/atmel_serial.c +++ b/trunk/drivers/serial/atmel_serial.c @@ -427,7 +427,7 @@ static void atmel_rx_chars(struct uart_port *port) */ static void atmel_tx_chars(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; + struct circ_buf *xmit = &port->info->xmit; if (port->x_char && UART_GET_CSR(port) & ATMEL_US_TXRDY) { UART_PUT_CHAR(port, port->x_char); @@ -560,7 +560,7 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id) 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->state->xmit; + struct circ_buf *xmit = &port->info->xmit; struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; int count; @@ -663,14 +663,14 @@ static void atmel_rx_from_ring(struct uart_port *port) * uart_start(), which takes the lock. */ spin_unlock(&port->lock); - tty_flip_buffer_push(port->state->port.tty); + tty_flip_buffer_push(port->info->port.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->state->port.tty; + struct tty_struct *tty = port->info->port.tty; struct atmel_dma_buffer *pdc; int rx_idx = atmel_port->pdc_rx_idx; unsigned int head; @@ -776,7 +776,7 @@ static void atmel_tasklet_func(unsigned long data) if (status_change & ATMEL_US_CTS) uart_handle_cts_change(port, !(status & ATMEL_US_CTS)); - wake_up_interruptible(&port->state->port.delta_msr_wait); + wake_up_interruptible(&port->info->delta_msr_wait); atmel_port->irq_status_prev = status; } @@ -795,7 +795,7 @@ static void atmel_tasklet_func(unsigned long data) static int atmel_startup(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - struct tty_struct *tty = port->state->port.tty; + struct tty_struct *tty = port->info->port.tty; int retval; /* @@ -854,7 +854,7 @@ static int atmel_startup(struct uart_port *port) } if (atmel_use_dma_tx(port)) { struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; - struct circ_buf *xmit = &port->state->xmit; + struct circ_buf *xmit = &port->info->xmit; pdc->buf = xmit->buf; pdc->dma_addr = dma_map_single(port->dev, diff --git a/trunk/drivers/serial/bfin_5xx.c b/trunk/drivers/serial/bfin_5xx.c index 50abb7e557f4..b4a7650af696 100644 --- a/trunk/drivers/serial/bfin_5xx.c +++ b/trunk/drivers/serial/bfin_5xx.c @@ -42,10 +42,6 @@ # undef CONFIG_EARLY_PRINTK #endif -#ifdef CONFIG_SERIAL_BFIN_MODULE -# undef CONFIG_EARLY_PRINTK -#endif - /* UART name and device definitions */ #define BFIN_SERIAL_NAME "ttyBF" #define BFIN_SERIAL_MAJOR 204 @@ -144,7 +140,7 @@ static void bfin_serial_stop_tx(struct uart_port *port) { struct bfin_serial_port *uart = (struct bfin_serial_port *)port; #ifdef CONFIG_SERIAL_BFIN_DMA - struct circ_buf *xmit = &uart->port.state->xmit; + struct circ_buf *xmit = &uart->port.info->xmit; #endif while (!(UART_GET_LSR(uart) & TEMT)) @@ -171,7 +167,7 @@ static void bfin_serial_stop_tx(struct uart_port *port) static void bfin_serial_start_tx(struct uart_port *port) { struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - struct tty_struct *tty = uart->port.state->port.tty; + struct tty_struct *tty = uart->port.info->port.tty; #ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS if (uart->scts && !(bfin_serial_get_mctrl(&uart->port) & TIOCM_CTS)) { @@ -243,10 +239,10 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart) return; } - if (!uart->port.state || !uart->port.state->port.tty) + if (!uart->port.info || !uart->port.info->port.tty) return; #endif - tty = uart->port.state->port.tty; + tty = uart->port.info->port.tty; if (ANOMALY_05000363) { /* The BF533 (and BF561) family of processors have a nice anomaly @@ -331,7 +327,7 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart) static void bfin_serial_tx_chars(struct bfin_serial_port *uart) { - struct circ_buf *xmit = &uart->port.state->xmit; + struct circ_buf *xmit = &uart->port.info->xmit; if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { #ifdef CONFIG_BF54x @@ -398,7 +394,7 @@ static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id) #ifdef CONFIG_SERIAL_BFIN_DMA static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart) { - struct circ_buf *xmit = &uart->port.state->xmit; + struct circ_buf *xmit = &uart->port.info->xmit; uart->tx_done = 0; @@ -436,7 +432,7 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart) static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart) { - struct tty_struct *tty = uart->port.state->port.tty; + struct tty_struct *tty = uart->port.info->port.tty; int i, flg, status; status = UART_GET_LSR(uart); @@ -529,7 +525,7 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id) { struct bfin_serial_port *uart = dev_id; - struct circ_buf *xmit = &uart->port.state->xmit; + struct circ_buf *xmit = &uart->port.info->xmit; #ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS if (uart->scts && !(bfin_serial_get_mctrl(&uart->port)&TIOCM_CTS)) { @@ -965,10 +961,10 @@ static void bfin_serial_set_ldisc(struct uart_port *port) int line = port->line; unsigned short val; - if (line >= port->state->port.tty->driver->num) + if (line >= port->info->port.tty->driver->num) return; - switch (port->state->port.tty->termios->c_line) { + switch (port->info->port.tty->termios->c_line) { case N_IRDA: val = UART_GET_GCTL(&bfin_serial_ports[line]); val |= (IREN | RPOLC); diff --git a/trunk/drivers/serial/bfin_sport_uart.c b/trunk/drivers/serial/bfin_sport_uart.c index 088bb35475f1..c108b1a0ce98 100644 --- a/trunk/drivers/serial/bfin_sport_uart.c +++ b/trunk/drivers/serial/bfin_sport_uart.c @@ -178,7 +178,7 @@ static int sport_uart_setup(struct sport_uart_port *up, int sclk, int baud_rate) static irqreturn_t sport_uart_rx_irq(int irq, void *dev_id) { struct sport_uart_port *up = dev_id; - struct tty_struct *tty = up->port.state->port.tty; + struct tty_struct *tty = up->port.info->port.tty; unsigned int ch; do { @@ -205,7 +205,7 @@ static irqreturn_t sport_uart_tx_irq(int irq, void *dev_id) static irqreturn_t sport_uart_err_irq(int irq, void *dev_id) { struct sport_uart_port *up = dev_id; - struct tty_struct *tty = up->port.state->port.tty; + struct tty_struct *tty = up->port.info->port.tty; unsigned int stat = SPORT_GET_STAT(up); /* Overflow in RX FIFO */ @@ -290,7 +290,7 @@ static int sport_startup(struct uart_port *port) static void sport_uart_tx_chars(struct sport_uart_port *up) { - struct circ_buf *xmit = &up->port.state->xmit; + struct circ_buf *xmit = &up->port.info->xmit; if (SPORT_GET_STAT(up) & TXF) return; diff --git a/trunk/drivers/serial/clps711x.c b/trunk/drivers/serial/clps711x.c index b6acd19b458e..80e76426131d 100644 --- a/trunk/drivers/serial/clps711x.c +++ b/trunk/drivers/serial/clps711x.c @@ -93,7 +93,7 @@ static void clps711xuart_enable_ms(struct uart_port *port) static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id) { struct uart_port *port = dev_id; - struct tty_struct *tty = port->state->port.tty; + struct tty_struct *tty = port->info->port.tty; unsigned int status, ch, flg; status = clps_readl(SYSFLG(port)); @@ -147,7 +147,7 @@ static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id) static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id) { struct uart_port *port = dev_id; - struct circ_buf *xmit = &port->state->xmit; + struct circ_buf *xmit = &port->info->xmit; int count; if (port->x_char) { diff --git a/trunk/drivers/serial/cpm_uart/cpm_uart_core.c b/trunk/drivers/serial/cpm_uart/cpm_uart_core.c index 8d349b23249a..f8df0681e160 100644 --- a/trunk/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/trunk/drivers/serial/cpm_uart/cpm_uart_core.c @@ -244,7 +244,7 @@ static void cpm_uart_int_rx(struct uart_port *port) int i; unsigned char ch; u8 *cp; - struct tty_struct *tty = port->state->port.tty; + struct tty_struct *tty = port->info->port.tty; struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; cbd_t __iomem *bdp; u16 status; diff --git a/trunk/drivers/serial/dz.c b/trunk/drivers/serial/dz.c index 57421d776329..6042b87797a1 100644 --- a/trunk/drivers/serial/dz.c +++ b/trunk/drivers/serial/dz.c @@ -197,7 +197,7 @@ static inline void dz_receive_chars(struct dz_mux *mux) while ((status = dz_in(dport, DZ_RBUF)) & DZ_DVAL) { dport = &mux->dport[LINE(status)]; uport = &dport->port; - tty = uport->state->port.tty; /* point to the proper dev */ + tty = uport->info->port.tty; /* point to the proper dev */ ch = UCHAR(status); /* grab the char */ flag = TTY_NORMAL; @@ -249,7 +249,7 @@ static inline void dz_receive_chars(struct dz_mux *mux) } for (i = 0; i < DZ_NB_PORT; i++) if (lines_rx[i]) - tty_flip_buffer_push(mux->dport[i].port.state->port.tty); + tty_flip_buffer_push(mux->dport[i].port.info->port.tty); } /* @@ -268,7 +268,7 @@ static inline void dz_transmit_chars(struct dz_mux *mux) status = dz_in(dport, DZ_CSR); dport = &mux->dport[LINE(status)]; - xmit = &dport->port.state->xmit; + xmit = &dport->port.info->xmit; if (dport->port.x_char) { /* XON/XOFF chars */ dz_out(dport, DZ_TDR, dport->port.x_char); diff --git a/trunk/drivers/serial/icom.c b/trunk/drivers/serial/icom.c index 2d7feecaf492..cd1b6a45bb82 100644 --- a/trunk/drivers/serial/icom.c +++ b/trunk/drivers/serial/icom.c @@ -617,7 +617,7 @@ static void shutdown(struct icom_port *icom_port) * disable break condition */ cmdReg = readb(&icom_port->dram->CmdReg); - if (cmdReg & CMD_SND_BREAK) { + if ((cmdReg | CMD_SND_BREAK) == CMD_SND_BREAK) { writeb(cmdReg & ~CMD_SND_BREAK, &icom_port->dram->CmdReg); } } @@ -627,7 +627,7 @@ static int icom_write(struct uart_port *port) unsigned long data_count; unsigned char cmdReg; unsigned long offset; - int temp_tail = port->state->xmit.tail; + int temp_tail = port->info->xmit.tail; trace(ICOM_PORT, "WRITE", 0); @@ -638,11 +638,11 @@ static int icom_write(struct uart_port *port) } data_count = 0; - while ((port->state->xmit.head != temp_tail) && + while ((port->info->xmit.head != temp_tail) && (data_count <= XMIT_BUFF_SZ)) { ICOM_PORT->xmit_buf[data_count++] = - port->state->xmit.buf[temp_tail]; + port->info->xmit.buf[temp_tail]; temp_tail++; temp_tail &= (UART_XMIT_SIZE - 1); @@ -694,8 +694,8 @@ static inline void check_modem_status(struct icom_port *icom_port) uart_handle_cts_change(&icom_port->uart_port, delta_status & ICOM_CTS); - wake_up_interruptible(&icom_port->uart_port.state-> - port.delta_msr_wait); + wake_up_interruptible(&icom_port->uart_port.info-> + delta_msr_wait); old_status = status; } spin_unlock(&icom_port->uart_port.lock); @@ -718,10 +718,10 @@ static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port) icom_port->uart_port.icount.tx += count; for (i=0; iuart_port.state->xmit); i++) { + !uart_circ_empty(&icom_port->uart_port.info->xmit); i++) { - icom_port->uart_port.state->xmit.tail++; - icom_port->uart_port.state->xmit.tail &= + icom_port->uart_port.info->xmit.tail++; + icom_port->uart_port.info->xmit.tail &= (UART_XMIT_SIZE - 1); } @@ -735,7 +735,7 @@ static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port) static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port) { short int count, rcv_buff; - struct tty_struct *tty = icom_port->uart_port.state->port.tty; + struct tty_struct *tty = icom_port->uart_port.info->port.tty; unsigned short int status; struct uart_icount *icount; unsigned long offset; diff --git a/trunk/drivers/serial/imx.c b/trunk/drivers/serial/imx.c index 18130f11238e..7485afd0df4c 100644 --- a/trunk/drivers/serial/imx.c +++ b/trunk/drivers/serial/imx.c @@ -224,7 +224,7 @@ static void imx_mctrl_check(struct imx_port *sport) if (changed & TIOCM_CTS) uart_handle_cts_change(&sport->port, status & TIOCM_CTS); - wake_up_interruptible(&sport->port.state->port.delta_msr_wait); + wake_up_interruptible(&sport->port.info->delta_msr_wait); } /* @@ -236,7 +236,7 @@ static void imx_timeout(unsigned long data) struct imx_port *sport = (struct imx_port *)data; unsigned long flags; - if (sport->port.state) { + if (sport->port.info) { spin_lock_irqsave(&sport->port.lock, flags); imx_mctrl_check(sport); spin_unlock_irqrestore(&sport->port.lock, flags); @@ -323,7 +323,7 @@ static void imx_enable_ms(struct uart_port *port) static inline void imx_transmit_buffer(struct imx_port *sport) { - struct circ_buf *xmit = &sport->port.state->xmit; + struct circ_buf *xmit = &sport->port.info->xmit; while (!(readl(sport->port.membase + UTS) & UTS_TXFULL)) { /* send xmit->buf[xmit->tail] @@ -388,7 +388,7 @@ static irqreturn_t imx_rtsint(int irq, void *dev_id) writel(USR1_RTSD, sport->port.membase + USR1); uart_handle_cts_change(&sport->port, !!val); - wake_up_interruptible(&sport->port.state->port.delta_msr_wait); + wake_up_interruptible(&sport->port.info->delta_msr_wait); spin_unlock_irqrestore(&sport->port.lock, flags); return IRQ_HANDLED; @@ -397,7 +397,7 @@ static irqreturn_t imx_rtsint(int irq, void *dev_id) static irqreturn_t imx_txint(int irq, void *dev_id) { struct imx_port *sport = dev_id; - struct circ_buf *xmit = &sport->port.state->xmit; + struct circ_buf *xmit = &sport->port.info->xmit; unsigned long flags; spin_lock_irqsave(&sport->port.lock,flags); @@ -427,7 +427,7 @@ static irqreturn_t imx_rxint(int irq, void *dev_id) { struct imx_port *sport = dev_id; unsigned int rx,flg,ignored = 0; - struct tty_struct *tty = sport->port.state->port.tty; + struct tty_struct *tty = sport->port.info->port.tty; unsigned long flags, temp; spin_lock_irqsave(&sport->port.lock,flags); @@ -900,11 +900,11 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, rational_best_approximation(16 * div * baud, sport->port.uartclk, 1 << 16, 1 << 16, &num, &denom); - if (port->state && port->state->port.tty) { + if (port->info && port->info->port.tty) { tdiv64 = sport->port.uartclk; tdiv64 *= num; do_div(tdiv64, denom * 16 * div); - tty_encode_baud_rate(sport->port.state->port.tty, + tty_encode_baud_rate(sport->port.info->port.tty, (speed_t)tdiv64, (speed_t)tdiv64); } diff --git a/trunk/drivers/serial/ioc3_serial.c b/trunk/drivers/serial/ioc3_serial.c index d8983dd5c4b2..ae3699d77dd0 100644 --- a/trunk/drivers/serial/ioc3_serial.c +++ b/trunk/drivers/serial/ioc3_serial.c @@ -897,25 +897,25 @@ static void transmit_chars(struct uart_port *the_port) char *start; struct tty_struct *tty; struct ioc3_port *port = get_ioc3_port(the_port); - struct uart_state *state; + struct uart_info *info; if (!the_port) return; if (!port) return; - state = the_port->state; - tty = state->port.tty; + info = the_port->info; + tty = info->port.tty; - if (uart_circ_empty(&state->xmit) || uart_tx_stopped(the_port)) { + if (uart_circ_empty(&info->xmit) || uart_tx_stopped(the_port)) { /* Nothing to do or hw stopped */ set_notification(port, N_ALL_OUTPUT, 0); return; } - head = state->xmit.head; - tail = state->xmit.tail; - start = (char *)&state->xmit.buf[tail]; + head = info->xmit.head; + tail = info->xmit.tail; + start = (char *)&info->xmit.buf[tail]; /* write out all the data or until the end of the buffer */ xmit_count = (head < tail) ? (UART_XMIT_SIZE - tail) : (head - tail); @@ -928,14 +928,14 @@ static void transmit_chars(struct uart_port *the_port) /* advance the pointers */ tail += result; tail &= UART_XMIT_SIZE - 1; - state->xmit.tail = tail; - start = (char *)&state->xmit.buf[tail]; + info->xmit.tail = tail; + start = (char *)&info->xmit.buf[tail]; } } - if (uart_circ_chars_pending(&state->xmit) < WAKEUP_CHARS) + if (uart_circ_chars_pending(&info->xmit) < WAKEUP_CHARS) uart_write_wakeup(the_port); - if (uart_circ_empty(&state->xmit)) { + if (uart_circ_empty(&info->xmit)) { set_notification(port, N_OUTPUT_LOWAT, 0); } else { set_notification(port, N_OUTPUT_LOWAT, 1); @@ -956,7 +956,7 @@ ioc3_change_speed(struct uart_port *the_port, unsigned int cflag; int baud; int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8; - struct uart_state *state = the_port->state; + struct uart_info *info = the_port->info; cflag = new_termios->c_cflag; @@ -997,14 +997,14 @@ ioc3_change_speed(struct uart_port *the_port, the_port->ignore_status_mask = N_ALL_INPUT; - state->port.tty->low_latency = 1; + info->port.tty->low_latency = 1; - if (I_IGNPAR(state->port.tty)) + if (I_IGNPAR(info->port.tty)) the_port->ignore_status_mask &= ~(N_PARITY_ERROR | N_FRAMING_ERROR); - if (I_IGNBRK(state->port.tty)) { + if (I_IGNBRK(info->port.tty)) { the_port->ignore_status_mask &= ~N_BREAK; - if (I_IGNPAR(state->port.tty)) + if (I_IGNPAR(info->port.tty)) the_port->ignore_status_mask &= ~N_OVERRUN_ERROR; } if (!(cflag & CREAD)) { @@ -1286,8 +1286,8 @@ static inline int do_read(struct uart_port *the_port, char *buf, int len) uart_handle_dcd_change (port->ip_port, 0); wake_up_interruptible - (&the_port->state-> - port.delta_msr_wait); + (&the_port->info-> + delta_msr_wait); } /* If we had any data to return, we @@ -1392,21 +1392,21 @@ static int receive_chars(struct uart_port *the_port) struct tty_struct *tty; unsigned char ch[MAX_CHARS]; int read_count = 0, read_room, flip = 0; - struct uart_state *state = the_port->state; + struct uart_info *info = the_port->info; struct ioc3_port *port = get_ioc3_port(the_port); unsigned long pflags; /* Make sure all the pointers are "good" ones */ - if (!state) + if (!info) return 0; - if (!state->port.tty) + if (!info->port.tty) return 0; if (!(port->ip_flags & INPUT_ENABLE)) return 0; spin_lock_irqsave(&the_port->lock, pflags); - tty = state->port.tty; + tty = info->port.tty; read_count = do_read(the_port, ch, MAX_CHARS); if (read_count > 0) { @@ -1491,7 +1491,7 @@ ioc3uart_intr_one(struct ioc3_submodule *is, uart_handle_dcd_change(the_port, shadow & SHADOW_DCD); wake_up_interruptible - (&the_port->state->port.delta_msr_wait); + (&the_port->info->delta_msr_wait); } else if ((port->ip_notify & N_DDCD) && !(shadow & SHADOW_DCD)) { /* Flag delta DCD/no DCD */ @@ -1511,7 +1511,7 @@ ioc3uart_intr_one(struct ioc3_submodule *is, uart_handle_cts_change(the_port, shadow & SHADOW_CTS); wake_up_interruptible - (&the_port->state->port.delta_msr_wait); + (&the_port->info->delta_msr_wait); } } @@ -1721,14 +1721,14 @@ static void ic3_shutdown(struct uart_port *the_port) { unsigned long port_flags; struct ioc3_port *port; - struct uart_state *state; + struct uart_info *info; port = get_ioc3_port(the_port); if (!port) return; - state = the_port->state; - wake_up_interruptible(&state->port.delta_msr_wait); + info = the_port->info; + wake_up_interruptible(&info->delta_msr_wait); spin_lock_irqsave(&the_port->lock, port_flags); set_notification(port, N_ALL, 0); diff --git a/trunk/drivers/serial/ioc4_serial.c b/trunk/drivers/serial/ioc4_serial.c index 2e02c3026d24..e5c58fe7e745 100644 --- a/trunk/drivers/serial/ioc4_serial.c +++ b/trunk/drivers/serial/ioc4_serial.c @@ -1627,25 +1627,25 @@ static void transmit_chars(struct uart_port *the_port) char *start; struct tty_struct *tty; struct ioc4_port *port = get_ioc4_port(the_port, 0); - struct uart_state *state; + struct uart_info *info; if (!the_port) return; if (!port) return; - state = the_port->state; - tty = state->port.tty; + info = the_port->info; + tty = info->port.tty; - if (uart_circ_empty(&state->xmit) || uart_tx_stopped(the_port)) { + if (uart_circ_empty(&info->xmit) || uart_tx_stopped(the_port)) { /* Nothing to do or hw stopped */ set_notification(port, N_ALL_OUTPUT, 0); return; } - head = state->xmit.head; - tail = state->xmit.tail; - start = (char *)&state->xmit.buf[tail]; + head = info->xmit.head; + tail = info->xmit.tail; + start = (char *)&info->xmit.buf[tail]; /* write out all the data or until the end of the buffer */ xmit_count = (head < tail) ? (UART_XMIT_SIZE - tail) : (head - tail); @@ -1658,14 +1658,14 @@ static void transmit_chars(struct uart_port *the_port) /* advance the pointers */ tail += result; tail &= UART_XMIT_SIZE - 1; - state->xmit.tail = tail; - start = (char *)&state->xmit.buf[tail]; + info->xmit.tail = tail; + start = (char *)&info->xmit.buf[tail]; } } - if (uart_circ_chars_pending(&state->xmit) < WAKEUP_CHARS) + if (uart_circ_chars_pending(&info->xmit) < WAKEUP_CHARS) uart_write_wakeup(the_port); - if (uart_circ_empty(&state->xmit)) { + if (uart_circ_empty(&info->xmit)) { set_notification(port, N_OUTPUT_LOWAT, 0); } else { set_notification(port, N_OUTPUT_LOWAT, 1); @@ -1686,7 +1686,7 @@ ioc4_change_speed(struct uart_port *the_port, int baud, bits; unsigned cflag; int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8; - struct uart_state *state = the_port->state; + struct uart_info *info = the_port->info; cflag = new_termios->c_cflag; @@ -1738,14 +1738,14 @@ ioc4_change_speed(struct uart_port *the_port, the_port->ignore_status_mask = N_ALL_INPUT; - state->port.tty->low_latency = 1; + info->port.tty->low_latency = 1; - if (I_IGNPAR(state->port.tty)) + if (I_IGNPAR(info->port.tty)) the_port->ignore_status_mask &= ~(N_PARITY_ERROR | N_FRAMING_ERROR); - if (I_IGNBRK(state->port.tty)) { + if (I_IGNBRK(info->port.tty)) { the_port->ignore_status_mask &= ~N_BREAK; - if (I_IGNPAR(state->port.tty)) + if (I_IGNPAR(info->port.tty)) the_port->ignore_status_mask &= ~N_OVERRUN_ERROR; } if (!(cflag & CREAD)) { @@ -1784,7 +1784,7 @@ ioc4_change_speed(struct uart_port *the_port, static inline int ic4_startup_local(struct uart_port *the_port) { struct ioc4_port *port; - struct uart_state *state; + struct uart_info *info; if (!the_port) return -1; @@ -1793,7 +1793,7 @@ static inline int ic4_startup_local(struct uart_port *the_port) if (!port) return -1; - state = the_port->state; + info = the_port->info; local_open(port); @@ -1801,7 +1801,7 @@ static inline int ic4_startup_local(struct uart_port *the_port) ioc4_set_proto(port, the_port->mapbase); /* set the speed of the serial port */ - ioc4_change_speed(the_port, state->port.tty->termios, + ioc4_change_speed(the_port, info->port.tty->termios, (struct ktermios *)0); return 0; @@ -1882,7 +1882,7 @@ static void handle_intr(void *arg, uint32_t sio_ir) the_port = port->ip_port; the_port->icount.dcd = 1; wake_up_interruptible - (&the_port->state->port.delta_msr_wait); + (&the_port-> info->delta_msr_wait); } else if ((port->ip_notify & N_DDCD) && !(shadow & IOC4_SHADOW_DCD)) { /* Flag delta DCD/no DCD */ @@ -1904,7 +1904,7 @@ static void handle_intr(void *arg, uint32_t sio_ir) the_port->icount.cts = (shadow & IOC4_SHADOW_CTS) ? 1 : 0; wake_up_interruptible - (&the_port->state->port.delta_msr_wait); + (&the_port->info->delta_msr_wait); } } @@ -2236,8 +2236,8 @@ static inline int do_read(struct uart_port *the_port, unsigned char *buf, && port->ip_port) { the_port->icount.dcd = 0; wake_up_interruptible - (&the_port->state-> - port.delta_msr_wait); + (&the_port->info-> + delta_msr_wait); } /* If we had any data to return, we @@ -2341,17 +2341,17 @@ static void receive_chars(struct uart_port *the_port) unsigned char ch[IOC4_MAX_CHARS]; int read_count, request_count = IOC4_MAX_CHARS; struct uart_icount *icount; - struct uart_state *state = the_port->state; + struct uart_info *info = the_port->info; unsigned long pflags; /* Make sure all the pointers are "good" ones */ - if (!state) + if (!info) return; - if (!state->port.tty) + if (!info->port.tty) return; spin_lock_irqsave(&the_port->lock, pflags); - tty = state->port.tty; + tty = info->port.tty; request_count = tty_buffer_request_room(tty, IOC4_MAX_CHARS); @@ -2430,19 +2430,19 @@ static void ic4_shutdown(struct uart_port *the_port) { unsigned long port_flags; struct ioc4_port *port; - struct uart_state *state; + struct uart_info *info; port = get_ioc4_port(the_port, 0); if (!port) return; - state = the_port->state; + info = the_port->info; port->ip_port = NULL; - wake_up_interruptible(&state->port.delta_msr_wait); + wake_up_interruptible(&info->delta_msr_wait); - if (state->port.tty) - set_bit(TTY_IO_ERROR, &state->port.tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); spin_lock_irqsave(&the_port->lock, port_flags); set_notification(port, N_ALL, 0); @@ -2538,7 +2538,7 @@ static int ic4_startup(struct uart_port *the_port) int retval; struct ioc4_port *port; struct ioc4_control *control; - struct uart_state *state; + struct uart_info *info; unsigned long port_flags; if (!the_port) @@ -2546,7 +2546,7 @@ static int ic4_startup(struct uart_port *the_port) port = get_ioc4_port(the_port, 1); if (!port) return -ENODEV; - state = the_port->state; + info = the_port->info; control = port->ip_control; if (!control) { diff --git a/trunk/drivers/serial/ip22zilog.c b/trunk/drivers/serial/ip22zilog.c index ebff4a1d4bcc..0d9acbd0bb70 100644 --- a/trunk/drivers/serial/ip22zilog.c +++ b/trunk/drivers/serial/ip22zilog.c @@ -256,9 +256,9 @@ static struct tty_struct *ip22zilog_receive_chars(struct uart_ip22zilog_port *up unsigned int r1; tty = NULL; - if (up->port.state != NULL && - up->port.state->port.tty != NULL) - tty = up->port.state->port.tty; + if (up->port.info != NULL && + up->port.info->port.tty != NULL) + tty = up->port.info->port.tty; for (;;) { ch = readb(&channel->control); @@ -354,7 +354,7 @@ static void ip22zilog_status_handle(struct uart_ip22zilog_port *up, uart_handle_cts_change(&up->port, (status & CTS)); - wake_up_interruptible(&up->port.state->port.delta_msr_wait); + wake_up_interruptible(&up->port.info->delta_msr_wait); } up->prev_status = status; @@ -404,9 +404,9 @@ static void ip22zilog_transmit_chars(struct uart_ip22zilog_port *up, return; } - if (up->port.state == NULL) + if (up->port.info == NULL) goto ack_tx_int; - xmit = &up->port.state->xmit; + xmit = &up->port.info->xmit; if (uart_circ_empty(xmit)) goto ack_tx_int; if (uart_tx_stopped(&up->port)) @@ -607,7 +607,7 @@ static void ip22zilog_start_tx(struct uart_port *port) port->icount.tx++; port->x_char = 0; } else { - struct circ_buf *xmit = &port->state->xmit; + struct circ_buf *xmit = &port->info->xmit; writeb(xmit->buf[xmit->tail], &channel->data); ZSDELAY(); diff --git a/trunk/drivers/serial/jsm/jsm_neo.c b/trunk/drivers/serial/jsm/jsm_neo.c index b4b124e4828f..9dadaa11d266 100644 --- a/trunk/drivers/serial/jsm/jsm_neo.c +++ b/trunk/drivers/serial/jsm/jsm_neo.c @@ -989,7 +989,7 @@ static void neo_param(struct jsm_channel *ch) { 50, B50 }, }; - cflag = C_BAUD(ch->uart_port.state->port.tty); + cflag = C_BAUD(ch->uart_port.info->port.tty); baud = 9600; for (i = 0; i < ARRAY_SIZE(baud_rates); i++) { if (baud_rates[i].cflag == cflag) { diff --git a/trunk/drivers/serial/jsm/jsm_tty.c b/trunk/drivers/serial/jsm/jsm_tty.c index 7439c0373620..00f4577d2f7f 100644 --- a/trunk/drivers/serial/jsm/jsm_tty.c +++ b/trunk/drivers/serial/jsm/jsm_tty.c @@ -147,7 +147,7 @@ static void jsm_tty_send_xchar(struct uart_port *port, char ch) struct ktermios *termios; spin_lock_irqsave(&port->lock, lock_flags); - termios = port->state->port.tty->termios; + termios = port->info->port.tty->termios; if (ch == termios->c_cc[VSTART]) channel->ch_bd->bd_ops->send_start_character(channel); @@ -245,7 +245,7 @@ static int jsm_tty_open(struct uart_port *port) channel->ch_cached_lsr = 0; channel->ch_stops_sent = 0; - termios = port->state->port.tty->termios; + termios = port->info->port.tty->termios; channel->ch_c_cflag = termios->c_cflag; channel->ch_c_iflag = termios->c_iflag; channel->ch_c_oflag = termios->c_oflag; @@ -278,7 +278,7 @@ static void jsm_tty_close(struct uart_port *port) jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n"); bd = channel->ch_bd; - ts = port->state->port.tty->termios; + ts = port->info->port.tty->termios; channel->ch_flags &= ~(CH_STOPI); @@ -530,7 +530,7 @@ void jsm_input(struct jsm_channel *ch) if (!ch) return; - tp = ch->uart_port.state->port.tty; + tp = ch->uart_port.info->port.tty; bd = ch->ch_bd; if(!bd) @@ -849,7 +849,7 @@ int jsm_tty_write(struct uart_port *port) u16 tail; u16 tmask; u32 remain; - int temp_tail = port->state->xmit.tail; + int temp_tail = port->info->xmit.tail; struct jsm_channel *channel = (struct jsm_channel *)port; tmask = WQUEUEMASK; @@ -865,10 +865,10 @@ int jsm_tty_write(struct uart_port *port) data_count = 0; if (bufcount >= remain) { bufcount -= remain; - while ((port->state->xmit.head != temp_tail) && + while ((port->info->xmit.head != temp_tail) && (data_count < remain)) { channel->ch_wqueue[head++] = - port->state->xmit.buf[temp_tail]; + port->info->xmit.buf[temp_tail]; temp_tail++; temp_tail &= (UART_XMIT_SIZE - 1); @@ -880,10 +880,10 @@ int jsm_tty_write(struct uart_port *port) data_count1 = 0; if (bufcount > 0) { remain = bufcount; - while ((port->state->xmit.head != temp_tail) && + while ((port->info->xmit.head != temp_tail) && (data_count1 < remain)) { channel->ch_wqueue[head++] = - port->state->xmit.buf[temp_tail]; + port->info->xmit.buf[temp_tail]; temp_tail++; temp_tail &= (UART_XMIT_SIZE - 1); @@ -892,7 +892,7 @@ int jsm_tty_write(struct uart_port *port) } } - port->state->xmit.tail = temp_tail; + port->info->xmit.tail = temp_tail; data_count += data_count1; if (data_count) { diff --git a/trunk/drivers/serial/m32r_sio.c b/trunk/drivers/serial/m32r_sio.c index bea5c215460c..611c97a15654 100644 --- a/trunk/drivers/serial/m32r_sio.c +++ b/trunk/drivers/serial/m32r_sio.c @@ -286,7 +286,7 @@ static void m32r_sio_start_tx(struct uart_port *port) { #ifdef CONFIG_SERIAL_M32R_PLDSIO struct uart_sio_port *up = (struct uart_sio_port *)port; - struct circ_buf *xmit = &up->port.state->xmit; + struct circ_buf *xmit = &up->port.info->xmit; if (!(up->ier & UART_IER_THRI)) { up->ier |= UART_IER_THRI; @@ -325,7 +325,7 @@ static void m32r_sio_enable_ms(struct uart_port *port) static void receive_chars(struct uart_sio_port *up, int *status) { - struct tty_struct *tty = up->port.state->port.tty; + struct tty_struct *tty = up->port.info->port.tty; unsigned char ch; unsigned char flag; int max_count = 256; @@ -398,7 +398,7 @@ static void receive_chars(struct uart_sio_port *up, int *status) static void transmit_chars(struct uart_sio_port *up) { - struct circ_buf *xmit = &up->port.state->xmit; + struct circ_buf *xmit = &up->port.info->xmit; int count; if (up->port.x_char) { diff --git a/trunk/drivers/serial/max3100.c b/trunk/drivers/serial/max3100.c index 75ab00631c41..9fd33e5622bd 100644 --- a/trunk/drivers/serial/max3100.c +++ b/trunk/drivers/serial/max3100.c @@ -184,7 +184,7 @@ static void max3100_timeout(unsigned long data) { struct max3100_port *s = (struct max3100_port *)data; - if (s->port.state) { + if (s->port.info) { max3100_dowork(s); mod_timer(&s->timer, jiffies + s->poll_time); } @@ -261,7 +261,7 @@ static void max3100_work(struct work_struct *w) int rxchars; u16 tx, rx; int conf, cconf, rts, crts; - struct circ_buf *xmit = &s->port.state->xmit; + struct circ_buf *xmit = &s->port.info->xmit; dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -307,8 +307,8 @@ static void max3100_work(struct work_struct *w) } } - if (rxchars > 16 && s->port.state->port.tty != NULL) { - tty_flip_buffer_push(s->port.state->port.tty); + if (rxchars > 16 && s->port.info->port.tty != NULL) { + tty_flip_buffer_push(s->port.info->port.tty); rxchars = 0; } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) @@ -320,8 +320,8 @@ static void max3100_work(struct work_struct *w) (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)))); - if (rxchars > 0 && s->port.state->port.tty != NULL) - tty_flip_buffer_push(s->port.state->port.tty); + if (rxchars > 0 && s->port.info->port.tty != NULL) + tty_flip_buffer_push(s->port.info->port.tty); } static irqreturn_t max3100_irq(int irqno, void *dev_id) @@ -429,7 +429,7 @@ max3100_set_termios(struct uart_port *port, struct ktermios *termios, int baud = 0; unsigned cflag; u32 param_new, param_mask, parity = 0; - struct tty_struct *tty = s->port.state->port.tty; + struct tty_struct *tty = s->port.info->port.tty; dev_dbg(&s->spi->dev, "%s\n", __func__); if (!tty) @@ -529,7 +529,7 @@ max3100_set_termios(struct uart_port *port, struct ktermios *termios, MAX3100_STATUS_OE; /* we are sending char from a workqueue so enable */ - s->port.state->port.tty->low_latency = 1; + s->port.info->port.tty->low_latency = 1; if (s->poll_time > 0) del_timer_sync(&s->timer); diff --git a/trunk/drivers/serial/mcf.c b/trunk/drivers/serial/mcf.c index b44382442bf1..0eefb07bebaf 100644 --- a/trunk/drivers/serial/mcf.c +++ b/trunk/drivers/serial/mcf.c @@ -323,7 +323,7 @@ static void mcf_rx_chars(struct mcf_uart *pp) uart_insert_char(port, status, MCFUART_USR_RXOVERRUN, ch, flag); } - tty_flip_buffer_push(port->state->port.tty); + tty_flip_buffer_push(port->info->port.tty); } /****************************************************************************/ @@ -331,7 +331,7 @@ static void mcf_rx_chars(struct mcf_uart *pp) static void mcf_tx_chars(struct mcf_uart *pp) { struct uart_port *port = &pp->port; - struct circ_buf *xmit = &port->state->xmit; + struct circ_buf *xmit = &port->info->xmit; if (port->x_char) { /* Send special char - probably flow control */ diff --git a/trunk/drivers/serial/mpc52xx_uart.c b/trunk/drivers/serial/mpc52xx_uart.c index d7bcd074d383..abbd146c50d9 100644 --- a/trunk/drivers/serial/mpc52xx_uart.c +++ b/trunk/drivers/serial/mpc52xx_uart.c @@ -745,7 +745,7 @@ static struct uart_ops mpc52xx_uart_ops = { static inline int mpc52xx_uart_int_rx_chars(struct uart_port *port) { - struct tty_struct *tty = port->state->port.tty; + struct tty_struct *tty = port->info->port.tty; unsigned char ch, flag; unsigned short status; @@ -812,7 +812,7 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port) static inline int mpc52xx_uart_int_tx_chars(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; + struct circ_buf *xmit = &port->info->xmit; /* Process out of band chars */ if (port->x_char) { diff --git a/trunk/drivers/serial/mpsc.c b/trunk/drivers/serial/mpsc.c index b5496c28e60b..61d3ade5286c 100644 --- a/trunk/drivers/serial/mpsc.c +++ b/trunk/drivers/serial/mpsc.c @@ -936,7 +936,7 @@ static int serial_polled; static int mpsc_rx_intr(struct mpsc_port_info *pi) { struct mpsc_rx_desc *rxre; - struct tty_struct *tty = pi->port.state->port.tty; + struct tty_struct *tty = pi->port.info->port.tty; u32 cmdstat, bytes_in, i; int rc = 0; u8 *bp; @@ -1109,7 +1109,7 @@ static void mpsc_setup_tx_desc(struct mpsc_port_info *pi, u32 count, u32 intr) static void mpsc_copy_tx_data(struct mpsc_port_info *pi) { - struct circ_buf *xmit = &pi->port.state->xmit; + struct circ_buf *xmit = &pi->port.info->xmit; u8 *bp; u32 i; diff --git a/trunk/drivers/serial/msm_serial.c b/trunk/drivers/serial/msm_serial.c index b05c5aa02cb4..f7c24baa1416 100644 --- a/trunk/drivers/serial/msm_serial.c +++ b/trunk/drivers/serial/msm_serial.c @@ -88,7 +88,7 @@ static void msm_enable_ms(struct uart_port *port) static void handle_rx(struct uart_port *port) { - struct tty_struct *tty = port->state->port.tty; + struct tty_struct *tty = port->info->port.tty; unsigned int sr; /* @@ -136,7 +136,7 @@ static void handle_rx(struct uart_port *port) static void handle_tx(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; + struct circ_buf *xmit = &port->info->xmit; struct msm_port *msm_port = UART_TO_MSM(port); int sent_tx; @@ -169,7 +169,7 @@ static void handle_delta_cts(struct uart_port *port) { msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR); port->icount.cts++; - wake_up_interruptible(&port->state->port.delta_msr_wait); + wake_up_interruptible(&port->info->delta_msr_wait); } static irqreturn_t msm_irq(int irq, void *dev_id) diff --git a/trunk/drivers/serial/mux.c b/trunk/drivers/serial/mux.c index 7571aaa138b0..953a5ffa9b44 100644 --- a/trunk/drivers/serial/mux.c +++ b/trunk/drivers/serial/mux.c @@ -199,7 +199,7 @@ static void mux_break_ctl(struct uart_port *port, int break_state) static void mux_write(struct uart_port *port) { int count; - struct circ_buf *xmit = &port->state->xmit; + struct circ_buf *xmit = &port->info->xmit; if(port->x_char) { UART_PUT_CHAR(port, port->x_char); @@ -243,7 +243,7 @@ static void mux_write(struct uart_port *port) static void mux_read(struct uart_port *port) { int data; - struct tty_struct *tty = port->state->port.tty; + struct tty_struct *tty = port->info->port.tty; __u32 start_count = port->icount.rx; while(1) { diff --git a/trunk/drivers/serial/netx-serial.c b/trunk/drivers/serial/netx-serial.c index 7735c9f35fa0..3e5dda8518b7 100644 --- a/trunk/drivers/serial/netx-serial.c +++ b/trunk/drivers/serial/netx-serial.c @@ -140,7 +140,7 @@ static void netx_enable_ms(struct uart_port *port) static inline void netx_transmit_buffer(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; + struct circ_buf *xmit = &port->info->xmit; if (port->x_char) { writel(port->x_char, port->membase + UART_DR); @@ -185,7 +185,7 @@ static unsigned int netx_tx_empty(struct uart_port *port) static void netx_txint(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; + struct circ_buf *xmit = &port->info->xmit; if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { netx_stop_tx(port); @@ -201,7 +201,7 @@ static void netx_txint(struct uart_port *port) static void netx_rxint(struct uart_port *port) { unsigned char rx, flg, status; - struct tty_struct *tty = port->state->port.tty; + struct tty_struct *tty = port->info->port.tty; while (!(readl(port->membase + UART_FR) & FR_RXFE)) { rx = readl(port->membase + UART_DR); diff --git a/trunk/drivers/serial/nwpserial.c b/trunk/drivers/serial/nwpserial.c index e1ab8ec0a4a6..9e150b19d726 100644 --- a/trunk/drivers/serial/nwpserial.c +++ b/trunk/drivers/serial/nwpserial.c @@ -126,7 +126,7 @@ static void nwpserial_config_port(struct uart_port *port, int flags) static irqreturn_t nwpserial_interrupt(int irq, void *dev_id) { struct nwpserial_port *up = dev_id; - struct tty_struct *tty = up->port.state->port.tty; + struct tty_struct *tty = up->port.info->port.tty; irqreturn_t ret; unsigned int iir; unsigned char ch; @@ -261,7 +261,7 @@ static void nwpserial_start_tx(struct uart_port *port) struct nwpserial_port *up; struct circ_buf *xmit; up = container_of(port, struct nwpserial_port, port); - xmit = &up->port.state->xmit; + xmit = &up->port.info->xmit; if (port->x_char) { nwpserial_putchar(up, up->port.x_char); diff --git a/trunk/drivers/serial/pmac_zilog.c b/trunk/drivers/serial/pmac_zilog.c index 0700cd10b97c..9c1243fbd512 100644 --- a/trunk/drivers/serial/pmac_zilog.c +++ b/trunk/drivers/serial/pmac_zilog.c @@ -242,12 +242,12 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap) } /* Sanity check, make sure the old bug is no longer happening */ - if (uap->port.state == NULL || uap->port.state->port.tty == NULL) { + if (uap->port.info == NULL || uap->port.info->port.tty == NULL) { WARN_ON(1); (void)read_zsdata(uap); return NULL; } - tty = uap->port.state->port.tty; + tty = uap->port.info->port.tty; while (1) { error = 0; @@ -369,7 +369,7 @@ static void pmz_status_handle(struct uart_pmac_port *uap) uart_handle_cts_change(&uap->port, !(status & CTS)); - wake_up_interruptible(&uap->port.state->port.delta_msr_wait); + wake_up_interruptible(&uap->port.info->delta_msr_wait); } if (status & BRK_ABRT) @@ -420,9 +420,9 @@ static void pmz_transmit_chars(struct uart_pmac_port *uap) return; } - if (uap->port.state == NULL) + if (uap->port.info == NULL) goto ack_tx_int; - xmit = &uap->port.state->xmit; + xmit = &uap->port.info->xmit; if (uart_circ_empty(xmit)) { uart_write_wakeup(&uap->port); goto ack_tx_int; @@ -655,7 +655,7 @@ static void pmz_start_tx(struct uart_port *port) port->icount.tx++; port->x_char = 0; } else { - struct circ_buf *xmit = &port->state->xmit; + struct circ_buf *xmit = &port->info->xmit; write_zsdata(uap, xmit->buf[xmit->tail]); zssync(uap); @@ -1645,7 +1645,7 @@ static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state) state = pmz_uart_reg.state + uap->port.line; mutex_lock(&pmz_irq_mutex); - mutex_lock(&state->port.mutex); + mutex_lock(&state->mutex); spin_lock_irqsave(&uap->port.lock, flags); @@ -1676,7 +1676,7 @@ static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state) /* Shut the chip down */ pmz_set_scc_power(uap, 0); - mutex_unlock(&state->port.mutex); + mutex_unlock(&state->mutex); mutex_unlock(&pmz_irq_mutex); pmz_debug("suspend, switching complete\n"); @@ -1705,7 +1705,7 @@ static int pmz_resume(struct macio_dev *mdev) state = pmz_uart_reg.state + uap->port.line; mutex_lock(&pmz_irq_mutex); - mutex_lock(&state->port.mutex); + mutex_lock(&state->mutex); spin_lock_irqsave(&uap->port.lock, flags); if (!ZS_IS_OPEN(uap) && !ZS_IS_CONS(uap)) { @@ -1737,7 +1737,7 @@ static int pmz_resume(struct macio_dev *mdev) } bail: - mutex_unlock(&state->port.mutex); + mutex_unlock(&state->mutex); mutex_unlock(&pmz_irq_mutex); /* Right now, we deal with delay by blocking here, I'll be diff --git a/trunk/drivers/serial/pnx8xxx_uart.c b/trunk/drivers/serial/pnx8xxx_uart.c index 0aa75a97531c..1bb8f1b45767 100644 --- a/trunk/drivers/serial/pnx8xxx_uart.c +++ b/trunk/drivers/serial/pnx8xxx_uart.c @@ -100,7 +100,7 @@ static void pnx8xxx_mctrl_check(struct pnx8xxx_port *sport) if (changed & TIOCM_CTS) uart_handle_cts_change(&sport->port, status & TIOCM_CTS); - wake_up_interruptible(&sport->port.state->port.delta_msr_wait); + wake_up_interruptible(&sport->port.info->delta_msr_wait); } /* @@ -112,7 +112,7 @@ static void pnx8xxx_timeout(unsigned long data) struct pnx8xxx_port *sport = (struct pnx8xxx_port *)data; unsigned long flags; - if (sport->port.state) { + if (sport->port.info) { spin_lock_irqsave(&sport->port.lock, flags); pnx8xxx_mctrl_check(sport); spin_unlock_irqrestore(&sport->port.lock, flags); @@ -181,7 +181,7 @@ static void pnx8xxx_enable_ms(struct uart_port *port) static void pnx8xxx_rx_chars(struct pnx8xxx_port *sport) { - struct tty_struct *tty = sport->port.state->port.tty; + struct tty_struct *tty = sport->port.info->port.tty; unsigned int status, ch, flg; status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) | @@ -243,7 +243,7 @@ static void pnx8xxx_rx_chars(struct pnx8xxx_port *sport) static void pnx8xxx_tx_chars(struct pnx8xxx_port *sport) { - struct circ_buf *xmit = &sport->port.state->xmit; + struct circ_buf *xmit = &sport->port.info->xmit; if (sport->port.x_char) { serial_out(sport, PNX8XXX_FIFO, sport->port.x_char); diff --git a/trunk/drivers/serial/pxa.c b/trunk/drivers/serial/pxa.c index 6443b7ff274a..a48a8a13d87b 100644 --- a/trunk/drivers/serial/pxa.c +++ b/trunk/drivers/serial/pxa.c @@ -96,7 +96,7 @@ static void serial_pxa_stop_rx(struct uart_port *port) static inline void receive_chars(struct uart_pxa_port *up, int *status) { - struct tty_struct *tty = up->port.state->port.tty; + struct tty_struct *tty = up->port.info->port.tty; unsigned int ch, flag; int max_count = 256; @@ -161,7 +161,7 @@ static inline void receive_chars(struct uart_pxa_port *up, int *status) static void transmit_chars(struct uart_pxa_port *up) { - struct circ_buf *xmit = &up->port.state->xmit; + struct circ_buf *xmit = &up->port.info->xmit; int count; if (up->port.x_char) { @@ -220,7 +220,7 @@ static inline void check_modem_status(struct uart_pxa_port *up) if (status & UART_MSR_DCTS) uart_handle_cts_change(&up->port, status & UART_MSR_CTS); - wake_up_interruptible(&up->port.state->port.delta_msr_wait); + wake_up_interruptible(&up->port.info->delta_msr_wait); } /* diff --git a/trunk/drivers/serial/sa1100.c b/trunk/drivers/serial/sa1100.c index 7f5e26873220..94530f01521e 100644 --- a/trunk/drivers/serial/sa1100.c +++ b/trunk/drivers/serial/sa1100.c @@ -117,7 +117,7 @@ static void sa1100_mctrl_check(struct sa1100_port *sport) if (changed & TIOCM_CTS) uart_handle_cts_change(&sport->port, status & TIOCM_CTS); - wake_up_interruptible(&sport->port.state->port.delta_msr_wait); + wake_up_interruptible(&sport->port.info->delta_msr_wait); } /* @@ -129,7 +129,7 @@ static void sa1100_timeout(unsigned long data) struct sa1100_port *sport = (struct sa1100_port *)data; unsigned long flags; - if (sport->port.state) { + if (sport->port.info) { spin_lock_irqsave(&sport->port.lock, flags); sa1100_mctrl_check(sport); spin_unlock_irqrestore(&sport->port.lock, flags); @@ -189,7 +189,7 @@ static void sa1100_enable_ms(struct uart_port *port) static void sa1100_rx_chars(struct sa1100_port *sport) { - struct tty_struct *tty = sport->port.state->port.tty; + struct tty_struct *tty = sport->port.info->port.tty; unsigned int status, ch, flg; status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) | @@ -239,7 +239,7 @@ sa1100_rx_chars(struct sa1100_port *sport) static void sa1100_tx_chars(struct sa1100_port *sport) { - struct circ_buf *xmit = &sport->port.state->xmit; + struct circ_buf *xmit = &sport->port.info->xmit; if (sport->port.x_char) { UART_PUT_CHAR(sport, sport->port.x_char); diff --git a/trunk/drivers/serial/samsung.c b/trunk/drivers/serial/samsung.c index 1523e8d9ae77..c8851a0db63a 100644 --- a/trunk/drivers/serial/samsung.c +++ b/trunk/drivers/serial/samsung.c @@ -196,7 +196,7 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id) { struct s3c24xx_uart_port *ourport = dev_id; struct uart_port *port = &ourport->port; - struct tty_struct *tty = port->state->port.tty; + struct tty_struct *tty = port->info->port.tty; unsigned int ufcon, ch, flag, ufstat, uerstat; int max_count = 64; @@ -281,7 +281,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) { struct s3c24xx_uart_port *ourport = id; struct uart_port *port = &ourport->port; - struct circ_buf *xmit = &port->state->xmit; + struct circ_buf *xmit = &port->info->xmit; int count = 256; if (port->x_char) { @@ -992,10 +992,10 @@ static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb, struct ktermios *termios; struct tty_struct *tty; - if (uport->state == NULL) + if (uport->info == NULL) goto exit; - tty = uport->state->port.tty; + tty = uport->info->port.tty; if (tty == NULL) goto exit; diff --git a/trunk/drivers/serial/sb1250-duart.c b/trunk/drivers/serial/sb1250-duart.c index a2f2b3254499..319e8b83f6be 100644 --- a/trunk/drivers/serial/sb1250-duart.c +++ b/trunk/drivers/serial/sb1250-duart.c @@ -384,13 +384,13 @@ static void sbd_receive_chars(struct sbd_port *sport) uart_insert_char(uport, status, M_DUART_OVRUN_ERR, ch, flag); } - tty_flip_buffer_push(uport->state->port.tty); + tty_flip_buffer_push(uport->info->port.tty); } static void sbd_transmit_chars(struct sbd_port *sport) { struct uart_port *uport = &sport->port; - struct circ_buf *xmit = &sport->port.state->xmit; + struct circ_buf *xmit = &sport->port.info->xmit; unsigned int mask; int stop_tx; @@ -440,7 +440,7 @@ static void sbd_status_handle(struct sbd_port *sport) if (delta & ((M_DUART_IN_PIN2_VAL | M_DUART_IN_PIN0_VAL) << S_DUART_IN_PIN_CHNG)) - wake_up_interruptible(&uport->state->port.delta_msr_wait); + wake_up_interruptible(&uport->info->delta_msr_wait); } static irqreturn_t sbd_interrupt(int irq, void *dev_id) diff --git a/trunk/drivers/serial/sc26xx.c b/trunk/drivers/serial/sc26xx.c index 75038ad2b242..e0be11ceaa25 100644 --- a/trunk/drivers/serial/sc26xx.c +++ b/trunk/drivers/serial/sc26xx.c @@ -140,8 +140,8 @@ static struct tty_struct *receive_chars(struct uart_port *port) char flag; u8 status; - if (port->state != NULL) /* Unopened serial console */ - tty = port->state->port.tty; + if (port->info != NULL) /* Unopened serial console */ + tty = port->info->port.tty; while (limit-- > 0) { status = READ_SC_PORT(port, SR); @@ -190,10 +190,10 @@ static void transmit_chars(struct uart_port *port) { struct circ_buf *xmit; - if (!port->state) + if (!port->info) return; - xmit = &port->state->xmit; + xmit = &port->info->xmit; if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { sc26xx_disable_irq(port, IMR_TXRDY); return; @@ -316,7 +316,7 @@ static void sc26xx_stop_tx(struct uart_port *port) /* port->lock held by caller. */ static void sc26xx_start_tx(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; + struct circ_buf *xmit = &port->info->xmit; while (!uart_circ_empty(xmit)) { if (!(READ_SC_PORT(port, SR) & SR_TXRDY)) { diff --git a/trunk/drivers/serial/serial_core.c b/trunk/drivers/serial/serial_core.c index 2514d00c0f6f..b0bb29d804ae 100644 --- a/trunk/drivers/serial/serial_core.c +++ b/trunk/drivers/serial/serial_core.c @@ -29,10 +29,10 @@ #include #include #include +#include #include #include #include /* for serial_state and serial_icounter_struct */ -#include #include #include @@ -52,6 +52,8 @@ static struct lock_class_key port_lock_key; #define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) +#define uart_users(state) ((state)->count + (state)->info.port.blocked_open) + #ifdef CONFIG_SERIAL_CORE_CONSOLE #define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line) #else @@ -69,19 +71,19 @@ static void uart_change_pm(struct uart_state *state, int pm_state); */ void uart_write_wakeup(struct uart_port *port) { - struct uart_state *state = port->state; + struct uart_info *info = port->info; /* * This means you called this function _after_ the port was * closed. No cookie for you. */ - BUG_ON(!state); - tasklet_schedule(&state->tlet); + BUG_ON(!info); + tasklet_schedule(&info->tlet); } static void uart_stop(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; - struct uart_port *port = state->uart_port; + struct uart_port *port = state->port; unsigned long flags; spin_lock_irqsave(&port->lock, flags); @@ -92,9 +94,9 @@ static void uart_stop(struct tty_struct *tty) static void __uart_start(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; - struct uart_port *port = state->uart_port; + struct uart_port *port = state->port; - if (!uart_circ_empty(&state->xmit) && state->xmit.buf && + if (!uart_circ_empty(&state->info.xmit) && state->info.xmit.buf && !tty->stopped && !tty->hw_stopped) port->ops->start_tx(port); } @@ -102,7 +104,7 @@ static void __uart_start(struct tty_struct *tty) static void uart_start(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; - struct uart_port *port = state->uart_port; + struct uart_port *port = state->port; unsigned long flags; spin_lock_irqsave(&port->lock, flags); @@ -113,7 +115,7 @@ static void uart_start(struct tty_struct *tty) static void uart_tasklet_action(unsigned long data) { struct uart_state *state = (struct uart_state *)data; - tty_wakeup(state->port.tty); + tty_wakeup(state->info.port.tty); } static inline void @@ -139,12 +141,12 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear) */ static int uart_startup(struct uart_state *state, int init_hw) { - struct uart_port *uport = state->uart_port; - struct tty_port *port = &state->port; + struct uart_info *info = &state->info; + struct uart_port *port = state->port; unsigned long page; int retval = 0; - if (port->flags & ASYNC_INITIALIZED) + if (info->flags & UIF_INITIALIZED) return 0; /* @@ -152,26 +154,26 @@ static int uart_startup(struct uart_state *state, int init_hw) * once we have successfully opened the port. Also set * up the tty->alt_speed kludge */ - set_bit(TTY_IO_ERROR, &port->tty->flags); + set_bit(TTY_IO_ERROR, &info->port.tty->flags); - if (uport->type == PORT_UNKNOWN) + if (port->type == PORT_UNKNOWN) return 0; /* * Initialise and allocate the transmit and temporary * buffer. */ - if (!state->xmit.buf) { + if (!info->xmit.buf) { /* This is protected by the per port mutex */ page = get_zeroed_page(GFP_KERNEL); if (!page) return -ENOMEM; - state->xmit.buf = (unsigned char *) page; - uart_circ_clear(&state->xmit); + info->xmit.buf = (unsigned char *) page; + uart_circ_clear(&info->xmit); } - retval = uport->ops->startup(uport); + retval = port->ops->startup(port); if (retval == 0) { if (init_hw) { /* @@ -183,20 +185,20 @@ static int uart_startup(struct uart_state *state, int init_hw) * Setup the RTS and DTR signals once the * port is open and ready to respond. */ - if (port->tty->termios->c_cflag & CBAUD) - uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR); + if (info->port.tty->termios->c_cflag & CBAUD) + uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR); } - if (port->flags & ASYNC_CTS_FLOW) { - spin_lock_irq(&uport->lock); - if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) - port->tty->hw_stopped = 1; - spin_unlock_irq(&uport->lock); + if (info->flags & UIF_CTS_FLOW) { + spin_lock_irq(&port->lock); + if (!(port->ops->get_mctrl(port) & TIOCM_CTS)) + info->port.tty->hw_stopped = 1; + spin_unlock_irq(&port->lock); } - set_bit(ASYNCB_INITIALIZED, &port->flags); + info->flags |= UIF_INITIALIZED; - clear_bit(TTY_IO_ERROR, &port->tty->flags); + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); } if (retval && capable(CAP_SYS_ADMIN)) @@ -212,9 +214,9 @@ static int uart_startup(struct uart_state *state, int init_hw) */ static void uart_shutdown(struct uart_state *state) { - struct uart_port *uport = state->uart_port; - struct tty_port *port = &state->port; - struct tty_struct *tty = port->tty; + struct uart_info *info = &state->info; + struct uart_port *port = state->port; + struct tty_struct *tty = info->port.tty; /* * Set the TTY IO error marker @@ -222,12 +224,14 @@ static void uart_shutdown(struct uart_state *state) if (tty) set_bit(TTY_IO_ERROR, &tty->flags); - if (test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) { + if (info->flags & UIF_INITIALIZED) { + info->flags &= ~UIF_INITIALIZED; + /* * Turn off DTR and RTS early. */ if (!tty || (tty->termios->c_cflag & HUPCL)) - uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); + uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); /* * clear delta_msr_wait queue to avoid mem leaks: we may free @@ -236,30 +240,30 @@ static void uart_shutdown(struct uart_state *state) * any outstanding file descriptors should be pointing at * hung_up_tty_fops now. */ - wake_up_interruptible(&port->delta_msr_wait); + wake_up_interruptible(&info->delta_msr_wait); /* * Free the IRQ and disable the port. */ - uport->ops->shutdown(uport); + port->ops->shutdown(port); /* * Ensure that the IRQ handler isn't running on another CPU. */ - synchronize_irq(uport->irq); + synchronize_irq(port->irq); } /* * kill off our tasklet */ - tasklet_kill(&state->tlet); + tasklet_kill(&info->tlet); /* * Free the transmit buffer page. */ - if (state->xmit.buf) { - free_page((unsigned long)state->xmit.buf); - state->xmit.buf = NULL; + if (info->xmit.buf) { + free_page((unsigned long)info->xmit.buf); + info->xmit.buf = NULL; } } @@ -426,16 +430,15 @@ EXPORT_SYMBOL(uart_get_divisor); static void uart_change_speed(struct uart_state *state, struct ktermios *old_termios) { - struct tty_port *port = &state->port; - struct tty_struct *tty = port->tty; - struct uart_port *uport = state->uart_port; + struct tty_struct *tty = state->info.port.tty; + struct uart_port *port = state->port; struct ktermios *termios; /* * If we have no tty, termios, or the port does not exist, * then we can't set the parameters for this port. */ - if (!tty || !tty->termios || uport->type == PORT_UNKNOWN) + if (!tty || !tty->termios || port->type == PORT_UNKNOWN) return; termios = tty->termios; @@ -444,16 +447,16 @@ uart_change_speed(struct uart_state *state, struct ktermios *old_termios) * Set flags based on termios cflag */ if (termios->c_cflag & CRTSCTS) - set_bit(ASYNCB_CTS_FLOW, &port->flags); + state->info.flags |= UIF_CTS_FLOW; else - clear_bit(ASYNCB_CTS_FLOW, &port->flags); + state->info.flags &= ~UIF_CTS_FLOW; if (termios->c_cflag & CLOCAL) - clear_bit(ASYNCB_CHECK_CD, &port->flags); + state->info.flags &= ~UIF_CHECK_CD; else - set_bit(ASYNCB_CHECK_CD, &port->flags); + state->info.flags |= UIF_CHECK_CD; - uport->ops->set_termios(uport, termios, old_termios); + port->ops->set_termios(port, termios, old_termios); } static inline int @@ -479,7 +482,7 @@ static int uart_put_char(struct tty_struct *tty, unsigned char ch) { struct uart_state *state = tty->driver_data; - return __uart_put_char(state->uart_port, &state->xmit, ch); + return __uart_put_char(state->port, &state->info.xmit, ch); } static void uart_flush_chars(struct tty_struct *tty) @@ -505,8 +508,8 @@ uart_write(struct tty_struct *tty, const unsigned char *buf, int count) return -EL3HLT; } - port = state->uart_port; - circ = &state->xmit; + port = state->port; + circ = &state->info.xmit; if (!circ->buf) return 0; @@ -536,9 +539,9 @@ static int uart_write_room(struct tty_struct *tty) unsigned long flags; int ret; - spin_lock_irqsave(&state->uart_port->lock, flags); - ret = uart_circ_chars_free(&state->xmit); - spin_unlock_irqrestore(&state->uart_port->lock, flags); + spin_lock_irqsave(&state->port->lock, flags); + ret = uart_circ_chars_free(&state->info.xmit); + spin_unlock_irqrestore(&state->port->lock, flags); return ret; } @@ -548,9 +551,9 @@ static int uart_chars_in_buffer(struct tty_struct *tty) unsigned long flags; int ret; - spin_lock_irqsave(&state->uart_port->lock, flags); - ret = uart_circ_chars_pending(&state->xmit); - spin_unlock_irqrestore(&state->uart_port->lock, flags); + spin_lock_irqsave(&state->port->lock, flags); + ret = uart_circ_chars_pending(&state->info.xmit); + spin_unlock_irqrestore(&state->port->lock, flags); return ret; } @@ -569,11 +572,11 @@ static void uart_flush_buffer(struct tty_struct *tty) return; } - port = state->uart_port; + port = state->port; pr_debug("uart_flush_buffer(%d) called\n", tty->index); spin_lock_irqsave(&port->lock, flags); - uart_circ_clear(&state->xmit); + uart_circ_clear(&state->info.xmit); if (port->ops->flush_buffer) port->ops->flush_buffer(port); spin_unlock_irqrestore(&port->lock, flags); @@ -587,7 +590,7 @@ static void uart_flush_buffer(struct tty_struct *tty) static void uart_send_xchar(struct tty_struct *tty, char ch) { struct uart_state *state = tty->driver_data; - struct uart_port *port = state->uart_port; + struct uart_port *port = state->port; unsigned long flags; if (port->ops->send_xchar) @@ -610,13 +613,13 @@ static void uart_throttle(struct tty_struct *tty) uart_send_xchar(tty, STOP_CHAR(tty)); if (tty->termios->c_cflag & CRTSCTS) - uart_clear_mctrl(state->uart_port, TIOCM_RTS); + uart_clear_mctrl(state->port, TIOCM_RTS); } static void uart_unthrottle(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; - struct uart_port *port = state->uart_port; + struct uart_port *port = state->port; if (I_IXOFF(tty)) { if (port->x_char) @@ -632,36 +635,35 @@ static void uart_unthrottle(struct tty_struct *tty) static int uart_get_info(struct uart_state *state, struct serial_struct __user *retinfo) { - struct uart_port *uport = state->uart_port; - struct tty_port *port = &state->port; + struct uart_port *port = state->port; struct serial_struct tmp; memset(&tmp, 0, sizeof(tmp)); /* Ensure the state we copy is consistent and no hardware changes occur as we go */ - mutex_lock(&port->mutex); + mutex_lock(&state->mutex); - tmp.type = uport->type; - tmp.line = uport->line; - tmp.port = uport->iobase; + tmp.type = port->type; + tmp.line = port->line; + tmp.port = port->iobase; if (HIGH_BITS_OFFSET) - tmp.port_high = (long) uport->iobase >> HIGH_BITS_OFFSET; - tmp.irq = uport->irq; - tmp.flags = uport->flags; - tmp.xmit_fifo_size = uport->fifosize; - tmp.baud_base = uport->uartclk / 16; - tmp.close_delay = port->close_delay / 10; - tmp.closing_wait = port->closing_wait == ASYNC_CLOSING_WAIT_NONE ? + tmp.port_high = (long) port->iobase >> HIGH_BITS_OFFSET; + tmp.irq = port->irq; + tmp.flags = port->flags; + tmp.xmit_fifo_size = port->fifosize; + tmp.baud_base = port->uartclk / 16; + tmp.close_delay = state->close_delay / 10; + tmp.closing_wait = state->closing_wait == USF_CLOSING_WAIT_NONE ? ASYNC_CLOSING_WAIT_NONE : - port->closing_wait / 10; - tmp.custom_divisor = uport->custom_divisor; - tmp.hub6 = uport->hub6; - tmp.io_type = uport->iotype; - tmp.iomem_reg_shift = uport->regshift; - tmp.iomem_base = (void *)(unsigned long)uport->mapbase; + state->closing_wait / 10; + tmp.custom_divisor = port->custom_divisor; + tmp.hub6 = port->hub6; + tmp.io_type = port->iotype; + tmp.iomem_reg_shift = port->regshift; + tmp.iomem_base = (void *)(unsigned long)port->mapbase; - mutex_unlock(&port->mutex); + mutex_unlock(&state->mutex); if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) return -EFAULT; @@ -672,8 +674,7 @@ static int uart_set_info(struct uart_state *state, struct serial_struct __user *newinfo) { struct serial_struct new_serial; - struct uart_port *uport = state->uart_port; - struct tty_port *port = &state->port; + struct uart_port *port = state->port; unsigned long new_port; unsigned int change_irq, change_port, closing_wait; unsigned int old_custom_divisor, close_delay; @@ -690,58 +691,58 @@ static int uart_set_info(struct uart_state *state, new_serial.irq = irq_canonicalize(new_serial.irq); close_delay = new_serial.close_delay * 10; closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? - ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; + USF_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; /* - * This semaphore protects port->count. It is also + * This semaphore protects state->count. It is also * very useful to prevent opens. Also, take the * port configuration semaphore to make sure that a * module insertion/removal doesn't change anything * under us. */ - mutex_lock(&port->mutex); + mutex_lock(&state->mutex); - change_irq = !(uport->flags & UPF_FIXED_PORT) - && new_serial.irq != uport->irq; + change_irq = !(port->flags & UPF_FIXED_PORT) + && new_serial.irq != port->irq; /* * Since changing the 'type' of the port changes its resource * allocations, we should treat type changes the same as * IO port changes. */ - change_port = !(uport->flags & UPF_FIXED_PORT) - && (new_port != uport->iobase || - (unsigned long)new_serial.iomem_base != uport->mapbase || - new_serial.hub6 != uport->hub6 || - new_serial.io_type != uport->iotype || - new_serial.iomem_reg_shift != uport->regshift || - new_serial.type != uport->type); - - old_flags = uport->flags; + change_port = !(port->flags & UPF_FIXED_PORT) + && (new_port != port->iobase || + (unsigned long)new_serial.iomem_base != port->mapbase || + new_serial.hub6 != port->hub6 || + new_serial.io_type != port->iotype || + new_serial.iomem_reg_shift != port->regshift || + new_serial.type != port->type); + + old_flags = port->flags; new_flags = new_serial.flags; - old_custom_divisor = uport->custom_divisor; + old_custom_divisor = port->custom_divisor; if (!capable(CAP_SYS_ADMIN)) { retval = -EPERM; if (change_irq || change_port || - (new_serial.baud_base != uport->uartclk / 16) || - (close_delay != port->close_delay) || - (closing_wait != port->closing_wait) || + (new_serial.baud_base != port->uartclk / 16) || + (close_delay != state->close_delay) || + (closing_wait != state->closing_wait) || (new_serial.xmit_fifo_size && - new_serial.xmit_fifo_size != uport->fifosize) || + new_serial.xmit_fifo_size != port->fifosize) || (((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0)) goto exit; - uport->flags = ((uport->flags & ~UPF_USR_MASK) | + port->flags = ((port->flags & ~UPF_USR_MASK) | (new_flags & UPF_USR_MASK)); - uport->custom_divisor = new_serial.custom_divisor; + port->custom_divisor = new_serial.custom_divisor; goto check_and_exit; } /* * Ask the low level driver to verify the settings. */ - if (uport->ops->verify_port) - retval = uport->ops->verify_port(uport, &new_serial); + if (port->ops->verify_port) + retval = port->ops->verify_port(port, &new_serial); if ((new_serial.irq >= nr_irqs) || (new_serial.irq < 0) || (new_serial.baud_base < 9600)) @@ -756,7 +757,7 @@ static int uart_set_info(struct uart_state *state, /* * Make sure that we are the sole user of this port. */ - if (tty_port_users(port) > 1) + if (uart_users(state) > 1) goto exit; /* @@ -770,31 +771,31 @@ static int uart_set_info(struct uart_state *state, unsigned long old_iobase, old_mapbase; unsigned int old_type, old_iotype, old_hub6, old_shift; - old_iobase = uport->iobase; - old_mapbase = uport->mapbase; - old_type = uport->type; - old_hub6 = uport->hub6; - old_iotype = uport->iotype; - old_shift = uport->regshift; + old_iobase = port->iobase; + old_mapbase = port->mapbase; + old_type = port->type; + old_hub6 = port->hub6; + old_iotype = port->iotype; + old_shift = port->regshift; /* * Free and release old regions */ if (old_type != PORT_UNKNOWN) - uport->ops->release_port(uport); + port->ops->release_port(port); - uport->iobase = new_port; - uport->type = new_serial.type; - uport->hub6 = new_serial.hub6; - uport->iotype = new_serial.io_type; - uport->regshift = new_serial.iomem_reg_shift; - uport->mapbase = (unsigned long)new_serial.iomem_base; + port->iobase = new_port; + port->type = new_serial.type; + port->hub6 = new_serial.hub6; + port->iotype = new_serial.io_type; + port->regshift = new_serial.iomem_reg_shift; + port->mapbase = (unsigned long)new_serial.iomem_base; /* * Claim and map the new regions */ - if (uport->type != PORT_UNKNOWN) { - retval = uport->ops->request_port(uport); + if (port->type != PORT_UNKNOWN) { + retval = port->ops->request_port(port); } else { /* Always success - Jean II */ retval = 0; @@ -805,19 +806,19 @@ static int uart_set_info(struct uart_state *state, * new port, try to restore the old settings. */ if (retval && old_type != PORT_UNKNOWN) { - uport->iobase = old_iobase; - uport->type = old_type; - uport->hub6 = old_hub6; - uport->iotype = old_iotype; - uport->regshift = old_shift; - uport->mapbase = old_mapbase; - retval = uport->ops->request_port(uport); + port->iobase = old_iobase; + port->type = old_type; + port->hub6 = old_hub6; + port->iotype = old_iotype; + port->regshift = old_shift; + port->mapbase = old_mapbase; + retval = port->ops->request_port(port); /* * If we failed to restore the old settings, * we fail like this. */ if (retval) - uport->type = PORT_UNKNOWN; + port->type = PORT_UNKNOWN; /* * We failed anyway. @@ -829,45 +830,45 @@ static int uart_set_info(struct uart_state *state, } if (change_irq) - uport->irq = new_serial.irq; - if (!(uport->flags & UPF_FIXED_PORT)) - uport->uartclk = new_serial.baud_base * 16; - uport->flags = (uport->flags & ~UPF_CHANGE_MASK) | + port->irq = new_serial.irq; + if (!(port->flags & UPF_FIXED_PORT)) + port->uartclk = new_serial.baud_base * 16; + port->flags = (port->flags & ~UPF_CHANGE_MASK) | (new_flags & UPF_CHANGE_MASK); - uport->custom_divisor = new_serial.custom_divisor; - port->close_delay = close_delay; - port->closing_wait = closing_wait; + port->custom_divisor = new_serial.custom_divisor; + state->close_delay = close_delay; + state->closing_wait = closing_wait; if (new_serial.xmit_fifo_size) - uport->fifosize = new_serial.xmit_fifo_size; - if (port->tty) - port->tty->low_latency = - (uport->flags & UPF_LOW_LATENCY) ? 1 : 0; + port->fifosize = new_serial.xmit_fifo_size; + if (state->info.port.tty) + state->info.port.tty->low_latency = + (port->flags & UPF_LOW_LATENCY) ? 1 : 0; check_and_exit: retval = 0; - if (uport->type == PORT_UNKNOWN) + if (port->type == PORT_UNKNOWN) goto exit; - if (port->flags & ASYNC_INITIALIZED) { - if (((old_flags ^ uport->flags) & UPF_SPD_MASK) || - old_custom_divisor != uport->custom_divisor) { + if (state->info.flags & UIF_INITIALIZED) { + if (((old_flags ^ port->flags) & UPF_SPD_MASK) || + old_custom_divisor != port->custom_divisor) { /* * If they're setting up a custom divisor or speed, * instead of clearing it, then bitch about it. No * need to rate-limit; it's CAP_SYS_ADMIN only. */ - if (uport->flags & UPF_SPD_MASK) { + if (port->flags & UPF_SPD_MASK) { char buf[64]; printk(KERN_NOTICE "%s sets custom speed on %s. This " "is deprecated.\n", current->comm, - tty_name(port->tty, buf)); + tty_name(state->info.port.tty, buf)); } uart_change_speed(state, NULL); } } else retval = uart_startup(state, 1); exit: - mutex_unlock(&port->mutex); + mutex_unlock(&state->mutex); return retval; } @@ -879,11 +880,10 @@ static int uart_set_info(struct uart_state *state, static int uart_get_lsr_info(struct uart_state *state, unsigned int __user *value) { - struct uart_port *uport = state->uart_port; - struct tty_port *port = &state->port; + struct uart_port *port = state->port; unsigned int result; - result = uport->ops->tx_empty(uport); + result = port->ops->tx_empty(port); /* * If we're about to load something into the transmit @@ -891,9 +891,9 @@ static int uart_get_lsr_info(struct uart_state *state, * avoid a race condition (depending on when the transmit * interrupt happens). */ - if (uport->x_char || - ((uart_circ_chars_pending(&state->xmit) > 0) && - !port->tty->stopped && !port->tty->hw_stopped)) + if (port->x_char || + ((uart_circ_chars_pending(&state->info.xmit) > 0) && + !state->info.port.tty->stopped && !state->info.port.tty->hw_stopped)) result &= ~TIOCSER_TEMT; return put_user(result, value); @@ -902,20 +902,19 @@ static int uart_get_lsr_info(struct uart_state *state, static int uart_tiocmget(struct tty_struct *tty, struct file *file) { struct uart_state *state = tty->driver_data; - struct tty_port *port = &state->port; - struct uart_port *uport = state->uart_port; + struct uart_port *port = state->port; int result = -EIO; - mutex_lock(&port->mutex); + mutex_lock(&state->mutex); if ((!file || !tty_hung_up_p(file)) && !(tty->flags & (1 << TTY_IO_ERROR))) { - result = uport->mctrl; + result = port->mctrl; - spin_lock_irq(&uport->lock); - result |= uport->ops->get_mctrl(uport); - spin_unlock_irq(&uport->lock); + spin_lock_irq(&port->lock); + result |= port->ops->get_mctrl(port); + spin_unlock_irq(&port->lock); } - mutex_unlock(&port->mutex); + mutex_unlock(&state->mutex); return result; } @@ -925,39 +924,36 @@ uart_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { struct uart_state *state = tty->driver_data; - struct uart_port *uport = state->uart_port; - struct tty_port *port = &state->port; + struct uart_port *port = state->port; int ret = -EIO; - mutex_lock(&port->mutex); + mutex_lock(&state->mutex); if ((!file || !tty_hung_up_p(file)) && !(tty->flags & (1 << TTY_IO_ERROR))) { - uart_update_mctrl(uport, set, clear); + uart_update_mctrl(port, set, clear); ret = 0; } - mutex_unlock(&port->mutex); + mutex_unlock(&state->mutex); return ret; } static int uart_break_ctl(struct tty_struct *tty, int break_state) { struct uart_state *state = tty->driver_data; - struct tty_port *port = &state->port; - struct uart_port *uport = state->uart_port; + struct uart_port *port = state->port; - mutex_lock(&port->mutex); + mutex_lock(&state->mutex); - if (uport->type != PORT_UNKNOWN) - uport->ops->break_ctl(uport, break_state); + if (port->type != PORT_UNKNOWN) + port->ops->break_ctl(port, break_state); - mutex_unlock(&port->mutex); + mutex_unlock(&state->mutex); return 0; } static int uart_do_autoconfig(struct uart_state *state) { - struct uart_port *uport = state->uart_port; - struct tty_port *port = &state->port; + struct uart_port *port = state->port; int flags, ret; if (!capable(CAP_SYS_ADMIN)) @@ -968,33 +964,33 @@ static int uart_do_autoconfig(struct uart_state *state) * changing, and hence any extra opens of the port while * we're auto-configuring. */ - if (mutex_lock_interruptible(&port->mutex)) + if (mutex_lock_interruptible(&state->mutex)) return -ERESTARTSYS; ret = -EBUSY; - if (tty_port_users(port) == 1) { + if (uart_users(state) == 1) { uart_shutdown(state); /* * If we already have a port type configured, * we must release its resources. */ - if (uport->type != PORT_UNKNOWN) - uport->ops->release_port(uport); + if (port->type != PORT_UNKNOWN) + port->ops->release_port(port); flags = UART_CONFIG_TYPE; - if (uport->flags & UPF_AUTO_IRQ) + if (port->flags & UPF_AUTO_IRQ) flags |= UART_CONFIG_IRQ; /* * This will claim the ports resources if * a port is found. */ - uport->ops->config_port(uport, flags); + port->ops->config_port(port, flags); ret = uart_startup(state, 1); } - mutex_unlock(&port->mutex); + mutex_unlock(&state->mutex); return ret; } @@ -1003,15 +999,11 @@ static int uart_do_autoconfig(struct uart_state *state) * - mask passed in arg for lines of interest * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) * Caller should use TIOCGICOUNT to see which one it was - * - * FIXME: This wants extracting into a common all driver implementation - * of TIOCMWAIT using tty_port. */ static int uart_wait_modem_status(struct uart_state *state, unsigned long arg) { - struct uart_port *uport = state->uart_port; - struct tty_port *port = &state->port; + struct uart_port *port = state->port; DECLARE_WAITQUEUE(wait, current); struct uart_icount cprev, cnow; int ret; @@ -1019,20 +1011,20 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg) /* * note the counters on entry */ - spin_lock_irq(&uport->lock); - memcpy(&cprev, &uport->icount, sizeof(struct uart_icount)); + spin_lock_irq(&port->lock); + memcpy(&cprev, &port->icount, sizeof(struct uart_icount)); /* * Force modem status interrupts on */ - uport->ops->enable_ms(uport); - spin_unlock_irq(&uport->lock); + port->ops->enable_ms(port); + spin_unlock_irq(&port->lock); - add_wait_queue(&port->delta_msr_wait, &wait); + add_wait_queue(&state->info.delta_msr_wait, &wait); for (;;) { - spin_lock_irq(&uport->lock); - memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); - spin_unlock_irq(&uport->lock); + spin_lock_irq(&port->lock); + memcpy(&cnow, &port->icount, sizeof(struct uart_icount)); + spin_unlock_irq(&port->lock); set_current_state(TASK_INTERRUPTIBLE); @@ -1056,7 +1048,7 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg) } current->state = TASK_RUNNING; - remove_wait_queue(&port->delta_msr_wait, &wait); + remove_wait_queue(&state->info.delta_msr_wait, &wait); return ret; } @@ -1072,11 +1064,11 @@ static int uart_get_count(struct uart_state *state, { struct serial_icounter_struct icount; struct uart_icount cnow; - struct uart_port *uport = state->uart_port; + struct uart_port *port = state->port; - spin_lock_irq(&uport->lock); - memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); - spin_unlock_irq(&uport->lock); + spin_lock_irq(&port->lock); + memcpy(&cnow, &port->icount, sizeof(struct uart_icount)); + spin_unlock_irq(&port->lock); icount.cts = cnow.cts; icount.dsr = cnow.dsr; @@ -1101,7 +1093,6 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, unsigned long arg) { struct uart_state *state = tty->driver_data; - struct tty_port *port = &state->port; void __user *uarg = (void __user *)arg; int ret = -ENOIOCTLCMD; @@ -1152,7 +1143,7 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, if (ret != -ENOIOCTLCMD) goto out; - mutex_lock(&port->mutex); + mutex_lock(&state->mutex); if (tty_hung_up_p(filp)) { ret = -EIO; @@ -1169,14 +1160,14 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, break; default: { - struct uart_port *uport = state->uart_port; - if (uport->ops->ioctl) - ret = uport->ops->ioctl(uport, cmd, arg); + struct uart_port *port = state->port; + if (port->ops->ioctl) + ret = port->ops->ioctl(port, cmd, arg); break; } } out_up: - mutex_unlock(&port->mutex); + mutex_unlock(&state->mutex); out: return ret; } @@ -1184,10 +1175,10 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, static void uart_set_ldisc(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; - struct uart_port *uport = state->uart_port; + struct uart_port *port = state->port; - if (uport->ops->set_ldisc) - uport->ops->set_ldisc(uport); + if (port->ops->set_ldisc) + port->ops->set_ldisc(port); } static void uart_set_termios(struct tty_struct *tty, @@ -1216,7 +1207,7 @@ static void uart_set_termios(struct tty_struct *tty, /* Handle transition to B0 status */ if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) - uart_clear_mctrl(state->uart_port, TIOCM_RTS | TIOCM_DTR); + uart_clear_mctrl(state->port, TIOCM_RTS | TIOCM_DTR); /* Handle transition away from B0 status */ if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { @@ -1224,25 +1215,25 @@ static void uart_set_termios(struct tty_struct *tty, if (!(cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) mask |= TIOCM_RTS; - uart_set_mctrl(state->uart_port, mask); + uart_set_mctrl(state->port, mask); } /* Handle turning off CRTSCTS */ if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) { - spin_lock_irqsave(&state->uart_port->lock, flags); + spin_lock_irqsave(&state->port->lock, flags); tty->hw_stopped = 0; __uart_start(tty); - spin_unlock_irqrestore(&state->uart_port->lock, flags); + spin_unlock_irqrestore(&state->port->lock, flags); } /* Handle turning on CRTSCTS */ if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) { - spin_lock_irqsave(&state->uart_port->lock, flags); - if (!(state->uart_port->ops->get_mctrl(state->uart_port) & TIOCM_CTS)) { + spin_lock_irqsave(&state->port->lock, flags); + if (!(state->port->ops->get_mctrl(state->port) & TIOCM_CTS)) { tty->hw_stopped = 1; - state->uart_port->ops->stop_tx(state->uart_port); + state->port->ops->stop_tx(state->port); } - spin_unlock_irqrestore(&state->uart_port->lock, flags); + spin_unlock_irqrestore(&state->port->lock, flags); } #if 0 /* @@ -1253,7 +1244,7 @@ static void uart_set_termios(struct tty_struct *tty, */ if (!(old_termios->c_cflag & CLOCAL) && (tty->termios->c_cflag & CLOCAL)) - wake_up_interruptible(&state->uart_port.open_wait); + wake_up_interruptible(&info->port.open_wait); #endif } @@ -1265,39 +1256,40 @@ static void uart_set_termios(struct tty_struct *tty, static void uart_close(struct tty_struct *tty, struct file *filp) { struct uart_state *state = tty->driver_data; - struct tty_port *port; - struct uart_port *uport; + struct uart_port *port; BUG_ON(!kernel_locked()); - uport = state->uart_port; - port = &state->port; + if (!state || !state->port) + return; - pr_debug("uart_close(%d) called\n", uport->line); + port = state->port; - mutex_lock(&port->mutex); + pr_debug("uart_close(%d) called\n", port->line); + + mutex_lock(&state->mutex); if (tty_hung_up_p(filp)) goto done; - if ((tty->count == 1) && (port->count != 1)) { + if ((tty->count == 1) && (state->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. port->count should always + * structure will be freed. state->count should always * be one in these conditions. If it's greater than * one, we've got real problems, since it means the * serial port won't be shutdown. */ printk(KERN_ERR "uart_close: bad serial port count; tty->count is 1, " - "port->count is %d\n", port->count); - port->count = 1; + "state->count is %d\n", state->count); + state->count = 1; } - if (--port->count < 0) { + if (--state->count < 0) { printk(KERN_ERR "uart_close: bad serial port count for %s: %d\n", - tty->name, port->count); - port->count = 0; + tty->name, state->count); + state->count = 0; } - if (port->count) + if (state->count) goto done; /* @@ -1307,24 +1299,24 @@ static void uart_close(struct tty_struct *tty, struct file *filp) */ tty->closing = 1; - if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, msecs_to_jiffies(port->closing_wait)); + if (state->closing_wait != USF_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, msecs_to_jiffies(state->closing_wait)); /* * At this point, we stop accepting input. To do this, we * disable the receive line status interrupts. */ - if (port->flags & ASYNC_INITIALIZED) { + if (state->info.flags & UIF_INITIALIZED) { unsigned long flags; spin_lock_irqsave(&port->lock, flags); - uport->ops->stop_rx(uport); + port->ops->stop_rx(port); spin_unlock_irqrestore(&port->lock, flags); /* * Before we drop DTR, make sure the UART transmitter * has completely drained; this is especially * important if there is a transmit FIFO! */ - uart_wait_until_sent(tty, uport->timeout); + uart_wait_until_sent(tty, port->timeout); } uart_shutdown(state); @@ -1333,29 +1325,29 @@ static void uart_close(struct tty_struct *tty, struct file *filp) tty_ldisc_flush(tty); tty->closing = 0; - tty_port_tty_set(port, NULL); + state->info.port.tty = NULL; - if (port->blocked_open) { - if (port->close_delay) - msleep_interruptible(port->close_delay); - } else if (!uart_console(uport)) { + if (state->info.port.blocked_open) { + if (state->close_delay) + msleep_interruptible(state->close_delay); + } else if (!uart_console(port)) { uart_change_pm(state, 3); } /* * Wake up anyone trying to open this port. */ - clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); - wake_up_interruptible(&port->open_wait); + state->info.flags &= ~UIF_NORMAL_ACTIVE; + wake_up_interruptible(&state->info.port.open_wait); -done: - mutex_unlock(&port->mutex); + done: + mutex_unlock(&state->mutex); } static void uart_wait_until_sent(struct tty_struct *tty, int timeout) { struct uart_state *state = tty->driver_data; - struct uart_port *port = state->uart_port; + struct uart_port *port = state->port; unsigned long char_time, expire; if (port->type == PORT_UNKNOWN || port->fifosize == 0) @@ -1420,22 +1412,22 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout) static void uart_hangup(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; - struct tty_port *port = &state->port; + struct uart_info *info = &state->info; BUG_ON(!kernel_locked()); - pr_debug("uart_hangup(%d)\n", state->uart_port->line); + pr_debug("uart_hangup(%d)\n", state->port->line); - mutex_lock(&port->mutex); - if (port->flags & ASYNC_NORMAL_ACTIVE) { + mutex_lock(&state->mutex); + if (info->flags & UIF_NORMAL_ACTIVE) { uart_flush_buffer(tty); uart_shutdown(state); - port->count = 0; - clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); - tty_port_tty_set(port, NULL); - wake_up_interruptible(&port->open_wait); - wake_up_interruptible(&port->delta_msr_wait); + state->count = 0; + info->flags &= ~UIF_NORMAL_ACTIVE; + info->port.tty = NULL; + wake_up_interruptible(&info->port.open_wait); + wake_up_interruptible(&info->delta_msr_wait); } - mutex_unlock(&port->mutex); + mutex_unlock(&state->mutex); } /* @@ -1446,8 +1438,8 @@ static void uart_hangup(struct tty_struct *tty) */ static void uart_update_termios(struct uart_state *state) { - struct tty_struct *tty = state->port.tty; - struct uart_port *port = state->uart_port; + struct tty_struct *tty = state->info.port.tty; + struct uart_port *port = state->port; if (uart_console(port) && port->cons->cflag) { tty->termios->c_cflag = port->cons->cflag; @@ -1481,27 +1473,27 @@ static int uart_block_til_ready(struct file *filp, struct uart_state *state) { DECLARE_WAITQUEUE(wait, current); - struct uart_port *uport = state->uart_port; - struct tty_port *port = &state->port; + struct uart_info *info = &state->info; + struct uart_port *port = state->port; unsigned int mctrl; - port->blocked_open++; - port->count--; + info->port.blocked_open++; + state->count--; - add_wait_queue(&port->open_wait, &wait); + add_wait_queue(&info->port.open_wait, &wait); while (1) { set_current_state(TASK_INTERRUPTIBLE); /* * If we have been hung up, tell userspace/restart open. */ - if (tty_hung_up_p(filp) || port->tty == NULL) + if (tty_hung_up_p(filp) || info->port.tty == NULL) break; /* * If the port has been closed, tell userspace/restart open. */ - if (!(port->flags & ASYNC_INITIALIZED)) + if (!(info->flags & UIF_INITIALIZED)) break; /* @@ -1514,8 +1506,8 @@ 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) || - (port->tty->termios->c_cflag & CLOCAL) || - (port->tty->flags & (1 << TTY_IO_ERROR))) + (info->port.tty->termios->c_cflag & CLOCAL) || + (info->port.tty->flags & (1 << TTY_IO_ERROR))) break; /* @@ -1523,37 +1515,37 @@ uart_block_til_ready(struct file *filp, struct uart_state *state) * not set RTS here - we want to make sure we catch * the data from the modem. */ - if (port->tty->termios->c_cflag & CBAUD) - uart_set_mctrl(uport, TIOCM_DTR); + if (info->port.tty->termios->c_cflag & CBAUD) + uart_set_mctrl(port, TIOCM_DTR); /* * and wait for the carrier to indicate that the * modem is ready for us. */ - spin_lock_irq(&uport->lock); - uport->ops->enable_ms(uport); - mctrl = uport->ops->get_mctrl(uport); - spin_unlock_irq(&uport->lock); + spin_lock_irq(&port->lock); + port->ops->enable_ms(port); + mctrl = port->ops->get_mctrl(port); + spin_unlock_irq(&port->lock); if (mctrl & TIOCM_CAR) break; - mutex_unlock(&port->mutex); + mutex_unlock(&state->mutex); schedule(); - mutex_lock(&port->mutex); + mutex_lock(&state->mutex); if (signal_pending(current)) break; } set_current_state(TASK_RUNNING); - remove_wait_queue(&port->open_wait, &wait); + remove_wait_queue(&info->port.open_wait, &wait); - port->count++; - port->blocked_open--; + state->count++; + info->port.blocked_open--; if (signal_pending(current)) return -ERESTARTSYS; - if (!port->tty || tty_hung_up_p(filp)) + if (!info->port.tty || tty_hung_up_p(filp)) return -EAGAIN; return 0; @@ -1562,26 +1554,24 @@ uart_block_til_ready(struct file *filp, struct uart_state *state) static struct uart_state *uart_get(struct uart_driver *drv, int line) { struct uart_state *state; - struct tty_port *port; int ret = 0; state = drv->state + line; - port = &state->port; - if (mutex_lock_interruptible(&port->mutex)) { + if (mutex_lock_interruptible(&state->mutex)) { ret = -ERESTARTSYS; goto err; } - port->count++; - if (!state->uart_port || state->uart_port->flags & UPF_DEAD) { + state->count++; + if (!state->port || state->port->flags & UPF_DEAD) { ret = -ENXIO; goto err_unlock; } return state; err_unlock: - port->count--; - mutex_unlock(&port->mutex); + state->count--; + mutex_unlock(&state->mutex); err: return ERR_PTR(ret); } @@ -1600,7 +1590,6 @@ static int uart_open(struct tty_struct *tty, struct file *filp) { struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state; struct uart_state *state; - struct tty_port *port; int retval, line = tty->index; BUG_ON(!kernel_locked()); @@ -1617,18 +1606,16 @@ static int uart_open(struct tty_struct *tty, struct file *filp) /* * We take the semaphore inside uart_get to guarantee that we won't - * be re-entered while allocating the state structure, or while we + * be re-entered while allocating the info structure, or while we * request any IRQs that the driver may need. This also has the nice * side-effect that it delays the action of uart_hangup, so we can - * guarantee that state->port.tty will always contain something - * reasonable. + * guarantee that info->port.tty will always contain something reasonable. */ state = uart_get(drv, line); if (IS_ERR(state)) { retval = PTR_ERR(state); goto fail; } - port = &state->port; /* * Once we set tty->driver_data here, we are guaranteed that @@ -1636,25 +1623,25 @@ static int uart_open(struct tty_struct *tty, struct file *filp) * Any failures from here onwards should not touch the count. */ tty->driver_data = state; - state->uart_port->state = state; - tty->low_latency = (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0; + state->port->info = &state->info; + tty->low_latency = (state->port->flags & UPF_LOW_LATENCY) ? 1 : 0; tty->alt_speed = 0; - tty_port_tty_set(port, tty); + state->info.port.tty = tty; /* * If the port is in the middle of closing, bail out now. */ if (tty_hung_up_p(filp)) { retval = -EAGAIN; - port->count--; - mutex_unlock(&port->mutex); + state->count--; + mutex_unlock(&state->mutex); goto fail; } /* * Make sure the device is in D0 state. */ - if (port->count == 1) + if (state->count == 1) uart_change_pm(state, 0); /* @@ -1667,18 +1654,18 @@ static int uart_open(struct tty_struct *tty, struct file *filp) */ if (retval == 0) retval = uart_block_til_ready(filp, state); - mutex_unlock(&port->mutex); + mutex_unlock(&state->mutex); /* * If this is the first open to succeed, adjust things to suit. */ - if (retval == 0 && !(port->flags & ASYNC_NORMAL_ACTIVE)) { - set_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); + if (retval == 0 && !(state->info.flags & UIF_NORMAL_ACTIVE)) { + state->info.flags |= UIF_NORMAL_ACTIVE; uart_update_termios(state); } -fail: + fail: return retval; } @@ -1700,58 +1687,57 @@ static const char *uart_type(struct uart_port *port) static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i) { struct uart_state *state = drv->state + i; - struct tty_port *port = &state->port; int pm_state; - struct uart_port *uport = state->uart_port; + struct uart_port *port = state->port; char stat_buf[32]; unsigned int status; int mmio; - if (!uport) + if (!port) return; - mmio = uport->iotype >= UPIO_MEM; + mmio = port->iotype >= UPIO_MEM; seq_printf(m, "%d: uart:%s %s%08llX irq:%d", - uport->line, uart_type(uport), + port->line, uart_type(port), mmio ? "mmio:0x" : "port:", - mmio ? (unsigned long long)uport->mapbase - : (unsigned long long)uport->iobase, - uport->irq); + mmio ? (unsigned long long)port->mapbase + : (unsigned long long) port->iobase, + port->irq); - if (uport->type == PORT_UNKNOWN) { + if (port->type == PORT_UNKNOWN) { seq_putc(m, '\n'); return; } if (capable(CAP_SYS_ADMIN)) { - mutex_lock(&port->mutex); + mutex_lock(&state->mutex); pm_state = state->pm_state; if (pm_state) uart_change_pm(state, 0); - spin_lock_irq(&uport->lock); - status = uport->ops->get_mctrl(uport); - spin_unlock_irq(&uport->lock); + spin_lock_irq(&port->lock); + status = port->ops->get_mctrl(port); + spin_unlock_irq(&port->lock); if (pm_state) uart_change_pm(state, pm_state); - mutex_unlock(&port->mutex); + mutex_unlock(&state->mutex); seq_printf(m, " tx:%d rx:%d", - uport->icount.tx, uport->icount.rx); - if (uport->icount.frame) + port->icount.tx, port->icount.rx); + if (port->icount.frame) seq_printf(m, " fe:%d", - uport->icount.frame); - if (uport->icount.parity) + port->icount.frame); + if (port->icount.parity) seq_printf(m, " pe:%d", - uport->icount.parity); - if (uport->icount.brk) + port->icount.parity); + if (port->icount.brk) seq_printf(m, " brk:%d", - uport->icount.brk); - if (uport->icount.overrun) + port->icount.brk); + if (port->icount.overrun) seq_printf(m, " oe:%d", - uport->icount.overrun); + port->icount.overrun); #define INFOBIT(bit, str) \ - if (uport->mctrl & (bit)) \ + if (port->mctrl & (bit)) \ strncat(stat_buf, (str), sizeof(stat_buf) - \ strlen(stat_buf) - 2) #define STATBIT(bit, str) \ @@ -1972,7 +1958,7 @@ EXPORT_SYMBOL_GPL(uart_set_options); static void uart_change_pm(struct uart_state *state, int pm_state) { - struct uart_port *port = state->uart_port; + struct uart_port *port = state->port; if (state->pm_state != pm_state) { if (port->ops->pm) @@ -1996,138 +1982,132 @@ static int serial_match_port(struct device *dev, void *data) return dev->devt == devt; /* Actually, only one tty per port */ } -int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) +int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) { - struct uart_state *state = drv->state + uport->line; - struct tty_port *port = &state->port; + struct uart_state *state = drv->state + port->line; struct device *tty_dev; - struct uart_match match = {uport, drv}; + struct uart_match match = {port, drv}; - mutex_lock(&port->mutex); + mutex_lock(&state->mutex); - if (!console_suspend_enabled && uart_console(uport)) { + if (!console_suspend_enabled && uart_console(port)) { /* we're going to avoid suspending serial console */ - mutex_unlock(&port->mutex); + mutex_unlock(&state->mutex); return 0; } - tty_dev = device_find_child(uport->dev, &match, serial_match_port); + tty_dev = device_find_child(port->dev, &match, serial_match_port); if (device_may_wakeup(tty_dev)) { - enable_irq_wake(uport->irq); + enable_irq_wake(port->irq); put_device(tty_dev); - mutex_unlock(&port->mutex); + mutex_unlock(&state->mutex); return 0; } - uport->suspended = 1; + port->suspended = 1; - if (port->flags & ASYNC_INITIALIZED) { - const struct uart_ops *ops = uport->ops; + if (state->info.flags & UIF_INITIALIZED) { + const struct uart_ops *ops = port->ops; int tries; - set_bit(ASYNCB_SUSPENDED, &port->flags); - clear_bit(ASYNCB_INITIALIZED, &port->flags); + state->info.flags = (state->info.flags & ~UIF_INITIALIZED) + | UIF_SUSPENDED; - spin_lock_irq(&uport->lock); - ops->stop_tx(uport); - ops->set_mctrl(uport, 0); - ops->stop_rx(uport); - spin_unlock_irq(&uport->lock); + spin_lock_irq(&port->lock); + ops->stop_tx(port); + ops->set_mctrl(port, 0); + ops->stop_rx(port); + spin_unlock_irq(&port->lock); /* * Wait for the transmitter to empty. */ - for (tries = 3; !ops->tx_empty(uport) && 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", - uport->dev ? dev_name(uport->dev) : "", - uport->dev ? ": " : "", + port->dev ? dev_name(port->dev) : "", + port->dev ? ": " : "", drv->dev_name, - drv->tty_driver->name_base + uport->line); + drv->tty_driver->name_base + port->line); - ops->shutdown(uport); + ops->shutdown(port); } /* * Disable the console device before suspending. */ - if (uart_console(uport)) - console_stop(uport->cons); + if (uart_console(port)) + console_stop(port->cons); uart_change_pm(state, 3); - mutex_unlock(&port->mutex); + mutex_unlock(&state->mutex); return 0; } -int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) +int uart_resume_port(struct uart_driver *drv, struct uart_port *port) { - struct uart_state *state = drv->state + uport->line; - struct tty_port *port = &state->port; + struct uart_state *state = drv->state + port->line; struct device *tty_dev; - struct uart_match match = {uport, drv}; - struct ktermios termios; + struct uart_match match = {port, drv}; - mutex_lock(&port->mutex); + mutex_lock(&state->mutex); - if (!console_suspend_enabled && uart_console(uport)) { + if (!console_suspend_enabled && uart_console(port)) { /* no need to resume serial console, it wasn't suspended */ - /* - * First try to use the console cflag setting. - */ - memset(&termios, 0, sizeof(struct ktermios)); - termios.c_cflag = uport->cons->cflag; - /* - * If that's unset, use the tty termios setting. - */ - if (termios.c_cflag == 0) - termios = *state->port.tty->termios; - else { - termios.c_ispeed = termios.c_ospeed = - tty_termios_input_baud_rate(&termios); - termios.c_ispeed = termios.c_ospeed = - tty_termios_baud_rate(&termios); - } - uport->ops->set_termios(uport, &termios, NULL); - mutex_unlock(&port->mutex); + mutex_unlock(&state->mutex); return 0; } - tty_dev = device_find_child(uport->dev, &match, serial_match_port); - if (!uport->suspended && device_may_wakeup(tty_dev)) { - disable_irq_wake(uport->irq); - mutex_unlock(&port->mutex); + tty_dev = device_find_child(port->dev, &match, serial_match_port); + if (!port->suspended && device_may_wakeup(tty_dev)) { + disable_irq_wake(port->irq); + mutex_unlock(&state->mutex); return 0; } - uport->suspended = 0; + port->suspended = 0; /* * Re-enable the console device after suspending. */ - if (uart_console(uport)) { + if (uart_console(port)) { + struct ktermios termios; + + /* + * First try to use the console cflag setting. + */ + memset(&termios, 0, sizeof(struct ktermios)); + termios.c_cflag = port->cons->cflag; + + /* + * If that's unset, use the tty termios setting. + */ + if (state->info.port.tty && termios.c_cflag == 0) + termios = *state->info.port.tty->termios; + uart_change_pm(state, 0); - uport->ops->set_termios(uport, &termios, NULL); - console_start(uport->cons); + port->ops->set_termios(port, &termios, NULL); + console_start(port->cons); } - if (port->flags & ASYNC_SUSPENDED) { - const struct uart_ops *ops = uport->ops; + if (state->info.flags & UIF_SUSPENDED) { + const struct uart_ops *ops = port->ops; int ret; uart_change_pm(state, 0); - spin_lock_irq(&uport->lock); - ops->set_mctrl(uport, 0); - spin_unlock_irq(&uport->lock); - ret = ops->startup(uport); + spin_lock_irq(&port->lock); + ops->set_mctrl(port, 0); + spin_unlock_irq(&port->lock); + ret = ops->startup(port); if (ret == 0) { uart_change_speed(state, NULL); - spin_lock_irq(&uport->lock); - ops->set_mctrl(uport, uport->mctrl); - ops->start_tx(uport); - spin_unlock_irq(&uport->lock); - set_bit(ASYNCB_INITIALIZED, &port->flags); + spin_lock_irq(&port->lock); + ops->set_mctrl(port, port->mctrl); + ops->start_tx(port); + spin_unlock_irq(&port->lock); + state->info.flags |= UIF_INITIALIZED; } else { /* * Failed to resume - maybe hardware went away? @@ -2137,10 +2117,10 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) uart_shutdown(state); } - clear_bit(ASYNCB_SUSPENDED, &port->flags); + state->info.flags &= ~UIF_SUSPENDED; } - mutex_unlock(&port->mutex); + mutex_unlock(&state->mutex); return 0; } @@ -2252,10 +2232,10 @@ static int uart_poll_init(struct tty_driver *driver, int line, char *options) int parity = 'n'; int flow = 'n'; - if (!state || !state->uart_port) + if (!state || !state->port) return -1; - port = state->uart_port; + port = state->port; if (!(port->ops->poll_get_char && port->ops->poll_put_char)) return -1; @@ -2273,10 +2253,10 @@ static int uart_poll_get_char(struct tty_driver *driver, int line) struct uart_state *state = drv->state + line; struct uart_port *port; - if (!state || !state->uart_port) + if (!state || !state->port) return -1; - port = state->uart_port; + port = state->port; return port->ops->poll_get_char(port); } @@ -2286,10 +2266,10 @@ static void uart_poll_put_char(struct tty_driver *driver, int line, char ch) struct uart_state *state = drv->state + line; struct uart_port *port; - if (!state || !state->uart_port) + if (!state || !state->port) return; - port = state->uart_port; + port = state->port; port->ops->poll_put_char(port, ch); } #endif @@ -2380,12 +2360,14 @@ int uart_register_driver(struct uart_driver *drv) */ for (i = 0; i < drv->nr; i++) { struct uart_state *state = drv->state + i; - struct tty_port *port = &state->port; - tty_port_init(port); - port->close_delay = 500; /* .5 seconds */ - port->closing_wait = 30000; /* 30 seconds */ - tasklet_init(&state->tlet, uart_tasklet_action, + state->close_delay = 500; /* .5 seconds */ + state->closing_wait = 30000; /* 30 seconds */ + mutex_init(&state->mutex); + + tty_port_init(&state->info.port); + init_waitqueue_head(&state->info.delta_msr_wait); + tasklet_init(&state->info.tlet, uart_tasklet_action, (unsigned long)state); } @@ -2433,64 +2415,62 @@ struct tty_driver *uart_console_device(struct console *co, int *index) * level uart drivers to expand uart_port, rather than having yet * more levels of structures. */ -int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) +int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) { struct uart_state *state; - struct tty_port *port; int ret = 0; struct device *tty_dev; BUG_ON(in_interrupt()); - if (uport->line >= drv->nr) + if (port->line >= drv->nr) return -EINVAL; - state = drv->state + uport->line; - port = &state->port; + state = drv->state + port->line; mutex_lock(&port_mutex); - mutex_lock(&port->mutex); - if (state->uart_port) { + mutex_lock(&state->mutex); + if (state->port) { ret = -EINVAL; goto out; } - state->uart_port = uport; + state->port = port; state->pm_state = -1; - uport->cons = drv->cons; - uport->state = state; + port->cons = drv->cons; + port->info = &state->info; /* * If this port is a console, then the spinlock is already * initialised. */ - if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) { - spin_lock_init(&uport->lock); - lockdep_set_class(&uport->lock, &port_lock_key); + if (!(uart_console(port) && (port->cons->flags & CON_ENABLED))) { + spin_lock_init(&port->lock); + lockdep_set_class(&port->lock, &port_lock_key); } - uart_configure_port(drv, state, uport); + uart_configure_port(drv, state, port); /* * Register the port whether it's detected or not. This allows * setserial to be used to alter this ports parameters. */ - tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev); + tty_dev = tty_register_device(drv->tty_driver, port->line, port->dev); if (likely(!IS_ERR(tty_dev))) { device_init_wakeup(tty_dev, 1); device_set_wakeup_enable(tty_dev, 0); } else printk(KERN_ERR "Cannot register tty device on line %d\n", - uport->line); + port->line); /* * Ensure UPF_DEAD is not set. */ - uport->flags &= ~UPF_DEAD; + port->flags &= ~UPF_DEAD; out: - mutex_unlock(&port->mutex); + mutex_unlock(&state->mutex); mutex_unlock(&port_mutex); return ret; @@ -2505,16 +2485,16 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) * core driver. No further calls will be made to the low-level code * for this port. */ -int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) +int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) { - struct uart_state *state = drv->state + uport->line; - struct tty_port *port = &state->port; + struct uart_state *state = drv->state + port->line; + struct uart_info *info; BUG_ON(in_interrupt()); - if (state->uart_port != uport) + if (state->port != port) printk(KERN_ALERT "Removing wrong port: %p != %p\n", - state->uart_port, uport); + state->port, port); mutex_lock(&port_mutex); @@ -2522,35 +2502,37 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) * Mark the port "dead" - this prevents any opens from * succeeding while we shut down the port. */ - mutex_lock(&port->mutex); - uport->flags |= UPF_DEAD; - mutex_unlock(&port->mutex); + mutex_lock(&state->mutex); + port->flags |= UPF_DEAD; + mutex_unlock(&state->mutex); /* * Remove the devices from the tty layer */ - tty_unregister_device(drv->tty_driver, uport->line); + tty_unregister_device(drv->tty_driver, port->line); - if (port->tty) - tty_vhangup(port->tty); + info = &state->info; + if (info && info->port.tty) + tty_vhangup(info->port.tty); /* * Free the port IO and memory resources, if any. */ - if (uport->type != PORT_UNKNOWN) - uport->ops->release_port(uport); + if (port->type != PORT_UNKNOWN) + port->ops->release_port(port); /* * Indicate that there isn't a port here anymore. */ - uport->type = PORT_UNKNOWN; + port->type = PORT_UNKNOWN; /* * Kill the tasklet, and free resources. */ - tasklet_kill(&state->tlet); + if (info) + tasklet_kill(&info->tlet); - state->uart_port = NULL; + state->port = NULL; mutex_unlock(&port_mutex); return 0; diff --git a/trunk/drivers/serial/serial_cs.c b/trunk/drivers/serial/serial_cs.c index a3bb49031a7f..ed4648b556c7 100644 --- a/trunk/drivers/serial/serial_cs.c +++ b/trunk/drivers/serial/serial_cs.c @@ -884,7 +884,6 @@ static struct pcmcia_device_id serial_ids[] = { PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0xa555, "SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- pre update */ PCMCIA_DEVICE_CIS_MANF_CARD(0x013f, 0xa555, "SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- post update */ PCMCIA_DEVICE_CIS_PROD_ID12("MultiTech", "PCMCIA 56K DataFax", 0x842047ee, 0xc2efcf03, "cis/MT5634ZLX.cis"), - PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-2", 0x96913a85, 0x27ab5437, "COMpad2.cis"), PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-4", 0x96913a85, 0xcec8f102, "COMpad4.cis"), PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "COMpad2.cis"), PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "cis/RS-COM-2P.cis"), diff --git a/trunk/drivers/serial/serial_ks8695.c b/trunk/drivers/serial/serial_ks8695.c index 2e71bbc04dac..52db5cc3f900 100644 --- a/trunk/drivers/serial/serial_ks8695.c +++ b/trunk/drivers/serial/serial_ks8695.c @@ -154,7 +154,7 @@ static void ks8695uart_disable_ms(struct uart_port *port) static irqreturn_t ks8695uart_rx_chars(int irq, void *dev_id) { struct uart_port *port = dev_id; - struct tty_struct *tty = port->state->port.tty; + struct tty_struct *tty = port->info->port.tty; unsigned int status, ch, lsr, flg, max_count = 256; status = UART_GET_LSR(port); /* clears pending LSR interrupts */ @@ -210,7 +210,7 @@ static irqreturn_t ks8695uart_rx_chars(int irq, void *dev_id) static irqreturn_t ks8695uart_tx_chars(int irq, void *dev_id) { struct uart_port *port = dev_id; - struct circ_buf *xmit = &port->state->xmit; + struct circ_buf *xmit = &port->info->xmit; unsigned int count; if (port->x_char) { @@ -266,7 +266,7 @@ static irqreturn_t ks8695uart_modem_status(int irq, void *dev_id) if (status & URMS_URTERI) port->icount.rng++; - wake_up_interruptible(&port->state->port.delta_msr_wait); + wake_up_interruptible(&port->info->delta_msr_wait); return IRQ_HANDLED; } diff --git a/trunk/drivers/serial/serial_lh7a40x.c b/trunk/drivers/serial/serial_lh7a40x.c index ea744707c4d6..a7bf024a8286 100644 --- a/trunk/drivers/serial/serial_lh7a40x.c +++ b/trunk/drivers/serial/serial_lh7a40x.c @@ -138,7 +138,7 @@ static void lh7a40xuart_enable_ms (struct uart_port* port) static void lh7a40xuart_rx_chars (struct uart_port* port) { - struct tty_struct* tty = port->state->port.tty; + struct tty_struct* tty = port->info->port.tty; int cbRxMax = 256; /* (Gross) limit on receive */ unsigned int data; /* Received data and status */ unsigned int flag; @@ -184,7 +184,7 @@ static void lh7a40xuart_rx_chars (struct uart_port* port) static void lh7a40xuart_tx_chars (struct uart_port* port) { - struct circ_buf* xmit = &port->state->xmit; + struct circ_buf* xmit = &port->info->xmit; int cbTxMax = port->fifosize; if (port->x_char) { @@ -241,7 +241,7 @@ static void lh7a40xuart_modem_status (struct uart_port* port) if (delta & CTS) uart_handle_cts_change (port, status & CTS); - wake_up_interruptible (&port->state->port.delta_msr_wait); + wake_up_interruptible (&port->info->delta_msr_wait); } static irqreturn_t lh7a40xuart_int (int irq, void* dev_id) diff --git a/trunk/drivers/serial/serial_txx9.c b/trunk/drivers/serial/serial_txx9.c index 0f7cf4c453e6..54dd16d66a4b 100644 --- a/trunk/drivers/serial/serial_txx9.c +++ b/trunk/drivers/serial/serial_txx9.c @@ -272,7 +272,7 @@ static void serial_txx9_initialize(struct uart_port *port) static inline void receive_chars(struct uart_txx9_port *up, unsigned int *status) { - struct tty_struct *tty = up->port.state->port.tty; + struct tty_struct *tty = up->port.info->port.tty; unsigned char ch; unsigned int disr = *status; int max_count = 256; @@ -348,7 +348,7 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status) static inline void transmit_chars(struct uart_txx9_port *up) { - struct circ_buf *xmit = &up->port.state->xmit; + struct circ_buf *xmit = &up->port.info->xmit; int count; if (up->port.x_char) { diff --git a/trunk/drivers/serial/sh-sci.c b/trunk/drivers/serial/sh-sci.c index 85119fb7cb50..32dc2fc50e6b 100644 --- a/trunk/drivers/serial/sh-sci.c +++ b/trunk/drivers/serial/sh-sci.c @@ -361,7 +361,7 @@ static inline int sci_rxroom(struct uart_port *port) static void sci_transmit_chars(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; + struct circ_buf *xmit = &port->info->xmit; unsigned int stopped = uart_tx_stopped(port); unsigned short status; unsigned short ctrl; @@ -426,7 +426,7 @@ static void sci_transmit_chars(struct uart_port *port) static inline void sci_receive_chars(struct uart_port *port) { struct sci_port *sci_port = to_sci_port(port); - struct tty_struct *tty = port->state->port.tty; + struct tty_struct *tty = port->info->port.tty; int i, count, copied = 0; unsigned short status; unsigned char flag; @@ -546,7 +546,7 @@ static inline int sci_handle_errors(struct uart_port *port) { int copied = 0; unsigned short status = sci_in(port, SCxSR); - struct tty_struct *tty = port->state->port.tty; + struct tty_struct *tty = port->info->port.tty; if (status & SCxSR_ORER(port)) { /* overrun error */ @@ -600,7 +600,7 @@ static inline int sci_handle_errors(struct uart_port *port) static inline int sci_handle_fifo_overrun(struct uart_port *port) { - struct tty_struct *tty = port->state->port.tty; + struct tty_struct *tty = port->info->port.tty; int copied = 0; if (port->type != PORT_SCIF) @@ -623,7 +623,7 @@ static inline int sci_handle_breaks(struct uart_port *port) { int copied = 0; unsigned short status = sci_in(port, SCxSR); - struct tty_struct *tty = port->state->port.tty; + struct tty_struct *tty = port->info->port.tty; struct sci_port *s = to_sci_port(port); if (uart_handle_break(port)) diff --git a/trunk/drivers/serial/sn_console.c b/trunk/drivers/serial/sn_console.c index 9794e0cd3dcc..d5276c012f78 100644 --- a/trunk/drivers/serial/sn_console.c +++ b/trunk/drivers/serial/sn_console.c @@ -469,9 +469,9 @@ sn_receive_chars(struct sn_cons_port *port, unsigned long flags) return; } - if (port->sc_port.state) { + if (port->sc_port.info) { /* The serial_core stuffs are initilized, use them */ - tty = port->sc_port.state->port.tty; + tty = port->sc_port.info->port.tty; } else { /* Not registered yet - can't pass to tty layer. */ @@ -550,9 +550,9 @@ static void sn_transmit_chars(struct sn_cons_port *port, int raw) BUG_ON(!port->sc_is_asynch); - if (port->sc_port.state) { + if (port->sc_port.info) { /* We're initilized, using serial core infrastructure */ - xmit = &port->sc_port.state->xmit; + xmit = &port->sc_port.info->xmit; } else { /* Probably sn_sal_switch_to_asynch has been run but serial core isn't * initilized yet. Just return. Writes are going through @@ -927,7 +927,7 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count) /* We can't look at the xmit buffer if we're not registered with serial core * yet. So only do the fancy recovery after registering */ - if (!port->sc_port.state) { + if (!port->sc_port.info) { /* Not yet registered with serial core - simple case */ puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count); return; @@ -936,8 +936,8 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count) /* somebody really wants this output, might be an * oops, kdb, panic, etc. make sure they get it. */ if (spin_is_locked(&port->sc_port.lock)) { - int lhead = port->sc_port.state->xmit.head; - int ltail = port->sc_port.state->xmit.tail; + int lhead = port->sc_port.info->xmit.head; + int ltail = port->sc_port.info->xmit.tail; int counter, got_lock = 0; /* @@ -962,13 +962,13 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count) break; } else { /* still locked */ - if ((lhead != port->sc_port.state->xmit.head) + if ((lhead != port->sc_port.info->xmit.head) || (ltail != - port->sc_port.state->xmit.tail)) { + port->sc_port.info->xmit.tail)) { lhead = - port->sc_port.state->xmit.head; + port->sc_port.info->xmit.head; ltail = - port->sc_port.state->xmit.tail; + port->sc_port.info->xmit.tail; counter = 0; } } diff --git a/trunk/drivers/serial/sunhv.c b/trunk/drivers/serial/sunhv.c index d548652dee50..1df5325faab2 100644 --- a/trunk/drivers/serial/sunhv.c +++ b/trunk/drivers/serial/sunhv.c @@ -184,8 +184,8 @@ static struct tty_struct *receive_chars(struct uart_port *port) { struct tty_struct *tty = NULL; - if (port->state != NULL) /* Unopened serial console */ - tty = port->state->port.tty; + if (port->info != NULL) /* Unopened serial console */ + tty = port->info->port.tty; if (sunhv_ops->receive_chars(port, tty)) sun_do_break(); @@ -197,10 +197,10 @@ static void transmit_chars(struct uart_port *port) { struct circ_buf *xmit; - if (!port->state) + if (!port->info) return; - xmit = &port->state->xmit; + xmit = &port->info->xmit; if (uart_circ_empty(xmit) || uart_tx_stopped(port)) return; diff --git a/trunk/drivers/serial/sunsab.c b/trunk/drivers/serial/sunsab.c index d1ad34128635..0355efe115d9 100644 --- a/trunk/drivers/serial/sunsab.c +++ b/trunk/drivers/serial/sunsab.c @@ -117,8 +117,8 @@ receive_chars(struct uart_sunsab_port *up, int count = 0; int i; - if (up->port.state != NULL) /* Unopened serial console */ - tty = up->port.state->port.tty; + if (up->port.info != NULL) /* Unopened serial console */ + tty = up->port.info->port.tty; /* Read number of BYTES (Character + Status) available. */ if (stat->sreg.isr0 & SAB82532_ISR0_RPF) { @@ -229,7 +229,7 @@ static void sunsab_tx_idle(struct uart_sunsab_port *); static void transmit_chars(struct uart_sunsab_port *up, union sab82532_irq_status *stat) { - struct circ_buf *xmit = &up->port.state->xmit; + struct circ_buf *xmit = &up->port.info->xmit; int i; if (stat->sreg.isr1 & SAB82532_ISR1_ALLS) { @@ -297,7 +297,7 @@ static void check_status(struct uart_sunsab_port *up, up->port.icount.dsr++; } - wake_up_interruptible(&up->port.state->port.delta_msr_wait); + wake_up_interruptible(&up->port.info->delta_msr_wait); } static irqreturn_t sunsab_interrupt(int irq, void *dev_id) @@ -429,7 +429,7 @@ static void sunsab_tx_idle(struct uart_sunsab_port *up) static void sunsab_start_tx(struct uart_port *port) { struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; - struct circ_buf *xmit = &up->port.state->xmit; + struct circ_buf *xmit = &up->port.info->xmit; int i; up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR); diff --git a/trunk/drivers/serial/sunsu.c b/trunk/drivers/serial/sunsu.c index 68d262b15749..47c6837850b1 100644 --- a/trunk/drivers/serial/sunsu.c +++ b/trunk/drivers/serial/sunsu.c @@ -311,7 +311,7 @@ static void sunsu_enable_ms(struct uart_port *port) static struct tty_struct * receive_chars(struct uart_sunsu_port *up, unsigned char *status) { - struct tty_struct *tty = up->port.state->port.tty; + struct tty_struct *tty = up->port.info->port.tty; unsigned char ch, flag; int max_count = 256; int saw_console_brk = 0; @@ -389,7 +389,7 @@ receive_chars(struct uart_sunsu_port *up, unsigned char *status) static void transmit_chars(struct uart_sunsu_port *up) { - struct circ_buf *xmit = &up->port.state->xmit; + struct circ_buf *xmit = &up->port.info->xmit; int count; if (up->port.x_char) { @@ -441,7 +441,7 @@ static void check_modem_status(struct uart_sunsu_port *up) if (status & UART_MSR_DCTS) uart_handle_cts_change(&up->port, status & UART_MSR_CTS); - wake_up_interruptible(&up->port.state->port.delta_msr_wait); + wake_up_interruptible(&up->port.info->delta_msr_wait); } static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id) diff --git a/trunk/drivers/serial/sunzilog.c b/trunk/drivers/serial/sunzilog.c index ef693ae22e7f..e09d3cebb4fb 100644 --- a/trunk/drivers/serial/sunzilog.c +++ b/trunk/drivers/serial/sunzilog.c @@ -328,9 +328,9 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up, unsigned char ch, r1, flag; tty = NULL; - if (up->port.state != NULL && /* Unopened serial console */ - up->port.state->port.tty != NULL) /* Keyboard || mouse */ - tty = up->port.state->port.tty; + if (up->port.info != NULL && /* Unopened serial console */ + up->port.info->port.tty != NULL) /* Keyboard || mouse */ + tty = up->port.info->port.tty; for (;;) { @@ -451,7 +451,7 @@ static void sunzilog_status_handle(struct uart_sunzilog_port *up, uart_handle_cts_change(&up->port, (status & CTS)); - wake_up_interruptible(&up->port.state->port.delta_msr_wait); + wake_up_interruptible(&up->port.info->delta_msr_wait); } up->prev_status = status; @@ -501,9 +501,9 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up, return; } - if (up->port.state == NULL) + if (up->port.info == NULL) goto ack_tx_int; - xmit = &up->port.state->xmit; + xmit = &up->port.info->xmit; if (uart_circ_empty(xmit)) goto ack_tx_int; @@ -705,7 +705,7 @@ static void sunzilog_start_tx(struct uart_port *port) port->icount.tx++; port->x_char = 0; } else { - struct circ_buf *xmit = &port->state->xmit; + struct circ_buf *xmit = &port->info->xmit; writeb(xmit->buf[xmit->tail], &channel->data); ZSDELAY(); diff --git a/trunk/drivers/serial/timbuart.c b/trunk/drivers/serial/timbuart.c index 34b31da01d09..063a313b755c 100644 --- a/trunk/drivers/serial/timbuart.c +++ b/trunk/drivers/serial/timbuart.c @@ -77,7 +77,7 @@ static void timbuart_flush_buffer(struct uart_port *port) static void timbuart_rx_chars(struct uart_port *port) { - struct tty_struct *tty = port->state->port.tty; + struct tty_struct *tty = port->info->port.tty; while (ioread32(port->membase + TIMBUART_ISR) & RXDP) { u8 ch = ioread8(port->membase + TIMBUART_RXFIFO); @@ -86,7 +86,7 @@ static void timbuart_rx_chars(struct uart_port *port) } spin_unlock(&port->lock); - tty_flip_buffer_push(port->state->port.tty); + tty_flip_buffer_push(port->info->port.tty); spin_lock(&port->lock); dev_dbg(port->dev, "%s - total read %d bytes\n", @@ -95,7 +95,7 @@ static void timbuart_rx_chars(struct uart_port *port) static void timbuart_tx_chars(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; + struct circ_buf *xmit = &port->info->xmit; while (!(ioread32(port->membase + TIMBUART_ISR) & TXBF) && !uart_circ_empty(xmit)) { @@ -118,7 +118,7 @@ static void timbuart_handle_tx_port(struct uart_port *port, u32 isr, u32 *ier) { struct timbuart_port *uart = container_of(port, struct timbuart_port, port); - struct circ_buf *xmit = &port->state->xmit; + struct circ_buf *xmit = &port->info->xmit; if (uart_circ_empty(xmit) || uart_tx_stopped(port)) return; @@ -231,7 +231,7 @@ static void timbuart_mctrl_check(struct uart_port *port, u32 isr, u32 *ier) iowrite32(CTS_DELTA, port->membase + TIMBUART_ISR); cts = timbuart_get_mctrl(port); uart_handle_cts_change(port, cts & TIOCM_CTS); - wake_up_interruptible(&port->state->port.delta_msr_wait); + wake_up_interruptible(&port->info->delta_msr_wait); } *ier |= CTS_DELTA; diff --git a/trunk/drivers/serial/uartlite.c b/trunk/drivers/serial/uartlite.c index 377f2712289e..3317148a4b93 100644 --- a/trunk/drivers/serial/uartlite.c +++ b/trunk/drivers/serial/uartlite.c @@ -75,7 +75,7 @@ static struct uart_port ulite_ports[ULITE_NR_UARTS]; static int ulite_receive(struct uart_port *port, int stat) { - struct tty_struct *tty = port->state->port.tty; + struct tty_struct *tty = port->info->port.tty; unsigned char ch = 0; char flag = TTY_NORMAL; @@ -125,7 +125,7 @@ static int ulite_receive(struct uart_port *port, int stat) static int ulite_transmit(struct uart_port *port, int stat) { - struct circ_buf *xmit = &port->state->xmit; + struct circ_buf *xmit = &port->info->xmit; if (stat & ULITE_STATUS_TXFULL) return 0; @@ -154,22 +154,17 @@ static int ulite_transmit(struct uart_port *port, int stat) static irqreturn_t ulite_isr(int irq, void *dev_id) { struct uart_port *port = dev_id; - int busy, n = 0; + int busy; do { int stat = readb(port->membase + ULITE_STATUS); busy = ulite_receive(port, stat); busy |= ulite_transmit(port, stat); - n++; } while (busy); - /* work done? */ - if (n > 1) { - tty_flip_buffer_push(port->state->port.tty); - return IRQ_HANDLED; - } else { - return IRQ_NONE; - } + tty_flip_buffer_push(port->info->port.tty); + + return IRQ_HANDLED; } static unsigned int ulite_tx_empty(struct uart_port *port) @@ -226,7 +221,7 @@ static int ulite_startup(struct uart_port *port) int ret; ret = request_irq(port->irq, ulite_isr, - IRQF_SHARED | IRQF_SAMPLE_RANDOM, "uartlite", port); + IRQF_DISABLED | IRQF_SAMPLE_RANDOM, "uartlite", port); if (ret) return ret; diff --git a/trunk/drivers/serial/ucc_uart.c b/trunk/drivers/serial/ucc_uart.c index 0c08f286a2ef..e945e780b5c9 100644 --- a/trunk/drivers/serial/ucc_uart.c +++ b/trunk/drivers/serial/ucc_uart.c @@ -327,7 +327,7 @@ static int qe_uart_tx_pump(struct uart_qe_port *qe_port) unsigned char *p; unsigned int count; struct uart_port *port = &qe_port->port; - struct circ_buf *xmit = &port->state->xmit; + struct circ_buf *xmit = &port->info->xmit; bdp = qe_port->rx_cur; @@ -466,7 +466,7 @@ static void qe_uart_int_rx(struct uart_qe_port *qe_port) int i; unsigned char ch, *cp; struct uart_port *port = &qe_port->port; - struct tty_struct *tty = port->state->port.tty; + struct tty_struct *tty = port->info->port.tty; struct qe_bd *bdp; u16 status; unsigned int flg; diff --git a/trunk/drivers/serial/vr41xx_siu.c b/trunk/drivers/serial/vr41xx_siu.c index 3beb6ab4fa68..dac550e57c29 100644 --- a/trunk/drivers/serial/vr41xx_siu.c +++ b/trunk/drivers/serial/vr41xx_siu.c @@ -318,7 +318,7 @@ static inline void receive_chars(struct uart_port *port, uint8_t *status) char flag; int max_count = RX_MAX_COUNT; - tty = port->state->port.tty; + tty = port->info->port.tty; lsr = *status; do { @@ -386,7 +386,7 @@ static inline void check_modem_status(struct uart_port *port) if (msr & UART_MSR_DCTS) uart_handle_cts_change(port, msr & UART_MSR_CTS); - wake_up_interruptible(&port->state->port.delta_msr_wait); + wake_up_interruptible(&port->info->delta_msr_wait); } static inline void transmit_chars(struct uart_port *port) @@ -394,7 +394,7 @@ static inline void transmit_chars(struct uart_port *port) struct circ_buf *xmit; int max_count = TX_MAX_COUNT; - xmit = &port->state->xmit; + xmit = &port->info->xmit; if (port->x_char) { siu_write(port, UART_TX, port->x_char); diff --git a/trunk/drivers/serial/zs.c b/trunk/drivers/serial/zs.c index 1a7fd3e70315..d8c2809b1ab6 100644 --- a/trunk/drivers/serial/zs.c +++ b/trunk/drivers/serial/zs.c @@ -602,12 +602,12 @@ static void zs_receive_chars(struct zs_port *zport) uart_insert_char(uport, status, Rx_OVR, ch, flag); } - tty_flip_buffer_push(uport->state->port.tty); + tty_flip_buffer_push(uport->info->port.tty); } static void zs_raw_transmit_chars(struct zs_port *zport) { - struct circ_buf *xmit = &zport->port.state->xmit; + struct circ_buf *xmit = &zport->port.info->xmit; /* XON/XOFF chars. */ if (zport->port.x_char) { @@ -686,7 +686,7 @@ static void zs_status_handle(struct zs_port *zport, struct zs_port *zport_a) uport->icount.rng++; if (delta) - wake_up_interruptible(&uport->state->port.delta_msr_wait); + wake_up_interruptible(&uport->info->delta_msr_wait); spin_lock(&scc->zlock); } diff --git a/trunk/drivers/usb/class/cdc-acm.c b/trunk/drivers/usb/class/cdc-acm.c index 85a1a55815cf..2bfc41ece0e1 100644 --- a/trunk/drivers/usb/class/cdc-acm.c +++ b/trunk/drivers/usb/class/cdc-acm.c @@ -858,7 +858,10 @@ static void acm_tty_set_termios(struct tty_struct *tty, if (!ACM_READY(acm)) return; - newline.dwDTERate = cpu_to_le32(tty_get_baud_rate(tty)); + /* FIXME: Needs to support the tty_baud interface */ + /* FIXME: Broken on sparc */ + newline.dwDTERate = cpu_to_le32p(acm_tty_speed + + (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0)); newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0; newline.bParityType = termios->c_cflag & PARENB ? (termios->c_cflag & PARODD ? 1 : 2) + diff --git a/trunk/drivers/usb/class/usblp.c b/trunk/drivers/usb/class/usblp.c index 9bc112ee7803..26c09f0257db 100644 --- a/trunk/drivers/usb/class/usblp.c +++ b/trunk/drivers/usb/class/usblp.c @@ -1057,14 +1057,14 @@ static const struct file_operations usblp_fops = { .release = usblp_release, }; -static char *usblp_devnode(struct device *dev, mode_t *mode) +static char *usblp_nodename(struct device *dev) { return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev)); } static struct usb_class_driver usblp_class = { .name = "lp%d", - .devnode = usblp_devnode, + .nodename = usblp_nodename, .fops = &usblp_fops, .minor_base = USBLP_MINOR_BASE, }; diff --git a/trunk/drivers/usb/core/file.c b/trunk/drivers/usb/core/file.c index 222ee07ea680..5cef88929b3e 100644 --- a/trunk/drivers/usb/core/file.c +++ b/trunk/drivers/usb/core/file.c @@ -67,14 +67,14 @@ static struct usb_class { struct class *class; } *usb_class; -static char *usb_devnode(struct device *dev, mode_t *mode) +static char *usb_nodename(struct device *dev) { struct usb_class_driver *drv; drv = dev_get_drvdata(dev); - if (!drv || !drv->devnode) + if (!drv || !drv->nodename) return NULL; - return drv->devnode(dev, mode); + return drv->nodename(dev); } static int init_usb_class(void) @@ -100,7 +100,7 @@ static int init_usb_class(void) kfree(usb_class); usb_class = NULL; } - usb_class->class->devnode = usb_devnode; + usb_class->class->nodename = usb_nodename; exit: return result; diff --git a/trunk/drivers/usb/core/usb.c b/trunk/drivers/usb/core/usb.c index 43ee943d757a..a26f73880c32 100644 --- a/trunk/drivers/usb/core/usb.c +++ b/trunk/drivers/usb/core/usb.c @@ -311,7 +311,7 @@ static struct dev_pm_ops usb_device_pm_ops = { #endif /* CONFIG_PM */ -static char *usb_devnode(struct device *dev, mode_t *mode) +static char *usb_nodename(struct device *dev) { struct usb_device *usb_dev; @@ -324,7 +324,7 @@ struct device_type usb_device_type = { .name = "usb_device", .release = usb_release_dev, .uevent = usb_dev_uevent, - .devnode = usb_devnode, + .nodename = usb_nodename, .pm = &usb_device_pm_ops, }; diff --git a/trunk/drivers/usb/misc/iowarrior.c b/trunk/drivers/usb/misc/iowarrior.c index e75bb87ee92b..90e1a8dedfa9 100644 --- a/trunk/drivers/usb/misc/iowarrior.c +++ b/trunk/drivers/usb/misc/iowarrior.c @@ -727,7 +727,7 @@ static const struct file_operations iowarrior_fops = { .poll = iowarrior_poll, }; -static char *iowarrior_devnode(struct device *dev, mode_t *mode) +static char *iowarrior_nodename(struct device *dev) { return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev)); } @@ -738,7 +738,7 @@ static char *iowarrior_devnode(struct device *dev, mode_t *mode) */ static struct usb_class_driver iowarrior_class = { .name = "iowarrior%d", - .devnode = iowarrior_devnode, + .nodename = iowarrior_nodename, .fops = &iowarrior_fops, .minor_base = IOWARRIOR_MINOR_BASE, }; diff --git a/trunk/drivers/usb/misc/legousbtower.c b/trunk/drivers/usb/misc/legousbtower.c index 97efeaec4d52..c1e2433f640d 100644 --- a/trunk/drivers/usb/misc/legousbtower.c +++ b/trunk/drivers/usb/misc/legousbtower.c @@ -266,7 +266,7 @@ static const struct file_operations tower_fops = { .llseek = tower_llseek, }; -static char *legousbtower_devnode(struct device *dev, mode_t *mode) +static char *legousbtower_nodename(struct device *dev) { return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev)); } @@ -277,7 +277,7 @@ static char *legousbtower_devnode(struct device *dev, mode_t *mode) */ static struct usb_class_driver tower_class = { .name = "legousbtower%d", - .devnode = legousbtower_devnode, + .nodename = legousbtower_nodename, .fops = &tower_fops, .minor_base = LEGO_USB_TOWER_MINOR_BASE, }; diff --git a/trunk/drivers/usb/serial/ark3116.c b/trunk/drivers/usb/serial/ark3116.c index 5d25d3e52bf6..aec61880f36c 100644 --- a/trunk/drivers/usb/serial/ark3116.c +++ b/trunk/drivers/usb/serial/ark3116.c @@ -35,6 +35,11 @@ static struct usb_device_id id_table [] = { }; MODULE_DEVICE_TABLE(usb, id_table); +struct ark3116_private { + spinlock_t lock; + u8 termios_initialized; +}; + static inline void ARK3116_SND(struct usb_serial *serial, int seq, __u8 request, __u8 requesttype, __u16 value, __u16 index) @@ -77,11 +82,22 @@ static inline void ARK3116_RCV_QUIET(struct usb_serial *serial, static int ark3116_attach(struct usb_serial *serial) { char *buf; + struct ark3116_private *priv; + int i; + + for (i = 0; i < serial->num_ports; ++i) { + priv = kzalloc(sizeof(struct ark3116_private), GFP_KERNEL); + if (!priv) + goto cleanup; + spin_lock_init(&priv->lock); + + usb_set_serial_port_data(serial->port[i], priv); + } buf = kmalloc(1, GFP_KERNEL); if (!buf) { dbg("error kmalloc -> out of mem?"); - return -ENOMEM; + goto cleanup; } /* 3 */ @@ -133,16 +149,13 @@ static int ark3116_attach(struct usb_serial *serial) kfree(buf); return 0; -} -static void ark3116_init_termios(struct tty_struct *tty) -{ - struct ktermios *termios = tty->termios; - *termios = tty_std_termios; - termios->c_cflag = B9600 | CS8 - | CREAD | HUPCL | CLOCAL; - termios->c_ispeed = 9600; - termios->c_ospeed = 9600; +cleanup: + for (--i; i >= 0; --i) { + kfree(usb_get_serial_port_data(serial->port[i])); + usb_set_serial_port_data(serial->port[i], NULL); + } + return -ENOMEM; } static void ark3116_set_termios(struct tty_struct *tty, @@ -150,8 +163,10 @@ static void ark3116_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct usb_serial *serial = port->serial; + struct ark3116_private *priv = usb_get_serial_port_data(port); struct ktermios *termios = tty->termios; unsigned int cflag = termios->c_cflag; + unsigned long flags; int baud; int ark3116_baud; char *buf; @@ -161,6 +176,16 @@ static void ark3116_set_termios(struct tty_struct *tty, dbg("%s - port %d", __func__, port->number); + spin_lock_irqsave(&priv->lock, flags); + if (!priv->termios_initialized) { + *termios = tty_std_termios; + termios->c_cflag = B9600 | CS8 + | CREAD | HUPCL | CLOCAL; + termios->c_ispeed = 9600; + termios->c_ospeed = 9600; + priv->termios_initialized = 1; + } + spin_unlock_irqrestore(&priv->lock, flags); cflag = termios->c_cflag; termios->c_cflag &= ~(CMSPAR|CRTSCTS); @@ -293,7 +318,8 @@ static void ark3116_set_termios(struct tty_struct *tty, return; } -static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) +static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port, + struct file *filp) { struct ktermios tmp_termios; struct usb_serial *serial = port->serial; @@ -308,7 +334,7 @@ static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) return -ENOMEM; } - result = usb_serial_generic_open(tty, port); + result = usb_serial_generic_open(tty, port, filp); if (result) goto err_out; @@ -429,7 +455,6 @@ static struct usb_serial_driver ark3116_device = { .num_ports = 1, .attach = ark3116_attach, .set_termios = ark3116_set_termios, - .init_termios = ark3116_init_termios, .ioctl = ark3116_ioctl, .tiocmget = ark3116_tiocmget, .open = ark3116_open, diff --git a/trunk/drivers/usb/serial/belkin_sa.c b/trunk/drivers/usb/serial/belkin_sa.c index a0467bc61627..7033b031b443 100644 --- a/trunk/drivers/usb/serial/belkin_sa.c +++ b/trunk/drivers/usb/serial/belkin_sa.c @@ -92,7 +92,7 @@ static int debug; static int belkin_sa_startup(struct usb_serial *serial); static void belkin_sa_release(struct usb_serial *serial); static int belkin_sa_open(struct tty_struct *tty, - struct usb_serial_port *port); + struct usb_serial_port *port, struct file *filp); static void belkin_sa_close(struct usb_serial_port *port); static void belkin_sa_read_int_callback(struct urb *urb); static void belkin_sa_set_termios(struct tty_struct *tty, @@ -213,7 +213,7 @@ static void belkin_sa_release(struct usb_serial *serial) static int belkin_sa_open(struct tty_struct *tty, - struct usb_serial_port *port) + struct usb_serial_port *port, struct file *filp) { int retval = 0; diff --git a/trunk/drivers/usb/serial/ch341.c b/trunk/drivers/usb/serial/ch341.c index 8c894a7d5dcf..2830766f5b39 100644 --- a/trunk/drivers/usb/serial/ch341.c +++ b/trunk/drivers/usb/serial/ch341.c @@ -300,7 +300,8 @@ static void ch341_close(struct usb_serial_port *port) /* open this device, set default parameters */ -static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port) +static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port, + struct file *filp) { struct usb_serial *serial = port->serial; struct ch341_private *priv = usb_get_serial_port_data(serial->port[0]); @@ -332,7 +333,7 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port) return -EPROTO; } - r = usb_serial_generic_open(tty, port); + r = usb_serial_generic_open(tty, port, filp); out: return r; } diff --git a/trunk/drivers/usb/serial/console.c b/trunk/drivers/usb/serial/console.c index b22ac3258523..0e4f2e41ace5 100644 --- a/trunk/drivers/usb/serial/console.c +++ b/trunk/drivers/usb/serial/console.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -64,7 +63,7 @@ static int usb_console_setup(struct console *co, char *options) char *s; struct usb_serial *serial; struct usb_serial_port *port; - int retval; + int retval = 0; struct tty_struct *tty = NULL; struct ktermios *termios = NULL, dummy; @@ -117,17 +116,13 @@ static int usb_console_setup(struct console *co, char *options) return -ENODEV; } - retval = usb_autopm_get_interface(serial->interface); - if (retval) - goto error_get_interface; - - port = serial->port[co->index - serial->minor]; + port = serial->port[0]; tty_port_tty_set(&port->port, NULL); info->port = port; ++port->port.count; - if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) { + if (port->port.count == 1) { if (serial->type->set_termios) { /* * allocate a fake tty so the driver can initialize @@ -155,9 +150,9 @@ static int usb_console_setup(struct console *co, char *options) /* only call the device specific open if this * is the first time the port is opened */ if (serial->type->open) - retval = serial->type->open(NULL, port); + retval = serial->type->open(NULL, port, NULL); else - retval = usb_serial_generic_open(NULL, port); + retval = usb_serial_generic_open(NULL, port, NULL); if (retval) { err("could not open USB console port"); @@ -173,7 +168,6 @@ static int usb_console_setup(struct console *co, char *options) kfree(termios); kfree(tty); } - set_bit(ASYNCB_INITIALIZED, &port->port.flags); } /* Now that any required fake tty operations are completed restore * the tty port count */ @@ -181,22 +175,18 @@ static int usb_console_setup(struct console *co, char *options) /* The console is special in terms of closing the device so * indicate this port is now acting as a system console. */ port->console = 1; + retval = 0; - mutex_unlock(&serial->disc_mutex); +out: return retval; - - free_termios: +free_termios: kfree(termios); tty_port_tty_set(&port->port, NULL); - free_tty: +free_tty: kfree(tty); - reset_open_count: +reset_open_count: port->port.count = 0; - usb_autopm_put_interface(serial->interface); - error_get_interface: - usb_serial_put(serial); - mutex_unlock(&serial->disc_mutex); - return retval; + goto out; } static void usb_console_write(struct console *co, diff --git a/trunk/drivers/usb/serial/cp210x.c b/trunk/drivers/usb/serial/cp210x.c index 4a208fe85bc9..985cbcf48bda 100644 --- a/trunk/drivers/usb/serial/cp210x.c +++ b/trunk/drivers/usb/serial/cp210x.c @@ -33,7 +33,8 @@ /* * Function Prototypes */ -static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *); +static int cp210x_open(struct tty_struct *, struct usb_serial_port *, + struct file *); static void cp210x_cleanup(struct usb_serial_port *); static void cp210x_close(struct usb_serial_port *); static void cp210x_get_termios(struct tty_struct *, @@ -367,7 +368,8 @@ static unsigned int cp210x_quantise_baudrate(unsigned int baud) { return baud; } -static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) +static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port, + struct file *filp) { struct usb_serial *serial = port->serial; int result; @@ -397,6 +399,12 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) /* Configure the termios structure */ cp210x_get_termios(tty, port); + + /* Set the DTR and RTS pins low */ + cp210x_tiocmset_port(tty ? (struct usb_serial_port *) tty->driver_data + : port, + NULL, TIOCM_DTR | TIOCM_RTS, 0); + return 0; } diff --git a/trunk/drivers/usb/serial/cyberjack.c b/trunk/drivers/usb/serial/cyberjack.c index b0f6402a91ca..336523fd7366 100644 --- a/trunk/drivers/usb/serial/cyberjack.c +++ b/trunk/drivers/usb/serial/cyberjack.c @@ -61,7 +61,7 @@ static int cyberjack_startup(struct usb_serial *serial); static void cyberjack_disconnect(struct usb_serial *serial); static void cyberjack_release(struct usb_serial *serial); static int cyberjack_open(struct tty_struct *tty, - struct usb_serial_port *port); + struct usb_serial_port *port, struct file *filp); static void cyberjack_close(struct usb_serial_port *port); static int cyberjack_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); @@ -173,7 +173,7 @@ static void cyberjack_release(struct usb_serial *serial) } static int cyberjack_open(struct tty_struct *tty, - struct usb_serial_port *port) + struct usb_serial_port *port, struct file *filp) { struct cyberjack_private *priv; unsigned long flags; diff --git a/trunk/drivers/usb/serial/cypress_m8.c b/trunk/drivers/usb/serial/cypress_m8.c index e0a8b715f2f2..59adfe123110 100644 --- a/trunk/drivers/usb/serial/cypress_m8.c +++ b/trunk/drivers/usb/serial/cypress_m8.c @@ -172,7 +172,8 @@ static int cypress_earthmate_startup(struct usb_serial *serial); static int cypress_hidcom_startup(struct usb_serial *serial); static int cypress_ca42v2_startup(struct usb_serial *serial); static void cypress_release(struct usb_serial *serial); -static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port); +static int cypress_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp); static void cypress_close(struct usb_serial_port *port); static void cypress_dtr_rts(struct usb_serial_port *port, int on); static int cypress_write(struct tty_struct *tty, struct usb_serial_port *port, @@ -632,7 +633,8 @@ static void cypress_release(struct usb_serial *serial) } -static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port) +static int cypress_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp) { struct cypress_private *priv = usb_get_serial_port_data(port); struct usb_serial *serial = port->serial; @@ -657,7 +659,15 @@ static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port) spin_unlock_irqrestore(&priv->lock, flags); /* Set termios */ - cypress_send(port); + result = cypress_write(tty, port, NULL, 0); + + if (result) { + dev_err(&port->dev, + "%s - failed setting the control lines - error %d\n", + __func__, result); + return result; + } else + dbg("%s - success setting the control lines", __func__); if (tty) cypress_set_termios(tty, port, &priv->tmp_termios); @@ -995,8 +1005,6 @@ static void cypress_set_termios(struct tty_struct *tty, dbg("%s - port %d", __func__, port->number); spin_lock_irqsave(&priv->lock, flags); - /* We can't clean this one up as we don't know the device type - early enough */ if (!priv->termios_initialized) { if (priv->chiptype == CT_EARTHMATE) { *(tty->termios) = tty_std_termios; diff --git a/trunk/drivers/usb/serial/digi_acceleport.c b/trunk/drivers/usb/serial/digi_acceleport.c index ab3dd991586b..f4808091c47c 100644 --- a/trunk/drivers/usb/serial/digi_acceleport.c +++ b/trunk/drivers/usb/serial/digi_acceleport.c @@ -453,7 +453,8 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port, static void digi_write_bulk_callback(struct urb *urb); static int digi_write_room(struct tty_struct *tty); static int digi_chars_in_buffer(struct tty_struct *tty); -static int digi_open(struct tty_struct *tty, struct usb_serial_port *port); +static int digi_open(struct tty_struct *tty, struct usb_serial_port *port, + struct file *filp); static void digi_close(struct usb_serial_port *port); static int digi_carrier_raised(struct usb_serial_port *port); static void digi_dtr_rts(struct usb_serial_port *port, int on); @@ -1346,7 +1347,8 @@ static int digi_carrier_raised(struct usb_serial_port *port) return 0; } -static int digi_open(struct tty_struct *tty, struct usb_serial_port *port) +static int digi_open(struct tty_struct *tty, struct usb_serial_port *port, + struct file *filp) { int ret; unsigned char buf[32]; diff --git a/trunk/drivers/usb/serial/empeg.c b/trunk/drivers/usb/serial/empeg.c index 33c9e9cf9eb2..80cb3471adbe 100644 --- a/trunk/drivers/usb/serial/empeg.c +++ b/trunk/drivers/usb/serial/empeg.c @@ -79,7 +79,8 @@ static int debug; #define EMPEG_PRODUCT_ID 0x0001 /* function prototypes for an empeg-car player */ -static int empeg_open(struct tty_struct *tty, struct usb_serial_port *port); +static int empeg_open(struct tty_struct *tty, struct usb_serial_port *port, + struct file *filp); static void empeg_close(struct usb_serial_port *port); static int empeg_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, @@ -89,7 +90,8 @@ static int empeg_chars_in_buffer(struct tty_struct *tty); static void empeg_throttle(struct tty_struct *tty); static void empeg_unthrottle(struct tty_struct *tty); static int empeg_startup(struct usb_serial *serial); -static void empeg_init_termios(struct tty_struct *tty); +static void empeg_set_termios(struct tty_struct *tty, + struct usb_serial_port *port, struct ktermios *old_termios); static void empeg_write_bulk_callback(struct urb *urb); static void empeg_read_bulk_callback(struct urb *urb); @@ -121,7 +123,7 @@ static struct usb_serial_driver empeg_device = { .throttle = empeg_throttle, .unthrottle = empeg_unthrottle, .attach = empeg_startup, - .init_termios = empeg_init_termios, + .set_termios = empeg_set_termios, .write = empeg_write, .write_room = empeg_write_room, .chars_in_buffer = empeg_chars_in_buffer, @@ -140,13 +142,17 @@ static int bytes_out; /****************************************************************************** * Empeg specific driver functions ******************************************************************************/ -static int empeg_open(struct tty_struct *tty,struct usb_serial_port *port) +static int empeg_open(struct tty_struct *tty, struct usb_serial_port *port, + struct file *filp) { struct usb_serial *serial = port->serial; int result = 0; dbg("%s - port %d", __func__, port->number); + /* Force default termio settings */ + empeg_set_termios(tty, port, NULL) ; + bytes_in = 0; bytes_out = 0; @@ -419,9 +425,11 @@ static int empeg_startup(struct usb_serial *serial) } -static void empeg_init_termios(struct tty_struct *tty) +static void empeg_set_termios(struct tty_struct *tty, + struct usb_serial_port *port, struct ktermios *old_termios) { struct ktermios *termios = tty->termios; + dbg("%s - port %d", __func__, port->number); /* * The empeg-car player wants these particular tty settings. diff --git a/trunk/drivers/usb/serial/ftdi_sio.c b/trunk/drivers/usb/serial/ftdi_sio.c index 76a17f915eef..8fec5d4455c9 100644 --- a/trunk/drivers/usb/serial/ftdi_sio.c +++ b/trunk/drivers/usb/serial/ftdi_sio.c @@ -747,7 +747,8 @@ static int ftdi_sio_probe(struct usb_serial *serial, const struct usb_device_id *id); static int ftdi_sio_port_probe(struct usb_serial_port *port); static int ftdi_sio_port_remove(struct usb_serial_port *port); -static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port); +static int ftdi_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp); static void ftdi_close(struct usb_serial_port *port); static void ftdi_dtr_rts(struct usb_serial_port *port, int on); static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port, @@ -1679,7 +1680,8 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port) return 0; } -static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) +static int ftdi_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp) { /* ftdi_open */ struct usb_device *dev = port->serial->dev; struct ftdi_private *priv = usb_get_serial_port_data(port); diff --git a/trunk/drivers/usb/serial/garmin_gps.c b/trunk/drivers/usb/serial/garmin_gps.c index 20432d345529..8839f1c70b7f 100644 --- a/trunk/drivers/usb/serial/garmin_gps.c +++ b/trunk/drivers/usb/serial/garmin_gps.c @@ -933,7 +933,8 @@ static int garmin_init_session(struct usb_serial_port *port) -static int garmin_open(struct tty_struct *tty, struct usb_serial_port *port) +static int garmin_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp) { unsigned long flags; int status = 0; diff --git a/trunk/drivers/usb/serial/generic.c b/trunk/drivers/usb/serial/generic.c index d9398e9f30ce..ce57f6a32bdf 100644 --- a/trunk/drivers/usb/serial/generic.c +++ b/trunk/drivers/usb/serial/generic.c @@ -114,7 +114,8 @@ void usb_serial_generic_deregister(void) #endif } -int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port) +int usb_serial_generic_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp) { struct usb_serial *serial = port->serial; int result = 0; diff --git a/trunk/drivers/usb/serial/io_edgeport.c b/trunk/drivers/usb/serial/io_edgeport.c index dc0f832657e6..0191693625d6 100644 --- a/trunk/drivers/usb/serial/io_edgeport.c +++ b/trunk/drivers/usb/serial/io_edgeport.c @@ -205,7 +205,8 @@ static void edge_bulk_out_data_callback(struct urb *urb); static void edge_bulk_out_cmd_callback(struct urb *urb); /* function prototypes for the usbserial callbacks */ -static int edge_open(struct tty_struct *tty, struct usb_serial_port *port); +static int edge_open(struct tty_struct *tty, struct usb_serial_port *port, + struct file *filp); static void edge_close(struct usb_serial_port *port); static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); @@ -851,7 +852,8 @@ static void edge_bulk_out_cmd_callback(struct urb *urb) * If successful, we return 0 * Otherwise we return a negative error number. *****************************************************************************/ -static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) +static int edge_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp) { struct edgeport_port *edge_port = usb_get_serial_port_data(port); struct usb_serial *serial; diff --git a/trunk/drivers/usb/serial/io_ti.c b/trunk/drivers/usb/serial/io_ti.c index d4cc0f7af400..e8bc42f92e79 100644 --- a/trunk/drivers/usb/serial/io_ti.c +++ b/trunk/drivers/usb/serial/io_ti.c @@ -1831,7 +1831,8 @@ static void edge_bulk_out_callback(struct urb *urb) tty_kref_put(tty); } -static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) +static int edge_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp) { struct edgeport_port *edge_port = usb_get_serial_port_data(port); struct edgeport_serial *edge_serial; diff --git a/trunk/drivers/usb/serial/ipaq.c b/trunk/drivers/usb/serial/ipaq.c index 24fcc64b837d..2545d45ce16f 100644 --- a/trunk/drivers/usb/serial/ipaq.c +++ b/trunk/drivers/usb/serial/ipaq.c @@ -75,7 +75,7 @@ static int initial_wait; /* Function prototypes for an ipaq */ static int ipaq_open(struct tty_struct *tty, - struct usb_serial_port *port); + struct usb_serial_port *port, struct file *filp); static void ipaq_close(struct usb_serial_port *port); static int ipaq_calc_num_ports(struct usb_serial *serial); static int ipaq_startup(struct usb_serial *serial); @@ -587,7 +587,7 @@ static int bytes_in; static int bytes_out; static int ipaq_open(struct tty_struct *tty, - struct usb_serial_port *port) + struct usb_serial_port *port, struct file *filp) { struct usb_serial *serial = port->serial; struct ipaq_private *priv; @@ -628,6 +628,11 @@ static int ipaq_open(struct tty_struct *tty, priv->free_len += PACKET_SIZE; } + if (tty) { + /* FIXME: These two are bogus */ + tty->raw = 1; + tty->real_raw = 1; + } /* * Lose the small buffers usbserial provides. Make larger ones. */ diff --git a/trunk/drivers/usb/serial/ipw.c b/trunk/drivers/usb/serial/ipw.c index 727d323f092a..29ad038b9c8d 100644 --- a/trunk/drivers/usb/serial/ipw.c +++ b/trunk/drivers/usb/serial/ipw.c @@ -193,7 +193,8 @@ static void ipw_read_bulk_callback(struct urb *urb) return; } -static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port) +static int ipw_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp) { struct usb_device *dev = port->serial->dev; u8 buf_flow_static[16] = IPW_BYTES_FLOWINIT; diff --git a/trunk/drivers/usb/serial/ir-usb.c b/trunk/drivers/usb/serial/ir-usb.c index 95d8d26b9a44..66009b6b763a 100644 --- a/trunk/drivers/usb/serial/ir-usb.c +++ b/trunk/drivers/usb/serial/ir-usb.c @@ -86,7 +86,8 @@ static int buffer_size; static int xbof = -1; static int ir_startup (struct usb_serial *serial); -static int ir_open(struct tty_struct *tty, struct usb_serial_port *port); +static int ir_open(struct tty_struct *tty, struct usb_serial_port *port, + struct file *filep); static void ir_close(struct usb_serial_port *port); static int ir_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); @@ -295,7 +296,8 @@ static int ir_startup(struct usb_serial *serial) return 0; } -static int ir_open(struct tty_struct *tty, struct usb_serial_port *port) +static int ir_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp) { char *buffer; int result = 0; diff --git a/trunk/drivers/usb/serial/iuu_phoenix.c b/trunk/drivers/usb/serial/iuu_phoenix.c index 6138c1cda35f..96873a7a32b0 100644 --- a/trunk/drivers/usb/serial/iuu_phoenix.c +++ b/trunk/drivers/usb/serial/iuu_phoenix.c @@ -71,6 +71,7 @@ struct iuu_private { spinlock_t lock; /* store irq state */ wait_queue_head_t delta_msr_wait; u8 line_status; + u8 termios_initialized; int tiostatus; /* store IUART SIGNAL for tiocmget call */ u8 reset; /* if 1 reset is needed */ int poll; /* number of poll */ @@ -1017,24 +1018,14 @@ static void iuu_close(struct usb_serial_port *port) } } -static void iuu_init_termios(struct tty_struct *tty) -{ - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600 - | TIOCM_CTS | CSTOPB | PARENB; - tty->termios->c_ispeed = 9600; - tty->termios->c_ospeed = 9600; - tty->termios->c_lflag = 0; - tty->termios->c_oflag = 0; - tty->termios->c_iflag = 0; -} - -static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) +static int iuu_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp) { struct usb_serial *serial = port->serial; u8 *buf; int result; u32 actual; + unsigned long flags; struct iuu_private *priv = usb_get_serial_port_data(port); dbg("%s - port %d", __func__, port->number); @@ -1073,7 +1064,21 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) port->bulk_in_buffer, 512, NULL, NULL); - priv->poll = 0; + /* set the termios structure */ + spin_lock_irqsave(&priv->lock, flags); + if (tty && !priv->termios_initialized) { + *(tty->termios) = tty_std_termios; + tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600 + | TIOCM_CTS | CSTOPB | PARENB; + tty->termios->c_ispeed = 9600; + tty->termios->c_ospeed = 9600; + tty->termios->c_lflag = 0; + tty->termios->c_oflag = 0; + tty->termios->c_iflag = 0; + priv->termios_initialized = 1; + priv->poll = 0; + } + spin_unlock_irqrestore(&priv->lock, flags); /* initialize writebuf */ #define FISH(a, b, c, d) do { \ @@ -1196,7 +1201,6 @@ static struct usb_serial_driver iuu_device = { .tiocmget = iuu_tiocmget, .tiocmset = iuu_tiocmset, .set_termios = iuu_set_termios, - .init_termios = iuu_init_termios, .attach = iuu_startup, .release = iuu_release, }; diff --git a/trunk/drivers/usb/serial/keyspan.c b/trunk/drivers/usb/serial/keyspan.c index f8c4b07033ff..2594b8743d3f 100644 --- a/trunk/drivers/usb/serial/keyspan.c +++ b/trunk/drivers/usb/serial/keyspan.c @@ -1209,7 +1209,8 @@ static int keyspan_write_room(struct tty_struct *tty) } -static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port) +static int keyspan_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp) { struct keyspan_port_private *p_priv; struct keyspan_serial_private *s_priv; diff --git a/trunk/drivers/usb/serial/keyspan.h b/trunk/drivers/usb/serial/keyspan.h index 30771e5b3973..3107ed15af64 100644 --- a/trunk/drivers/usb/serial/keyspan.h +++ b/trunk/drivers/usb/serial/keyspan.h @@ -36,7 +36,8 @@ /* Function prototypes for Keyspan serial converter */ static int keyspan_open (struct tty_struct *tty, - struct usb_serial_port *port); + struct usb_serial_port *port, + struct file *filp); static void keyspan_close (struct usb_serial_port *port); static void keyspan_dtr_rts (struct usb_serial_port *port, int on); static int keyspan_startup (struct usb_serial *serial); diff --git a/trunk/drivers/usb/serial/keyspan_pda.c b/trunk/drivers/usb/serial/keyspan_pda.c index 257c16cc6b2a..d0b12e40c2b1 100644 --- a/trunk/drivers/usb/serial/keyspan_pda.c +++ b/trunk/drivers/usb/serial/keyspan_pda.c @@ -681,7 +681,7 @@ static int keyspan_pda_carrier_raised(struct usb_serial_port *port) static int keyspan_pda_open(struct tty_struct *tty, - struct usb_serial_port *port) + struct usb_serial_port *port, struct file *filp) { struct usb_serial *serial = port->serial; unsigned char room; diff --git a/trunk/drivers/usb/serial/kl5kusb105.c b/trunk/drivers/usb/serial/kl5kusb105.c index a61673133d7d..0f44bb8e8d4f 100644 --- a/trunk/drivers/usb/serial/kl5kusb105.c +++ b/trunk/drivers/usb/serial/kl5kusb105.c @@ -75,7 +75,8 @@ static int debug; static int klsi_105_startup(struct usb_serial *serial); static void klsi_105_disconnect(struct usb_serial *serial); static void klsi_105_release(struct usb_serial *serial); -static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port); +static int klsi_105_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp); static void klsi_105_close(struct usb_serial_port *port); static int klsi_105_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); @@ -357,7 +358,8 @@ static void klsi_105_release(struct usb_serial *serial) } } /* klsi_105_release */ -static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) +static int klsi_105_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp) { struct klsi_105_private *priv = usb_get_serial_port_data(port); int retval = 0; @@ -369,6 +371,10 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) dbg("%s port %d", __func__, port->number); + /* force low_latency on so that our tty_push actually forces + * the data through + * tty->low_latency = 1; */ + /* Do a defined restart: * Set up sane default baud rate and send the 'READ_ON' * vendor command. diff --git a/trunk/drivers/usb/serial/kobil_sct.c b/trunk/drivers/usb/serial/kobil_sct.c index 45ea694b3ae6..6db0e561f680 100644 --- a/trunk/drivers/usb/serial/kobil_sct.c +++ b/trunk/drivers/usb/serial/kobil_sct.c @@ -70,7 +70,8 @@ static int debug; /* Function prototypes */ static int kobil_startup(struct usb_serial *serial); static void kobil_release(struct usb_serial *serial); -static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port); +static int kobil_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp); static void kobil_close(struct usb_serial_port *port); static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); @@ -84,7 +85,7 @@ static void kobil_read_int_callback(struct urb *urb); static void kobil_write_callback(struct urb *purb); static void kobil_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); -static void kobil_init_termios(struct tty_struct *tty); + static struct usb_device_id id_table [] = { { USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_B_PRODUCT_ID) }, @@ -119,7 +120,6 @@ static struct usb_serial_driver kobil_device = { .release = kobil_release, .ioctl = kobil_ioctl, .set_termios = kobil_set_termios, - .init_termios = kobil_init_termios, .tiocmget = kobil_tiocmget, .tiocmset = kobil_tiocmset, .open = kobil_open, @@ -210,17 +210,9 @@ static void kobil_release(struct usb_serial *serial) kfree(usb_get_serial_port_data(serial->port[i])); } -static void kobil_init_termios(struct tty_struct *tty) -{ - /* Default to echo off and other sane device settings */ - tty->termios->c_lflag = 0; - tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE); - tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF; - /* do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) */ - tty->termios->c_oflag &= ~ONLCR; -} -static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) +static int kobil_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp) { int result = 0; struct kobil_private *priv; @@ -234,6 +226,16 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) /* someone sets the dev to 0 if the close method has been called */ port->interrupt_in_urb->dev = port->serial->dev; + if (tty) { + + /* Default to echo off and other sane device settings */ + tty->termios->c_lflag = 0; + tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN | + XCASE); + tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF; + /* do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) */ + tty->termios->c_oflag &= ~ONLCR; + } /* allocate memory for transfer buffer */ transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL); if (!transfer_buffer) diff --git a/trunk/drivers/usb/serial/mct_u232.c b/trunk/drivers/usb/serial/mct_u232.c index ad4998bbf16f..d8825e159aa5 100644 --- a/trunk/drivers/usb/serial/mct_u232.c +++ b/trunk/drivers/usb/serial/mct_u232.c @@ -93,7 +93,8 @@ static int debug; */ static int mct_u232_startup(struct usb_serial *serial); static void mct_u232_release(struct usb_serial *serial); -static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port); +static int mct_u232_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp); static void mct_u232_close(struct usb_serial_port *port); static void mct_u232_dtr_rts(struct usb_serial_port *port, int on); static void mct_u232_read_int_callback(struct urb *urb); @@ -420,7 +421,8 @@ static void mct_u232_release(struct usb_serial *serial) } } /* mct_u232_release */ -static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port) +static int mct_u232_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp) { struct usb_serial *serial = port->serial; struct mct_u232_private *priv = usb_get_serial_port_data(port); @@ -566,13 +568,10 @@ static void mct_u232_read_int_callback(struct urb *urb) * Work-a-round: handle the 'usual' bulk-in pipe here */ if (urb->transfer_buffer_length > 2) { + tty = tty_port_tty_get(&port->port); if (urb->actual_length) { - tty = tty_port_tty_get(&port->port); - if (tty) { - tty_insert_flip_string(tty, data, - urb->actual_length); - tty_flip_buffer_push(tty); - } + tty_insert_flip_string(tty, data, urb->actual_length); + tty_flip_buffer_push(tty); tty_kref_put(tty); } goto exit; diff --git a/trunk/drivers/usb/serial/mos7720.c b/trunk/drivers/usb/serial/mos7720.c index 763e32a44be0..ccd4dd340d2c 100644 --- a/trunk/drivers/usb/serial/mos7720.c +++ b/trunk/drivers/usb/serial/mos7720.c @@ -85,7 +85,7 @@ static int debug; #define MOSCHIP_DEVICE_ID_7720 0x7720 #define MOSCHIP_DEVICE_ID_7715 0x7715 -static struct usb_device_id moschip_port_id_table[] = { +static struct usb_device_id moschip_port_id_table [] = { { USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7720) }, { } /* terminating entry */ }; @@ -319,7 +319,8 @@ static int send_mos_cmd(struct usb_serial *serial, __u8 request, __u16 value, return status; } -static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port) +static int mos7720_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp) { struct usb_serial *serial; struct usb_serial_port *port0; @@ -377,14 +378,10 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port) /* Initialize MCS7720 -- Write Init values to corresponding Registers * * Register Index - * 0 : THR/RHR * 1 : IER * 2 : FCR * 3 : LCR * 4 : MCR - * 5 : LSR - * 6 : MSR - * 7 : SPR * * 0x08 : SP1/2 Control Reg */ @@ -1253,88 +1250,20 @@ static void mos7720_set_termios(struct tty_struct *tty, static int get_lsr_info(struct tty_struct *tty, struct moschip_port *mos7720_port, unsigned int __user *value) { - struct usb_serial_port *port = tty->driver_data; - unsigned int result = 0; - unsigned char data = 0; - int port_number = port->number - port->serial->minor; int count; + unsigned int result = 0; count = mos7720_chars_in_buffer(tty); if (count == 0) { - send_mos_cmd(port->serial, MOS_READ, port_number, - UART_LSR, &data); - if ((data & (UART_LSR_TEMT | UART_LSR_THRE)) - == (UART_LSR_TEMT | UART_LSR_THRE)) { - dbg("%s -- Empty", __func__); - result = TIOCSER_TEMT; - } + dbg("%s -- Empty", __func__); + result = TIOCSER_TEMT; } + if (copy_to_user(value, &result, sizeof(int))) return -EFAULT; return 0; } -static int mos7720_tiocmget(struct tty_struct *tty, struct file *file) -{ - struct usb_serial_port *port = tty->driver_data; - struct moschip_port *mos7720_port = usb_get_serial_port_data(port); - unsigned int result = 0; - unsigned int mcr ; - unsigned int msr ; - - dbg("%s - port %d", __func__, port->number); - - mcr = mos7720_port->shadowMCR; - msr = mos7720_port->shadowMSR; - - result = ((mcr & UART_MCR_DTR) ? TIOCM_DTR : 0) /* 0x002 */ - | ((mcr & UART_MCR_RTS) ? TIOCM_RTS : 0) /* 0x004 */ - | ((msr & UART_MSR_CTS) ? TIOCM_CTS : 0) /* 0x020 */ - | ((msr & UART_MSR_DCD) ? TIOCM_CAR : 0) /* 0x040 */ - | ((msr & UART_MSR_RI) ? TIOCM_RI : 0) /* 0x080 */ - | ((msr & UART_MSR_DSR) ? TIOCM_DSR : 0); /* 0x100 */ - - dbg("%s -- %x", __func__, result); - - return result; -} - -static int mos7720_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct moschip_port *mos7720_port = usb_get_serial_port_data(port); - unsigned int mcr ; - unsigned char lmcr; - - dbg("%s - port %d", __func__, port->number); - dbg("he was at tiocmget"); - - mcr = mos7720_port->shadowMCR; - - if (set & TIOCM_RTS) - mcr |= UART_MCR_RTS; - if (set & TIOCM_DTR) - mcr |= UART_MCR_DTR; - if (set & TIOCM_LOOP) - mcr |= UART_MCR_LOOP; - - if (clear & TIOCM_RTS) - mcr &= ~UART_MCR_RTS; - if (clear & TIOCM_DTR) - mcr &= ~UART_MCR_DTR; - if (clear & TIOCM_LOOP) - mcr &= ~UART_MCR_LOOP; - - mos7720_port->shadowMCR = mcr; - lmcr = mos7720_port->shadowMCR; - - send_mos_cmd(port->serial, MOS_WRITE, - port->number - port->serial->minor, UART_MCR, &lmcr); - - return 0; -} - static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd, unsigned int __user *value) { @@ -1372,6 +1301,14 @@ static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd, mcr &= ~UART_MCR_LOOP; break; + case TIOCMSET: + /* turn off the RTS and DTR and LOOPBACK + * and then only turn on what was asked to */ + mcr &= ~(UART_MCR_RTS | UART_MCR_DTR | UART_MCR_LOOP); + mcr |= ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0); + mcr |= ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0); + mcr |= ((arg & TIOCM_LOOP) ? UART_MCR_LOOP : 0); + break; } mos7720_port->shadowMCR = mcr; @@ -1383,6 +1320,28 @@ static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd, return 0; } +static int get_modem_info(struct moschip_port *mos7720_port, + unsigned int __user *value) +{ + unsigned int result = 0; + unsigned int msr = mos7720_port->shadowMSR; + unsigned int mcr = mos7720_port->shadowMCR; + + result = ((mcr & UART_MCR_DTR) ? TIOCM_DTR: 0) /* 0x002 */ + | ((mcr & UART_MCR_RTS) ? TIOCM_RTS: 0) /* 0x004 */ + | ((msr & UART_MSR_CTS) ? TIOCM_CTS: 0) /* 0x020 */ + | ((msr & UART_MSR_DCD) ? TIOCM_CAR: 0) /* 0x040 */ + | ((msr & UART_MSR_RI) ? TIOCM_RI: 0) /* 0x080 */ + | ((msr & UART_MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */ + + + dbg("%s -- %x", __func__, result); + + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + return 0; +} + static int get_serial_info(struct moschip_port *mos7720_port, struct serial_struct __user *retinfo) { @@ -1433,11 +1392,17 @@ static int mos7720_ioctl(struct tty_struct *tty, struct file *file, /* FIXME: These should be using the mode methods */ case TIOCMBIS: case TIOCMBIC: + case TIOCMSET: dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __func__, port->number); return set_modem_info(mos7720_port, cmd, (unsigned int __user *)arg); + case TIOCMGET: + dbg("%s (%d) TIOCMGET", __func__, port->number); + return get_modem_info(mos7720_port, + (unsigned int __user *)arg); + case TIOCGSERIAL: dbg("%s (%d) TIOCGSERIAL", __func__, port->number); return get_serial_info(mos7720_port, @@ -1592,8 +1557,6 @@ static struct usb_serial_driver moschip7720_2port_driver = { .attach = mos7720_startup, .release = mos7720_release, .ioctl = mos7720_ioctl, - .tiocmget = mos7720_tiocmget, - .tiocmset = mos7720_tiocmset, .set_termios = mos7720_set_termios, .write = mos7720_write, .write_room = mos7720_write_room, diff --git a/trunk/drivers/usb/serial/mos7840.c b/trunk/drivers/usb/serial/mos7840.c index f11abf52be7d..270009afdf77 100644 --- a/trunk/drivers/usb/serial/mos7840.c +++ b/trunk/drivers/usb/serial/mos7840.c @@ -824,7 +824,8 @@ static int mos7840_serial_probe(struct usb_serial *serial, * Otherwise we return a negative error number. *****************************************************************************/ -static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) +static int mos7840_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp) { int response; int j; @@ -2132,6 +2133,106 @@ static int mos7840_get_lsr_info(struct tty_struct *tty, return 0; } +/***************************************************************************** + * mos7840_set_modem_info + * function to set modem info + *****************************************************************************/ + +/* FIXME: Should be using the model control hooks */ + +static int mos7840_set_modem_info(struct moschip_port *mos7840_port, + unsigned int cmd, unsigned int __user *value) +{ + unsigned int mcr; + unsigned int arg; + __u16 Data; + int status; + struct usb_serial_port *port; + + if (mos7840_port == NULL) + return -1; + + port = (struct usb_serial_port *)mos7840_port->port; + if (mos7840_port_paranoia_check(port, __func__)) { + dbg("%s", "Invalid port"); + return -1; + } + + mcr = mos7840_port->shadowMCR; + + if (copy_from_user(&arg, value, sizeof(int))) + return -EFAULT; + + switch (cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS) + mcr |= MCR_RTS; + if (arg & TIOCM_DTR) + mcr |= MCR_RTS; + if (arg & TIOCM_LOOP) + mcr |= MCR_LOOPBACK; + break; + + case TIOCMBIC: + if (arg & TIOCM_RTS) + mcr &= ~MCR_RTS; + if (arg & TIOCM_DTR) + mcr &= ~MCR_RTS; + if (arg & TIOCM_LOOP) + mcr &= ~MCR_LOOPBACK; + break; + + case TIOCMSET: + /* turn off the RTS and DTR and LOOPBACK + * and then only turn on what was asked to */ + mcr &= ~(MCR_RTS | MCR_DTR | MCR_LOOPBACK); + mcr |= ((arg & TIOCM_RTS) ? MCR_RTS : 0); + mcr |= ((arg & TIOCM_DTR) ? MCR_DTR : 0); + mcr |= ((arg & TIOCM_LOOP) ? MCR_LOOPBACK : 0); + break; + } + + lock_kernel(); + mos7840_port->shadowMCR = mcr; + + Data = mos7840_port->shadowMCR; + status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data); + unlock_kernel(); + if (status < 0) { + dbg("setting MODEM_CONTROL_REGISTER Failed"); + return -1; + } + + return 0; +} + +/***************************************************************************** + * mos7840_get_modem_info + * function to get modem info + *****************************************************************************/ + +static int mos7840_get_modem_info(struct moschip_port *mos7840_port, + unsigned int __user *value) +{ + unsigned int result = 0; + __u16 msr; + unsigned int mcr = mos7840_port->shadowMCR; + mos7840_get_uart_reg(mos7840_port->port, + MODEM_STATUS_REGISTER, &msr); + result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0) /* 0x002 */ + |((mcr & MCR_RTS) ? TIOCM_RTS : 0) /* 0x004 */ + |((msr & MOS7840_MSR_CTS) ? TIOCM_CTS : 0) /* 0x020 */ + |((msr & MOS7840_MSR_CD) ? TIOCM_CAR : 0) /* 0x040 */ + |((msr & MOS7840_MSR_RI) ? TIOCM_RI : 0) /* 0x080 */ + |((msr & MOS7840_MSR_DSR) ? TIOCM_DSR : 0); /* 0x100 */ + + dbg("%s -- %x", __func__, result); + + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + return 0; +} + /***************************************************************************** * mos7840_get_serial_info * function to get information about serial port @@ -2180,6 +2281,7 @@ static int mos7840_ioctl(struct tty_struct *tty, struct file *file, struct async_icount cnow; struct async_icount cprev; struct serial_icounter_struct icount; + int mosret = 0; if (mos7840_port_paranoia_check(port, __func__)) { dbg("%s", "Invalid port"); @@ -2201,6 +2303,20 @@ static int mos7840_ioctl(struct tty_struct *tty, struct file *file, return mos7840_get_lsr_info(tty, argp); return 0; + /* FIXME: use the modem hooks and remove this */ + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __func__, + port->number); + mosret = + mos7840_set_modem_info(mos7840_port, cmd, argp); + return mosret; + + case TIOCMGET: + dbg("%s (%d) TIOCMGET", __func__, port->number); + return mos7840_get_modem_info(mos7840_port, argp); + case TIOCGSERIAL: dbg("%s (%d) TIOCGSERIAL", __func__, port->number); return mos7840_get_serial_info(mos7840_port, argp); diff --git a/trunk/drivers/usb/serial/navman.c b/trunk/drivers/usb/serial/navman.c index 5ceaa4c6be09..f5f3751a888c 100644 --- a/trunk/drivers/usb/serial/navman.c +++ b/trunk/drivers/usb/serial/navman.c @@ -80,7 +80,8 @@ static void navman_read_int_callback(struct urb *urb) __func__, result); } -static int navman_open(struct tty_struct *tty, struct usb_serial_port *port) +static int navman_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp) { int result = 0; diff --git a/trunk/drivers/usb/serial/omninet.c b/trunk/drivers/usb/serial/omninet.c index 062265038bf0..56857ddbd70b 100644 --- a/trunk/drivers/usb/serial/omninet.c +++ b/trunk/drivers/usb/serial/omninet.c @@ -64,7 +64,8 @@ static int debug; #define BT_IGNITIONPRO_ID 0x2000 /* function prototypes */ -static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port); +static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port, + struct file *filp); static void omninet_close(struct usb_serial_port *port); static void omninet_read_bulk_callback(struct urb *urb); static void omninet_write_bulk_callback(struct urb *urb); @@ -162,7 +163,8 @@ static int omninet_attach(struct usb_serial *serial) return 0; } -static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port) +static int omninet_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp) { struct usb_serial *serial = port->serial; struct usb_serial_port *wport; diff --git a/trunk/drivers/usb/serial/opticon.c b/trunk/drivers/usb/serial/opticon.c index 1085a577c5c1..336bba79ad32 100644 --- a/trunk/drivers/usb/serial/opticon.c +++ b/trunk/drivers/usb/serial/opticon.c @@ -144,7 +144,8 @@ static void opticon_bulk_callback(struct urb *urb) spin_unlock(&priv->lock); } -static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port) +static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port, + struct file *filp) { struct opticon_private *priv = usb_get_serial_data(port->serial); unsigned long flags; diff --git a/trunk/drivers/usb/serial/option.c b/trunk/drivers/usb/serial/option.c index fe47051dbef2..c784ddbe7b61 100644 --- a/trunk/drivers/usb/serial/option.c +++ b/trunk/drivers/usb/serial/option.c @@ -45,7 +45,8 @@ /* Function prototypes */ static int option_probe(struct usb_serial *serial, const struct usb_device_id *id); -static int option_open(struct tty_struct *tty, struct usb_serial_port *port); +static int option_open(struct tty_struct *tty, struct usb_serial_port *port, + struct file *filp); static void option_close(struct usb_serial_port *port); static void option_dtr_rts(struct usb_serial_port *port, int on); @@ -960,7 +961,8 @@ static int option_chars_in_buffer(struct tty_struct *tty) return data_len; } -static int option_open(struct tty_struct *tty, struct usb_serial_port *port) +static int option_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp) { struct option_port_private *portdata; int i, err; diff --git a/trunk/drivers/usb/serial/oti6858.c b/trunk/drivers/usb/serial/oti6858.c index 0f4a70ce3823..3cece27325e7 100644 --- a/trunk/drivers/usb/serial/oti6858.c +++ b/trunk/drivers/usb/serial/oti6858.c @@ -141,11 +141,11 @@ struct oti6858_control_pkt { && ((a)->frame_fmt == (priv)->pending_setup.frame_fmt)) /* function prototypes */ -static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port); +static int oti6858_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp); static void oti6858_close(struct usb_serial_port *port); static void oti6858_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); -static void oti6858_init_termios(struct tty_struct *tty); static int oti6858_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); static void oti6858_read_int_callback(struct urb *urb); @@ -186,7 +186,6 @@ static struct usb_serial_driver oti6858_device = { .write = oti6858_write, .ioctl = oti6858_ioctl, .set_termios = oti6858_set_termios, - .init_termios = oti6858_init_termios, .tiocmget = oti6858_tiocmget, .tiocmset = oti6858_tiocmset, .read_bulk_callback = oti6858_read_bulk_callback, @@ -207,6 +206,7 @@ struct oti6858_private { struct { u8 read_urb_in_use; u8 write_urb_in_use; + u8 termios_initialized; } flags; struct delayed_work delayed_write_work; @@ -447,14 +447,6 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty) return chars; } -static void oti6858_init_termios(struct tty_struct *tty) -{ - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL; - tty->termios->c_ispeed = 38400; - tty->termios->c_ospeed = 38400; -} - static void oti6858_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { @@ -472,6 +464,16 @@ static void oti6858_set_termios(struct tty_struct *tty, return; } + spin_lock_irqsave(&priv->lock, flags); + if (!priv->flags.termios_initialized) { + *(tty->termios) = tty_std_termios; + tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL; + tty->termios->c_ispeed = 38400; + tty->termios->c_ospeed = 38400; + priv->flags.termios_initialized = 1; + } + spin_unlock_irqrestore(&priv->lock, flags); + cflag = tty->termios->c_cflag; spin_lock_irqsave(&priv->lock, flags); @@ -564,7 +566,8 @@ static void oti6858_set_termios(struct tty_struct *tty, spin_unlock_irqrestore(&priv->lock, flags); } -static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port) +static int oti6858_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp) { struct oti6858_private *priv = usb_get_serial_port_data(port); struct ktermios tmp_termios; diff --git a/trunk/drivers/usb/serial/pl2303.c b/trunk/drivers/usb/serial/pl2303.c index a63ea99936f7..3e86815b2705 100644 --- a/trunk/drivers/usb/serial/pl2303.c +++ b/trunk/drivers/usb/serial/pl2303.c @@ -691,7 +691,8 @@ static void pl2303_close(struct usb_serial_port *port) } -static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port) +static int pl2303_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp) { struct ktermios tmp_termios; struct usb_serial *serial = port->serial; @@ -713,6 +714,8 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port) if (tty) pl2303_set_termios(tty, port, &tmp_termios); + /* FIXME: need to assert RTS and DTR if CRTSCTS off */ + dbg("%s - submitting read urb", __func__); port->read_urb->dev = serial->dev; result = usb_submit_urb(port->read_urb, GFP_KERNEL); diff --git a/trunk/drivers/usb/serial/sierra.c b/trunk/drivers/usb/serial/sierra.c index 55391bbe1230..f48d05e0acc1 100644 --- a/trunk/drivers/usb/serial/sierra.c +++ b/trunk/drivers/usb/serial/sierra.c @@ -734,7 +734,8 @@ static void sierra_close(struct usb_serial_port *port) } } -static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port) +static int sierra_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp) { struct sierra_port_private *portdata; struct usb_serial *serial = port->serial; diff --git a/trunk/drivers/usb/serial/spcp8x5.c b/trunk/drivers/usb/serial/spcp8x5.c index 61e7c40b94fb..3c249d8e8b8e 100644 --- a/trunk/drivers/usb/serial/spcp8x5.c +++ b/trunk/drivers/usb/serial/spcp8x5.c @@ -299,6 +299,7 @@ struct spcp8x5_private { wait_queue_head_t delta_msr_wait; u8 line_control; u8 line_status; + u8 termios_initialized; }; /* desc : when device plug in,this function would be called. @@ -497,15 +498,6 @@ static void spcp8x5_close(struct usb_serial_port *port) dev_dbg(&port->dev, "usb_unlink_urb(read_urb) = %d\n", result); } -static void spcp8x5_init_termios(struct tty_struct *tty) -{ - /* for the 1st time call this function */ - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; - tty->termios->c_ispeed = 115200; - tty->termios->c_ospeed = 115200; -} - /* set the serial param for transfer. we should check if we really need to * transfer. if we set flow control we should do this too. */ static void spcp8x5_set_termios(struct tty_struct *tty, @@ -522,6 +514,16 @@ static void spcp8x5_set_termios(struct tty_struct *tty, int i; u8 control; + /* for the 1st time call this function */ + spin_lock_irqsave(&priv->lock, flags); + if (!priv->termios_initialized) { + *(tty->termios) = tty_std_termios; + tty->termios->c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; + tty->termios->c_ispeed = 115200; + tty->termios->c_ospeed = 115200; + priv->termios_initialized = 1; + } + spin_unlock_irqrestore(&priv->lock, flags); /* check that they really want us to change something */ if (!tty_termios_hw_change(tty->termios, old_termios)) @@ -621,7 +623,8 @@ static void spcp8x5_set_termios(struct tty_struct *tty, /* open the serial port. do some usb system call. set termios and get the line * status of the device. then submit the read urb */ -static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port) +static int spcp8x5_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp) { struct ktermios tmp_termios; struct usb_serial *serial = port->serial; @@ -655,6 +658,8 @@ static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port) priv->line_status = status & 0xf0 ; spin_unlock_irqrestore(&priv->lock, flags); + /* FIXME: need to assert RTS and DTR if CRTSCTS off */ + dbg("%s - submitting read urb", __func__); port->read_urb->dev = serial->dev; ret = usb_submit_urb(port->read_urb, GFP_KERNEL); @@ -1006,7 +1011,6 @@ static struct usb_serial_driver spcp8x5_device = { .carrier_raised = spcp8x5_carrier_raised, .write = spcp8x5_write, .set_termios = spcp8x5_set_termios, - .init_termios = spcp8x5_init_termios, .ioctl = spcp8x5_ioctl, .tiocmget = spcp8x5_tiocmget, .tiocmset = spcp8x5_tiocmset, diff --git a/trunk/drivers/usb/serial/symbolserial.c b/trunk/drivers/usb/serial/symbolserial.c index cb7e95f9fcbf..6157fac9366b 100644 --- a/trunk/drivers/usb/serial/symbolserial.c +++ b/trunk/drivers/usb/serial/symbolserial.c @@ -124,7 +124,8 @@ static void symbol_int_callback(struct urb *urb) spin_unlock(&priv->lock); } -static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port) +static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port, + struct file *filp) { struct symbol_private *priv = usb_get_serial_data(port->serial); unsigned long flags; diff --git a/trunk/drivers/usb/serial/ti_usb_3410_5052.c b/trunk/drivers/usb/serial/ti_usb_3410_5052.c index 1e9dc8821698..3bc609fe2242 100644 --- a/trunk/drivers/usb/serial/ti_usb_3410_5052.c +++ b/trunk/drivers/usb/serial/ti_usb_3410_5052.c @@ -98,7 +98,8 @@ struct ti_device { static int ti_startup(struct usb_serial *serial); static void ti_release(struct usb_serial *serial); -static int ti_open(struct tty_struct *tty, struct usb_serial_port *port); +static int ti_open(struct tty_struct *tty, struct usb_serial_port *port, + struct file *file); static void ti_close(struct usb_serial_port *port); static int ti_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *data, int count); @@ -491,7 +492,8 @@ static void ti_release(struct usb_serial *serial) } -static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) +static int ti_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *file) { struct ti_port *tport = usb_get_serial_port_data(port); struct ti_device *tdev; diff --git a/trunk/drivers/usb/serial/usb-serial.c b/trunk/drivers/usb/serial/usb-serial.c index 9d7ca4868d37..99188c92068b 100644 --- a/trunk/drivers/usb/serial/usb-serial.c +++ b/trunk/drivers/usb/serial/usb-serial.c @@ -43,6 +43,8 @@ #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/" #define DRIVER_DESC "USB Serial Driver core" +static void port_free(struct usb_serial_port *port); + /* Driver structure we register with the USB core */ static struct usb_driver usb_serial_driver = { .name = "usbserial", @@ -66,11 +68,6 @@ static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; static DEFINE_MUTEX(table_lock); static LIST_HEAD(usb_serial_driver_list); -/* - * Look up the serial structure. If it is found and it hasn't been - * disconnected, return with its disc_mutex held and its refcount - * incremented. Otherwise return NULL. - */ struct usb_serial *usb_serial_get_by_index(unsigned index) { struct usb_serial *serial; @@ -78,15 +75,8 @@ struct usb_serial *usb_serial_get_by_index(unsigned index) mutex_lock(&table_lock); serial = serial_table[index]; - if (serial) { - mutex_lock(&serial->disc_mutex); - if (serial->disconnected) { - mutex_unlock(&serial->disc_mutex); - serial = NULL; - } else { - kref_get(&serial->kref); - } - } + if (serial) + kref_get(&serial->kref); mutex_unlock(&table_lock); return serial; } @@ -135,10 +125,8 @@ static void return_serial(struct usb_serial *serial) dbg("%s", __func__); - mutex_lock(&table_lock); for (i = 0; i < serial->num_ports; ++i) serial_table[serial->minor + i] = NULL; - mutex_unlock(&table_lock); } static void destroy_serial(struct kref *kref) @@ -157,157 +145,161 @@ static void destroy_serial(struct kref *kref) serial->type->release(serial); - /* Now that nothing is using the ports, they can be freed */ - for (i = 0; i < serial->num_port_pointers; ++i) { + for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; - if (port) { - port->serial = NULL; + if (port) put_device(&port->dev); + } + + /* If this is a "fake" port, we have to clean it up here, as it will + * not get cleaned up in port_release() as it was never registered with + * the driver core */ + if (serial->num_ports < serial->num_port_pointers) { + for (i = serial->num_ports; + i < serial->num_port_pointers; ++i) { + port = serial->port[i]; + if (port) + port_free(port); } } usb_put_dev(serial->dev); + + /* free up any memory that we allocated */ kfree(serial); } void usb_serial_put(struct usb_serial *serial) { + mutex_lock(&table_lock); kref_put(&serial->kref, destroy_serial); + mutex_unlock(&table_lock); } /***************************************************************************** * Driver tty interface functions *****************************************************************************/ - -/** - * serial_install - install tty - * @driver: the driver (USB in our case) - * @tty: the tty being created - * - * Create the termios objects for this tty. We use the default - * USB serial settings but permit them to be overridden by - * serial->type->init_termios. - * - * This is the first place a new tty gets used. Hence this is where we - * acquire references to the usb_serial structure and the driver module, - * where we store a pointer to the port, and where we do an autoresume. - * All these actions are reversed in serial_release(). - */ -static int serial_install(struct tty_driver *driver, struct tty_struct *tty) +static int serial_open (struct tty_struct *tty, struct file *filp) { - int idx = tty->index; struct usb_serial *serial; struct usb_serial_port *port; - int retval = -ENODEV; + unsigned int portNumber; + int retval = 0; + int first = 0; dbg("%s", __func__); - serial = usb_serial_get_by_index(idx); - if (!serial) - return retval; - - port = serial->port[idx - serial->minor]; - if (!port) - goto error_no_port; - if (!try_module_get(serial->type->driver.owner)) - goto error_module_get; - - /* perform the standard setup */ - retval = tty_init_termios(tty); - if (retval) - goto error_init_termios; + /* get the serial object associated with this tty pointer */ + serial = usb_serial_get_by_index(tty->index); + if (!serial) { + tty->driver_data = NULL; + return -ENODEV; + } - retval = usb_autopm_get_interface(serial->interface); + mutex_lock(&serial->disc_mutex); + portNumber = tty->index - serial->minor; + port = serial->port[portNumber]; + if (!port || serial->disconnected) + retval = -ENODEV; + else + get_device(&port->dev); + /* + * Note: Our locking order requirement does not allow port->mutex + * to be acquired while serial->disc_mutex is held. + */ + mutex_unlock(&serial->disc_mutex); if (retval) - goto error_get_interface; + goto bailout_serial_put; - mutex_unlock(&serial->disc_mutex); + if (mutex_lock_interruptible(&port->mutex)) { + retval = -ERESTARTSYS; + goto bailout_port_put; + } - /* allow the driver to update the settings */ - if (serial->type->init_termios) - serial->type->init_termios(tty); + ++port->port.count; + /* set up our port structure making the tty driver + * remember our port object, and us it */ tty->driver_data = port; - - /* Final install (we use the default method) */ - tty_driver_kref_get(driver); - tty->count++; - driver->ttys[idx] = tty; - return retval; - - error_get_interface: - error_init_termios: - module_put(serial->type->driver.owner); - error_module_get: - error_no_port: - usb_serial_put(serial); - mutex_unlock(&serial->disc_mutex); - return retval; -} - -static int serial_open(struct tty_struct *tty, struct file *filp) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; - int retval; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irq(&port->port.lock); - if (!tty_hung_up_p(filp)) - ++port->port.count; - spin_unlock_irq(&port->port.lock); tty_port_tty_set(&port->port, tty); - /* Do the device-specific open only if the hardware isn't - * already initialized. - */ - if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) { - if (mutex_lock_interruptible(&port->mutex)) - return -ERESTARTSYS; + /* If the console is attached, the device is already open */ + if (port->port.count == 1 && !port->console) { + first = 1; + /* lock this module before we call it + * this may fail, which means we must bail out, + * safe because we are called with BKL held */ + if (!try_module_get(serial->type->driver.owner)) { + retval = -ENODEV; + goto bailout_mutex_unlock; + } + mutex_lock(&serial->disc_mutex); if (serial->disconnected) retval = -ENODEV; else - retval = port->serial->type->open(tty, port); - mutex_unlock(&serial->disc_mutex); - mutex_unlock(&port->mutex); + retval = usb_autopm_get_interface(serial->interface); if (retval) - return retval; + goto bailout_module_put; + + /* only call the device specific open if this + * is the first time the port is opened */ + retval = serial->type->open(tty, port, filp); + if (retval) + goto bailout_interface_put; + mutex_unlock(&serial->disc_mutex); set_bit(ASYNCB_INITIALIZED, &port->port.flags); } - + mutex_unlock(&port->mutex); /* Now do the correct tty layer semantics */ retval = tty_port_block_til_ready(&port->port, tty, filp); + if (retval == 0) { + if (!first) + usb_serial_put(serial); + return 0; + } + mutex_lock(&port->mutex); + if (first == 0) + goto bailout_mutex_unlock; + /* Undo the initial port actions */ + mutex_lock(&serial->disc_mutex); +bailout_interface_put: + usb_autopm_put_interface(serial->interface); +bailout_module_put: + mutex_unlock(&serial->disc_mutex); + module_put(serial->type->driver.owner); +bailout_mutex_unlock: + port->port.count = 0; + tty->driver_data = NULL; + tty_port_tty_set(&port->port, NULL); + mutex_unlock(&port->mutex); +bailout_port_put: + put_device(&port->dev); +bailout_serial_put: + usb_serial_put(serial); return retval; } /** - * serial_down - shut down hardware - * @port: port to shut down + * serial_do_down - shut down hardware + * @port: port to shut down + * + * Shut down a USB port unless it is the console. We never shut down the + * console hardware as it will always be in use. * - * Shut down a USB serial port unless it is the console. We never - * shut down the console hardware as it will always be in use. + * Don't free any resources at this point */ -static void serial_down(struct usb_serial_port *port) +static void serial_do_down(struct usb_serial_port *port) { struct usb_serial_driver *drv = port->serial->type; struct usb_serial *serial; struct module *owner; - /* - * The console is magical. Do not hang up the console hardware - * or there will be tears. - */ + /* The console is magical, do not hang up the console hardware + or there will be tears */ if (port->console) return; - /* Don't call the close method if the hardware hasn't been - * initialized. - */ - if (!test_and_clear_bit(ASYNCB_INITIALIZED, &port->port.flags)) - return; - mutex_lock(&port->mutex); serial = port->serial; owner = serial->type->driver.owner; @@ -318,69 +310,79 @@ static void serial_down(struct usb_serial_port *port) mutex_unlock(&port->mutex); } -static void serial_hangup(struct tty_struct *tty) +/** + * serial_do_free - free resources post close/hangup + * @port: port to free up + * + * Do the resource freeing and refcount dropping for the port. We must + * be careful about ordering and we must avoid freeing up the console. + */ + +static void serial_do_free(struct usb_serial_port *port) { - struct usb_serial_port *port = tty->driver_data; + struct usb_serial *serial; + struct module *owner; - dbg("%s - port %d", __func__, port->number); + /* The console is magical, do not hang up the console hardware + or there will be tears */ + if (port->console) + return; - serial_down(port); - tty_port_hangup(&port->port); + serial = port->serial; + owner = serial->type->driver.owner; + put_device(&port->dev); + /* Mustn't dereference port any more */ + mutex_lock(&serial->disc_mutex); + if (!serial->disconnected) + usb_autopm_put_interface(serial->interface); + mutex_unlock(&serial->disc_mutex); + usb_serial_put(serial); + /* Mustn't dereference serial any more */ + module_put(owner); } static void serial_close(struct tty_struct *tty, struct file *filp) { struct usb_serial_port *port = tty->driver_data; + if (!port) + return; + dbg("%s - port %d", __func__, port->number); - if (tty_hung_up_p(filp)) + /* FIXME: + This leaves a very narrow race. Really we should do the + serial_do_free() on tty->shutdown(), but tty->shutdown can + be called from IRQ context and serial_do_free can sleep. + + The right fix is probably to make the tty free (which is rare) + and thus tty->shutdown() occur via a work queue and simplify all + the drivers that use it. + */ + if (tty_hung_up_p(filp)) { + /* serial_hangup already called serial_down at this point. + Another user may have already reopened the port but + serial_do_free is refcounted */ + serial_do_free(port); return; + } + if (tty_port_close_start(&port->port, tty, filp) == 0) return; - serial_down(port); + + serial_do_down(port); tty_port_close_end(&port->port, tty); tty_port_tty_set(&port->port, NULL); + serial_do_free(port); } -/** - * serial_release - free resources post close/hangup - * @port: port to free up - * - * Do the resource freeing and refcount dropping for the port. - * Avoid freeing the console. - * - * Called when the last tty kref is dropped. - */ -static void serial_release(struct tty_struct *tty) +static void serial_hangup(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial; - struct module *owner; - - /* The console is magical. Do not hang up the console hardware - * or there will be tears. - */ - if (port->console) - return; - - dbg("%s - port %d", __func__, port->number); - - /* Standard shutdown processing */ - tty_shutdown(tty); - - tty->driver_data = NULL; - - serial = port->serial; - owner = serial->type->driver.owner; - - mutex_lock(&serial->disc_mutex); - if (!serial->disconnected) - usb_autopm_put_interface(serial->interface); - mutex_unlock(&serial->disc_mutex); - - usb_serial_put(serial); - module_put(owner); + serial_do_down(port); + tty_port_hangup(&port->port); + /* We must not free port yet - the USB serial layer depends on it's + continued existence */ } static int serial_write(struct tty_struct *tty, const unsigned char *buf, @@ -525,7 +527,6 @@ static int serial_proc_show(struct seq_file *m, void *v) seq_putc(m, '\n'); usb_serial_put(serial); - mutex_unlock(&serial->disc_mutex); } return 0; } @@ -595,6 +596,14 @@ static void usb_serial_port_work(struct work_struct *work) tty_kref_put(tty); } +static void port_release(struct device *dev) +{ + struct usb_serial_port *port = to_usb_serial_port(dev); + + dbg ("%s - %s", __func__, dev_name(dev)); + port_free(port); +} + static void kill_traffic(struct usb_serial_port *port) { usb_kill_urb(port->read_urb); @@ -614,12 +623,8 @@ static void kill_traffic(struct usb_serial_port *port) usb_kill_urb(port->interrupt_out_urb); } -static void port_release(struct device *dev) +static void port_free(struct usb_serial_port *port) { - struct usb_serial_port *port = to_usb_serial_port(dev); - - dbg ("%s - %s", __func__, dev_name(dev)); - /* * Stop all the traffic before cancelling the work, so that * nobody will restart it by calling usb_serial_port_softint. @@ -930,11 +935,6 @@ int usb_serial_probe(struct usb_interface *interface, mutex_init(&port->mutex); INIT_WORK(&port->work, usb_serial_port_work); serial->port[i] = port; - port->dev.parent = &interface->dev; - port->dev.driver = NULL; - port->dev.bus = &usb_serial_bus_type; - port->dev.release = &port_release; - device_initialize(&port->dev); } /* set up the endpoint information */ @@ -1077,10 +1077,15 @@ int usb_serial_probe(struct usb_interface *interface, /* register all of the individual ports with the driver core */ for (i = 0; i < num_ports; ++i) { port = serial->port[i]; + port->dev.parent = &interface->dev; + port->dev.driver = NULL; + port->dev.bus = &usb_serial_bus_type; + port->dev.release = &port_release; + dev_set_name(&port->dev, "ttyUSB%d", port->number); dbg ("%s - registering %s", __func__, dev_name(&port->dev)); port->dev_state = PORT_REGISTERING; - retval = device_add(&port->dev); + retval = device_register(&port->dev); if (retval) { dev_err(&port->dev, "Error registering port device, " "continuing\n"); @@ -1098,7 +1103,39 @@ int usb_serial_probe(struct usb_interface *interface, return 0; probe_error: - usb_serial_put(serial); + for (i = 0; i < num_bulk_in; ++i) { + port = serial->port[i]; + if (!port) + continue; + usb_free_urb(port->read_urb); + kfree(port->bulk_in_buffer); + } + for (i = 0; i < num_bulk_out; ++i) { + port = serial->port[i]; + if (!port) + continue; + usb_free_urb(port->write_urb); + kfree(port->bulk_out_buffer); + } + for (i = 0; i < num_interrupt_in; ++i) { + port = serial->port[i]; + if (!port) + continue; + usb_free_urb(port->interrupt_in_urb); + kfree(port->interrupt_in_buffer); + } + for (i = 0; i < num_interrupt_out; ++i) { + port = serial->port[i]; + if (!port) + continue; + usb_free_urb(port->interrupt_out_urb); + kfree(port->interrupt_out_buffer); + } + + /* free up any memory that we allocated */ + for (i = 0; i < serial->num_port_pointers; ++i) + kfree(serial->port[i]); + kfree(serial); return -EIO; } EXPORT_SYMBOL_GPL(usb_serial_probe); @@ -1124,7 +1161,10 @@ void usb_serial_disconnect(struct usb_interface *interface) if (port) { struct tty_struct *tty = tty_port_tty_get(&port->port); if (tty) { - tty_vhangup(tty); + /* The hangup will occur asynchronously but + the object refcounts will sort out all the + cleanup */ + tty_hangup(tty); tty_kref_put(tty); } kill_traffic(port); @@ -1149,7 +1189,8 @@ void usb_serial_disconnect(struct usb_interface *interface) } serial->type->disconnect(serial); - /* let the last holder of this object cause it to be cleaned up */ + /* let the last holder of this object + * cause it to be cleaned up */ usb_serial_put(serial); dev_info(dev, "device disconnected\n"); } @@ -1205,8 +1246,6 @@ static const struct tty_operations serial_ops = { .chars_in_buffer = serial_chars_in_buffer, .tiocmget = serial_tiocmget, .tiocmset = serial_tiocmset, - .shutdown = serial_release, - .install = serial_install, .proc_fops = &serial_proc_fops, }; diff --git a/trunk/drivers/usb/serial/usb_debug.c b/trunk/drivers/usb/serial/usb_debug.c index 7b5bfc4edd3d..614800972dc3 100644 --- a/trunk/drivers/usb/serial/usb_debug.c +++ b/trunk/drivers/usb/serial/usb_debug.c @@ -43,10 +43,11 @@ static struct usb_driver debug_driver = { .no_dynamic_id = 1, }; -static int usb_debug_open(struct tty_struct *tty, struct usb_serial_port *port) +static int usb_debug_open(struct tty_struct *tty, struct usb_serial_port *port, + struct file *filp) { port->bulk_out_size = USB_DEBUG_MAX_PACKET_SIZE; - return usb_serial_generic_open(tty, port); + return usb_serial_generic_open(tty, port, filp); } /* This HW really does not support a serial break, so one will be diff --git a/trunk/drivers/usb/serial/visor.c b/trunk/drivers/usb/serial/visor.c index 1aa5d20a5d99..f5d0f64dcc52 100644 --- a/trunk/drivers/usb/serial/visor.c +++ b/trunk/drivers/usb/serial/visor.c @@ -36,7 +36,8 @@ #define DRIVER_DESC "USB HandSpring Visor / Palm OS driver" /* function prototypes for a handspring visor */ -static int visor_open(struct tty_struct *tty, struct usb_serial_port *port); +static int visor_open(struct tty_struct *tty, struct usb_serial_port *port, + struct file *filp); static void visor_close(struct usb_serial_port *port); static int visor_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); @@ -272,7 +273,8 @@ static int stats; /****************************************************************************** * Handspring Visor specific driver functions ******************************************************************************/ -static int visor_open(struct tty_struct *tty, struct usb_serial_port *port) +static int visor_open(struct tty_struct *tty, struct usb_serial_port *port, + struct file *filp) { struct usb_serial *serial = port->serial; struct visor_private *priv = usb_get_serial_port_data(port); diff --git a/trunk/drivers/usb/serial/whiteheat.c b/trunk/drivers/usb/serial/whiteheat.c index 62424eec33ec..8d126dd7a02e 100644 --- a/trunk/drivers/usb/serial/whiteheat.c +++ b/trunk/drivers/usb/serial/whiteheat.c @@ -146,7 +146,7 @@ static int whiteheat_firmware_attach(struct usb_serial *serial); static int whiteheat_attach(struct usb_serial *serial); static void whiteheat_release(struct usb_serial *serial); static int whiteheat_open(struct tty_struct *tty, - struct usb_serial_port *port); + struct usb_serial_port *port, struct file *filp); static void whiteheat_close(struct usb_serial_port *port); static int whiteheat_write(struct tty_struct *tty, struct usb_serial_port *port, @@ -259,7 +259,7 @@ static int firm_send_command(struct usb_serial_port *port, __u8 command, __u8 *data, __u8 datasize); static int firm_open(struct usb_serial_port *port); static int firm_close(struct usb_serial_port *port); -static void firm_setup_port(struct tty_struct *tty); +static int firm_setup_port(struct tty_struct *tty); static int firm_set_rts(struct usb_serial_port *port, __u8 onoff); static int firm_set_dtr(struct usb_serial_port *port, __u8 onoff); static int firm_set_break(struct usb_serial_port *port, __u8 onoff); @@ -659,7 +659,8 @@ static void whiteheat_release(struct usb_serial *serial) return; } -static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port) +static int whiteheat_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp) { int retval = 0; @@ -1210,7 +1211,7 @@ static int firm_close(struct usb_serial_port *port) } -static void firm_setup_port(struct tty_struct *tty) +static int firm_setup_port(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct whiteheat_port_settings port_settings; @@ -1285,7 +1286,7 @@ static void firm_setup_port(struct tty_struct *tty) port_settings.lloop = 0; /* now send the message to the device */ - firm_send_command(port, WHITEHEAT_SETUP_PORT, + return firm_send_command(port, WHITEHEAT_SETUP_PORT, (__u8 *)&port_settings, sizeof(port_settings)); } diff --git a/trunk/include/linux/cyclades.h b/trunk/include/linux/cyclades.h index a5049eaf782d..1fbdea4f08eb 100644 --- a/trunk/include/linux/cyclades.h +++ b/trunk/include/linux/cyclades.h @@ -499,7 +499,6 @@ struct cyclades_card { void __iomem *p9050; struct RUNTIME_9060 __iomem *p9060; } ctl_addr; - struct BOARD_CTRL __iomem *board_ctrl; /* cyz specific */ int irq; unsigned int num_chips; /* 0 if card absent, -1 if Z/PCI, else Y */ unsigned int first_line; /* minor number of first channel on card */ @@ -542,15 +541,6 @@ struct cyclades_port { int magic; struct tty_port port; struct cyclades_card *card; - union { - struct { - void __iomem *base_addr; - } cyy; - struct { - struct CH_CTRL __iomem *ch_ctrl; - struct BUF_CTRL __iomem *buf_ctrl; - } cyz; - } u; int line; int flags; /* defined in tty.h */ int type; /* UART type */ @@ -578,6 +568,7 @@ struct cyclades_port { struct cyclades_idle_stats idle_stats; struct cyclades_icount icount; struct completion shutdown_wait; + wait_queue_head_t delta_msr_wait; int throttle; }; diff --git a/trunk/include/linux/device.h b/trunk/include/linux/device.h index aca31bf7d8ed..847b763e40e9 100644 --- a/trunk/include/linux/device.h +++ b/trunk/include/linux/device.h @@ -193,7 +193,7 @@ struct class { struct kobject *dev_kobj; int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env); - char *(*devnode)(struct device *dev, mode_t *mode); + char *(*nodename)(struct device *dev); void (*class_release)(struct class *class); void (*dev_release)(struct device *dev); @@ -298,7 +298,7 @@ struct device_type { const char *name; const struct attribute_group **groups; int (*uevent)(struct device *dev, struct kobj_uevent_env *env); - char *(*devnode)(struct device *dev, mode_t *mode); + char *(*nodename)(struct device *dev); void (*release)(struct device *dev); const struct dev_pm_ops *pm; @@ -487,8 +487,7 @@ extern struct device *device_find_child(struct device *dev, void *data, extern int device_rename(struct device *dev, char *new_name); extern int device_move(struct device *dev, struct device *new_parent, enum dpm_order dpm_order); -extern const char *device_get_devnode(struct device *dev, - mode_t *mode, const char **tmp); +extern const char *device_get_nodename(struct device *dev, const char **tmp); extern void *dev_get_drvdata(const struct device *dev); extern void dev_set_drvdata(struct device *dev, void *data); diff --git a/trunk/include/linux/genhd.h b/trunk/include/linux/genhd.h index 109d179adb93..44263cb27121 100644 --- a/trunk/include/linux/genhd.h +++ b/trunk/include/linux/genhd.h @@ -142,7 +142,7 @@ struct gendisk { * disks that can't be partitioned. */ char disk_name[DISK_NAME_LEN]; /* name of major driver */ - char *(*devnode)(struct gendisk *gd, mode_t *mode); + char *(*nodename)(struct gendisk *gd); /* Array of pointers to partitions indexed by partno. * Protected with matching bdev lock but stat and other * non-critical accesses use RCU. Always access through diff --git a/trunk/include/linux/hayesesp.h b/trunk/include/linux/hayesesp.h index 92b08cfe4a75..940aeb51d53f 100644 --- a/trunk/include/linux/hayesesp.h +++ b/trunk/include/linux/hayesesp.h @@ -96,6 +96,7 @@ struct esp_struct { int xmit_head; int xmit_tail; int xmit_cnt; + wait_queue_head_t delta_msr_wait; wait_queue_head_t break_wait; struct async_icount icount; /* kernel counters for the 4 input interrupts */ struct hayes_esp_config config; /* port configuration */ diff --git a/trunk/include/linux/kfifo.h b/trunk/include/linux/kfifo.h index ad6bdf5a5970..29f62e1733ff 100644 --- a/trunk/include/linux/kfifo.h +++ b/trunk/include/linux/kfifo.h @@ -38,7 +38,7 @@ extern struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock); extern void kfifo_free(struct kfifo *fifo); extern unsigned int __kfifo_put(struct kfifo *fifo, - const unsigned char *buffer, unsigned int len); + unsigned char *buffer, unsigned int len); extern unsigned int __kfifo_get(struct kfifo *fifo, unsigned char *buffer, unsigned int len); @@ -77,7 +77,7 @@ static inline void kfifo_reset(struct kfifo *fifo) * bytes copied. */ static inline unsigned int kfifo_put(struct kfifo *fifo, - const unsigned char *buffer, unsigned int len) + unsigned char *buffer, unsigned int len) { unsigned long flags; unsigned int ret; diff --git a/trunk/include/linux/miscdevice.h b/trunk/include/linux/miscdevice.h index adaf3c15e449..052117744629 100644 --- a/trunk/include/linux/miscdevice.h +++ b/trunk/include/linux/miscdevice.h @@ -41,8 +41,7 @@ struct miscdevice { struct list_head list; struct device *parent; struct device *this_device; - const char *nodename; - mode_t mode; + const char *devnode; }; extern int misc_register(struct miscdevice * misc); diff --git a/trunk/include/linux/perf_counter.h b/trunk/include/linux/perf_counter.h index bd341007c4fc..972f90d7a32f 100644 --- a/trunk/include/linux/perf_counter.h +++ b/trunk/include/linux/perf_counter.h @@ -199,14 +199,10 @@ struct perf_counter_attr { inherit_stat : 1, /* per task counts */ enable_on_exec : 1, /* next exec enables */ task : 1, /* trace fork/exit */ - watermark : 1, /* wakeup_watermark */ - __reserved_1 : 49; + __reserved_1 : 50; - union { - __u32 wakeup_events; /* wakeup every n events */ - __u32 wakeup_watermark; /* bytes before wakeup */ - }; + __u32 wakeup_events; /* wakeup every n events */ __u32 __reserved_2; __u64 __reserved_3; @@ -336,7 +332,6 @@ enum perf_event_type { * struct perf_event_header header; * u32 pid, ppid; * u32 tid, ptid; - * u64 time; * }; */ PERF_EVENT_EXIT = 4, @@ -357,7 +352,6 @@ enum perf_event_type { * struct perf_event_header header; * u32 pid, ppid; * u32 tid, ptid; - * { u64 time; } && PERF_SAMPLE_TIME * }; */ PERF_EVENT_FORK = 7, @@ -527,8 +521,6 @@ struct perf_mmap_data { atomic_t wakeup; /* needs a wakeup */ atomic_t lost; /* nr records lost */ - long watermark; /* wakeup watermark */ - struct perf_counter_mmap_page *user_page; void *data_pages[0]; }; @@ -693,17 +685,6 @@ struct perf_cpu_context { int recursion[4]; }; -struct perf_output_handle { - struct perf_counter *counter; - struct perf_mmap_data *data; - unsigned long head; - unsigned long offset; - int nmi; - int sample; - int locked; - unsigned long flags; -}; - #ifdef CONFIG_PERF_COUNTERS /* @@ -735,38 +716,16 @@ extern int hw_perf_group_sched_in(struct perf_counter *group_leader, extern void perf_counter_update_userpage(struct perf_counter *counter); struct perf_sample_data { - u64 type; - - u64 ip; - struct { - u32 pid; - u32 tid; - } tid_entry; - u64 time; + struct pt_regs *regs; u64 addr; - u64 id; - u64 stream_id; - struct { - u32 cpu; - u32 reserved; - } cpu_entry; u64 period; - struct perf_callchain_entry *callchain; struct perf_raw_record *raw; }; -extern void perf_output_sample(struct perf_output_handle *handle, - struct perf_event_header *header, - struct perf_sample_data *data, - struct perf_counter *counter); -extern void perf_prepare_sample(struct perf_event_header *header, - struct perf_sample_data *data, - struct perf_counter *counter, - struct pt_regs *regs); - extern int perf_counter_overflow(struct perf_counter *counter, int nmi, - struct perf_sample_data *data, - struct pt_regs *regs); + struct perf_sample_data *data); +extern void perf_counter_output(struct perf_counter *counter, int nmi, + struct perf_sample_data *data); /* * Return 1 for a software counter, 0 for a hardware counter @@ -816,12 +775,6 @@ extern void perf_tpcounter_event(int event_id, u64 addr, u64 count, #define perf_instruction_pointer(regs) instruction_pointer(regs) #endif -extern int perf_output_begin(struct perf_output_handle *handle, - struct perf_counter *counter, unsigned int size, - int nmi, int sample); -extern void perf_output_end(struct perf_output_handle *handle); -extern void perf_output_copy(struct perf_output_handle *handle, - const void *buf, unsigned int len); #else static inline void perf_counter_task_sched_in(struct task_struct *task, int cpu) { } @@ -848,28 +801,7 @@ static inline void perf_counter_mmap(struct vm_area_struct *vma) { } static inline void perf_counter_comm(struct task_struct *tsk) { } static inline void perf_counter_fork(struct task_struct *tsk) { } static inline void perf_counter_init(void) { } - -static inline int -perf_output_begin(struct perf_output_handle *handle, struct perf_counter *c, - unsigned int size, int nmi, int sample) { } -static inline void perf_output_end(struct perf_output_handle *handle) { } -static inline void -perf_output_copy(struct perf_output_handle *handle, - const void *buf, unsigned int len) { } -static inline void -perf_output_sample(struct perf_output_handle *handle, - struct perf_event_header *header, - struct perf_sample_data *data, - struct perf_counter *counter) { } -static inline void -perf_prepare_sample(struct perf_event_header *header, - struct perf_sample_data *data, - struct perf_counter *counter, - struct pt_regs *regs) { } #endif -#define perf_output_put(handle, x) \ - perf_output_copy((handle), &(x), sizeof(x)) - #endif /* __KERNEL__ */ #endif /* _LINUX_PERF_COUNTER_H */ diff --git a/trunk/include/linux/serial.h b/trunk/include/linux/serial.h index c8613c3ff9d3..e5bb75a63802 100644 --- a/trunk/include/linux/serial.h +++ b/trunk/include/linux/serial.h @@ -122,7 +122,6 @@ struct serial_uart_config { /* Internal flags used only by kernel */ #define ASYNCB_INITIALIZED 31 /* Serial port was initialized */ -#define ASYNCB_SUSPENDED 30 /* Serial port is suspended */ #define ASYNCB_NORMAL_ACTIVE 29 /* Normal device is active */ #define ASYNCB_BOOT_AUTOCONF 28 /* Autoconfigure port on bootup */ #define ASYNCB_CLOSING 27 /* Serial port is closing */ @@ -134,7 +133,6 @@ struct serial_uart_config { #define ASYNCB_FIRST_KERNEL 22 #define ASYNC_HUP_NOTIFY (1U << ASYNCB_HUP_NOTIFY) -#define ASYNC_SUSPENDED (1U << ASYNCB_SUSPENDED) #define ASYNC_FOURPORT (1U << ASYNCB_FOURPORT) #define ASYNC_SAK (1U << ASYNCB_SAK) #define ASYNC_SPLIT_TERMIOS (1U << ASYNCB_SPLIT_TERMIOS) diff --git a/trunk/include/linux/serial_8250.h b/trunk/include/linux/serial_8250.h index fb46aba11fb5..d4d2a78ad43e 100644 --- a/trunk/include/linux/serial_8250.h +++ b/trunk/include/linux/serial_8250.h @@ -22,7 +22,6 @@ struct plat_serial8250_port { void __iomem *membase; /* ioremap cookie or NULL */ resource_size_t mapbase; /* resource base */ unsigned int irq; /* interrupt number */ - unsigned long irqflags; /* request_irq flags */ unsigned int uartclk; /* UART clock rate */ void *private_data; unsigned char regshift; /* register shift */ diff --git a/trunk/include/linux/serial_core.h b/trunk/include/linux/serial_core.h index d58e460844dd..23d2fb051f97 100644 --- a/trunk/include/linux/serial_core.h +++ b/trunk/include/linux/serial_core.h @@ -20,8 +20,6 @@ #ifndef LINUX_SERIAL_CORE_H #define LINUX_SERIAL_CORE_H -#include - /* * The type definitions. These are from Ted Ts'o's serial.h */ @@ -188,6 +186,7 @@ #include struct uart_port; +struct uart_info; struct serial_struct; struct device; @@ -266,7 +265,6 @@ struct uart_port { unsigned int (*serial_in)(struct uart_port *, int); void (*serial_out)(struct uart_port *, int, int); unsigned int irq; /* irq number */ - unsigned long irqflags; /* irq flags */ unsigned int uartclk; /* base uart clock */ unsigned int fifosize; /* tx fifo size */ unsigned char x_char; /* xon/xoff char */ @@ -285,7 +283,7 @@ struct uart_port { unsigned int read_status_mask; /* driver specific */ unsigned int ignore_status_mask; /* driver specific */ - struct uart_state *state; /* pointer to parent state */ + struct uart_info *info; /* pointer to parent info */ struct uart_icount icount; /* statistics */ struct console *cons; /* struct console, if any */ @@ -336,17 +334,53 @@ struct uart_port { void *private_data; /* generic platform data pointer */ }; +/* + * This is the state information which is only valid when the port + * is open; it may be cleared the core driver once the device has + * been closed. Either the low level driver or the core can modify + * stuff here. + */ +typedef unsigned int __bitwise__ uif_t; + +struct uart_info { + struct tty_port port; + struct circ_buf xmit; + uif_t flags; + +/* + * Definitions for info->flags. These are _private_ to serial_core, and + * are specific to this structure. They may be queried by low level drivers. + * + * FIXME: use the ASY_ definitions + */ +#define UIF_CHECK_CD ((__force uif_t) (1 << 25)) +#define UIF_CTS_FLOW ((__force uif_t) (1 << 26)) +#define UIF_NORMAL_ACTIVE ((__force uif_t) (1 << 29)) +#define UIF_INITIALIZED ((__force uif_t) (1 << 31)) +#define UIF_SUSPENDED ((__force uif_t) (1 << 30)) + + struct tasklet_struct tlet; + wait_queue_head_t delta_msr_wait; +}; + /* * This is the state information which is persistent across opens. + * The low level driver must not to touch any elements contained + * within. */ struct uart_state { - struct tty_port port; + unsigned int close_delay; /* msec */ + unsigned int closing_wait; /* msec */ + +#define USF_CLOSING_WAIT_INF (0) +#define USF_CLOSING_WAIT_NONE (~0U) + int count; int pm_state; - struct circ_buf xmit; + struct uart_info info; + struct uart_port *port; - struct tasklet_struct tlet; - struct uart_port *uart_port; + struct mutex mutex; }; #define UART_XMIT_SIZE PAGE_SIZE @@ -427,7 +461,7 @@ int uart_resume_port(struct uart_driver *reg, struct uart_port *port); static inline int uart_tx_stopped(struct uart_port *port) { - struct tty_struct *tty = port->state->port.tty; + struct tty_struct *tty = port->info->port.tty; if(tty->stopped || tty->hw_stopped) return 1; return 0; @@ -442,7 +476,7 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch) #ifdef SUPPORT_SYSRQ if (port->sysrq) { if (ch && time_before(jiffies, port->sysrq)) { - handle_sysrq(ch, port->state->port.tty); + handle_sysrq(ch, port->info->port.tty); port->sysrq = 0; return 1; } @@ -460,7 +494,7 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch) */ static inline int uart_handle_break(struct uart_port *port) { - struct uart_state *state = port->state; + struct uart_info *info = port->info; #ifdef SUPPORT_SYSRQ if (port->cons && port->cons->index == port->line) { if (!port->sysrq) { @@ -471,7 +505,7 @@ static inline int uart_handle_break(struct uart_port *port) } #endif if (port->flags & UPF_SAK) - do_SAK(state->port.tty); + do_SAK(info->port.tty); return 0; } @@ -481,23 +515,22 @@ static inline int uart_handle_break(struct uart_port *port) * @status: new carrier detect status, nonzero if active */ static inline void -uart_handle_dcd_change(struct uart_port *uport, unsigned int status) +uart_handle_dcd_change(struct uart_port *port, unsigned int status) { - struct uart_state *state = uport->state; - struct tty_port *port = &state->port; + struct uart_info *info = port->info; - uport->icount.dcd++; + port->icount.dcd++; #ifdef CONFIG_HARD_PPS - if ((uport->flags & UPF_HARDPPS_CD) && status) + if ((port->flags & UPF_HARDPPS_CD) && status) hardpps(); #endif - if (port->flags & ASYNC_CHECK_CD) { + if (info->flags & UIF_CHECK_CD) { if (status) - wake_up_interruptible(&port->open_wait); - else if (port->tty) - tty_hangup(port->tty); + wake_up_interruptible(&info->port.open_wait); + else if (info->port.tty) + tty_hangup(info->port.tty); } } @@ -507,24 +540,24 @@ uart_handle_dcd_change(struct uart_port *uport, unsigned int status) * @status: new clear to send status, nonzero if active */ static inline void -uart_handle_cts_change(struct uart_port *uport, unsigned int status) +uart_handle_cts_change(struct uart_port *port, unsigned int status) { - struct tty_port *port = &uport->state->port; - struct tty_struct *tty = port->tty; + struct uart_info *info = port->info; + struct tty_struct *tty = info->port.tty; - uport->icount.cts++; + port->icount.cts++; - if (port->flags & ASYNC_CTS_FLOW) { + if (info->flags & UIF_CTS_FLOW) { if (tty->hw_stopped) { if (status) { tty->hw_stopped = 0; - uport->ops->start_tx(uport); - uart_write_wakeup(uport); + port->ops->start_tx(port); + uart_write_wakeup(port); } } else { if (!status) { tty->hw_stopped = 1; - uport->ops->stop_tx(uport); + port->ops->stop_tx(port); } } } @@ -536,7 +569,7 @@ static inline void uart_insert_char(struct uart_port *port, unsigned int status, unsigned int overrun, unsigned int ch, unsigned int flag) { - struct tty_struct *tty = port->state->port.tty; + struct tty_struct *tty = port->info->port.tty; if ((status & port->ignore_status_mask & ~overrun) == 0) tty_insert_flip_char(tty, ch, flag); diff --git a/trunk/include/linux/tty.h b/trunk/include/linux/tty.h index f0f43d08d8b8..a916a318004e 100644 --- a/trunk/include/linux/tty.h +++ b/trunk/include/linux/tty.h @@ -187,12 +187,7 @@ struct tty_port; struct tty_port_operations { /* Return 1 if the carrier is raised */ int (*carrier_raised)(struct tty_port *port); - /* Control the DTR line */ void (*dtr_rts)(struct tty_port *port, int raise); - /* Called when the last close completes or a hangup finishes - IFF the port was initialized. Do not use to free resources */ - void (*shutdown)(struct tty_port *port); - void (*drop)(struct tty_port *port); }; struct tty_port { @@ -203,12 +198,11 @@ struct tty_port { int count; /* Usage count */ wait_queue_head_t open_wait; /* Open waiters */ wait_queue_head_t close_wait; /* Close waiters */ - wait_queue_head_t delta_msr_wait; /* Modem status change */ unsigned long flags; /* TTY flags ASY_*/ struct mutex mutex; /* Locking */ unsigned char *xmit_buf; /* Optional buffer */ - unsigned int close_delay; /* Close port delay */ - unsigned int closing_wait; /* Delay for output */ + int close_delay; /* Close port delay */ + int closing_wait; /* Delay for output */ int drain_delay; /* Set to zero if no pure time based drain is needed else set to size of fifo */ @@ -465,12 +459,6 @@ extern int tty_port_block_til_ready(struct tty_port *port, extern int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct file *filp); extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty); -extern void tty_port_close(struct tty_port *port, - struct tty_struct *tty, struct file *filp); -extern inline int tty_port_users(struct tty_port *port) -{ - return port->count + port->blocked_open; -} extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc); extern int tty_unregister_ldisc(int disc); @@ -536,8 +524,5 @@ extern int pcxe_open(struct tty_struct *tty, struct file *filp); extern int vt_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); -extern long vt_compat_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg); - #endif /* __KERNEL__ */ #endif diff --git a/trunk/include/linux/usb.h b/trunk/include/linux/usb.h index a8fe05f224e5..b1e3c2fbfe11 100644 --- a/trunk/include/linux/usb.h +++ b/trunk/include/linux/usb.h @@ -922,7 +922,7 @@ extern struct bus_type usb_bus_type; /** * struct usb_class_driver - identifies a USB driver that wants to use the USB major number * @name: the usb class device name for this driver. Will show up in sysfs. - * @devnode: Callback to provide a naming hint for a possible + * @nodename: Callback to provide a naming hint for a possible * device node to create. * @fops: pointer to the struct file_operations of this driver. * @minor_base: the start of the minor range for this driver. @@ -933,7 +933,7 @@ extern struct bus_type usb_bus_type; */ struct usb_class_driver { char *name; - char *(*devnode)(struct device *dev, mode_t *mode); + char *(*nodename)(struct device *dev); const struct file_operations *fops; int minor_base; }; diff --git a/trunk/include/linux/usb/serial.h b/trunk/include/linux/usb/serial.h index 7b85e327af91..0ec50ba62139 100644 --- a/trunk/include/linux/usb/serial.h +++ b/trunk/include/linux/usb/serial.h @@ -238,8 +238,9 @@ struct usb_serial_driver { int (*resume)(struct usb_serial *serial); /* serial function calls */ - /* Called by console and by the tty layer */ - int (*open)(struct tty_struct *tty, struct usb_serial_port *port); + /* Called by console with tty = NULL and by tty */ + int (*open)(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp); void (*close)(struct usb_serial_port *port); int (*write)(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); @@ -260,9 +261,6 @@ struct usb_serial_driver { be an attached tty at this point */ void (*dtr_rts)(struct usb_serial_port *port, int on); int (*carrier_raised)(struct usb_serial_port *port); - /* Called by the usb serial hooks to allow the user to rework the - termios state */ - void (*init_termios)(struct tty_struct *tty); /* USB events */ void (*read_int_callback)(struct urb *urb); void (*write_int_callback)(struct urb *urb); @@ -302,7 +300,7 @@ static inline void usb_serial_console_disconnect(struct usb_serial *serial) {} extern struct usb_serial *usb_serial_get_by_index(unsigned int minor); extern void usb_serial_put(struct usb_serial *serial); extern int usb_serial_generic_open(struct tty_struct *tty, - struct usb_serial_port *port); + struct usb_serial_port *port, struct file *filp); extern int usb_serial_generic_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); extern void usb_serial_generic_close(struct usb_serial_port *port); diff --git a/trunk/include/linux/vt.h b/trunk/include/linux/vt.h index 7afca0d72139..02c1c0288770 100644 --- a/trunk/include/linux/vt.h +++ b/trunk/include/linux/vt.h @@ -1,6 +1,17 @@ #ifndef _LINUX_VT_H #define _LINUX_VT_H +#ifdef __KERNEL__ +struct notifier_block; + +struct vt_notifier_param { + struct vc_data *vc; /* VC on which the update happened */ + unsigned int c; /* Printed char */ +}; + +extern int register_vt_notifier(struct notifier_block *nb); +extern int unregister_vt_notifier(struct notifier_block *nb); +#endif /* * These constants are also useful for user-level apps (e.g., VC @@ -63,25 +74,4 @@ struct vt_consize { #define VT_UNLOCKSWITCH 0x560C /* allow vt switching */ #define VT_GETHIFONTMASK 0x560D /* return hi font mask */ -struct vt_event { - unsigned int event; -#define VT_EVENT_SWITCH 0x0001 /* Console switch */ -#define VT_EVENT_BLANK 0x0002 /* Screen blank */ -#define VT_EVENT_UNBLANK 0x0004 /* Screen unblank */ -#define VT_EVENT_RESIZE 0x0008 /* Resize display */ -#define VT_MAX_EVENT 0x000F - unsigned int old; /* Old console */ - unsigned int new; /* New console (if changing) */ - unsigned int pad[4]; /* Padding for expansion */ -}; - -#define VT_WAITEVENT 0x560E /* Wait for an event */ - -struct vt_setactivate { - unsigned int console; - struct vt_mode mode; -}; - -#define VT_SETACTIVATE 0x560F /* Activate and set the mode of a console */ - #endif /* _LINUX_VT_H */ diff --git a/trunk/include/linux/vt_kern.h b/trunk/include/linux/vt_kern.h index c0c4e1103a73..2f1113467f70 100644 --- a/trunk/include/linux/vt_kern.h +++ b/trunk/include/linux/vt_kern.h @@ -13,7 +13,6 @@ #include #include #include -#include /* * Presently, a lot of graphics programs do not restore the contents of @@ -92,8 +91,7 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc); #endif /* vt.c */ -void vt_event_post(unsigned int event, unsigned int old, unsigned int new); -int vt_waitactive(int n); +int vt_waitactive(int vt); void change_console(struct vc_data *new_vc); void reset_vc(struct vc_data *vc); extern int unbind_con_driver(const struct consw *csw, int first, int last, @@ -118,16 +116,4 @@ struct vt_spawn_console { }; extern struct vt_spawn_console vt_spawn_con; -extern int vt_move_to_console(unsigned int vt, int alloc); - -/* Interfaces for VC notification of character events (for accessibility etc) */ - -struct vt_notifier_param { - struct vc_data *vc; /* VC on which the update happened */ - unsigned int c; /* Printed char */ -}; - -extern int register_vt_notifier(struct notifier_block *nb); -extern int unregister_vt_notifier(struct notifier_block *nb); - #endif /* _VT_KERN_H */ diff --git a/trunk/include/trace/events/power.h b/trunk/include/trace/events/power.h deleted file mode 100644 index ea6d579261ad..000000000000 --- a/trunk/include/trace/events/power.h +++ /dev/null @@ -1,81 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM power - -#if !defined(_TRACE_POWER_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_POWER_H - -#include -#include - -#ifndef _TRACE_POWER_ENUM_ -#define _TRACE_POWER_ENUM_ -enum { - POWER_NONE = 0, - POWER_CSTATE = 1, - POWER_PSTATE = 2, -}; -#endif - - - -TRACE_EVENT(power_start, - - TP_PROTO(unsigned int type, unsigned int state), - - TP_ARGS(type, state), - - TP_STRUCT__entry( - __field( u64, type ) - __field( u64, state ) - ), - - TP_fast_assign( - __entry->type = type; - __entry->state = state; - ), - - TP_printk("type=%lu state=%lu", (unsigned long)__entry->type, (unsigned long)__entry->state) -); - -TRACE_EVENT(power_end, - - TP_PROTO(int dummy), - - TP_ARGS(dummy), - - TP_STRUCT__entry( - __field( u64, dummy ) - ), - - TP_fast_assign( - __entry->dummy = 0xffff; - ), - - TP_printk("dummy=%lu", (unsigned long)__entry->dummy) - -); - - -TRACE_EVENT(power_frequency, - - TP_PROTO(unsigned int type, unsigned int state), - - TP_ARGS(type, state), - - TP_STRUCT__entry( - __field( u64, type ) - __field( u64, state ) - ), - - TP_fast_assign( - __entry->type = type; - __entry->state = state; - ), - - TP_printk("type=%lu state=%lu", (unsigned long)__entry->type, (unsigned long) __entry->state) -); - -#endif /* _TRACE_POWER_H */ - -/* This part must be outside protection */ -#include diff --git a/trunk/include/trace/events/sched.h b/trunk/include/trace/events/sched.h index 4069c43f4187..b48f1ad7c946 100644 --- a/trunk/include/trace/events/sched.h +++ b/trunk/include/trace/events/sched.h @@ -379,39 +379,6 @@ TRACE_EVENT(sched_stat_wait, (unsigned long long)__entry->delay) ); -/* - * Tracepoint for accounting runtime (time the task is executing - * on a CPU). - */ -TRACE_EVENT(sched_stat_runtime, - - TP_PROTO(struct task_struct *tsk, u64 runtime, u64 vruntime), - - TP_ARGS(tsk, runtime, vruntime), - - TP_STRUCT__entry( - __array( char, comm, TASK_COMM_LEN ) - __field( pid_t, pid ) - __field( u64, runtime ) - __field( u64, vruntime ) - ), - - TP_fast_assign( - memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN); - __entry->pid = tsk->pid; - __entry->runtime = runtime; - __entry->vruntime = vruntime; - ) - TP_perf_assign( - __perf_count(runtime); - ), - - TP_printk("task: %s:%d runtime: %Lu [ns], vruntime: %Lu [ns]", - __entry->comm, __entry->pid, - (unsigned long long)__entry->runtime, - (unsigned long long)__entry->vruntime) -); - /* * Tracepoint for accounting sleep time (time the task is not runnable, * including iowait, see below). diff --git a/trunk/kernel/kfifo.c b/trunk/kernel/kfifo.c index 3765ff3c1bbe..26539e3228e5 100644 --- a/trunk/kernel/kfifo.c +++ b/trunk/kernel/kfifo.c @@ -117,7 +117,7 @@ EXPORT_SYMBOL(kfifo_free); * writer, you don't need extra locking to use these functions. */ unsigned int __kfifo_put(struct kfifo *fifo, - const unsigned char *buffer, unsigned int len) + unsigned char *buffer, unsigned int len) { unsigned int l; diff --git a/trunk/kernel/perf_counter.c b/trunk/kernel/perf_counter.c index cc768ab81ac8..8cb94a52d1bb 100644 --- a/trunk/kernel/perf_counter.c +++ b/trunk/kernel/perf_counter.c @@ -2176,13 +2176,6 @@ static int perf_mmap_data_alloc(struct perf_counter *counter, int nr_pages) data->nr_pages = nr_pages; atomic_set(&data->lock, -1); - if (counter->attr.watermark) { - data->watermark = min_t(long, PAGE_SIZE * nr_pages, - counter->attr.wakeup_watermark); - } - if (!data->watermark) - data->watermark = max(PAGE_SIZE, PAGE_SIZE * nr_pages / 4); - rcu_assign_pointer(counter->data, data); return 0; @@ -2322,8 +2315,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) lock_limit >>= PAGE_SHIFT; locked = vma->vm_mm->locked_vm + extra; - if ((locked > lock_limit) && perf_paranoid_tracepoint_raw() && - !capable(CAP_IPC_LOCK)) { + if ((locked > lock_limit) && !capable(CAP_IPC_LOCK)) { ret = -EPERM; goto unlock; } @@ -2512,15 +2504,35 @@ __weak struct perf_callchain_entry *perf_callchain(struct pt_regs *regs) /* * Output */ -static bool perf_output_space(struct perf_mmap_data *data, unsigned long tail, - unsigned long offset, unsigned long head) + +struct perf_output_handle { + struct perf_counter *counter; + struct perf_mmap_data *data; + unsigned long head; + unsigned long offset; + int nmi; + int sample; + int locked; + unsigned long flags; +}; + +static bool perf_output_space(struct perf_mmap_data *data, + unsigned int offset, unsigned int head) { + unsigned long tail; unsigned long mask; if (!data->writable) return true; mask = (data->nr_pages << PAGE_SHIFT) - 1; + /* + * Userspace could choose to issue a mb() before updating the tail + * pointer. So that all reads will be completed before the write is + * issued. + */ + tail = ACCESS_ONCE(data->user_page->data_tail); + smp_rmb(); offset = (offset - tail) & mask; head = (head - tail) & mask; @@ -2621,8 +2633,8 @@ static void perf_output_unlock(struct perf_output_handle *handle) local_irq_restore(handle->flags); } -void perf_output_copy(struct perf_output_handle *handle, - const void *buf, unsigned int len) +static void perf_output_copy(struct perf_output_handle *handle, + const void *buf, unsigned int len) { unsigned int pages_mask; unsigned int offset; @@ -2657,13 +2669,16 @@ void perf_output_copy(struct perf_output_handle *handle, WARN_ON_ONCE(((long)(handle->head - handle->offset)) < 0); } -int perf_output_begin(struct perf_output_handle *handle, - struct perf_counter *counter, unsigned int size, - int nmi, int sample) +#define perf_output_put(handle, x) \ + perf_output_copy((handle), &(x), sizeof(x)) + +static int perf_output_begin(struct perf_output_handle *handle, + struct perf_counter *counter, unsigned int size, + int nmi, int sample) { struct perf_counter *output_counter; struct perf_mmap_data *data; - unsigned long tail, offset, head; + unsigned int offset, head; int have_lost; struct { struct perf_event_header header; @@ -2701,23 +2716,16 @@ int perf_output_begin(struct perf_output_handle *handle, perf_output_lock(handle); do { - /* - * Userspace could choose to issue a mb() before updating the - * tail pointer. So that all reads will be completed before the - * write is issued. - */ - tail = ACCESS_ONCE(data->user_page->data_tail); - smp_rmb(); offset = head = atomic_long_read(&data->head); head += size; - if (unlikely(!perf_output_space(data, tail, offset, head))) + if (unlikely(!perf_output_space(data, offset, head))) goto fail; } while (atomic_long_cmpxchg(&data->head, offset, head) != offset); handle->offset = offset; handle->head = head; - if (head - tail > data->watermark) + if ((offset >> PAGE_SHIFT) != (head >> PAGE_SHIFT)) atomic_set(&data->wakeup, 1); if (have_lost) { @@ -2741,7 +2749,7 @@ int perf_output_begin(struct perf_output_handle *handle, return -ENOSPC; } -void perf_output_end(struct perf_output_handle *handle) +static void perf_output_end(struct perf_output_handle *handle) { struct perf_counter *counter = handle->counter; struct perf_mmap_data *data = handle->data; @@ -2855,148 +2863,82 @@ static void perf_output_read(struct perf_output_handle *handle, perf_output_read_one(handle, counter); } -void perf_output_sample(struct perf_output_handle *handle, - struct perf_event_header *header, - struct perf_sample_data *data, - struct perf_counter *counter) -{ - u64 sample_type = data->type; - - perf_output_put(handle, *header); - - if (sample_type & PERF_SAMPLE_IP) - perf_output_put(handle, data->ip); - - if (sample_type & PERF_SAMPLE_TID) - perf_output_put(handle, data->tid_entry); - - if (sample_type & PERF_SAMPLE_TIME) - perf_output_put(handle, data->time); - - if (sample_type & PERF_SAMPLE_ADDR) - perf_output_put(handle, data->addr); - - if (sample_type & PERF_SAMPLE_ID) - perf_output_put(handle, data->id); - - if (sample_type & PERF_SAMPLE_STREAM_ID) - perf_output_put(handle, data->stream_id); - - if (sample_type & PERF_SAMPLE_CPU) - perf_output_put(handle, data->cpu_entry); - - if (sample_type & PERF_SAMPLE_PERIOD) - perf_output_put(handle, data->period); - - if (sample_type & PERF_SAMPLE_READ) - perf_output_read(handle, counter); - - if (sample_type & PERF_SAMPLE_CALLCHAIN) { - if (data->callchain) { - int size = 1; - - if (data->callchain) - size += data->callchain->nr; - - size *= sizeof(u64); - - perf_output_copy(handle, data->callchain, size); - } else { - u64 nr = 0; - perf_output_put(handle, nr); - } - } - - if (sample_type & PERF_SAMPLE_RAW) { - if (data->raw) { - perf_output_put(handle, data->raw->size); - perf_output_copy(handle, data->raw->data, - data->raw->size); - } else { - struct { - u32 size; - u32 data; - } raw = { - .size = sizeof(u32), - .data = 0, - }; - perf_output_put(handle, raw); - } - } -} - -void perf_prepare_sample(struct perf_event_header *header, - struct perf_sample_data *data, - struct perf_counter *counter, - struct pt_regs *regs) +void perf_counter_output(struct perf_counter *counter, int nmi, + struct perf_sample_data *data) { + int ret; u64 sample_type = counter->attr.sample_type; + struct perf_output_handle handle; + struct perf_event_header header; + u64 ip; + struct { + u32 pid, tid; + } tid_entry; + struct perf_callchain_entry *callchain = NULL; + int callchain_size = 0; + u64 time; + struct { + u32 cpu, reserved; + } cpu_entry; - data->type = sample_type; - - header->type = PERF_EVENT_SAMPLE; - header->size = sizeof(*header); + header.type = PERF_EVENT_SAMPLE; + header.size = sizeof(header); - header->misc = 0; - header->misc |= perf_misc_flags(regs); + header.misc = 0; + header.misc |= perf_misc_flags(data->regs); if (sample_type & PERF_SAMPLE_IP) { - data->ip = perf_instruction_pointer(regs); - - header->size += sizeof(data->ip); + ip = perf_instruction_pointer(data->regs); + header.size += sizeof(ip); } if (sample_type & PERF_SAMPLE_TID) { /* namespace issues */ - data->tid_entry.pid = perf_counter_pid(counter, current); - data->tid_entry.tid = perf_counter_tid(counter, current); + tid_entry.pid = perf_counter_pid(counter, current); + tid_entry.tid = perf_counter_tid(counter, current); - header->size += sizeof(data->tid_entry); + header.size += sizeof(tid_entry); } if (sample_type & PERF_SAMPLE_TIME) { - data->time = perf_clock(); + /* + * Maybe do better on x86 and provide cpu_clock_nmi() + */ + time = sched_clock(); - header->size += sizeof(data->time); + header.size += sizeof(u64); } if (sample_type & PERF_SAMPLE_ADDR) - header->size += sizeof(data->addr); - - if (sample_type & PERF_SAMPLE_ID) { - data->id = primary_counter_id(counter); - - header->size += sizeof(data->id); - } + header.size += sizeof(u64); - if (sample_type & PERF_SAMPLE_STREAM_ID) { - data->stream_id = counter->id; + if (sample_type & PERF_SAMPLE_ID) + header.size += sizeof(u64); - header->size += sizeof(data->stream_id); - } + if (sample_type & PERF_SAMPLE_STREAM_ID) + header.size += sizeof(u64); if (sample_type & PERF_SAMPLE_CPU) { - data->cpu_entry.cpu = raw_smp_processor_id(); - data->cpu_entry.reserved = 0; + header.size += sizeof(cpu_entry); - header->size += sizeof(data->cpu_entry); + cpu_entry.cpu = raw_smp_processor_id(); + cpu_entry.reserved = 0; } if (sample_type & PERF_SAMPLE_PERIOD) - header->size += sizeof(data->period); + header.size += sizeof(u64); if (sample_type & PERF_SAMPLE_READ) - header->size += perf_counter_read_size(counter); + header.size += perf_counter_read_size(counter); if (sample_type & PERF_SAMPLE_CALLCHAIN) { - int size = 1; - - data->callchain = perf_callchain(regs); - - if (data->callchain) - size += data->callchain->nr; + callchain = perf_callchain(data->regs); - header->size += size * sizeof(u64); + if (callchain) { + callchain_size = (1 + callchain->nr) * sizeof(u64); + header.size += callchain_size; + } else + header.size += sizeof(u64); } if (sample_type & PERF_SAMPLE_RAW) { @@ -3008,23 +2950,69 @@ void perf_prepare_sample(struct perf_event_header *header, size += sizeof(u32); WARN_ON_ONCE(size & (sizeof(u64)-1)); - header->size += size; + header.size += size; } -} -static void perf_counter_output(struct perf_counter *counter, int nmi, - struct perf_sample_data *data, - struct pt_regs *regs) -{ - struct perf_output_handle handle; - struct perf_event_header header; + ret = perf_output_begin(&handle, counter, header.size, nmi, 1); + if (ret) + return; - perf_prepare_sample(&header, data, counter, regs); + perf_output_put(&handle, header); - if (perf_output_begin(&handle, counter, header.size, nmi, 1)) - return; + if (sample_type & PERF_SAMPLE_IP) + perf_output_put(&handle, ip); + + if (sample_type & PERF_SAMPLE_TID) + perf_output_put(&handle, tid_entry); + + if (sample_type & PERF_SAMPLE_TIME) + perf_output_put(&handle, time); + + if (sample_type & PERF_SAMPLE_ADDR) + perf_output_put(&handle, data->addr); + + if (sample_type & PERF_SAMPLE_ID) { + u64 id = primary_counter_id(counter); + + perf_output_put(&handle, id); + } + + if (sample_type & PERF_SAMPLE_STREAM_ID) + perf_output_put(&handle, counter->id); + + if (sample_type & PERF_SAMPLE_CPU) + perf_output_put(&handle, cpu_entry); + + if (sample_type & PERF_SAMPLE_PERIOD) + perf_output_put(&handle, data->period); + + if (sample_type & PERF_SAMPLE_READ) + perf_output_read(&handle, counter); + + if (sample_type & PERF_SAMPLE_CALLCHAIN) { + if (callchain) + perf_output_copy(&handle, callchain, callchain_size); + else { + u64 nr = 0; + perf_output_put(&handle, nr); + } + } - perf_output_sample(&handle, &header, data, counter); + if (sample_type & PERF_SAMPLE_RAW) { + if (data->raw) { + perf_output_put(&handle, data->raw->size); + perf_output_copy(&handle, data->raw->data, data->raw->size); + } else { + struct { + u32 size; + u32 data; + } raw = { + .size = sizeof(u32), + .data = 0, + }; + perf_output_put(&handle, raw); + } + } perf_output_end(&handle); } @@ -3083,7 +3071,6 @@ struct perf_task_event { u32 ppid; u32 tid; u32 ptid; - u64 time; } event; }; @@ -3091,12 +3078,9 @@ static void perf_counter_task_output(struct perf_counter *counter, struct perf_task_event *task_event) { struct perf_output_handle handle; - int size; + int size = task_event->event.header.size; struct task_struct *task = task_event->task; - int ret; - - size = task_event->event.header.size; - ret = perf_output_begin(&handle, counter, size, 0, 0); + int ret = perf_output_begin(&handle, counter, size, 0, 0); if (ret) return; @@ -3107,10 +3091,7 @@ static void perf_counter_task_output(struct perf_counter *counter, task_event->event.tid = perf_counter_tid(counter, task); task_event->event.ptid = perf_counter_tid(counter, current); - task_event->event.time = perf_clock(); - perf_output_put(&handle, task_event->event); - perf_output_end(&handle); } @@ -3492,7 +3473,7 @@ static void perf_log_throttle(struct perf_counter *counter, int enable) .misc = 0, .size = sizeof(throttle_event), }, - .time = perf_clock(), + .time = sched_clock(), .id = primary_counter_id(counter), .stream_id = counter->id, }; @@ -3512,16 +3493,14 @@ static void perf_log_throttle(struct perf_counter *counter, int enable) * Generic counter overflow handling, sampling. */ -static int __perf_counter_overflow(struct perf_counter *counter, int nmi, - int throttle, struct perf_sample_data *data, - struct pt_regs *regs) +int perf_counter_overflow(struct perf_counter *counter, int nmi, + struct perf_sample_data *data) { int events = atomic_read(&counter->event_limit); + int throttle = counter->pmu->unthrottle != NULL; struct hw_perf_counter *hwc = &counter->hw; int ret = 0; - throttle = (throttle && counter->pmu->unthrottle != NULL); - if (!throttle) { hwc->interrupts++; } else { @@ -3544,7 +3523,7 @@ static int __perf_counter_overflow(struct perf_counter *counter, int nmi, } if (counter->attr.freq) { - u64 now = perf_clock(); + u64 now = sched_clock(); s64 delta = now - hwc->freq_stamp; hwc->freq_stamp = now; @@ -3570,17 +3549,10 @@ static int __perf_counter_overflow(struct perf_counter *counter, int nmi, perf_counter_disable(counter); } - perf_counter_output(counter, nmi, data, regs); + perf_counter_output(counter, nmi, data); return ret; } -int perf_counter_overflow(struct perf_counter *counter, int nmi, - struct perf_sample_data *data, - struct pt_regs *regs) -{ - return __perf_counter_overflow(counter, nmi, 1, data, regs); -} - /* * Generic software counter infrastructure */ @@ -3616,11 +3588,9 @@ static u64 perf_swcounter_set_period(struct perf_counter *counter) } static void perf_swcounter_overflow(struct perf_counter *counter, - int nmi, struct perf_sample_data *data, - struct pt_regs *regs) + int nmi, struct perf_sample_data *data) { struct hw_perf_counter *hwc = &counter->hw; - int throttle = 0; u64 overflow; data->period = counter->hw.last_period; @@ -3630,15 +3600,13 @@ static void perf_swcounter_overflow(struct perf_counter *counter, return; for (; overflow; overflow--) { - if (__perf_counter_overflow(counter, nmi, throttle, - data, regs)) { + if (perf_counter_overflow(counter, nmi, data)) { /* * We inhibit the overflow from happening when * hwc->interrupts == MAX_INTERRUPTS. */ break; } - throttle = 1; } } @@ -3650,8 +3618,7 @@ static void perf_swcounter_unthrottle(struct perf_counter *counter) } static void perf_swcounter_add(struct perf_counter *counter, u64 nr, - int nmi, struct perf_sample_data *data, - struct pt_regs *regs) + int nmi, struct perf_sample_data *data) { struct hw_perf_counter *hwc = &counter->hw; @@ -3660,11 +3627,11 @@ static void perf_swcounter_add(struct perf_counter *counter, u64 nr, if (!hwc->sample_period) return; - if (!regs) + if (!data->regs) return; if (!atomic64_add_negative(nr, &hwc->period_left)) - perf_swcounter_overflow(counter, nmi, data, regs); + perf_swcounter_overflow(counter, nmi, data); } static int perf_swcounter_is_counting(struct perf_counter *counter) @@ -3723,8 +3690,7 @@ static int perf_swcounter_match(struct perf_counter *counter, static void perf_swcounter_ctx_event(struct perf_counter_context *ctx, enum perf_type_id type, u32 event, u64 nr, int nmi, - struct perf_sample_data *data, - struct pt_regs *regs) + struct perf_sample_data *data) { struct perf_counter *counter; @@ -3733,8 +3699,8 @@ static void perf_swcounter_ctx_event(struct perf_counter_context *ctx, rcu_read_lock(); list_for_each_entry_rcu(counter, &ctx->event_list, event_entry) { - if (perf_swcounter_match(counter, type, event, regs)) - perf_swcounter_add(counter, nr, nmi, data, regs); + if (perf_swcounter_match(counter, type, event, data->regs)) + perf_swcounter_add(counter, nr, nmi, data); } rcu_read_unlock(); } @@ -3755,8 +3721,7 @@ static int *perf_swcounter_recursion_context(struct perf_cpu_context *cpuctx) static void do_perf_swcounter_event(enum perf_type_id type, u32 event, u64 nr, int nmi, - struct perf_sample_data *data, - struct pt_regs *regs) + struct perf_sample_data *data) { struct perf_cpu_context *cpuctx = &get_cpu_var(perf_cpu_context); int *recursion = perf_swcounter_recursion_context(cpuctx); @@ -3769,7 +3734,7 @@ static void do_perf_swcounter_event(enum perf_type_id type, u32 event, barrier(); perf_swcounter_ctx_event(&cpuctx->ctx, type, event, - nr, nmi, data, regs); + nr, nmi, data); rcu_read_lock(); /* * doesn't really matter which of the child contexts the @@ -3777,7 +3742,7 @@ static void do_perf_swcounter_event(enum perf_type_id type, u32 event, */ ctx = rcu_dereference(current->perf_counter_ctxp); if (ctx) - perf_swcounter_ctx_event(ctx, type, event, nr, nmi, data, regs); + perf_swcounter_ctx_event(ctx, type, event, nr, nmi, data); rcu_read_unlock(); barrier(); @@ -3791,11 +3756,11 @@ void __perf_swcounter_event(u32 event, u64 nr, int nmi, struct pt_regs *regs, u64 addr) { struct perf_sample_data data = { + .regs = regs, .addr = addr, }; - do_perf_swcounter_event(PERF_TYPE_SOFTWARE, event, nr, nmi, - &data, regs); + do_perf_swcounter_event(PERF_TYPE_SOFTWARE, event, nr, nmi, &data); } static void perf_swcounter_read(struct perf_counter *counter) @@ -3832,7 +3797,6 @@ static enum hrtimer_restart perf_swcounter_hrtimer(struct hrtimer *hrtimer) { enum hrtimer_restart ret = HRTIMER_RESTART; struct perf_sample_data data; - struct pt_regs *regs; struct perf_counter *counter; u64 period; @@ -3840,17 +3804,17 @@ static enum hrtimer_restart perf_swcounter_hrtimer(struct hrtimer *hrtimer) counter->pmu->read(counter); data.addr = 0; - regs = get_irq_regs(); + data.regs = get_irq_regs(); /* * In case we exclude kernel IPs or are somehow not in interrupt * context, provide the next best thing, the user IP. */ - if ((counter->attr.exclude_kernel || !regs) && + if ((counter->attr.exclude_kernel || !data.regs) && !counter->attr.exclude_user) - regs = task_pt_regs(current); + data.regs = task_pt_regs(current); - if (regs) { - if (perf_counter_overflow(counter, 0, &data, regs)) + if (data.regs) { + if (perf_counter_overflow(counter, 0, &data)) ret = HRTIMER_NORESTART; } @@ -3986,17 +3950,15 @@ void perf_tpcounter_event(int event_id, u64 addr, u64 count, void *record, }; struct perf_sample_data data = { + .regs = get_irq_regs(), .addr = addr, .raw = &raw, }; - struct pt_regs *regs = get_irq_regs(); - - if (!regs) - regs = task_pt_regs(current); + if (!data.regs) + data.regs = task_pt_regs(current); - do_perf_swcounter_event(PERF_TYPE_TRACEPOINT, event_id, count, 1, - &data, regs); + do_perf_swcounter_event(PERF_TYPE_TRACEPOINT, event_id, count, 1, &data); } EXPORT_SYMBOL_GPL(perf_tpcounter_event); @@ -4208,8 +4170,8 @@ perf_counter_alloc(struct perf_counter_attr *attr, static int perf_copy_attr(struct perf_counter_attr __user *uattr, struct perf_counter_attr *attr) { - u32 size; int ret; + u32 size; if (!access_ok(VERIFY_WRITE, uattr, PERF_ATTR_SIZE_VER0)) return -EFAULT; @@ -4234,19 +4196,19 @@ static int perf_copy_attr(struct perf_counter_attr __user *uattr, /* * If we're handed a bigger struct than we know of, - * ensure all the unknown bits are 0 - i.e. new - * user-space does not rely on any kernel feature - * extensions we dont know about yet. + * ensure all the unknown bits are 0. */ if (size > sizeof(*attr)) { - unsigned char __user *addr; - unsigned char __user *end; - unsigned char val; + unsigned long val; + unsigned long __user *addr; + unsigned long __user *end; - addr = (void __user *)uattr + sizeof(*attr); - end = (void __user *)uattr + size; + addr = PTR_ALIGN((void __user *)uattr + sizeof(*attr), + sizeof(unsigned long)); + end = PTR_ALIGN((void __user *)uattr + size, + sizeof(unsigned long)); - for (; addr < end; addr++) { + for (; addr < end; addr += sizeof(unsigned long)) { ret = get_user(val, addr); if (ret) return ret; diff --git a/trunk/kernel/power/console.c b/trunk/kernel/power/console.c index 5187136fe1de..a3961b205de7 100644 --- a/trunk/kernel/power/console.c +++ b/trunk/kernel/power/console.c @@ -14,13 +14,56 @@ #define SUSPEND_CONSOLE (MAX_NR_CONSOLES-1) static int orig_fgconsole, orig_kmsg; +static int disable_vt_switch; + +/* + * Normally during a suspend, we allocate a new console and switch to it. + * When we resume, we switch back to the original console. This switch + * can be slow, so on systems where the framebuffer can handle restoration + * of video registers anyways, there's little point in doing the console + * switch. This function allows you to disable it by passing it '0'. + */ +void pm_set_vt_switch(int do_switch) +{ + acquire_console_sem(); + disable_vt_switch = !do_switch; + release_console_sem(); +} +EXPORT_SYMBOL(pm_set_vt_switch); int pm_prepare_console(void) { - orig_fgconsole = vt_move_to_console(SUSPEND_CONSOLE, 1); - if (orig_fgconsole < 0) + acquire_console_sem(); + + if (disable_vt_switch) { + release_console_sem(); + return 0; + } + + orig_fgconsole = fg_console; + + if (vc_allocate(SUSPEND_CONSOLE)) { + /* we can't have a free VC for now. Too bad, + * we don't want to mess the screen for now. */ + release_console_sem(); return 1; + } + if (set_console(SUSPEND_CONSOLE)) { + /* + * We're unable to switch to the SUSPEND_CONSOLE. + * Let the calling function know so it can decide + * what to do. + */ + release_console_sem(); + return 1; + } + release_console_sem(); + + if (vt_waitactive(SUSPEND_CONSOLE)) { + pr_debug("Suspend: Can't switch VCs."); + return 1; + } orig_kmsg = kmsg_redirect; kmsg_redirect = SUSPEND_CONSOLE; return 0; @@ -28,9 +71,19 @@ int pm_prepare_console(void) void pm_restore_console(void) { - if (orig_fgconsole >= 0) { - vt_move_to_console(orig_fgconsole, 0); - kmsg_redirect = orig_kmsg; + acquire_console_sem(); + if (disable_vt_switch) { + release_console_sem(); + return; + } + set_console(orig_fgconsole); + release_console_sem(); + + if (vt_waitactive(orig_fgconsole)) { + pr_debug("Resume: Can't switch VCs."); + return; } + + kmsg_redirect = orig_kmsg; } #endif diff --git a/trunk/kernel/sched_clock.c b/trunk/kernel/sched_clock.c index ac2e1dc708bd..e1d16c9a7680 100644 --- a/trunk/kernel/sched_clock.c +++ b/trunk/kernel/sched_clock.c @@ -48,6 +48,13 @@ static __read_mostly int sched_clock_running; __read_mostly int sched_clock_stable; struct sched_clock_data { + /* + * Raw spinlock - this is a special case: this might be called + * from within instrumentation code so we dont want to do any + * instrumentation ourselves. + */ + raw_spinlock_t lock; + u64 tick_raw; u64 tick_gtod; u64 clock; @@ -73,6 +80,7 @@ void sched_clock_init(void) for_each_possible_cpu(cpu) { struct sched_clock_data *scd = cpu_sdc(cpu); + scd->lock = (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED; scd->tick_raw = 0; scd->tick_gtod = ktime_now; scd->clock = ktime_now; @@ -101,19 +109,14 @@ static inline u64 wrap_max(u64 x, u64 y) * - filter out backward motion * - use the GTOD tick value to create a window to filter crazy TSC values */ -static u64 sched_clock_local(struct sched_clock_data *scd) +static u64 __update_sched_clock(struct sched_clock_data *scd, u64 now) { - u64 now, clock, old_clock, min_clock, max_clock; - s64 delta; + s64 delta = now - scd->tick_raw; + u64 clock, min_clock, max_clock; -again: - now = sched_clock(); - delta = now - scd->tick_raw; if (unlikely(delta < 0)) delta = 0; - old_clock = scd->clock; - /* * scd->clock = clamp(scd->tick_gtod + delta, * max(scd->tick_gtod, scd->clock), @@ -121,73 +124,84 @@ static u64 sched_clock_local(struct sched_clock_data *scd) */ clock = scd->tick_gtod + delta; - min_clock = wrap_max(scd->tick_gtod, old_clock); - max_clock = wrap_max(old_clock, scd->tick_gtod + TICK_NSEC); + min_clock = wrap_max(scd->tick_gtod, scd->clock); + max_clock = wrap_max(scd->clock, scd->tick_gtod + TICK_NSEC); clock = wrap_max(clock, min_clock); clock = wrap_min(clock, max_clock); - if (cmpxchg(&scd->clock, old_clock, clock) != old_clock) - goto again; + scd->clock = clock; - return clock; + return scd->clock; } -static u64 sched_clock_remote(struct sched_clock_data *scd) +static void lock_double_clock(struct sched_clock_data *data1, + struct sched_clock_data *data2) { - struct sched_clock_data *my_scd = this_scd(); - u64 this_clock, remote_clock; - u64 *ptr, old_val, val; - - sched_clock_local(my_scd); -again: - this_clock = my_scd->clock; - remote_clock = scd->clock; - - /* - * Use the opportunity that we have both locks - * taken to couple the two clocks: we take the - * larger time as the latest time for both - * runqueues. (this creates monotonic movement) - */ - if (likely((s64)(remote_clock - this_clock) < 0)) { - ptr = &scd->clock; - old_val = remote_clock; - val = this_clock; + if (data1 < data2) { + __raw_spin_lock(&data1->lock); + __raw_spin_lock(&data2->lock); } else { - /* - * Should be rare, but possible: - */ - ptr = &my_scd->clock; - old_val = this_clock; - val = remote_clock; + __raw_spin_lock(&data2->lock); + __raw_spin_lock(&data1->lock); } - - if (cmpxchg(ptr, old_val, val) != old_val) - goto again; - - return val; } u64 sched_clock_cpu(int cpu) { + u64 now, clock, this_clock, remote_clock; struct sched_clock_data *scd; - u64 clock; - - WARN_ON_ONCE(!irqs_disabled()); if (sched_clock_stable) return sched_clock(); + scd = cpu_sdc(cpu); + + /* + * Normally this is not called in NMI context - but if it is, + * trying to do any locking here is totally lethal. + */ + if (unlikely(in_nmi())) + return scd->clock; + if (unlikely(!sched_clock_running)) return 0ull; - scd = cpu_sdc(cpu); + WARN_ON_ONCE(!irqs_disabled()); + now = sched_clock(); + + if (cpu != raw_smp_processor_id()) { + struct sched_clock_data *my_scd = this_scd(); + + lock_double_clock(scd, my_scd); + + this_clock = __update_sched_clock(my_scd, now); + remote_clock = scd->clock; + + /* + * Use the opportunity that we have both locks + * taken to couple the two clocks: we take the + * larger time as the latest time for both + * runqueues. (this creates monotonic movement) + */ + if (likely((s64)(remote_clock - this_clock) < 0)) { + clock = this_clock; + scd->clock = clock; + } else { + /* + * Should be rare, but possible: + */ + clock = remote_clock; + my_scd->clock = remote_clock; + } + + __raw_spin_unlock(&my_scd->lock); + } else { + __raw_spin_lock(&scd->lock); + clock = __update_sched_clock(scd, now); + } - if (cpu != smp_processor_id()) - clock = sched_clock_remote(scd); - else - clock = sched_clock_local(scd); + __raw_spin_unlock(&scd->lock); return clock; } @@ -209,9 +223,11 @@ void sched_clock_tick(void) now_gtod = ktime_to_ns(ktime_get()); now = sched_clock(); + __raw_spin_lock(&scd->lock); scd->tick_raw = now; scd->tick_gtod = now_gtod; - sched_clock_local(scd); + __update_sched_clock(scd, now); + __raw_spin_unlock(&scd->lock); } /* diff --git a/trunk/kernel/sched_fair.c b/trunk/kernel/sched_fair.c index 990b188803ce..10d218ab69f2 100644 --- a/trunk/kernel/sched_fair.c +++ b/trunk/kernel/sched_fair.c @@ -513,7 +513,6 @@ static void update_curr(struct cfs_rq *cfs_rq) if (entity_is_task(curr)) { struct task_struct *curtask = task_of(curr); - trace_sched_stat_runtime(curtask, delta_exec, curr->vruntime); cpuacct_charge(curtask, delta_exec); account_group_exec_runtime(curtask, delta_exec); } diff --git a/trunk/kernel/trace/Makefile b/trunk/kernel/trace/Makefile index 26f03ac07c2b..844164dca90a 100644 --- a/trunk/kernel/trace/Makefile +++ b/trunk/kernel/trace/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_BOOT_TRACER) += trace_boot.o obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += trace_functions_graph.o obj-$(CONFIG_TRACE_BRANCH_PROFILING) += trace_branch.o obj-$(CONFIG_HW_BRANCH_TRACER) += trace_hw_branches.o +obj-$(CONFIG_POWER_TRACER) += trace_power.o obj-$(CONFIG_KMEMTRACE) += kmemtrace.o obj-$(CONFIG_WORKQUEUE_TRACER) += trace_workqueue.o obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o @@ -53,6 +54,5 @@ obj-$(CONFIG_EVENT_TRACING) += trace_export.o obj-$(CONFIG_FTRACE_SYSCALLS) += trace_syscalls.o obj-$(CONFIG_EVENT_PROFILE) += trace_event_profile.o obj-$(CONFIG_EVENT_TRACING) += trace_events_filter.o -obj-$(CONFIG_EVENT_TRACING) += power-traces.o libftrace-y := ftrace.o diff --git a/trunk/kernel/trace/power-traces.c b/trunk/kernel/trace/power-traces.c deleted file mode 100644 index e06c6e3d56a3..000000000000 --- a/trunk/kernel/trace/power-traces.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Power trace points - * - * Copyright (C) 2009 Arjan van de Ven - */ - -#include -#include -#include -#include -#include -#include - -#define CREATE_TRACE_POINTS -#include - -EXPORT_TRACEPOINT_SYMBOL_GPL(power_start); -EXPORT_TRACEPOINT_SYMBOL_GPL(power_end); -EXPORT_TRACEPOINT_SYMBOL_GPL(power_frequency); - diff --git a/trunk/kernel/trace/trace.h b/trunk/kernel/trace/trace.h index 405cb850b75d..86bcff94791a 100644 --- a/trunk/kernel/trace/trace.h +++ b/trunk/kernel/trace/trace.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -36,6 +37,7 @@ enum trace_type { TRACE_HW_BRANCHES, TRACE_KMEM_ALLOC, TRACE_KMEM_FREE, + TRACE_POWER, TRACE_BLK, __TRACE_LAST_TYPE, @@ -205,6 +207,7 @@ extern void __ftrace_bad_type(void); IF_ASSIGN(var, ent, struct ftrace_graph_ret_entry, \ TRACE_GRAPH_RET); \ IF_ASSIGN(var, ent, struct hw_branch_entry, TRACE_HW_BRANCHES);\ + IF_ASSIGN(var, ent, struct trace_power, TRACE_POWER); \ IF_ASSIGN(var, ent, struct kmemtrace_alloc_entry, \ TRACE_KMEM_ALLOC); \ IF_ASSIGN(var, ent, struct kmemtrace_free_entry, \ diff --git a/trunk/kernel/trace/trace_entries.h b/trunk/kernel/trace/trace_entries.h index ead3d724599d..a431748ddd6e 100644 --- a/trunk/kernel/trace/trace_entries.h +++ b/trunk/kernel/trace/trace_entries.h @@ -330,6 +330,23 @@ FTRACE_ENTRY(hw_branch, hw_branch_entry, F_printk("from: %llx to: %llx", __entry->from, __entry->to) ); +FTRACE_ENTRY(power, trace_power, + + TRACE_POWER, + + F_STRUCT( + __field_struct( struct power_trace, state_data ) + __field_desc( s64, state_data, stamp ) + __field_desc( s64, state_data, end ) + __field_desc( int, state_data, type ) + __field_desc( int, state_data, state ) + ), + + F_printk("%llx->%llx type:%u state:%u", + __entry->stamp, __entry->end, + __entry->type, __entry->state) +); + FTRACE_ENTRY(kmem_alloc, kmemtrace_alloc_entry, TRACE_KMEM_ALLOC, diff --git a/trunk/kernel/trace/trace_power.c b/trunk/kernel/trace/trace_power.c new file mode 100644 index 000000000000..fe1a00f1445a --- /dev/null +++ b/trunk/kernel/trace/trace_power.c @@ -0,0 +1,218 @@ +/* + * ring buffer based C-state tracer + * + * Arjan van de Ven + * Copyright (C) 2008 Intel Corporation + * + * Much is borrowed from trace_boot.c which is + * Copyright (C) 2008 Frederic Weisbecker + * + */ + +#include +#include +#include +#include +#include + +#include "trace.h" +#include "trace_output.h" + +static struct trace_array *power_trace; +static int __read_mostly trace_power_enabled; + +static void probe_power_start(struct power_trace *it, unsigned int type, + unsigned int level) +{ + if (!trace_power_enabled) + return; + + memset(it, 0, sizeof(struct power_trace)); + it->state = level; + it->type = type; + it->stamp = ktime_get(); +} + + +static void probe_power_end(struct power_trace *it) +{ + struct ftrace_event_call *call = &event_power; + struct ring_buffer_event *event; + struct ring_buffer *buffer; + struct trace_power *entry; + struct trace_array_cpu *data; + struct trace_array *tr = power_trace; + + if (!trace_power_enabled) + return; + + buffer = tr->buffer; + + preempt_disable(); + it->end = ktime_get(); + data = tr->data[smp_processor_id()]; + + event = trace_buffer_lock_reserve(buffer, TRACE_POWER, + sizeof(*entry), 0, 0); + if (!event) + goto out; + entry = ring_buffer_event_data(event); + entry->state_data = *it; + if (!filter_check_discard(call, entry, buffer, event)) + trace_buffer_unlock_commit(buffer, event, 0, 0); + out: + preempt_enable(); +} + +static void probe_power_mark(struct power_trace *it, unsigned int type, + unsigned int level) +{ + struct ftrace_event_call *call = &event_power; + struct ring_buffer_event *event; + struct ring_buffer *buffer; + struct trace_power *entry; + struct trace_array_cpu *data; + struct trace_array *tr = power_trace; + + if (!trace_power_enabled) + return; + + buffer = tr->buffer; + + memset(it, 0, sizeof(struct power_trace)); + it->state = level; + it->type = type; + it->stamp = ktime_get(); + preempt_disable(); + it->end = it->stamp; + data = tr->data[smp_processor_id()]; + + event = trace_buffer_lock_reserve(buffer, TRACE_POWER, + sizeof(*entry), 0, 0); + if (!event) + goto out; + entry = ring_buffer_event_data(event); + entry->state_data = *it; + if (!filter_check_discard(call, entry, buffer, event)) + trace_buffer_unlock_commit(buffer, event, 0, 0); + out: + preempt_enable(); +} + +static int tracing_power_register(void) +{ + int ret; + + ret = register_trace_power_start(probe_power_start); + if (ret) { + pr_info("power trace: Couldn't activate tracepoint" + " probe to trace_power_start\n"); + return ret; + } + ret = register_trace_power_end(probe_power_end); + if (ret) { + pr_info("power trace: Couldn't activate tracepoint" + " probe to trace_power_end\n"); + goto fail_start; + } + ret = register_trace_power_mark(probe_power_mark); + if (ret) { + pr_info("power trace: Couldn't activate tracepoint" + " probe to trace_power_mark\n"); + goto fail_end; + } + return ret; +fail_end: + unregister_trace_power_end(probe_power_end); +fail_start: + unregister_trace_power_start(probe_power_start); + return ret; +} + +static void start_power_trace(struct trace_array *tr) +{ + trace_power_enabled = 1; +} + +static void stop_power_trace(struct trace_array *tr) +{ + trace_power_enabled = 0; +} + +static void power_trace_reset(struct trace_array *tr) +{ + trace_power_enabled = 0; + unregister_trace_power_start(probe_power_start); + unregister_trace_power_end(probe_power_end); + unregister_trace_power_mark(probe_power_mark); +} + + +static int power_trace_init(struct trace_array *tr) +{ + power_trace = tr; + + trace_power_enabled = 1; + tracing_power_register(); + + tracing_reset_online_cpus(tr); + return 0; +} + +static enum print_line_t power_print_line(struct trace_iterator *iter) +{ + int ret = 0; + struct trace_entry *entry = iter->ent; + struct trace_power *field ; + struct power_trace *it; + struct trace_seq *s = &iter->seq; + struct timespec stamp; + struct timespec duration; + + trace_assign_type(field, entry); + it = &field->state_data; + stamp = ktime_to_timespec(it->stamp); + duration = ktime_to_timespec(ktime_sub(it->end, it->stamp)); + + if (entry->type == TRACE_POWER) { + if (it->type == POWER_CSTATE) + ret = trace_seq_printf(s, "[%5ld.%09ld] CSTATE: Going to C%i on cpu %i for %ld.%09ld\n", + stamp.tv_sec, + stamp.tv_nsec, + it->state, iter->cpu, + duration.tv_sec, + duration.tv_nsec); + if (it->type == POWER_PSTATE) + ret = trace_seq_printf(s, "[%5ld.%09ld] PSTATE: Going to P%i on cpu %i\n", + stamp.tv_sec, + stamp.tv_nsec, + it->state, iter->cpu); + if (!ret) + return TRACE_TYPE_PARTIAL_LINE; + return TRACE_TYPE_HANDLED; + } + return TRACE_TYPE_UNHANDLED; +} + +static void power_print_header(struct seq_file *s) +{ + seq_puts(s, "# TIMESTAMP STATE EVENT\n"); + seq_puts(s, "# | | |\n"); +} + +static struct tracer power_tracer __read_mostly = +{ + .name = "power", + .init = power_trace_init, + .start = start_power_trace, + .stop = stop_power_trace, + .reset = power_trace_reset, + .print_line = power_print_line, + .print_header = power_print_header, +}; + +static int init_power_trace(void) +{ + return register_tracer(&power_tracer); +} +device_initcall(init_power_trace); diff --git a/trunk/scripts/tracing/power.pl b/trunk/scripts/tracing/power.pl new file mode 100644 index 000000000000..4f729b3501e0 --- /dev/null +++ b/trunk/scripts/tracing/power.pl @@ -0,0 +1,108 @@ +#!/usr/bin/perl + +# Copyright 2008, Intel Corporation +# +# This file is part of the Linux kernel +# +# This program file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# +# Authors: +# Arjan van de Ven + + +# +# This script turns a cstate ftrace output into a SVG graphic that shows +# historic C-state information +# +# +# cat /sys/kernel/debug/tracing/trace | perl power.pl > out.svg +# + +my @styles; +my $base = 0; + +my @pstate_last; +my @pstate_level; + +$styles[0] = "fill:rgb(0,0,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)"; +$styles[1] = "fill:rgb(0,255,0);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)"; +$styles[2] = "fill:rgb(255,0,20);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)"; +$styles[3] = "fill:rgb(255,255,20);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)"; +$styles[4] = "fill:rgb(255,0,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)"; +$styles[5] = "fill:rgb(0,255,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)"; +$styles[6] = "fill:rgb(0,128,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)"; +$styles[7] = "fill:rgb(0,255,128);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)"; +$styles[8] = "fill:rgb(0,25,20);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)"; + + +print " \n"; +print "\n"; + +my $scale = 30000.0; +while (<>) { + my $line = $_; + if ($line =~ /([0-9\.]+)\] CSTATE: Going to C([0-9]) on cpu ([0-9]+) for ([0-9\.]+)/) { + if ($base == 0) { + $base = $1; + } + my $time = $1 - $base; + $time = $time * $scale; + my $C = $2; + my $cpu = $3; + my $y = 400 * $cpu; + my $duration = $4 * $scale; + my $msec = int($4 * 100000)/100.0; + my $height = $C * 20; + $style = $styles[$C]; + + $y = $y + 140 - $height; + + $x2 = $time + 4; + $y2 = $y + 4; + + + print "\n"; + print "C$C $msec\n"; + } + if ($line =~ /([0-9\.]+)\] PSTATE: Going to P([0-9]) on cpu ([0-9]+)/) { + my $time = $1 - $base; + my $state = $2; + my $cpu = $3; + + if (defined($pstate_last[$cpu])) { + my $from = $pstate_last[$cpu]; + my $oldstate = $pstate_state[$cpu]; + my $duration = ($time-$from) * $scale; + + $from = $from * $scale; + my $to = $from + $duration; + my $height = 140 - ($oldstate * (140/8)); + + my $y = 400 * $cpu + 200 + $height; + my $y2 = $y+4; + my $style = $styles[8]; + + print "\n"; + print "P$oldstate (cpu $cpu)\n"; + }; + + $pstate_last[$cpu] = $time; + $pstate_state[$cpu] = $state; + } +} + + +print "\n"; diff --git a/trunk/sound/sound_core.c b/trunk/sound/sound_core.c index 49c998186592..bb4b88e606bb 100644 --- a/trunk/sound/sound_core.c +++ b/trunk/sound/sound_core.c @@ -29,7 +29,7 @@ MODULE_DESCRIPTION("Core sound module"); MODULE_AUTHOR("Alan Cox"); MODULE_LICENSE("GPL"); -static char *sound_devnode(struct device *dev, mode_t *mode) +static char *sound_nodename(struct device *dev) { if (MAJOR(dev->devt) == SOUND_MAJOR) return NULL; @@ -50,7 +50,7 @@ static int __init init_soundcore(void) return PTR_ERR(sound_class); } - sound_class->devnode = sound_devnode; + sound_class->nodename = sound_nodename; return 0; } diff --git a/trunk/tools/perf/Documentation/perf-sched.txt b/trunk/tools/perf/Documentation/perf-sched.txt deleted file mode 100644 index 1ce79198997b..000000000000 --- a/trunk/tools/perf/Documentation/perf-sched.txt +++ /dev/null @@ -1,41 +0,0 @@ -perf-sched(1) -============== - -NAME ----- -perf-sched - Tool to trace/measure scheduler properties (latencies) - -SYNOPSIS --------- -[verse] -'perf sched' {record|latency|replay|trace} - -DESCRIPTION ------------ -There's four variants of perf sched: - - 'perf sched record ' to record the scheduling events - of an arbitrary workload. - - 'perf sched latency' to report the per task scheduling latencies - and other scheduling properties of the workload. - - 'perf sched trace' to see a detailed trace of the workload that - was recorded. - - 'perf sched replay' to simulate the workload that was recorded - via perf sched record. (this is done by starting up mockup threads - that mimic the workload based on the events in the trace. These - threads can then replay the timings (CPU runtime and sleep patterns) - of the workload as it occured when it was recorded - and can repeat - it a number of times, measuring its performance.) - -OPTIONS -------- --D:: ---dump-raw-trace=:: - Display verbose dump of the sched data. - -SEE ALSO --------- -linkperf:perf-record[1] diff --git a/trunk/tools/perf/Documentation/perf-timechart.txt b/trunk/tools/perf/Documentation/perf-timechart.txt deleted file mode 100644 index 61e0104c6270..000000000000 --- a/trunk/tools/perf/Documentation/perf-timechart.txt +++ /dev/null @@ -1,35 +0,0 @@ -perf-timechart(1) -================= - -NAME ----- -perf-timechart - Tool to visualize total system behavior during a workload - -SYNOPSIS --------- -[verse] -'perf timechart' {record} - -DESCRIPTION ------------ -There are two variants of perf timechart: - - 'perf timechart record ' to record the system level events - of an arbitrary workload. - - 'perf timechart' to turn a trace into a Scalable Vector Graphics file, - that can be viewed with popular SVG viewers such as 'Inkscape'. - -OPTIONS -------- --o:: ---output=:: - Select the output file (default: output.svg) --i:: ---input=:: - Select the input file (default: perf.data) - - -SEE ALSO --------- -linkperf:perf-record[1] diff --git a/trunk/tools/perf/Documentation/perf-trace.txt b/trunk/tools/perf/Documentation/perf-trace.txt deleted file mode 100644 index 41ed75398ca9..000000000000 --- a/trunk/tools/perf/Documentation/perf-trace.txt +++ /dev/null @@ -1,25 +0,0 @@ -perf-trace(1) -============== - -NAME ----- -perf-trace - Read perf.data (created by perf record) and display trace output - -SYNOPSIS --------- -[verse] -'perf trace' [-i | --input=file] symbol_name - -DESCRIPTION ------------ -This command reads the input file and displays the trace recorded. - -OPTIONS -------- --D:: ---dump-raw-trace=:: - Display verbose dump of the trace data. - -SEE ALSO --------- -linkperf:perf-record[1] diff --git a/trunk/tools/perf/Makefile b/trunk/tools/perf/Makefile index 0aba8b6e9c54..9f8d207a91bf 100644 --- a/trunk/tools/perf/Makefile +++ b/trunk/tools/perf/Makefile @@ -373,16 +373,13 @@ LIB_OBJS += util/thread.o LIB_OBJS += util/trace-event-parse.o LIB_OBJS += util/trace-event-read.o LIB_OBJS += util/trace-event-info.o -LIB_OBJS += util/svghelper.o BUILTIN_OBJS += builtin-annotate.o BUILTIN_OBJS += builtin-help.o -BUILTIN_OBJS += builtin-sched.o BUILTIN_OBJS += builtin-list.o BUILTIN_OBJS += builtin-record.o BUILTIN_OBJS += builtin-report.o BUILTIN_OBJS += builtin-stat.o -BUILTIN_OBJS += builtin-timechart.o BUILTIN_OBJS += builtin-top.o BUILTIN_OBJS += builtin-trace.o @@ -713,12 +710,6 @@ builtin-help.o: builtin-help.c common-cmds.h PERF-CFLAGS '-DPERF_MAN_PATH="$(mandir_SQ)"' \ '-DPERF_INFO_PATH="$(infodir_SQ)"' $< -builtin-timechart.o: builtin-timechart.c common-cmds.h PERF-CFLAGS - $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \ - '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ - '-DPERF_MAN_PATH="$(mandir_SQ)"' \ - '-DPERF_INFO_PATH="$(infodir_SQ)"' $< - $(BUILT_INS): perf$X $(QUIET_BUILT_IN)$(RM) $@ && \ ln perf$X $@ 2>/dev/null || \ diff --git a/trunk/tools/perf/builtin-record.c b/trunk/tools/perf/builtin-record.c index 2459e5a22ed8..99a12fe86e9f 100644 --- a/trunk/tools/perf/builtin-record.c +++ b/trunk/tools/perf/builtin-record.c @@ -48,8 +48,6 @@ static int call_graph = 0; static int inherit_stat = 0; static int no_samples = 0; static int sample_address = 0; -static int multiplex = 0; -static int multiplex_fd = -1; static long samples; static struct timeval last_read; @@ -472,28 +470,19 @@ static void create_counter(int counter, int cpu, pid_t pid) */ if (group && group_fd == -1) group_fd = fd[nr_cpu][counter]; - if (multiplex && multiplex_fd == -1) - multiplex_fd = fd[nr_cpu][counter]; - if (multiplex && fd[nr_cpu][counter] != multiplex_fd) { - int ret; - - ret = ioctl(fd[nr_cpu][counter], PERF_COUNTER_IOC_SET_OUTPUT, multiplex_fd); - assert(ret != -1); - } else { - event_array[nr_poll].fd = fd[nr_cpu][counter]; - event_array[nr_poll].events = POLLIN; - nr_poll++; - - mmap_array[nr_cpu][counter].counter = counter; - mmap_array[nr_cpu][counter].prev = 0; - mmap_array[nr_cpu][counter].mask = mmap_pages*page_size - 1; - mmap_array[nr_cpu][counter].base = mmap(NULL, (mmap_pages+1)*page_size, - PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter], 0); - if (mmap_array[nr_cpu][counter].base == MAP_FAILED) { - error("failed to mmap with %d (%s)\n", errno, strerror(errno)); - exit(-1); - } + event_array[nr_poll].fd = fd[nr_cpu][counter]; + event_array[nr_poll].events = POLLIN; + nr_poll++; + + mmap_array[nr_cpu][counter].counter = counter; + mmap_array[nr_cpu][counter].prev = 0; + mmap_array[nr_cpu][counter].mask = mmap_pages*page_size - 1; + mmap_array[nr_cpu][counter].base = mmap(NULL, (mmap_pages+1)*page_size, + PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter], 0); + if (mmap_array[nr_cpu][counter].base == MAP_FAILED) { + error("failed to mmap with %d (%s)\n", errno, strerror(errno)); + exit(-1); } ioctl(fd[nr_cpu][counter], PERF_COUNTER_IOC_ENABLE); @@ -524,7 +513,6 @@ static int __cmd_record(int argc, const char **argv) pid_t pid = 0; int flags; int ret; - unsigned long waking = 0; page_size = sysconf(_SC_PAGE_SIZE); nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); @@ -626,29 +614,17 @@ static int __cmd_record(int argc, const char **argv) int hits = samples; for (i = 0; i < nr_cpu; i++) { - for (counter = 0; counter < nr_counters; counter++) { - if (mmap_array[i][counter].base) - mmap_read(&mmap_array[i][counter]); - } + for (counter = 0; counter < nr_counters; counter++) + mmap_read(&mmap_array[i][counter]); } if (hits == samples) { if (done) break; - ret = poll(event_array, nr_poll, -1); - waking++; - } - - if (done) { - for (i = 0; i < nr_cpu; i++) { - for (counter = 0; counter < nr_counters; counter++) - ioctl(fd[i][counter], PERF_COUNTER_IOC_DISABLE); - } + ret = poll(event_array, nr_poll, 100); } } - fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking); - /* * Approximate RIP event size: 24 bytes. */ @@ -705,8 +681,6 @@ static const struct option options[] = { "Sample addresses"), OPT_BOOLEAN('n', "no-samples", &no_samples, "don't sample"), - OPT_BOOLEAN('M', "multiplex", &multiplex, - "multiplex counter output in a single channel"), OPT_END() }; diff --git a/trunk/tools/perf/builtin-sched.c b/trunk/tools/perf/builtin-sched.c deleted file mode 100644 index 275d79c6627a..000000000000 --- a/trunk/tools/perf/builtin-sched.c +++ /dev/null @@ -1,2004 +0,0 @@ -#include "builtin.h" -#include "perf.h" - -#include "util/util.h" -#include "util/cache.h" -#include "util/symbol.h" -#include "util/thread.h" -#include "util/header.h" - -#include "util/parse-options.h" -#include "util/trace-event.h" - -#include "util/debug.h" - -#include -#include - -#include -#include -#include - -static char const *input_name = "perf.data"; -static int input; -static unsigned long page_size; -static unsigned long mmap_window = 32; - -static unsigned long total_comm = 0; - -static struct rb_root threads; -static struct thread *last_match; - -static struct perf_header *header; -static u64 sample_type; - -static char default_sort_order[] = "avg, max, switch, runtime"; -static char *sort_order = default_sort_order; - -#define PR_SET_NAME 15 /* Set process name */ -#define MAX_CPUS 4096 - -#define BUG_ON(x) assert(!(x)) - -static u64 run_measurement_overhead; -static u64 sleep_measurement_overhead; - -#define COMM_LEN 20 -#define SYM_LEN 129 - -#define MAX_PID 65536 - -static unsigned long nr_tasks; - -struct sched_atom; - -struct task_desc { - unsigned long nr; - unsigned long pid; - char comm[COMM_LEN]; - - unsigned long nr_events; - unsigned long curr_event; - struct sched_atom **atoms; - - pthread_t thread; - sem_t sleep_sem; - - sem_t ready_for_work; - sem_t work_done_sem; - - u64 cpu_usage; -}; - -enum sched_event_type { - SCHED_EVENT_RUN, - SCHED_EVENT_SLEEP, - SCHED_EVENT_WAKEUP, -}; - -struct sched_atom { - enum sched_event_type type; - u64 timestamp; - u64 duration; - unsigned long nr; - int specific_wait; - sem_t *wait_sem; - struct task_desc *wakee; -}; - -static struct task_desc *pid_to_task[MAX_PID]; - -static struct task_desc **tasks; - -static pthread_mutex_t start_work_mutex = PTHREAD_MUTEX_INITIALIZER; -static u64 start_time; - -static pthread_mutex_t work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER; - -static unsigned long nr_run_events; -static unsigned long nr_sleep_events; -static unsigned long nr_wakeup_events; - -static unsigned long nr_sleep_corrections; -static unsigned long nr_run_events_optimized; - -static unsigned long targetless_wakeups; -static unsigned long multitarget_wakeups; - -static u64 cpu_usage; -static u64 runavg_cpu_usage; -static u64 parent_cpu_usage; -static u64 runavg_parent_cpu_usage; - -static unsigned long nr_runs; -static u64 sum_runtime; -static u64 sum_fluct; -static u64 run_avg; - -static unsigned long replay_repeat = 10; -static unsigned long nr_timestamps; -static unsigned long nr_unordered_timestamps; -static unsigned long nr_state_machine_bugs; -static unsigned long nr_context_switch_bugs; -static unsigned long nr_events; -static unsigned long nr_lost_chunks; -static unsigned long nr_lost_events; - -#define TASK_STATE_TO_CHAR_STR "RSDTtZX" - -enum thread_state { - THREAD_SLEEPING = 0, - THREAD_WAIT_CPU, - THREAD_SCHED_IN, - THREAD_IGNORE -}; - -struct work_atom { - struct list_head list; - enum thread_state state; - u64 sched_out_time; - u64 wake_up_time; - u64 sched_in_time; - u64 runtime; -}; - -struct work_atoms { - struct list_head work_list; - struct thread *thread; - struct rb_node node; - u64 max_lat; - u64 total_lat; - u64 nb_atoms; - u64 total_runtime; -}; - -typedef int (*sort_fn_t)(struct work_atoms *, struct work_atoms *); - -static struct rb_root atom_root, sorted_atom_root; - -static u64 all_runtime; -static u64 all_count; - - -static u64 get_nsecs(void) -{ - struct timespec ts; - - clock_gettime(CLOCK_MONOTONIC, &ts); - - return ts.tv_sec * 1000000000ULL + ts.tv_nsec; -} - -static void burn_nsecs(u64 nsecs) -{ - u64 T0 = get_nsecs(), T1; - - do { - T1 = get_nsecs(); - } while (T1 + run_measurement_overhead < T0 + nsecs); -} - -static void sleep_nsecs(u64 nsecs) -{ - struct timespec ts; - - ts.tv_nsec = nsecs % 999999999; - ts.tv_sec = nsecs / 999999999; - - nanosleep(&ts, NULL); -} - -static void calibrate_run_measurement_overhead(void) -{ - u64 T0, T1, delta, min_delta = 1000000000ULL; - int i; - - for (i = 0; i < 10; i++) { - T0 = get_nsecs(); - burn_nsecs(0); - T1 = get_nsecs(); - delta = T1-T0; - min_delta = min(min_delta, delta); - } - run_measurement_overhead = min_delta; - - printf("run measurement overhead: %Ld nsecs\n", min_delta); -} - -static void calibrate_sleep_measurement_overhead(void) -{ - u64 T0, T1, delta, min_delta = 1000000000ULL; - int i; - - for (i = 0; i < 10; i++) { - T0 = get_nsecs(); - sleep_nsecs(10000); - T1 = get_nsecs(); - delta = T1-T0; - min_delta = min(min_delta, delta); - } - min_delta -= 10000; - sleep_measurement_overhead = min_delta; - - printf("sleep measurement overhead: %Ld nsecs\n", min_delta); -} - -static struct sched_atom * -get_new_event(struct task_desc *task, u64 timestamp) -{ - struct sched_atom *event = calloc(1, sizeof(*event)); - unsigned long idx = task->nr_events; - size_t size; - - event->timestamp = timestamp; - event->nr = idx; - - task->nr_events++; - size = sizeof(struct sched_atom *) * task->nr_events; - task->atoms = realloc(task->atoms, size); - BUG_ON(!task->atoms); - - task->atoms[idx] = event; - - return event; -} - -static struct sched_atom *last_event(struct task_desc *task) -{ - if (!task->nr_events) - return NULL; - - return task->atoms[task->nr_events - 1]; -} - -static void -add_sched_event_run(struct task_desc *task, u64 timestamp, u64 duration) -{ - struct sched_atom *event, *curr_event = last_event(task); - - /* - * optimize an existing RUN event by merging this one - * to it: - */ - if (curr_event && curr_event->type == SCHED_EVENT_RUN) { - nr_run_events_optimized++; - curr_event->duration += duration; - return; - } - - event = get_new_event(task, timestamp); - - event->type = SCHED_EVENT_RUN; - event->duration = duration; - - nr_run_events++; -} - -static void -add_sched_event_wakeup(struct task_desc *task, u64 timestamp, - struct task_desc *wakee) -{ - struct sched_atom *event, *wakee_event; - - event = get_new_event(task, timestamp); - event->type = SCHED_EVENT_WAKEUP; - event->wakee = wakee; - - wakee_event = last_event(wakee); - if (!wakee_event || wakee_event->type != SCHED_EVENT_SLEEP) { - targetless_wakeups++; - return; - } - if (wakee_event->wait_sem) { - multitarget_wakeups++; - return; - } - - wakee_event->wait_sem = calloc(1, sizeof(*wakee_event->wait_sem)); - sem_init(wakee_event->wait_sem, 0, 0); - wakee_event->specific_wait = 1; - event->wait_sem = wakee_event->wait_sem; - - nr_wakeup_events++; -} - -static void -add_sched_event_sleep(struct task_desc *task, u64 timestamp, - u64 task_state __used) -{ - struct sched_atom *event = get_new_event(task, timestamp); - - event->type = SCHED_EVENT_SLEEP; - - nr_sleep_events++; -} - -static struct task_desc *register_pid(unsigned long pid, const char *comm) -{ - struct task_desc *task; - - BUG_ON(pid >= MAX_PID); - - task = pid_to_task[pid]; - - if (task) - return task; - - task = calloc(1, sizeof(*task)); - task->pid = pid; - task->nr = nr_tasks; - strcpy(task->comm, comm); - /* - * every task starts in sleeping state - this gets ignored - * if there's no wakeup pointing to this sleep state: - */ - add_sched_event_sleep(task, 0, 0); - - pid_to_task[pid] = task; - nr_tasks++; - tasks = realloc(tasks, nr_tasks*sizeof(struct task_task *)); - BUG_ON(!tasks); - tasks[task->nr] = task; - - if (verbose) - printf("registered task #%ld, PID %ld (%s)\n", nr_tasks, pid, comm); - - return task; -} - - -static void print_task_traces(void) -{ - struct task_desc *task; - unsigned long i; - - for (i = 0; i < nr_tasks; i++) { - task = tasks[i]; - printf("task %6ld (%20s:%10ld), nr_events: %ld\n", - task->nr, task->comm, task->pid, task->nr_events); - } -} - -static void add_cross_task_wakeups(void) -{ - struct task_desc *task1, *task2; - unsigned long i, j; - - for (i = 0; i < nr_tasks; i++) { - task1 = tasks[i]; - j = i + 1; - if (j == nr_tasks) - j = 0; - task2 = tasks[j]; - add_sched_event_wakeup(task1, 0, task2); - } -} - -static void -process_sched_event(struct task_desc *this_task __used, struct sched_atom *atom) -{ - int ret = 0; - u64 now; - long long delta; - - now = get_nsecs(); - delta = start_time + atom->timestamp - now; - - switch (atom->type) { - case SCHED_EVENT_RUN: - burn_nsecs(atom->duration); - break; - case SCHED_EVENT_SLEEP: - if (atom->wait_sem) - ret = sem_wait(atom->wait_sem); - BUG_ON(ret); - break; - case SCHED_EVENT_WAKEUP: - if (atom->wait_sem) - ret = sem_post(atom->wait_sem); - BUG_ON(ret); - break; - default: - BUG_ON(1); - } -} - -static u64 get_cpu_usage_nsec_parent(void) -{ - struct rusage ru; - u64 sum; - int err; - - err = getrusage(RUSAGE_SELF, &ru); - BUG_ON(err); - - sum = ru.ru_utime.tv_sec*1e9 + ru.ru_utime.tv_usec*1e3; - sum += ru.ru_stime.tv_sec*1e9 + ru.ru_stime.tv_usec*1e3; - - return sum; -} - -static u64 get_cpu_usage_nsec_self(void) -{ - char filename [] = "/proc/1234567890/sched"; - unsigned long msecs, nsecs; - char *line = NULL; - u64 total = 0; - size_t len = 0; - ssize_t chars; - FILE *file; - int ret; - - sprintf(filename, "/proc/%d/sched", getpid()); - file = fopen(filename, "r"); - BUG_ON(!file); - - while ((chars = getline(&line, &len, file)) != -1) { - ret = sscanf(line, "se.sum_exec_runtime : %ld.%06ld\n", - &msecs, &nsecs); - if (ret == 2) { - total = msecs*1e6 + nsecs; - break; - } - } - if (line) - free(line); - fclose(file); - - return total; -} - -static void *thread_func(void *ctx) -{ - struct task_desc *this_task = ctx; - u64 cpu_usage_0, cpu_usage_1; - unsigned long i, ret; - char comm2[22]; - - sprintf(comm2, ":%s", this_task->comm); - prctl(PR_SET_NAME, comm2); - -again: - ret = sem_post(&this_task->ready_for_work); - BUG_ON(ret); - ret = pthread_mutex_lock(&start_work_mutex); - BUG_ON(ret); - ret = pthread_mutex_unlock(&start_work_mutex); - BUG_ON(ret); - - cpu_usage_0 = get_cpu_usage_nsec_self(); - - for (i = 0; i < this_task->nr_events; i++) { - this_task->curr_event = i; - process_sched_event(this_task, this_task->atoms[i]); - } - - cpu_usage_1 = get_cpu_usage_nsec_self(); - this_task->cpu_usage = cpu_usage_1 - cpu_usage_0; - - ret = sem_post(&this_task->work_done_sem); - BUG_ON(ret); - - ret = pthread_mutex_lock(&work_done_wait_mutex); - BUG_ON(ret); - ret = pthread_mutex_unlock(&work_done_wait_mutex); - BUG_ON(ret); - - goto again; -} - -static void create_tasks(void) -{ - struct task_desc *task; - pthread_attr_t attr; - unsigned long i; - int err; - - err = pthread_attr_init(&attr); - BUG_ON(err); - err = pthread_attr_setstacksize(&attr, (size_t)(16*1024)); - BUG_ON(err); - err = pthread_mutex_lock(&start_work_mutex); - BUG_ON(err); - err = pthread_mutex_lock(&work_done_wait_mutex); - BUG_ON(err); - for (i = 0; i < nr_tasks; i++) { - task = tasks[i]; - sem_init(&task->sleep_sem, 0, 0); - sem_init(&task->ready_for_work, 0, 0); - sem_init(&task->work_done_sem, 0, 0); - task->curr_event = 0; - err = pthread_create(&task->thread, &attr, thread_func, task); - BUG_ON(err); - } -} - -static void wait_for_tasks(void) -{ - u64 cpu_usage_0, cpu_usage_1; - struct task_desc *task; - unsigned long i, ret; - - start_time = get_nsecs(); - cpu_usage = 0; - pthread_mutex_unlock(&work_done_wait_mutex); - - for (i = 0; i < nr_tasks; i++) { - task = tasks[i]; - ret = sem_wait(&task->ready_for_work); - BUG_ON(ret); - sem_init(&task->ready_for_work, 0, 0); - } - ret = pthread_mutex_lock(&work_done_wait_mutex); - BUG_ON(ret); - - cpu_usage_0 = get_cpu_usage_nsec_parent(); - - pthread_mutex_unlock(&start_work_mutex); - - for (i = 0; i < nr_tasks; i++) { - task = tasks[i]; - ret = sem_wait(&task->work_done_sem); - BUG_ON(ret); - sem_init(&task->work_done_sem, 0, 0); - cpu_usage += task->cpu_usage; - task->cpu_usage = 0; - } - - cpu_usage_1 = get_cpu_usage_nsec_parent(); - if (!runavg_cpu_usage) - runavg_cpu_usage = cpu_usage; - runavg_cpu_usage = (runavg_cpu_usage*9 + cpu_usage)/10; - - parent_cpu_usage = cpu_usage_1 - cpu_usage_0; - if (!runavg_parent_cpu_usage) - runavg_parent_cpu_usage = parent_cpu_usage; - runavg_parent_cpu_usage = (runavg_parent_cpu_usage*9 + - parent_cpu_usage)/10; - - ret = pthread_mutex_lock(&start_work_mutex); - BUG_ON(ret); - - for (i = 0; i < nr_tasks; i++) { - task = tasks[i]; - sem_init(&task->sleep_sem, 0, 0); - task->curr_event = 0; - } -} - -static void run_one_test(void) -{ - u64 T0, T1, delta, avg_delta, fluct, std_dev; - - T0 = get_nsecs(); - wait_for_tasks(); - T1 = get_nsecs(); - - delta = T1 - T0; - sum_runtime += delta; - nr_runs++; - - avg_delta = sum_runtime / nr_runs; - if (delta < avg_delta) - fluct = avg_delta - delta; - else - fluct = delta - avg_delta; - sum_fluct += fluct; - std_dev = sum_fluct / nr_runs / sqrt(nr_runs); - if (!run_avg) - run_avg = delta; - run_avg = (run_avg*9 + delta)/10; - - printf("#%-3ld: %0.3f, ", - nr_runs, (double)delta/1000000.0); - - printf("ravg: %0.2f, ", - (double)run_avg/1e6); - - printf("cpu: %0.2f / %0.2f", - (double)cpu_usage/1e6, (double)runavg_cpu_usage/1e6); - -#if 0 - /* - * rusage statistics done by the parent, these are less - * accurate than the sum_exec_runtime based statistics: - */ - printf(" [%0.2f / %0.2f]", - (double)parent_cpu_usage/1e6, - (double)runavg_parent_cpu_usage/1e6); -#endif - - printf("\n"); - - if (nr_sleep_corrections) - printf(" (%ld sleep corrections)\n", nr_sleep_corrections); - nr_sleep_corrections = 0; -} - -static void test_calibrations(void) -{ - u64 T0, T1; - - T0 = get_nsecs(); - burn_nsecs(1e6); - T1 = get_nsecs(); - - printf("the run test took %Ld nsecs\n", T1-T0); - - T0 = get_nsecs(); - sleep_nsecs(1e6); - T1 = get_nsecs(); - - printf("the sleep test took %Ld nsecs\n", T1-T0); -} - -static int -process_comm_event(event_t *event, unsigned long offset, unsigned long head) -{ - struct thread *thread; - - thread = threads__findnew(event->comm.pid, &threads, &last_match); - - dump_printf("%p [%p]: perf_event_comm: %s:%d\n", - (void *)(offset + head), - (void *)(long)(event->header.size), - event->comm.comm, event->comm.pid); - - if (thread == NULL || - thread__set_comm(thread, event->comm.comm)) { - dump_printf("problem processing perf_event_comm, skipping event.\n"); - return -1; - } - total_comm++; - - return 0; -} - - -struct raw_event_sample { - u32 size; - char data[0]; -}; - -#define FILL_FIELD(ptr, field, event, data) \ - ptr.field = (typeof(ptr.field)) raw_field_value(event, #field, data) - -#define FILL_ARRAY(ptr, array, event, data) \ -do { \ - void *__array = raw_field_ptr(event, #array, data); \ - memcpy(ptr.array, __array, sizeof(ptr.array)); \ -} while(0) - -#define FILL_COMMON_FIELDS(ptr, event, data) \ -do { \ - FILL_FIELD(ptr, common_type, event, data); \ - FILL_FIELD(ptr, common_flags, event, data); \ - FILL_FIELD(ptr, common_preempt_count, event, data); \ - FILL_FIELD(ptr, common_pid, event, data); \ - FILL_FIELD(ptr, common_tgid, event, data); \ -} while (0) - - - -struct trace_switch_event { - u32 size; - - u16 common_type; - u8 common_flags; - u8 common_preempt_count; - u32 common_pid; - u32 common_tgid; - - char prev_comm[16]; - u32 prev_pid; - u32 prev_prio; - u64 prev_state; - char next_comm[16]; - u32 next_pid; - u32 next_prio; -}; - -struct trace_runtime_event { - u32 size; - - u16 common_type; - u8 common_flags; - u8 common_preempt_count; - u32 common_pid; - u32 common_tgid; - - char comm[16]; - u32 pid; - u64 runtime; - u64 vruntime; -}; - -struct trace_wakeup_event { - u32 size; - - u16 common_type; - u8 common_flags; - u8 common_preempt_count; - u32 common_pid; - u32 common_tgid; - - char comm[16]; - u32 pid; - - u32 prio; - u32 success; - u32 cpu; -}; - -struct trace_fork_event { - u32 size; - - u16 common_type; - u8 common_flags; - u8 common_preempt_count; - u32 common_pid; - u32 common_tgid; - - char parent_comm[16]; - u32 parent_pid; - char child_comm[16]; - u32 child_pid; -}; - -struct trace_sched_handler { - void (*switch_event)(struct trace_switch_event *, - struct event *, - int cpu, - u64 timestamp, - struct thread *thread); - - void (*runtime_event)(struct trace_runtime_event *, - struct event *, - int cpu, - u64 timestamp, - struct thread *thread); - - void (*wakeup_event)(struct trace_wakeup_event *, - struct event *, - int cpu, - u64 timestamp, - struct thread *thread); - - void (*fork_event)(struct trace_fork_event *, - struct event *, - int cpu, - u64 timestamp, - struct thread *thread); -}; - - -static void -replay_wakeup_event(struct trace_wakeup_event *wakeup_event, - struct event *event, - int cpu __used, - u64 timestamp __used, - struct thread *thread __used) -{ - struct task_desc *waker, *wakee; - - if (verbose) { - printf("sched_wakeup event %p\n", event); - - printf(" ... pid %d woke up %s/%d\n", - wakeup_event->common_pid, - wakeup_event->comm, - wakeup_event->pid); - } - - waker = register_pid(wakeup_event->common_pid, ""); - wakee = register_pid(wakeup_event->pid, wakeup_event->comm); - - add_sched_event_wakeup(waker, timestamp, wakee); -} - -static u64 cpu_last_switched[MAX_CPUS]; - -static void -replay_switch_event(struct trace_switch_event *switch_event, - struct event *event, - int cpu, - u64 timestamp, - struct thread *thread __used) -{ - struct task_desc *prev, *next; - u64 timestamp0; - s64 delta; - - if (verbose) - printf("sched_switch event %p\n", event); - - if (cpu >= MAX_CPUS || cpu < 0) - return; - - timestamp0 = cpu_last_switched[cpu]; - if (timestamp0) - delta = timestamp - timestamp0; - else - delta = 0; - - if (delta < 0) - die("hm, delta: %Ld < 0 ?\n", delta); - - if (verbose) { - printf(" ... switch from %s/%d to %s/%d [ran %Ld nsecs]\n", - switch_event->prev_comm, switch_event->prev_pid, - switch_event->next_comm, switch_event->next_pid, - delta); - } - - prev = register_pid(switch_event->prev_pid, switch_event->prev_comm); - next = register_pid(switch_event->next_pid, switch_event->next_comm); - - cpu_last_switched[cpu] = timestamp; - - add_sched_event_run(prev, timestamp, delta); - add_sched_event_sleep(prev, timestamp, switch_event->prev_state); -} - - -static void -replay_fork_event(struct trace_fork_event *fork_event, - struct event *event, - int cpu __used, - u64 timestamp __used, - struct thread *thread __used) -{ - if (verbose) { - printf("sched_fork event %p\n", event); - printf("... parent: %s/%d\n", fork_event->parent_comm, fork_event->parent_pid); - printf("... child: %s/%d\n", fork_event->child_comm, fork_event->child_pid); - } - register_pid(fork_event->parent_pid, fork_event->parent_comm); - register_pid(fork_event->child_pid, fork_event->child_comm); -} - -static struct trace_sched_handler replay_ops = { - .wakeup_event = replay_wakeup_event, - .switch_event = replay_switch_event, - .fork_event = replay_fork_event, -}; - -struct sort_dimension { - const char *name; - sort_fn_t cmp; - struct list_head list; -}; - -static LIST_HEAD(cmp_pid); - -static int -thread_lat_cmp(struct list_head *list, struct work_atoms *l, struct work_atoms *r) -{ - struct sort_dimension *sort; - int ret = 0; - - BUG_ON(list_empty(list)); - - list_for_each_entry(sort, list, list) { - ret = sort->cmp(l, r); - if (ret) - return ret; - } - - return ret; -} - -static struct work_atoms * -thread_atoms_search(struct rb_root *root, struct thread *thread, - struct list_head *sort_list) -{ - struct rb_node *node = root->rb_node; - struct work_atoms key = { .thread = thread }; - - while (node) { - struct work_atoms *atoms; - int cmp; - - atoms = container_of(node, struct work_atoms, node); - - cmp = thread_lat_cmp(sort_list, &key, atoms); - if (cmp > 0) - node = node->rb_left; - else if (cmp < 0) - node = node->rb_right; - else { - BUG_ON(thread != atoms->thread); - return atoms; - } - } - return NULL; -} - -static void -__thread_latency_insert(struct rb_root *root, struct work_atoms *data, - struct list_head *sort_list) -{ - struct rb_node **new = &(root->rb_node), *parent = NULL; - - while (*new) { - struct work_atoms *this; - int cmp; - - this = container_of(*new, struct work_atoms, node); - parent = *new; - - cmp = thread_lat_cmp(sort_list, data, this); - - if (cmp > 0) - new = &((*new)->rb_left); - else - new = &((*new)->rb_right); - } - - rb_link_node(&data->node, parent, new); - rb_insert_color(&data->node, root); -} - -static void thread_atoms_insert(struct thread *thread) -{ - struct work_atoms *atoms; - - atoms = calloc(sizeof(*atoms), 1); - if (!atoms) - die("No memory"); - - atoms->thread = thread; - INIT_LIST_HEAD(&atoms->work_list); - __thread_latency_insert(&atom_root, atoms, &cmp_pid); -} - -static void -latency_fork_event(struct trace_fork_event *fork_event __used, - struct event *event __used, - int cpu __used, - u64 timestamp __used, - struct thread *thread __used) -{ - /* should insert the newcomer */ -} - -__used -static char sched_out_state(struct trace_switch_event *switch_event) -{ - const char *str = TASK_STATE_TO_CHAR_STR; - - return str[switch_event->prev_state]; -} - -static void -add_sched_out_event(struct work_atoms *atoms, - char run_state, - u64 timestamp) -{ - struct work_atom *atom; - - atom = calloc(sizeof(*atom), 1); - if (!atom) - die("Non memory"); - - atom->sched_out_time = timestamp; - - if (run_state == 'R') { - atom->state = THREAD_WAIT_CPU; - atom->wake_up_time = atom->sched_out_time; - } - - list_add_tail(&atom->list, &atoms->work_list); -} - -static void -add_runtime_event(struct work_atoms *atoms, u64 delta, u64 timestamp __used) -{ - struct work_atom *atom; - - BUG_ON(list_empty(&atoms->work_list)); - - atom = list_entry(atoms->work_list.prev, struct work_atom, list); - - atom->runtime += delta; - atoms->total_runtime += delta; -} - -static void -add_sched_in_event(struct work_atoms *atoms, u64 timestamp) -{ - struct work_atom *atom; - u64 delta; - - if (list_empty(&atoms->work_list)) - return; - - atom = list_entry(atoms->work_list.prev, struct work_atom, list); - - if (atom->state != THREAD_WAIT_CPU) - return; - - if (timestamp < atom->wake_up_time) { - atom->state = THREAD_IGNORE; - return; - } - - atom->state = THREAD_SCHED_IN; - atom->sched_in_time = timestamp; - - delta = atom->sched_in_time - atom->wake_up_time; - atoms->total_lat += delta; - if (delta > atoms->max_lat) - atoms->max_lat = delta; - atoms->nb_atoms++; -} - -static void -latency_switch_event(struct trace_switch_event *switch_event, - struct event *event __used, - int cpu, - u64 timestamp, - struct thread *thread __used) -{ - struct work_atoms *out_events, *in_events; - struct thread *sched_out, *sched_in; - u64 timestamp0; - s64 delta; - - BUG_ON(cpu >= MAX_CPUS || cpu < 0); - - timestamp0 = cpu_last_switched[cpu]; - cpu_last_switched[cpu] = timestamp; - if (timestamp0) - delta = timestamp - timestamp0; - else - delta = 0; - - if (delta < 0) - die("hm, delta: %Ld < 0 ?\n", delta); - - - sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match); - sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match); - - out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid); - if (!out_events) { - thread_atoms_insert(sched_out); - out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid); - if (!out_events) - die("out-event: Internal tree error"); - } - add_sched_out_event(out_events, sched_out_state(switch_event), timestamp); - - in_events = thread_atoms_search(&atom_root, sched_in, &cmp_pid); - if (!in_events) { - thread_atoms_insert(sched_in); - in_events = thread_atoms_search(&atom_root, sched_in, &cmp_pid); - if (!in_events) - die("in-event: Internal tree error"); - /* - * Take came in we have not heard about yet, - * add in an initial atom in runnable state: - */ - add_sched_out_event(in_events, 'R', timestamp); - } - add_sched_in_event(in_events, timestamp); -} - -static void -latency_runtime_event(struct trace_runtime_event *runtime_event, - struct event *event __used, - int cpu, - u64 timestamp, - struct thread *this_thread __used) -{ - struct work_atoms *atoms; - struct thread *thread; - - BUG_ON(cpu >= MAX_CPUS || cpu < 0); - - thread = threads__findnew(runtime_event->pid, &threads, &last_match); - atoms = thread_atoms_search(&atom_root, thread, &cmp_pid); - if (!atoms) { - thread_atoms_insert(thread); - atoms = thread_atoms_search(&atom_root, thread, &cmp_pid); - if (!atoms) - die("in-event: Internal tree error"); - add_sched_out_event(atoms, 'R', timestamp); - } - - add_runtime_event(atoms, runtime_event->runtime, timestamp); -} - -static void -latency_wakeup_event(struct trace_wakeup_event *wakeup_event, - struct event *__event __used, - int cpu __used, - u64 timestamp, - struct thread *thread __used) -{ - struct work_atoms *atoms; - struct work_atom *atom; - struct thread *wakee; - - /* Note for later, it may be interesting to observe the failing cases */ - if (!wakeup_event->success) - return; - - wakee = threads__findnew(wakeup_event->pid, &threads, &last_match); - atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid); - if (!atoms) { - thread_atoms_insert(wakee); - atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid); - if (!atoms) - die("wakeup-event: Internal tree error"); - add_sched_out_event(atoms, 'S', timestamp); - } - - BUG_ON(list_empty(&atoms->work_list)); - - atom = list_entry(atoms->work_list.prev, struct work_atom, list); - - if (atom->state != THREAD_SLEEPING) - nr_state_machine_bugs++; - - nr_timestamps++; - if (atom->sched_out_time > timestamp) { - nr_unordered_timestamps++; - return; - } - - atom->state = THREAD_WAIT_CPU; - atom->wake_up_time = timestamp; -} - -static struct trace_sched_handler lat_ops = { - .wakeup_event = latency_wakeup_event, - .switch_event = latency_switch_event, - .runtime_event = latency_runtime_event, - .fork_event = latency_fork_event, -}; - -static void output_lat_thread(struct work_atoms *work_list) -{ - int i; - int ret; - u64 avg; - - if (!work_list->nb_atoms) - return; - /* - * Ignore idle threads: - */ - if (!strcmp(work_list->thread->comm, "swapper")) - return; - - all_runtime += work_list->total_runtime; - all_count += work_list->nb_atoms; - - ret = printf(" %s:%d ", work_list->thread->comm, work_list->thread->pid); - - for (i = 0; i < 24 - ret; i++) - printf(" "); - - avg = work_list->total_lat / work_list->nb_atoms; - - printf("|%11.3f ms |%9llu | avg:%9.3f ms | max:%9.3f ms |\n", - (double)work_list->total_runtime / 1e6, - work_list->nb_atoms, (double)avg / 1e6, - (double)work_list->max_lat / 1e6); -} - -static int pid_cmp(struct work_atoms *l, struct work_atoms *r) -{ - if (l->thread->pid < r->thread->pid) - return -1; - if (l->thread->pid > r->thread->pid) - return 1; - - return 0; -} - -static struct sort_dimension pid_sort_dimension = { - .name = "pid", - .cmp = pid_cmp, -}; - -static int avg_cmp(struct work_atoms *l, struct work_atoms *r) -{ - u64 avgl, avgr; - - if (!l->nb_atoms) - return -1; - - if (!r->nb_atoms) - return 1; - - avgl = l->total_lat / l->nb_atoms; - avgr = r->total_lat / r->nb_atoms; - - if (avgl < avgr) - return -1; - if (avgl > avgr) - return 1; - - return 0; -} - -static struct sort_dimension avg_sort_dimension = { - .name = "avg", - .cmp = avg_cmp, -}; - -static int max_cmp(struct work_atoms *l, struct work_atoms *r) -{ - if (l->max_lat < r->max_lat) - return -1; - if (l->max_lat > r->max_lat) - return 1; - - return 0; -} - -static struct sort_dimension max_sort_dimension = { - .name = "max", - .cmp = max_cmp, -}; - -static int switch_cmp(struct work_atoms *l, struct work_atoms *r) -{ - if (l->nb_atoms < r->nb_atoms) - return -1; - if (l->nb_atoms > r->nb_atoms) - return 1; - - return 0; -} - -static struct sort_dimension switch_sort_dimension = { - .name = "switch", - .cmp = switch_cmp, -}; - -static int runtime_cmp(struct work_atoms *l, struct work_atoms *r) -{ - if (l->total_runtime < r->total_runtime) - return -1; - if (l->total_runtime > r->total_runtime) - return 1; - - return 0; -} - -static struct sort_dimension runtime_sort_dimension = { - .name = "runtime", - .cmp = runtime_cmp, -}; - -static struct sort_dimension *available_sorts[] = { - &pid_sort_dimension, - &avg_sort_dimension, - &max_sort_dimension, - &switch_sort_dimension, - &runtime_sort_dimension, -}; - -#define NB_AVAILABLE_SORTS (int)(sizeof(available_sorts) / sizeof(struct sort_dimension *)) - -static LIST_HEAD(sort_list); - -static int sort_dimension__add(char *tok, struct list_head *list) -{ - int i; - - for (i = 0; i < NB_AVAILABLE_SORTS; i++) { - if (!strcmp(available_sorts[i]->name, tok)) { - list_add_tail(&available_sorts[i]->list, list); - - return 0; - } - } - - return -1; -} - -static void setup_sorting(void); - -static void sort_lat(void) -{ - struct rb_node *node; - - for (;;) { - struct work_atoms *data; - node = rb_first(&atom_root); - if (!node) - break; - - rb_erase(node, &atom_root); - data = rb_entry(node, struct work_atoms, node); - __thread_latency_insert(&sorted_atom_root, data, &sort_list); - } -} - -static struct trace_sched_handler *trace_handler; - -static void -process_sched_wakeup_event(struct raw_event_sample *raw, - struct event *event, - int cpu __used, - u64 timestamp __used, - struct thread *thread __used) -{ - struct trace_wakeup_event wakeup_event; - - FILL_COMMON_FIELDS(wakeup_event, event, raw->data); - - FILL_ARRAY(wakeup_event, comm, event, raw->data); - FILL_FIELD(wakeup_event, pid, event, raw->data); - FILL_FIELD(wakeup_event, prio, event, raw->data); - FILL_FIELD(wakeup_event, success, event, raw->data); - FILL_FIELD(wakeup_event, cpu, event, raw->data); - - if (trace_handler->wakeup_event) - trace_handler->wakeup_event(&wakeup_event, event, cpu, timestamp, thread); -} - -/* - * Track the current task - that way we can know whether there's any - * weird events, such as a task being switched away that is not current. - */ -static int max_cpu; - -static u32 curr_pid[MAX_CPUS] = { [0 ... MAX_CPUS-1] = -1 }; - -static struct thread *curr_thread[MAX_CPUS]; - -static char next_shortname1 = 'A'; -static char next_shortname2 = '0'; - -static void -map_switch_event(struct trace_switch_event *switch_event, - struct event *event __used, - int this_cpu, - u64 timestamp, - struct thread *thread __used) -{ - struct thread *sched_out, *sched_in; - int new_shortname; - u64 timestamp0; - s64 delta; - int cpu; - - BUG_ON(this_cpu >= MAX_CPUS || this_cpu < 0); - - if (this_cpu > max_cpu) - max_cpu = this_cpu; - - timestamp0 = cpu_last_switched[this_cpu]; - cpu_last_switched[this_cpu] = timestamp; - if (timestamp0) - delta = timestamp - timestamp0; - else - delta = 0; - - if (delta < 0) - die("hm, delta: %Ld < 0 ?\n", delta); - - - sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match); - sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match); - - curr_thread[this_cpu] = sched_in; - - printf(" "); - - new_shortname = 0; - if (!sched_in->shortname[0]) { - sched_in->shortname[0] = next_shortname1; - sched_in->shortname[1] = next_shortname2; - - if (next_shortname1 < 'Z') { - next_shortname1++; - } else { - next_shortname1='A'; - if (next_shortname2 < '9') { - next_shortname2++; - } else { - next_shortname2='0'; - } - } - new_shortname = 1; - } - - for (cpu = 0; cpu <= max_cpu; cpu++) { - if (cpu != this_cpu) - printf(" "); - else - printf("*"); - - if (curr_thread[cpu]) { - if (curr_thread[cpu]->pid) - printf("%2s ", curr_thread[cpu]->shortname); - else - printf(". "); - } else - printf(" "); - } - - printf(" %12.6f secs ", (double)timestamp/1e9); - if (new_shortname) { - printf("%s => %s:%d\n", - sched_in->shortname, sched_in->comm, sched_in->pid); - } else { - printf("\n"); - } -} - - -static void -process_sched_switch_event(struct raw_event_sample *raw, - struct event *event, - int this_cpu, - u64 timestamp __used, - struct thread *thread __used) -{ - struct trace_switch_event switch_event; - - FILL_COMMON_FIELDS(switch_event, event, raw->data); - - FILL_ARRAY(switch_event, prev_comm, event, raw->data); - FILL_FIELD(switch_event, prev_pid, event, raw->data); - FILL_FIELD(switch_event, prev_prio, event, raw->data); - FILL_FIELD(switch_event, prev_state, event, raw->data); - FILL_ARRAY(switch_event, next_comm, event, raw->data); - FILL_FIELD(switch_event, next_pid, event, raw->data); - FILL_FIELD(switch_event, next_prio, event, raw->data); - - if (curr_pid[this_cpu] != (u32)-1) { - /* - * Are we trying to switch away a PID that is - * not current? - */ - if (curr_pid[this_cpu] != switch_event.prev_pid) - nr_context_switch_bugs++; - } - if (trace_handler->switch_event) - trace_handler->switch_event(&switch_event, event, this_cpu, timestamp, thread); - - curr_pid[this_cpu] = switch_event.next_pid; -} - -static void -process_sched_runtime_event(struct raw_event_sample *raw, - struct event *event, - int cpu __used, - u64 timestamp __used, - struct thread *thread __used) -{ - struct trace_runtime_event runtime_event; - - FILL_ARRAY(runtime_event, comm, event, raw->data); - FILL_FIELD(runtime_event, pid, event, raw->data); - FILL_FIELD(runtime_event, runtime, event, raw->data); - FILL_FIELD(runtime_event, vruntime, event, raw->data); - - if (trace_handler->runtime_event) - trace_handler->runtime_event(&runtime_event, event, cpu, timestamp, thread); -} - -static void -process_sched_fork_event(struct raw_event_sample *raw, - struct event *event, - int cpu __used, - u64 timestamp __used, - struct thread *thread __used) -{ - struct trace_fork_event fork_event; - - FILL_COMMON_FIELDS(fork_event, event, raw->data); - - FILL_ARRAY(fork_event, parent_comm, event, raw->data); - FILL_FIELD(fork_event, parent_pid, event, raw->data); - FILL_ARRAY(fork_event, child_comm, event, raw->data); - FILL_FIELD(fork_event, child_pid, event, raw->data); - - if (trace_handler->fork_event) - trace_handler->fork_event(&fork_event, event, cpu, timestamp, thread); -} - -static void -process_sched_exit_event(struct event *event, - int cpu __used, - u64 timestamp __used, - struct thread *thread __used) -{ - if (verbose) - printf("sched_exit event %p\n", event); -} - -static void -process_raw_event(event_t *raw_event __used, void *more_data, - int cpu, u64 timestamp, struct thread *thread) -{ - struct raw_event_sample *raw = more_data; - struct event *event; - int type; - - type = trace_parse_common_type(raw->data); - event = trace_find_event(type); - - if (!strcmp(event->name, "sched_switch")) - process_sched_switch_event(raw, event, cpu, timestamp, thread); - if (!strcmp(event->name, "sched_stat_runtime")) - process_sched_runtime_event(raw, event, cpu, timestamp, thread); - if (!strcmp(event->name, "sched_wakeup")) - process_sched_wakeup_event(raw, event, cpu, timestamp, thread); - if (!strcmp(event->name, "sched_wakeup_new")) - process_sched_wakeup_event(raw, event, cpu, timestamp, thread); - if (!strcmp(event->name, "sched_process_fork")) - process_sched_fork_event(raw, event, cpu, timestamp, thread); - if (!strcmp(event->name, "sched_process_exit")) - process_sched_exit_event(event, cpu, timestamp, thread); -} - -static int -process_sample_event(event_t *event, unsigned long offset, unsigned long head) -{ - char level; - int show = 0; - struct dso *dso = NULL; - struct thread *thread; - u64 ip = event->ip.ip; - u64 timestamp = -1; - u32 cpu = -1; - u64 period = 1; - void *more_data = event->ip.__more_data; - int cpumode; - - thread = threads__findnew(event->ip.pid, &threads, &last_match); - - if (sample_type & PERF_SAMPLE_TIME) { - timestamp = *(u64 *)more_data; - more_data += sizeof(u64); - } - - if (sample_type & PERF_SAMPLE_CPU) { - cpu = *(u32 *)more_data; - more_data += sizeof(u32); - more_data += sizeof(u32); /* reserved */ - } - - if (sample_type & PERF_SAMPLE_PERIOD) { - period = *(u64 *)more_data; - more_data += sizeof(u64); - } - - dump_printf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", - (void *)(offset + head), - (void *)(long)(event->header.size), - event->header.misc, - event->ip.pid, event->ip.tid, - (void *)(long)ip, - (long long)period); - - dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); - - if (thread == NULL) { - eprintf("problem processing %d event, skipping it.\n", - event->header.type); - return -1; - } - - cpumode = event->header.misc & PERF_EVENT_MISC_CPUMODE_MASK; - - if (cpumode == PERF_EVENT_MISC_KERNEL) { - show = SHOW_KERNEL; - level = 'k'; - - dso = kernel_dso; - - dump_printf(" ...... dso: %s\n", dso->name); - - } else if (cpumode == PERF_EVENT_MISC_USER) { - - show = SHOW_USER; - level = '.'; - - } else { - show = SHOW_HV; - level = 'H'; - - dso = hypervisor_dso; - - dump_printf(" ...... dso: [hypervisor]\n"); - } - - if (sample_type & PERF_SAMPLE_RAW) - process_raw_event(event, more_data, cpu, timestamp, thread); - - return 0; -} - -static int -process_event(event_t *event, unsigned long offset, unsigned long head) -{ - trace_event(event); - - nr_events++; - switch (event->header.type) { - case PERF_EVENT_MMAP: - return 0; - case PERF_EVENT_LOST: - nr_lost_chunks++; - nr_lost_events += event->lost.lost; - return 0; - - case PERF_EVENT_COMM: - return process_comm_event(event, offset, head); - - case PERF_EVENT_EXIT ... PERF_EVENT_READ: - return 0; - - case PERF_EVENT_SAMPLE: - return process_sample_event(event, offset, head); - - case PERF_EVENT_MAX: - default: - return -1; - } - - return 0; -} - -static int read_events(void) -{ - int ret, rc = EXIT_FAILURE; - unsigned long offset = 0; - unsigned long head = 0; - struct stat perf_stat; - event_t *event; - uint32_t size; - char *buf; - - trace_report(); - register_idle_thread(&threads, &last_match); - - input = open(input_name, O_RDONLY); - if (input < 0) { - perror("failed to open file"); - exit(-1); - } - - ret = fstat(input, &perf_stat); - if (ret < 0) { - perror("failed to stat file"); - exit(-1); - } - - if (!perf_stat.st_size) { - fprintf(stderr, "zero-sized file, nothing to do!\n"); - exit(0); - } - header = perf_header__read(input); - head = header->data_offset; - sample_type = perf_header__sample_type(header); - - if (!(sample_type & PERF_SAMPLE_RAW)) - die("No trace sample to read. Did you call perf record " - "without -R?"); - - if (load_kernel() < 0) { - perror("failed to load kernel symbols"); - return EXIT_FAILURE; - } - -remap: - buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, - MAP_SHARED, input, offset); - if (buf == MAP_FAILED) { - perror("failed to mmap file"); - exit(-1); - } - -more: - event = (event_t *)(buf + head); - - size = event->header.size; - if (!size) - size = 8; - - if (head + event->header.size >= page_size * mmap_window) { - unsigned long shift = page_size * (head / page_size); - int res; - - res = munmap(buf, page_size * mmap_window); - assert(res == 0); - - offset += shift; - head -= shift; - goto remap; - } - - size = event->header.size; - - - if (!size || process_event(event, offset, head) < 0) { - - /* - * assume we lost track of the stream, check alignment, and - * increment a single u64 in the hope to catch on again 'soon'. - */ - - if (unlikely(head & 7)) - head &= ~7ULL; - - size = 8; - } - - head += size; - - if (offset + head < (unsigned long)perf_stat.st_size) - goto more; - - rc = EXIT_SUCCESS; - close(input); - - return rc; -} - -static void print_bad_events(void) -{ - if (nr_unordered_timestamps && nr_timestamps) { - printf(" INFO: %.3f%% unordered timestamps (%ld out of %ld)\n", - (double)nr_unordered_timestamps/(double)nr_timestamps*100.0, - nr_unordered_timestamps, nr_timestamps); - } - if (nr_lost_events && nr_events) { - printf(" INFO: %.3f%% lost events (%ld out of %ld, in %ld chunks)\n", - (double)nr_lost_events/(double)nr_events*100.0, - nr_lost_events, nr_events, nr_lost_chunks); - } - if (nr_state_machine_bugs && nr_timestamps) { - printf(" INFO: %.3f%% state machine bugs (%ld out of %ld)", - (double)nr_state_machine_bugs/(double)nr_timestamps*100.0, - nr_state_machine_bugs, nr_timestamps); - if (nr_lost_events) - printf(" (due to lost events?)"); - printf("\n"); - } - if (nr_context_switch_bugs && nr_timestamps) { - printf(" INFO: %.3f%% context switch bugs (%ld out of %ld)", - (double)nr_context_switch_bugs/(double)nr_timestamps*100.0, - nr_context_switch_bugs, nr_timestamps); - if (nr_lost_events) - printf(" (due to lost events?)"); - printf("\n"); - } -} - -static void __cmd_lat(void) -{ - struct rb_node *next; - - setup_pager(); - read_events(); - sort_lat(); - - printf("\n -----------------------------------------------------------------------------------------\n"); - printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms |\n"); - printf(" -----------------------------------------------------------------------------------------\n"); - - next = rb_first(&sorted_atom_root); - - while (next) { - struct work_atoms *work_list; - - work_list = rb_entry(next, struct work_atoms, node); - output_lat_thread(work_list); - next = rb_next(next); - } - - printf(" -----------------------------------------------------------------------------------------\n"); - printf(" TOTAL: |%11.3f ms |%9Ld |\n", - (double)all_runtime/1e6, all_count); - - printf(" ---------------------------------------------------\n"); - - print_bad_events(); - printf("\n"); - -} - -static struct trace_sched_handler map_ops = { - .wakeup_event = NULL, - .switch_event = map_switch_event, - .runtime_event = NULL, - .fork_event = NULL, -}; - -static void __cmd_map(void) -{ - max_cpu = sysconf(_SC_NPROCESSORS_CONF); - - setup_pager(); - read_events(); - print_bad_events(); -} - -static void __cmd_replay(void) -{ - unsigned long i; - - calibrate_run_measurement_overhead(); - calibrate_sleep_measurement_overhead(); - - test_calibrations(); - - read_events(); - - printf("nr_run_events: %ld\n", nr_run_events); - printf("nr_sleep_events: %ld\n", nr_sleep_events); - printf("nr_wakeup_events: %ld\n", nr_wakeup_events); - - if (targetless_wakeups) - printf("target-less wakeups: %ld\n", targetless_wakeups); - if (multitarget_wakeups) - printf("multi-target wakeups: %ld\n", multitarget_wakeups); - if (nr_run_events_optimized) - printf("run atoms optimized: %ld\n", - nr_run_events_optimized); - - print_task_traces(); - add_cross_task_wakeups(); - - create_tasks(); - printf("------------------------------------------------------------\n"); - for (i = 0; i < replay_repeat; i++) - run_one_test(); -} - - -static const char * const sched_usage[] = { - "perf sched [] {record|latency|map|replay|trace}", - NULL -}; - -static const struct option sched_options[] = { - OPT_STRING('i', "input", &input_name, "file", - "input file name"), - OPT_BOOLEAN('v', "verbose", &verbose, - "be more verbose (show symbol address, etc)"), - OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, - "dump raw trace in ASCII"), - OPT_END() -}; - -static const char * const latency_usage[] = { - "perf sched latency []", - NULL -}; - -static const struct option latency_options[] = { - OPT_STRING('s', "sort", &sort_order, "key[,key2...]", - "sort by key(s): runtime, switch, avg, max"), - OPT_BOOLEAN('v', "verbose", &verbose, - "be more verbose (show symbol address, etc)"), - OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, - "dump raw trace in ASCII"), - OPT_END() -}; - -static const char * const replay_usage[] = { - "perf sched replay []", - NULL -}; - -static const struct option replay_options[] = { - OPT_INTEGER('r', "repeat", &replay_repeat, - "repeat the workload replay N times (-1: infinite)"), - OPT_BOOLEAN('v', "verbose", &verbose, - "be more verbose (show symbol address, etc)"), - OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, - "dump raw trace in ASCII"), - OPT_END() -}; - -static void setup_sorting(void) -{ - char *tmp, *tok, *str = strdup(sort_order); - - for (tok = strtok_r(str, ", ", &tmp); - tok; tok = strtok_r(NULL, ", ", &tmp)) { - if (sort_dimension__add(tok, &sort_list) < 0) { - error("Unknown --sort key: `%s'", tok); - usage_with_options(latency_usage, latency_options); - } - } - - free(str); - - sort_dimension__add((char *)"pid", &cmp_pid); -} - -static const char *record_args[] = { - "record", - "-a", - "-R", - "-M", - "-f", - "-m", "1024", - "-c", "1", - "-e", "sched:sched_switch:r", - "-e", "sched:sched_stat_wait:r", - "-e", "sched:sched_stat_sleep:r", - "-e", "sched:sched_stat_iowait:r", - "-e", "sched:sched_stat_runtime:r", - "-e", "sched:sched_process_exit:r", - "-e", "sched:sched_process_fork:r", - "-e", "sched:sched_wakeup:r", - "-e", "sched:sched_migrate_task:r", -}; - -static int __cmd_record(int argc, const char **argv) -{ - unsigned int rec_argc, i, j; - const char **rec_argv; - - rec_argc = ARRAY_SIZE(record_args) + argc - 1; - rec_argv = calloc(rec_argc + 1, sizeof(char *)); - - for (i = 0; i < ARRAY_SIZE(record_args); i++) - rec_argv[i] = strdup(record_args[i]); - - for (j = 1; j < (unsigned int)argc; j++, i++) - rec_argv[i] = argv[j]; - - BUG_ON(i != rec_argc); - - return cmd_record(i, rec_argv, NULL); -} - -int cmd_sched(int argc, const char **argv, const char *prefix __used) -{ - symbol__init(); - page_size = getpagesize(); - - argc = parse_options(argc, argv, sched_options, sched_usage, - PARSE_OPT_STOP_AT_NON_OPTION); - if (!argc) - usage_with_options(sched_usage, sched_options); - - if (!strncmp(argv[0], "rec", 3)) { - return __cmd_record(argc, argv); - } else if (!strncmp(argv[0], "lat", 3)) { - trace_handler = &lat_ops; - if (argc > 1) { - argc = parse_options(argc, argv, latency_options, latency_usage, 0); - if (argc) - usage_with_options(latency_usage, latency_options); - } - setup_sorting(); - __cmd_lat(); - } else if (!strcmp(argv[0], "map")) { - trace_handler = &map_ops; - setup_sorting(); - __cmd_map(); - } else if (!strncmp(argv[0], "rep", 3)) { - trace_handler = &replay_ops; - if (argc) { - argc = parse_options(argc, argv, replay_options, replay_usage, 0); - if (argc) - usage_with_options(replay_usage, replay_options); - } - __cmd_replay(); - } else if (!strcmp(argv[0], "trace")) { - /* - * Aliased to 'perf trace' for now: - */ - return cmd_trace(argc, argv, prefix); - } else { - usage_with_options(sched_usage, sched_options); - } - - return 0; -} diff --git a/trunk/tools/perf/builtin-timechart.c b/trunk/tools/perf/builtin-timechart.c deleted file mode 100644 index 58d737ec8f5e..000000000000 --- a/trunk/tools/perf/builtin-timechart.c +++ /dev/null @@ -1,1151 +0,0 @@ -/* - * builtin-timechart.c - make an svg timechart of system activity - * - * (C) Copyright 2009 Intel Corporation - * - * Authors: - * Arjan van de Ven - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; version 2 - * of the License. - */ - -#include "builtin.h" - -#include "util/util.h" - -#include "util/color.h" -#include -#include "util/cache.h" -#include -#include "util/symbol.h" -#include "util/string.h" -#include "util/callchain.h" -#include "util/strlist.h" - -#include "perf.h" -#include "util/header.h" -#include "util/parse-options.h" -#include "util/parse-events.h" -#include "util/svghelper.h" - -static char const *input_name = "perf.data"; -static char const *output_name = "output.svg"; - - -static unsigned long page_size; -static unsigned long mmap_window = 32; -static u64 sample_type; - -static unsigned int numcpus; -static u64 min_freq; /* Lowest CPU frequency seen */ -static u64 max_freq; /* Highest CPU frequency seen */ -static u64 turbo_frequency; - -static u64 first_time, last_time; - - -static struct perf_header *header; - -struct per_pid; -struct per_pidcomm; - -struct cpu_sample; -struct power_event; -struct wake_event; - -struct sample_wrapper; - -/* - * Datastructure layout: - * We keep an list of "pid"s, matching the kernels notion of a task struct. - * Each "pid" entry, has a list of "comm"s. - * this is because we want to track different programs different, while - * exec will reuse the original pid (by design). - * Each comm has a list of samples that will be used to draw - * final graph. - */ - -struct per_pid { - struct per_pid *next; - - int pid; - int ppid; - - u64 start_time; - u64 end_time; - u64 total_time; - int display; - - struct per_pidcomm *all; - struct per_pidcomm *current; - - int painted; -}; - - -struct per_pidcomm { - struct per_pidcomm *next; - - u64 start_time; - u64 end_time; - u64 total_time; - - int Y; - int display; - - long state; - u64 state_since; - - char *comm; - - struct cpu_sample *samples; -}; - -struct sample_wrapper { - struct sample_wrapper *next; - - u64 timestamp; - unsigned char data[0]; -}; - -#define TYPE_NONE 0 -#define TYPE_RUNNING 1 -#define TYPE_WAITING 2 -#define TYPE_BLOCKED 3 - -struct cpu_sample { - struct cpu_sample *next; - - u64 start_time; - u64 end_time; - int type; - int cpu; -}; - -static struct per_pid *all_data; - -#define CSTATE 1 -#define PSTATE 2 - -struct power_event { - struct power_event *next; - int type; - int state; - u64 start_time; - u64 end_time; - int cpu; -}; - -struct wake_event { - struct wake_event *next; - int waker; - int wakee; - u64 time; -}; - -static struct power_event *power_events; -static struct wake_event *wake_events; - -struct sample_wrapper *all_samples; - -static struct per_pid *find_create_pid(int pid) -{ - struct per_pid *cursor = all_data; - - while (cursor) { - if (cursor->pid == pid) - return cursor; - cursor = cursor->next; - } - cursor = malloc(sizeof(struct per_pid)); - assert(cursor != NULL); - memset(cursor, 0, sizeof(struct per_pid)); - cursor->pid = pid; - cursor->next = all_data; - all_data = cursor; - return cursor; -} - -static void pid_set_comm(int pid, char *comm) -{ - struct per_pid *p; - struct per_pidcomm *c; - p = find_create_pid(pid); - c = p->all; - while (c) { - if (c->comm && strcmp(c->comm, comm) == 0) { - p->current = c; - return; - } - if (!c->comm) { - c->comm = strdup(comm); - p->current = c; - return; - } - c = c->next; - } - c = malloc(sizeof(struct per_pidcomm)); - assert(c != NULL); - memset(c, 0, sizeof(struct per_pidcomm)); - c->comm = strdup(comm); - p->current = c; - c->next = p->all; - p->all = c; -} - -static void pid_fork(int pid, int ppid, u64 timestamp) -{ - struct per_pid *p, *pp; - p = find_create_pid(pid); - pp = find_create_pid(ppid); - p->ppid = ppid; - if (pp->current && pp->current->comm && !p->current) - pid_set_comm(pid, pp->current->comm); - - p->start_time = timestamp; - if (p->current) { - p->current->start_time = timestamp; - p->current->state_since = timestamp; - } -} - -static void pid_exit(int pid, u64 timestamp) -{ - struct per_pid *p; - p = find_create_pid(pid); - p->end_time = timestamp; - if (p->current) - p->current->end_time = timestamp; -} - -static void -pid_put_sample(int pid, int type, unsigned int cpu, u64 start, u64 end) -{ - struct per_pid *p; - struct per_pidcomm *c; - struct cpu_sample *sample; - - p = find_create_pid(pid); - c = p->current; - if (!c) { - c = malloc(sizeof(struct per_pidcomm)); - assert(c != NULL); - memset(c, 0, sizeof(struct per_pidcomm)); - p->current = c; - c->next = p->all; - p->all = c; - } - - sample = malloc(sizeof(struct cpu_sample)); - assert(sample != NULL); - memset(sample, 0, sizeof(struct cpu_sample)); - sample->start_time = start; - sample->end_time = end; - sample->type = type; - sample->next = c->samples; - sample->cpu = cpu; - c->samples = sample; - - if (sample->type == TYPE_RUNNING && end > start && start > 0) { - c->total_time += (end-start); - p->total_time += (end-start); - } - - if (c->start_time == 0 || c->start_time > start) - c->start_time = start; - if (p->start_time == 0 || p->start_time > start) - p->start_time = start; - - if (cpu > numcpus) - numcpus = cpu; -} - -#define MAX_CPUS 4096 - -static u64 cpus_cstate_start_times[MAX_CPUS]; -static int cpus_cstate_state[MAX_CPUS]; -static u64 cpus_pstate_start_times[MAX_CPUS]; -static u64 cpus_pstate_state[MAX_CPUS]; - -static int -process_comm_event(event_t *event) -{ - pid_set_comm(event->comm.pid, event->comm.comm); - return 0; -} -static int -process_fork_event(event_t *event) -{ - pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); - return 0; -} - -static int -process_exit_event(event_t *event) -{ - pid_exit(event->fork.pid, event->fork.time); - return 0; -} - -struct trace_entry { - u32 size; - unsigned short type; - unsigned char flags; - unsigned char preempt_count; - int pid; - int tgid; -}; - -struct power_entry { - struct trace_entry te; - s64 type; - s64 value; -}; - -#define TASK_COMM_LEN 16 -struct wakeup_entry { - struct trace_entry te; - char comm[TASK_COMM_LEN]; - int pid; - int prio; - int success; -}; - -/* - * trace_flag_type is an enumeration that holds different - * states when a trace occurs. These are: - * IRQS_OFF - interrupts were disabled - * IRQS_NOSUPPORT - arch does not support irqs_disabled_flags - * NEED_RESCED - reschedule is requested - * HARDIRQ - inside an interrupt handler - * SOFTIRQ - inside a softirq handler - */ -enum trace_flag_type { - TRACE_FLAG_IRQS_OFF = 0x01, - TRACE_FLAG_IRQS_NOSUPPORT = 0x02, - TRACE_FLAG_NEED_RESCHED = 0x04, - TRACE_FLAG_HARDIRQ = 0x08, - TRACE_FLAG_SOFTIRQ = 0x10, -}; - - - -struct sched_switch { - struct trace_entry te; - char prev_comm[TASK_COMM_LEN]; - int prev_pid; - int prev_prio; - long prev_state; /* Arjan weeps. */ - char next_comm[TASK_COMM_LEN]; - int next_pid; - int next_prio; -}; - -static void c_state_start(int cpu, u64 timestamp, int state) -{ - cpus_cstate_start_times[cpu] = timestamp; - cpus_cstate_state[cpu] = state; -} - -static void c_state_end(int cpu, u64 timestamp) -{ - struct power_event *pwr; - pwr = malloc(sizeof(struct power_event)); - if (!pwr) - return; - memset(pwr, 0, sizeof(struct power_event)); - - pwr->state = cpus_cstate_state[cpu]; - pwr->start_time = cpus_cstate_start_times[cpu]; - pwr->end_time = timestamp; - pwr->cpu = cpu; - pwr->type = CSTATE; - pwr->next = power_events; - - power_events = pwr; -} - -static void p_state_change(int cpu, u64 timestamp, u64 new_freq) -{ - struct power_event *pwr; - pwr = malloc(sizeof(struct power_event)); - - if (new_freq > 8000000) /* detect invalid data */ - return; - - if (!pwr) - return; - memset(pwr, 0, sizeof(struct power_event)); - - pwr->state = cpus_pstate_state[cpu]; - pwr->start_time = cpus_pstate_start_times[cpu]; - pwr->end_time = timestamp; - pwr->cpu = cpu; - pwr->type = PSTATE; - pwr->next = power_events; - - if (!pwr->start_time) - pwr->start_time = first_time; - - power_events = pwr; - - cpus_pstate_state[cpu] = new_freq; - cpus_pstate_start_times[cpu] = timestamp; - - if ((u64)new_freq > max_freq) - max_freq = new_freq; - - if (new_freq < min_freq || min_freq == 0) - min_freq = new_freq; - - if (new_freq == max_freq - 1000) - turbo_frequency = max_freq; -} - -static void -sched_wakeup(int cpu, u64 timestamp, int pid, struct trace_entry *te) -{ - struct wake_event *we; - struct per_pid *p; - struct wakeup_entry *wake = (void *)te; - - we = malloc(sizeof(struct wake_event)); - if (!we) - return; - - memset(we, 0, sizeof(struct wake_event)); - we->time = timestamp; - we->waker = pid; - - if ((te->flags & TRACE_FLAG_HARDIRQ) || (te->flags & TRACE_FLAG_SOFTIRQ)) - we->waker = -1; - - we->wakee = wake->pid; - we->next = wake_events; - wake_events = we; - p = find_create_pid(we->wakee); - - if (p && p->current && p->current->state == TYPE_NONE) { - p->current->state_since = timestamp; - p->current->state = TYPE_WAITING; - } - if (p && p->current && p->current->state == TYPE_BLOCKED) { - pid_put_sample(p->pid, p->current->state, cpu, p->current->state_since, timestamp); - p->current->state_since = timestamp; - p->current->state = TYPE_WAITING; - } -} - -static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te) -{ - struct per_pid *p = NULL, *prev_p; - struct sched_switch *sw = (void *)te; - - - prev_p = find_create_pid(sw->prev_pid); - - p = find_create_pid(sw->next_pid); - - if (prev_p->current && prev_p->current->state != TYPE_NONE) - pid_put_sample(sw->prev_pid, TYPE_RUNNING, cpu, prev_p->current->state_since, timestamp); - if (p && p->current) { - if (p->current->state != TYPE_NONE) - pid_put_sample(sw->next_pid, p->current->state, cpu, p->current->state_since, timestamp); - - p->current->state_since = timestamp; - p->current->state = TYPE_RUNNING; - } - - if (prev_p->current) { - prev_p->current->state = TYPE_NONE; - prev_p->current->state_since = timestamp; - if (sw->prev_state & 2) - prev_p->current->state = TYPE_BLOCKED; - if (sw->prev_state == 0) - prev_p->current->state = TYPE_WAITING; - } -} - - -static int -process_sample_event(event_t *event) -{ - int cursor = 0; - u64 addr = 0; - u64 stamp = 0; - u32 cpu = 0; - u32 pid = 0; - struct trace_entry *te; - - if (sample_type & PERF_SAMPLE_IP) - cursor++; - - if (sample_type & PERF_SAMPLE_TID) { - pid = event->sample.array[cursor]>>32; - cursor++; - } - if (sample_type & PERF_SAMPLE_TIME) { - stamp = event->sample.array[cursor++]; - - if (!first_time || first_time > stamp) - first_time = stamp; - if (last_time < stamp) - last_time = stamp; - - } - if (sample_type & PERF_SAMPLE_ADDR) - addr = event->sample.array[cursor++]; - if (sample_type & PERF_SAMPLE_ID) - cursor++; - if (sample_type & PERF_SAMPLE_STREAM_ID) - cursor++; - if (sample_type & PERF_SAMPLE_CPU) - cpu = event->sample.array[cursor++] & 0xFFFFFFFF; - if (sample_type & PERF_SAMPLE_PERIOD) - cursor++; - - te = (void *)&event->sample.array[cursor]; - - if (sample_type & PERF_SAMPLE_RAW && te->size > 0) { - char *event_str; - struct power_entry *pe; - - pe = (void *)te; - - event_str = perf_header__find_event(te->type); - - if (!event_str) - return 0; - - if (strcmp(event_str, "power:power_start") == 0) - c_state_start(cpu, stamp, pe->value); - - if (strcmp(event_str, "power:power_end") == 0) - c_state_end(cpu, stamp); - - if (strcmp(event_str, "power:power_frequency") == 0) - p_state_change(cpu, stamp, pe->value); - - if (strcmp(event_str, "sched:sched_wakeup") == 0) - sched_wakeup(cpu, stamp, pid, te); - - if (strcmp(event_str, "sched:sched_switch") == 0) - sched_switch(cpu, stamp, te); - } - return 0; -} - -/* - * After the last sample we need to wrap up the current C/P state - * and close out each CPU for these. - */ -static void end_sample_processing(void) -{ - u64 cpu; - struct power_event *pwr; - - for (cpu = 0; cpu < numcpus; cpu++) { - pwr = malloc(sizeof(struct power_event)); - if (!pwr) - return; - memset(pwr, 0, sizeof(struct power_event)); - - /* C state */ -#if 0 - pwr->state = cpus_cstate_state[cpu]; - pwr->start_time = cpus_cstate_start_times[cpu]; - pwr->end_time = last_time; - pwr->cpu = cpu; - pwr->type = CSTATE; - pwr->next = power_events; - - power_events = pwr; -#endif - /* P state */ - - pwr = malloc(sizeof(struct power_event)); - if (!pwr) - return; - memset(pwr, 0, sizeof(struct power_event)); - - pwr->state = cpus_pstate_state[cpu]; - pwr->start_time = cpus_pstate_start_times[cpu]; - pwr->end_time = last_time; - pwr->cpu = cpu; - pwr->type = PSTATE; - pwr->next = power_events; - - if (!pwr->start_time) - pwr->start_time = first_time; - if (!pwr->state) - pwr->state = min_freq; - power_events = pwr; - } -} - -static u64 sample_time(event_t *event) -{ - int cursor; - - cursor = 0; - if (sample_type & PERF_SAMPLE_IP) - cursor++; - if (sample_type & PERF_SAMPLE_TID) - cursor++; - if (sample_type & PERF_SAMPLE_TIME) - return event->sample.array[cursor]; - return 0; -} - - -/* - * We first queue all events, sorted backwards by insertion. - * The order will get flipped later. - */ -static int -queue_sample_event(event_t *event) -{ - struct sample_wrapper *copy, *prev; - int size; - - size = event->sample.header.size + sizeof(struct sample_wrapper) + 8; - - copy = malloc(size); - if (!copy) - return 1; - - memset(copy, 0, size); - - copy->next = NULL; - copy->timestamp = sample_time(event); - - memcpy(©->data, event, event->sample.header.size); - - /* insert in the right place in the list */ - - if (!all_samples) { - /* first sample ever */ - all_samples = copy; - return 0; - } - - if (all_samples->timestamp < copy->timestamp) { - /* insert at the head of the list */ - copy->next = all_samples; - all_samples = copy; - return 0; - } - - prev = all_samples; - while (prev->next) { - if (prev->next->timestamp < copy->timestamp) { - copy->next = prev->next; - prev->next = copy; - return 0; - } - prev = prev->next; - } - /* insert at the end of the list */ - prev->next = copy; - - return 0; -} - -static void sort_queued_samples(void) -{ - struct sample_wrapper *cursor, *next; - - cursor = all_samples; - all_samples = NULL; - - while (cursor) { - next = cursor->next; - cursor->next = all_samples; - all_samples = cursor; - cursor = next; - } -} - -/* - * Sort the pid datastructure - */ -static void sort_pids(void) -{ - struct per_pid *new_list, *p, *cursor, *prev; - /* sort by ppid first, then by pid, lowest to highest */ - - new_list = NULL; - - while (all_data) { - p = all_data; - all_data = p->next; - p->next = NULL; - - if (new_list == NULL) { - new_list = p; - p->next = NULL; - continue; - } - prev = NULL; - cursor = new_list; - while (cursor) { - if (cursor->ppid > p->ppid || - (cursor->ppid == p->ppid && cursor->pid > p->pid)) { - /* must insert before */ - if (prev) { - p->next = prev->next; - prev->next = p; - cursor = NULL; - continue; - } else { - p->next = new_list; - new_list = p; - cursor = NULL; - continue; - } - } - - prev = cursor; - cursor = cursor->next; - if (!cursor) - prev->next = p; - } - } - all_data = new_list; -} - - -static void draw_c_p_states(void) -{ - struct power_event *pwr; - pwr = power_events; - - /* - * two pass drawing so that the P state bars are on top of the C state blocks - */ - while (pwr) { - if (pwr->type == CSTATE) - svg_cstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state); - pwr = pwr->next; - } - - pwr = power_events; - while (pwr) { - if (pwr->type == PSTATE) { - if (!pwr->state) - pwr->state = min_freq; - svg_pstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state); - } - pwr = pwr->next; - } -} - -static void draw_wakeups(void) -{ - struct wake_event *we; - struct per_pid *p; - struct per_pidcomm *c; - - we = wake_events; - while (we) { - int from = 0, to = 0; - - /* locate the column of the waker and wakee */ - p = all_data; - while (p) { - if (p->pid == we->waker || p->pid == we->wakee) { - c = p->all; - while (c) { - if (c->Y && c->start_time <= we->time && c->end_time >= we->time) { - if (p->pid == we->waker) - from = c->Y; - if (p->pid == we->wakee) - to = c->Y; - } - c = c->next; - } - } - p = p->next; - } - - if (we->waker == -1) - svg_interrupt(we->time, to); - else if (from && to && abs(from - to) == 1) - svg_wakeline(we->time, from, to); - else - svg_partial_wakeline(we->time, from, to); - we = we->next; - } -} - -static void draw_cpu_usage(void) -{ - struct per_pid *p; - struct per_pidcomm *c; - struct cpu_sample *sample; - p = all_data; - while (p) { - c = p->all; - while (c) { - sample = c->samples; - while (sample) { - if (sample->type == TYPE_RUNNING) - svg_process(sample->cpu, sample->start_time, sample->end_time, "sample", c->comm); - - sample = sample->next; - } - c = c->next; - } - p = p->next; - } -} - -static void draw_process_bars(void) -{ - struct per_pid *p; - struct per_pidcomm *c; - struct cpu_sample *sample; - int Y = 0; - - Y = 2 * numcpus + 2; - - p = all_data; - while (p) { - c = p->all; - while (c) { - if (!c->display) { - c->Y = 0; - c = c->next; - continue; - } - - svg_box(Y, p->start_time, p->end_time, "process"); - sample = c->samples; - while (sample) { - if (sample->type == TYPE_RUNNING) - svg_sample(Y, sample->cpu, sample->start_time, sample->end_time, "sample"); - if (sample->type == TYPE_BLOCKED) - svg_box(Y, sample->start_time, sample->end_time, "blocked"); - if (sample->type == TYPE_WAITING) - svg_box(Y, sample->start_time, sample->end_time, "waiting"); - sample = sample->next; - } - - if (c->comm) { - char comm[256]; - if (c->total_time > 5000000000) /* 5 seconds */ - sprintf(comm, "%s:%i (%2.2fs)", c->comm, p->pid, c->total_time / 1000000000.0); - else - sprintf(comm, "%s:%i (%3.1fms)", c->comm, p->pid, c->total_time / 1000000.0); - - svg_text(Y, c->start_time, comm); - } - c->Y = Y; - Y++; - c = c->next; - } - p = p->next; - } -} - -static int determine_display_tasks(u64 threshold) -{ - struct per_pid *p; - struct per_pidcomm *c; - int count = 0; - - p = all_data; - while (p) { - p->display = 0; - if (p->start_time == 1) - p->start_time = first_time; - - /* no exit marker, task kept running to the end */ - if (p->end_time == 0) - p->end_time = last_time; - if (p->total_time >= threshold) - p->display = 1; - - c = p->all; - - while (c) { - c->display = 0; - - if (c->start_time == 1) - c->start_time = first_time; - - if (c->total_time >= threshold) { - c->display = 1; - count++; - } - - if (c->end_time == 0) - c->end_time = last_time; - - c = c->next; - } - p = p->next; - } - return count; -} - - - -#define TIME_THRESH 10000000 - -static void write_svg_file(const char *filename) -{ - u64 i; - int count; - - numcpus++; - - - count = determine_display_tasks(TIME_THRESH); - - /* We'd like to show at least 15 tasks; be less picky if we have fewer */ - if (count < 15) - count = determine_display_tasks(TIME_THRESH / 10); - - open_svg(filename, numcpus, count); - - svg_time_grid(first_time, last_time); - svg_legenda(); - - for (i = 0; i < numcpus; i++) - svg_cpu_box(i, max_freq, turbo_frequency); - - draw_cpu_usage(); - draw_process_bars(); - draw_c_p_states(); - draw_wakeups(); - - svg_close(); -} - -static int -process_event(event_t *event) -{ - - switch (event->header.type) { - - case PERF_EVENT_COMM: - return process_comm_event(event); - case PERF_EVENT_FORK: - return process_fork_event(event); - case PERF_EVENT_EXIT: - return process_exit_event(event); - case PERF_EVENT_SAMPLE: - return queue_sample_event(event); - - /* - * We dont process them right now but they are fine: - */ - case PERF_EVENT_MMAP: - case PERF_EVENT_THROTTLE: - case PERF_EVENT_UNTHROTTLE: - return 0; - - default: - return -1; - } - - return 0; -} - -static void process_samples(void) -{ - struct sample_wrapper *cursor; - event_t *event; - - sort_queued_samples(); - - cursor = all_samples; - while (cursor) { - event = (void *)&cursor->data; - cursor = cursor->next; - process_sample_event(event); - } -} - - -static int __cmd_timechart(void) -{ - int ret, rc = EXIT_FAILURE; - unsigned long offset = 0; - unsigned long head, shift; - struct stat statbuf; - event_t *event; - uint32_t size; - char *buf; - int input; - - input = open(input_name, O_RDONLY); - if (input < 0) { - fprintf(stderr, " failed to open file: %s", input_name); - if (!strcmp(input_name, "perf.data")) - fprintf(stderr, " (try 'perf record' first)"); - fprintf(stderr, "\n"); - exit(-1); - } - - ret = fstat(input, &statbuf); - if (ret < 0) { - perror("failed to stat file"); - exit(-1); - } - - if (!statbuf.st_size) { - fprintf(stderr, "zero-sized file, nothing to do!\n"); - exit(0); - } - - header = perf_header__read(input); - head = header->data_offset; - - sample_type = perf_header__sample_type(header); - - shift = page_size * (head / page_size); - offset += shift; - head -= shift; - -remap: - buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, - MAP_SHARED, input, offset); - if (buf == MAP_FAILED) { - perror("failed to mmap file"); - exit(-1); - } - -more: - event = (event_t *)(buf + head); - - size = event->header.size; - if (!size) - size = 8; - - if (head + event->header.size >= page_size * mmap_window) { - int ret2; - - shift = page_size * (head / page_size); - - ret2 = munmap(buf, page_size * mmap_window); - assert(ret2 == 0); - - offset += shift; - head -= shift; - goto remap; - } - - size = event->header.size; - - if (!size || process_event(event) < 0) { - - printf("%p [%p]: skipping unknown header type: %d\n", - (void *)(offset + head), - (void *)(long)(event->header.size), - event->header.type); - - /* - * assume we lost track of the stream, check alignment, and - * increment a single u64 in the hope to catch on again 'soon'. - */ - - if (unlikely(head & 7)) - head &= ~7ULL; - - size = 8; - } - - head += size; - - if (offset + head >= header->data_offset + header->data_size) - goto done; - - if (offset + head < (unsigned long)statbuf.st_size) - goto more; - -done: - rc = EXIT_SUCCESS; - close(input); - - - process_samples(); - - end_sample_processing(); - - sort_pids(); - - write_svg_file(output_name); - - printf("Written %2.1f seconds of trace to %s.\n", (last_time - first_time) / 1000000000.0, output_name); - - return rc; -} - -static const char * const timechart_usage[] = { - "perf timechart [] {record}", - NULL -}; - -static const char *record_args[] = { - "record", - "-a", - "-R", - "-M", - "-f", - "-c", "1", - "-e", "power:power_start", - "-e", "power:power_end", - "-e", "power:power_frequency", - "-e", "sched:sched_wakeup", - "-e", "sched:sched_switch", -}; - -static int __cmd_record(int argc, const char **argv) -{ - unsigned int rec_argc, i, j; - const char **rec_argv; - - rec_argc = ARRAY_SIZE(record_args) + argc - 1; - rec_argv = calloc(rec_argc + 1, sizeof(char *)); - - for (i = 0; i < ARRAY_SIZE(record_args); i++) - rec_argv[i] = strdup(record_args[i]); - - for (j = 1; j < (unsigned int)argc; j++, i++) - rec_argv[i] = argv[j]; - - return cmd_record(i, rec_argv, NULL); -} - -static const struct option options[] = { - OPT_STRING('i', "input", &input_name, "file", - "input file name"), - OPT_STRING('o', "output", &output_name, "file", - "output file name"), - OPT_END() -}; - - -int cmd_timechart(int argc, const char **argv, const char *prefix __used) -{ - symbol__init(); - - page_size = getpagesize(); - - argc = parse_options(argc, argv, options, timechart_usage, - PARSE_OPT_STOP_AT_NON_OPTION); - - if (argc && !strncmp(argv[0], "rec", 3)) - return __cmd_record(argc, argv); - else if (argc) - usage_with_options(timechart_usage, options); - - setup_pager(); - - return __cmd_timechart(); -} diff --git a/trunk/tools/perf/builtin.h b/trunk/tools/perf/builtin.h index e11d8d231c3b..3a63e41fb44e 100644 --- a/trunk/tools/perf/builtin.h +++ b/trunk/tools/perf/builtin.h @@ -16,14 +16,12 @@ extern int check_pager_config(const char *cmd); extern int cmd_annotate(int argc, const char **argv, const char *prefix); extern int cmd_help(int argc, const char **argv, const char *prefix); -extern int cmd_sched(int argc, const char **argv, const char *prefix); -extern int cmd_list(int argc, const char **argv, const char *prefix); extern int cmd_record(int argc, const char **argv, const char *prefix); extern int cmd_report(int argc, const char **argv, const char *prefix); extern int cmd_stat(int argc, const char **argv, const char *prefix); -extern int cmd_timechart(int argc, const char **argv, const char *prefix); extern int cmd_top(int argc, const char **argv, const char *prefix); -extern int cmd_trace(int argc, const char **argv, const char *prefix); extern int cmd_version(int argc, const char **argv, const char *prefix); +extern int cmd_list(int argc, const char **argv, const char *prefix); +extern int cmd_trace(int argc, const char **argv, const char *prefix); #endif diff --git a/trunk/tools/perf/command-list.txt b/trunk/tools/perf/command-list.txt index 00326e230d87..eebce30afbc0 100644 --- a/trunk/tools/perf/command-list.txt +++ b/trunk/tools/perf/command-list.txt @@ -4,10 +4,7 @@ # perf-annotate mainporcelain common perf-list mainporcelain common -perf-sched mainporcelain common perf-record mainporcelain common perf-report mainporcelain common perf-stat mainporcelain common -perf-timechart mainporcelain common perf-top mainporcelain common -perf-trace mainporcelain common diff --git a/trunk/tools/perf/perf.c b/trunk/tools/perf/perf.c index 19fc7feb9d59..fe4589dde950 100644 --- a/trunk/tools/perf/perf.c +++ b/trunk/tools/perf/perf.c @@ -289,12 +289,10 @@ static void handle_internal_command(int argc, const char **argv) { "record", cmd_record, 0 }, { "report", cmd_report, 0 }, { "stat", cmd_stat, 0 }, - { "timechart", cmd_timechart, 0 }, { "top", cmd_top, 0 }, { "annotate", cmd_annotate, 0 }, { "version", cmd_version, 0 }, { "trace", cmd_trace, 0 }, - { "sched", cmd_sched, 0 }, }; unsigned int i; static const char ext[] = STRIP_EXTENSION; diff --git a/trunk/tools/perf/util/event.h b/trunk/tools/perf/util/event.h index 018d414a09d1..fa2d4e91d329 100644 --- a/trunk/tools/perf/util/event.h +++ b/trunk/tools/perf/util/event.h @@ -39,7 +39,6 @@ struct fork_event { struct perf_event_header header; u32 pid, ppid; u32 tid, ptid; - u64 time; }; struct lost_event { @@ -53,19 +52,13 @@ struct lost_event { */ struct read_event { struct perf_event_header header; - u32 pid, tid; + u32 pid,tid; u64 value; u64 time_enabled; u64 time_running; u64 id; }; -struct sample_event{ - struct perf_event_header header; - u64 array[]; -}; - - typedef union event_union { struct perf_event_header header; struct ip_event ip; @@ -74,7 +67,6 @@ typedef union event_union { struct fork_event fork; struct lost_event lost; struct read_event read; - struct sample_event sample; } event_t; struct map { diff --git a/trunk/tools/perf/util/header.c b/trunk/tools/perf/util/header.c index bb4fca3efcc3..ec4d4c2f9522 100644 --- a/trunk/tools/perf/util/header.c +++ b/trunk/tools/perf/util/header.c @@ -7,8 +7,9 @@ #include "header.h" /* - * Create new perf.data header attribute: + * */ + struct perf_header_attr *perf_header_attr__new(struct perf_counter_attr *attr) { struct perf_header_attr *self = malloc(sizeof(*self)); @@ -42,8 +43,9 @@ void perf_header_attr__add_id(struct perf_header_attr *self, u64 id) } /* - * Create new perf.data header: + * */ + struct perf_header *perf_header__new(void) { struct perf_header *self = malloc(sizeof(*self)); @@ -84,46 +86,6 @@ void perf_header__add_attr(struct perf_header *self, self->attr[pos] = attr; } -#define MAX_EVENT_NAME 64 - -struct perf_trace_event_type { - u64 event_id; - char name[MAX_EVENT_NAME]; -}; - -static int event_count; -static struct perf_trace_event_type *events; - -void perf_header__push_event(u64 id, const char *name) -{ - if (strlen(name) > MAX_EVENT_NAME) - printf("Event %s will be truncated\n", name); - - if (!events) { - events = malloc(sizeof(struct perf_trace_event_type)); - if (!events) - die("nomem"); - } else { - events = realloc(events, (event_count + 1) * sizeof(struct perf_trace_event_type)); - if (!events) - die("nomem"); - } - memset(&events[event_count], 0, sizeof(struct perf_trace_event_type)); - events[event_count].event_id = id; - strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1); - event_count++; -} - -char *perf_header__find_event(u64 id) -{ - int i; - for (i = 0 ; i < event_count; i++) { - if (events[i].event_id == id) - return events[i].name; - } - return NULL; -} - static const char *__perf_magic = "PERFFILE"; #define PERF_MAGIC (*(u64 *)__perf_magic) @@ -144,7 +106,6 @@ struct perf_file_header { u64 attr_size; struct perf_file_section attrs; struct perf_file_section data; - struct perf_file_section event_types; }; static void do_write(int fd, void *buf, size_t size) @@ -193,11 +154,6 @@ void perf_header__write(struct perf_header *self, int fd) do_write(fd, &f_attr, sizeof(f_attr)); } - self->event_offset = lseek(fd, 0, SEEK_CUR); - self->event_size = event_count * sizeof(struct perf_trace_event_type); - if (events) - do_write(fd, events, self->event_size); - self->data_offset = lseek(fd, 0, SEEK_CUR); @@ -213,10 +169,6 @@ void perf_header__write(struct perf_header *self, int fd) .offset = self->data_offset, .size = self->data_size, }, - .event_types = { - .offset = self->event_offset, - .size = self->event_size, - }, }; lseek(fd, 0, SEEK_SET); @@ -282,17 +234,6 @@ struct perf_header *perf_header__read(int fd) lseek(fd, tmp, SEEK_SET); } - if (f_header.event_types.size) { - lseek(fd, f_header.event_types.offset, SEEK_SET); - events = malloc(f_header.event_types.size); - if (!events) - die("nomem"); - do_read(fd, events, f_header.event_types.size); - event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); - } - self->event_offset = f_header.event_types.offset; - self->event_size = f_header.event_types.size; - self->data_offset = f_header.data.offset; self->data_size = f_header.data.size; diff --git a/trunk/tools/perf/util/header.h b/trunk/tools/perf/util/header.h index 7b0e84a87179..5d0a72ecc919 100644 --- a/trunk/tools/perf/util/header.h +++ b/trunk/tools/perf/util/header.h @@ -19,8 +19,6 @@ struct perf_header { s64 attr_offset; u64 data_offset; u64 data_size; - u64 event_offset; - u64 event_size; }; struct perf_header *perf_header__read(int fd); @@ -29,10 +27,6 @@ void perf_header__write(struct perf_header *self, int fd); void perf_header__add_attr(struct perf_header *self, struct perf_header_attr *attr); -void perf_header__push_event(u64 id, const char *name); -char *perf_header__find_event(u64 id); - - struct perf_header_attr * perf_header_attr__new(struct perf_counter_attr *attr); void perf_header_attr__add_id(struct perf_header_attr *self, u64 id); diff --git a/trunk/tools/perf/util/parse-events.c b/trunk/tools/perf/util/parse-events.c index 89172fd0038b..a587d41ae3c9 100644 --- a/trunk/tools/perf/util/parse-events.c +++ b/trunk/tools/perf/util/parse-events.c @@ -6,7 +6,6 @@ #include "exec_cmd.h" #include "string.h" #include "cache.h" -#include "header.h" int nr_counters; @@ -19,12 +18,6 @@ struct event_symbol { const char *alias; }; -enum event_result { - EVT_FAILED, - EVT_HANDLED, - EVT_HANDLED_ALL -}; - char debugfs_path[MAXPATHLEN]; #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x @@ -146,7 +139,7 @@ static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir) (strcmp(evt_dirent.d_name, "..")) && \ (!tp_event_has_id(&sys_dirent, &evt_dirent))) -#define MAX_EVENT_LENGTH 512 +#define MAX_EVENT_LENGTH 30 int valid_debugfs_mount(const char *debugfs) { @@ -351,7 +344,7 @@ static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int return -1; } -static enum event_result +static int parse_generic_hw_event(const char **str, struct perf_counter_attr *attr) { const char *s = *str; @@ -363,7 +356,7 @@ parse_generic_hw_event(const char **str, struct perf_counter_attr *attr) * then bail out: */ if (cache_type == -1) - return EVT_FAILED; + return 0; while ((cache_op == -1 || cache_result == -1) && *s == '-') { ++s; @@ -409,115 +402,27 @@ parse_generic_hw_event(const char **str, struct perf_counter_attr *attr) attr->type = PERF_TYPE_HW_CACHE; *str = s; - return EVT_HANDLED; -} - -static enum event_result -parse_single_tracepoint_event(char *sys_name, - const char *evt_name, - unsigned int evt_length, - char *flags, - struct perf_counter_attr *attr, - const char **strp) -{ - char evt_path[MAXPATHLEN]; - char id_buf[4]; - u64 id; - int fd; - - if (flags) { - if (!strncmp(flags, "record", strlen(flags))) { - attr->sample_type |= PERF_SAMPLE_RAW; - attr->sample_type |= PERF_SAMPLE_TIME; - attr->sample_type |= PERF_SAMPLE_CPU; - } - } - - snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, - sys_name, evt_name); - - fd = open(evt_path, O_RDONLY); - if (fd < 0) - return EVT_FAILED; - - if (read(fd, id_buf, sizeof(id_buf)) < 0) { - close(fd); - return EVT_FAILED; - } - - close(fd); - id = atoll(id_buf); - attr->config = id; - attr->type = PERF_TYPE_TRACEPOINT; - *strp = evt_name + evt_length; - - return EVT_HANDLED; -} - -/* sys + ':' + event + ':' + flags*/ -#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) -static enum event_result -parse_subsystem_tracepoint_event(char *sys_name, char *flags) -{ - char evt_path[MAXPATHLEN]; - struct dirent *evt_ent; - DIR *evt_dir; - - snprintf(evt_path, MAXPATHLEN, "%s/%s", debugfs_path, sys_name); - evt_dir = opendir(evt_path); - - if (!evt_dir) { - perror("Can't open event dir"); - return EVT_FAILED; - } - - while ((evt_ent = readdir(evt_dir))) { - char event_opt[MAX_EVOPT_LEN + 1]; - int len; - unsigned int rem = MAX_EVOPT_LEN; - - if (!strcmp(evt_ent->d_name, ".") - || !strcmp(evt_ent->d_name, "..") - || !strcmp(evt_ent->d_name, "enable") - || !strcmp(evt_ent->d_name, "filter")) - continue; - - len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s", sys_name, - evt_ent->d_name); - if (len < 0) - return EVT_FAILED; - - rem -= len; - if (flags) { - if (rem < strlen(flags) + 1) - return EVT_FAILED; - - strcat(event_opt, ":"); - strcat(event_opt, flags); - } - - if (parse_events(NULL, event_opt, 0)) - return EVT_FAILED; - } - - return EVT_HANDLED_ALL; + return 1; } - -static enum event_result parse_tracepoint_event(const char **strp, +static int parse_tracepoint_event(const char **strp, struct perf_counter_attr *attr) { const char *evt_name; char *flags; char sys_name[MAX_EVENT_LENGTH]; + char id_buf[4]; + int fd; unsigned int sys_length, evt_length; + u64 id; + char evt_path[MAXPATHLEN]; if (valid_debugfs_mount(debugfs_path)) return 0; evt_name = strchr(*strp, ':'); if (!evt_name) - return EVT_FAILED; + return 0; sys_length = evt_name - *strp; if (sys_length >= MAX_EVENT_LENGTH) @@ -529,22 +434,32 @@ static enum event_result parse_tracepoint_event(const char **strp, flags = strchr(evt_name, ':'); if (flags) { - /* split it out: */ - evt_name = strndup(evt_name, flags - evt_name); + *flags = '\0'; flags++; + if (!strncmp(flags, "record", strlen(flags))) + attr->sample_type |= PERF_SAMPLE_RAW; } evt_length = strlen(evt_name); if (evt_length >= MAX_EVENT_LENGTH) - return EVT_FAILED; + return 0; - if (!strcmp(evt_name, "*")) { - *strp = evt_name + evt_length; - return parse_subsystem_tracepoint_event(sys_name, flags); - } else - return parse_single_tracepoint_event(sys_name, evt_name, - evt_length, flags, - attr, strp); + snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, + sys_name, evt_name); + fd = open(evt_path, O_RDONLY); + if (fd < 0) + return 0; + + if (read(fd, id_buf, sizeof(id_buf)) < 0) { + close(fd); + return 0; + } + close(fd); + id = atoll(id_buf); + attr->config = id; + attr->type = PERF_TYPE_TRACEPOINT; + *strp = evt_name + evt_length; + return 1; } static int check_events(const char *str, unsigned int i) @@ -562,7 +477,7 @@ static int check_events(const char *str, unsigned int i) return 0; } -static enum event_result +static int parse_symbolic_event(const char **strp, struct perf_counter_attr *attr) { const char *str = *strp; @@ -575,32 +490,31 @@ parse_symbolic_event(const char **strp, struct perf_counter_attr *attr) attr->type = event_symbols[i].type; attr->config = event_symbols[i].config; *strp = str + n; - return EVT_HANDLED; + return 1; } } - return EVT_FAILED; + return 0; } -static enum event_result -parse_raw_event(const char **strp, struct perf_counter_attr *attr) +static int parse_raw_event(const char **strp, struct perf_counter_attr *attr) { const char *str = *strp; u64 config; int n; if (*str != 'r') - return EVT_FAILED; + return 0; n = hex2u64(str + 1, &config); if (n > 0) { *strp = str + n + 1; attr->type = PERF_TYPE_RAW; attr->config = config; - return EVT_HANDLED; + return 1; } - return EVT_FAILED; + return 0; } -static enum event_result +static int parse_numeric_event(const char **strp, struct perf_counter_attr *attr) { const char *str = *strp; @@ -616,13 +530,13 @@ parse_numeric_event(const char **strp, struct perf_counter_attr *attr) attr->type = type; attr->config = config; *strp = endp; - return EVT_HANDLED; + return 1; } } - return EVT_FAILED; + return 0; } -static enum event_result +static int parse_event_modifier(const char **strp, struct perf_counter_attr *attr) { const char *str = *strp; @@ -655,84 +569,37 @@ parse_event_modifier(const char **strp, struct perf_counter_attr *attr) * Each event can have multiple symbolic names. * Symbolic names are (almost) exactly matched. */ -static enum event_result -parse_event_symbols(const char **str, struct perf_counter_attr *attr) +static int parse_event_symbols(const char **str, struct perf_counter_attr *attr) { - enum event_result ret; - - ret = parse_tracepoint_event(str, attr); - if (ret != EVT_FAILED) - goto modifier; - - ret = parse_raw_event(str, attr); - if (ret != EVT_FAILED) - goto modifier; - - ret = parse_numeric_event(str, attr); - if (ret != EVT_FAILED) - goto modifier; - - ret = parse_symbolic_event(str, attr); - if (ret != EVT_FAILED) - goto modifier; - - ret = parse_generic_hw_event(str, attr); - if (ret != EVT_FAILED) - goto modifier; - - return EVT_FAILED; + if (!(parse_tracepoint_event(str, attr) || + parse_raw_event(str, attr) || + parse_numeric_event(str, attr) || + parse_symbolic_event(str, attr) || + parse_generic_hw_event(str, attr))) + return 0; -modifier: parse_event_modifier(str, attr); - return ret; + return 1; } -static void store_event_type(const char *orgname) -{ - char filename[PATH_MAX], *c; - FILE *file; - int id; - - sprintf(filename, "/sys/kernel/debug/tracing/events/%s/id", orgname); - c = strchr(filename, ':'); - if (c) - *c = '/'; - - file = fopen(filename, "r"); - if (!file) - return; - if (fscanf(file, "%i", &id) < 1) - die("cannot store event ID"); - fclose(file); - perf_header__push_event(id, orgname); -} - - int parse_events(const struct option *opt __used, const char *str, int unset __used) { struct perf_counter_attr attr; - enum event_result ret; - - if (strchr(str, ':')) - store_event_type(str); for (;;) { if (nr_counters == MAX_COUNTERS) return -1; memset(&attr, 0, sizeof(attr)); - ret = parse_event_symbols(&str, &attr); - if (ret == EVT_FAILED) + if (!parse_event_symbols(&str, &attr)) return -1; if (!(*str == 0 || *str == ',' || isspace(*str))) return -1; - if (ret != EVT_HANDLED_ALL) { - attrs[nr_counters] = attr; - nr_counters++; - } + attrs[nr_counters] = attr; + nr_counters++; if (*str == 0) break; diff --git a/trunk/tools/perf/util/parse-options.h b/trunk/tools/perf/util/parse-options.h index 2ee248ff27e5..8aa3464c7090 100644 --- a/trunk/tools/perf/util/parse-options.h +++ b/trunk/tools/perf/util/parse-options.h @@ -104,8 +104,6 @@ struct option { { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb } #define OPT_CALLBACK(s, l, v, a, h, f) \ { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f) } -#define OPT_CALLBACK_NOOPT(s, l, v, a, h, f) \ - { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .flags = PARSE_OPT_NOARG } #define OPT_CALLBACK_DEFAULT(s, l, v, a, h, f, d) \ { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d, .flags = PARSE_OPT_LASTARG_DEFAULT } diff --git a/trunk/tools/perf/util/svghelper.c b/trunk/tools/perf/util/svghelper.c deleted file mode 100644 index b0fcecdf378d..000000000000 --- a/trunk/tools/perf/util/svghelper.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * svghelper.c - helper functions for outputting svg - * - * (C) Copyright 2009 Intel Corporation - * - * Authors: - * Arjan van de Ven - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; version 2 - * of the License. - */ - -#include -#include -#include -#include - -#include "svghelper.h" - -static u64 first_time, last_time; -static u64 turbo_frequency, max_freq; - - -#define SLOT_MULT 30.0 -#define SLOT_HEIGHT 25.0 -#define WIDTH 1000.0 - -#define MIN_TEXT_SIZE 0.001 - -static u64 total_height; -static FILE *svgfile; - -static double cpu2slot(int cpu) -{ - return 2 * cpu + 1; -} - -static double cpu2y(int cpu) -{ - return cpu2slot(cpu) * SLOT_MULT; -} - -static double time2pixels(u64 time) -{ - double X; - - X = WIDTH * (time - first_time) / (last_time - first_time); - return X; -} - -void open_svg(const char *filename, int cpus, int rows) -{ - - svgfile = fopen(filename, "w"); - if (!svgfile) { - fprintf(stderr, "Cannot open %s for output\n", filename); - return; - } - total_height = (1 + rows + cpu2slot(cpus)) * SLOT_MULT; - fprintf(svgfile, " \n"); - fprintf(svgfile, "\n", WIDTH, total_height); - - fprintf(svgfile, "\n \n\n"); -} - -void svg_box(int Yslot, u64 start, u64 end, const char *type) -{ - if (!svgfile) - return; - - fprintf(svgfile, "\n", - time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type); -} - -void svg_sample(int Yslot, int cpu, u64 start, u64 end, const char *type) -{ - double text_size; - if (!svgfile) - return; - - fprintf(svgfile, "\n", - time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type); - - text_size = (time2pixels(end)-time2pixels(start)); - if (cpu > 9) - text_size = text_size/2; - if (text_size > 1.25) - text_size = 1.25; - if (text_size > MIN_TEXT_SIZE) - fprintf(svgfile, "%i\n", - time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1); - -} - -static char *cpu_model(void) -{ - static char cpu_m[255]; - char buf[256]; - FILE *file; - - cpu_m[0] = 0; - /* CPU type */ - file = fopen("/proc/cpuinfo", "r"); - if (file) { - while (fgets(buf, 255, file)) { - if (strstr(buf, "model name")) { - strncpy(cpu_m, &buf[13], 255); - break; - } - } - fclose(file); - } - return cpu_m; -} - -void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq) -{ - char cpu_string[80]; - if (!svgfile) - return; - - max_freq = __max_freq; - turbo_frequency = __turbo_freq; - - fprintf(svgfile, "\n", - time2pixels(first_time), - time2pixels(last_time)-time2pixels(first_time), - cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT); - - sprintf(cpu_string, "CPU %i", (int)cpu+1); - fprintf(svgfile, "%s\n", - 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string); - - fprintf(svgfile, "%s\n", - 10+time2pixels(first_time), cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - 4, cpu_model()); -} - -void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name) -{ - double width; - - if (!svgfile) - return; - - fprintf(svgfile, "\n", - time2pixels(start), time2pixels(end)-time2pixels(start), cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT, type); - width = time2pixels(end)-time2pixels(start); - if (width > 6) - width = 6; - - if (width > MIN_TEXT_SIZE) - fprintf(svgfile, "%s\n", - time2pixels(start), cpu2y(cpu), width, name); -} - -void svg_cstate(int cpu, u64 start, u64 end, int type) -{ - double width; - char style[128]; - - if (!svgfile) - return; - - - if (type > 6) - type = 6; - sprintf(style, "c%i", type); - - fprintf(svgfile, "\n", - style, - time2pixels(start), time2pixels(end)-time2pixels(start), - cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT); - - width = time2pixels(end)-time2pixels(start); - if (width > 6) - width = 6; - - if (width > MIN_TEXT_SIZE) - fprintf(svgfile, "C%i\n", - time2pixels(start), cpu2y(cpu), width, type); -} - -static char *HzToHuman(unsigned long hz) -{ - static char buffer[1024]; - unsigned long long Hz; - - memset(buffer, 0, 1024); - - Hz = hz; - - /* default: just put the Number in */ - sprintf(buffer, "%9lli", Hz); - - if (Hz > 1000) - sprintf(buffer, " %6lli Mhz", (Hz+500)/1000); - - if (Hz > 1500000) - sprintf(buffer, " %6.2f Ghz", (Hz+5000.0)/1000000); - - if (Hz == turbo_frequency) - sprintf(buffer, "Turbo"); - - return buffer; -} - -void svg_pstate(int cpu, u64 start, u64 end, u64 freq) -{ - double height = 0; - - if (!svgfile) - return; - - if (max_freq) - height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT); - height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height; - fprintf(svgfile, "\n", - time2pixels(start), time2pixels(end), height, height); - fprintf(svgfile, "%s\n", - time2pixels(start), height+0.9, HzToHuman(freq)); - -} - - -void svg_partial_wakeline(u64 start, int row1, int row2) -{ - double height; - - if (!svgfile) - return; - - - if (row1 < row2) { - if (row1) - fprintf(svgfile, "\n", - time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32); - - if (row2) - fprintf(svgfile, "\n", - time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row2 * SLOT_MULT); - } else { - if (row2) - fprintf(svgfile, "\n", - time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32); - - if (row1) - fprintf(svgfile, "\n", - time2pixels(start), row1 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row1 * SLOT_MULT); - } - height = row1 * SLOT_MULT; - if (row2 > row1) - height += SLOT_HEIGHT; - if (row1) - fprintf(svgfile, "\n", - time2pixels(start), height); -} - -void svg_wakeline(u64 start, int row1, int row2) -{ - double height; - - if (!svgfile) - return; - - - if (row1 < row2) - fprintf(svgfile, "\n", - time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT); - else - fprintf(svgfile, "\n", - time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT); - - height = row1 * SLOT_MULT; - if (row2 > row1) - height += SLOT_HEIGHT; - fprintf(svgfile, "\n", - time2pixels(start), height); -} - -void svg_interrupt(u64 start, int row) -{ - if (!svgfile) - return; - - fprintf(svgfile, "\n", - time2pixels(start), row * SLOT_MULT); - fprintf(svgfile, "\n", - time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT); -} - -void svg_text(int Yslot, u64 start, const char *text) -{ - if (!svgfile) - return; - - fprintf(svgfile, "%s\n", - time2pixels(start), Yslot * SLOT_MULT+SLOT_HEIGHT/2, text); -} - -static void svg_legenda_box(int X, const char *text, const char *style) -{ - double boxsize; - boxsize = SLOT_HEIGHT / 2; - - fprintf(svgfile, "\n", - X, boxsize, boxsize, style); - fprintf(svgfile, "%s\n", - X + boxsize + 5, boxsize, 0.8 * boxsize, text); -} - -void svg_legenda(void) -{ - if (!svgfile) - return; - - svg_legenda_box(0, "Running", "sample"); - svg_legenda_box(100, "Idle","rect.c1"); - svg_legenda_box(200, "Deeper Idle", "rect.c3"); - svg_legenda_box(350, "Deepest Idle", "rect.c6"); - svg_legenda_box(550, "Sleeping", "process2"); - svg_legenda_box(650, "Waiting for cpu", "waiting"); - svg_legenda_box(800, "Blocked on IO", "blocked"); -} - -void svg_time_grid(u64 start, u64 end) -{ - u64 i; - - first_time = start; - last_time = end; - - first_time = first_time / 100000000 * 100000000; - - if (!svgfile) - return; - - i = first_time; - while (i < last_time) { - int color = 220; - double thickness = 0.075; - if ((i % 100000000) == 0) { - thickness = 0.5; - color = 192; - } - if ((i % 1000000000) == 0) { - thickness = 2.0; - color = 128; - } - - fprintf(svgfile, "\n", - time2pixels(i), SLOT_MULT/2, time2pixels(i), total_height, color, color, color, thickness); - - i += 10000000; - } -} - -void svg_close(void) -{ - if (svgfile) { - fprintf(svgfile, "\n"); - fclose(svgfile); - svgfile = NULL; - } -} diff --git a/trunk/tools/perf/util/svghelper.h b/trunk/tools/perf/util/svghelper.h deleted file mode 100644 index ad79b5dc53de..000000000000 --- a/trunk/tools/perf/util/svghelper.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef _INCLUDE_GUARD_SVG_HELPER_ -#define _INCLUDE_GUARD_SVG_HELPER_ - -#include "types.h" - -extern void open_svg(const char *filename, int cpus, int rows); -extern void svg_box(int Yslot, u64 start, u64 end, const char *type); -extern void svg_sample(int Yslot, int cpu, u64 start, u64 end, const char *type); -extern void svg_cpu_box(int cpu, u64 max_frequency, u64 turbo_frequency); - - -extern void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name); -extern void svg_cstate(int cpu, u64 start, u64 end, int type); -extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq); - - -extern void svg_time_grid(u64 start, u64 end); -extern void svg_legenda(void); -extern void svg_wakeline(u64 start, int row1, int row2); -extern void svg_partial_wakeline(u64 start, int row1, int row2); -extern void svg_interrupt(u64 start, int row); -extern void svg_text(int Yslot, u64 start, const char *text); -extern void svg_close(void); - -#endif diff --git a/trunk/tools/perf/util/thread.c b/trunk/tools/perf/util/thread.c index 45efb5db0d19..7635928ca278 100644 --- a/trunk/tools/perf/util/thread.c +++ b/trunk/tools/perf/util/thread.c @@ -8,7 +8,7 @@ static struct thread *thread__new(pid_t pid) { - struct thread *self = calloc(1, sizeof(*self)); + struct thread *self = malloc(sizeof(*self)); if (self != NULL) { self->pid = pid; @@ -85,7 +85,7 @@ register_idle_thread(struct rb_root *threads, struct thread **last_match) { struct thread *thread = threads__findnew(0, threads, last_match); - if (!thread || thread__set_comm(thread, "swapper")) { + if (!thread || thread__set_comm(thread, "[init]")) { fprintf(stderr, "problem inserting idle task.\n"); exit(-1); } diff --git a/trunk/tools/perf/util/thread.h b/trunk/tools/perf/util/thread.h index 32aea3c1c2ad..634f2809a342 100644 --- a/trunk/tools/perf/util/thread.h +++ b/trunk/tools/perf/util/thread.h @@ -4,11 +4,10 @@ #include "symbol.h" struct thread { - struct rb_node rb_node; - struct list_head maps; - pid_t pid; - char shortname[3]; - char *comm; + struct rb_node rb_node; + struct list_head maps; + pid_t pid; + char *comm; }; int thread__set_comm(struct thread *self, const char *comm); diff --git a/trunk/tools/perf/util/trace-event-info.c b/trunk/tools/perf/util/trace-event-info.c index 1fd824c1f1c4..6c9302a7274c 100644 --- a/trunk/tools/perf/util/trace-event-info.c +++ b/trunk/tools/perf/util/trace-event-info.c @@ -458,7 +458,7 @@ static void read_proc_kallsyms(void) static void read_ftrace_printk(void) { unsigned int size, check_size; - char *path; + const char *path; struct stat st; int ret; @@ -468,15 +468,14 @@ static void read_ftrace_printk(void) /* not found */ size = 0; write_or_die(&size, 4); - goto out; + return; } size = get_size(path); write_or_die(&size, 4); check_size = copy_file(path); if (size != check_size) die("error in size of file '%s'", path); -out: - put_tracing_file(path); + } static struct tracepoint_path * diff --git a/trunk/tools/perf/util/trace-event-parse.c b/trunk/tools/perf/util/trace-event-parse.c index f6a8437141c8..629e602d9405 100644 --- a/trunk/tools/perf/util/trace-event-parse.c +++ b/trunk/tools/perf/util/trace-event-parse.c @@ -1776,29 +1776,6 @@ static unsigned long long read_size(void *ptr, int size) } } -unsigned long long -raw_field_value(struct event *event, const char *name, void *data) -{ - struct format_field *field; - - field = find_any_field(event, name); - if (!field) - return 0ULL; - - return read_size(data + field->offset, field->size); -} - -void *raw_field_ptr(struct event *event, const char *name, void *data) -{ - struct format_field *field; - - field = find_any_field(event, name); - if (!field) - return NULL; - - return data + field->offset; -} - static int get_common_info(const char *type, int *offset, int *size) { struct event *event; @@ -1822,7 +1799,7 @@ static int get_common_info(const char *type, int *offset, int *size) return 0; } -int trace_parse_common_type(void *data) +static int parse_common_type(void *data) { static int type_offset; static int type_size; @@ -1855,7 +1832,7 @@ static int parse_common_pid(void *data) return read_size(data + pid_offset, pid_size); } -struct event *trace_find_event(int id) +static struct event *find_event(int id) { struct event *event; @@ -2443,8 +2420,8 @@ get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func, int type; int pid; - type = trace_parse_common_type(next->data); - event = trace_find_event(type); + type = parse_common_type(next->data); + event = find_event(type); if (!event) return NULL; @@ -2525,8 +2502,8 @@ print_graph_entry_leaf(struct event *event, void *data, struct record *ret_rec) int type; int i; - type = trace_parse_common_type(ret_rec->data); - ret_event = trace_find_event(type); + type = parse_common_type(ret_rec->data); + ret_event = find_event(type); field = find_field(ret_event, "rettime"); if (!field) @@ -2719,13 +2696,11 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs, nsecs -= secs * NSECS_PER_SEC; usecs = nsecs / NSECS_PER_USEC; - type = trace_parse_common_type(data); + type = parse_common_type(data); - event = trace_find_event(type); - if (!event) { - printf("ug! no event found for type %d\n", type); - return; - } + event = find_event(type); + if (!event) + die("ug! no event found for type %d", type); pid = parse_common_pid(data); diff --git a/trunk/tools/perf/util/trace-event-read.c b/trunk/tools/perf/util/trace-event-read.c index 1b5c847d2c22..a1217a10632f 100644 --- a/trunk/tools/perf/util/trace-event-read.c +++ b/trunk/tools/perf/util/trace-event-read.c @@ -458,13 +458,12 @@ struct record *trace_read_data(int cpu) return data; } -void trace_report(void) +void trace_report (void) { const char *input_file = "trace.info"; char buf[BUFSIZ]; char test[] = { 23, 8, 68 }; char *version; - int show_version = 0; int show_funcs = 0; int show_printk = 0; @@ -481,8 +480,7 @@ void trace_report(void) die("not a trace file (missing tracing)"); version = read_string(); - if (show_version) - printf("version = %s\n", version); + printf("version = %s\n", version); free(version); read_or_die(buf, 1); diff --git a/trunk/tools/perf/util/trace-event.h b/trunk/tools/perf/util/trace-event.h index d35ebf1e29ff..420294a5773e 100644 --- a/trunk/tools/perf/util/trace-event.h +++ b/trunk/tools/perf/util/trace-event.h @@ -234,11 +234,6 @@ extern int header_page_data_offset; extern int header_page_data_size; int parse_header_page(char *buf, unsigned long size); -int trace_parse_common_type(void *data); -struct event *trace_find_event(int id); -unsigned long long -raw_field_value(struct event *event, const char *name, void *data); -void *raw_field_ptr(struct event *event, const char *name, void *data); void read_tracing_data(struct perf_counter_attr *pattrs, int nb_counters);