Commit 09f1c96e authored by Linus Torvalds's avatar Linus Torvalds

Import 2.4.0-test4pre5

parent 79e75677
......@@ -386,7 +386,7 @@
announces it. The <function>parport_announce_port</function>
function walks down the list of parallel port device drivers
(<structname>struct parport_driver</structname>s) calling the
<function>attach</function> function of each.
<function>attach</function> function of each (which may block).
</para>
<para>
......@@ -394,7 +394,7 @@
registering a port with the
<function>parport_unregister_port</function> function, and device
drivers are notified using the <function>detach</function>
callback.
callback (which may not block).
</para>
<para>
......@@ -656,9 +656,31 @@ struct parport_driver {
to the <function>attach</function> function when it is called, or
alternatively can be found from the list of detected parallel ports
directly with the (now deprecated)
<function>parport_enumerate</function> function.
<function>parport_enumerate</function> function. A better way of
doing this is with <function>parport_find_number</function> or
<function>parport_find_base</function> functions, which find ports
by number and by base I/O address respectively.
</para>
<funcsynopsis>
<funcsynopsisinfo>
#include &lt;parport.h&gt;
</funcsynopsisinfo>
<funcprototype>
<funcdef>struct parport *<function>parport_find_number</function></funcdef>
<paramdef>int <parameter>number</parameter></paramdef>
</funcprototype>
</funcsynopsis>
<funcsynopsis>
<funcsynopsisinfo>
#include &lt;parport.h&gt;
</funcsynopsisinfo>
<funcprototype>
<funcdef>struct parport *<function>parport_find_base</function></funcdef>
<paramdef>unsigned long <parameter>base</parameter></paramdef>
</funcprototype>
</funcsynopsis>
<para>
The next three parameters, <parameter>pf</parameter>,
<parameter>kf</parameter>, and <parameter>irq_func</parameter>, are
......@@ -2202,6 +2224,9 @@ ssize_t write_printer (int fd, const void *ptr, size_t count)
!Fdrivers/parport/daisy.c parport_find_class
!Fdrivers/parport/share.c parport_register_driver
!Fdrivers/parport/share.c parport_unregister_driver
!Fdrivers/parport/share.c parport_get_port
!Fdrivers/parport/share.c parport_put_port
!Fdrivers/parport/share.c parport_find_number parport_find_base
!Fdrivers/parport/share.c parport_register_device
!Fdrivers/parport/share.c parport_unregister_device
!Fdrivers/parport/daisy.c parport_open
......
June 2000 Kernel Parameters v2.4.0
July 2000 Kernel Parameters v2.4.0
~~~~~~~~~~~~~~~~~
The following is a consolidated list of the kernel parameters as implemented
......@@ -80,6 +80,8 @@ running once the system is up.
AM53C974= [HW,SCSI]
amijoy= [HW,JOY] Amiga joystick support
apm= [APM] Advanced Power Management.
applicom= [HW]
......@@ -139,6 +141,12 @@ running once the system is up.
dasd= [HW,NET]
db9= [HW,JOY]
db9_2= [HW,JOY]
db9_3= [HW,JOY]
debug [KNL] Enable kernel debugging (events log level).
decnet= [HW,NET]
......@@ -179,6 +187,12 @@ running once the system is up.
ftape= [HW] Floppy Tape subsystem debugging options.
gc= [HW,JOY]
gc_2= [HW,JOY]
gc_3= [HW,JOY]
gdth= [HW,SCSI]
gscd= [HW,CD]
......@@ -194,10 +208,6 @@ running once the system is up.
hisax= [HW,ISDN]
in2000= [HW,SCSI]
init= [KNL]
ibmmcascsi= [HW,MCA,SCSI] IBM MicroChannel SCSI adapter.
icn= [HW,ISDN]
......@@ -208,39 +218,19 @@ running once the system is up.
idebus= [HW] (E)IDE subsystem : VLB/PCI bus speed.
ip= [PNP]
isp16= [HW,CD]
iucv= [HW,NET]
js_am= [HW,JOY]
idle= [HW]
js_an= [HW,JOY]
js_as= [HW.JOY]
js_console= [HW,JOY]
js_console2= [HW,JOY]
js_console3= [HW,JOY]
js_db9= [HW,JOY]
js_db9_2= [HW,JOY]
js_db9_3= [HW,JOY]
in2000= [HW,SCSI]
js_l4= [HW,JOY]
init= [KNL]
js_pci= [HW,JOY,PCI]
ip= [PNP]
js_tg= [HW,JOY]
isp16= [HW,CD]
js_tg_2= [HW,JOY]
iucv= [HW,NET]
js_tg_3= [HW,JOY]
js= [HW,JOY] Analog joystick
kbd-reset [VT]
......@@ -354,6 +344,8 @@ running once the system is up.
nosync [HW, M68K] Disables sync negotiation for all devices.
notsc [BUGS=ix86] Disable Time Stamp Counter
nowb [ARM]
opl3= [HW,SOUND]
......@@ -484,6 +476,12 @@ running once the system is up.
tdfx= [HW,DRM]
tgfx= [HW,JOY]
tgfx_2= [HW,JOY]
tgfx_3= [HW,JOY]
tmc8xx= [HW,SCSI]
tmscsim= [HW,SCSI]
......
......@@ -15,6 +15,14 @@ bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
bool 'Prompt for obsolete code/drivers' CONFIG_OBSOLETE
endmenu
mainmenu_option next_comment
comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool ' Set version information on all module symbols' CONFIG_MODVERSIONS
bool ' Kernel module loader' CONFIG_KMOD
fi
endmenu
mainmenu_option next_comment
comment 'System Type'
......@@ -157,17 +165,6 @@ else
fi
endmenu
mainmenu_option next_comment
comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool ' Set version information on all symbols for modules' CONFIG_MODVERSIONS
bool ' Kernel module loader' CONFIG_KMOD
fi
endmenu
mainmenu_option next_comment
comment 'General setup'
source drivers/pci/Config.in
......
......@@ -15,6 +15,15 @@ comment 'Code maturity level options'
bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
endmenu
mainmenu_option next_comment
comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool ' Set version information on all module symbols' CONFIG_MODVERSIONS
bool ' Kernel module loader' CONFIG_KMOD
fi
endmenu
mainmenu_option next_comment
comment 'Processor type and features'
choice 'Processor family' \
......@@ -145,15 +154,6 @@ if [ "$CONFIG_SMP" = "y" -a "$CONFIG_X86_CMPXCHG" = "y" ]; then
fi
endmenu
mainmenu_option next_comment
comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool ' Set version information on all module symbols' CONFIG_MODVERSIONS
bool ' Kernel module loader' CONFIG_KMOD
fi
endmenu
mainmenu_option next_comment
comment 'General setup'
......
......@@ -392,6 +392,8 @@ void smp_send_reschedule(int cpu)
* Structure and data for smp_call_function(). This is designed to minimise
* static memory requirements. It also looks cleaner.
*/
static spinlock_t call_lock = SPIN_LOCK_UNLOCKED;
static volatile struct call_data_struct {
void (*func) (void *info);
void *info;
......@@ -422,9 +424,8 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
{
struct call_data_struct data;
int ret, cpus = smp_num_cpus-1;
static spinlock_t lock = SPIN_LOCK_UNLOCKED;
if(cpus == 0)
if (!cpus)
return 0;
data.func = func;
......@@ -434,21 +435,21 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
if (wait)
atomic_set(&data.finished, 0);
spin_lock_bh(&lock);
spin_lock_bh(&call_lock);
call_data = &data;
/* Send a message to all other CPUs and wait for them to respond */
send_IPI_allbutself(CALL_FUNCTION_VECTOR);
/* Wait for response */
/* FIXME: lock-up detection, backtrace on lock-up */
while(atomic_read(&data.started) != cpus)
while (atomic_read(&data.started) != cpus)
barrier();
ret = 0;
if (wait)
while (atomic_read(&data.finished) != cpus)
barrier();
spin_unlock_bh(&lock);
spin_unlock_bh(&call_lock);
return 0;
}
......
......@@ -3,6 +3,20 @@
#
mainmenu_name "Kernel configuration of Linux for IA-64 machines"
mainmenu_option next_comment
comment 'Code maturity level options'
bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
endmenu
mainmenu_option next_comment
comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool ' Set version information on all module symbols' CONFIG_MODVERSIONS
bool ' Kernel module loader' CONFIG_KMOD
fi
endmenu
mainmenu_option next_comment
comment 'General setup'
......@@ -67,20 +81,6 @@ else
define_bool CONFIG_PCMCIA n
fi
mainmenu_option next_comment
comment 'Code maturity level options'
bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
endmenu
mainmenu_option next_comment
comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
bool 'Kernel module loader' CONFIG_KMOD
fi
endmenu
source drivers/parport/Config.in
endmenu
......
......@@ -12,6 +12,15 @@ comment 'Code maturity level options'
bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
endmenu
mainmenu_option next_comment
comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool ' Set version information on all module symbols' CONFIG_MODVERSIONS
bool ' Kernel module loader' CONFIG_KMOD
fi
endmenu
mainmenu_option next_comment
comment 'Platform dependent setup'
......@@ -136,15 +145,6 @@ fi
endmenu
mainmenu_option next_comment
comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool ' Set version information on all symbols for modules' CONFIG_MODVERSIONS
bool ' Kernel module loader' CONFIG_KMOD
fi
endmenu
source drivers/mtd/Config.in
source drivers/block/Config.in
......
/*
* Reset a Cobalt Qube.
*/
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <asm/io.h>
......
......@@ -9,6 +9,15 @@ comment 'Code maturity level options'
bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
endmenu
mainmenu_option next_comment
comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool ' Set version information on all module symbols' CONFIG_MODVERSIONS
bool ' Kernel module loader' CONFIG_KMOD
fi
endmenu
mainmenu_option next_comment
comment 'Machine selection'
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
......@@ -159,12 +168,6 @@ comment 'General setup'
source drivers/parport/Config.in
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool ' Set version information on all symbols for modules' CONFIG_MODVERSIONS
bool ' Kernel module loader' CONFIG_KMOD
fi
if [ "$CONFIG_DECSTATION" = "y" ]; then
bool 'TURBOchannel support' CONFIG_TC
# if [ "$CONFIG_TC" = "y" ]; then
......
......@@ -25,7 +25,8 @@
#include <linux/mc146818rtc.h>
#include <linux/timex.h>
extern volatile unsigned long lost_ticks;
extern volatile unsigned long wall_jiffies;
extern rwlock_t xtime_lock;
/*
* Change this if you have some constant time drift
......@@ -64,7 +65,7 @@ static unsigned long do_fast_gettimeoffset(void)
quotient = cached_quotient;
if (last_jiffies != tmp) {
if (tmp && last_jiffies != tmp) {
last_jiffies = tmp;
__asm__(".set\tnoreorder\n\t"
".set\tnoat\n\t"
......@@ -81,12 +82,12 @@ static unsigned long do_fast_gettimeoffset(void)
".set\tmips0\n\t"
".set\tat\n\t"
".set\treorder"
: "=&r"(quotient)
: "r"(timerhi),
:"=&r"(quotient)
:"r"(timerhi),
"m"(timerlo),
"r"(tmp),
"r"(USECS_PER_JIFFY)
: "$1");
:"$1");
cached_quotient = quotient;
}
/* Get last timer tick in absolute kernel time */
......@@ -98,8 +99,8 @@ static unsigned long do_fast_gettimeoffset(void)
__asm__("multu\t%1,%2\n\t"
"mfhi\t%0"
: "=r"(res)
: "r"(count),
:"=r"(res)
:"r"(count),
"r"(quotient));
/*
......@@ -164,7 +165,7 @@ void do_gettimeofday(struct timeval *tv)
{
unsigned long flags;
save_and_cli(flags);
read_lock_irqsave(&xtime_lock, flags);
*tv = xtime;
tv->tv_usec += do_gettimeoffset();
......@@ -172,10 +173,10 @@ void do_gettimeofday(struct timeval *tv)
* xtime is atomically updated in timer_bh. lost_ticks is
* nonzero if the timer bottom half hasnt executed yet.
*/
if (lost_ticks)
if (jiffies - wall_jiffies)
tv->tv_usec += USECS_PER_JIFFY;
restore_flags(flags);
read_unlock_irqrestore(&xtime_lock, flags);
if (tv->tv_usec >= 1000000) {
tv->tv_usec -= 1000000;
......@@ -185,7 +186,7 @@ void do_gettimeofday(struct timeval *tv)
void do_settimeofday(struct timeval *tv)
{
cli();
write_lock_irq(&xtime_lock);
/* This is revolting. We need to set the xtime.tv_usec
* correctly. However, the value in this location is
* is value at the last tick.
......@@ -202,7 +203,7 @@ void do_settimeofday(struct timeval *tv)
time_state = TIME_BAD;
time_maxerror = MAXPHASE;
time_esterror = MAXPHASE;
sti();
write_unlock_irq(&xtime_lock);
}
/*
......@@ -247,8 +248,12 @@ static int set_rtc_mmss(unsigned long nowtime)
}
CMOS_WRITE(real_seconds, RTC_SECONDS);
CMOS_WRITE(real_minutes, RTC_MINUTES);
} else
} else {
printk(KERN_WARNING
"set_rtc_mmss: can't update from %d to %d\n",
cmos_minutes, real_minutes);
retval = -1;
}
/* The following flags have to be released exactly in this order,
* otherwise the DS12887 (popular MC146818A clone with integrated
......@@ -271,11 +276,29 @@ static long last_rtc_update = 0;
* as well as call the "do_timer()" routine every clocktick
*/
static void inline
timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
volatile unsigned char dummy;
dummy = CMOS_READ(RTC_REG_C); /* ACK RTC Interrupt */
if (!user_mode(regs)) {
if (prof_buffer && current->pid) {
extern int _stext;
unsigned long pc = regs->cp0_epc;
pc -= (unsigned long) &_stext;
pc >>= prof_shift;
/*
* Dont ignore out-of-bounds pc values silently,
* put them into the last histogram slot, so if
* present, they will show up as a sharp peak.
*/
if (pc > prof_len - 1)
pc = prof_len - 1;
atomic_inc((atomic_t *) & prof_buffer[pc]);
}
}
do_timer(regs);
/*
......@@ -283,6 +306,7 @@ static void inline
* CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
* called as close as possible to 500 ms before the new second starts.
*/
read_lock(&xtime_lock);
if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
xtime.tv_usec > 500000 - (tick >> 1) &&
xtime.tv_usec < 500000 + (tick >> 1))
......@@ -290,6 +314,12 @@ static void inline
last_rtc_update = xtime.tv_sec;
else
last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
/* As we return to user mode fire off the other CPU schedulers.. this is
basically because we don't yet share IRQ's around. This message is
rigged to be safe on the 386 - basically it's a hack, so don't look
closely for now.. */
/*smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0); */
read_unlock(&xtime_lock);
}
static void r4k_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
......@@ -305,6 +335,15 @@ static void r4k_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
timerlo = count;
timer_interrupt(irq, dev_id, regs);
if (!jiffies) {
/*
* If jiffies has overflowed in this timer_interrupt we must
* update the timer[hi]/[lo] to make do_fast_gettimeoffset()
* quotient calc still valid. -arca
*/
timerhi = timerlo = 0;
}
}
/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
......@@ -378,11 +417,9 @@ static inline void init_cycle_counter(void)
}
}
struct irqaction irq0 =
{timer_interrupt, SA_INTERRUPT, 0,
struct irqaction irq0 = {timer_interrupt, SA_INTERRUPT, 0,
"timer", NULL, NULL};
void (*board_time_init) (struct irqaction * irq);
void __init time_init(void)
......@@ -423,10 +460,12 @@ void __init time_init(void)
* The PROM will reset the year to either '70, '71 or '72.
* This hack will only work until Dec 31 2001.
*/
year += 1927;
year += 1928;
write_lock_irq(&xtime_lock);
xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
xtime.tv_usec = 0;
write_unlock_irq(&xtime_lock);
init_cycle_counter();
......
......@@ -49,6 +49,7 @@ EXPORT_SYMBOL_NOVERS(memcmp);
EXPORT_SYMBOL_NOVERS(memset);
EXPORT_SYMBOL_NOVERS(memcpy);
EXPORT_SYMBOL_NOVERS(memmove);
EXPORT_SYMBOL(simple_strtol);
EXPORT_SYMBOL_NOVERS(strcat);
EXPORT_SYMBOL_NOVERS(strchr);
EXPORT_SYMBOL_NOVERS(strlen);
......
......@@ -91,6 +91,15 @@ SECTIONS
_end = . ;
PROVIDE (end = .);
}
/* Sections to be discarded */
/DISCARD/ :
{
*(.text.exit)
*(.data.exit)
*(.exitcall.exit)
}
/* These are needed for ELF backends which have not yet been
converted to the new style linker. */
.stab 0 : { *(.stab) }
......
......@@ -91,6 +91,15 @@ SECTIONS
_end = . ;
PROVIDE (end = .);
}
/* Sections to be discarded */
/DISCARD/ :
{
*(.text.exit)
*(.data.exit)
*(.exitcall.exit)
}
/* These are needed for ELF backends which have not yet been
converted to the new style linker. */
.stab 0 : { *(.stab) }
......
......@@ -35,10 +35,8 @@
#include <asm/stackframe.h>
#include <asm/system.h>
#include <asm/cpu.h>
#include <linux/sched.h>
#include <linux/bootmem.h>
#include <asm/addrspace.h>
#include <asm/bootinfo.h>
#include <asm/mc146818rtc.h>
char arcs_cmdline[CL_SIZE] = {0, };
......
......@@ -35,10 +35,8 @@
#include <asm/stackframe.h>
#include <asm/system.h>
#include <asm/cpu.h>
#include <linux/sched.h>
#include <linux/bootmem.h>
#include <asm/addrspace.h>
#include <asm/bootinfo.h>
#include <asm/mc146818rtc.h>
#include <asm/orion.h>
......
......@@ -10,6 +10,15 @@ comment 'Code maturity level options'
bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
endmenu
mainmenu_option next_comment
comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool ' Set version information on all module symbols' CONFIG_MODVERSIONS
bool ' Kernel module loader' CONFIG_KMOD
fi
endmenu
mainmenu_option next_comment
comment 'Machine selection'
bool 'Support for SGI IP22' CONFIG_SGI_IP22
......@@ -109,14 +118,6 @@ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
endmenu
mainmenu_option next_comment
comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
bool 'Kernel module loader' CONFIG_KMOD
fi
source drivers/pci/Config.in
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
......
......@@ -100,10 +100,6 @@ NESTED(kernel_entry, 16, sp) # kernel entry point
ARC64_TWIDDLE_PC
/* Note that all firmware passed argument registers still
have their values. */
jal prom_init # initialize firmware
CLI # disable interrupts
mfc0 t0, CP0_STATUS
......@@ -127,6 +123,10 @@ NESTED(kernel_entry, 16, sp) # kernel entry point
dsrl32 t0, t0, 0
mtc0 t0, CP0_WATCHHI
#endif
/* Note that all firmware passed argument registers still
have their values. */
jal prom_init # initialize firmware
jal start_kernel
1: b 1b # just in case ...
END(kernel_entry)
......
......@@ -46,6 +46,7 @@ EXPORT_SYMBOL_NOVERS(memcmp);
EXPORT_SYMBOL_NOVERS(memset);
EXPORT_SYMBOL_NOVERS(memcpy);
EXPORT_SYMBOL_NOVERS(memmove);
EXPORT_SYMBOL(simple_strtol);
EXPORT_SYMBOL_NOVERS(strcat);
EXPORT_SYMBOL_NOVERS(strchr);
EXPORT_SYMBOL_NOVERS(strlen);
......
/* $Id: process.c,v 1.4 2000/01/16 01:34:01 ralf Exp $
*
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 1994 - 1999 by Ralf Baechle and others.
* Copyright (C) 1999 Silicon Graphics, Inc.
* Copyright (C) 1994 - 1999, 2000 by Ralf Baechle and others.
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
*/
#include <linux/errno.h>
#include <linux/sched.h>
......
/* $Id: r4k_tlb.S,v 1.3 2000/06/30 00:48:29 kanoj Exp $
*
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
......
......@@ -4,8 +4,8 @@
* for more details.
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 1994 - 1999 Ralf Baechle
* Copyright (C) 1999 Silicon Graphics, Inc.
* Copyright (C) 1994 - 2000 Ralf Baechle
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
*/
#include <linux/sched.h>
#include <linux/mm.h>
......
......@@ -83,6 +83,15 @@ SECTIONS
*(COMMON)
_end = . ;
}
/* Sections to be discarded */
/DISCARD/ :
{
*(.text.exit)
*(.data.exit)
*(.exitcall.exit)
}
/* These are needed for ELF backends which have not yet been
converted to the new style linker. */
.stab 0 : { *(.stab) }
......
......@@ -92,6 +92,15 @@ SECTIONS
*(COMMON)
_end = . ;
}
/* Sections to be discarded */
/DISCARD/ :
{
*(.text.exit)
*(.data.exit)
*(.exitcall.exit)
}
/* These are needed for ELF backends which have not yet been
converted to the new style linker. */
.stab 0 : { *(.stab) }
......
......@@ -26,6 +26,7 @@
#include <asm/pci/bridge.h>
#include <asm/paccess.h>
#include <asm/sn/sn0/ip27.h>
#include <asm/sn/sn0/hubio.h>
/* Check against user dumbness. */
#ifdef CONFIG_VT
......
......@@ -11,6 +11,15 @@ comment 'Code maturity level options'
bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
endmenu
mainmenu_option next_comment
comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool ' Set version information on all module symbols' CONFIG_MODVERSIONS
bool ' Kernel module loader' CONFIG_KMOD
fi
endmenu
mainmenu_option next_comment
comment 'Platform support'
define_bool CONFIG_PPC y
......@@ -76,15 +85,6 @@ if [ "$CONFIG_4xx" = "y" -o "$CONFIG_8xx" = "y" ]; then
fi
endmenu
mainmenu_option next_comment
comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool ' Set version information on all module symbols' CONFIG_MODVERSIONS
bool ' Kernel module loader' CONFIG_KMOD
fi
endmenu
mainmenu_option next_comment
comment 'General setup'
......
......@@ -13,21 +13,21 @@ comment 'Code maturity level options'
bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
endmenu
mainmenu_option next_comment
comment 'Processor type and features'
bool 'Symmetric multi-processing support' CONFIG_SMP
bool 'IEEE FPU emulation' CONFIG_IEEEFPU_EMULATION
endmenu
mainmenu_option next_comment
comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
bool 'Kernel module loader' CONFIG_KMOD
bool ' Set version information on all module symbols' CONFIG_MODVERSIONS
bool ' Kernel module loader' CONFIG_KMOD
fi
endmenu
mainmenu_option next_comment
comment 'Processor type and features'
bool 'Symmetric multi-processing support' CONFIG_SMP
bool 'IEEE FPU emulation' CONFIG_IEEEFPU_EMULATION
endmenu
mainmenu_option next_comment
comment 'General setup'
bool 'Fast IRQ handling' CONFIG_FAST_IRQ
......
......@@ -13,6 +13,15 @@ comment 'Code maturity level options'
bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
endmenu
mainmenu_option next_comment
comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool ' Set version information on all module symbols' CONFIG_MODVERSIONS
bool ' Kernel module loader' CONFIG_KMOD
fi
endmenu
mainmenu_option next_comment
comment 'Processor type and features'
choice 'SuperH system type' \
......@@ -47,15 +56,6 @@ else
fi
endmenu
mainmenu_option next_comment
comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
bool 'Kernel module loader' CONFIG_KMOD
fi
endmenu
mainmenu_option next_comment
comment 'General setup'
......
/* $Id: timod.c,v 1.8 2000/07/12 00:51:06 davem Exp $
/* $Id: timod.c,v 1.9 2000/07/12 23:21:02 davem Exp $
* timod.c: timod emulation.
*
* Copyright (C) 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
......
......@@ -11,7 +11,7 @@ O_TARGET := acpi.o
O_OBJS :=
M_OBJS :=
ACPI_OBJS := osd.o
ACPI_OBJS := driver.o ec.o cpu.o os.o sys.o tables.o
ACPI_OBJS += $(patsubst %.c,%.o,$(wildcard */*.c))
EXTRA_CFLAGS += -I./include -D_LINUX
......
/*
* cpu.c - Processor handling
*
* Copyright (C) 2000 Andrew Henroid
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/pm.h>
#include <linux/acpi.h>
#include "acpi.h"
#include "driver.h"
unsigned long acpi_c2_exit_latency = ACPI_INFINITE;
unsigned long acpi_c3_exit_latency = ACPI_INFINITE;
unsigned long acpi_c2_enter_latency = ACPI_INFINITE;
unsigned long acpi_c3_enter_latency = ACPI_INFINITE;
static unsigned long acpi_pblk = ACPI_INVALID;
static int acpi_c2_tested = 0;
static int acpi_c3_tested = 0;
/*
* Clear busmaster activity flag
*/
static inline void
acpi_clear_bm_activity(struct acpi_facp *facp)
{
acpi_write_pm1_status(facp, ACPI_BM);
}
/*
* Returns 1 if there has been busmaster activity
*/
static inline int
acpi_bm_activity(struct acpi_facp *facp)
{
return acpi_read_pm1_status(facp) & ACPI_BM;
}
/*
* Set system to sleep through busmaster requests
*/
static void
acpi_sleep_on_busmaster(struct acpi_facp *facp)
{
u32 pm1_cntr = acpi_read_pm1_control(facp);
if (pm1_cntr & ACPI_BM_RLD) {
pm1_cntr &= ~ACPI_BM_RLD;
acpi_write_pm1_control(facp, pm1_cntr);
}
}
/*
* Set system to wake on busmaster requests
*/
static void
acpi_wake_on_busmaster(struct acpi_facp *facp)
{
u32 pm1_cntr = acpi_read_pm1_control(facp);
if (!(pm1_cntr & ACPI_BM_RLD)) {
pm1_cntr |= ACPI_BM_RLD;
acpi_write_pm1_control(facp, pm1_cntr);
}
acpi_clear_bm_activity(facp);
}
/* The ACPI timer is just the low 24 bits */
#define TIME_BEGIN(tmr) inl(tmr)
#define TIME_END(tmr, begin) ((inl(tmr) - (begin)) & 0x00ffffff)
/*
* Idle loop (uniprocessor only)
*/
static void
acpi_idle(void)
{
static int sleep_level = 1;
struct acpi_facp *facp = &acpi_facp;
if (!facp
|| facp->hdr.signature != ACPI_FACP_SIG
|| !facp->pm_tmr
|| !acpi_pblk)
goto not_initialized;
/*
* start from the previous sleep level..
*/
if (sleep_level == 1)
goto sleep1;
if (sleep_level == 2)
goto sleep2;
sleep3:
sleep_level = 3;
if (!acpi_c3_tested) {
printk(KERN_DEBUG "ACPI C3 works\n");
acpi_c3_tested = 1;
}
acpi_wake_on_busmaster(facp);
if (facp->pm2_cnt)
goto sleep3_with_arbiter;
for (;;) {
unsigned long time;
unsigned int pm_tmr = facp->pm_tmr;
__cli();
if (current->need_resched)
goto out;
if (acpi_bm_activity(facp))
goto sleep2;
time = TIME_BEGIN(pm_tmr);
inb(acpi_pblk + ACPI_P_LVL3);
/* Dummy read, force synchronization with the PMU */
inl(pm_tmr);
time = TIME_END(pm_tmr, time);
__sti();
if (time < acpi_c3_exit_latency)
goto sleep2;
}
sleep3_with_arbiter:
for (;;) {
unsigned long time;
u8 arbiter;
unsigned int pm2_cntr = facp->pm2_cnt;
unsigned int pm_tmr = facp->pm_tmr;
__cli();
if (current->need_resched)
goto out;
if (acpi_bm_activity(facp))
goto sleep2;
time = TIME_BEGIN(pm_tmr);
arbiter = inb(pm2_cntr) & ~ACPI_ARB_DIS;
/* Disable arbiter, park on CPU */
outb(arbiter | ACPI_ARB_DIS, pm2_cntr);
inb(acpi_pblk + ACPI_P_LVL3);
/* Dummy read, force synchronization with the PMU */
inl(pm_tmr);
time = TIME_END(pm_tmr, time);
/* Enable arbiter again.. */
outb(arbiter, pm2_cntr);
__sti();
if (time < acpi_c3_exit_latency)
goto sleep2;
}
sleep2:
sleep_level = 2;
if (!acpi_c2_tested) {
printk(KERN_DEBUG "ACPI C2 works\n");
acpi_c2_tested = 1;
}
acpi_wake_on_busmaster(facp); /* Required to track BM activity.. */
for (;;) {
unsigned long time;
unsigned int pm_tmr = facp->pm_tmr;
__cli();
if (current->need_resched)
goto out;
time = TIME_BEGIN(pm_tmr);
inb(acpi_pblk + ACPI_P_LVL2);
/* Dummy read, force synchronization with the PMU */
inl(pm_tmr);
time = TIME_END(pm_tmr, time);
__sti();
if (time < acpi_c2_exit_latency)
goto sleep1;
if (acpi_bm_activity(facp)) {
acpi_clear_bm_activity(facp);
continue;
}
if (time > acpi_c3_enter_latency)
goto sleep3;
}
sleep1:
sleep_level = 1;
acpi_sleep_on_busmaster(facp);
for (;;) {
unsigned long time;
unsigned int pm_tmr = facp->pm_tmr;
__cli();
if (current->need_resched)
goto out;
time = TIME_BEGIN(pm_tmr);
safe_halt();
time = TIME_END(pm_tmr, time);
if (time > acpi_c2_enter_latency)
goto sleep2;
}
not_initialized:
for (;;) {
__cli();
if (current->need_resched)
goto out;
safe_halt();
}
out:
__sti();
}
/*
* Get processor information
*/
static ACPI_STATUS
acpi_find_cpu(ACPI_HANDLE handle, u32 level, void *ctx, void **value)
{
ACPI_OBJECT obj;
ACPI_CX_STATE lat[4];
ACPI_CPU_THROTTLING_STATE throttle[ACPI_MAX_THROTTLE];
ACPI_BUFFER buf;
int i, count;
buf.length = sizeof(obj);
buf.pointer = &obj;
if (!ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buf)))
return AE_OK;
printk(KERN_INFO "ACPI: PBLK %d @ 0x%04x:%d\n",
obj.processor.proc_id,
obj.processor.pblk_address,
obj.processor.pblk_length);
if (acpi_pblk != ACPI_INVALID
|| !obj.processor.pblk_address
|| obj.processor.pblk_length != 6)
return AE_OK;
acpi_pblk = obj.processor.pblk_address;
buf.length = sizeof(lat);
buf.pointer = lat;
if (!ACPI_SUCCESS(acpi_get_processor_cx_info(handle, &buf)))
return AE_OK;
if (lat[2].latency < MAX_CX_STATE_LATENCY) {
printk(KERN_INFO "ACPI: C2 supported\n");
acpi_c2_exit_latency = lat[2].latency;
}
if (lat[3].latency < MAX_CX_STATE_LATENCY) {
printk(KERN_INFO "ACPI: C3 supported\n");
acpi_c3_exit_latency = lat[3].latency;
}
memset(throttle, 0, sizeof(throttle));
buf.length = sizeof(throttle);
buf.pointer = throttle;
if (!ACPI_SUCCESS(acpi_get_processor_throttling_info(handle, &buf)))
return AE_OK;
for (i = 0, count = 0; i < ACPI_MAX_THROTTLE; i++) {
if (throttle[i].percent_of_clock)
count++;
}
count--;
if (count > 0)
printk(KERN_INFO "ACPI: %d throttling states\n", count);
return AE_OK;
}
int
acpi_cpu_init(void)
{
acpi_walk_namespace(ACPI_TYPE_PROCESSOR,
ACPI_ROOT_OBJECT,
ACPI_INT32_MAX,
acpi_find_cpu,
NULL,
NULL);
#ifdef CONFIG_SMP
if (smp_num_cpus == 1)
pm_idle = acpi_idle;
#else
pm_idle = acpi_idle;
#endif
return 0;
}
/*
* driver.c - ACPI driver
*
* Copyright (C) 2000 Andrew Henroid
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <linux/sysctl.h>
#include <linux/pm.h>
#include <linux/acpi.h>
#include <asm/uaccess.h>
#include "acpi.h"
#include "driver.h"
struct acpi_run_entry
{
void (*callback)(void*);
void *context;
struct tq_struct task;
};
static spinlock_t acpi_event_lock = SPIN_LOCK_UNLOCKED;
static volatile u32 acpi_event_status = 0;
static volatile acpi_sstate_t acpi_event_state = ACPI_S0;
static DECLARE_WAIT_QUEUE_HEAD(acpi_event_wait);
static volatile int acpi_thread_pid = -1;
static DECLARE_TASK_QUEUE(acpi_thread_run);
static DECLARE_WAIT_QUEUE_HEAD(acpi_thread_wait);
static struct ctl_table_header *acpi_sysctl = NULL;
/*
* Examine/modify value
*/
static int
acpi_do_ulong(ctl_table * ctl,
int write,
struct file *file,
void *buffer,
size_t * len)
{
char str[2 * sizeof(unsigned long) + 4], *strend;
unsigned long val;
int size;
if (!write) {
if (file->f_pos) {
*len = 0;
return 0;
}
val = *(unsigned long *) ctl->data;
size = sprintf(str, "0x%08lx\n", val);
if (*len >= size) {
copy_to_user(buffer, str, size);
*len = size;
}
else
*len = 0;
}
else {
size = sizeof(str) - 1;
if (size > *len)
size = *len;
copy_from_user(str, buffer, size);
str[size] = '\0';
val = simple_strtoul(str, &strend, 0);
if (strend == str)
return -EINVAL;
*(unsigned long *) ctl->data = val;
}
file->f_pos += *len;
return 0;
}
/*
* Handle ACPI event
*/
static u32
acpi_event(void *context)
{
unsigned long flags;
int event = (int) context;
int mask = 0;
switch (event) {
case ACPI_EVENT_POWER_BUTTON: mask = ACPI_PWRBTN; break;
case ACPI_EVENT_SLEEP_BUTTON: mask = ACPI_SLPBTN; break;
default: return AE_ERROR;
}
if (mask) {
// notify process waiting on /dev/acpi
spin_lock_irqsave(&acpi_event_lock, flags);
acpi_event_status |= mask;
spin_unlock_irqrestore(&acpi_event_lock, flags);
acpi_event_state = acpi_sleep_state;
wake_up_interruptible(&acpi_event_wait);
}
return AE_OK;
}
/*
* Wait for next event
*/
static int
acpi_do_event(ctl_table * ctl,
int write,
struct file *file,
void *buffer,
size_t * len)
{
u32 event_status = 0;
acpi_sstate_t event_state = 0;
char str[27];
int size;
if (write)
return -EPERM;
if (*len < sizeof(str)) {
*len = 0;
return 0;
}
for (;;) {
unsigned long flags;
// we need an atomic exchange here
spin_lock_irqsave(&acpi_event_lock, flags);
event_status = acpi_event_status;
acpi_event_status = 0;
spin_unlock_irqrestore(&acpi_event_lock, flags);
event_state = acpi_event_state;
if (event_status)
break;
// wait for an event to arrive
interruptible_sleep_on(&acpi_event_wait);
if (signal_pending(current))
return -ERESTARTSYS;
}
size = sprintf(str,
"0x%08x 0x%08x 0x%01x\n",
event_status,
0,
event_state);
copy_to_user(buffer, str, size);
*len = size;
file->f_pos += size;
return 0;
}
/*
* Enter system sleep state
*/
static int
acpi_do_sleep(ctl_table * ctl,
int write,
struct file *file,
void *buffer,
size_t * len)
{
if (!write) {
if (file->f_pos) {
*len = 0;
return 0;
}
}
else {
#ifdef CONFIG_ACPI_S1_SLEEP
int status = acpi_enter_sx(ACPI_S1);
if (status)
return status;
#endif
}
file->f_pos += *len;
return 0;
}
/*
* Run queued callback
*/
static void
acpi_run_exec(void *context)
{
struct acpi_run_entry *entry
= (struct acpi_run_entry*) context;
(*entry->callback)(entry->context);
kfree(entry);
}
/*
* Queue for execution by the ACPI thread
*/
int
acpi_run(void (*callback)(void*), void *context)
{
struct acpi_run_entry *entry;
entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
if (!entry)
return -1;
memset(entry, 0, sizeof(entry));
entry->callback = callback;
entry->context = context;
entry->task.routine = acpi_run_exec;
entry->task.data = entry;
queue_task(&entry->task, &acpi_thread_run);
if (waitqueue_active(&acpi_thread_wait))
wake_up(&acpi_thread_wait);
return 0;
}
static struct ctl_table acpi_table[] =
{
{ACPI_P_LVL2_LAT, "c2_exit_latency",
&acpi_c2_exit_latency, sizeof(acpi_c2_exit_latency),
0644, NULL, &acpi_do_ulong},
{ACPI_ENTER_LVL2_LAT, "c2_enter_latency",
&acpi_c2_enter_latency, sizeof(acpi_c2_enter_latency),
0644, NULL, &acpi_do_ulong},
{ACPI_P_LVL3_LAT, "c3_exit_latency",
&acpi_c3_exit_latency, sizeof(acpi_c3_exit_latency),
0644, NULL, &acpi_do_ulong},
{ACPI_ENTER_LVL3_LAT, "c3_enter_latency",
&acpi_c3_enter_latency, sizeof(acpi_c3_enter_latency),
0644, NULL, &acpi_do_ulong},
{ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &acpi_do_sleep},
{ACPI_EVENT, "event", NULL, 0, 0400, NULL, &acpi_do_event},
{0}
};
static struct ctl_table acpi_dir_table[] =
{
{CTL_ACPI, "acpi", NULL, 0, 0555, acpi_table},
{0}
};
/*
* Initialize and run interpreter within a kernel thread
*/
static int
acpi_thread(void *context)
{
/*
* initialize
*/
exit_files(current);
daemonize();
strcpy(current->comm, "acpi");
if (!ACPI_SUCCESS(acpi_initialize(NULL))) {
printk(KERN_ERR "ACPI: initialize failed\n");
return -ENODEV;
}
if (acpi_load_tables())
return -ENODEV;
if (PM_IS_ACTIVE()) {
printk(KERN_NOTICE "ACPI: APM is already active.\n");
acpi_terminate();
return -ENODEV;
}
pm_active = 1;
if (!ACPI_SUCCESS(acpi_enable())) {
printk(KERN_ERR "ACPI: enable failed\n");
acpi_terminate();
return -ENODEV;
}
acpi_cpu_init();
acpi_sys_init();
acpi_ec_init();
if (!ACPI_SUCCESS(acpi_install_fixed_event_handler(
ACPI_EVENT_POWER_BUTTON,
acpi_event,
(void *) ACPI_EVENT_POWER_BUTTON))) {
printk(KERN_ERR "ACPI: power button enable failed\n");
}
if (!ACPI_SUCCESS(acpi_install_fixed_event_handler(
ACPI_EVENT_SLEEP_BUTTON,
acpi_event,
(void *) ACPI_EVENT_SLEEP_BUTTON))) {
printk(KERN_ERR "ACPI: sleep button enable failed\n");
}
acpi_sysctl = register_sysctl_table(acpi_dir_table, 1);
/*
* run
*/
for (;;) {
interruptible_sleep_on(&acpi_thread_wait);
if (signal_pending(current))
break;
do {
run_task_queue(&acpi_thread_run);
} while (acpi_thread_run);
}
/*
* terminate
*/
unregister_sysctl_table(acpi_sysctl);
acpi_terminate();
acpi_thread_pid = -1;
return 0;
}
/*
* Start the interpreter
*/
int __init
acpi_init(void)
{
acpi_thread_pid = kernel_thread(acpi_thread,
NULL,
(CLONE_FS | CLONE_FILES
| CLONE_SIGHAND | SIGCHLD));
return ((acpi_thread_pid >= 0) ? 0:-ENODEV);
}
/*
* Terminate the interpreter
*/
void __exit
acpi_exit(void)
{
int count;
if (!kill_proc(acpi_thread_pid, SIGTERM, 1)) {
// wait until thread terminates (at most 5 seconds)
count = 5 * HZ;
while (acpi_thread_pid >= 0 && --count) {
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(1);
}
}
pm_idle = NULL;
pm_power_off = NULL;
pm_active = 0;
}
module_init(acpi_init);
module_exit(acpi_exit);
/*
* driver.h - ACPI driver
*
* Copyright (C) 2000 Andrew Henroid
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __DRIVER_H
#define __DRIVER_H
#include <linux/tqueue.h>
#include <linux/wait.h>
#include <linux/pm.h>
#include <linux/acpi.h>
#include <asm/io.h>
#define ACPI_MAX_THROTTLE 10
#define ACPI_INVALID ~0UL
#define ACPI_INFINITE ~0UL
/*
* cpu.c
*/
int acpi_cpu_init(void);
extern unsigned long acpi_c2_exit_latency;
extern unsigned long acpi_c3_exit_latency;
extern unsigned long acpi_c2_enter_latency;
extern unsigned long acpi_c3_enter_latency;
/*
* driver.c
*/
int acpi_run(void (*callback)(void*), void *context);
/*
* ec.c
*/
int acpi_ec_init(void);
int acpi_ec_read(int addr, int *value);
int acpi_ec_write(int addr, int value);
/*
* sys.c
*/
int acpi_sys_init(void);
int acpi_enter_sx(acpi_sstate_t state);
extern volatile acpi_sstate_t acpi_sleep_state;
/*
* tables.c
*/
extern struct acpi_facp acpi_facp;
int acpi_load_tables(void);
/*
* access ACPI registers
*/
extern inline u32
acpi_read_pm1_control(struct acpi_facp *facp)
{
u32 value = 0;
if (facp->pm1a_cnt)
value = inw(facp->pm1a_cnt);
if (facp->pm1b_cnt)
value |= inw(facp->pm1b_cnt);
return value;
}
extern inline void
acpi_write_pm1_control(struct acpi_facp *facp, u32 value)
{
if (facp->pm1a_cnt)
outw(value, facp->pm1a_cnt);
if (facp->pm1b_cnt)
outw(value, facp->pm1b_cnt);
}
extern inline u32
acpi_read_pm1_status(struct acpi_facp *facp)
{
u32 value = 0;
if (facp->pm1a_evt)
value = inw(facp->pm1a_evt);
if (facp->pm1b_evt)
value |= inw(facp->pm1b_evt);
return value;
}
extern inline void
acpi_write_pm1_status(struct acpi_facp *facp, u32 value)
{
if (facp->pm1a_evt)
outw(value, facp->pm1a_evt);
if (facp->pm1b_evt)
outw(value, facp->pm1b_evt);
}
#endif /* __DRIVER_H */
/*
* ec.c - Embedded controller support
*
* Copyright (C) 2000 Andrew Henroid
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/pm.h>
#include <linux/acpi.h>
#include <linux/delay.h>
#include <asm/io.h>
#include "acpi.h"
#include "driver.h"
enum
{
ACPI_EC_HID = 0x090cd041,
};
enum
{
ACPI_EC_SMI = 0x40,
ACPI_EC_SCI = 0x20,
ACPI_EC_BURST = 0x10,
ACPI_EC_CMD = 0x08,
ACPI_EC_IBF = 0x02,
ACPI_EC_OBF = 0x01
};
enum
{
ACPI_EC_READ = 0x80,
ACPI_EC_WRITE = 0x81,
ACPI_EC_BURST_ENABLE = 0x82,
ACPI_EC_BURST_DISABLE = 0x83,
ACPI_EC_QUERY = 0x84,
};
static int acpi_ec_data = 0;
static int acpi_ec_status = 0;
static DECLARE_WAIT_QUEUE_HEAD(acpi_ec_wait);
/*
* handle GPE
*/
static void
acpi_ec_gpe(void *context)
{
printk(KERN_INFO "ACPI: EC GPE\n");
if (waitqueue_active(&acpi_ec_wait))
wake_up_interruptible(&acpi_ec_wait);
}
/*
* wait for read/write status to clear
*/
static void
acpi_ec_wait_control(void)
{
udelay(1);
while(inb(acpi_ec_status) & ACPI_EC_IBF)
udelay(10);
}
/*
* read a byte from the EC
*/
int
acpi_ec_read(int addr, int *value)
{
if (!acpi_ec_data || !acpi_ec_status)
return -1;
outb(ACPI_EC_READ, acpi_ec_status);
acpi_ec_wait_control();
outb(addr, acpi_ec_data);
acpi_ec_wait_control();
interruptible_sleep_on(&acpi_ec_wait);
*value = inb(acpi_ec_data);
return 0;
}
/*
* write a byte to the EC
*/
int
acpi_ec_write(int addr, int value)
{
if (!acpi_ec_data || !acpi_ec_status)
return -1;
outb(ACPI_EC_WRITE, acpi_ec_status);
acpi_ec_wait_control();
outb(addr, acpi_ec_data);
acpi_ec_wait_control();
outb(value, acpi_ec_data);
acpi_ec_wait_control();
interruptible_sleep_on(&acpi_ec_wait);
return 0;
}
/*
* Get processor information
*/
static ACPI_STATUS
acpi_find_ec(ACPI_HANDLE handle, u32 level, void *ctx, void **value)
{
ACPI_BUFFER buf;
ACPI_OBJECT obj;
RESOURCE *res;
int gpe;
buf.length = sizeof(obj);
buf.pointer = &obj;
if (!ACPI_SUCCESS(acpi_evaluate_object(handle, "_HID", NULL, &buf))
|| obj.type != ACPI_TYPE_NUMBER
|| obj.number.value != ACPI_EC_HID)
return AE_OK;
buf.length = 0;
buf.pointer = NULL;
if (acpi_get_current_resources(handle, &buf) != AE_BUFFER_OVERFLOW)
return AE_OK;
buf.pointer = kmalloc(buf.length, GFP_KERNEL);
if (!buf.pointer)
return AE_OK;
if (!ACPI_SUCCESS(acpi_get_current_resources(handle, &buf))) {
kfree(buf.pointer);
return AE_OK;
}
res = (RESOURCE*) buf.pointer;
acpi_ec_data = (int) res->data.io.min_base_address;
res = (RESOURCE*)((u8*) buf.pointer + res->length);
acpi_ec_status = (int) res->data.io.min_base_address;
kfree(buf.pointer);
buf.length = sizeof(obj);
buf.pointer = &obj;
if (!ACPI_SUCCESS(acpi_evaluate_object(handle, "_GPE", NULL, &buf))
|| obj.type != ACPI_TYPE_NUMBER)
return AE_OK;
gpe = (int) obj.number.value;
printk(KERN_INFO "ACPI: found EC @ (0x%02x,0x%02x,%d)\n",
acpi_ec_data, acpi_ec_status, gpe);
if (!ACPI_SUCCESS(acpi_install_gpe_handler(
gpe,
(ACPI_EVENT_LEVEL_TRIGGERED
| ACPI_EVENT_EDGE_TRIGGERED),
acpi_ec_gpe,
NULL)))
return AE_OK;
return AE_OK;
}
int
acpi_ec_init(void)
{
acpi_walk_namespace(ACPI_TYPE_DEVICE,
ACPI_ROOT_OBJECT,
ACPI_INT32_MAX,
acpi_find_ec,
NULL,
NULL);
return 0;
}
/*
* os.c - OS-dependent functions
*
* Copyright (C) 2000 Andrew Henroid
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/pci.h>
#include <linux/acpi.h>
#include <asm/io.h>
#include <asm/delay.h>
#include "acpi.h"
#include "driver.h"
static int acpi_irq_irq = 0;
static OSD_HANDLER acpi_irq_handler = NULL;
static void *acpi_irq_context = NULL;
char *
strupr(char *str)
{
char *s = str;
while (*s) {
*s = TOUPPER(*s);
s++;
}
return str;
}
ACPI_STATUS
acpi_os_initialize(void)
{
return AE_OK;
}
ACPI_STATUS
acpi_os_terminate(void)
{
if (acpi_irq_handler) {
acpi_os_remove_interrupt_handler(acpi_irq_irq,
acpi_irq_handler);
}
return AE_OK;
}
s32
acpi_os_printf(const char *fmt,...)
{
s32 size;
va_list args;
va_start(args, fmt);
size = acpi_os_vprintf(fmt, args);
va_end(args);
return size;
}
s32
acpi_os_vprintf(const char *fmt, va_list args)
{
static char buffer[512];
int size = vsprintf(buffer, fmt, args);
printk(KERN_DEBUG "ACPI: %s", buffer);
return size;
}
void *
acpi_os_allocate(u32 size)
{
return kmalloc(size, GFP_KERNEL);
}
void *
acpi_os_callocate(u32 size)
{
void *ptr = acpi_os_allocate(size);
if (ptr)
memset(ptr, 0, size);
return ptr;
}
void
acpi_os_free(void *ptr)
{
kfree(ptr);
}
ACPI_STATUS
acpi_os_map_memory(void *phys, u32 size, void **virt)
{
if ((unsigned long) phys < virt_to_phys(high_memory)) {
*virt = phys_to_virt((unsigned long) phys);
return AE_OK;
}
*virt = ioremap((unsigned long) phys, size);
if (!*virt)
return AE_ERROR;
return AE_OK;
}
void
acpi_os_unmap_memory(void *virt, u32 size)
{
if (virt >= high_memory)
iounmap(virt);
}
static void
acpi_irq(int irq, void *dev_id, struct pt_regs *regs)
{
(*acpi_irq_handler)(acpi_irq_context);
}
ACPI_STATUS
acpi_os_install_interrupt_handler(u32 irq, OSD_HANDLER handler, void *context)
{
acpi_irq_irq = irq;
acpi_irq_handler = handler;
acpi_irq_context = context;
if (request_irq(irq,
acpi_irq,
SA_INTERRUPT | SA_SHIRQ,
"acpi",
acpi_irq)) {
printk(KERN_ERR "ACPI: SCI (IRQ%d) allocation failed\n", irq);
return AE_ERROR;
}
return AE_OK;
}
ACPI_STATUS
acpi_os_remove_interrupt_handler(u32 irq, OSD_HANDLER handler)
{
if (acpi_irq_handler) {
free_irq(irq, acpi_irq);
acpi_irq_handler = NULL;
}
return AE_OK;
}
/*
* Running in interpreter thread context, safe to sleep
*/
void
acpi_os_sleep(u32 sec, u32 ms)
{
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(HZ * sec + (ms * HZ) / 1000);
}
void
acpi_os_sleep_usec(u32 us)
{
udelay(us);
}
u8
acpi_os_in8(ACPI_IO_ADDRESS port)
{
return inb(port);
}
u16
acpi_os_in16(ACPI_IO_ADDRESS port)
{
return inw(port);
}
u32
acpi_os_in32(ACPI_IO_ADDRESS port)
{
return inl(port);
}
void
acpi_os_out8(ACPI_IO_ADDRESS port, u8 val)
{
outb(val, port);
}
void
acpi_os_out16(ACPI_IO_ADDRESS port, u16 val)
{
outw(val, port);
}
void
acpi_os_out32(ACPI_IO_ADDRESS port, u32 val)
{
outl(val, port);
}
ACPI_STATUS
acpi_os_read_pci_cfg_byte(
u32 bus,
u32 func,
u32 addr,
u8 * val)
{
int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff);
struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn);
if (!val || !dev || pci_read_config_byte(dev, addr, val))
return AE_ERROR;
return AE_OK;
}
ACPI_STATUS
acpi_os_read_pci_cfg_word(
u32 bus,
u32 func,
u32 addr,
u16 * val)
{
int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff);
struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn);
if (!val || !dev || pci_read_config_word(dev, addr, val))
return AE_ERROR;
return AE_OK;
}
ACPI_STATUS
acpi_os_read_pci_cfg_dword(
u32 bus,
u32 func,
u32 addr,
u32 * val)
{
int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff);
struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn);
if (!val || !dev || pci_read_config_dword(dev, addr, val))
return AE_ERROR;
return AE_OK;
}
ACPI_STATUS
acpi_os_write_pci_cfg_byte(
u32 bus,
u32 func,
u32 addr,
u8 val)
{
int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff);
struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn);
if (!dev || pci_write_config_byte(dev, addr, val))
return AE_ERROR;
return AE_OK;
}
ACPI_STATUS
acpi_os_write_pci_cfg_word(
u32 bus,
u32 func,
u32 addr,
u16 val)
{
int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff);
struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn);
if (!dev || pci_write_config_word(dev, addr, val))
return AE_ERROR;
return AE_OK;
}
ACPI_STATUS
acpi_os_write_pci_cfg_dword(
u32 bus,
u32 func,
u32 addr,
u32 val)
{
int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff);
struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn);
if (!dev || pci_write_config_dword(dev, addr, val))
return AE_ERROR;
return AE_OK;
}
/*
* Queue for interpreter thread
*/
ACPI_STATUS
acpi_os_queue_for_execution(
u32 priority,
OSD_EXECUTION_CALLBACK callback,
void *context)
{
if (acpi_run(callback, context))
return AE_ERROR;
return AE_OK;
}
/*
* Semaphores are unused, interpreter access is single threaded
*/
ACPI_STATUS
acpi_os_create_semaphore(u32 max_units, u32 init, ACPI_HANDLE * handle)
{
*handle = (ACPI_HANDLE) 0;
return AE_OK;
}
ACPI_STATUS
acpi_os_delete_semaphore(ACPI_HANDLE handle)
{
return AE_OK;
}
ACPI_STATUS
acpi_os_wait_semaphore(ACPI_HANDLE handle, u32 units, u32 timeout)
{
return AE_OK;
}
ACPI_STATUS
acpi_os_signal_semaphore(ACPI_HANDLE handle, u32 units)
{
return AE_OK;
}
ACPI_STATUS
acpi_os_breakpoint(char *msg)
{
acpi_os_printf("breakpoint: %s", msg);
return AE_OK;
}
void
acpi_os_dbg_trap(char *msg)
{
acpi_os_printf("trap: %s", msg);
}
void
acpi_os_dbg_assert(void *failure, void *file, u32 line, char *msg)
{
acpi_os_printf("assert: %s", msg);
}
u32
acpi_os_get_line(char *buffer)
{
return 0;
}
/*
* We just have to assume we're dealing with valid memory
*/
BOOLEAN
acpi_os_readable(void *ptr, u32 len)
{
return 1;
}
BOOLEAN
acpi_os_writable(void *ptr, u32 len)
{
return 1;
}
This diff is collapsed.
/*
* sys.c - System management (suspend, ...)
*
* Copyright (C) 2000 Andrew Henroid
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/pm.h>
#include <linux/acpi.h>
#include "acpi.h"
#include "driver.h"
#define ACPI_SLP_TYP(typa, typb) (((int)(typa) << 8) | (int)(typb))
#define ACPI_SLP_TYPA(value) \
((((value) >> 8) << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK)
#define ACPI_SLP_TYPB(value) \
((((value) & 0xff) << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK)
struct acpi_enter_sx_ctx
{
wait_queue_head_t wait;
int state;
};
volatile acpi_sstate_t acpi_sleep_state = ACPI_S0;
static unsigned long acpi_slptyp[ACPI_S5 + 1] = {ACPI_INVALID,};
/*
* Enter system sleep state
*/
static void
acpi_enter_sx_async(void *context)
{
struct acpi_enter_sx_ctx *ctx = (struct acpi_enter_sx_ctx*) context;
struct acpi_facp *facp = &acpi_facp;
ACPI_OBJECT_LIST arg_list;
ACPI_OBJECT arg;
u16 value;
/*
* _PSW methods could be run here to enable wake-on keyboard, LAN, etc.
*/
// run the _PTS method
memset(&arg_list, 0, sizeof(arg_list));
arg_list.count = 1;
arg_list.pointer = &arg;
memset(&arg, 0, sizeof(arg));
arg.type = ACPI_TYPE_NUMBER;
arg.number.value = ctx->state;
acpi_evaluate_object(NULL, "\\_PTS", &arg_list, NULL);
// clear wake status
acpi_write_pm1_status(facp, ACPI_WAK);
acpi_sleep_state = ctx->state;
// set ACPI_SLP_TYPA/b and ACPI_SLP_EN
__cli();
if (facp->pm1a_cnt) {
value = inw(facp->pm1a_cnt) & ~ACPI_SLP_TYP_MASK;
value |= (ACPI_SLP_TYPA(acpi_slptyp[ctx->state])
| ACPI_SLP_EN);
outw(value, facp->pm1a_cnt);
}
if (facp->pm1b_cnt) {
value = inw(facp->pm1b_cnt) & ~ACPI_SLP_TYP_MASK;
value |= (ACPI_SLP_TYPB(acpi_slptyp[ctx->state])
| ACPI_SLP_EN);
outw(value, facp->pm1b_cnt);
}
__sti();
if (ctx->state != ACPI_S1) {
printk(KERN_ERR "ACPI: S%d failed\n", ctx->state);
goto out;
}
// wait until S1 is entered
while (!(acpi_read_pm1_status(facp) & ACPI_WAK))
safe_halt();
// run the _WAK method
memset(&arg_list, 0, sizeof(arg_list));
arg_list.count = 1;
arg_list.pointer = &arg;
memset(&arg, 0, sizeof(arg));
arg.type = ACPI_TYPE_NUMBER;
arg.number.value = ctx->state;
acpi_evaluate_object(NULL, "\\_WAK", &arg_list, NULL);
out:
acpi_sleep_state = ACPI_S0;
if (waitqueue_active(&ctx->wait))
wake_up_interruptible(&ctx->wait);
}
/*
* Enter soft-off (S5)
*/
static void
acpi_power_off(void)
{
struct acpi_enter_sx_ctx ctx;
if (acpi_facp.hdr.signature != ACPI_FACP_SIG
|| acpi_slptyp[ACPI_S5] == ACPI_INVALID)
return;
init_waitqueue_head(&ctx.wait);
ctx.state = ACPI_S5;
acpi_enter_sx_async(&ctx);
}
/*
* Enter system sleep state and wait for completion
*/
int
acpi_enter_sx(acpi_sstate_t state)
{
struct acpi_enter_sx_ctx ctx;
if (acpi_facp.hdr.signature != ACPI_FACP_SIG
|| acpi_slptyp[state] == ACPI_INVALID)
return -EINVAL;
init_waitqueue_head(&ctx.wait);
ctx.state = state;
if (acpi_os_queue_for_execution(0, acpi_enter_sx_async, &ctx))
return -1;
interruptible_sleep_on(&ctx.wait);
if (signal_pending(current))
return -ERESTARTSYS;
return 0;
}
int
acpi_sys_init(void)
{
u8 sx, typa, typb;
for (sx = ACPI_S0; sx <= ACPI_S5; sx++) {
int ca_sx = (sx <= ACPI_S4) ? sx : (sx + 1);
if (ACPI_SUCCESS(
acpi_hw_obtain_sleep_type_register_data(ca_sx,
&typa,
&typb)))
acpi_slptyp[sx] = ACPI_SLP_TYP(typa, typb);
else
acpi_slptyp[sx] = ACPI_INVALID;
}
if (acpi_slptyp[ACPI_S1] != ACPI_INVALID)
printk(KERN_INFO "ACPI: S1 supported\n");
if (acpi_slptyp[ACPI_S5] != ACPI_INVALID)
printk(KERN_INFO "ACPI: S5 supported\n");
pm_power_off = acpi_power_off;
return 0;
}
/*
* tables.c - ACPI tables, chipset, and errata handling
*
* Copyright (C) 2000 Andrew Henroid
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/pm.h>
#include <linux/acpi.h>
#include "acpi.h"
#include "driver.h"
struct acpi_facp acpi_facp;
#define ACPI_DUMMY_CHECKSUM 9
#define ACPI_DUMMY_PBLK 51
static u8 acpi_dummy_dsdt[] =
{
0x44, 0x53, 0x44, 0x54, // "DSDT"
0x38, 0x00, 0x00, 0x00, // length
0x01, // revision
0x00, // checksum
0x4c, 0x49, 0x4e, 0x55, 0x58, 0x00, // "LINUX"
0x44, 0x55, 0x4d, 0x4d, 0x59, 0x00, 0x00, 0x00, // "DUMMY"
0x01, 0x00, 0x00, 0x00, // OEM rev
0x4c, 0x4e, 0x55, 0x58, // "LNUX"
0x01, 0x00, 0x00, 0x00, // creator rev
0x10, // Scope
0x13, // PkgLength
0x5c, 0x5f, 0x50, 0x52, 0x5f, // \_PR_
0x5b, 0x83, // Processor
0x0b, // PkgLength
0x43, 0x50, 0x55, 0x30, // CPU0
0x00, // ID
0x00, 0x00, 0x00, 0x00, // PBLK
0x06 // PBLK size
};
/*
* Calculate and set ACPI table checksum
*/
static void
acpi_set_checksum(u8 *table, int size)
{
int i, sum = 0;
for (i = 0; i < size; i++)
sum += (int) table[i];
sum = (0x100 - ((sum - table[ACPI_DUMMY_CHECKSUM]) & 0xff));
table[ACPI_DUMMY_CHECKSUM] = sum;
}
/*
* Init PIIX4 device, create a fake FACP
*/
static int
acpi_init_piix4(struct pci_dev *dev)
{
u32 base, pblk;
u16 cmd;
u8 pmregmisc;
pci_read_config_word(dev, PCI_COMMAND, &cmd);
if (!(cmd & PCI_COMMAND_IO))
return -ENODEV;
pci_read_config_byte(dev, ACPI_PIIX4_PMREGMISC, &pmregmisc);
if (!(pmregmisc & ACPI_PIIX4_PMIOSE))
return -ENODEV;
base = pci_resource_start (dev, PCI_BRIDGE_RESOURCES);
if (!base)
return -ENODEV;
printk(KERN_INFO "ACPI: found \"%s\" at 0x%04x\n", dev->name, base);
memset(&acpi_facp, 0, sizeof(acpi_facp));
acpi_facp.hdr.signature = ACPI_FACP_SIG;
acpi_facp.hdr.length = sizeof(acpi_facp);
acpi_facp.int_model = ACPI_PIIX4_INT_MODEL;
acpi_facp.sci_int = ACPI_PIIX4_SCI_INT;
acpi_facp.smi_cmd = ACPI_PIIX4_SMI_CMD;
acpi_facp.acpi_enable = ACPI_PIIX4_ACPI_ENABLE;
acpi_facp.acpi_disable = ACPI_PIIX4_ACPI_DISABLE;
acpi_facp.s4bios_req = ACPI_PIIX4_S4BIOS_REQ;
acpi_facp.pm1a_evt = base + ACPI_PIIX4_PM1_EVT;
acpi_facp.pm1a_cnt = base + ACPI_PIIX4_PM1_CNT;
acpi_facp.pm2_cnt = ACPI_PIIX4_PM2_CNT;
acpi_facp.pm_tmr = base + ACPI_PIIX4_PM_TMR;
acpi_facp.gpe0 = base + ACPI_PIIX4_GPE0;
acpi_facp.pm1_evt_len = ACPI_PIIX4_PM1_EVT_LEN;
acpi_facp.pm1_cnt_len = ACPI_PIIX4_PM1_CNT_LEN;
acpi_facp.pm2_cnt_len = ACPI_PIIX4_PM2_CNT_LEN;
acpi_facp.pm_tm_len = ACPI_PIIX4_PM_TM_LEN;
acpi_facp.gpe0_len = ACPI_PIIX4_GPE0_LEN;
acpi_facp.p_lvl2_lat = (__u16) ACPI_INFINITE_LAT;
acpi_facp.p_lvl3_lat = (__u16) ACPI_INFINITE_LAT;
acpi_set_checksum((u8*) &acpi_facp, sizeof(acpi_facp));
acpi_load_table((ACPI_TABLE_HEADER*) &acpi_facp);
pblk = base + ACPI_PIIX4_P_BLK;
memcpy(acpi_dummy_dsdt + ACPI_DUMMY_PBLK, &pblk, sizeof(pblk));
acpi_set_checksum(acpi_dummy_dsdt, sizeof(acpi_dummy_dsdt));
acpi_load_table((ACPI_TABLE_HEADER*) acpi_dummy_dsdt);
return 0;
}
/*
* Init VIA ACPI device and create a fake FACP
*/
static int
acpi_init_via(struct pci_dev *dev)
{
u32 base, pblk;
u8 tmp, irq;
pci_read_config_byte(dev, 0x41, &tmp);
if (!(tmp & 0x80))
return -ENODEV;
base = pci_resource_start(dev, PCI_BRIDGE_RESOURCES);
if (!base) {
base = pci_resource_start(dev, PCI_BASE_ADDRESS_4);
if (!base)
return -ENODEV;
}
pci_read_config_byte(dev, 0x42, &irq);
printk(KERN_INFO "ACPI: found \"%s\" at 0x%04x\n", dev->name, base);
memset(&acpi_facp, 0, sizeof(acpi_facp));
acpi_facp.hdr.signature = ACPI_FACP_SIG;
acpi_facp.hdr.length = sizeof(acpi_facp);
acpi_facp.int_model = ACPI_VIA_INT_MODEL;
acpi_facp.sci_int = irq;
acpi_facp.smi_cmd = base + ACPI_VIA_SMI_CMD;
acpi_facp.acpi_enable = ACPI_VIA_ACPI_ENABLE;
acpi_facp.acpi_disable = ACPI_VIA_ACPI_DISABLE;
acpi_facp.pm1a_evt = base + ACPI_VIA_PM1_EVT;
acpi_facp.pm1a_cnt = base + ACPI_VIA_PM1_CNT;
acpi_facp.pm_tmr = base + ACPI_VIA_PM_TMR;
acpi_facp.gpe0 = base + ACPI_VIA_GPE0;
acpi_facp.pm1_evt_len = ACPI_VIA_PM1_EVT_LEN;
acpi_facp.pm1_cnt_len = ACPI_VIA_PM1_CNT_LEN;
acpi_facp.pm_tm_len = ACPI_VIA_PM_TM_LEN;
acpi_facp.gpe0_len = ACPI_VIA_GPE0_LEN;
acpi_facp.p_lvl2_lat = (__u16) ACPI_INFINITE_LAT;
acpi_facp.p_lvl3_lat = (__u16) ACPI_INFINITE_LAT;
acpi_facp.duty_offset = ACPI_VIA_DUTY_OFFSET;
acpi_facp.duty_width = ACPI_VIA_DUTY_WIDTH;
acpi_facp.day_alarm = ACPI_VIA_DAY_ALARM;
acpi_facp.mon_alarm = ACPI_VIA_MON_ALARM;
acpi_facp.century = ACPI_VIA_CENTURY;
acpi_set_checksum((u8*) &acpi_facp, sizeof(acpi_facp));
acpi_load_table((ACPI_TABLE_HEADER*) &acpi_facp);
pblk = base + ACPI_VIA_P_BLK;
memcpy(acpi_dummy_dsdt + ACPI_DUMMY_PBLK, &pblk, sizeof(pblk));
acpi_set_checksum(acpi_dummy_dsdt, sizeof(acpi_dummy_dsdt));
acpi_load_table((ACPI_TABLE_HEADER*) acpi_dummy_dsdt);
return 0;
}
typedef enum
{
CH_UNKNOWN = 0,
CH_INTEL_PIIX4,
CH_VIA_586,
CH_VIA_686A,
} acpi_chip_t;
/* indexed by value of each enum in acpi_chip_t */
const static struct
{
int (*chip_init)(struct pci_dev *dev);
} acpi_chip_info[] =
{
{NULL,},
{acpi_init_piix4},
{acpi_init_via},
{acpi_init_via},
};
static struct pci_device_id acpi_pci_tbl[] =
{
{0x8086, 0x7113, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_INTEL_PIIX4},
{0x1106, 0x3040, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VIA_586},
{0x1106, 0x3057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VIA_686A},
{0,} /* terminate list */
};
static int
acpi_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
return acpi_chip_info[id->driver_data].chip_init(dev);
}
static struct pci_driver acpi_driver =
{
name: "acpi",
id_table: acpi_pci_tbl,
probe: acpi_probe,
};
static int acpi_driver_registered = 0;
/*
* Locate a known ACPI chipset
*/
static int
acpi_find_chipset(void)
{
if (pci_register_driver(&acpi_driver) < 1)
return -ENODEV;
acpi_driver_registered = 1;
return 0;
}
/*
* Fetch the FACP information
*/
static int
acpi_fetch_facp(void)
{
ACPI_BUFFER buffer;
memset(&acpi_facp, 0, sizeof(acpi_facp));
buffer.pointer = &acpi_facp;
buffer.length = sizeof(acpi_facp);
if (!ACPI_SUCCESS(acpi_get_table(ACPI_TABLE_FACP, 1, &buffer))) {
printk(KERN_ERR "ACPI: missing FACP\n");
return -ENODEV;
}
if (acpi_facp.p_lvl2_lat
&& acpi_facp.p_lvl2_lat <= ACPI_MAX_P_LVL2_LAT) {
acpi_c2_exit_latency
= ACPI_uS_TO_TMR_TICKS(acpi_facp.p_lvl2_lat);
acpi_c2_enter_latency
= ACPI_uS_TO_TMR_TICKS(ACPI_TMR_HZ / 1000);
}
if (acpi_facp.p_lvl3_lat
&& acpi_facp.p_lvl3_lat <= ACPI_MAX_P_LVL3_LAT) {
acpi_c3_exit_latency
= ACPI_uS_TO_TMR_TICKS(acpi_facp.p_lvl3_lat);
acpi_c3_enter_latency
= ACPI_uS_TO_TMR_TICKS(acpi_facp.p_lvl3_lat * 5);
}
return 0;
}
/*
* Find and load ACPI tables
*/
int
acpi_load_tables(void)
{
if (ACPI_SUCCESS(acpi_load_firmware_tables()))
{
printk(KERN_INFO "ACPI: support found\n");
}
else if (acpi_find_chipset()) {
acpi_terminate();
return -1;
}
if (acpi_fetch_facp()) {
acpi_terminate();
return -1;
}
if (!ACPI_SUCCESS(acpi_load_namespace())) {
printk(KERN_ERR "ACPI: namespace load failed\n");
acpi_terminate();
return -1;
}
return 0;
}
......@@ -792,8 +792,7 @@ int generic_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
device. Currently the only restriction is that all buffers must belong to
the same device */
static void __ll_rw_block(int rw, int nr, struct buffer_head * bhs[],
int haslock)
void ll_rw_block(int rw, int nr, struct buffer_head * bhs[])
{
struct buffer_head *bh;
request_queue_t *q;
......@@ -840,13 +839,9 @@ static void __ll_rw_block(int rw, int nr, struct buffer_head * bhs[],
bh = bhs[i];
/* Only one thread can actually submit the I/O. */
if (haslock) {
if (!buffer_locked(bh))
BUG();
} else {
if (test_and_set_bit(BH_Lock, &bh->b_state))
continue;
}
set_bit(BH_Req, &bh->b_state);
/*
......@@ -865,15 +860,6 @@ static void __ll_rw_block(int rw, int nr, struct buffer_head * bhs[],
buffer_IO_error(bhs[i]);
}
void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
{
__ll_rw_block(rw, nr, bh, 0);
}
void ll_rw_block_locked(int rw, int nr, struct buffer_head * bh[])
{
__ll_rw_block(rw, nr, bh, 1);
}
#ifdef CONFIG_STRAM_SWAP
extern int stram_device_init (void);
......
......@@ -3412,7 +3412,7 @@ int md_do_sync(mddev_t *mddev, mdp_disk_t *spare)
currspeed = (j-mddev->resync_mark_cnt)/((jiffies-mddev->resync_mark)/HZ +1) +1;
if (currspeed > sysctl_speed_limit_min) {
current->priority = 19;
current->nice = 19;
if ((currspeed > sysctl_speed_limit_max) ||
!is_mddev_idle(mddev)) {
......@@ -3422,7 +3422,7 @@ int md_do_sync(mddev_t *mddev, mdp_disk_t *spare)
goto repeat;
}
} else
current->priority = -20;
current->nice = -20;
}
fsync_dev(read_disk);
printk(KERN_INFO "md: md%d: sync done.\n",mdidx(mddev));
......
......@@ -13,10 +13,11 @@
1.02 GRG 1998.05.05 init_proto, release_proto, ktti
1.03 GRG 1998.08.15 eliminate compiler warning
1.04 GRG 1998.11.28 added support for FRIQ
1.05 TMW 2000.06.06 use parport_find_number instead of
parport_enumerate
*/
#define PI_VERSION "1.04"
#define PI_VERSION "1.05"
#include <linux/module.h>
#include <linux/config.h>
......@@ -238,22 +239,25 @@ static void pi_register_parport( PIA *pi, int verbose)
{
#ifdef CONFIG_PARPORT
struct parport *pp;
pp = parport_enumerate();
struct parport *port;
while((pp)&&(pp->base != pi->port)) pp = pp->next;
port = parport_find_base (pi->port);
if (!port) return;
if (!pp) return;
pi->pardev = parport_register_device(port,
pi->device,NULL,
pi_wake_up,NULL,
0,(void *)pi);
parport_put_port (port);
if (!pi->pardev) return;
pi->pardev = (void *) parport_register_device(
pp,pi->device,NULL,pi_wake_up,NULL,0,(void *)pi);
init_waitqueue_head(&pi->parq);
if (verbose) printk("%s: 0x%x is %s\n",pi->device,pi->port,pp->name);
if (verbose) printk("%s: 0x%x is %s\n",pi->device,pi->port,
port->name);
pi->parname = (char *)pp->name;
pi->parname = (char *)port->name;
#endif
}
......@@ -406,6 +410,7 @@ int init_module(void)
{ int k;
for (k=0;k<MAX_PROTOS;k++) protocols[k] = 0;
printk("paride: version %s installed\n",PI_VERSION);
return 0;
}
......
......@@ -2,7 +2,7 @@
#define Z_WAKE
#undef Z_EXT_CHARS_IN_BUFFER
static char rcsid[] =
"$Revision: 2.3.2.7 $$Date: 2000/06/01 18:26:34 $";
"$Revision: 2.3.2.8 $$Date: 2000/07/06 18:14:16 $";
/*
* linux/drivers/char/cyclades.c
......@@ -25,6 +25,11 @@ static char rcsid[] =
* This version supports shared IRQ's (only for PCI boards).
*
* $Log: cyclades.c,v $
* Revision 2.3.2.8 2000/07/06 18:14:16 ivan
* Fixed the PCI detection function to work properly on Alpha systems.
* Implemented support for TIOCSERGETLSR ioctl.
* Implemented full support for non-standard baud rates.
*
* Revision 2.3.2.7 2000/06/01 18:26:34 ivan
* Request PLX I/O region, although driver doesn't use it, to avoid
* problems with other drivers accessing it.
......@@ -1363,9 +1368,16 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
while (char_count-- > 0){
if (!info->xmit_cnt){
if (cy_readb(base_addr+(CySRER<<index))&CyTxMpty) {
cy_writeb((u_long)base_addr+(CySRER<<index),
cy_readb(base_addr+(CySRER<<index)) &
~CyTxRdy);
~CyTxMpty);
} else {
cy_writeb((u_long)base_addr+(CySRER<<index),
((cy_readb(base_addr+(CySRER<<index))
& ~CyTxRdy)
| CyTxMpty));
}
goto txdone;
}
if (info->xmit_buf == 0){
......@@ -3176,6 +3188,30 @@ cy_chars_in_buffer(struct tty_struct *tty)
* ------------------------------------------------------------
*/
static void
cyy_baud_calc(struct cyclades_port *info, uclong baud)
{
int co, co_val, bpr;
uclong cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 : 25000000);
if (baud == 0) {
info->tbpr = info->tco = info->rbpr = info->rco = 0;
return;
}
/* determine which prescaler to use */
for (co = 4, co_val = 2048; co; co--, co_val >>= 2) {
if (cy_clock / co_val / baud > 63)
break;
}
bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
if (bpr > 255)
bpr = 255;
info->tbpr = info->rbpr = bpr;
info->tco = info->rco = co;
}
/*
* This routine finds or computes the various line characteristics.
......@@ -3189,7 +3225,7 @@ set_line_char(struct cyclades_port * info)
int card,chip,channel,index;
unsigned cflag, iflag;
unsigned short chip_number;
int baud;
int baud, baud_rate = 0;
int i;
......@@ -3225,12 +3261,14 @@ set_line_char(struct cyclades_port * info)
index = cy_card[card].bus_index;
/* baud rate */
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) {
baud = info->baud;
} else {
baud = tty_get_baud_rate(info->tty);
}
if (baud > CD1400_MAX_SPEED) {
if ((baud == 38400) &&
((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) {
if (info->custom_divisor)
baud_rate = info->baud / info->custom_divisor;
else
baud_rate = info->baud;
} else if (baud > CD1400_MAX_SPEED) {
baud = CD1400_MAX_SPEED;
}
/* find the baud index */
......@@ -3243,7 +3281,10 @@ set_line_char(struct cyclades_port * info)
i = 19; /* CD1400_MAX_SPEED */
}
if ((baud == 38400) &&
((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) {
cyy_baud_calc(info, baud_rate);
} else {
if(info->chip_rev >= CD1400_REV_J) {
/* It is a CD1400 rev. J or later */
info->tbpr = baud_bpr_60[i]; /* Tx BPR */
......@@ -3256,9 +3297,13 @@ set_line_char(struct cyclades_port * info)
info->rbpr = baud_bpr_25[i]; /* Rx BPR */
info->rco = baud_co_25[i]; /* Rx CO */
}
}
if (baud_table[i] == 134) {
info->timeout = (info->xmit_fifo_size*HZ*15/269) + 2;
/* get it right for 134.5 baud */
info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
} else if ((baud == 38400) &&
((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) {
info->timeout = (info->xmit_fifo_size*HZ*15/baud_rate) + 2;
} else if (baud_table[i]) {
info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2;
/* this needs to be propagated into the card info */
......@@ -3447,19 +3492,24 @@ set_line_char(struct cyclades_port * info)
buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
/* baud rate */
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) {
baud = info->baud;
} else {
baud = tty_get_baud_rate(info->tty);
}
if (baud > CYZ_MAX_SPEED) {
if ((baud == 38400) &&
((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) {
if (info->custom_divisor)
baud_rate = info->baud / info->custom_divisor;
else
baud_rate = info->baud;
} else if (baud > CYZ_MAX_SPEED) {
baud = CYZ_MAX_SPEED;
}
cy_writel(&ch_ctrl->comm_baud , baud);
if (baud == 134) {
info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
/* get it right for 134.5 baud */
info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
} else if ((baud == 38400) &&
((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) {
info->timeout = (info->xmit_fifo_size*HZ*15/baud_rate) + 2;
} else if (baud) {
info->timeout = (info->xmit_fifo_size*HZ*15/baud) + 2;
/* this needs to be propagated into the card info */
......@@ -3549,8 +3599,6 @@ set_line_char(struct cyclades_port * info)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
}
}
} /* set_line_char */
......@@ -3571,7 +3619,7 @@ get_serial_info(struct cyclades_port * info,
tmp.flags = info->flags;
tmp.close_delay = info->close_delay;
tmp.baud_base = info->baud;
tmp.custom_divisor = 0; /*!!!*/
tmp.custom_divisor = info->custom_divisor;
tmp.hub6 = 0; /*!!!*/
return copy_to_user(retinfo,&tmp,sizeof(*retinfo))?-EFAULT:0;
} /* get_serial_info */
......@@ -3597,6 +3645,7 @@ set_serial_info(struct cyclades_port * info,
info->flags = ((info->flags & ~ASYNC_USR_MASK) |
(new_serial.flags & ASYNC_USR_MASK));
info->baud = new_serial.baud_base;
info->custom_divisor = new_serial.custom_divisor;
goto check_and_exit;
}
......@@ -3607,6 +3656,7 @@ set_serial_info(struct cyclades_port * info,
*/
info->baud = new_serial.baud_base;
info->custom_divisor = new_serial.custom_divisor;
info->flags = ((info->flags & ~ASYNC_FLAGS) |
(new_serial.flags & ASYNC_FLAGS));
info->close_delay = new_serial.close_delay * HZ/100;
......@@ -3621,6 +3671,43 @@ set_serial_info(struct cyclades_port * info,
}
} /* set_serial_info */
/*
* get_lsr_info - get line status register info
*
* Purpose: Let user call ioctl() to get info when the UART physically
* is emptied. On bus types like RS485, the transmitter must
* release the bus after transmitting. This must be done when
* the transmit shift register is empty, not be done when the
* transmit holding register is empty. This functionality
* allows an RS485 driver to be written in user space.
*/
static int get_lsr_info(struct cyclades_port *info, unsigned int *value)
{
int card, chip, channel, index;
unsigned char status;
unsigned int result;
unsigned long flags;
unsigned char *base_addr;
card = info->card;
channel = (info->line) - (cy_card[card].first_line);
if (!IS_CYC_Z(cy_card[card])) {
chip = channel>>2;
channel &= 0x03;
index = cy_card[card].bus_index;
base_addr = (unsigned char *)
(cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
CY_LOCK(info, flags);
status = cy_readb(base_addr+(CySRER<<index)) & (CyTxRdy|CyTxMpty);
CY_UNLOCK(info, flags);
result = (status ? 0 : TIOCSER_TEMT);
} else {
/* Not supported yet */
return -EINVAL;
}
return cy_put_user(result, (unsigned long *) value);
}
static int
get_modem_info(struct cyclades_port * info, unsigned int *value)
......@@ -4247,6 +4334,9 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
case TIOCSSERIAL:
ret_val = set_serial_info(info, (struct serial_struct *) arg);
break;
case TIOCSERGETLSR: /* Get line status register */
ret_val = get_lsr_info(info, (unsigned int *) arg);
break;
/*
* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
* - mask passed in arg for lines of interest
......@@ -4937,10 +5027,9 @@ cy_detect_pci(void)
i--;
continue;
}
#else
#endif
cy_pci_addr0 = (ulong)ioremap(cy_pci_phys0, CyPCI_Yctl);
cy_pci_addr2 = (ulong)ioremap(cy_pci_phys2, CyPCI_Ywin);
#endif
#ifdef CY_PCI_DEBUG
printk("Cyclom-Y/PCI: relocate winaddr=0x%lx ctladdr=0x%lx\n",
......@@ -5048,9 +5137,7 @@ cy_detect_pci(void)
printk("Cyclades-Z/PCI: found winaddr=0x%lx ctladdr=0x%lx\n",
(ulong)cy_pci_phys2, (ulong)cy_pci_phys0);
#endif
#if !defined(__alpha__)
cy_pci_addr0 = (ulong)ioremap(cy_pci_phys0, CyPCI_Zctl);
#endif
/* Disable interrupts on the PLX before resetting it */
cy_writew(cy_pci_addr0+0x68,
......@@ -5078,9 +5165,7 @@ cy_detect_pci(void)
request_region(cy_pci_phys1, CyPCI_Zctl, "Cyclades-Z");
if (mailbox == ZE_V1) {
#if !defined(__alpha__)
cy_pci_addr2 = (ulong)ioremap(cy_pci_phys2, CyPCI_Ze_win);
#endif
if (ZeIndex == NR_CARDS) {
printk("Cyclades-Ze/PCI found at 0x%lx ",
(ulong)cy_pci_phys2);
......@@ -5097,9 +5182,7 @@ cy_detect_pci(void)
i--;
continue;
} else {
#if !defined(__alpha__)
cy_pci_addr2 = (ulong)ioremap(cy_pci_phys2, CyPCI_Zwin);
#endif
}
#ifdef CY_PCI_DEBUG
......@@ -5538,6 +5621,7 @@ cy_init(void)
info->tco = 0;
info->rbpr = 0;
info->rco = 0;
info->custom_divisor = 0;
info->close_delay = 5*HZ/10;
info->closing_wait = CLOSING_WAIT_DELAY;
info->icount.cts = info->icount.dsr =
......@@ -5596,6 +5680,7 @@ cy_init(void)
info->cor3 = 0x08; /* _very_ small rcv threshold */
info->cor4 = 0;
info->cor5 = 0;
info->custom_divisor = 0;
info->close_delay = 5*HZ/10;
info->closing_wait = CLOSING_WAIT_DELAY;
info->icount.cts = info->icount.dsr =
......
......@@ -75,7 +75,7 @@ static void i2c_parport_attach(struct parport *port)
struct parport_i2c_bus *b = kmalloc(sizeof(struct parport_i2c_bus),
GFP_KERNEL);
b->i2c = parport_i2c_bus_template;
b->i2c.data = port;
b->i2c.data = parport_get_port (port);
strncpy(b->i2c.name, port->name, 32);
spin_lock(&bus_list_lock);
b->next = bus_list;
......
......@@ -83,64 +83,6 @@ struct pp_struct {
/* ROUND_UP macro from fs/select.c */
#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
struct pp_port_list_struct {
struct parport *port;
struct pp_port_list_struct *next;
};
static struct pp_port_list_struct *pp_port_list;
static DECLARE_MUTEX(pp_port_list_lock);
/* pp_attach and pp_detach are for keeping a list of currently
* available ports, held under a mutex. We do this rather than
* using parport_enumerate because it stops a load of races.
*/
static void pp_attach (struct parport *port)
{
struct pp_port_list_struct *add;
add = kmalloc (sizeof (struct pp_port_list_struct), GFP_KERNEL);
if (!add) {
printk (KERN_WARNING CHRDEV ": memory squeeze\n");
return;
}
add->port = port;
down (&pp_port_list_lock);
add->next = pp_port_list;
pp_port_list = add;
up (&pp_port_list_lock);
}
static void pp_detach (struct parport *port)
{
struct pp_port_list_struct *del;
down (&pp_port_list_lock);
del = pp_port_list;
if (del->port == port)
pp_port_list = del->next;
else {
struct pp_port_list_struct *prev;
do {
prev = del;
del = del->next;
} while (del && del->port != port);
if (del)
prev->next = del->next;
}
up (&pp_port_list_lock);
if (del)
kfree (del);
}
static struct parport_driver ppdev_driver = {
name: CHRDEV,
attach: pp_attach,
detach: pp_detach
};
static inline void pp_enable_irq (struct pp_struct *pp)
{
struct parport *port = pp->pdev->port;
......@@ -274,7 +216,7 @@ static void pp_irq (int irq, void * private, struct pt_regs * unused)
static int register_device (int minor, struct pp_struct *pp)
{
struct pp_port_list_struct *ports;
struct parport *port;
struct pardevice * pdev = NULL;
char *name;
int fl;
......@@ -285,23 +227,17 @@ static int register_device (int minor, struct pp_struct *pp)
sprintf (name, CHRDEV "%x", minor);
down (&pp_port_list_lock);
ports = pp_port_list;
while (ports && ports->port->number != minor)
ports = ports->next;
if (ports->port) {
fl = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0;
pdev = parport_register_device (ports->port, name, NULL,
NULL, pp_irq, fl, pp);
}
up (&pp_port_list_lock);
if (!ports->port) {
port = parport_find_number (minor);
if (!port) {
printk (KERN_WARNING "%s: no associated port!\n", name);
kfree (name);
return -ENXIO;
}
fl = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0;
pdev = parport_register_device (port, name, NULL,
NULL, pp_irq, fl, pp);
parport_put_port (port);
if (!pdev) {
printk (KERN_WARNING "%s: failed to register device!\n", name);
......@@ -654,10 +590,6 @@ static devfs_handle_t devfs_handle = NULL;
static int __init ppdev_init (void)
{
if (parport_register_driver (&ppdev_driver)) {
printk (KERN_WARNING CHRDEV ": unable to register driver\n");
return -EIO;
}
if (devfs_register_chrdev (PP_MAJOR, CHRDEV, &pp_fops)) {
printk (KERN_WARNING CHRDEV ": unable to get major %d\n",
PP_MAJOR);
......@@ -678,7 +610,6 @@ static void __exit ppdev_cleanup (void)
/* Clean up all parport stuff */
devfs_unregister (devfs_handle);
devfs_unregister_chrdev (PP_MAJOR, CHRDEV);
parport_unregister_driver (&ppdev_driver);
}
module_init(ppdev_init);
......
# $Id: Config.in,v 1.18 2000/07/12 13:43:24 dwmw2 Exp $
mainmenu_option next_comment
comment 'Memory Technology Devices (MTD)'
tristate 'Memory Technology Device (MTD) support' CONFIG_MTD
if [ "$CONFIG_MTD" != "n" ]; then
dep_tristate 'M-Systems Disk-On-Chip 1000 support' CONFIG_MTD_DOC1000 $CONFIG_MTD
dep_tristate 'M-Systems Disk-On-Chip 2000' CONFIG_MTD_DOC2000 $CONFIG_MTD
dep_tristate 'M-Systems Disk-On-Chip Millennium' CONFIG_MTD_DOC2001 $CONFIG_MTD
dep_tristate ' M-Systems Disk-On-Chip 1000 support' CONFIG_MTD_DOC1000 $CONFIG_MTD
dep_tristate ' M-Systems Disk-On-Chip 2000' CONFIG_MTD_DOC2000 $CONFIG_MTD
dep_tristate ' M-Systems Disk-On-Chip Millennium' CONFIG_MTD_DOC2001 $CONFIG_MTD
if [ "$CONFIG_MTD_DOC2001" = "y" -o "$CONFIG_MTD_DOC2000" = "y" ]; then
define_bool CONFIG_MTD_DOCPROBE y
define_tristate CONFIG_MTD_DOCPROBE y
else
if [ "$CONFIG_MTD_DOC2001" = "m" -o "$CONFIG_MTD_DOC2000" = "m" ]; then
define_bool CONFIG_MTD_DOCPROBE m
define_tristate CONFIG_MTD_DOCPROBE m
else
define_bool CONFIG_MTD_DOCPROBE n
define_tristate CONFIG_MTD_DOCPROBE n
fi
fi
dep_tristate 'Use extra onboard system memory as MTD device' CONFIG_MTD_SLRAM $CONFIG_MTD
dep_tristate 'Ramix PMC551 PCI Mezzanine ram card support' CONFIG_MTD_PMC551 $CONFIG_MTD
dep_tristate ' Use extra onboard system memory as MTD device' CONFIG_MTD_SLRAM $CONFIG_MTD
dep_tristate ' Ramix PMC551 PCI Mezzanine ram card support' CONFIG_MTD_PMC551 $CONFIG_MTD
if [ "$CONFIG_MTD_PMC551" != "n" ]; then
bool 'PMC551 256M DRAM Bugfix' CONFIG_MTD_PMC551_BUGFIX
bool ' PMC551 256M DRAM Bugfix' CONFIG_MTD_PMC551_BUGFIX
fi
dep_tristate 'Debugging RAM test driver' CONFIG_MTD_MTDRAM $CONFIG_MTD
dep_tristate ' Debugging RAM test driver' CONFIG_MTD_MTDRAM $CONFIG_MTD
mainmenu_option next_comment
comment 'MTD drivers for mapped chips'
dep_tristate ' Common Flash Interface (CFI) support' CONFIG_MTD_CFI $CONFIG_MTD
dep_tristate ' CFI support for Intel/Sharp Extended Command Set chips' CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_CFI
dep_tristate 'Common Flash Interface (CFI) support' CONFIG_MTD_CFI $CONFIG_MTD
dep_tristate 'CFI support for Intel/Sharp Extended Command Set chips' CONFIG_MTD_CFI_INTELEXT $CONFIG_CFI
define_bool CONFIG_MTD_JEDEC n
define_bool CONFIG_MTD_RAM n
define_bool CONFIG_MTD_ROM n
mainmenu_option next_comment
comment 'Drivers for chip mappings'
# These will later become config-options
define_bool CONFIG_MTD_JEDEC n
define_bool CONFIG_MTD_RAM n
define_bool CONFIG_MTD_ROM n
dep_tristate 'Flash chip mapping in physical memory' CONFIG_MTD_PHYSMAP $CONFIG_MTD_CFI
dep_tristate ' Flash chip mapping in physical memory' CONFIG_MTD_PHYSMAP $CONFIG_MTD_CFI
if [ "$CONFIG_MTD_PHYSMAP" != "n" ]; then
hex ' Physical start location of flash chip mapping (0x8000000)' CONFIG_MTD_PHYSMAP_START 0x8000000
hex ' Physical length of flash chip mapping (0x4000000)' CONFIG_MTD_PHYSMAP_LEN 0x4000000
hex 'Physical start location of flash chip mapping' CONFIG_MTD_PHYSMAP_START 0x8000000
hex 'Physical length of flash chip mapping' CONFIG_MTD_PHYSMAP_LEN 0x4000000
fi
dep_tristate 'Flash chip mapping on Mixcom piggyback card' CONFIG_MTD_MIXMEM $CONFIG_MTD_JEDEC
dep_tristate 'Flash chip mapping on Nora' CONFIG_MTD_NORA $CONFIG_MTD_CFI
dep_tristate 'Flash chip mapping on Octagon 5066 SBC' CONFIG_MTD_OCTAGON $CONFIG_MTD_JEDEC
dep_tristate 'Flash chip mapping on RPXLite PPC board' CONFIG_MTD_RPXLITE $CONFIG_MTD_CFI
dep_tristate 'Flash chip mapping on Tempustech VMAX SBC301' CONFIG_MTD_VMAX $CONFIG_MTD_JEDEC
mainmenu_option next_comment
comment 'Drivers for chip mappings'
dep_tristate ' Flash chip mapping on Mixcom piggyback card' CONFIG_MTD_MIXMEM $CONFIG_MTD_JEDEC
dep_tristate ' Flash chip mapping on Nora' CONFIG_MTD_NORA $CONFIG_MTD_CFI
dep_tristate ' Flash chip mapping on Octagon 5066 SBC' CONFIG_MTD_OCTAGON $CONFIG_MTD_JEDEC
dep_tristate ' Flash chip mapping on RPXLite PPC board' CONFIG_MTD_RPXLITE $CONFIG_MTD_CFI
dep_tristate ' Flash chip mapping on Tempustech VMAX SBC301' CONFIG_MTD_VMAX $CONFIG_MTD_JEDEC
comment 'User modules and translation layers for MTD devices'
dep_tristate 'Direct chardevice access to MTD devices' CONFIG_MTD_CHAR $CONFIG_MTD
dep_tristate 'Pseudo-blockdevice access to MTD devices' CONFIG_MTD_BLOCK $CONFIG_MTD
dep_tristate 'FTL (Flash Translation Layer) support' CONFIG_FTL $CONFIG_MTD
dep_tristate 'NFTL (NAND Flash Translation Layer) support' CONFIG_NFTL $CONFIG_MTD
dep_tristate ' Direct chardevice access to MTD devices' CONFIG_MTD_CHAR $CONFIG_MTD
dep_tristate ' Pseudo-blockdevice access to MTD devices' CONFIG_MTD_BLOCK $CONFIG_MTD
dep_tristate ' FTL (Flash Translation Layer) support' CONFIG_FTL $CONFIG_MTD
dep_tristate ' NFTL (NAND Flash Translation Layer) support' CONFIG_NFTL $CONFIG_MTD
if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_NFTL" != "n" ]; then
bool 'Write support for NFTL (EXPERIMENTAL)' CONFIG_NFTL_RW
bool ' Write support for NFTL (EXPERIMENTAL)' CONFIG_NFTL_RW
fi
fi
......
2000-06-30 Gunther Mayer <gunther.mayer@braunschweig.okersurf.de>
2000-07-12 Tim Waugh <twaugh@redhat.com>
* share.c: Documentation for parport_{get,port}_port,
parport_find_{number,base}.
2000-07-12 Tim Waugh <twaugh@redhat.com>
* share.c (parport_unregister_device): Remove unneeded locking
(test cad==dev).
(parport_claim): Likewise.
(parport_find_number): New function.
2000-07-12 Tim Waugh <twaugh@redhat.com>
* share.c (parport_register_port): Hold the parportlist_lock while
looking for a free parport number.
(parport_register_driver): Make sure that attach can block.
(attach_driver_chain): Likewise.
2000-07-12 Tim Waugh <twaugh@redhat.com>
* share.c (call_driver_chain): Do reference counting things.
(parport_get_port): New function.
(parport_put_port): New function.
(parport_register_port): Initialise reference count to zero.
(parport_unregister_port): Check reference count rather than
driver list to see if we can free the port.
2000-07-12 Tim Waugh <twaugh@redhat.com>
* share.c: Clarifications in doc comments.
2000-07-12 Tim Waugh <twaugh@redhat.com>
* share.c (parport_unregister_port): Fix typo in comment.
2000-07-11 Gunther Mayer <gunther.mayer@braunschweig.okersurf.de>
* parport_pc.c: Support for the full range of Timedia cards.
......
......@@ -180,6 +180,10 @@ EXPORT_SYMBOL(parport_unregister_driver);
EXPORT_SYMBOL(parport_register_device);
EXPORT_SYMBOL(parport_unregister_device);
EXPORT_SYMBOL(parport_enumerate);
EXPORT_SYMBOL(parport_get_port);
EXPORT_SYMBOL(parport_put_port);
EXPORT_SYMBOL(parport_find_number);
EXPORT_SYMBOL(parport_find_base);
EXPORT_SYMBOL(parport_negotiate);
EXPORT_SYMBOL(parport_write);
EXPORT_SYMBOL(parport_read);
......
This diff is collapsed.
......@@ -138,6 +138,10 @@ static struct dev_info device_list[] =
{"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN},
{"TOSHIBA","CDROM","*", BLIST_ISROM},
{"MegaRAID", "LD", "*", BLIST_FORCELUN},
{"DGC", "RAID", "*", BLIST_SPARSELUN}, // Dell PV 650F (tgt @ LUN 0)
{"DGC", "DISK", "*", BLIST_SPARSELUN}, // Dell PV 650F (no tgt @ LUN 0)
{"DELL", "PV530F", "*", BLIST_SPARSELUN}, // Dell PV 530F
{"SONY", "TSL", "*", BLIST_FORCELUN}, // DDS3 & DDS4 autoloaders
/*
* Must be at end of list...
......
......@@ -45,6 +45,9 @@
* up an eventual usbd
* 2000-01-04: Thomas Sailer <sailer@ife.ee.ethz.ch>
* Turned into its own filesystem
* 2000-07-05: Ashley Montanaro <ashley@compsoc.man.ac.uk>
* Converted file reading routine to dump to buffer once
* per device, not per bus
*
* $Id: devices.c,v 1.5 2000/01/11 13:58:21 tom Exp $
*/
......@@ -367,22 +370,39 @@ static char *usb_dump_string(char *start, char *end, const struct usb_device *de
/*****************************************************************/
static char *usb_device_dump(char *start, char *end, struct usb_device *usbdev,
struct usb_bus *bus, int level, int index, int count)
/* This is a recursive function. Parameters:
* buffer - the user-space buffer to write data into
* nbytes - the maximum number of bytes to write
* skip_bytes - the number of bytes to skip before writing anything
* file_offset - the offset into the devices file on completion
*/
static ssize_t usb_device_dump(char **buffer, size_t *nbytes, loff_t *skip_bytes, loff_t *file_offset,
struct usb_device *usbdev, struct usb_bus *bus, int level, int index, int count)
{
int chix;
int cnt = 0;
int ret, cnt = 0;
int parent_devnum = 0;
char *pages_start, *data_end;
unsigned int length;
ssize_t total_written = 0;
/* don't bother with anything else if we're not writing any data */
if (*nbytes <= 0)
return 0;
if (level > MAX_TOPO_LEVEL)
return start;
return total_written;
/* allocate 2^1 pages = 8K (on i386); should be more than enough for one device */
if (!(pages_start = (char*) __get_free_pages(GFP_KERNEL,1)))
return -ENOMEM;
if (usbdev->parent && usbdev->parent->devnum != -1)
parent_devnum = usbdev->parent->devnum;
/*
* So the root hub's parent is 0 and any device that is
* plugged into the root hub has a parent of 0.
*/
start += sprintf(start, format_topo, bus->busnum, level, parent_devnum, index, count,
data_end = pages_start + sprintf(pages_start, format_topo, bus->busnum, level, parent_devnum, index, count,
usbdev->devnum, usbdev->slow ? "1.5" : "12 ", usbdev->maxchild);
/*
* level = topology-tier level;
......@@ -392,30 +412,58 @@ static char *usb_device_dump(char *start, char *end, struct usb_device *usbdev,
*/
/* If this is the root hub, display the bandwidth information */
if (level == 0)
start += sprintf(start, format_bandwidth, bus->bandwidth_allocated,
data_end += sprintf(data_end, format_bandwidth, bus->bandwidth_allocated,
FRAME_TIME_MAX_USECS_ALLOC,
(100 * bus->bandwidth_allocated + FRAME_TIME_MAX_USECS_ALLOC / 2) / FRAME_TIME_MAX_USECS_ALLOC,
bus->bandwidth_int_reqs, bus->bandwidth_isoc_reqs);
start = usb_dump_desc(start, end, usbdev);
if (start > end)
return start + sprintf(start, "(truncated)\n");
data_end = usb_dump_desc(data_end, pages_start + (2 * PAGE_SIZE) - 256, usbdev);
if (data_end > (pages_start + (2 * PAGE_SIZE) - 256))
data_end += sprintf(data_end, "(truncated)\n");
length = data_end - pages_start;
/* if we can start copying some data to the user */
if (length > *skip_bytes) {
length -= *skip_bytes;
if (length > *nbytes)
length = *nbytes;
if (copy_to_user(*buffer, pages_start + *skip_bytes, length)) {
free_pages((unsigned long)pages_start, 1);
if (total_written == 0)
return -EFAULT;
return total_written;
}
*nbytes -= length;
*file_offset += length;
total_written += length;
*buffer += length;
*skip_bytes = 0;
} else
*skip_bytes -= length;
free_pages((unsigned long)pages_start, 1);
/* Now look at all of this device's children. */
for (chix = 0; chix < usbdev->maxchild; chix++) {
if (start > end)
return start;
if (usbdev->children[chix])
start = usb_device_dump(start, end, usbdev->children[chix], bus, level + 1, chix, ++cnt);
if (usbdev->children[chix]) {
ret = usb_device_dump(buffer, nbytes, skip_bytes, file_offset, usbdev->children[chix],
bus, level + 1, chix, ++cnt);
if (ret == -EFAULT)
return total_written;
total_written += ret;
}
return start;
}
return total_written;
}
static ssize_t usb_device_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
{
struct list_head *buslist;
struct usb_bus *bus;
char *page, *end;
ssize_t ret = 0;
unsigned int pos, len;
ssize_t ret, total_written = 0;
loff_t skip_bytes = *ppos;
if (*ppos < 0)
return -EINVAL;
......@@ -423,34 +471,18 @@ static ssize_t usb_device_read(struct file *file, char *buf, size_t nbytes, loff
return 0;
if (!access_ok(VERIFY_WRITE, buf, nbytes))
return -EFAULT;
if (!(page = (char*) __get_free_pages(GFP_KERNEL,1)))
return -ENOMEM;
pos = *ppos;
/* enumerate busses */
for (buslist = usb_bus_list.next; buslist != &usb_bus_list; buslist = buslist->next) {
/* print devices for this bus */
bus = list_entry(buslist, struct usb_bus, bus_list);
end = usb_device_dump(page, page + (2*PAGE_SIZE - 256), bus->root_hub, bus, 0, 0, 0);
len = end - page;
if (len > pos) {
len -= pos;
if (len > nbytes)
len = nbytes;
if (copy_to_user(buf, page + pos, len)) {
if (!ret)
ret = -EFAULT;
break;
}
nbytes -= len;
buf += len;
ret += len;
pos = 0;
*ppos += len;
} else
pos -= len;
}
free_pages((unsigned long)page, 1);
/* recurse through all children of the root hub */
ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, bus->root_hub, bus, 0, 0, 0);
if (ret < 0)
return ret;
total_written += ret;
}
return total_written;
}
/* Kernel lock for "lastev" protection */
......
......@@ -33,7 +33,7 @@ obj- :=
# Each configuration option enables a list of files.
obj-$(CONFIG_DUMMY_CONSOLE) += dummycon.o
obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o vga_font.o
obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o
obj-$(CONFIG_PROM_CONSOLE) += promcon.o promcon_tbl.o
obj-$(CONFIG_VGA_CONSOLE) += vgacon.o
obj-$(CONFIG_MDA_CONSOLE) += mdacon.o
......
This diff is collapsed.
......@@ -933,6 +933,9 @@ void d_move(struct dentry * dentry, struct dentry * target)
/**
* d_path - return the path of a dentry
* @dentry: dentry to report
* @vfsmnt: vfsmnt to which the dentry belongs
* @root: root dentry
* @rootmnt: vfsmnt to which the root dentry belongs
* @buffer: buffer to return value in
* @buflen: buffer length
*
......
......@@ -261,6 +261,7 @@ static void sync_all_inodes(void)
/**
* write_inode_now - write an inode to disk
* @inode: inode to write to disk
* @sync: whether the write should be synchronous or not
*
* This function commits an inode to disk immediately if it is
* dirty. This is primarily needed by knfsd.
......
......@@ -8,7 +8,7 @@
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* $Id: inode-v23.c,v 1.16 2000/07/06 14:38:10 dwmw2 Exp $
* $Id: inode-v23.c,v 1.17 2000/07/06 20:35:19 prumpf Exp $
*
*
* Ported to Linux 2.3.x and MTD:
......@@ -24,7 +24,6 @@
* maybe other stuff do to.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
......@@ -1453,7 +1452,6 @@ static struct inode_operations jffs_file_inode_operations =
static struct file_operations jffs_dir_operations =
{
read: generic_read_dir,
readdir: jffs_readdir,
};
......@@ -1533,16 +1531,19 @@ jffs_delete_inode(struct inode *inode)
inode->i_size = 0;
unlock_kernel();
clear_inode(inode);
unlock_kernel();
}
void
jffs_write_super(struct super_block *sb)
{
#ifdef USE_GC
jffs_garbage_collect((struct jffs_control *)sb->u.generic_sbp);
struct jffs_control *c = (struct jffs_control *)sb->u.generic_sbp;
if(!c->fmc->no_call_gc)
jffs_garbage_collect(c);
#endif
}
......
......@@ -164,6 +164,8 @@ int do_select(int n, fd_set_bits *fds, long *timeout)
poll_initwait(&table);
wait = &table;
if (!__timeout)
wait = NULL;
retval = 0;
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
......@@ -385,7 +387,7 @@ asmlinkage long sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout)
{
int i, j, fdcount, err;
struct pollfd **fds;
poll_table table;
poll_table table, *wait;
int nchunks, nleft;
/* Do a sanity check on nfds ... */
......@@ -401,8 +403,11 @@ asmlinkage long sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout)
}
poll_initwait(&table);
err = -ENOMEM;
wait = &table;
if (!timeout)
wait = NULL;
err = -ENOMEM;
fds = NULL;
if (nfds != 0) {
fds = (struct pollfd **)kmalloc(
......@@ -437,7 +442,7 @@ asmlinkage long sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout)
goto out_fds1;
}
fdcount = do_poll(nfds, nchunks, nleft, fds, &table, timeout);
fdcount = do_poll(nfds, nchunks, nleft, fds, wait, timeout);
/* OK, now copy the revents fields back to user space. */
for(i=0; i < nchunks; i++)
......
This diff is collapsed.
/* $Id: dma.h,v 1.5 2000/03/07 15:45:42 ralf Exp $
*
/*
* linux/include/asm/dma.h: Defines for using and allocating dma channels.
* Written by Hennus Bergman, 1992.
* High DMA channel support & info by Hannu Savolainen
......
/* $Id: param.h,v 1.1 1999/08/18 23:37:51 ralf Exp $
*
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright 1994 - 1999 Ralf Baechle (ralf@gnu.org)
* Copyright 1994 - 2000 Ralf Baechle (ralf@gnu.org)
* Copyright 2000 Silicon Graphics, Inc.
*/
#ifndef _ASM_PARAM_H
#define _ASM_PARAM_H
......@@ -13,7 +13,7 @@
#define HZ 100
# define HZ 100
#ifdef __KERNEL__
# define HZ_TO_STD(a) (a)
# define hz_to_std(a) (a)
#endif
#endif
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -8,7 +8,6 @@
#ifndef _SPARC_BITOPS_H
#define _SPARC_BITOPS_H
#include <linux/config.h>
#include <linux/kernel.h>
#include <asm/byteorder.h>
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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