Commit 9e319251 authored by Linus Torvalds's avatar Linus Torvalds

Merge penguin:v2.5/linux

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 40aafff3 d1791d31
......@@ -1068,6 +1068,8 @@ The pdflush writeback daemons will periodically wake up and write `old' data
out to disk. This tunable expresses the interval between those wakeups, in
100'ths of a second.
Setting this to zero disables periodic writeback altogether.
dirty_expire_centisecs
----------------------
......
......@@ -18,7 +18,7 @@ organized in a tree structure:
+- ...
Every entry has its own dependencies. These dependencies are used
to determine the visible of an entry. Any child entry is only
to determine the visibility of an entry. Any child entry is only
visible if its parent entry is also visible.
Menu entries
......@@ -50,7 +50,7 @@ applicable everywhere (see syntax).
- type definition: "bool"/"tristate"/"string"/"hex"/"integer"
Every config option must have a type. There are only two basic types:
tristate and string, the other types base on these two. The type
tristate and string, the other types are based on these two. The type
definition optionally accepts an input prompt, so these two examples
are equivalent:
......@@ -64,7 +64,7 @@ applicable everywhere (see syntax).
to the user. Optionally dependencies only for this prompt can be added
with "if".
- default value: "default" <symbol> ["if" <expr>]
- default value: "default" <expr> ["if" <expr>]
A config option can have any number of default values. If multiple
default values are visible, only the first defined one is active.
Default values are not limited to the menu entry, where they are
......@@ -81,7 +81,7 @@ applicable everywhere (see syntax).
This defines a dependency for this menu entry. If multiple
dependencies are defined they are connected with '&&'. Dependencies
are applied to all other options within this menu entry (which also
accept "if" expression), so these two examples are equivalent:
accept an "if" expression), so these two examples are equivalent:
bool "foo" if BAR
default y if BAR
......@@ -90,9 +90,24 @@ applicable everywhere (see syntax).
bool "foo"
default y
- reverse dependencies: "select" <symbol> ["if" <expr>]
While normal dependencies reduce the upper limit of a symbol (see
below), reverse dependencies can be used to force a lower limit of
another symbol. The value of the current menu symbol is used as the
minimal value <symbol> can be set to. If <symbol> is selected multiple
times, the limit is set to the largest selection.
Reverse dependencies can only be used with boolean or tristate
symbols.
- numerical ranges: "range" <symbol> <symbol> ["if" <expr>]
This allows to limit the range of possible input values for integer
and hex symbols. The user can only input a value which is larger than
or equal to the first symbol and smaller than or equal to the second
symbol.
- help text: "help"
This defines a help text. The end of the help text is determined by
the level indentation, this means it ends at the first line which has
the indentation level, this means it ends at the first line which has
a smaller indentation than the first line of the help text.
......@@ -123,14 +138,14 @@ Expressions are listed in decreasing order of precedence.
otherwise 'y'.
(4) Returns the value of the expression. Used to override precedence.
(5) Returns the result of (2-/expr/).
(6) Returns the result of min(/expr/, /expr/).
(7) Returns the result of max(/expr/, /expr/).
(6) Returns the result of max(/expr/, /expr/).
(7) Returns the result of min(/expr/, /expr/).
An expression can have a value of 'n', 'm' or 'y' (or 0, 1, 2
respectively for calculations). A menu entry becomes visible when it's
expression evaluates to 'm' or 'y'.
There are two type of symbols: constant and nonconstant symbols.
There are two types of symbols: constant and nonconstant symbols.
Nonconstant symbols are the most common ones and are defined with the
'config' statement. Nonconstant symbols consist entirely of alphanumeric
characters or underscores.
......@@ -159,8 +174,8 @@ dependency list of the config option NETDEVICES.
The other way to generate the menu structure is done by analyzing the
dependencies. If a menu entry somehow depends on the previous entry, it
can be made a submenu of it. First the the previous (parent) symbol must
be part of the dependency list and then one of these two condititions
can be made a submenu of it. First, the previous (parent) symbol must
be part of the dependency list and then one of these two conditions
must be true:
- the child entry must become invisible, if the parent is set to 'n'
- the child entry must only be visible, if the parent is visible
......@@ -177,7 +192,7 @@ comment "module support disabled"
MODVERSIONS directly depends on MODULES, this means it's only visible if
MODULES is different from 'n'. The comment on the other hand is always
visible when MODULES it's visible (the (empty) dependency of MODULES is
visible when MODULES is visible (the (empty) dependency of MODULES is
also part of the comment dependencies).
......@@ -188,12 +203,13 @@ The configuration file describes a series of menu entries, where every
line starts with a keyword (except help texts). The following keywords
end a menu entry:
- config
- menuconfig
- choice/endchoice
- comment
- menu/endmenu
- if/endif
- source
The first four also start the definition of a menu entry.
The first five also start the definition of a menu entry.
config:
......@@ -203,6 +219,14 @@ config:
This defines a config symbol <symbol> and accepts any of above
attributes as options.
menuconfig:
"menuconfig" <symbol>
<config options>
This is similiar to the simple config entry above, but it also gives a
hint to front ends, that all suboptions should be displayed as a
separate list of options.
choices:
"choice"
......
......@@ -352,16 +352,8 @@ static inline void balance_irq(int cpu, int irq)
unsigned long allowed_mask;
unsigned int new_cpu;
if (irqbalance_disabled == IRQBALANCE_CHECK_ARCH)
irqbalance_disabled = NO_BALANCE_IRQ;
if (irqbalance_disabled) {
static int warned;
if (warned == 0) {
printk("irqbalance disabled\n");
warned = 1;
}
if (irqbalance_disabled)
return;
}
allowed_mask = cpu_online_map & irq_affinity[irq];
new_cpu = move(cpu, allowed_mask, now, 1);
......@@ -620,6 +612,9 @@ static int __init balanced_irq_init(void)
struct cpuinfo_x86 *c;
c = &boot_cpu_data;
/* When not overwritten by the command line ask subarchitecture. */
if (irqbalance_disabled == IRQBALANCE_CHECK_ARCH)
irqbalance_disabled = NO_BALANCE_IRQ;
if (irqbalance_disabled)
return 0;
......
......@@ -2,6 +2,7 @@
* Default generic APIC driver. This handles upto 8 CPUs.
*/
#define APIC_DEFINITION 1
#include <asm/mach-default/mach_apicdef.h>
#include <asm/genapic.h>
#include <asm/fixmap.h>
#include <asm/apicdef.h>
......@@ -10,7 +11,6 @@
#include <linux/smp.h>
#include <linux/init.h>
#include <asm/mach-default/mach_apic.h>
#include <asm/mach-default/mach_apicdef.h>
#include <asm/mach-default/mach_ipi.h>
#include <asm/mach-default/mach_mpparse.h>
......
......@@ -32,7 +32,7 @@
struct mmu_gather mmu_gathers[NR_CPUS];
/* References to section boundaries: */
extern char _stext, _etext, _edata, __init_begin, __init_end;
extern char _stext, _etext, _edata, __init_begin, __init_end, _end;
extern void ia64_tlb_init (void);
......@@ -583,6 +583,7 @@ mem_init (void)
long reserved_pages, codesize, datasize, initsize;
unsigned long num_pgt_pages;
pg_data_t *pgdat;
static struct kcore_list kcore_mem, kcore_vmem, kcore_kernel;
#ifdef CONFIG_PCI
/*
......@@ -601,6 +602,10 @@ mem_init (void)
high_memory = __va(max_low_pfn * PAGE_SIZE);
kclist_add(&kcore_mem, __va(0), max_low_pfn * PAGE_SIZE);
kclist_add(&kcore_vmem, (void *)VMALLOC_START, VMALLOC_END-VMALLOC_START);
kclist_add(&kcore_kernel, &_stext, &_end - &_stext);
for_each_pgdat(pgdat)
totalram_pages += free_all_bootmem_node(pgdat);
......
......@@ -1728,10 +1728,8 @@ int acsi_init( void )
sprintf(disk->disk_name, "ad%c", 'a'+i);
disk->major = ACSI_MAJOR;
disk->first_minor = i << 4;
if (acsi_info[i].type != HARDDISK) {
disk->minor_shift = 0;
if (acsi_info[i].type != HARDDISK)
disk->minors = 1;
}
disk->fops = &acsi_fops;
disk->private_data = &acsi_info[i];
set_capacity(disk, acsi_info[i].size);
......
......@@ -538,8 +538,6 @@ struct gendisk *alloc_disk(int minors)
memset(disk->part, 0, size);
}
disk->minors = minors;
while (minors >>= 1)
disk->minor_shift++;
kobj_set_kset_s(disk,block_subsys);
kobject_init(&disk->kobj);
rand_initialize_disk(disk);
......
......@@ -3376,7 +3376,6 @@ static int ide_cdrom_attach (ide_drive_t *drive)
drive->driver_data = info;
DRIVER(drive)->busy++;
g->minors = 1;
g->minor_shift = 0;
snprintf(g->devfs_name, sizeof(g->devfs_name),
"%s/cd", drive->devfs_name);
g->driverfs_dev = &drive->gendev;
......
......@@ -1814,7 +1814,6 @@ static int idedisk_attach(ide_drive_t *drive)
}
DRIVER(drive)->busy--;
g->minors = 1 << PARTN_BITS;
g->minor_shift = PARTN_BITS;
strcpy(g->devfs_name, drive->devfs_name);
g->driverfs_dev = &drive->gendev;
g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;
......
......@@ -2057,7 +2057,6 @@ static int idefloppy_attach (ide_drive_t *drive)
idefloppy_setup (drive, floppy);
DRIVER(drive)->busy--;
g->minors = 1 << PARTN_BITS;
g->minor_shift = PARTN_BITS;
g->driverfs_dev = &drive->gendev;
strcpy(g->devfs_name, drive->devfs_name);
g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;
......
This diff is collapsed.
......@@ -38,7 +38,7 @@
#define ETHER1394_GASP_SPECIFIER_ID_LO (ETHER1394_GASP_SPECIFIER_ID & 0xff)
#define ETHER1394_GASP_VERSION 1
#define ETHER1394_OVERHEAD (2 * sizeof(quadlet_t)) /* GASP header overhead */
#define ETHER1394_GASP_OVERHEAD (2 * sizeof(quadlet_t)) /* GASP header overhead */
/* Node set == 64 */
#define NODE_SET (ALL_NODES + 1)
......@@ -56,10 +56,9 @@ struct pdg_list {
struct eth1394_priv {
struct net_device_stats stats; /* Device stats */
struct hpsb_host *host; /* The card for this dev */
unsigned char max_rec[NODE_SET];/* Max payload per node */
u16 maxpayload[NODE_SET]; /* Max payload per node */
unsigned char sspd[NODE_SET]; /* Max speed per node */
u16 fifo_hi[ALL_NODES]; /* 16bit hi fifo offset per node */
u32 fifo_lo[ALL_NODES]; /* 32bit lo fifo offset per node */
u64 fifo[ALL_NODES]; /* FIFO offset per node */
u64 eui[ALL_NODES]; /* EUI-64 per node */
spinlock_t lock; /* Private lock */
int broadcast_channel; /* Async stream Broadcast Channel */
......@@ -74,6 +73,21 @@ struct host_info {
struct net_device *dev;
};
/* Define a fake hardware header format for the networking core. Note that
* header size cannot exceed 16 bytes as that is the size of the header cache.
* Also, we do not need the source address in the header so we omit it and
* keep the header to under 16 bytes */
#define ETH1394_ALEN (8)
#define ETH1394_HLEN (10)
struct eth1394hdr {
unsigned char h_dest[ETH1394_ALEN]; /* destination eth1394 addr */
unsigned short h_proto; /* packet type ID field */
} __attribute__((packed));
typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type;
/* IP1394 headers */
......
......@@ -57,7 +57,6 @@
/* Maps speed values above to a string representation */
extern const char *hpsb_speedto_str[];
extern const u8 hpsb_speedto_maxrec[];
#define SELFID_PWRCL_NO_POWER 0x0
......
......@@ -61,7 +61,6 @@ static kmem_cache_t *hpsb_packet_cache;
/* Some globals used */
const char *hpsb_speedto_str[] = { "S100", "S200", "S400", "S800", "S1600", "S3200" };
const u8 hpsb_speedto_maxrec[] = { 0x7, 0x8, 0x9, 0x10, 0x11, 0x12 };
static void dump_packet(const char *text, quadlet_t *data, int size)
{
......@@ -1246,7 +1245,6 @@ EXPORT_SYMBOL(hpsb_unref_host);
/** ieee1394_core.c **/
EXPORT_SYMBOL(hpsb_speedto_str);
EXPORT_SYMBOL(hpsb_speedto_maxrec);
EXPORT_SYMBOL(hpsb_set_packet_complete_task);
EXPORT_SYMBOL(alloc_hpsb_packet);
EXPORT_SYMBOL(free_hpsb_packet);
......
......@@ -10,6 +10,7 @@
*/
#include <linux/slab.h>
#include <linux/sched.h>
#include "iso.h"
void hpsb_iso_stop(struct hpsb_iso *iso)
......
......@@ -79,7 +79,7 @@
#include "sbp2.h"
static char version[] __devinitdata =
"$Rev: 938 $ Ben Collins <bcollins@debian.org>";
"$Rev: 942 $ Ben Collins <bcollins@debian.org>";
/*
* Module load parameter definitions
......@@ -230,6 +230,8 @@ static void sbp2scsi_complete_command(struct scsi_id_instance_data *scsi_id,
static Scsi_Host_Template scsi_driver_template;
const u8 sbp2_speedto_max_payload[] = { 0x7, 0x8, 0x9, 0xA, 0xB, 0xC };
static struct hpsb_highlevel sbp2_highlevel = {
.name = SBP2_DEVICE_NAME,
.remove_host = sbp2_remove_host,
......@@ -779,7 +781,7 @@ static int sbp2_start_ud(struct sbp2scsi_host_info *hi, struct unit_directory *u
scsi_id->ne = ud->ne;
scsi_id->hi = hi;
scsi_id->speed_code = SPEED_100;
scsi_id->max_payload_size = hpsb_speedto_maxrec[SPEED_100];
scsi_id->max_payload_size = sbp2_speedto_max_payload[SPEED_100];
atomic_set(&scsi_id->sbp2_login_complete, 0);
INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_inuse);
INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_completed);
......@@ -1690,7 +1692,7 @@ static int sbp2_max_speed_and_size(struct scsi_id_instance_data *scsi_id)
/* Payload size is the lesser of what our speed supports and what
* our host supports. */
scsi_id->max_payload_size = min(hpsb_speedto_maxrec[scsi_id->speed_code],
scsi_id->max_payload_size = min(sbp2_speedto_max_payload[scsi_id->speed_code],
(u8)(((be32_to_cpu(hi->host->csr.rom[2]) >> 12) & 0xf) - 1));
SBP2_ERR("Node[" NODE_BUS_FMT "]: Max speed [%s] - Max payload [%u]",
......
......@@ -13,6 +13,7 @@
#include <asm/io.h>
#include <linux/mtd/map.h>
#include <linux/mtd/cfi.h>
static u8 simple_map_read8(struct map_info *map, unsigned long ofs)
{
......
......@@ -150,6 +150,14 @@ struct eventpoll {
/* Protect the this structure access */
rwlock_t lock;
/*
* This semaphore is used to ensure that files are not removed
* while epoll is using them. This is read-held during the event
* collection loop and it is write-held during the file cleanup
* path, the epoll file exit code and the ctl operations.
*/
struct rw_semaphore sem;
/* Wait queue used by sys_epoll_wait() */
wait_queue_head_t wq;
......@@ -279,16 +287,6 @@ static struct super_block *eventpollfs_get_sb(struct file_system_type *fs_type,
/* Safe wake up implementation */
static struct poll_safewake psw;
/*
* This semaphore is used to ensure that files are not removed
* while epoll is using them. Namely the f_op->poll(), since
* it has to be called from outside the lock, must be protected.
* This is read-held during the event transfer loop to userspace
* and it is write-held during the file cleanup path and the epoll
* file exit code.
*/
static struct rw_semaphore epsem;
/* Slab cache used to allocate "struct epitem" */
static kmem_cache_t *epi_cache;
......@@ -357,8 +355,8 @@ static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq)
list_for_each(lnk, lsthead) {
tncur = list_entry(lnk, struct wake_task_node, llink);
if (tncur->task == this_task) {
if (tncur->wq == wq || ++wake_nests > EP_MAX_POLLWAKE_NESTS) {
if (tncur->wq == wq ||
(tncur->task == this_task && ++wake_nests > EP_MAX_POLLWAKE_NESTS)) {
/*
* Ops ... loop detected or maximum nest level reached.
* We abort this wake by breaking the cycle itself.
......@@ -367,7 +365,6 @@ static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq)
return;
}
}
}
/* Add the current task to the list */
tnode.task = this_task;
......@@ -437,14 +434,15 @@ void eventpoll_release(struct file *file)
* The only hit might come from ep_free() but by holding the semaphore
* will correctly serialize the operation.
*/
down_write(&epsem);
while (!list_empty(lsthead)) {
epi = list_entry(lsthead->next, struct epitem, fllink);
EP_LIST_DEL(&epi->fllink);
down_write(&epi->ep->sem);
ep_remove(epi->ep, epi);
up_write(&epi->ep->sem);
}
up_write(&epsem);
}
......@@ -568,9 +566,18 @@ asmlinkage long sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event *even
error = -EEXIST;
break;
case EPOLL_CTL_DEL:
if (epi)
if (epi) {
/*
* We need to protect the remove operation because another
* thread might be doing an epoll_wait() and using the
* target file.
*/
down_write(&ep->sem);
error = ep_remove(ep, epi);
else
up_write(&ep->sem);
} else
error = -ENOENT;
break;
case EPOLL_CTL_MOD:
......@@ -703,10 +710,6 @@ static int ep_getfd(int *efd, struct inode **einode, struct file **efile)
file->f_vfsmnt = mntget(eventpoll_mnt);
file->f_dentry = dget(dentry);
/*
* Initialize the file as read/write because it could be used
* with write() to add/remove/change interest sets.
*/
file->f_pos = 0;
file->f_flags = O_RDONLY;
file->f_op = &eventpoll_fops;
......@@ -815,6 +818,7 @@ static int ep_init(struct eventpoll *ep, unsigned int hashbits)
unsigned int i, hsize;
rwlock_init(&ep->lock);
init_rwsem(&ep->sem);
init_waitqueue_head(&ep->wq);
init_waitqueue_head(&ep->poll_wait);
INIT_LIST_HEAD(&ep->rdllist);
......@@ -841,11 +845,15 @@ static void ep_free(struct eventpoll *ep)
struct list_head *lsthead, *lnk;
struct epitem *epi;
/* We need to release all tasks waiting for these file */
if (waitqueue_active(&ep->poll_wait))
ep_poll_safewake(&psw, &ep->poll_wait);
/*
* We need to lock this because we could be hit by
* eventpoll_release() while we're freeing the "struct eventpoll".
*/
down_write(&epsem);
down_write(&ep->sem);
/*
* Walks through the whole hash by unregistering poll callbacks.
......@@ -863,7 +871,7 @@ static void ep_free(struct eventpoll *ep)
/*
* Walks through the whole hash by freeing each "struct epitem". At this
* point we are sure no poll callbacks will be lingering around, and also by
* write-holding "epsem" we can be sure that no file cleanup code will hit
* write-holding "sem" we can be sure that no file cleanup code will hit
* us during this operation. So we can avoid the lock on "ep->lock".
*/
for (i = 0, hsize = 1 << ep->hashbits; i < hsize; i++) {
......@@ -876,7 +884,7 @@ static void ep_free(struct eventpoll *ep)
}
}
up_write(&epsem);
up_write(&ep->sem);
/* Free hash pages */
ep_free_pages(ep->hpages, EP_HASH_PAGES(ep->hashbits));
......@@ -1337,20 +1345,6 @@ static int ep_collect_ready_items(struct eventpoll *ep, struct list_head *txlist
/* If this file is already in the ready list we exit soon */
if (!EP_IS_LINKED(&epi->txlink)) {
/*
* We need to increase the usage count of the "struct epitem" because
* another thread might call EPOLL_CTL_DEL on this target and make the
* object to vanish underneath our nose.
*/
ep_use_epitem(epi);
/*
* We need to increase the usage count of the "struct file" because
* another thread might call close() on this target and make the file
* to vanish before we will be able to call f_op->poll().
*/
get_file(epi->file);
/*
* This is initialized in this way so that the default
* behaviour of the reinjecting code will be to push back
......@@ -1389,19 +1383,21 @@ static int ep_send_events(struct eventpoll *ep, struct list_head *txlist,
struct epitem *epi;
struct epoll_event event[EP_MAX_BUF_EVENTS];
/*
* We can loop without lock because this is a task private list.
* The test done during the collection loop will guarantee us that
* another task will not try to collect this file. Also, items
* cannot vanish during the loop because we are holding "sem".
*/
list_for_each(lnk, txlist) {
epi = list_entry(lnk, struct epitem, txlink);
/* Get the ready file event set */
revents = epi->file->f_op->poll(epi->file, NULL);
/*
* Release the file usage before checking the event mask.
* In case this call will lead to the file removal, its
* ->event.events member has been already set to zero and
* this will make the event to be dropped.
* Get the ready file event set. We can safely use the file
* because we are holding the "sem" in read and this will
* guarantee that both the file and the item will not vanish.
*/
fput(epi->file);
revents = epi->file->f_op->poll(epi->file, NULL);
/*
* Set the return event set for the current file descriptor.
......@@ -1416,17 +1412,8 @@ static int ep_send_events(struct eventpoll *ep, struct list_head *txlist,
eventbuf++;
if (eventbuf == EP_MAX_BUF_EVENTS) {
if (__copy_to_user(&events[eventcnt], event,
eventbuf * sizeof(struct epoll_event))) {
/*
* We need to complete the loop to decrement the file
* usage before returning from this function.
*/
for (lnk = lnk->next; lnk != txlist; lnk = lnk->next) {
epi = list_entry(lnk, struct epitem, txlink);
fput(epi->file);
}
eventbuf * sizeof(struct epoll_event)))
return -EFAULT;
}
eventcnt += eventbuf;
eventbuf = 0;
}
......@@ -1447,7 +1434,8 @@ static int ep_send_events(struct eventpoll *ep, struct list_head *txlist,
/*
* Walk through the transfer list we collected with ep_collect_ready_items()
* and, if 1) the item is still "alive" 2) its event set is not empty 3) it's
* not already linked, links it to the ready list.
* not already linked, links it to the ready list. Same as above, we are holding
* "sem" so items cannot vanish underneath our nose.
*/
static void ep_reinject_items(struct eventpoll *ep, struct list_head *txlist)
{
......@@ -1475,8 +1463,6 @@ static void ep_reinject_items(struct eventpoll *ep, struct list_head *txlist)
list_add_tail(&epi->rdllink, &ep->rdllist);
ricnt++;
}
ep_release_epitem(epi);
}
if (ricnt) {
......@@ -1510,17 +1496,12 @@ static int ep_events_transfer(struct eventpoll *ep, struct epoll_event *events,
/*
* We need to lock this because we could be hit by
* eventpoll_release() while we're transfering
* events to userspace. Read-holding "epsem" will lock
* out eventpoll_release() during the whole
* transfer loop and this will garantie us that the
* file will not vanish underneath our nose when
* we will call f_op->poll() from ep_send_events().
* eventpoll_release() and epoll_ctl(EPOLL_CTL_DEL).
*/
down_read(&epsem);
down_read(&ep->sem);
/* Collect/extract ready items */
if (ep_collect_ready_items(ep, &txlist, maxevents)) {
if (ep_collect_ready_items(ep, &txlist, maxevents) > 0) {
/* Build result set in userspace */
eventcnt = ep_send_events(ep, &txlist, events);
......@@ -1528,7 +1509,7 @@ static int ep_events_transfer(struct eventpoll *ep, struct epoll_event *events,
ep_reinject_items(ep, &txlist);
}
up_read(&epsem);
up_read(&ep->sem);
return eventcnt;
}
......@@ -1652,9 +1633,6 @@ static int __init eventpoll_init(void)
{
int error;
/* Initialize the semaphore used to syncronize the file cleanup code */
init_rwsem(&epsem);
/* Initialize the structure used to perform safe poll wait head wake ups */
ep_poll_safewake_init(&psw);
......
......@@ -1262,6 +1262,13 @@ static int bput_one(handle_t *handle, struct buffer_head *bh)
return 0;
}
static int journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh)
{
if (buffer_mapped(bh))
return ext3_journal_dirty_data(handle, bh);
return 0;
}
/*
* Note that we always start a transaction even if we're not journalling
* data. This is to preserve ordering: any hole instantiation within
......@@ -1381,7 +1388,7 @@ static int ext3_writepage(struct page *page, struct writeback_control *wbc)
if (ret == 0) {
err = walk_page_buffers(handle, page_bufs,
0, PAGE_CACHE_SIZE, NULL,
ext3_journal_dirty_data);
journal_dirty_data_fn);
if (!ret)
ret = err;
}
......
......@@ -99,7 +99,12 @@ static ssize_t read_kcore(struct file *file, char *buf, size_t count, loff_t *pp
}
#else /* CONFIG_KCORE_AOUT */
#define KCORE_BASE PAGE_OFFSET
#ifndef kc_vaddr_to_offset
#define kc_vaddr_to_offset(v) ((v) - PAGE_OFFSET)
#endif
#ifndef kc_offset_to_vaddr
#define kc_offset_to_vaddr(o) ((o) + PAGE_OFFSET)
#endif
#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
......@@ -112,29 +117,60 @@ struct memelfnote
void *data;
};
static struct kcore_list *kclist;
static rwlock_t kclist_lock = RW_LOCK_UNLOCKED;
void
kclist_add(struct kcore_list *new, void *addr, size_t size)
{
new->addr = (unsigned long)addr;
new->size = size;
write_lock(&kclist_lock);
new->next = kclist;
kclist = new;
write_unlock(&kclist_lock);
}
struct kcore_list *
kclist_del(void *addr)
{
struct kcore_list *m, **p = &kclist;
write_lock(&kclist_lock);
for (m = *p; m; p = &m->next) {
if (m->addr == (unsigned long)addr) {
*p = m->next;
write_unlock(&kclist_lock);
return m;
}
}
write_unlock(&kclist_lock);
return 0;
}
extern char saved_command_line[];
static size_t get_kcore_size(int *num_vma, size_t *elf_buflen)
static size_t get_kcore_size(int *nphdr, size_t *elf_buflen)
{
size_t try, size;
struct vm_struct *m;
struct kcore_list *m;
*num_vma = 0;
size = ((size_t)high_memory - KCORE_BASE + PAGE_SIZE);
if (!vmlist) {
*elf_buflen = PAGE_SIZE;
return (size);
}
*nphdr = 1; /* PT_NOTE */
size = 0;
for (m=vmlist; m; m=m->next) {
try = (size_t)m->addr + m->size;
if (try > KCORE_BASE + size)
size = try - KCORE_BASE;
*num_vma = *num_vma + 1;
for (m=kclist; m; m=m->next) {
try = kc_vaddr_to_offset((size_t)m->addr + m->size);
if (try > size)
size = try;
*nphdr = *nphdr + 1;
}
*elf_buflen = sizeof(struct elfhdr) +
(*num_vma + 2)*sizeof(struct elf_phdr) +
3 * sizeof(struct memelfnote);
(*nphdr + 2)*sizeof(struct elf_phdr) +
3 * sizeof(struct memelfnote) +
sizeof(struct elf_prstatus) +
sizeof(struct elf_prpsinfo) +
sizeof(struct task_struct);
*elf_buflen = PAGE_ALIGN(*elf_buflen);
return size + *elf_buflen;
}
......@@ -184,9 +220,9 @@ static char *storenote(struct memelfnote *men, char *bufp)
/*
* store an ELF coredump header in the supplied buffer
* num_vma is the number of elements in vmlist
* nphdr is the number of elf_phdr to insert
*/
static void elf_kcore_store_hdr(char *bufp, int num_vma, int dataoff)
static void elf_kcore_store_hdr(char *bufp, int nphdr, int dataoff)
{
struct elf_prstatus prstatus; /* NT_PRSTATUS */
struct elf_prpsinfo prpsinfo; /* NT_PRPSINFO */
......@@ -194,7 +230,7 @@ static void elf_kcore_store_hdr(char *bufp, int num_vma, int dataoff)
struct elfhdr *elf;
struct memelfnote notes[3];
off_t offset = 0;
struct vm_struct *m;
struct kcore_list *m;
/* setup ELF header */
elf = (struct elfhdr *) bufp;
......@@ -214,7 +250,7 @@ static void elf_kcore_store_hdr(char *bufp, int num_vma, int dataoff)
elf->e_flags = 0;
elf->e_ehsize = sizeof(struct elfhdr);
elf->e_phentsize= sizeof(struct elf_phdr);
elf->e_phnum = 2 + num_vma;
elf->e_phnum = nphdr;
elf->e_shentsize= 0;
elf->e_shnum = 0;
elf->e_shstrndx = 0;
......@@ -232,33 +268,17 @@ static void elf_kcore_store_hdr(char *bufp, int num_vma, int dataoff)
nhdr->p_flags = 0;
nhdr->p_align = 0;
/* setup ELF PT_LOAD program header for the
* virtual range 0xc0000000 -> high_memory */
phdr = (struct elf_phdr *) bufp;
bufp += sizeof(struct elf_phdr);
offset += sizeof(struct elf_phdr);
phdr->p_type = PT_LOAD;
phdr->p_flags = PF_R|PF_W|PF_X;
phdr->p_offset = PAGE_OFFSET - KCORE_BASE + dataoff;
phdr->p_vaddr = PAGE_OFFSET;
phdr->p_paddr = __pa(PAGE_OFFSET);
phdr->p_filesz = phdr->p_memsz = ((unsigned long)high_memory - PAGE_OFFSET);
phdr->p_align = PAGE_SIZE;
/* setup ELF PT_LOAD program header for every vmalloc'd area */
for (m=vmlist; m; m=m->next) {
if (m->flags & VM_IOREMAP) /* don't dump ioremap'd stuff! (TA) */
continue;
/* setup ELF PT_LOAD program header for every area */
for (m=kclist; m; m=m->next) {
phdr = (struct elf_phdr *) bufp;
bufp += sizeof(struct elf_phdr);
offset += sizeof(struct elf_phdr);
phdr->p_type = PT_LOAD;
phdr->p_flags = PF_R|PF_W|PF_X;
phdr->p_offset = (size_t)m->addr - KCORE_BASE + dataoff;
phdr->p_offset = kc_vaddr_to_offset(m->addr) + dataoff;
phdr->p_vaddr = (size_t)m->addr;
phdr->p_paddr = __pa(m->addr);
phdr->p_paddr = 0;
phdr->p_filesz = phdr->p_memsz = m->size;
phdr->p_align = PAGE_SIZE;
}
......@@ -294,7 +314,7 @@ static void elf_kcore_store_hdr(char *bufp, int num_vma, int dataoff)
strcpy(prpsinfo.pr_fname, "vmlinux");
strncpy(prpsinfo.pr_psargs, saved_command_line, ELF_PRARGSZ);
nhdr->p_filesz = notesize(&notes[1]);
nhdr->p_filesz += notesize(&notes[1]);
bufp = storenote(&notes[1], bufp);
/* set up the task structure */
......@@ -303,7 +323,7 @@ static void elf_kcore_store_hdr(char *bufp, int num_vma, int dataoff)
notes[2].datasz = sizeof(struct task_struct);
notes[2].data = current;
nhdr->p_filesz = notesize(&notes[2]);
nhdr->p_filesz += notesize(&notes[2]);
bufp = storenote(&notes[2], bufp);
} /* end elf_kcore_store_hdr() */
......@@ -317,13 +337,14 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t
ssize_t acc = 0;
size_t size, tsz;
size_t elf_buflen;
int num_vma;
int nphdr;
unsigned long start;
read_lock(&vmlist_lock);
proc_root_kcore->size = size = get_kcore_size(&num_vma, &elf_buflen);
read_lock(&kclist_lock);
tsz = get_kcore_size(&nphdr, &elf_buflen);
proc_root_kcore->size = size = tsz + elf_buflen;
if (buflen == 0 || *fpos >= size) {
read_unlock(&vmlist_lock);
read_unlock(&kclist_lock);
return 0;
}
......@@ -340,12 +361,12 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t
tsz = buflen;
elf_buf = kmalloc(elf_buflen, GFP_ATOMIC);
if (!elf_buf) {
read_unlock(&vmlist_lock);
read_unlock(&kclist_lock);
return -ENOMEM;
}
memset(elf_buf, 0, elf_buflen);
elf_kcore_store_hdr(elf_buf, num_vma, elf_buflen);
read_unlock(&vmlist_lock);
elf_kcore_store_hdr(elf_buf, nphdr, elf_buflen);
read_unlock(&kclist_lock);
if (copy_to_user(buffer, elf_buf + *fpos, tsz)) {
kfree(elf_buf);
return -EFAULT;
......@@ -360,41 +381,30 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t
if (buflen == 0)
return acc;
} else
read_unlock(&vmlist_lock);
/* where page 0 not mapped, write zeros into buffer */
#if defined (__i386__) || defined (__mc68000__) || defined(__x86_64__)
if (*fpos < PAGE_SIZE + elf_buflen) {
/* work out how much to clear */
tsz = PAGE_SIZE + elf_buflen - *fpos;
if (buflen < tsz)
tsz = buflen;
/* write zeros to buffer */
if (clear_user(buffer, tsz))
return -EFAULT;
buflen -= tsz;
*fpos += tsz;
buffer += tsz;
acc += tsz;
/* leave now if filled buffer already */
if (buflen == 0)
return tsz;
}
#endif
read_unlock(&kclist_lock);
/*
* Fill the remainder of the buffer from kernel VM space.
* We said in the ELF header that the data which starts
* at 'elf_buflen' is virtual address KCORE_BASE. --rmk
* Check to see if our file offset matches with any of
* the addresses in the elf_phdr on our list.
*/
start = KCORE_BASE + (*fpos - elf_buflen);
start = kc_offset_to_vaddr(*fpos - elf_buflen);
if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen)
tsz = buflen;
while (buflen) {
if ((start >= VMALLOC_START) && (start < VMALLOC_END)) {
struct kcore_list *m;
read_lock(&kclist_lock);
for (m=kclist; m; m=m->next) {
if (start >= m->addr && start < (m->addr+m->size))
break;
}
read_unlock(&kclist_lock);
if (m == NULL) {
if (clear_user(buffer, tsz))
return -EFAULT;
} else if ((start >= VMALLOC_START) && (start < VMALLOC_END)) {
char * elf_buf;
struct vm_struct *m;
unsigned long curstart = start;
......@@ -439,8 +449,7 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t
return -EFAULT;
}
kfree(elf_buf);
} else if ((start > PAGE_OFFSET) && (start <
(unsigned long)high_memory)) {
} else {
if (kern_addr_valid(start)) {
if (copy_to_user(buffer, (char *)start, tsz))
return -EFAULT;
......@@ -448,9 +457,6 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t
if (clear_user(buffer, tsz))
return -EFAULT;
}
} else {
if (clear_user(buffer, tsz))
return -EFAULT;
}
buflen -= tsz;
*fpos += tsz;
......
......@@ -24,8 +24,6 @@
#define check_apicid_present (genapic->check_apicid_present)
#define check_phys_apicid_present (genapic->check_phys_apicid_present)
#define check_apicid_used (genapic->check_apicid_used)
#define GET_APIC_ID (genapic->get_apic_id)
#define APIC_ID_MASK (genapic->apic_id_mask)
#define cpu_mask_to_apicid (genapic->cpu_mask_to_apicid)
#endif /* __ASM_MACH_APIC_H */
#ifndef _GENAPIC_MACH_APICDEF_H
#define _GENAPIC_MACH_APICDEF_H 1
#ifndef APIC_DEFINITION
#include <asm/genapic.h>
#define GET_APIC_ID (genapic->get_apic_id)
#define APIC_ID_MASK (genapic->apic_id_mask)
#endif
#endif
......@@ -73,4 +73,6 @@ struct stat64 {
unsigned long long st_ino;
};
#define STAT_HAVE_NSEC 1
#endif
......@@ -209,6 +209,10 @@ ia64_phys_addr_valid (unsigned long addr)
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
#define VMALLOC_END (0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9)))
/* fs/proc/kcore.c */
#define kc_vaddr_to_offset(v) ((v) - 0xA000000000000000)
#define kc_offset_to_vaddr(o) ((o) + 0xA000000000000000)
/*
* Conversion functions: convert page frame number (pfn) and a protection value to a page
* table entry (pte).
......
......@@ -83,8 +83,6 @@ struct gendisk {
int major; /* major number of driver */
int first_minor;
int minors;
int minor_shift; /* number of times minor is shifted to
get real minor */
char disk_name[16]; /* name of major driver */
struct hd_struct **part; /* [indexed by minor] */
struct block_device_operations *fops;
......
......@@ -45,7 +45,9 @@
#define INIT_SIGNALS(sig) { \
.count = ATOMIC_INIT(1), \
.shared_pending = { NULL, &sig.shared_pending.head, {{0}}}, \
.shared_pending = { \
.list = LIST_HEAD_INIT(sig.shared_pending.list), \
.signal = {{0}}}, \
}
#define INIT_SIGHAND(sighand) { \
......@@ -97,7 +99,9 @@
.files = &init_files, \
.signal = &init_signals, \
.sighand = &init_sighand, \
.pending = { NULL, &tsk.pending.head, {{0}}}, \
.pending = { \
.list = LIST_HEAD_INIT(tsk.pending.list), \
.signal = {{0}}}, \
.blocked = {{0}}, \
.posix_timers = LIST_HEAD_INIT(tsk.posix_timers), \
.alloc_lock = SPIN_LOCK_UNLOCKED, \
......
......@@ -74,6 +74,12 @@ struct proc_dir_entry {
kdev_t rdev;
};
struct kcore_list {
struct kcore_list *next;
unsigned long addr;
size_t size;
};
#ifdef CONFIG_PROC_FS
extern struct proc_dir_entry proc_root;
......@@ -179,6 +185,12 @@ static inline void proc_net_remove(const char *name)
remove_proc_entry(name,proc_net);
}
/*
* fs/proc/kcore.c
*/
extern void kclist_add(struct kcore_list *, void *, size_t);
extern struct kcore_list *kclist_del(void *);
#else
#define proc_root_driver NULL
......@@ -223,6 +235,8 @@ static inline struct kcore_list * kclist_del(void *addr)
return NULL;
}
static inline void kclist_add(struct kcore_list *new, void *addr, size_t size) {};
static inline struct kcore_list * kclist_del(void *addr) {return NULL};
#endif /* CONFIG_PROC_FS */
struct proc_inode {
......
......@@ -317,6 +317,7 @@ struct k_itimer {
unsigned long it_incr; /* interval specified in jiffies */
struct task_struct *it_process; /* process to send signal to */
struct timer_list it_timer;
struct sigqueue *sigq; /* signal queue entry. */
};
......@@ -571,6 +572,10 @@ extern void zap_other_threads(struct task_struct *p);
extern int kill_pg(pid_t, int, int);
extern int kill_sl(pid_t, int, int);
extern int kill_proc(pid_t, int, int);
extern struct sigqueue *sigqueue_alloc(void);
extern void sigqueue_free(struct sigqueue *);
extern int send_sigqueue(int, struct sigqueue *, struct task_struct *);
extern int send_group_sigqueue(int, struct sigqueue *, struct task_struct *);
extern int do_sigaction(int, const struct k_sigaction *, struct k_sigaction *);
extern int do_sigaltstack(const stack_t __user *, stack_t __user *, unsigned long);
......
......@@ -3,6 +3,7 @@
#include <asm/signal.h>
#include <asm/siginfo.h>
#include <linux/list.h>
#ifdef __KERNEL__
/*
......@@ -10,12 +11,17 @@
*/
struct sigqueue {
struct sigqueue *next;
struct list_head list;
spinlock_t *lock;
int flags;
siginfo_t info;
};
/* flags values. */
#define SIGQUEUE_PREALLOC 1
struct sigpending {
struct sigqueue *head, **tail;
struct list_head list;
sigset_t signal;
};
......@@ -197,8 +203,7 @@ static inline void siginitsetinv(sigset_t *set, unsigned long mask)
static inline void init_sigpending(struct sigpending *sig)
{
sigemptyset(&sig->signal);
sig->head = NULL;
sig->tail = &sig->head;
INIT_LIST_HEAD(&sig->list);
}
extern long do_sigpending(void __user *, unsigned long);
......
......@@ -51,6 +51,9 @@
#ifndef _LINUX_TIMEX_H
#define _LINUX_TIMEX_H
#include <linux/config.h>
#include <linux/compiler.h>
#include <asm/param.h>
/*
......@@ -310,6 +313,105 @@ extern long pps_calcnt; /* calibration intervals */
extern long pps_errcnt; /* calibration errors */
extern long pps_stbcnt; /* stability limit exceeded */
#ifdef CONFIG_TIME_INTERPOLATION
struct time_interpolator {
/* cache-hot stuff first: */
unsigned long (*get_offset) (void);
void (*update) (long);
void (*reset) (void);
/* cache-cold stuff follows here: */
struct time_interpolator *next;
unsigned long frequency; /* frequency in counts/second */
long drift; /* drift in parts-per-million (or -1) */
};
extern volatile unsigned long last_nsec_offset;
#ifndef __HAVE_ARCH_CMPXCHG
extern spin_lock_t last_nsec_offset_lock;
#endif
extern struct time_interpolator *time_interpolator;
extern void register_time_interpolator(struct time_interpolator *);
extern void unregister_time_interpolator(struct time_interpolator *);
/* Called with xtime WRITE-lock acquired. */
static inline void
time_interpolator_update(long delta_nsec)
{
struct time_interpolator *ti = time_interpolator;
if (last_nsec_offset > 0) {
#ifdef __HAVE_ARCH_CMPXCHG
unsigned long new, old;
do {
old = last_nsec_offset;
if (old > delta_nsec)
new = old - delta_nsec;
else
new = 0;
} while (cmpxchg(&last_nsec_offset, old, new) != old);
#else
/*
* This really hurts, because it serializes gettimeofday(), but without an
* atomic single-word compare-and-exchange, there isn't all that much else
* we can do.
*/
spin_lock(&last_nsec_offset_lock);
{
last_nsec_offset -= min(last_nsec_offset, delta_nsec);
}
spin_unlock(&last_nsec_offset_lock);
#endif
}
if (ti)
(*ti->update)(delta_nsec);
}
/* Called with xtime WRITE-lock acquired. */
static inline void
time_interpolator_reset(void)
{
struct time_interpolator *ti = time_interpolator;
last_nsec_offset = 0;
if (ti)
(*ti->reset)();
}
/* Called with xtime READ-lock acquired. */
static inline unsigned long
time_interpolator_get_offset(void)
{
struct time_interpolator *ti = time_interpolator;
if (ti)
return (*ti->get_offset)();
return last_nsec_offset;
}
#else /* !CONFIG_TIME_INTERPOLATION */
static inline void
time_interpolator_update(long delta_nsec)
{
}
static inline void
time_interpolator_reset(void)
{
}
static inline unsigned long
time_interpolator_get_offset(void)
{
return 0;
}
#endif /* !CONFIG_TIME_INTERPOLATION */
#endif /* KERNEL */
#endif /* LINUX_TIMEX_H */
......@@ -78,6 +78,10 @@ extern int vm_dirty_ratio;
extern int dirty_writeback_centisecs;
extern int dirty_expire_centisecs;
struct ctl_table;
struct file;
int dirty_writeback_centisecs_handler(struct ctl_table *, int, struct file *,
void *, size_t *);
void page_writeback_init(void);
void balance_dirty_pages(struct address_space *mapping);
......
......@@ -268,38 +268,38 @@ static int try_atomic_semop (struct sem_array * sma, struct sembuf * sops,
for (sop = sops; sop < sops + nsops; sop++) {
curr = sma->sem_base + sop->sem_num;
sem_op = sop->sem_op;
result = curr->semval;
if (!sem_op && curr->semval)
if (!sem_op && result)
goto would_block;
curr->sempid = (curr->sempid << 16) | pid;
curr->semval += sem_op;
if (sop->sem_flg & SEM_UNDO)
{
result += sem_op;
if (result < 0)
goto would_block;
if (result > SEMVMX)
goto out_of_range;
if (sop->sem_flg & SEM_UNDO) {
int undo = un->semadj[sop->sem_num] - sem_op;
/*
* Exceeding the undo range is an error.
*/
if (undo < (-SEMAEM - 1) || undo > SEMAEM)
{
/* Don't undo the undo */
sop->sem_flg &= ~SEM_UNDO;
goto out_of_range;
}
un->semadj[sop->sem_num] = undo;
}
if (curr->semval < 0)
goto would_block;
if (curr->semval > SEMVMX)
goto out_of_range;
curr->semval = result;
}
if (do_undo)
{
sop--;
if (do_undo) {
result = 0;
goto undo;
}
sop--;
while (sop >= sops) {
sma->sem_base[sop->sem_num].sempid = pid;
if (sop->sem_flg & SEM_UNDO)
un->semadj[sop->sem_num] -= sop->sem_op;
sop--;
}
sma->sem_otime = get_seconds();
return 0;
......@@ -315,13 +315,9 @@ static int try_atomic_semop (struct sem_array * sma, struct sembuf * sops,
result = 1;
undo:
sop--;
while (sop >= sops) {
curr = sma->sem_base + sop->sem_num;
curr->semval -= sop->sem_op;
curr->sempid >>= 16;
if (sop->sem_flg & SEM_UNDO)
un->semadj[sop->sem_num] += sop->sem_op;
sma->sem_base[sop->sem_num].semval -= sop->sem_op;
sop--;
}
......@@ -659,7 +655,7 @@ static int semctl_main(int semid, int semnum, int cmd, int version, union semun
err = curr->semval;
goto out_unlock;
case GETPID:
err = curr->sempid & 0xffff;
err = curr->sempid;
goto out_unlock;
case GETNCNT:
err = count_semncnt(sma,semnum);
......
......@@ -288,46 +288,32 @@ void do_schedule_next_timer(struct siginfo *info)
static void timer_notify_task(struct k_itimer *timr)
{
struct siginfo info;
int ret;
memset(&info, 0, sizeof (info));
memset(&timr->sigq->info, 0, sizeof(siginfo_t));
/* Send signal to the process that owns this timer. */
info.si_signo = timr->it_sigev_signo;
info.si_errno = 0;
info.si_code = SI_TIMER;
info.si_tid = timr->it_id;
info.si_value = timr->it_sigev_value;
timr->sigq->info.si_signo = timr->it_sigev_signo;
timr->sigq->info.si_errno = 0;
timr->sigq->info.si_code = SI_TIMER;
timr->sigq->info.si_tid = timr->it_id;
timr->sigq->info.si_value = timr->it_sigev_value;
if (timr->it_incr)
info.si_sys_private = ++timr->it_requeue_pending;
timr->sigq->info.si_sys_private = ++timr->it_requeue_pending;
if (timr->it_sigev_notify & SIGEV_THREAD_ID & MIPS_SIGEV)
ret = send_sig_info(info.si_signo, &info, timr->it_process);
ret = send_sigqueue(timr->it_sigev_signo, timr->sigq,
timr->it_process);
else
ret = send_group_sig_info(info.si_signo, &info,
ret = send_group_sigqueue(timr->it_sigev_signo, timr->sigq,
timr->it_process);
switch (ret) {
default:
if (ret) {
/*
* Signal was not sent. May or may not need to
* restart the timer.
*/
printk(KERN_WARNING "sending signal failed: %d\n", ret);
case 1:
/*
* signal was not sent because of sig_ignor or,
* possibly no queue memory OR will be sent but,
* signal was not sent because of sig_ignor
* we will not get a call back to restart it AND
* it should be restarted.
*/
schedule_next_timer(timr);
case 0:
/*
* all's well new signal queued
*/
break;
}
}
......@@ -379,7 +365,11 @@ static struct k_itimer * alloc_posix_timer(void)
struct k_itimer *tmr;
tmr = kmem_cache_alloc(posix_timers_cache, GFP_KERNEL);
memset(tmr, 0, sizeof (struct k_itimer));
tmr->it_id = (timer_t)-1;
if (unlikely(!(tmr->sigq = sigqueue_alloc()))) {
kmem_cache_free(posix_timers_cache, tmr);
tmr = 0;
}
return tmr;
}
......@@ -390,6 +380,7 @@ static void release_posix_timer(struct k_itimer *tmr)
idr_remove(&posix_timers_id, tmr->it_id);
spin_unlock_irq(&idr_lock);
}
sigqueue_free(tmr->sigq);
kmem_cache_free(posix_timers_cache, tmr);
}
......
This diff is collapsed.
......@@ -271,7 +271,6 @@ static ctl_table kern_table[] = {
/* Constants for minimum and maximum testing in vm_table.
We use these as one-element integer vectors. */
static int zero = 0;
static int one = 1;
static int one_hundred = 100;
......@@ -292,20 +291,7 @@ static ctl_table vm_table[] = {
&sysctl_intvec, NULL, &zero, &one_hundred },
{VM_DIRTY_WB_CS, "dirty_writeback_centisecs",
&dirty_writeback_centisecs, sizeof(dirty_writeback_centisecs), 0644,
NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL,
/* Here, we define the range of possible values for
dirty_writeback_centisecs.
The default value is 5 seconds (500 centisec). We will use 1
centisec, the smallest possible value that could make any sort of
sense. If we allowed the user to set the interval to 0 seconds
(which would presumably mean to chew up all of the CPU looking for
dirty pages and writing them out, without taking a break), the
interval would effectively become 1 second (100 centisecs), due to
some nicely documented throttling code in wb_kupdate().
There is no maximum legal value for dirty_writeback. */
&one , NULL},
NULL, dirty_writeback_centisecs_handler },
{VM_DIRTY_EXPIRE_CS, "dirty_expire_centisecs",
&dirty_expire_centisecs, sizeof(dirty_expire_centisecs), 0644,
NULL, &proc_dointvec},
......
......@@ -35,8 +35,6 @@
*/
struct timezone sys_tz;
extern unsigned long last_time_offset;
#if !defined(__alpha__) && !defined(__ia64__)
/*
......@@ -77,9 +75,10 @@ asmlinkage long sys_stime(int * tptr)
if (get_user(value, tptr))
return -EFAULT;
write_seqlock_irq(&xtime_lock);
time_interpolator_reset();
xtime.tv_sec = value;
xtime.tv_nsec = 0;
last_time_offset = 0;
time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC;
time_maxerror = NTP_PHASE_LIMIT;
......@@ -125,7 +124,7 @@ inline static void warp_clock(void)
{
write_seqlock_irq(&xtime_lock);
xtime.tv_sec += sys_tz.tz_minuteswest * 60;
last_time_offset = 0;
time_interpolator_update(sys_tz.tz_minuteswest * 60 * NSEC_PER_SEC);
write_sequnlock_irq(&xtime_lock);
}
......@@ -381,7 +380,6 @@ leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0
txc->calcnt = pps_calcnt;
txc->errcnt = pps_errcnt;
txc->stbcnt = pps_stbcnt;
last_time_offset = 0;
write_sequnlock_irq(&xtime_lock);
do_gettimeofday(&txc->time);
return(result);
......
......@@ -517,6 +517,7 @@ static void second_overflow(void)
if (xtime.tv_sec % 86400 == 0) {
xtime.tv_sec--;
wall_to_monotonic.tv_sec++;
time_interpolator_update(-NSEC_PER_SEC);
time_state = TIME_OOP;
clock_was_set();
printk(KERN_NOTICE "Clock: inserting leap second 23:59:60 UTC\n");
......@@ -527,6 +528,7 @@ static void second_overflow(void)
if ((xtime.tv_sec + 1) % 86400 == 0) {
xtime.tv_sec++;
wall_to_monotonic.tv_sec--;
time_interpolator_update(NSEC_PER_SEC);
time_state = TIME_WAIT;
clock_was_set();
printk(KERN_NOTICE "Clock: deleting leap second 23:59:59 UTC\n");
......@@ -605,7 +607,7 @@ static void second_overflow(void)
/* in the NTP reference this is called "hardclock()" */
static void update_wall_time_one_tick(void)
{
long time_adjust_step;
long time_adjust_step, delta_nsec;
if ( (time_adjust_step = time_adjust) != 0 ) {
/* We are doing an adjtime thing.
......@@ -625,7 +627,7 @@ static void update_wall_time_one_tick(void)
/* Reduce by this step the amount of time left */
time_adjust -= time_adjust_step;
}
xtime.tv_nsec += tick_nsec + time_adjust_step * 1000;
delta_nsec = tick_nsec + time_adjust_step * 1000;
/*
* Advance the phase, once it gets to one microsecond, then
* advance the tick more.
......@@ -634,13 +636,15 @@ static void update_wall_time_one_tick(void)
if (time_phase <= -FINEUSEC) {
long ltemp = -time_phase >> (SHIFT_SCALE - 10);
time_phase += ltemp << (SHIFT_SCALE - 10);
xtime.tv_nsec -= ltemp;
delta_nsec -= ltemp;
}
else if (time_phase >= FINEUSEC) {
long ltemp = time_phase >> (SHIFT_SCALE - 10);
time_phase -= ltemp << (SHIFT_SCALE - 10);
xtime.tv_nsec += ltemp;
delta_nsec += ltemp;
}
xtime.tv_nsec += delta_nsec;
time_interpolator_update(delta_nsec);
}
/*
......@@ -660,6 +664,7 @@ static void update_wall_time(unsigned long ticks)
if (xtime.tv_nsec >= 1000000000) {
xtime.tv_nsec -= 1000000000;
xtime.tv_sec++;
time_interpolator_update(NSEC_PER_SEC);
second_overflow();
}
}
......@@ -777,7 +782,6 @@ unsigned long wall_jiffies = INITIAL_JIFFIES;
#ifndef ARCH_HAVE_XTIME_LOCK
seqlock_t xtime_lock __cacheline_aligned_in_smp = SEQLOCK_UNLOCKED;
#endif
unsigned long last_time_offset;
/*
* This function runs timers and the timer-tq in bottom half context.
......@@ -811,7 +815,6 @@ static inline void update_times(void)
wall_jiffies += ticks;
update_wall_time(ticks);
}
last_time_offset = 0;
calc_load(ticks);
}
......@@ -1221,3 +1224,80 @@ void __init init_timers(void)
register_cpu_notifier(&timers_nb);
open_softirq(TIMER_SOFTIRQ, run_timer_softirq, NULL);
}
#ifdef CONFIG_TIME_INTERPOLATION
volatile unsigned long last_nsec_offset;
struct time_interpolator *time_interpolator;
#ifndef __HAVE_ARCH_CMPXCHG
spinlock_t last_nsec_offset_lock = SPIN_LOCK_UNLOCKED;
#endif
static struct {
spinlock_t lock; /* lock protecting list */
struct time_interpolator *list; /* list of registered interpolators */
} ti_global = {
.lock = SPIN_LOCK_UNLOCKED
};
static inline int
is_better_time_interpolator(struct time_interpolator *new)
{
if (!time_interpolator)
return 1;
return new->frequency > 2*time_interpolator->frequency
|| (unsigned long) new->drift < (unsigned long) time_interpolator->drift;
}
void
register_time_interpolator(struct time_interpolator *ti)
{
spin_lock(&ti_global.lock);
{
write_seqlock_irq(&xtime_lock);
{
if (is_better_time_interpolator(ti))
time_interpolator = ti;
}
write_sequnlock_irq(&xtime_lock);
ti->next = ti_global.list;
ti_global.list = ti;
}
spin_unlock(&ti_global.lock);
}
void
unregister_time_interpolator(struct time_interpolator *ti)
{
struct time_interpolator *curr, **prev;
spin_lock(&ti_global.lock);
{
prev = &ti_global.list;
for (curr = *prev; curr; curr = curr->next) {
if (curr == ti) {
*prev = curr->next;
break;
}
prev = &curr->next;
}
write_seqlock_irq(&xtime_lock);
{
if (ti == time_interpolator) {
/* we lost the best time-interpolator: */
time_interpolator = NULL;
/* find the next-best interpolator */
for (curr = ti_global.list; curr; curr = curr->next)
if (is_better_time_interpolator(curr))
time_interpolator = curr;
}
}
write_sequnlock_irq(&xtime_lock);
}
spin_unlock(&ti_global.lock);
}
#endif /* CONFIG_TIME_INTERPOLATION */
......@@ -677,6 +677,7 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
vma->vm_pgoff = pgoff;
vma->vm_file = NULL;
vma->vm_private_data = NULL;
vma->vm_next = NULL;
INIT_LIST_HEAD(&vma->shared);
if (file) {
......
......@@ -26,6 +26,7 @@
#include <linux/percpu.h>
#include <linux/notifier.h>
#include <linux/smp.h>
#include <linux/sysctl.h>
/*
* The maximum number of pages to writeout in a single bdflush/kupdate
......@@ -329,9 +330,26 @@ static void wb_kupdate(unsigned long arg)
}
if (time_before(next_jif, jiffies + HZ))
next_jif = jiffies + HZ;
if (dirty_writeback_centisecs)
mod_timer(&wb_timer, next_jif);
}
/*
* sysctl handler for /proc/sys/vm/dirty_writeback_centisecs
*/
int dirty_writeback_centisecs_handler(ctl_table *table, int write,
struct file *file, void *buffer, size_t *length)
{
proc_dointvec(table, write, file, buffer, length);
if (dirty_writeback_centisecs) {
mod_timer(&wb_timer,
jiffies + (dirty_writeback_centisecs * HZ) / 100);
} else {
del_timer(&wb_timer);
}
return 0;
}
static void wb_timer_fn(unsigned long unused)
{
if (pdflush_operation(wb_kupdate, 0) < 0)
......
This diff is collapsed.
......@@ -35,44 +35,6 @@ static struct menu *rootEntry;
static char nohelp_text[] = "Sorry, no help available for this option yet.\n";
#if 0
static void printc(int ch)
{
static int sep = 0;
if (!sep) {
putchar('[');
sep = 1;
} else if (ch)
putchar('/');
if (!ch) {
putchar(']');
putchar(' ');
sep = 0;
} else
putchar(ch);
}
#endif
static void printo(const char *o)
{
static int sep = 0;
if (!sep) {
putchar('(');
sep = 1;
} else if (o) {
putchar(',');
putchar(' ');
}
if (!o) {
putchar(')');
putchar(' ');
sep = 0;
} else
printf("%s", o);
}
static void strip(char *str)
{
char *p = str;
......@@ -90,6 +52,16 @@ static void strip(char *str)
*p-- = 0;
}
static void check_stdin(void)
{
if (!valid_stdin && input_mode == ask_silent) {
printf("aborted!\n\n");
printf("Console input/output is redirected. ");
printf("Run 'make oldconfig' to update configuration.\n\n");
exit(1);
}
}
static void conf_askvalue(struct symbol *sym, const char *def)
{
enum symbol_type type = sym_get_type(sym);
......@@ -108,13 +80,14 @@ static void conf_askvalue(struct symbol *sym, const char *def)
printf("%s\n", def);
return;
}
if (!valid_stdin && input_mode == ask_silent) {
printf("aborted!\n\n");
printf("Console input/output is redirected. ");
printf("Run 'make oldconfig' to update configuration.\n\n");
exit(1);
}
check_stdin();
case ask_all:
if (!sym_is_changable(sym)) {
printf("%s\n", def);
line[0] = '\n';
line[1] = 0;
return;
}
fflush(stdout);
fgets(line, 128, stdin);
return;
......@@ -294,9 +267,8 @@ static int conf_sym(struct menu *menu)
static int conf_choice(struct menu *menu)
{
struct symbol *sym, *def_sym;
struct menu *cmenu, *def_menu;
const char *help;
int type, len;
struct menu *child;
int type;
bool is_new;
sym = menu->sym;
......@@ -314,75 +286,108 @@ static int conf_choice(struct menu *menu)
break;
}
} else {
sym->def = sym->curr;
if (S_TRI(sym->curr) == mod) {
sym->user = sym->curr;
if (sym->curr.tri == mod) {
printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
return 0;
}
}
while (1) {
printf("%*s%s ", indent - 1, "", menu_get_prompt(menu));
int cnt, def;
printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
def_sym = sym_get_choice_value(sym);
def_menu = NULL;
for (cmenu = menu->list; cmenu; cmenu = cmenu->next) {
if (!menu_is_visible(cmenu))
cnt = def = 0;
line[0] = '0';
line[1] = 0;
for (child = menu->list; child; child = child->next) {
if (!menu_is_visible(child))
continue;
printo(menu_get_prompt(cmenu));
if (cmenu->sym == def_sym)
def_menu = cmenu;
}
printo(NULL);
if (def_menu)
printf("[%s] ", menu_get_prompt(def_menu));
else {
if (!child->sym) {
printf("%*c %s\n", indent, '*', menu_get_prompt(child));
continue;
}
cnt++;
if (child->sym == def_sym) {
def = cnt;
printf("%*c", indent, '>');
} else
printf("%*c", indent, ' ');
printf(" %d. %s", cnt, menu_get_prompt(child));
if (child->sym->name)
printf(" (%s)", child->sym->name);
if (!sym_has_value(child->sym))
printf(" (NEW)");
printf("\n");
return 1;
}
printf("%*schoice", indent - 1, "");
if (cnt == 1) {
printf("[1]: 1\n");
goto conf_childs;
}
printf("[1-%d", cnt);
if (sym->help)
printf("?");
printf("]: ");
switch (input_mode) {
case ask_new:
case ask_silent:
if (!is_new) {
cnt = def;
printf("%d\n", cnt);
break;
}
check_stdin();
case ask_all:
if (is_new)
sym->flags |= SYMBOL_NEW;
conf_askvalue(sym, menu_get_prompt(def_menu));
fflush(stdout);
fgets(line, 128, stdin);
strip(line);
break;
default:
line[0] = 0;
printf("\n");
if (line[0] == '?') {
printf("\n%s\n", menu->sym->help ?
menu->sym->help : nohelp_text);
continue;
}
if (line[0] == '?' && !line[1]) {
help = nohelp_text;
if (menu->sym->help)
help = menu->sym->help;
printf("\n%s\n", help);
if (!line[0])
cnt = def;
else if (isdigit(line[0]))
cnt = atoi(line);
else
continue;
break;
case set_random:
def = (random() % cnt) + 1;
case set_default:
case set_yes:
case set_mod:
case set_no:
cnt = def;
printf("%d\n", cnt);
break;
}
if (line[0]) {
len = strlen(line);
line[len] = 0;
def_menu = NULL;
for (cmenu = menu->list; cmenu; cmenu = cmenu->next) {
if (!cmenu->sym || !menu_is_visible(cmenu))
conf_childs:
for (child = menu->list; child; child = child->next) {
if (!child->sym || !menu_is_visible(child))
continue;
if (!strncasecmp(line, menu_get_prompt(cmenu), len)) {
def_menu = cmenu;
if (!--cnt)
break;
}
if (!child)
continue;
if (line[strlen(line) - 1] == '?') {
printf("\n%s\n", child->sym->help ?
child->sym->help : nohelp_text);
continue;
}
}
if (def_menu) {
sym_set_choice_value(sym, def_menu->sym);
if (def_menu->list) {
sym_set_choice_value(sym, child->sym);
if (child->list) {
indent += 2;
conf(def_menu->list);
conf(child->list);
indent -= 2;
}
return 1;
}
}
}
static void conf(struct menu *menu)
......@@ -422,7 +427,7 @@ static void conf(struct menu *menu)
if (sym_is_choice(sym)) {
conf_choice(menu);
if (S_TRI(sym->curr) != mod)
if (sym->curr.tri != mod)
return;
goto conf_childs;
}
......
......@@ -105,11 +105,11 @@ int conf_read(const char *name)
case S_INT:
case S_HEX:
case S_STRING:
if (S_VAL(sym->def))
free(S_VAL(sym->def));
if (sym->user.val)
free(sym->user.val);
default:
S_VAL(sym->def) = NULL;
S_TRI(sym->def) = no;
sym->user.val = NULL;
sym->user.tri = no;
}
}
......@@ -129,7 +129,7 @@ int conf_read(const char *name)
switch (sym->type) {
case S_BOOLEAN:
case S_TRISTATE:
sym->def = symbol_no.curr;
sym->user = symbol_no.curr;
sym->flags &= ~SYMBOL_NEW;
break;
default:
......@@ -154,18 +154,18 @@ int conf_read(const char *name)
switch (sym->type) {
case S_TRISTATE:
if (p[0] == 'm') {
S_TRI(sym->def) = mod;
sym->user.tri = mod;
sym->flags &= ~SYMBOL_NEW;
break;
}
case S_BOOLEAN:
if (p[0] == 'y') {
S_TRI(sym->def) = yes;
sym->user.tri = yes;
sym->flags &= ~SYMBOL_NEW;
break;
}
if (p[0] == 'n') {
S_TRI(sym->def) = no;
sym->user.tri = no;
sym->flags &= ~SYMBOL_NEW;
break;
}
......@@ -187,7 +187,7 @@ int conf_read(const char *name)
case S_INT:
case S_HEX:
if (sym_string_valid(sym, p)) {
S_VAL(sym->def) = strdup(p);
sym->user.val = strdup(p);
sym->flags &= ~SYMBOL_NEW;
} else {
fprintf(stderr, "%s:%d: symbol value '%s' invalid for %s\n", name, lineno, p, sym->name);
......@@ -198,21 +198,21 @@ int conf_read(const char *name)
;
}
if (sym_is_choice_value(sym)) {
prop = sym_get_choice_prop(sym);
switch (S_TRI(sym->def)) {
struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
switch (sym->user.tri) {
case mod:
if (S_TRI(prop->def->def) == yes)
if (cs->user.tri == yes)
/* warn? */;
break;
case yes:
if (S_TRI(prop->def->def) != no)
if (cs->user.tri != no)
/* warn? */;
S_VAL(prop->def->def) = sym;
cs->user.val = sym;
break;
case no:
break;
}
S_TRI(prop->def->def) = S_TRI(sym->def);
cs->user.tri = sym->user.tri;
}
break;
case '\n':
......@@ -224,11 +224,25 @@ int conf_read(const char *name)
fclose(in);
for_all_symbols(i, sym) {
sym_calc_value(sym);
if (sym_has_value(sym)) {
if (sym->visible == no)
sym->flags |= SYMBOL_NEW;
switch (sym->type) {
case S_STRING:
case S_INT:
case S_HEX:
if (!sym_string_within_range(sym, sym->user.val))
sym->flags |= SYMBOL_NEW;
default:
break;
}
}
if (!sym_is_choice(sym))
continue;
prop = sym_get_choice_prop(sym);
sym->flags &= ~SYMBOL_NEW;
for (e = prop->dep; e; e = e->left.expr)
for (e = prop->expr; e; e = e->left.expr)
sym->flags |= e->right.sym->flags & SYMBOL_NEW;
}
......@@ -242,19 +256,41 @@ int conf_write(const char *name)
FILE *out, *out_h;
struct symbol *sym;
struct menu *menu;
char oldname[128];
const char *basename;
char dirname[128], tmpname[128], newname[128];
int type, l;
const char *str;
out = fopen(".tmpconfig", "w");
dirname[0] = 0;
if (name && name[0]) {
char *slash = strrchr(name, '/');
if (slash) {
int size = slash - name + 1;
memcpy(dirname, name, size);
dirname[size] = 0;
if (slash[1])
basename = slash + 1;
else
basename = conf_def_filename;
} else
basename = name;
} else
basename = conf_def_filename;
sprintf(newname, "%s.tmpconfig.%d", dirname, getpid());
out = fopen(newname, "w");
if (!out)
return 1;
out_h = NULL;
if (!name) {
out_h = fopen(".tmpconfig.h", "w");
if (!out_h)
return 1;
}
fprintf(out, "#\n"
"# Automatically generated make config: don't edit\n"
"#\n");
if (out_h)
fprintf(out_h, "/*\n"
" * Automatically generated C config: don't edit\n"
" */\n"
......@@ -274,6 +310,7 @@ int conf_write(const char *name)
"#\n"
"# %s\n"
"#\n", str);
if (out_h)
fprintf(out_h, "\n"
"/*\n"
" * %s\n"
......@@ -286,7 +323,7 @@ int conf_write(const char *name)
type = sym->type;
if (type == S_TRISTATE) {
sym_calc_value(modules_sym);
if (S_TRI(modules_sym->curr) == no)
if (modules_sym->curr.tri == no)
type = S_BOOLEAN;
}
switch (type) {
......@@ -295,14 +332,17 @@ int conf_write(const char *name)
switch (sym_get_tristate_value(sym)) {
case no:
fprintf(out, "# CONFIG_%s is not set\n", sym->name);
if (out_h)
fprintf(out_h, "#undef CONFIG_%s\n", sym->name);
break;
case mod:
fprintf(out, "CONFIG_%s=m\n", sym->name);
if (out_h)
fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name);
break;
case yes:
fprintf(out, "CONFIG_%s=y\n", sym->name);
if (out_h)
fprintf(out_h, "#define CONFIG_%s 1\n", sym->name);
break;
}
......@@ -311,33 +351,39 @@ int conf_write(const char *name)
// fix me
str = sym_get_string_value(sym);
fprintf(out, "CONFIG_%s=\"", sym->name);
if (out_h)
fprintf(out_h, "#define CONFIG_%s \"", sym->name);
do {
l = strcspn(str, "\"\\");
if (l) {
fwrite(str, l, 1, out);
if (out_h)
fwrite(str, l, 1, out_h);
}
str += l;
while (*str == '\\' || *str == '"') {
fprintf(out, "\\%c", *str);
if (out_h)
fprintf(out_h, "\\%c", *str);
str++;
}
} while (*str);
fputs("\"\n", out);
if (out_h)
fputs("\"\n", out_h);
break;
case S_HEX:
str = sym_get_string_value(sym);
if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
if (out_h)
fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str);
break;
}
case S_INT:
str = sym_get_string_value(sym);
fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
if (out_h)
fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str);
break;
}
......@@ -358,18 +404,18 @@ int conf_write(const char *name)
}
}
fclose(out);
if (out_h) {
fclose(out_h);
if (!name) {
rename(".tmpconfig.h", "include/linux/autoconf.h");
}
if (!name || basename != conf_def_filename) {
if (!name)
name = conf_def_filename;
file_write_dep(NULL);
} else
unlink(".tmpconfig.h");
sprintf(oldname, "%s.old", name);
rename(name, oldname);
if (rename(".tmpconfig", name))
sprintf(tmpname, "%s.old", name);
rename(name, tmpname);
}
sprintf(tmpname, "%s%s", dirname, basename);
if (rename(newname, tmpname))
return 1;
sym_change_count = 0;
......
......@@ -55,6 +55,13 @@ struct expr *expr_alloc_and(struct expr *e1, struct expr *e2)
return e2 ? expr_alloc_two(E_AND, e1, e2) : e1;
}
struct expr *expr_alloc_or(struct expr *e1, struct expr *e2)
{
if (!e1)
return e2;
return e2 ? expr_alloc_two(E_OR, e1, e2) : e1;
}
struct expr *expr_copy(struct expr *org)
{
struct expr *e;
......@@ -158,9 +165,22 @@ static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct e
void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
{
if (!e1 || !e2 || e1->type != e2->type)
if (!e1 || !e2)
return;
switch (e1->type) {
case E_OR:
case E_AND:
__expr_eliminate_eq(e1->type, ep1, ep2);
default:
;
}
if (e1->type != e2->type) switch (e2->type) {
case E_OR:
case E_AND:
__expr_eliminate_eq(e2->type, ep1, ep2);
default:
;
}
e1 = expr_eliminate_yn(e1);
e2 = expr_eliminate_yn(e2);
}
......@@ -195,6 +215,7 @@ int expr_eq(struct expr *e1, struct expr *e2)
trans_count = old_count;
return res;
case E_CHOICE:
case E_RANGE:
case E_NONE:
/* panic */;
}
......@@ -897,6 +918,7 @@ struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symb
case E_SYMBOL:
return expr_alloc_comp(type, e->left.sym, sym);
case E_CHOICE:
case E_RANGE:
case E_NONE:
/* panic */;
}
......@@ -914,7 +936,7 @@ tristate expr_calc_value(struct expr *e)
switch (e->type) {
case E_SYMBOL:
sym_calc_value(e->left.sym);
return S_TRI(e->left.sym->curr);
return e->left.sym->curr.tri;
case E_AND:
val1 = expr_calc_value(e->left.expr);
val2 = expr_calc_value(e->right.expr);
......@@ -1017,11 +1039,18 @@ void expr_print(struct expr *e, void (*fn)(void *, const char *), void *data, in
expr_print(e->right.expr, fn, data, E_AND);
break;
case E_CHOICE:
fn(data, e->right.sym->name);
if (e->left.expr) {
expr_print(e->left.expr, fn, data, E_CHOICE);
fn(data, " ^ ");
expr_print(e->left.expr, fn, data, E_CHOICE);
}
break;
case E_RANGE:
fn(data, "[");
fn(data, e->left.sym->name);
fn(data, " ");
fn(data, e->right.sym->name);
fn(data, "]");
break;
default:
{
......
......@@ -18,10 +18,6 @@ extern "C" {
struct file {
struct file *next;
struct file *parent;
#ifdef CML1
struct statement *stmt;
struct statement *last_stmt;
#endif
char *name;
int lineno;
int flags;
......@@ -36,7 +32,7 @@ typedef enum tristate {
} tristate;
enum expr_type {
E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_CHOICE, E_SYMBOL
E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_CHOICE, E_SYMBOL, E_RANGE
};
union expr_data {
......@@ -45,18 +41,10 @@ union expr_data {
};
struct expr {
#ifdef CML1
int token;
#else
enum expr_type type;
#endif
union expr_data left, right;
};
#define E_TRI(ev) ((ev).tri)
#define E_EXPR(ev) ((ev).expr)
#define E_CALC(ev) (E_TRI(ev) = expr_calc_value(E_EXPR(ev)))
#define E_OR(dep1, dep2) (((dep1)>(dep2))?(dep1):(dep2))
#define E_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2))
#define E_NOT(dep) (2-(dep))
......@@ -66,12 +54,8 @@ struct expr_value {
tristate tri;
};
#define S_VAL(sv) ((sv).value)
#define S_TRI(sv) ((sv).tri)
#define S_EQ(sv1, sv2) (S_VAL(sv1) == S_VAL(sv2) || !strcmp(S_VAL(sv1), S_VAL(sv2)))
struct symbol_value {
void *value;
void *val;
tristate tri;
};
......@@ -83,31 +67,17 @@ struct symbol {
struct symbol *next;
char *name;
char *help;
#ifdef CML1
int type;
#else
enum symbol_type type;
#endif
struct symbol_value curr, def;
struct symbol_value curr, user;
tristate visible;
int flags;
struct property *prop;
struct expr *dep, *dep2;
struct menu *menu;
struct expr_value rev_dep;
};
#define for_all_symbols(i, sym) for (i = 0; i < 257; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
#ifdef CML1
#define SYMBOL_UNKNOWN S_UNKNOWN
#define SYMBOL_BOOLEAN S_BOOLEAN
#define SYMBOL_TRISTATE S_TRISTATE
#define SYMBOL_INT S_INT
#define SYMBOL_HEX S_HEX
#define SYMBOL_STRING S_STRING
#define SYMBOL_OTHER S_OTHER
#endif
#define SYMBOL_YES 0x0001
#define SYMBOL_MOD 0x0002
#define SYMBOL_NO 0x0004
......@@ -122,34 +92,28 @@ struct symbol {
#define SYMBOL_CHANGED 0x0400
#define SYMBOL_NEW 0x0800
#define SYMBOL_AUTO 0x1000
#define SYMBOL_CHECKED 0x2000
#define SYMBOL_CHECK_DONE 0x4000
#define SYMBOL_WARNED 0x8000
#define SYMBOL_MAXLENGTH 256
#define SYMBOL_HASHSIZE 257
#define SYMBOL_HASHMASK 0xff
enum prop_type {
P_UNKNOWN, P_PROMPT, P_COMMENT, P_MENU, P_ROOTMENU, P_DEFAULT, P_CHOICE
P_UNKNOWN, P_PROMPT, P_COMMENT, P_MENU, P_DEFAULT, P_CHOICE, P_SELECT, P_RANGE
};
struct property {
struct property *next;
struct symbol *sym;
#ifdef CML1
int token;
#else
enum prop_type type;
#endif
const char *text;
struct symbol *def;
struct expr_value visible;
struct expr *dep;
struct expr *dep2;
struct expr *expr;
struct menu *menu;
struct file *file;
int lineno;
#ifdef CML1
struct property *next_pos;
#endif
};
#define for_all_properties(sym, st, tok) \
......@@ -176,6 +140,7 @@ struct menu {
};
#define MENU_CHANGED 0x0001
#define MENU_ROOT 0x0002
#ifndef SWIG
......@@ -186,18 +151,12 @@ struct file *lookup_file(const char *name);
extern struct symbol symbol_yes, symbol_no, symbol_mod;
extern struct symbol *modules_sym;
extern int cdebug;
extern int print_type;
struct expr *expr_alloc_symbol(struct symbol *sym);
#ifdef CML1
struct expr *expr_alloc_one(int token, struct expr *ce);
struct expr *expr_alloc_two(int token, struct expr *e1, struct expr *e2);
struct expr *expr_alloc_comp(int token, struct symbol *s1, struct symbol *s2);
#else
struct expr *expr_alloc_one(enum expr_type type, struct expr *ce);
struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2);
struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2);
#endif
struct expr *expr_alloc_and(struct expr *e1, struct expr *e2);
struct expr *expr_alloc_or(struct expr *e1, struct expr *e2);
struct expr *expr_copy(struct expr *org);
void expr_free(struct expr *e);
int expr_eq(struct expr *e1, struct expr *e2);
......@@ -217,17 +176,6 @@ struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symb
void expr_fprint(struct expr *e, FILE *out);
void print_expr(int mask, struct expr *e, int prevtoken);
#ifdef CML1
static inline int expr_is_yes(struct expr *e)
{
return !e || (e->token == WORD && e->left.sym == &symbol_yes);
}
static inline int expr_is_no(struct expr *e)
{
return e && (e->token == WORD && e->left.sym == &symbol_no);
}
#else
static inline int expr_is_yes(struct expr *e)
{
return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes);
......@@ -238,7 +186,6 @@ static inline int expr_is_no(struct expr *e)
return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no);
}
#endif
#endif
#ifdef __cplusplus
}
......
......@@ -164,8 +164,6 @@ const char *dbg_print_ptype(int val)
strcpy(buf, "comment");
if (val == P_MENU)
strcpy(buf, "menu");
if (val == P_ROOTMENU)
strcpy(buf, "rootmenu");
if (val == P_DEFAULT)
strcpy(buf, "default");
if (val == P_CHOICE)
......@@ -798,7 +796,7 @@ void on_back_pressed(GtkButton * button, gpointer user_data)
current = current->parent;
ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
if ((ptype != P_ROOTMENU) && (ptype != P_MENU))
if (ptype != P_MENU)
current = current->parent;
display_tree_part();
......@@ -836,6 +834,8 @@ void on_split_clicked(GtkButton * button, gpointer user_data)
gtk_widget_show(tree1_w);
gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
if (tree2)
gtk_tree_store_clear(tree2);
display_list();
}
......@@ -922,8 +922,10 @@ static void change_sym_value(struct menu *menu, gint col)
config_changed = TRUE;
if (view_mode == FULL_VIEW)
update_tree(&rootmenu, NULL);
else if (view_mode == SPLIT_VIEW)
else if (view_mode == SPLIT_VIEW) {
update_tree(current, NULL);
display_list();
}
else if (view_mode == SINGLE_VIEW)
display_tree_part(); //fixme: keep exp/coll
break;
......@@ -949,8 +951,10 @@ static void toggle_sym_value(struct menu *menu)
sym_set_tristate_value(menu->sym, newval);
if (view_mode == FULL_VIEW)
update_tree(&rootmenu, NULL);
else if (view_mode == SPLIT_VIEW)
else if (view_mode == SPLIT_VIEW) {
update_tree(current, NULL);
display_list();
}
else if (view_mode == SINGLE_VIEW)
display_tree_part(); //fixme: keep exp/coll
}
......@@ -1035,8 +1039,7 @@ on_treeview2_button_press_event(GtkWidget * widget,
enum prop_type ptype;
ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
if (((ptype == P_MENU) || (ptype == P_ROOTMENU)) &&
(view_mode == SINGLE_VIEW) && (col == COL_OPTION)) {
if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
// goes down into menu
current = menu;
display_tree_part();
......@@ -1192,7 +1195,6 @@ static gchar **fill_row(struct menu *menu)
ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
switch (ptype) {
case P_MENU:
case P_ROOTMENU:
row[COL_PIXBUF] = (gchar *) xpm_menu;
if (view_mode != FULL_VIEW)
row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
......@@ -1477,11 +1479,11 @@ static void display_tree(struct menu *menu)
if (sym)
sym->flags &= ~SYMBOL_CHANGED;
if ((view_mode == SPLIT_VIEW) && (ptype != P_ROOTMENU) &&
if ((view_mode == SPLIT_VIEW) && !(child->flags & MENU_ROOT) &&
(tree == tree1))
continue;
if ((view_mode == SPLIT_VIEW) && (ptype == P_ROOTMENU) &&
if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT) &&
(tree == tree2))
continue;
......@@ -1503,7 +1505,7 @@ static void display_tree(struct menu *menu)
&& (tree == tree2))
continue;
if (((menu != &rootmenu) && (ptype != P_ROOTMENU)) ||
if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT)) ||
(view_mode == FULL_VIEW)
|| (view_mode == SPLIT_VIEW)) {
indent++;
......@@ -1525,8 +1527,6 @@ static void display_tree_part(void)
/* Display the list in the left frame (split view) */
static void display_list(void)
{
if (tree2)
gtk_tree_store_clear(tree2);
if (tree1)
gtk_tree_store_clear(tree1);
......@@ -1542,7 +1542,7 @@ static void fixup_rootmenu(struct menu *menu)
if (!menu->prompt || menu->prompt->type != P_MENU)
return;
menu->prompt->type = P_ROOTMENU;
menu->flags |= MENU_ROOT;
for (child = menu->list; child; child = child->next)
fixup_rootmenu(child);
}
......
This diff is collapsed.
......@@ -49,9 +49,11 @@ void menu_add_menu(void);
void menu_end_menu(void);
void menu_add_entry(struct symbol *sym);
void menu_end_entry(void);
struct property *create_prop(enum prop_type type);
void menu_add_dep(struct expr *dep);
struct property *menu_add_prop(int token, char *prompt, struct symbol *def, struct expr *dep);
struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep);
void menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
void menu_finalize(struct menu *parent);
void menu_set_type(int type);
struct file *file_lookup(const char *name);
......@@ -64,16 +66,19 @@ extern struct menu *current_menu;
void sym_init(void);
void sym_clear_all_valid(void);
void sym_set_changed(struct symbol *sym);
struct symbol *sym_check_deps(struct symbol *sym);
struct property *prop_alloc(enum prop_type type, struct symbol *sym);
struct symbol *prop_get_symbol(struct property *prop);
static inline tristate sym_get_tristate_value(struct symbol *sym)
{
return S_TRI(sym->curr);
return sym->curr.tri;
}
static inline struct symbol *sym_get_choice_value(struct symbol *sym)
{
return (struct symbol *)S_VAL(sym->curr);
return (struct symbol *)sym->curr.val;
}
static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval)
......@@ -98,7 +103,6 @@ static inline bool sym_is_optional(struct symbol *sym)
static inline bool sym_has_value(struct symbol *sym)
{
//return S_VAL(sym->def) != NULL;
return sym->flags & SYMBOL_NEW ? false : true;
}
......
......@@ -18,13 +18,14 @@ P(sym_change_count,int,);
P(sym_lookup,struct symbol *,(const char *name, int isconst));
P(sym_find,struct symbol *,(const char *name));
P(sym_type_name,const char *,(int type));
P(sym_type_name,const char *,(enum symbol_type type));
P(sym_calc_value,void,(struct symbol *sym));
P(sym_get_type,int,(struct symbol *sym));
P(sym_get_type,enum symbol_type,(struct symbol *sym));
P(sym_tristate_within_range,bool,(struct symbol *sym,tristate tri));
P(sym_set_tristate_value,bool,(struct symbol *sym,tristate tri));
P(sym_toggle_tristate_value,tristate,(struct symbol *sym));
P(sym_string_valid,bool,(struct symbol *sym, const char *newval));
P(sym_string_within_range,bool,(struct symbol *sym, const char *str));
P(sym_set_string_value,bool,(struct symbol *sym, const char *newval));
P(sym_is_changable,bool,(struct symbol *sym));
P(sym_get_choice_prop,struct property *,(struct symbol *sym));
......
......@@ -384,7 +384,10 @@ static void build_conf(struct menu *menu)
switch (type) {
case S_BOOLEAN:
cprint("t%p", menu);
if (sym_is_changable(sym))
cprint1("[%c]", val == no ? ' ' : '*');
else
cprint1("---");
break;
case S_TRISTATE:
cprint("t%p", menu);
......@@ -393,7 +396,10 @@ static void build_conf(struct menu *menu)
case mod: ch = 'M'; break;
default: ch = ' '; break;
}
if (sym_is_changable(sym))
cprint1("<%c>", ch);
else
cprint1("---");
break;
default:
cprint("s%p", menu);
......@@ -402,13 +408,15 @@ static void build_conf(struct menu *menu)
if (tmp < 0)
tmp = 0;
cprint1("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
sym_has_value(sym) ? "" : " (NEW)");
(sym_has_value(sym) || !sym_is_changable(sym)) ?
"" : " (NEW)");
cprint_done();
goto conf_childs;
}
}
cprint1("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
sym_has_value(sym) ? "" : " (NEW)");
(sym_has_value(sym) || !sym_is_changable(sym)) ?
"" : " (NEW)");
if (menu->prompt->type == P_MENU) {
cprint1(" --->");
cprint_done();
......@@ -780,10 +788,12 @@ int main(int ac, char **av)
conf_write(NULL);
printf("\n\n"
"*** End of Linux kernel configuration.\n"
"*** Check the top-level Makefile for additional configuration.\n"
"*** Next, you may run 'make bzImage', 'make bzdisk', or 'make install'.\n\n");
"*** Execute 'make' to build the kernel or try 'make help'."
"\n\n");
} else
printf("\n\nYour kernel configuration changes were NOT saved.\n\n");
printf("\n\n"
"Your kernel configuration changes were NOT saved."
"\n\n");
return 0;
}
......@@ -94,56 +94,43 @@ void menu_set_type(int type)
sym->type = type;
return;
}
fprintf(stderr, "%s:%d: type of '%s' redefined from '%s' to '%s'\n",
fprintf(stderr, "%s:%d:warning: type of '%s' redefined from '%s' to '%s'\n",
current_entry->file->name, current_entry->lineno,
sym->name ? sym->name : "<choice>", sym_type_name(sym->type), sym_type_name(type));
}
struct property *create_prop(enum prop_type type)
struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
{
struct property *prop;
prop = malloc(sizeof(*prop));
memset(prop, 0, sizeof(*prop));
prop->type = type;
prop->file = current_file;
prop->lineno = zconf_lineno();
return prop;
}
struct property *prop = prop_alloc(type, current_entry->sym);
struct property *menu_add_prop(int token, char *prompt, struct symbol *def, struct expr *dep)
{
struct property *prop = create_prop(token);
struct property **propp;
prop->sym = current_entry->sym;
prop->menu = current_entry;
prop->text = prompt;
prop->def = def;
E_EXPR(prop->visible) = menu_check_dep(dep);
prop->expr = expr;
prop->visible.expr = menu_check_dep(dep);
if (prompt)
if (prompt) {
if (current_entry->prompt)
fprintf(stderr, "%s:%d: prompt redefined\n",
current_entry->file->name, current_entry->lineno);
current_entry->prompt = prop;
/* append property to the prop list of symbol */
if (prop->sym) {
for (propp = &prop->sym->prop; *propp; propp = &(*propp)->next)
;
*propp = prop;
}
return prop;
}
void menu_add_prompt(int token, char *prompt, struct expr *dep)
void menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
{
current_entry->prompt = menu_add_prop(token, prompt, NULL, dep);
menu_add_prop(type, prompt, NULL, dep);
}
void menu_add_default(int token, struct symbol *def, struct expr *dep)
void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
{
current_entry->prompt = menu_add_prop(token, NULL, def, dep);
menu_add_prop(type, NULL, expr, dep);
}
void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
{
menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
}
void menu_finalize(struct menu *parent)
......@@ -151,7 +138,7 @@ void menu_finalize(struct menu *parent)
struct menu *menu, *last_menu;
struct symbol *sym;
struct property *prop;
struct expr *parentdep, *basedep, *dep, *dep2;
struct expr *parentdep, *basedep, *dep, *dep2, **ep;
sym = parent->sym;
if (parent->list) {
......@@ -168,7 +155,7 @@ void menu_finalize(struct menu *parent)
}
parentdep = expr_alloc_symbol(sym);
} else if (parent->prompt)
parentdep = E_EXPR(parent->prompt->visible);
parentdep = parent->prompt->visible.expr;
else
parentdep = parent->dep;
......@@ -184,23 +171,28 @@ void menu_finalize(struct menu *parent)
for (; prop; prop = prop->next) {
if (prop->menu != menu)
continue;
dep = expr_transform(E_EXPR(prop->visible));
dep = expr_transform(prop->visible.expr);
dep = expr_alloc_and(expr_copy(basedep), dep);
dep = expr_eliminate_dups(dep);
if (menu->sym && menu->sym->type != S_TRISTATE)
dep = expr_trans_bool(dep);
E_EXPR(prop->visible) = dep;
prop->visible.expr = dep;
if (prop->type == P_SELECT) {
struct symbol *es = prop_get_symbol(prop);
es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
}
}
}
for (menu = parent->list; menu; menu = menu->next)
menu_finalize(menu);
} else if (sym) {
basedep = parent->prompt ? E_EXPR(parent->prompt->visible) : NULL;
basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
basedep = expr_eliminate_dups(expr_transform(basedep));
last_menu = NULL;
for (menu = parent->next; menu; menu = menu->next) {
dep = menu->prompt ? E_EXPR(menu->prompt->visible) : menu->dep;
dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
if (!expr_contains_symbol(dep, sym))
break;
if (expr_depends_symbol(dep, sym))
......@@ -229,14 +221,20 @@ void menu_finalize(struct menu *parent)
for (menu = parent->list; menu; menu = menu->next) {
if (sym && sym_is_choice(sym) && menu->sym) {
menu->sym->flags |= SYMBOL_CHOICEVAL;
for (prop = menu->sym->prop; prop; prop = prop->next) {
if (prop->type != P_DEFAULT)
continue;
fprintf(stderr, "%s:%d:warning: defaults for choice values not supported\n",
prop->file->name, prop->lineno);
}
current_entry = menu;
menu_set_type(sym->type);
menu_add_prop(P_CHOICE, NULL, parent->sym, NULL);
prop = sym_get_choice_prop(parent->sym);
//dep = expr_alloc_one(E_CHOICE, dep);
//dep->right.sym = menu->sym;
prop->dep = expr_alloc_one(E_CHOICE, prop->dep);
prop->dep->right.sym = menu->sym;
menu_add_symbol(P_CHOICE, sym, NULL);
prop = sym_get_choice_prop(sym);
for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
;
*ep = expr_alloc_one(E_CHOICE, NULL);
(*ep)->right.sym = menu->sym;
}
if (menu->list && (!menu->prompt || !menu->prompt->text)) {
for (last_menu = menu->list; ; last_menu = last_menu->next) {
......@@ -249,20 +247,87 @@ void menu_finalize(struct menu *parent)
menu->list = NULL;
}
}
if (sym && !(sym->flags & SYMBOL_WARNED)) {
struct symbol *sym2;
if (sym->type == S_UNKNOWN)
fprintf(stderr, "%s:%d:warning: config symbol defined without type\n",
parent->file->name, parent->lineno);
if (sym_is_choice(sym) && !parent->prompt)
fprintf(stderr, "%s:%d:warning: choice must have a prompt\n",
parent->file->name, parent->lineno);
for (prop = sym->prop; prop; prop = prop->next) {
switch (prop->type) {
case P_DEFAULT:
if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
prop->expr->type != E_SYMBOL)
fprintf(stderr, "%s:%d:warning: default must be a single symbol\n",
prop->file->name, prop->lineno);
break;
case P_SELECT:
sym2 = prop_get_symbol(prop);
if ((sym->type != S_BOOLEAN && sym->type != S_TRISTATE) ||
(sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE))
fprintf(stderr, "%s:%d:warning: enable is only allowed with boolean and tristate symbols\n",
prop->file->name, prop->lineno);
break;
case P_RANGE:
if (sym->type != S_INT && sym->type != S_HEX)
fprintf(stderr, "%s:%d:warning: range is only allowed for int or hex symbols\n",
prop->file->name, prop->lineno);
if (!sym_string_valid(sym, prop->expr->left.sym->name) ||
!sym_string_valid(sym, prop->expr->right.sym->name))
fprintf(stderr, "%s:%d:warning: range is invalid\n",
prop->file->name, prop->lineno);
break;
default:
;
}
}
sym->flags |= SYMBOL_WARNED;
}
if (sym && !sym_is_optional(sym) && parent->prompt) {
sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
expr_alloc_and(parent->prompt->visible.expr,
expr_alloc_symbol(&symbol_mod)));
}
}
bool menu_is_visible(struct menu *menu)
{
struct menu *child;
struct symbol *sym;
tristate visible;
if (!menu->prompt)
return false;
if (menu->sym) {
sym_calc_value(menu->sym);
visible = E_TRI(menu->prompt->visible);
sym = menu->sym;
if (sym) {
sym_calc_value(sym);
visible = menu->prompt->visible.tri;
} else
visible = E_CALC(menu->prompt->visible);
return visible != no;
visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
if (sym && sym_is_choice(sym)) {
for (child = menu->list; child; child = child->next)
if (menu_is_visible(child))
break;
if (!child)
return false;
}
if (visible != no)
return true;
if (!sym || sym_get_tristate_value(menu->sym) == no)
return false;
for (child = menu->list; child; child = child->next)
if (menu_is_visible(child))
return true;
return false;
}
const char *menu_get_prompt(struct menu *menu)
......@@ -285,7 +350,7 @@ struct menu *menu_get_parent_menu(struct menu *menu)
for (; menu != &rootmenu; menu = menu->parent) {
type = menu->prompt ? menu->prompt->type : 0;
if (type == P_MENU || type == P_ROOTMENU)
if (type == P_MENU)
break;
}
return menu;
......
......@@ -65,11 +65,11 @@ void ConfigList::updateMenuList(P* parent, struct menu* menu)
switch (mode) {
case menuMode:
if (type != P_ROOTMENU)
if (!(child->flags & MENU_ROOT))
goto hide;
break;
case symbolMode:
if (type == P_ROOTMENU)
if (child->flags & MENU_ROOT)
goto hide;
break;
default:
......@@ -83,8 +83,7 @@ void ConfigList::updateMenuList(P* parent, struct menu* menu)
else
item->testUpdateMenu(visible);
if (mode == fullMode || mode == menuMode ||
(type != P_MENU && type != P_ROOTMENU))
if (mode == fullMode || mode == menuMode || type != P_MENU)
updateMenuList(item, child);
else
updateMenuList(item, 0);
......@@ -140,7 +139,6 @@ void ConfigItem::updateMenu(void)
if (prop) switch (prop->type) {
case P_MENU:
case P_ROOTMENU:
if (list->mode == singleMode || list->mode == symbolMode) {
/* a menuconfig entry is displayed differently
* depending whether it's at the view root or a child.
......@@ -172,6 +170,7 @@ void ConfigItem::updateMenu(void)
char ch;
if (!sym_is_changable(sym) && !list->showAll) {
setPixmap(promptColIdx, 0);
setText(noColIdx, 0);
setText(modColIdx, 0);
setText(yesColIdx, 0);
......@@ -288,7 +287,7 @@ void ConfigItem::init(void)
ConfigItem::~ConfigItem(void)
{
if (menu) {
ConfigItem** ip = &(ConfigItem*)menu->data;
ConfigItem** ip = (ConfigItem**)&menu->data;
for (; *ip; ip = &(*ip)->nextItem) {
if (*ip == this) {
*ip = nextItem;
......@@ -333,7 +332,7 @@ ConfigList::ConfigList(ConfigView* p, ConfigMainWindow* cv)
updateAll(false),
symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no),
choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no),
menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback),
menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void),
showAll(false), showName(false), showRange(false), showData(false),
rootEntry(0)
{
......@@ -392,7 +391,7 @@ void ConfigList::updateSelection(void)
if (!menu)
return;
type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
if (mode == menuMode && (type == P_MENU || type == P_ROOTMENU))
if (mode == menuMode && type == P_MENU)
emit menuSelected(menu);
}
......@@ -403,7 +402,8 @@ void ConfigList::updateList(ConfigItem* item)
if (!rootEntry)
goto update;
if ((mode == singleMode || mode == symbolMode) && rootEntry != &rootmenu) {
if (rootEntry != &rootmenu && (mode == singleMode ||
(mode == symbolMode && rootEntry->parent != &rootmenu))) {
item = firstChild();
if (!item)
item = new ConfigItem(this, 0, true);
......@@ -507,7 +507,7 @@ void ConfigList::setRootMenu(struct menu *menu)
if (rootEntry == menu)
return;
type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN;
if (type != P_MENU && type != P_ROOTMENU)
if (type != P_MENU)
return;
updateMenuList(this, 0);
rootEntry = menu;
......@@ -518,13 +518,12 @@ void ConfigList::setRootMenu(struct menu *menu)
void ConfigList::setParentMenu(void)
{
ConfigItem* item;
struct menu *oldroot, *newroot;
struct menu *oldroot;
oldroot = rootEntry;
newroot = menu_get_parent_menu(oldroot);
if (newroot == oldroot)
if (rootEntry == &rootmenu)
return;
setRootMenu(newroot);
setRootMenu(menu_get_parent_menu(rootEntry->parent));
QListViewItemIterator it(this);
for (; (item = (ConfigItem*)it.current()); it++) {
......@@ -566,7 +565,8 @@ void ConfigList::keyPressEvent(QKeyEvent* ev)
if (!menu)
break;
type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
if ((type == P_MENU || type == P_ROOTMENU) && mode != fullMode) {
if (type == P_MENU && rootEntry != menu &&
mode != fullMode && mode != menuMode) {
emit menuSelected(menu);
break;
}
......@@ -601,6 +601,7 @@ void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e)
QPoint p(contentsToViewport(e->pos()));
ConfigItem* item = (ConfigItem*)itemAt(p);
struct menu *menu;
enum prop_type ptype;
const QPixmap* pm;
int idx, x;
......@@ -617,14 +618,17 @@ void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e)
int off = header()->sectionPos(0) + itemMargin() +
treeStepSize() * (item->depth() + (rootIsDecorated() ? 1 : 0));
if (x >= off && x < off + pm->width()) {
if (item->goParent)
if (item->goParent) {
emit parentSelected();
else if (!menu)
break;
else if (menu->sym)
changeValue(item);
else
} else if (!menu)
break;
ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
if (ptype == P_MENU && rootEntry != menu &&
mode != fullMode && mode != menuMode)
emit menuSelected(menu);
else
changeValue(item);
}
}
break;
......@@ -671,8 +675,7 @@ void ConfigList::contentsMouseDoubleClickEvent(QMouseEvent* e)
if (!menu)
goto skip;
ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
if ((ptype == P_ROOTMENU || ptype == P_MENU) &&
(mode == singleMode || mode == symbolMode))
if (ptype == P_MENU && (mode == singleMode || mode == symbolMode))
emit menuSelected(menu);
else if (menu->sym)
changeValue(item);
......@@ -880,7 +883,6 @@ ConfigMainWindow::ConfigMainWindow(void)
connect(menuList, SIGNAL(gotFocus(void)),
SLOT(listFocusChanged(void)));
//showFullView();
showSplitView();
}
......@@ -959,36 +961,54 @@ void ConfigMainWindow::setHelp(QListViewItem* item)
if (showDebug) {
debug += "type: ";
debug += print_filter(sym_type_name(sym->type));
if (sym_is_choice(sym))
debug += " (choice)";
debug += "<br>";
if (sym->rev_dep.expr) {
debug += "reverse dep: ";
expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
debug += "<br>";
}
for (struct property *prop = sym->prop; prop; prop = prop->next) {
switch (prop->type) {
case P_PROMPT:
case P_MENU:
debug += "prompt: ";
debug += print_filter(prop->text);
debug += "<br>";
if (prop->visible.expr) {
debug += "&nbsp;&nbsp;dep: ";
expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
debug += "<br>";
}
break;
case P_DEFAULT:
debug += "default: ";
debug += print_filter(prop->def->name);
expr_print(prop->expr, expr_print_help, &debug, E_NONE);
debug += "<br>";
if (prop->visible.expr) {
debug += "&nbsp;&nbsp;dep: ";
expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
break;
case P_CHOICE:
if (sym_is_choice(sym)) {
debug += "choice: ";
expr_print(prop->expr, expr_print_help, &debug, E_NONE);
debug += "<br>";
}
break;
case P_CHOICE:
case P_SELECT:
debug += "select: ";
expr_print(prop->expr, expr_print_help, &debug, E_NONE);
debug += "<br>";
break;
case P_RANGE:
debug += "range: ";
expr_print(prop->expr, expr_print_help, &debug, E_NONE);
debug += "<br>";
break;
default:
debug += "unknown property: ";
debug += prop_get_type_name(prop->type);
debug += "<br>";
}
if (prop->visible.expr) {
debug += "&nbsp;&nbsp;&nbsp;&nbsp;dep: ";
expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
debug += "<br>";
}
}
debug += "<br>";
}
......@@ -1002,10 +1022,12 @@ void ConfigMainWindow::setHelp(QListViewItem* item)
if (menu->prompt->visible.expr) {
debug += "&nbsp;&nbsp;dep: ";
expr_print(menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
debug += "<br>";
debug += "<br><br>";
}
}
}
if (showDebug)
debug += QString().sprintf("defined at %s:%d<br><br>", menu->file->name, menu->lineno);
helpText->setText(head + debug + help);
}
......@@ -1133,6 +1155,8 @@ void ConfigMainWindow::setShowName(bool b)
return;
configList->showName = b;
configList->reinit();
menuList->showName = b;
menuList->reinit();
}
void ConfigMainWindow::setShowRange(bool b)
......@@ -1141,6 +1165,8 @@ void ConfigMainWindow::setShowRange(bool b)
return;
configList->showRange = b;
configList->reinit();
menuList->showRange = b;
menuList->reinit();
}
void ConfigMainWindow::setShowData(bool b)
......@@ -1149,6 +1175,8 @@ void ConfigMainWindow::setShowData(bool b)
return;
configList->showData = b;
configList->reinit();
menuList->showData = b;
menuList->reinit();
}
/*
......@@ -1206,12 +1234,25 @@ void ConfigMainWindow::showAbout(void)
void fixup_rootmenu(struct menu *menu)
{
struct menu *child;
static int menu_cnt = 0;
if (!menu->prompt || menu->prompt->type != P_MENU)
return;
menu->prompt->type = P_ROOTMENU;
for (child = menu->list; child; child = child->next)
menu->flags |= MENU_ROOT;
for (child = menu->list; child; child = child->next) {
if (child->prompt && child->prompt->type == P_MENU) {
menu_cnt++;
fixup_rootmenu(child);
menu_cnt--;
} else if (!menu_cnt)
fixup_rootmenu(child);
}
}
static const char *progname;
static void usage(void)
{
printf("%s <config>\n", progname);
exit(0);
}
int main(int ac, char** av)
......@@ -1223,23 +1264,23 @@ int main(int ac, char** av)
kconfig_load();
#endif
progname = av[0];
configApp = new QApplication(ac, av);
#if QT_VERSION >= 300
configSettings = new QSettings;
#endif
if (ac > 1 && av[1][0] == '-') {
switch (av[1][1]) {
case 'a':
//showAll = 1;
break;
case 'h':
case '?':
printf("%s <config>\n", av[0]);
exit(0);
usage();
}
name = av[2];
} else
name = av[1];
if (!name)
usage();
conf_parse(name);
fixup_rootmenu(&rootmenu);
conf_read(NULL);
......
......@@ -108,7 +108,7 @@ public slots:
QPixmap symbolYesPix, symbolModPix, symbolNoPix;
QPixmap choiceYesPix, choiceNoPix;
QPixmap menuPix, menuInvPix, menuBackPix;
QPixmap menuPix, menuInvPix, menuBackPix, voidPix;
bool showAll, showName, showRange, showData;
enum listMode mode;
......
This diff is collapsed.
......@@ -106,11 +106,17 @@ n [A-Za-z0-9_]
"default" BEGIN(PARAM); return T_DEFAULT;
"prompt" BEGIN(PARAM); return T_PROMPT;
"tristate" BEGIN(PARAM); return T_TRISTATE;
"def_tristate" BEGIN(PARAM); return T_DEF_TRISTATE;
"bool" BEGIN(PARAM); return T_BOOLEAN;
"boolean" BEGIN(PARAM); return T_BOOLEAN;
"def_bool" BEGIN(PARAM); return T_DEF_BOOLEAN;
"def_boolean" BEGIN(PARAM); return T_DEF_BOOLEAN;
"int" BEGIN(PARAM); return T_INT;
"hex" BEGIN(PARAM); return T_HEX;
"string" BEGIN(PARAM); return T_STRING;
"select" BEGIN(PARAM); return T_SELECT;
"enable" BEGIN(PARAM); return T_SELECT;
"range" BEGIN(PARAM); return T_RANGE;
{n}+ {
alloc_string(yytext, yyleng);
zconflval.string = text;
......@@ -208,7 +214,6 @@ n [A-Za-z0-9_]
}
append_string(" ", ts);
}
}
[ \t]*\n/[^ \t\n] {
current_file->lineno++;
......@@ -347,7 +352,7 @@ static struct buffer *zconf_endfile(void)
int zconf_lineno(void)
{
if (current_buf)
return current_file->lineno;
return current_file->lineno - 1;
else
return 0;
}
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment